- Notifications
You must be signed in to change notification settings - Fork39
Rust interface to the Linux GPIO Character Device API (/dev/gpiochip...)
License
Apache-2.0, MIT licenses found
Licenses found
rust-embedded/gpio-cdev
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
rust-gpio-cdev is a Rust library/crate providing access toGPIO character deviceABI. This API,stabilized with Linux v4.4, deprecates the legacy sysfs interface to GPIOs that isplanned to be removed from the upstream kernel afteryear 2020 (which is coming up quickly).
Use of this API is encouraged over the sysfs API used by this crate'spredecessorsysfs_gpio if you don't needto target older kernels. For more information on differences seeSysfs GPIO vsGPIO Character Device.
Add the following to yourCargo.toml
[dependencies]gpio-cdev = "0.4"Note that the following features are available:
async-tokio: Adds a Stream interface for consuming GPIO events in async codewithin a tokio runtime.
There are several additional examples available in theexamplesdirectory.
use gpio_cdev::{Chip,LineRequestFlags};// Read the state of GPIO4 on a raspberry pi. /dev/gpiochip0// maps to the driver for the SoC (builtin) GPIO controller.letmut chip =Chip::new("/dev/gpiochip0")?;let handle = chip.get_line(4)?.request(LineRequestFlags::INPUT,0,"read-input")?;for _in1..4{println!("Value: {:?}", handle.get_value()?);}
use gpio_cdev::{Chip,LineRequestFlags,EventRequestFlags,EventType};// Lines are offset within gpiochip0; see docs for more info on chips/lines//// This function will synchronously follow the state of one line// on gpiochip0 and mirror its state on another line. With this you// could, for instance, control the state of an LED with a button// if hooked up to the right pins on a raspberry pi.fnmirror_gpio(inputline:u32,outputline:u32) ->Result<(), gpio_cdev::Error>{letmut chip =Chip::new("/dev/gpiochip0")?;let input = chip.get_line(inputline)?;let output = chip.get_line(outputline)?;let output_handle = output.request(LineRequestFlags::OUTPUT,0,"mirror-gpio")?;for eventin input.events(LineRequestFlags::INPUT,EventRequestFlags::BOTH_EDGES,"mirror-gpio",)?{let evt = event?;println!("{:?}", evt);match evt.event_type(){EventType::RisingEdge =>{ output_handle.set_value(1)?;}EventType::FallingEdge =>{ output_handle.set_value(0)?;}}}Ok(())}
Note that this requires the addition of theasync-tokio feature.
use futures::stream::StreamExt;use gpio_cdev::{Chip,AsyncLineEventHandle};asyncfngpiomon(chip:String,line:u32) -> gpio_cdev::Result<()>{letmut chip =Chip::new(args.chip)?;let line = chip.get_line(args.line)?;letmut events =AsyncLineEventHandle::new(line.events(LineRequestFlags::INPUT,EventRequestFlags::BOTH_EDGES,"gpioevents",)?)?;whileletSome(event) = events.next().await{let event = event?;println!("GPIO Event: {:?}", event);}Ok(())}
Compared to the sysfs gpio interface (as made available by the sysfs_gpio crate)the character device has several advantages and critical design differences(some of which are driving the deprecation in the kernel).
Since many people are familiar with the sysfs interface (which is easilyaccessible via basic commands in the shell) and few people are familiar with theGPIO character device, an exploration of the two and key differences here mayprove useful.
In the Linux kernel, individual GPIOs are exposed via drivers that on probe registerthemselves as GPIO chips with the gpio subsystem. Each of these chips providesaccess to a set of GPIOs. At present, when this chip is registered a globalbase number is assigned to this driver. The comments from the linux kernelgpio_chip_add_datasum up the situation nicely when assigning the a base number to a GPIO chipon registration.
/* * TODO: this allocates a Linux GPIO number base in the global * GPIO numberspace for this chip. In the long run we want to * get *rid* of this numberspace and use only descriptors, but * it may be a pipe dream. It will not happen before we get rid * of the sysfs interface anyways. */The entire sysfs interface to GPIO is based around offsets from the base numberassigned to a GPIO chip. The base number is completely dependent on the orderin which the chip was registered with the subsystem and the number of GPIOs thateach of the previous chips registered. The only reason this is usable at all isthat most GPIOs are accessed via SoC hardware that is registered consistentlyduring boot. It's not great; in fact, it's not even good.
The GPIO character device ABI provides access to GPIOs owned by a GPIO chip viaa bus device,/sys/bus/gpiochipN (or/dev/gpiochipN). Within a chip, theprogrammer will still need to know some details about how to access the GPIO butthings are generally sane. Figuring out which bus device is the desired GPIOchip can be done by iterating over all that are present and/or setting upappropriate udev rules. One good example of this is thelsgpio utility inthe kernel source.
In sysfs each GPIO within a chip would be exported and used individually. TheGPIO character device allows for one or more GPIOs (referenced via offsets) tobe read, written, configured, and monitored via a "linehandle" fd that iscreated dynamically on request.
Using the sysfs API, one would write the global GPIO number to the "export" fileto perform further operations using new files on the filesystem. Using thegpiochip character device, a handle for performing operations on one or moreGPIO offsets within a chip are available via a "linehandle" fd created using theGPIO_GET_LINEHANDLE_IOCTL. A consequence of this is that a line will rememberits state only for as long as the fd is open; the line's state will be resetonce the fd is closed.
When a linehandle is requested, additional information is also included abouthow the individual GPIOs will be used (input, output, as-is, active-low, opendrain, open source, etc). Multiple lines can be grouped together in a singlerequest but they must all be configured the same way if being used in that way.Seestruct gpioevent_request.
Via sysfs, GPIOs could be read/written using the value file. For GPIO characterdevices, theGPIOHANDLE_GET_LINE_VALUES_IOCTL andGPIOHANDLE_SET_LINE_VALUES_IOCTL may be used to get/set the state of one ormore offsets within the chip.
Via sysfs, one could setup things up using the trigger file to notify userspace(by polling on the value file) of a single event based on how things were setup.With GPIO character devices, one can setup agpio_eventrequest that will createa new anonymous file (fd provided) for event notifications on a lines within agpiochip. Contrary to sysfs gpio events, the event file will queue multiple eventsand include with the event (best effort) nanosecond-precision timing and anidentifier with event type.
With this information one could more reasonably consider interpreting a basicdigital signal from userspace (with rising and falling edges) from userspaceusing the queueing with timing information captured in the kernel. Previously, onewould need to quickly handle the event notification, make another system callto the value file to see the state, etc. which had far too many variables involvedto be considered reliable.
This crate is guaranteed to compile on stable Rust 1.82.0 and up. Itmightcompile with older versions but that may change in any new patch release.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE orhttp://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT orhttp://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submittedfor inclusion in the work by you, as defined in the Apache-2.0 license, shall bedual licensed as above, without any additional terms or conditions.
Contribution to this crate is organized under the terms of theRust Code ofConduct, the maintainer of this crate, theEmbedded Linux Team, promisesto intervene to uphold that code of conduct.
About
Rust interface to the Linux GPIO Character Device API (/dev/gpiochip...)
Topics
Resources
License
Apache-2.0, MIT licenses found
Licenses found
Code of conduct
Uh oh!
There was an error while loading.Please reload this page.