diff --git a/Cargo.toml b/Cargo.toml index 9ddf3b5..937fae5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,14 +8,20 @@ name = "linux-embedded-hal" repository = "https://github.com/japaric/linux-embedded-hal" version = "0.3.0" +[features] +default = ["sysfs_gpio"] + +gpio_cdev = ["gpio-cdev"] + [dependencies] embedded-hal = { version = "0.2.3", features = ["unproven"] } i2cdev = "0.4.3" spidev = "0.4" -sysfs_gpio = "0.5" serial-unix = "0.4.0" serial-core = "0.4.0" nb = "0.1.1" +sysfs_gpio = { version = "0.5", optional = true } +gpio-cdev = { version="0.2", optional = true } [dev-dependencies] openpty = "0.1.0" diff --git a/README.md b/README.md index c51c950..253b57b 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,17 @@ This project is developed and maintained by the [Embedded Linux team][team]. ## [Documentation](https://docs.rs/linux-embedded-hal) +## GPIO character device + +Since Linux kernel v4.4 the use of sysfs GPIO was deprecated and replaced by the character device GPIO. +See [gpio-cdev documentation](https://github.com/rust-embedded/gpio-cdev#sysfs-gpio-vs-gpio-character-device) for details. + +This crate includes feature flag `gpio_cdev` that replaces [sysfs_gpio](https://crates.io/crates/sysfs_gpio) by [gpio-cdev](https://crates.io/crates/gpio-cdev). +To enable it update your Cargo.toml. +``` +linux-embedded-hal = { version = "0.3", features = ["gpio_cdev"] } +``` + ## License Licensed under either of diff --git a/src/lib.rs b/src/lib.rs index e999faf..26ba02f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,15 +11,19 @@ //! [0]: https://crates.io/keywords/embedded-hal #![deny(missing_docs)] +#![feature(doc_cfg)] extern crate cast; extern crate embedded_hal as hal; +#[cfg(feature = "gpio_cdev")] +pub extern crate gpio_cdev; pub extern crate i2cdev; +pub extern crate nb; +pub extern crate serial_core; +pub extern crate serial_unix; pub extern crate spidev; +#[cfg(not(feature = "gpio_cdev"))] pub extern crate sysfs_gpio; -pub extern crate serial_unix; -pub extern crate serial_core; -pub extern crate nb; use std::io::{self, Write}; use std::path::{Path, PathBuf}; @@ -92,11 +96,32 @@ impl hal::blocking::delay::DelayMs for Delay { } } +/// Newtype around [`gpio_cdev::LineHandle`] that implements the `embedded-hal` traits +/// +/// [`gpio_cdev::LineHandle`]: https://docs.rs/gpio-cdev/0.2.0/gpio_cdev/struct.LineHandle.html +#[cfg(feature = "gpio_cdev")] +#[doc(cfg(feature = "gpio_cdev"))] +pub struct Pin(pub gpio_cdev::LineHandle, bool); + +#[cfg(feature = "gpio_cdev")] +#[doc(cfg(feature = "gpio_cdev"))] +impl Pin { + /// See [`gpio_cdev::Line::request`][0] for details. + /// + /// [0]: https://docs.rs/gpio-cdev/0.2.0/gpio_cdev/struct.Line.html#method.request + pub fn new(handle: gpio_cdev::LineHandle) -> Result { + let info = handle.line().info()?; + Ok(Pin(handle, info.is_active_low())) + } +} + /// Newtype around [`sysfs_gpio::Pin`] that implements the `embedded-hal` traits /// /// [`sysfs_gpio::Pin`]: https://docs.rs/sysfs_gpio/0.5.1/sysfs_gpio/struct.Pin.html +#[cfg(not(feature = "gpio_cdev"))] pub struct Pin(pub sysfs_gpio::Pin); +#[cfg(not(feature = "gpio_cdev"))] impl Pin { /// See [`sysfs_gpio::Pin::new`][0] for details. /// @@ -117,6 +142,9 @@ impl Pin { } impl hal::digital::v2::OutputPin for Pin { + #[cfg(feature = "gpio_cdev")] + type Error = gpio_cdev::errors::Error; + #[cfg(not(feature = "gpio_cdev"))] type Error = sysfs_gpio::Error; fn set_low(&mut self) -> Result<(), Self::Error> { @@ -129,8 +157,20 @@ impl hal::digital::v2::OutputPin for Pin { } impl hal::digital::v2::InputPin for Pin { + #[cfg(feature = "gpio_cdev")] + type Error = gpio_cdev::errors::Error; + #[cfg(not(feature = "gpio_cdev"))] type Error = sysfs_gpio::Error; + #[cfg(feature = "gpio_cdev")] + fn is_high(&self) -> Result { + if !self.1 { + self.0.get_value().map(|val| val != 0) + } else { + self.0.get_value().map(|val| val == 0) + } + } + #[cfg(not(feature = "gpio_cdev"))] fn is_high(&self) -> Result { if !self.0.get_active_low()? { self.0.get_value().map(|val| val != 0) @@ -145,6 +185,9 @@ impl hal::digital::v2::InputPin for Pin { } impl ops::Deref for Pin { + #[cfg(feature = "gpio_cdev")] + type Target = gpio_cdev::LineHandle; + #[cfg(not(feature = "gpio_cdev"))] type Target = sysfs_gpio::Pin; fn deref(&self) -> &Self::Target { @@ -220,10 +263,7 @@ impl hal::blocking::i2c::WriteRead for I2cdev { buffer: &mut [u8], ) -> Result<(), Self::Error> { self.set_address(address)?; - let mut messages = [ - LinuxI2CMessage::write(bytes), - LinuxI2CMessage::read(buffer), - ]; + let mut messages = [LinuxI2CMessage::write(bytes), LinuxI2CMessage::read(buffer)]; self.inner.transfer(&mut messages).map(drop) } }