How to set a value in module init in rust and use it in module methods?

Hello,

In my embedded rust code, I map the gpio memory mapped registers to a struct and configure gpio pins as below.


#[repr(C)]
 struct GpioRegs{
    iput_val: u32, /* Pin Value */
    iput_en: u32, /* Pin input enable */
    oput_en: u32, /* pin output enable */
}
#[no_mangle]
    pub fn set_as_in(p: u8) {
        unsafe {
            let v: u32;
            let t = 0x2000_0000 as *mut GpioMmapRegs;
            v = (*t).iput_en | mask(p) ;
            (*t).iput_en = v;
        }

In every method set_as_in, set_as_out I duplicate this line
let t = 0x2000_0000 as *mut GpioMmapRegs;

In C, i would create a global variable and set this in module_init and later in every method, I would use this global variable accordingly.

In rust, is there a way (without global variable, since its discouraged in rust), but not to duplicate this line?

You can use a helper type to do the pointer cast once and store the result and have the define the other functions as methods on the helper.

I’m assuming GpioRegs and GpioMmapRegs are the same type here, you may have to tweak it if they aren’t.

Playground

#![allow(dead_code)]

#[repr(C)]
 struct GpioRegs{
    iput_val: u32, /* Pin Value */
    iput_en: u32, /* Pin input enable */
    oput_en: u32, /* pin output enable */
}

struct GpioHelper(*mut GpioRegs);

impl GpioHelper {
    pub fn set_as_in(&self, p: u8) {
        unsafe {
            let v: u32;
            v = (*self.0).iput_en | mask(p) ;
            (*self.0).iput_en = v;
        }
    }
    
    pub fn get() -> Self {
        Self(0x2000_0000 as *mut GpioRegs)
    }
}

fn mask(_: u8) -> u32 {
    todo!()
}

fn sample() {
    let gpio = GpioHelper::get();
    
    gpio.set_as_in(1);
}

You’re using no_mangle but not marking the function with an external ABI so I’m not sure if changing how the functions are called is viable. If they need to be callable from C or something a lazy static of some sort is probably reasonable. Or you could just declare a function[1] with a simple name that does the cast for you and call that instead. Not a huge improvement but at least would avoid duplicating the address everywhere.


I don’t believe you can use a const here since memory addresses aren’t integers during constant evaluation


  1. or macro if you’re so inclined ↩︎

Thank you !

Yes, GpioRegs and GpioMmapRegs are the same type.

Would it also be able to hide the struct GpioRegs from caller? (with the set methods as public, but the struct as private)

Caller dont have to know either the struct GpioRegs details or the 0x2000_0000.

Yup, as long as none of the functions take or return that type to the caller it can be fully private.