Allocating an object for C / FFI library calls

I have a C library that has a gpio implementation. There's gpio_type which is the target, each MCU has a different definition for gpio_type. One of the functions in the library:

void gpio_init(gpio_type *object, int32_t pin);

      

I want to write an abstraction of a Gpio object in Rust using the C library functions so something like an opaque pointer type is needed (in C ++ I would just create a member variable with the type: gpio_type). I figured I would create an empty enum (or structure), allocate the space needed for the object, and convert it to match the type in layer C.

pub enum gpio_type {}

#[link(name = "gpio_lib", kind = "static")]
extern {
    pub fn gpio_init(obj: *mut gpio_type, value: i32);
}

pub struct Gpio {
    gpio : *mut gpio_type,
}

impl Gpio {
    pub fn new(pin: u32) -> Gpio {
        unsafe {
            let mut gpio_ptr : &'static [u8; 4] = init(); // size of gpio in C is 4 bytes for one target, will be changed later to obtain it dynamically
            let gpio_out = Gpio { gpio: transmute(gpio_ptr)};
            gpio_init(gpio_out.gpio, pin);
            gpio_out
        }
    }
}

      

This is for embedded devices, so no std, no libc. I don't want to override gpio_type for every target in rust (copy the C declaration for each target) looking for something to just allocate memory for an object that will handle C.

The following snippet creates a pointer to address 0 according to the parse. Disassembly for the new Gpio method:

 45c:   b580        push    {r7, lr}
 45e:   466f        mov r7, sp
 460:   4601        mov r1, r0
 462:   2000        movs    r0, #0
 464:   f000 fae6   bl  a34 <gpio_init>
 468:   2000        movs    r0, #0
 46a:   bd80        pop {r7, pc}

      

Any ideas why 462 is 0?

+1


source to share


1 answer


looking for something to just allocate memory for an object that C will handle

How about something like this? Give the structure an actual size (in this case, by providing an array with a fixed size of bytes), allocate that space on the heap, and then treat that as a raw pointer.

use std::mem;

#[allow(missing_copy_implementations)]
pub struct Gpio([u8; 4]);

impl Gpio {
    fn new() -> Gpio { Gpio([0,0,0,0]) }
}

fn main() {
    // Allocate some bytes and get a raw pointer
    let a: *mut u8 = unsafe { mem::transmute(Box::new(Gpio::new())) };

    // Use it here!

    // When done... back to a box
    let b: Box<Gpio> = unsafe { mem::transmute(a) };

    // Now it will be dropped automatically (and free the allocated memory)

    // Or you can be explicit
    drop(b);
}

      

However, I would suggest doing something like this; this is much more obvious and doesn't require heap allocation:

#[allow(missing_copy_implementations)]
pub struct Gpio([u8; 4]);

impl Gpio {
    fn new() -> Gpio { Gpio([0,0,0,0]) }

    fn as_mut_ptr(&mut self) -> *mut u8 {
        self.0.as_mut_ptr()
    }
}

fn main() {
    let mut g = Gpio::new();
    let b = g.as_mut_ptr();
}

      



As a bonus, you get a great place to hang some of the methods. Potentially as_mut_ptr

unnecessary to publish and can be hidden behind public methods in the framework Gpio

.

(can also use uninitialized

instead [0,0,0,0]

)

Extended example of the second sentence

// This depends on your library, check the FFI guide for details
extern {
    fn gpio_init(gpio: *mut u8, pin: u8);
    fn gpio_pin_on(gpio: *mut u8);
    fn gpio_pin_off(gpio: *mut u8);
}

#[allow(missing_copy_implementations)]
pub struct Gpio([u8; 4]);

impl Gpio {
    fn new(pin: u8) -> Gpio {
        let mut g = Gpio([0,0,0,0]);
        g.init(pin);
        g
    }

    fn as_mut_ptr(&mut self) -> *mut u8 {
        self.0.as_mut_ptr()
    }

    fn init(&mut self, pin: u8) { unsafe { gpio_init(self.as_mut_ptr(), pin) } }
    pub fn on(&mut self) { unsafe { gpio_pin_on(self.as_mut_ptr()) } }
    pub fn off(&mut self) { unsafe { gpio_pin_off(self.as_mut_ptr()) } }
}

static BLUE_LED_PIN: u8 = 0x4;

fn main() {
    let mut g = Gpio::new(BLUE_LED_PIN);
    g.on();
    g.off();
}

      

+2


source







All Articles