rust-embedded/gpio-cdev

Improve documentation about keeping LineHandles in scope

kmdouglass opened this issue · 2 comments

Hello!

First, thanks a lot for creating this crate and the work you put into it.

I have a small suggestion that could improve the documentation. Consider the following program which is a simplified version of the driveoutput.rs example:

use gpio_cdev::{Chip, LineRequestFlags};

fn main() {
    let mut chip = Chip::new("/dev/gpiochip0").unwrap();

    chip
        .get_line(4).unwrap()
        .request(LineRequestFlags::OUTPUT, 1, "set-pin").unwrap();
    
    println!("Press Enter to exit");
    let mut buf = String::new();
    ::std::io::stdin().read_line(&mut buf).unwrap();
}

This program compiles and does not panic, but seemingly does nothing as the pin remains in an unset state while the program waits on the user to press Enter. However, if we assign the LineHandle instance to a variable like this:

let _handle = chip
        .get_line(4).unwrap()
        .request(LineRequestFlags::OUTPUT, 1, "set-pin").unwrap();

Then the pin state is correctly set, presumably because the file descriptor contained inside the LineHandle doesn't immediately get dropped after request is called.

I think that it is important to note in the comments that the LineHandle needs to remain in scope or assigned to a persistent variable to prevent these sorts of "silent failures." It may be obvious in the above example, but in my case I do some initialization of the chip and store it inside a struct that is passed around; it took me about a day of debugging to realize that I needed initialize and store the LineHandle instance in addition to the Chip.

If you agree, then I will open a small PR to update the examples and docstrings to make note of this.

I agree that's a good point. It's quite a surprise for people using the chardev GPIO for the first time, regardless of the language/implementation. There seems to be an assumption from the previous model that you can write a small app to set the value of a pin, and then when you exit the app, everything remains as you set. And the same goes for maintaining the handles from within the app.

So I'm all for improving the docs and examples for making this more obvious.

Is there any kernel documentation concerning this? In my testing GPIOs do not revert to their initial state when the LineHandle is dropped. So at least the README's claim that this "will" happen is incorrect.
I've not been able to find any concrete documentation concerning this. There is one blog post that also claims that GPIOs might reset, but like me they were not able to actually produce that behavior.
Maybe this depends on the underlying gpiochip/pinctrl?