Skip to content

Add support for character device GPIO #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added

- Added serial::Read/Write implementation.
- Added feature flag for Chardev GPIO

### Fixed

Expand All @@ -23,6 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Use embedded-hal::digital::v2 traits.
- Updated to i2cdev 0.4.3 (necessary for trasactional write-read).
- Updated to spidev 0.4
- Added feature flag for Sysfs GPIO

## [v0.2.2] - 2018-12-21

Expand Down
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@ name = "linux-embedded-hal"
repository = "https://github.com/japaric/linux-embedded-hal"
version = "0.3.0"

[features]
default = []
gpio_sysfs = ["sysfs_gpio"]
gpio_cdev = ["gpio-cdev"]

[dependencies]
embedded-hal = { version = "0.2.3", features = ["unproven"] }
gpio-cdev = { version = "0.2", optional = true }
sysfs_gpio = { version = "0.5", optional = true }

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"
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ 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 exposes `CdevPin` as wrapper around `LineHandle` from [gpio-cdev](https://crates.io/crates/gpio-cdev).
To enable it update your Cargo.toml. Please note that in order to prevent `LineHandle` fd from closing you should
assign to a variable, see [cdev issue](https://github.com/rust-embedded/gpio-cdev/issues/29) for more details.
```
linux-embedded-hal = { version = "0.3", features = ["gpio_cdev"] }
```

`SysfsPin` can be still used with feature flag `gpio_sysfs`.

## License

Licensed under either of
Expand Down
58 changes: 58 additions & 0 deletions src/cdev_pin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use core::ops;

/// 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
pub struct CdevPin(pub gpio_cdev::LineHandle, bool);

impl CdevPin {
/// 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<Self, gpio_cdev::errors::Error> {
let info = handle.line().info()?;
Ok(CdevPin(handle, info.is_active_low()))
}
}

impl hal::digital::v2::OutputPin for CdevPin {
type Error = gpio_cdev::errors::Error;

fn set_low(&mut self) -> Result<(), Self::Error> {
self.0.set_value(0)
}

fn set_high(&mut self) -> Result<(), Self::Error> {
self.0.set_value(1)
}
}

impl hal::digital::v2::InputPin for CdevPin {
type Error = gpio_cdev::errors::Error;

fn is_high(&self) -> Result<bool, Self::Error> {
if !self.1 {
self.0.get_value().map(|val| val != 0)
} else {
self.0.get_value().map(|val| val == 0)
}
}

fn is_low(&self) -> Result<bool, Self::Error> {
self.is_high().map(|val| !val)
}
}

impl ops::Deref for CdevPin {
type Target = gpio_cdev::LineHandle;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl ops::DerefMut for CdevPin {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
92 changes: 19 additions & 73 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
#![deny(missing_docs)]

extern crate cast;
extern crate core;
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(feature = "gpio_sysfs")]
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};
Expand All @@ -33,7 +37,18 @@ use spidev::SpidevTransfer;

mod serial;

#[cfg(feature = "gpio_cdev")]
/// Cdev Pin wrapper module
mod cdev_pin;
#[cfg(feature = "gpio_sysfs")]
/// Sysfs Pin wrapper module
mod sysfs_pin;

#[cfg(feature = "gpio_cdev")]
pub use cdev_pin::CdevPin;
pub use serial::Serial;
#[cfg(feature = "gpio_sysfs")]
pub use sysfs_pin::SysfsPin;

/// Empty struct that provides delay functionality on top of `thread::sleep`
pub struct Delay;
Expand Down Expand Up @@ -92,72 +107,6 @@ impl hal::blocking::delay::DelayMs<u64> for Delay {
}
}

/// 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
pub struct Pin(pub sysfs_gpio::Pin);

impl Pin {
/// See [`sysfs_gpio::Pin::new`][0] for details.
///
/// [0]: https://docs.rs/sysfs_gpio/0.5.1/sysfs_gpio/struct.Pin.html#method.new
pub fn new(pin_num: u64) -> Pin {
Pin(sysfs_gpio::Pin::new(pin_num))
}

/// See [`sysfs_gpio::Pin::from_path`][0] for details.
///
/// [0]: https://docs.rs/sysfs_gpio/0.5.1/sysfs_gpio/struct.Pin.html#method.from_path
pub fn from_path<P>(path: P) -> sysfs_gpio::Result<Pin>
where
P: AsRef<Path>,
{
sysfs_gpio::Pin::from_path(path).map(Pin)
}
}

impl hal::digital::v2::OutputPin for Pin {
type Error = sysfs_gpio::Error;

fn set_low(&mut self) -> Result<(), Self::Error> {
self.0.set_value(0)
}

fn set_high(&mut self) -> Result<(), Self::Error> {
self.0.set_value(1)
}
}

impl hal::digital::v2::InputPin for Pin {
type Error = sysfs_gpio::Error;

fn is_high(&self) -> Result<bool, Self::Error> {
if !self.0.get_active_low()? {
self.0.get_value().map(|val| val != 0)
} else {
self.0.get_value().map(|val| val == 0)
}
}

fn is_low(&self) -> Result<bool, Self::Error> {
self.is_high().map(|val| !val)
}
}

impl ops::Deref for Pin {
type Target = sysfs_gpio::Pin;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl ops::DerefMut for Pin {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

/// Newtype around [`i2cdev::linux::LinuxI2CDevice`] that implements the `embedded-hal` traits
///
/// [`i2cdev::linux::LinuxI2CDevice`]: https://docs.rs/i2cdev/0.3.1/i2cdev/linux/struct.LinuxI2CDevice.html
Expand Down Expand Up @@ -220,10 +169,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)
}
}
Expand Down
68 changes: 68 additions & 0 deletions src/sysfs_pin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::ops;
use std::path::Path;

/// 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
pub struct SysfsPin(pub sysfs_gpio::Pin);

impl SysfsPin {
/// See [`sysfs_gpio::Pin::new`][0] for details.
///
/// [0]: https://docs.rs/sysfs_gpio/0.5.1/sysfs_gpio/struct.Pin.html#method.new
pub fn new(pin_num: u64) -> Self {
SysfsPin(sysfs_gpio::Pin::new(pin_num))
}

/// See [`sysfs_gpio::Pin::from_path`][0] for details.
///
/// [0]: https://docs.rs/sysfs_gpio/0.5.1/sysfs_gpio/struct.Pin.html#method.from_path
pub fn from_path<P>(path: P) -> sysfs_gpio::Result<Self>
where
P: AsRef<Path>,
{
sysfs_gpio::Pin::from_path(path).map(SysfsPin)
}
}

impl hal::digital::v2::OutputPin for SysfsPin {
type Error = sysfs_gpio::Error;

fn set_low(&mut self) -> Result<(), Self::Error> {
self.0.set_value(0)
}

fn set_high(&mut self) -> Result<(), Self::Error> {
self.0.set_value(1)
}
}

impl hal::digital::v2::InputPin for SysfsPin {
type Error = sysfs_gpio::Error;

fn is_high(&self) -> Result<bool, Self::Error> {
if !self.0.get_active_low()? {
self.0.get_value().map(|val| val != 0)
} else {
self.0.get_value().map(|val| val == 0)
}
}

fn is_low(&self) -> Result<bool, Self::Error> {
self.is_high().map(|val| !val)
}
}

impl ops::Deref for SysfsPin {
type Target = sysfs_gpio::Pin;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl ops::DerefMut for SysfsPin {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}