From 112aa9e91ff7da41d2fb6aa8d86ff57cfebf00cb Mon Sep 17 00:00:00 2001 From: Morgan Roff Date: Sat, 3 Apr 2021 22:15:13 +0200 Subject: [PATCH 1/2] Implement embedded_hal::digital::IoPin --- CHANGELOG.md | 1 + Cargo.toml | 2 +- src/cdev_pin.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++--- src/sysfs_pin.rs | 20 +++++++++++++++ 4 files changed, 86 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11651fc..2ce2f48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Implement `embedded_hal::digital::IoPin` for `CdevPin` and `SysfsPin` - Set default features to build both sysfs and cdev pin types. - Removed `Pin` export, use `CdevPin` or `SysfsPin`. - Increased the Minimum Supported Rust Version to `1.36.0` due to an update of `gpio_cdev`. diff --git a/Cargo.toml b/Cargo.toml index ae62c40..ce98be5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ async-tokio = ["gpio-cdev/async-tokio"] default = [ "gpio_cdev", "gpio_sysfs" ] [dependencies] -embedded-hal = "=1.0.0-alpha.4" +embedded-hal = { git = "https://github.com/rust-embedded/embedded-hal" } gpio-cdev = { version = "0.4", optional = true } sysfs_gpio = { version = "0.5", optional = true } diff --git a/src/cdev_pin.rs b/src/cdev_pin.rs index 1d213e8..349effd 100644 --- a/src/cdev_pin.rs +++ b/src/cdev_pin.rs @@ -3,7 +3,7 @@ /// 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); +pub struct CdevPin(pub gpio_cdev::LineHandle, gpio_cdev::LineInfo); impl CdevPin { /// See [`gpio_cdev::Line::request`][0] for details. @@ -11,7 +11,25 @@ impl CdevPin { /// [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(CdevPin(handle, info.is_active_low())) + Ok(CdevPin(handle, info)) + } + + fn get_input_flags(&self) -> gpio_cdev::LineRequestFlags { + let mut flags = gpio_cdev::LineRequestFlags::INPUT; + if self.1.is_active_low() { + flags.insert(gpio_cdev::LineRequestFlags::ACTIVE_LOW); + } + return flags; + } + + fn get_output_flags(&self) -> gpio_cdev::LineRequestFlags { + let mut flags = gpio_cdev::LineRequestFlags::OUTPUT; + if self.1.is_open_drain() { + flags.insert(gpio_cdev::LineRequestFlags::OPEN_DRAIN); + } else if self.1.is_open_source() { + flags.insert(gpio_cdev::LineRequestFlags::OPEN_SOURCE); + } + return flags; } } @@ -31,7 +49,7 @@ impl embedded_hal::digital::InputPin for CdevPin { type Error = gpio_cdev::errors::Error; fn try_is_high(&self) -> Result { - if !self.1 { + if !self.1.is_active_low() { self.0.get_value().map(|val| val != 0) } else { self.0.get_value().map(|val| val == 0) @@ -43,6 +61,49 @@ impl embedded_hal::digital::InputPin for CdevPin { } } +impl embedded_hal::digital::IoPin for CdevPin { + type Error = gpio_cdev::errors::Error; + + fn try_into_input_pin(self) -> Result { + if self.1.direction() == gpio_cdev::LineDirection::In { + return Ok(self); + } + let line = self.0.line().clone(); + let input_flags = self.get_input_flags(); + let consumer = self.1.consumer().unwrap_or("").to_owned(); + + // Drop self to free the line before re-requesting it in a new mode. + std::mem::drop(self); + + CdevPin::new(line.request(input_flags, 0, &consumer)?) + } + + fn try_into_output_pin( + self, + state: embedded_hal::digital::PinState, + ) -> Result { + if self.1.direction() == gpio_cdev::LineDirection::Out { + return Ok(self); + } + + let line = self.0.line().clone(); + let output_flags = self.get_output_flags(); + let consumer = self.1.consumer().unwrap_or("").to_owned(); + + // Drop self to free the line before re-requesting it in a new mode. + std::mem::drop(self); + + CdevPin::new(line.request( + output_flags, + match state { + embedded_hal::digital::PinState::High => 1, + embedded_hal::digital::PinState::Low => 0, + }, + &consumer, + )?) + } +} + impl core::ops::Deref for CdevPin { type Target = gpio_cdev::LineHandle; diff --git a/src/sysfs_pin.rs b/src/sysfs_pin.rs index 10d8b8c..b1ccae8 100644 --- a/src/sysfs_pin.rs +++ b/src/sysfs_pin.rs @@ -54,6 +54,26 @@ impl embedded_hal::digital::InputPin for SysfsPin { } } +impl embedded_hal::digital::IoPin for SysfsPin { + type Error = sysfs_gpio::Error; + + fn try_into_input_pin(self) -> Result { + self.set_direction(sysfs_gpio::Direction::In)?; + Ok(self) + } + + fn try_into_output_pin( + self, + state: embedded_hal::digital::PinState, + ) -> Result { + self.set_direction(match state { + embedded_hal::digital::PinState::High => sysfs_gpio::Direction::High, + embedded_hal::digital::PinState::Low => sysfs_gpio::Direction::Low, + })?; + Ok(self) + } +} + impl core::ops::Deref for SysfsPin { type Target = sysfs_gpio::Pin; From 3e76395cea3ac2e166b10d4c4ffc13be66802981 Mon Sep 17 00:00:00 2001 From: Morgan Roff Date: Sun, 16 May 2021 18:10:26 +0200 Subject: [PATCH 2/2] Remove try_ method prefixes --- examples/transactional-i2c.rs | 2 +- src/cdev_pin.rs | 14 +++++++------- src/lib.rs | 34 +++++++++++++++------------------- src/serial.rs | 12 ++++++------ src/sysfs_pin.rs | 14 +++++++------- src/timer.rs | 14 +++++++------- 6 files changed, 43 insertions(+), 47 deletions(-) diff --git a/examples/transactional-i2c.rs b/examples/transactional-i2c.rs index 451ae43..5b4d9ce 100644 --- a/examples/transactional-i2c.rs +++ b/examples/transactional-i2c.rs @@ -23,7 +23,7 @@ where I2cOperation::Write(&[0xAB]), I2cOperation::Read(&mut read_buffer), ]; - self.i2c.try_exec(ADDR, &mut ops).and(Ok(read_buffer[0])) + self.i2c.exec(ADDR, &mut ops).and(Ok(read_buffer[0])) } } diff --git a/src/cdev_pin.rs b/src/cdev_pin.rs index 349effd..25356e4 100644 --- a/src/cdev_pin.rs +++ b/src/cdev_pin.rs @@ -36,11 +36,11 @@ impl CdevPin { impl embedded_hal::digital::OutputPin for CdevPin { type Error = gpio_cdev::errors::Error; - fn try_set_low(&mut self) -> Result<(), Self::Error> { + fn set_low(&mut self) -> Result<(), Self::Error> { self.0.set_value(0) } - fn try_set_high(&mut self) -> Result<(), Self::Error> { + fn set_high(&mut self) -> Result<(), Self::Error> { self.0.set_value(1) } } @@ -48,7 +48,7 @@ impl embedded_hal::digital::OutputPin for CdevPin { impl embedded_hal::digital::InputPin for CdevPin { type Error = gpio_cdev::errors::Error; - fn try_is_high(&self) -> Result { + fn is_high(&self) -> Result { if !self.1.is_active_low() { self.0.get_value().map(|val| val != 0) } else { @@ -56,15 +56,15 @@ impl embedded_hal::digital::InputPin for CdevPin { } } - fn try_is_low(&self) -> Result { - self.try_is_high().map(|val| !val) + fn is_low(&self) -> Result { + self.is_high().map(|val| !val) } } impl embedded_hal::digital::IoPin for CdevPin { type Error = gpio_cdev::errors::Error; - fn try_into_input_pin(self) -> Result { + fn into_input_pin(self) -> Result { if self.1.direction() == gpio_cdev::LineDirection::In { return Ok(self); } @@ -78,7 +78,7 @@ impl embedded_hal::digital::IoPin for CdevPin { CdevPin::new(line.request(input_flags, 0, &consumer)?) } - fn try_into_output_pin( + fn into_output_pin( self, state: embedded_hal::digital::PinState, ) -> Result { diff --git a/src/lib.rs b/src/lib.rs index f03c925..447f69d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ pub struct Delay; impl embedded_hal::blocking::delay::DelayUs for Delay { type Error = Infallible; - fn try_delay_us(&mut self, n: u8) -> Result<(), Self::Error> { + fn delay_us(&mut self, n: u8) -> Result<(), Self::Error> { thread::sleep(Duration::new(0, u32(n) * 1000)); Ok(()) } @@ -73,7 +73,7 @@ impl embedded_hal::blocking::delay::DelayUs for Delay { impl embedded_hal::blocking::delay::DelayUs for Delay { type Error = Infallible; - fn try_delay_us(&mut self, n: u16) -> Result<(), Self::Error> { + fn delay_us(&mut self, n: u16) -> Result<(), Self::Error> { thread::sleep(Duration::new(0, u32(n) * 1000)); Ok(()) } @@ -82,7 +82,7 @@ impl embedded_hal::blocking::delay::DelayUs for Delay { impl embedded_hal::blocking::delay::DelayUs for Delay { type Error = Infallible; - fn try_delay_us(&mut self, n: u32) -> Result<(), Self::Error> { + fn delay_us(&mut self, n: u32) -> Result<(), Self::Error> { let secs = n / 1_000_000; let nsecs = (n % 1_000_000) * 1_000; @@ -94,7 +94,7 @@ impl embedded_hal::blocking::delay::DelayUs for Delay { impl embedded_hal::blocking::delay::DelayUs for Delay { type Error = Infallible; - fn try_delay_us(&mut self, n: u64) -> Result<(), Self::Error> { + fn delay_us(&mut self, n: u64) -> Result<(), Self::Error> { let secs = n / 1_000_000; let nsecs = ((n % 1_000_000) * 1_000) as u32; @@ -106,7 +106,7 @@ impl embedded_hal::blocking::delay::DelayUs for Delay { impl embedded_hal::blocking::delay::DelayMs for Delay { type Error = Infallible; - fn try_delay_ms(&mut self, n: u8) -> Result<(), Self::Error> { + fn delay_ms(&mut self, n: u8) -> Result<(), Self::Error> { thread::sleep(Duration::from_millis(u64(n))); Ok(()) } @@ -115,7 +115,7 @@ impl embedded_hal::blocking::delay::DelayMs for Delay { impl embedded_hal::blocking::delay::DelayMs for Delay { type Error = Infallible; - fn try_delay_ms(&mut self, n: u16) -> Result<(), Self::Error> { + fn delay_ms(&mut self, n: u16) -> Result<(), Self::Error> { thread::sleep(Duration::from_millis(u64(n))); Ok(()) } @@ -124,7 +124,7 @@ impl embedded_hal::blocking::delay::DelayMs for Delay { impl embedded_hal::blocking::delay::DelayMs for Delay { type Error = Infallible; - fn try_delay_ms(&mut self, n: u32) -> Result<(), Self::Error> { + fn delay_ms(&mut self, n: u32) -> Result<(), Self::Error> { thread::sleep(Duration::from_millis(u64(n))); Ok(()) } @@ -133,7 +133,7 @@ impl embedded_hal::blocking::delay::DelayMs for Delay { impl embedded_hal::blocking::delay::DelayMs for Delay { type Error = Infallible; - fn try_delay_ms(&mut self, n: u64) -> Result<(), Self::Error> { + fn delay_ms(&mut self, n: u64) -> Result<(), Self::Error> { thread::sleep(Duration::from_millis(n)); Ok(()) } @@ -176,7 +176,7 @@ impl I2cdev { impl embedded_hal::blocking::i2c::Read for I2cdev { type Error = i2cdev::linux::LinuxI2CError; - fn try_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { self.set_address(address)?; self.inner.read(buffer) } @@ -185,7 +185,7 @@ impl embedded_hal::blocking::i2c::Read for I2cdev { impl embedded_hal::blocking::i2c::Write for I2cdev { type Error = i2cdev::linux::LinuxI2CError; - fn try_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { + fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { self.set_address(address)?; self.inner.write(bytes) } @@ -194,7 +194,7 @@ impl embedded_hal::blocking::i2c::Write for I2cdev { impl embedded_hal::blocking::i2c::WriteRead for I2cdev { type Error = i2cdev::linux::LinuxI2CError; - fn try_write_read( + fn write_read( &mut self, address: u8, bytes: &[u8], @@ -209,11 +209,7 @@ impl embedded_hal::blocking::i2c::WriteRead for I2cdev { impl embedded_hal::blocking::i2c::Transactional for I2cdev { type Error = i2cdev::linux::LinuxI2CError; - fn try_exec( - &mut self, - address: u8, - operations: &mut [I2cOperation], - ) -> Result<(), Self::Error> { + fn exec(&mut self, address: u8, operations: &mut [I2cOperation]) -> Result<(), Self::Error> { // Map operations from generic to linux objects let mut messages: Vec<_> = operations .as_mut() @@ -263,7 +259,7 @@ impl Spidev { impl embedded_hal::blocking::spi::Transfer for Spidev { type Error = io::Error; - fn try_transfer<'b>(&mut self, buffer: &'b mut [u8]) -> io::Result<&'b [u8]> { + fn transfer<'b>(&mut self, buffer: &'b mut [u8]) -> io::Result<&'b [u8]> { let tx = buffer.to_owned(); self.0 .transfer(&mut SpidevTransfer::read_write(&tx, buffer))?; @@ -274,7 +270,7 @@ impl embedded_hal::blocking::spi::Transfer for Spidev { impl embedded_hal::blocking::spi::Write for Spidev { type Error = io::Error; - fn try_write(&mut self, buffer: &[u8]) -> io::Result<()> { + fn write(&mut self, buffer: &[u8]) -> io::Result<()> { self.0.write_all(buffer) } } @@ -285,7 +281,7 @@ pub use embedded_hal::blocking::spi::Operation as SpiOperation; impl embedded_hal::blocking::spi::Transactional for Spidev { type Error = io::Error; - fn try_exec<'a>(&mut self, operations: &mut [SpiOperation<'a, u8>]) -> Result<(), Self::Error> { + fn exec<'a>(&mut self, operations: &mut [SpiOperation<'a, u8>]) -> Result<(), Self::Error> { // Map types from generic to linux objects let mut messages: Vec<_> = operations .iter_mut() diff --git a/src/serial.rs b/src/serial.rs index 102849c..ed9b338 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -32,7 +32,7 @@ fn translate_io_errors(err: std::io::Error) -> nb::Error { impl embedded_hal::serial::Read for Serial { type Error = IoErrorKind; - fn try_read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { let mut buffer = [0; 1]; let bytes_read = self.0.read(&mut buffer).map_err(translate_io_errors)?; if bytes_read == 1 { @@ -46,12 +46,12 @@ impl embedded_hal::serial::Read for Serial { impl embedded_hal::serial::Write for Serial { type Error = IoErrorKind; - fn try_write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.0.write(&[word]).map_err(translate_io_errors)?; Ok(()) } - fn try_flush(&mut self) -> nb::Result<(), Self::Error> { + fn flush(&mut self) -> nb::Result<(), Self::Error> { self.0.flush().map_err(translate_io_errors) } } @@ -75,20 +75,20 @@ mod test { #[test] fn test_empty_read() { let (mut _master, mut serial) = create_pty_and_serial(); - assert_eq!(Err(nb::Error::WouldBlock), serial.try_read()); + assert_eq!(Err(nb::Error::WouldBlock), serial.read()); } #[test] fn test_read() { let (mut master, mut serial) = create_pty_and_serial(); master.write(&[1]).expect("Write failed"); - assert_eq!(Ok(1), serial.try_read()); + assert_eq!(Ok(1), serial.read()); } #[test] fn test_write() { let (mut master, mut serial) = create_pty_and_serial(); - serial.try_write(2).expect("Write failed"); + serial.write(2).expect("Write failed"); let mut buf = [0; 2]; assert_eq!(1, master.read(&mut buf).unwrap()); assert_eq!(buf, [2, 0]); diff --git a/src/sysfs_pin.rs b/src/sysfs_pin.rs index b1ccae8..77ca3b3 100644 --- a/src/sysfs_pin.rs +++ b/src/sysfs_pin.rs @@ -29,11 +29,11 @@ impl SysfsPin { impl embedded_hal::digital::OutputPin for SysfsPin { type Error = sysfs_gpio::Error; - fn try_set_low(&mut self) -> Result<(), Self::Error> { + fn set_low(&mut self) -> Result<(), Self::Error> { self.0.set_value(0) } - fn try_set_high(&mut self) -> Result<(), Self::Error> { + fn set_high(&mut self) -> Result<(), Self::Error> { self.0.set_value(1) } } @@ -41,7 +41,7 @@ impl embedded_hal::digital::OutputPin for SysfsPin { impl embedded_hal::digital::InputPin for SysfsPin { type Error = sysfs_gpio::Error; - fn try_is_high(&self) -> Result { + fn is_high(&self) -> Result { if !self.0.get_active_low()? { self.0.get_value().map(|val| val != 0) } else { @@ -49,20 +49,20 @@ impl embedded_hal::digital::InputPin for SysfsPin { } } - fn try_is_low(&self) -> Result { - self.try_is_high().map(|val| !val) + fn is_low(&self) -> Result { + self.is_high().map(|val| !val) } } impl embedded_hal::digital::IoPin for SysfsPin { type Error = sysfs_gpio::Error; - fn try_into_input_pin(self) -> Result { + fn into_input_pin(self) -> Result { self.set_direction(sysfs_gpio::Direction::In)?; Ok(self) } - fn try_into_output_pin( + fn into_output_pin( self, state: embedded_hal::digital::PinState, ) -> Result { diff --git a/src/timer.rs b/src/timer.rs index 0b26b19..b32bafb 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -31,7 +31,7 @@ impl CountDown for SysTimer { type Error = Infallible; type Time = Duration; - fn try_start(&mut self, count: T) -> Result<(), Self::Error> + fn start(&mut self, count: T) -> Result<(), Self::Error> where T: Into, { @@ -40,7 +40,7 @@ impl CountDown for SysTimer { Ok(()) } - fn try_wait(&mut self) -> nb::Result<(), Self::Error> { + fn wait(&mut self) -> nb::Result<(), Self::Error> { if (Instant::now() - self.start) >= self.duration { // Restart the timer to fulfill the contract by `Periodic` self.start = Instant::now(); @@ -63,8 +63,8 @@ mod tests { fn test_delay() { let mut timer = SysTimer::new(); let before = Instant::now(); - timer.try_start(Duration::from_millis(100)).unwrap(); - nb::block!(timer.try_wait()).unwrap(); + timer.start(Duration::from_millis(100)).unwrap(); + nb::block!(timer.wait()).unwrap(); let after = Instant::now(); let duration_ms = (after - before).as_millis(); assert!(duration_ms >= 100); @@ -76,13 +76,13 @@ mod tests { fn test_periodic() { let mut timer = SysTimer::new(); let before = Instant::now(); - timer.try_start(Duration::from_millis(100)).unwrap(); - nb::block!(timer.try_wait()).unwrap(); + timer.start(Duration::from_millis(100)).unwrap(); + nb::block!(timer.wait()).unwrap(); let after1 = Instant::now(); let duration_ms_1 = (after1 - before).as_millis(); assert!(duration_ms_1 >= 100); assert!(duration_ms_1 < 500); - nb::block!(timer.try_wait()).unwrap(); + nb::block!(timer.wait()).unwrap(); let after2 = Instant::now(); let duration_ms_2 = (after2 - after1).as_millis(); assert!(duration_ms_2 >= 100);