From 77c3a704909d08cd2a65a7c3a823efe8a0aa7af1 Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Wed, 10 Apr 2024 15:14:10 +0300 Subject: [PATCH 01/10] Update embedded-hal to 1.0.0 HAL 1.0.0 substantially changes API, which in turn changed the crate API (mut requirements). It is a breaking change. --- Cargo.toml | 6 ++--- src/input/mod.rs | 12 ++++----- src/lib.rs | 4 +-- src/mock.rs | 56 +++++++++++++++++++++++----------------- src/output/mod.rs | 20 +++++++------- tests/input.rs | 12 ++++----- tests/output.rs | 24 ++++++++--------- tests/pin_into_switch.rs | 10 +++---- 8 files changed, 76 insertions(+), 68 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 021cd9f..966dbd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "switch-hal" -version = "0.4.0" +version = "0.5.0" authors = ["Christopher J. McClellan "] edition = "2018" description = "HAL and basic implementations for input and output switches (buttons, switches, leds, transistors)" @@ -17,5 +17,5 @@ exclude = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies.embedded-hal] -version = "0.2.5" -features = [ "unproven" ] \ No newline at end of file +version = "1.0" +#features = [ "unproven" ] \ No newline at end of file diff --git a/src/input/mod.rs b/src/input/mod.rs index 61ff01f..f06576d 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1,18 +1,18 @@ use crate::{ActiveHigh, ActiveLow, InputSwitch, Switch}; -use embedded_hal::digital::v2::InputPin; +use embedded_hal::digital::{ErrorType, InputPin}; -impl InputSwitch for Switch { - type Error = ::Error; +impl InputSwitch for Switch { + type Error = ::Error; - fn is_active(&self) -> Result { + fn is_active(&mut self) -> Result { self.pin.is_high() } } impl InputSwitch for Switch { - type Error = ::Error; + type Error = ::Error; - fn is_active(&self) -> Result { + fn is_active(&mut self) -> Result { self.pin.is_low() } } diff --git a/src/lib.rs b/src/lib.rs index 1f8271f..bd268f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,14 +19,14 @@ pub trait InputSwitch { /// use switch_hal::{InputSwitch, OutputSwitch, Switch, IntoSwitch}; /// # let pin = mock::Pin::with_state(mock::State::High); /// # let mut status_led = mock::Pin::new().into_active_high_switch(); - /// let button = pin.into_active_low_switch(); + /// let mut button = pin.into_active_low_switch(); /// match button.is_active() { /// Ok(true) => { status_led.on().ok(); } /// Ok(false) => { status_led.off().ok(); } /// Err(_) => { panic!("Failed to read button state"); } /// } /// ``` - fn is_active(&self) -> Result; + fn is_active(&mut self) -> Result; } /// Represents an output switch, such as a LED "switch" or transistor diff --git a/src/mock.rs b/src/mock.rs index f839299..44e572f 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -5,8 +5,8 @@ //! //! This is part of the main crate so it is accessible to doctests. //! Otherwise, I would have created a tests/mock/mod.rs file. -use embedded_hal::digital::v2::toggleable; -use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; + +use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; #[derive(PartialEq, Eq, Debug)] pub enum State { @@ -28,20 +28,30 @@ impl Pin { } } -type MockError = &'static str; +#[derive(Debug)] +#[allow(dead_code)] +pub struct MockError(&'static str); -impl InputPin for Pin { +impl embedded_hal::digital::Error for MockError { + fn kind(&self) -> embedded_hal::digital::ErrorKind { + embedded_hal::digital::ErrorKind::Other + } +} + +impl ErrorType for Pin { type Error = MockError; +} - fn is_high(&self) -> Result { +impl InputPin for Pin { + fn is_high(&mut self) -> Result { match self.state { Some(State::High) => Ok(true), Some(State::Low) => Ok(false), - None => Err("state not set"), + None => Err(MockError("state not set")), } } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { match self.is_high() { Ok(v) => Ok(!v), Err(e) => Err(e), @@ -50,8 +60,6 @@ impl InputPin for Pin { } impl OutputPin for Pin { - type Error = MockError; - fn set_low(&mut self) -> Result<(), Self::Error> { self.state = Some(State::Low); Ok(()) @@ -64,16 +72,16 @@ impl OutputPin for Pin { } impl StatefulOutputPin for Pin { - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { self.is_low() } - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { self.is_high() } } -impl toggleable::Default for Pin {} +// impl toggleable::Default for Pin {} #[cfg(test)] mod test { @@ -84,7 +92,7 @@ mod test { #[test] fn state_is_uninitialized() { - let pin = Pin::new(); + let mut pin = Pin::new(); assert_eq!(None, pin.state); pin.is_low().expect_err("Expected uninitialized pin"); } @@ -95,7 +103,7 @@ mod test { #[test] fn error_when_uninitialized() { - let pin = Pin { state: None }; + let mut pin = Pin { state: None }; pin.is_high().expect_err("Expected uninitialized pin"); } @@ -104,13 +112,13 @@ mod test { #[test] fn returns_true_when_state_is_high() { - let pin = Pin::with_state(State::High); + let mut pin = Pin::with_state(State::High); assert_eq!(true, pin.is_high().unwrap()); } #[test] fn returns_false_when_state_is_low() { - let pin = Pin::with_state(State::Low); + let mut pin = Pin::with_state(State::Low); assert_eq!(false, pin.is_high().unwrap()); } } @@ -120,13 +128,13 @@ mod test { #[test] fn returns_false_when_state_is_high() { - let pin = Pin::with_state(State::High); + let mut pin = Pin::with_state(State::High); assert_eq!(false, pin.is_low().unwrap()); } #[test] fn returns_true_when_state_is_high() { - let pin = Pin::with_state(State::Low); + let mut pin = Pin::with_state(State::Low); assert_eq!(true, pin.is_low().unwrap()); } } @@ -157,7 +165,7 @@ mod test { #[test] fn error_when_uninitialized() { - let pin = Pin { state: None }; + let mut pin = Pin { state: None }; pin.is_set_high().expect_err("Expected uninitialized pin"); } @@ -166,13 +174,13 @@ mod test { #[test] fn returns_false_when_state_is_high() { - let pin = Pin::with_state(State::High); + let mut pin = Pin::with_state(State::High); assert_eq!(false, pin.is_set_low().unwrap()); } #[test] fn returns_true_when_state_is_high() { - let pin = Pin::with_state(State::Low); + let mut pin = Pin::with_state(State::Low); assert_eq!(true, pin.is_set_low().unwrap()); } } @@ -182,20 +190,20 @@ mod test { #[test] fn returns_true_when_state_is_high() { - let pin = Pin::with_state(State::High); + let mut pin = Pin::with_state(State::High); assert_eq!(true, pin.is_set_high().unwrap()); } #[test] fn returns_false_when_state_is_low() { - let pin = Pin::with_state(State::Low); + let mut pin = Pin::with_state(State::Low); assert_eq!(false, pin.is_set_high().unwrap()); } } mod toggleable { use super::*; - use embedded_hal::digital::v2::ToggleableOutputPin; + use embedded_hal::digital::StatefulOutputPin; #[test] fn default_toggleable_impl() { diff --git a/src/output/mod.rs b/src/output/mod.rs index fbacf86..291f454 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -1,9 +1,9 @@ -use embedded_hal::digital::v2::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; +use embedded_hal::digital::{ErrorType, OutputPin, StatefulOutputPin}; use crate::{ActiveHigh, ActiveLow, OutputSwitch, Switch, StatefulOutputSwitch, ToggleableOutputSwitch}; -impl OutputSwitch for Switch { - type Error = ::Error; +impl OutputSwitch for Switch { + type Error = ::Error; fn on(&mut self) -> Result<(), Self::Error> { self.pin.set_high() @@ -14,8 +14,8 @@ impl OutputSwitch for Switch { } } -impl OutputSwitch for Switch { - type Error = ::Error; +impl OutputSwitch for Switch { + type Error = ::Error; fn on(&mut self) -> Result<(), Self::Error> { self.pin.set_low() @@ -26,20 +26,20 @@ impl OutputSwitch for Switch { } } -impl ToggleableOutputSwitch +impl ToggleableOutputSwitch for Switch { - type Error = ::Error; + type Error = ::Error; fn toggle(&mut self) -> Result<(), Self::Error> { self.pin.toggle() } } -impl StatefulOutputSwitch +impl StatefulOutputSwitch for Switch { - type Error = ::Error; + type Error = ::Error; fn is_on(&mut self) -> Result { self.pin.is_set_low() @@ -53,7 +53,7 @@ impl StatefulOutputSwitch impl StatefulOutputSwitch for Switch { - type Error = ::Error; + type Error = ::Error; fn is_on(&mut self) -> Result { self.pin.is_set_high() diff --git a/tests/input.rs b/tests/input.rs index 6688c8d..9f17e19 100644 --- a/tests/input.rs +++ b/tests/input.rs @@ -15,7 +15,7 @@ mod active_high_switch { fn true_when_pin_high() { let pin = Pin::with_state(State::High); - let button = Switch::<_, ActiveHigh>::new(pin); + let mut button = Switch::<_, ActiveHigh>::new(pin); assert_eq!(true, button.is_active().unwrap()); } @@ -23,14 +23,14 @@ mod active_high_switch { fn false_when_pin_low() { let pin = Pin::with_state(State::Low); - let button = Switch::<_, ActiveHigh>::new(pin); + let mut button = Switch::<_, ActiveHigh>::new(pin); assert_eq!(false, button.is_active().unwrap()); } #[test] fn propagates_errors_from_pin() { let pin = Pin::new(); - let button = Switch::<_, ActiveHigh>::new(pin); + let mut button = Switch::<_, ActiveHigh>::new(pin); button.is_active().expect_err("Expected uninitialized error"); } } @@ -48,7 +48,7 @@ mod active_low_switch { fn false_when_pin_high() { let pin = Pin::with_state(State::High); - let button = Switch::<_, ActiveLow>::new(pin); + let mut button = Switch::<_, ActiveLow>::new(pin); assert_eq!(false, button.is_active().unwrap()); } @@ -56,14 +56,14 @@ mod active_low_switch { fn true_when_pin_low() { let pin = Pin::with_state(State::Low); - let button = Switch::<_, ActiveLow>::new(pin); + let mut button = Switch::<_, ActiveLow>::new(pin); assert_eq!(true, button.is_active().unwrap()); } #[test] fn propagates_errors_from_pin() { let pin = Pin::new(); - let button = Switch::<_, ActiveLow>::new(pin); + let mut button = Switch::<_, ActiveLow>::new(pin); button.is_active().expect_err("Expected uninitialized error"); } } diff --git a/tests/output.rs b/tests/output.rs index 7015b93..e874756 100644 --- a/tests/output.rs +++ b/tests/output.rs @@ -4,7 +4,7 @@ use switch_hal::mock; mod active_high_switch { use super::*; - use embedded_hal::digital::v2::InputPin; + use embedded_hal::digital::InputPin; use switch_hal::{ActiveHigh, OutputSwitch, Switch}; #[test] @@ -14,7 +14,7 @@ mod active_high_switch { let mut led = Switch::<_, ActiveHigh>::new(pin); led.on().unwrap(); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(true, pin.is_high().unwrap()); } @@ -25,7 +25,7 @@ mod active_high_switch { let mut led = Switch::<_, ActiveHigh>::new(pin); led.off().unwrap(); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(true, pin.is_low().unwrap()); } @@ -40,7 +40,7 @@ mod active_high_switch { led.toggle().unwrap(); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(true, pin.is_high().unwrap()); } @@ -55,7 +55,7 @@ mod active_high_switch { assert_eq!(false, led.is_on().unwrap()); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(false, pin.is_high().unwrap()); } @@ -70,14 +70,14 @@ mod active_high_switch { assert_eq!(true, led.is_on().unwrap()); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(true, pin.is_high().unwrap()); } } mod active_low_switch { use super::*; - use embedded_hal::digital::v2::InputPin; + use embedded_hal::digital::InputPin; use switch_hal::{ActiveLow, OutputSwitch, Switch}; #[test] @@ -87,7 +87,7 @@ mod active_low_switch { let mut led = Switch::<_, ActiveLow>::new(pin); led.on().unwrap(); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(true, pin.is_low().unwrap()); } @@ -98,7 +98,7 @@ mod active_low_switch { let mut led = Switch::<_, ActiveLow>::new(pin); led.off().unwrap(); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(true, pin.is_high().unwrap()); } @@ -113,7 +113,7 @@ mod active_low_switch { led.toggle().unwrap(); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(true, pin.is_low().unwrap()); } @@ -128,7 +128,7 @@ mod active_low_switch { assert_eq!(false, led.is_on().unwrap()); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(false, pin.is_low().unwrap()); } @@ -143,7 +143,7 @@ mod active_low_switch { assert_eq!(true, led.is_on().unwrap()); - let pin = led.into_pin(); + let mut pin = led.into_pin(); assert_eq!(true, pin.is_low().unwrap()); } } diff --git a/tests/pin_into_switch.rs b/tests/pin_into_switch.rs index a6fd435..7097085 100644 --- a/tests/pin_into_switch.rs +++ b/tests/pin_into_switch.rs @@ -4,7 +4,7 @@ use switch_hal::IntoSwitch; mod output_pin { use super::*; - use embedded_hal::digital::v2::InputPin; + use embedded_hal::digital::InputPin; use switch_hal::OutputSwitch; #[test] @@ -13,7 +13,7 @@ mod output_pin { let mut switch = pin.into_active_high_switch(); switch.on().unwrap(); - let pin = switch.into_pin(); + let mut pin = switch.into_pin(); assert_eq!(true, pin.is_high().unwrap()); } @@ -23,7 +23,7 @@ mod output_pin { let mut switch = pin.into_active_low_switch(); switch.on().unwrap(); - let pin = switch.into_pin(); + let mut pin = switch.into_pin(); assert_eq!(true, pin.is_low().unwrap()); } } @@ -35,14 +35,14 @@ mod input_pin { #[test] fn active_high() { let pin = Pin::with_state(State::High); - let switch = pin.into_active_high_switch(); + let mut switch = pin.into_active_high_switch(); assert_eq!(true, switch.is_active().unwrap()); } #[test] fn active_low() { let pin = Pin::with_state(State::Low); - let switch = pin.into_active_low_switch(); + let mut switch = pin.into_active_low_switch(); assert_eq!(true, switch.is_active().unwrap()); } } From 5686c24e3c5e496a33ae909dcc1bcbd4ab97fbe1 Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Wed, 10 Apr 2024 15:43:49 +0300 Subject: [PATCH 02/10] Documentation update to reflext the hal changes --- src/lib.rs | 24 ++++++++++++------------ src/mock.rs | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bd268f1..df8eff0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,11 +63,11 @@ pub trait OutputSwitch { /// Toggles the switch from it's current state to it's opposite state. /// /// # Notes -/// This is only available if the underlying hal has implemented [ToggleableOutputPin](embedded_hal::digital::v2::ToggleableOutputPin) +/// This is only available if the underlying hal has implemented [StatefulOutputPin](embedded_hal::digital::StatefulOutputPin) pub trait ToggleableOutputSwitch { type Error; - /// Toggles the current state of the [OutputSwitch](OutputSwitch) + /// Toggles the current state of the [OutputSwitch] /// /// # Examples /// @@ -84,7 +84,7 @@ pub trait ToggleableOutputSwitch { /// Checks current switch state /// /// # Notes -/// This is only available if the underlying hal has implemented [StatefulOutputPin](embedded_hal::digital::v2::StatefulOutputPin) +/// This is only available if the underlying hal has implemented [StatefulOutputPin](embedded_hal::digital::StatefulOutputPin) pub trait StatefulOutputSwitch { type Error; @@ -127,10 +127,10 @@ use core::marker::PhantomData; /// Concrete implementation for [InputSwitch](trait.InputSwitch.html) and [OutputSwitch](trait.OutputSwitch.html) /// /// # Type Params -/// - `IoPin` must be a type that implements either of the [InputPin](embedded_hal::digital::v2::InputPin) or [OutputPin](embedded_hal::digital::v2::OutputPin) traits. -/// - `ActiveLevel` indicates whether the `Switch` is [ActiveHigh](ActiveHigh) or [ActiveLow](ActiveLow). +/// - `IoPin` must be a type that implements either of the [InputPin](embedded_hal::digital::InputPin) or [OutputPin](embedded_hal::digital::OutputPin) traits. +/// - `ActiveLevel` indicates whether the `Switch` is [ActiveHigh] or [ActiveLow]. /// `ActiveLevel` is not actually stored in the struct. -/// It's [PhantomData](core::marker::PhantomData) used to indicate which implementation to use. +/// It's [PhantomData] used to indicate which implementation to use. pub struct Switch { pin: IoPin, active: PhantomData, @@ -138,7 +138,7 @@ pub struct Switch { impl Switch { /// Constructs a new [Switch](struct.Switch.html) from a concrete implementation of an - /// [InputPin](embedded_hal::digital::v2::InputPin) or [OutputPin](embedded_hal::digital::v2::OutputPin) + /// [InputPin](embedded_hal::digital::InputPin) or [OutputPin](embedded_hal::digital::OutputPin) /// /// **Prefer the [IntoSwitch](trait.IntoSwitch.html) trait over calling [new](#method.new) directly.** /// @@ -188,7 +188,7 @@ impl Switch { } } - /// Consumes the [Switch](struct.Switch.html) and returns the underlying [InputPin](embedded_hal::digital::v2::InputPin) or [OutputPin](embedded_hal::digital::v2::OutputPin). + /// Consumes the [Switch](struct.Switch.html) and returns the underlying [InputPin](embedded_hal::digital::InputPin) or [OutputPin](embedded_hal::digital::OutputPin). /// /// This is useful fore retrieving the underlying pin to use it for a different purpose. /// @@ -208,13 +208,13 @@ impl Switch { } } -/// Convenience functions for converting [InputPin](embedded_hal::digital::v2::InputPin) -/// and [OutputPin](embedded_hal::digital::v2::OutputPin) to a [Switch](struct.Switch.html). +/// Convenience functions for converting [InputPin](embedded_hal::digital::InputPin) +/// and [OutputPin](embedded_hal::digital::OutputPin) to a [Switch](struct.Switch.html). /// /// The type of [Switch](struct.Switch.html) returned, /// [InputSwitch](trait.InputSwitch.html) or [OutputSwitch](trait.OutputSwitch.html) is -/// determined by whether the `IoPin` being consumed is an [InputPin](embedded_hal::digital::v2::InputPin) -/// or [OutputPin](embedded_hal::digital::v2::OutputPin). +/// determined by whether the `IoPin` being consumed is an [InputPin](embedded_hal::digital::InputPin) +/// or [OutputPin](embedded_hal::digital::OutputPin). pub trait IntoSwitch { /// Consumes the `IoPin` returning a [Switch](struct.Switch.html) of the appropriate `ActiveLevel`. diff --git a/src/mock.rs b/src/mock.rs index 44e572f..5099034 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -1,7 +1,7 @@ -//! Mock implementations of [InputPin](embedded_hal::digital::v2::InputPin) and [OutputPin](embedded_hal::digital::v2::OutputPin). +//! Mock implementations of [InputPin] and [OutputPin] //! //! WARNING: May be removed if `embedded_hal_mock` crate is improved. -//! https://github.com/dbrgn/embedded-hal-mock/issues/30 +//! //! //! This is part of the main crate so it is accessible to doctests. //! Otherwise, I would have created a tests/mock/mod.rs file. From 1cce9635b1e4e5e8f39bbe81fdaca87bdc957601 Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Wed, 10 Apr 2024 16:30:32 +0300 Subject: [PATCH 03/10] Cleanup unneeded trait boundaries --- src/input/mod.rs | 2 +- src/output/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index f06576d..8b79c99 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1,7 +1,7 @@ use crate::{ActiveHigh, ActiveLow, InputSwitch, Switch}; use embedded_hal::digital::{ErrorType, InputPin}; -impl InputSwitch for Switch { +impl InputSwitch for Switch { type Error = ::Error; fn is_active(&mut self) -> Result { diff --git a/src/output/mod.rs b/src/output/mod.rs index 291f454..2bf6223 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -2,7 +2,7 @@ use embedded_hal::digital::{ErrorType, OutputPin, StatefulOutputPin}; use crate::{ActiveHigh, ActiveLow, OutputSwitch, Switch, StatefulOutputSwitch, ToggleableOutputSwitch}; -impl OutputSwitch for Switch { +impl OutputSwitch for Switch { type Error = ::Error; fn on(&mut self) -> Result<(), Self::Error> { @@ -14,7 +14,7 @@ impl OutputSwitch for Switch { } } -impl OutputSwitch for Switch { +impl OutputSwitch for Switch { type Error = ::Error; fn on(&mut self) -> Result<(), Self::Error> { @@ -36,7 +36,7 @@ impl ToggleableOutputSwitch } } -impl StatefulOutputSwitch +impl StatefulOutputSwitch for Switch { type Error = ::Error; From c0ade87f8e132c3f84fae1399ae19893310b019d Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Tue, 16 Apr 2024 16:41:01 +0300 Subject: [PATCH 04/10] Async implementation --- Cargo.toml | 16 ++++++- src/input/mod.rs | 52 ++++++++++++++++++++ src/lib.rs | 13 ++++- src/mock.rs | 120 +++++++++++++++++++++++++++++++++++++++++++++- src/output/mod.rs | 12 ++--- tests/input.rs | 8 +++- 6 files changed, 208 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 966dbd6..1bd088e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,20 @@ exclude = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["async"] +# default = [] +async = ["dep:embedded-hal-async"] + [dependencies.embedded-hal] version = "1.0" -#features = [ "unproven" ] \ No newline at end of file + +[dependencies.embedded-hal-async] +version = "1.0" +optional = true + +[dev-dependencies.noop-waker] +version = "0.1" + +[dev-dependencies.assert_matches] +version = "1.5" \ No newline at end of file diff --git a/src/input/mod.rs b/src/input/mod.rs index 8b79c99..d65f114 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1,5 +1,9 @@ +#[cfg(feature = "async")] +use crate::WaitableInputSwitch; use crate::{ActiveHigh, ActiveLow, InputSwitch, Switch}; use embedded_hal::digital::{ErrorType, InputPin}; +#[cfg(feature = "async")] +use embedded_hal_async::digital::Wait; impl InputSwitch for Switch { type Error = ::Error; @@ -16,3 +20,51 @@ impl InputSwitch for Switch { self.pin.is_low() } } + +#[cfg(feature = "async")] +impl WaitableInputSwitch for Switch +where + Switch: InputSwitch, +{ + type Error = ::Error; + + async fn wait_for_active(&mut self) -> Result<(), Self::Error> { + self.pin.wait_for_high().await + } + + async fn wait_for_inactive(&mut self) -> Result<(), Self::Error> { + self.pin.wait_for_low().await + } + + async fn wait_for_change(&mut self) -> Result<(), Self::Error> { + if self.pin.is_high()? { + self.pin.wait_for_low().await + } else { + self.pin.wait_for_high().await + } + } +} + +#[cfg(feature = "async")] +impl WaitableInputSwitch for Switch +where + Switch: InputSwitch, +{ + type Error = ::Error; + + async fn wait_for_active(&mut self) -> Result<(), Self::Error> { + self.pin.wait_for_low().await + } + + async fn wait_for_inactive(&mut self) -> Result<(), Self::Error> { + self.pin.wait_for_high().await + } + + async fn wait_for_change(&mut self) -> Result<(), Self::Error> { + if self.pin.is_high()? { + self.pin.wait_for_low().await + } else { + self.pin.wait_for_high().await + } + } +} diff --git a/src/lib.rs b/src/lib.rs index df8eff0..469ad29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(async_fn_in_trait)] mod input; mod output; @@ -29,6 +30,15 @@ pub trait InputSwitch { fn is_active(&mut self) -> Result; } +#[cfg(feature = "async")] +pub trait WaitableInputSwitch { + type Error; + + async fn wait_for_active(&mut self) -> Result<(), Self::Error>; + async fn wait_for_inactive(&mut self) -> Result<(), Self::Error>; + async fn wait_for_change(&mut self) -> Result<(), Self::Error>; +} + /// Represents an output switch, such as a LED "switch" or transistor pub trait OutputSwitch { type Error; @@ -183,7 +193,7 @@ impl Switch { /// ``` pub fn new(pin: IoPin) -> Self { Switch { - pin: pin, + pin, active: PhantomData::, } } @@ -216,7 +226,6 @@ impl Switch { /// determined by whether the `IoPin` being consumed is an [InputPin](embedded_hal::digital::InputPin) /// or [OutputPin](embedded_hal::digital::OutputPin). pub trait IntoSwitch { - /// Consumes the `IoPin` returning a [Switch](struct.Switch.html) of the appropriate `ActiveLevel`. /// /// This method exists so other, more convenient functions, can have blanket implementations. diff --git a/src/mock.rs b/src/mock.rs index 5099034..4b75dad 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -6,7 +6,10 @@ //! This is part of the main crate so it is accessible to doctests. //! Otherwise, I would have created a tests/mock/mod.rs file. +use core::{future::poll_fn, task::Poll}; + use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; +use embedded_hal_async::digital::Wait; #[derive(PartialEq, Eq, Debug)] pub enum State { @@ -18,6 +21,12 @@ pub struct Pin { state: Option, } +impl Default for Pin { + fn default() -> Self { + Self::new() + } +} + impl Pin { pub fn new() -> Self { Pin { state: None } @@ -81,7 +90,47 @@ impl StatefulOutputPin for Pin { } } -// impl toggleable::Default for Pin {} +impl Wait for Pin { + async fn wait_for_high(&mut self) -> Result<(), Self::Error> { + poll_fn(|_cx| { + if self.state == Some(State::High) { + Poll::Ready(Ok(())) + } else { + Poll::Pending + } + }) + .await + } + + async fn wait_for_low(&mut self) -> Result<(), Self::Error> { + poll_fn(|_cx| { + if self.state == Some(State::Low) { + Poll::Ready(Ok(())) + } else { + Poll::Pending + } + }) + .await + } + + async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_low().await?; + self.wait_for_high().await + } + + async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_high().await?; + self.wait_for_low().await + } + + async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { + if self.is_high()? { + self.wait_for_falling_edge().await + } else { + self.wait_for_rising_edge().await + } + } +} #[cfg(test)] mod test { @@ -138,6 +187,75 @@ mod test { assert_eq!(true, pin.is_low().unwrap()); } } + + mod asynch { + use core::future::Future; + use core::pin::pin; + use core::task::Context; + use noop_waker::noop_waker; + + use super::*; + + #[test] + fn wait_for_high_while_high() { + let mut pin = Pin::with_state(State::High); + let mut future = pin!(pin.wait_for_high()); + let waker = noop_waker(); + let mut cx = Context::from_waker(&waker); + + assert!(matches!(future.as_mut().poll(&mut cx), Poll::Ready(_))) + } + + #[test] + fn wait_for_high_while_low() { + let mut pin = Pin::with_state(State::Low); + let mut future = pin!(pin.wait_for_high()); + let waker = noop_waker(); + let mut cx = Context::from_waker(&waker); + + assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending)); + } + + #[test] + fn wait_for_low_while_low() { + let mut pin = Pin::with_state(State::Low); + let mut future = pin!(pin.wait_for_low()); + let waker = noop_waker(); + let mut cx = Context::from_waker(&waker); + + assert!(matches!(future.as_mut().poll(&mut cx), Poll::Ready(_))); + } + + #[test] + fn wait_for_low_while_high() { + let mut pin = Pin::with_state(State::High); + let mut future = pin!(pin.wait_for_low()); + let waker = noop_waker(); + let mut cx = Context::from_waker(&waker); + + assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending)); + } + + #[test] + fn wait_for_any_edge_while_high() { + let mut pin = Pin::with_state(State::High); + let mut future = pin!(pin.wait_for_any_edge()); + let waker = noop_waker(); + let mut cx = Context::from_waker(&waker); + + assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending)); + } + + #[test] + fn wait_for_any_edge_while_low() { + let mut pin = Pin::with_state(State::Low); + let mut future = pin!(pin.wait_for_any_edge()); + let waker = noop_waker(); + let mut cx = Context::from_waker(&waker); + + assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending)); + } + } } mod output_pin { diff --git a/src/output/mod.rs b/src/output/mod.rs index 2bf6223..47c3a3a 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -1,6 +1,8 @@ use embedded_hal::digital::{ErrorType, OutputPin, StatefulOutputPin}; -use crate::{ActiveHigh, ActiveLow, OutputSwitch, Switch, StatefulOutputSwitch, ToggleableOutputSwitch}; +use crate::{ + ActiveHigh, ActiveLow, OutputSwitch, StatefulOutputSwitch, Switch, ToggleableOutputSwitch, +}; impl OutputSwitch for Switch { type Error = ::Error; @@ -36,9 +38,7 @@ impl ToggleableOutputSwitch } } -impl StatefulOutputSwitch - for Switch -{ +impl StatefulOutputSwitch for Switch { type Error = ::Error; fn is_on(&mut self) -> Result { @@ -50,9 +50,7 @@ impl StatefulOutputSwitch } } -impl StatefulOutputSwitch - for Switch -{ +impl StatefulOutputSwitch for Switch { type Error = ::Error; fn is_on(&mut self) -> Result { diff --git a/tests/input.rs b/tests/input.rs index 9f17e19..8c328b0 100644 --- a/tests/input.rs +++ b/tests/input.rs @@ -31,7 +31,9 @@ mod active_high_switch { fn propagates_errors_from_pin() { let pin = Pin::new(); let mut button = Switch::<_, ActiveHigh>::new(pin); - button.is_active().expect_err("Expected uninitialized error"); + button + .is_active() + .expect_err("Expected uninitialized error"); } } } @@ -64,7 +66,9 @@ mod active_low_switch { fn propagates_errors_from_pin() { let pin = Pin::new(); let mut button = Switch::<_, ActiveLow>::new(pin); - button.is_active().expect_err("Expected uninitialized error"); + button + .is_active() + .expect_err("Expected uninitialized error"); } } } From 53c1ac4cc75a56d01ce9f3651284699d70bdb250 Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Tue, 16 Apr 2024 17:07:22 +0300 Subject: [PATCH 05/10] Make clippy happy --- Cargo.toml | 4 ++-- src/mock.rs | 27 ++++++++++++++------------- tests/input.rs | 8 ++++---- tests/output.rs | 28 ++++++++++++++-------------- tests/pin_into_switch.rs | 8 ++++---- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1bd088e..0bf0ae8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,8 @@ exclude = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["async"] -# default = [] +# default = ["async"] +default = [] async = ["dep:embedded-hal-async"] [dependencies.embedded-hal] diff --git a/src/mock.rs b/src/mock.rs index 4b75dad..1b5dc03 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -6,9 +6,8 @@ //! This is part of the main crate so it is accessible to doctests. //! Otherwise, I would have created a tests/mock/mod.rs file. -use core::{future::poll_fn, task::Poll}; - use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; +#[cfg(feature = "async")] use embedded_hal_async::digital::Wait; #[derive(PartialEq, Eq, Debug)] @@ -90,6 +89,7 @@ impl StatefulOutputPin for Pin { } } +#[cfg(feature = "async")] impl Wait for Pin { async fn wait_for_high(&mut self) -> Result<(), Self::Error> { poll_fn(|_cx| { @@ -162,13 +162,13 @@ mod test { #[test] fn returns_true_when_state_is_high() { let mut pin = Pin::with_state(State::High); - assert_eq!(true, pin.is_high().unwrap()); + assert!(pin.is_high().unwrap()); } #[test] fn returns_false_when_state_is_low() { let mut pin = Pin::with_state(State::Low); - assert_eq!(false, pin.is_high().unwrap()); + assert!(!pin.is_high().unwrap()); } } @@ -178,16 +178,17 @@ mod test { #[test] fn returns_false_when_state_is_high() { let mut pin = Pin::with_state(State::High); - assert_eq!(false, pin.is_low().unwrap()); + assert!(!pin.is_low().unwrap()); } #[test] fn returns_true_when_state_is_high() { let mut pin = Pin::with_state(State::Low); - assert_eq!(true, pin.is_low().unwrap()); + assert!(pin.is_low().unwrap()); } } + #[cfg(feature = "async")] mod asynch { use core::future::Future; use core::pin::pin; @@ -266,7 +267,7 @@ mod test { let mut pin = Pin::new(); pin.set_low().unwrap(); - assert_eq!(true, pin.is_low().unwrap()); + assert!(pin.is_low().unwrap()); } #[test] @@ -274,7 +275,7 @@ mod test { let mut pin = Pin::new(); pin.set_high().unwrap(); - assert_eq!(true, pin.is_high().unwrap()); + assert!(pin.is_high().unwrap()); } } @@ -293,13 +294,13 @@ mod test { #[test] fn returns_false_when_state_is_high() { let mut pin = Pin::with_state(State::High); - assert_eq!(false, pin.is_set_low().unwrap()); + assert!(!pin.is_set_low().unwrap()); } #[test] fn returns_true_when_state_is_high() { let mut pin = Pin::with_state(State::Low); - assert_eq!(true, pin.is_set_low().unwrap()); + assert!(pin.is_set_low().unwrap()); } } @@ -309,13 +310,13 @@ mod test { #[test] fn returns_true_when_state_is_high() { let mut pin = Pin::with_state(State::High); - assert_eq!(true, pin.is_set_high().unwrap()); + assert!(pin.is_set_high().unwrap()); } #[test] fn returns_false_when_state_is_low() { let mut pin = Pin::with_state(State::Low); - assert_eq!(false, pin.is_set_high().unwrap()); + assert!(!pin.is_set_high().unwrap()); } } @@ -327,7 +328,7 @@ mod test { fn default_toggleable_impl() { let mut pin = Pin::with_state(State::Low); pin.toggle().unwrap(); - assert_eq!(true, pin.is_set_high().unwrap()); + assert!(pin.is_set_high().unwrap()); } } } diff --git a/tests/input.rs b/tests/input.rs index 8c328b0..67e1dc1 100644 --- a/tests/input.rs +++ b/tests/input.rs @@ -16,7 +16,7 @@ mod active_high_switch { let pin = Pin::with_state(State::High); let mut button = Switch::<_, ActiveHigh>::new(pin); - assert_eq!(true, button.is_active().unwrap()); + assert!(button.is_active().unwrap()); } #[test] @@ -24,7 +24,7 @@ mod active_high_switch { let pin = Pin::with_state(State::Low); let mut button = Switch::<_, ActiveHigh>::new(pin); - assert_eq!(false, button.is_active().unwrap()); + assert!(!button.is_active().unwrap()); } #[test] @@ -51,7 +51,7 @@ mod active_low_switch { let pin = Pin::with_state(State::High); let mut button = Switch::<_, ActiveLow>::new(pin); - assert_eq!(false, button.is_active().unwrap()); + assert!(!button.is_active().unwrap()); } #[test] @@ -59,7 +59,7 @@ mod active_low_switch { let pin = Pin::with_state(State::Low); let mut button = Switch::<_, ActiveLow>::new(pin); - assert_eq!(true, button.is_active().unwrap()); + assert!(button.is_active().unwrap()); } #[test] diff --git a/tests/output.rs b/tests/output.rs index e874756..f9b11fe 100644 --- a/tests/output.rs +++ b/tests/output.rs @@ -15,7 +15,7 @@ mod active_high_switch { led.on().unwrap(); let mut pin = led.into_pin(); - assert_eq!(true, pin.is_high().unwrap()); + assert!(pin.is_high().unwrap()); } #[test] @@ -26,7 +26,7 @@ mod active_high_switch { led.off().unwrap(); let mut pin = led.into_pin(); - assert_eq!(true, pin.is_low().unwrap()); + assert!(pin.is_low().unwrap()); } #[test] @@ -41,7 +41,7 @@ mod active_high_switch { led.toggle().unwrap(); let mut pin = led.into_pin(); - assert_eq!(true, pin.is_high().unwrap()); + assert!(pin.is_high().unwrap()); } #[test] @@ -53,10 +53,10 @@ mod active_high_switch { let mut led = Switch::<_, ActiveHigh>::new(pin); led.off().unwrap(); - assert_eq!(false, led.is_on().unwrap()); + assert!(!led.is_on().unwrap()); let mut pin = led.into_pin(); - assert_eq!(false, pin.is_high().unwrap()); + assert!(!pin.is_high().unwrap()); } #[test] @@ -68,10 +68,10 @@ mod active_high_switch { let mut led = Switch::<_, ActiveHigh>::new(pin); led.on().unwrap(); - assert_eq!(true, led.is_on().unwrap()); + assert!(led.is_on().unwrap()); let mut pin = led.into_pin(); - assert_eq!(true, pin.is_high().unwrap()); + assert!(pin.is_high().unwrap()); } } @@ -88,7 +88,7 @@ mod active_low_switch { led.on().unwrap(); let mut pin = led.into_pin(); - assert_eq!(true, pin.is_low().unwrap()); + assert!(pin.is_low().unwrap()); } #[test] @@ -99,7 +99,7 @@ mod active_low_switch { led.off().unwrap(); let mut pin = led.into_pin(); - assert_eq!(true, pin.is_high().unwrap()); + assert!(pin.is_high().unwrap()); } #[test] @@ -114,7 +114,7 @@ mod active_low_switch { led.toggle().unwrap(); let mut pin = led.into_pin(); - assert_eq!(true, pin.is_low().unwrap()); + assert!(pin.is_low().unwrap()); } #[test] @@ -126,10 +126,10 @@ mod active_low_switch { let mut led = Switch::<_, ActiveLow>::new(pin); led.off().unwrap(); - assert_eq!(false, led.is_on().unwrap()); + assert!(!led.is_on().unwrap()); let mut pin = led.into_pin(); - assert_eq!(false, pin.is_low().unwrap()); + assert!(!pin.is_low().unwrap()); } #[test] @@ -141,9 +141,9 @@ mod active_low_switch { let mut led = Switch::<_, ActiveLow>::new(pin); led.on().unwrap(); - assert_eq!(true, led.is_on().unwrap()); + assert!(led.is_on().unwrap()); let mut pin = led.into_pin(); - assert_eq!(true, pin.is_low().unwrap()); + assert!(pin.is_low().unwrap()); } } diff --git a/tests/pin_into_switch.rs b/tests/pin_into_switch.rs index 7097085..3721e50 100644 --- a/tests/pin_into_switch.rs +++ b/tests/pin_into_switch.rs @@ -14,7 +14,7 @@ mod output_pin { switch.on().unwrap(); let mut pin = switch.into_pin(); - assert_eq!(true, pin.is_high().unwrap()); + assert!(pin.is_high().unwrap()); } #[test] @@ -24,7 +24,7 @@ mod output_pin { switch.on().unwrap(); let mut pin = switch.into_pin(); - assert_eq!(true, pin.is_low().unwrap()); + assert!(pin.is_low().unwrap()); } } @@ -36,13 +36,13 @@ mod input_pin { fn active_high() { let pin = Pin::with_state(State::High); let mut switch = pin.into_active_high_switch(); - assert_eq!(true, switch.is_active().unwrap()); + assert!(switch.is_active().unwrap()); } #[test] fn active_low() { let pin = Pin::with_state(State::Low); let mut switch = pin.into_active_low_switch(); - assert_eq!(true, switch.is_active().unwrap()); + assert!(switch.is_active().unwrap()); } } From d8315528986623f18386b7b5487b81aa700ff511 Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Tue, 16 Apr 2024 17:50:48 +0300 Subject: [PATCH 06/10] Cleanup and docs --- Cargo.toml | 1 - src/lib.rs | 29 +++++++++++++++++++++++++++++ src/mock.rs | 4 +++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0bf0ae8..31f4de7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ exclude = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -# default = ["async"] default = [] async = ["dep:embedded-hal-async"] diff --git a/src/lib.rs b/src/lib.rs index 469ad29..73e90b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,25 @@ +//! Switch-HAL is a no_std embedded Rust library for working with buttons, switches, LEDs, and transistors. Basically, anything that acts like a switch, whether an input or output. +//! +//! It is both a driver that uses the embedded-hal::digital traits and is an abstraction in it's own right. It provides a simple, zero-cost, abstraction to clarify the intent of your application code. +//! +//! Why Switch-HAL? Why not just use raw GPIO? +//! Did you mean to drive that line high? +//! Or did you mean to turn that LED off? +//! Wait a second... is that LED active high? +//! Where's the schematic? +//! Okay... cathode is wired to the input line... that means it's active low. +//! +//! Now repeat this every place in your code where you need to turn that LED on or off. +//! What happens when the hardware changes? +//! Using the raw GPIO to set pins high and low will have you making changes all over your code base. +//! +//! Wouldn't it be nicer if you only had to think about that once, when you initialize your application, +//! and from then on out, simply called led.on() or led.off(). +//! Having an abstraction at the proper level reduces cognitive load. +//! Specifying whether a simple peripheral is active high or low in a single place in your application reduces the maintenance burden. +//! +//! "Async" feature enables async support for input switches. + #![no_std] #![allow(async_fn_in_trait)] @@ -31,11 +53,18 @@ pub trait InputSwitch { } #[cfg(feature = "async")] +/// Represents an input switch that can be asynchronously waited for pub trait WaitableInputSwitch { type Error; + /// Waits until the switch becomes active. If the switch in already active, returns immediately + /// async fn wait_for_active(&mut self) -> Result<(), Self::Error>; + /// Waits until the switch becomes inactive. If the switch is already inactive, returns immediately + /// async fn wait_for_inactive(&mut self) -> Result<(), Self::Error>; + /// Waits until the switch changess from active to inactive, or from inactive to active + /// async fn wait_for_change(&mut self) -> Result<(), Self::Error>; } diff --git a/src/mock.rs b/src/mock.rs index 1b5dc03..c6aaa71 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -9,6 +9,8 @@ use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; #[cfg(feature = "async")] use embedded_hal_async::digital::Wait; +#[cfg(feature = "async")] +use core::{future::poll_fn, task::Poll}; #[derive(PartialEq, Eq, Debug)] pub enum State { @@ -192,7 +194,7 @@ mod test { mod asynch { use core::future::Future; use core::pin::pin; - use core::task::Context; + use core::task::{Context, Poll}; use noop_waker::noop_waker; use super::*; From 3266119aec5579cd19e7c6fa4b9a2c7eec79a75b Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Wed, 17 Apr 2024 15:17:58 +0300 Subject: [PATCH 07/10] Make InputSwitch non-mut again --- src/input/mod.rs | 28 ++++++++++++++-------------- src/lib.rs | 10 +++++----- src/output/mod.rs | 18 +++++++++--------- tests/input.rs | 12 ++++++------ tests/pin_into_switch.rs | 4 ++-- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index d65f114..f44fafa 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -8,16 +8,16 @@ use embedded_hal_async::digital::Wait; impl InputSwitch for Switch { type Error = ::Error; - fn is_active(&mut self) -> Result { - self.pin.is_high() + fn is_active(&self) -> Result { + self.pin.borrow_mut().is_high() } } impl InputSwitch for Switch { type Error = ::Error; - fn is_active(&mut self) -> Result { - self.pin.is_low() + fn is_active(&self) -> Result { + self.pin.borrow_mut().is_low() } } @@ -29,18 +29,18 @@ where type Error = ::Error; async fn wait_for_active(&mut self) -> Result<(), Self::Error> { - self.pin.wait_for_high().await + self.pin.get_mut().wait_for_high().await } async fn wait_for_inactive(&mut self) -> Result<(), Self::Error> { - self.pin.wait_for_low().await + self.pin.get_mut().wait_for_low().await } async fn wait_for_change(&mut self) -> Result<(), Self::Error> { - if self.pin.is_high()? { - self.pin.wait_for_low().await + if self.pin.get_mut().is_high()? { + self.pin.get_mut().wait_for_low().await } else { - self.pin.wait_for_high().await + self.pin.get_mut().wait_for_high().await } } } @@ -53,18 +53,18 @@ where type Error = ::Error; async fn wait_for_active(&mut self) -> Result<(), Self::Error> { - self.pin.wait_for_low().await + self.pin.get_mut().wait_for_low().await } async fn wait_for_inactive(&mut self) -> Result<(), Self::Error> { - self.pin.wait_for_high().await + self.pin.get_mut().wait_for_high().await } async fn wait_for_change(&mut self) -> Result<(), Self::Error> { - if self.pin.is_high()? { - self.pin.wait_for_low().await + if self.pin.get_mut().is_high()? { + self.pin.get_mut().wait_for_low().await } else { - self.pin.wait_for_high().await + self.pin.get_mut().wait_for_high().await } } } diff --git a/src/lib.rs b/src/lib.rs index 73e90b7..8e7e920 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ pub trait InputSwitch { /// Err(_) => { panic!("Failed to read button state"); } /// } /// ``` - fn is_active(&mut self) -> Result; + fn is_active(&self) -> Result; } #[cfg(feature = "async")] @@ -161,7 +161,7 @@ pub struct ActiveHigh; /// Zero sized struct for signaling to [Switch](struct.Switch.html) that it is active low pub struct ActiveLow; -use core::marker::PhantomData; +use core::{cell::RefCell, marker::PhantomData}; /// Concrete implementation for [InputSwitch](trait.InputSwitch.html) and [OutputSwitch](trait.OutputSwitch.html) /// @@ -171,7 +171,7 @@ use core::marker::PhantomData; /// `ActiveLevel` is not actually stored in the struct. /// It's [PhantomData] used to indicate which implementation to use. pub struct Switch { - pin: IoPin, + pin: RefCell, active: PhantomData, } @@ -222,7 +222,7 @@ impl Switch { /// ``` pub fn new(pin: IoPin) -> Self { Switch { - pin, + pin: RefCell::new(pin), active: PhantomData::, } } @@ -243,7 +243,7 @@ impl Switch { /// // do something else with the pin /// ``` pub fn into_pin(self) -> IoPin { - self.pin + self.pin.into_inner() } } diff --git a/src/output/mod.rs b/src/output/mod.rs index 47c3a3a..7c1fad6 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -8,11 +8,11 @@ impl OutputSwitch for Switch { type Error = ::Error; fn on(&mut self) -> Result<(), Self::Error> { - self.pin.set_high() + self.pin.borrow_mut().set_high() } fn off(&mut self) -> Result<(), Self::Error> { - self.pin.set_low() + self.pin.borrow_mut().set_low() } } @@ -20,11 +20,11 @@ impl OutputSwitch for Switch { type Error = ::Error; fn on(&mut self) -> Result<(), Self::Error> { - self.pin.set_low() + self.pin.borrow_mut().set_low() } fn off(&mut self) -> Result<(), Self::Error> { - self.pin.set_high() + self.pin.borrow_mut().set_high() } } @@ -34,7 +34,7 @@ impl ToggleableOutputSwitch type Error = ::Error; fn toggle(&mut self) -> Result<(), Self::Error> { - self.pin.toggle() + self.pin.get_mut().toggle() } } @@ -42,11 +42,11 @@ impl StatefulOutputSwitch for Switch::Error; fn is_on(&mut self) -> Result { - self.pin.is_set_low() + self.pin.get_mut().is_set_low() } fn is_off(&mut self) -> Result { - self.pin.is_set_high() + self.pin.get_mut().is_set_high() } } @@ -54,10 +54,10 @@ impl StatefulOutputSwitch for Switch::Error; fn is_on(&mut self) -> Result { - self.pin.is_set_high() + self.pin.get_mut().is_set_high() } fn is_off(&mut self) -> Result { - self.pin.is_set_low() + self.pin.get_mut().is_set_low() } } diff --git a/tests/input.rs b/tests/input.rs index 67e1dc1..db0c0d9 100644 --- a/tests/input.rs +++ b/tests/input.rs @@ -15,7 +15,7 @@ mod active_high_switch { fn true_when_pin_high() { let pin = Pin::with_state(State::High); - let mut button = Switch::<_, ActiveHigh>::new(pin); + let button = Switch::<_, ActiveHigh>::new(pin); assert!(button.is_active().unwrap()); } @@ -23,14 +23,14 @@ mod active_high_switch { fn false_when_pin_low() { let pin = Pin::with_state(State::Low); - let mut button = Switch::<_, ActiveHigh>::new(pin); + let button = Switch::<_, ActiveHigh>::new(pin); assert!(!button.is_active().unwrap()); } #[test] fn propagates_errors_from_pin() { let pin = Pin::new(); - let mut button = Switch::<_, ActiveHigh>::new(pin); + let button = Switch::<_, ActiveHigh>::new(pin); button .is_active() .expect_err("Expected uninitialized error"); @@ -50,7 +50,7 @@ mod active_low_switch { fn false_when_pin_high() { let pin = Pin::with_state(State::High); - let mut button = Switch::<_, ActiveLow>::new(pin); + let button = Switch::<_, ActiveLow>::new(pin); assert!(!button.is_active().unwrap()); } @@ -58,14 +58,14 @@ mod active_low_switch { fn true_when_pin_low() { let pin = Pin::with_state(State::Low); - let mut button = Switch::<_, ActiveLow>::new(pin); + let button = Switch::<_, ActiveLow>::new(pin); assert!(button.is_active().unwrap()); } #[test] fn propagates_errors_from_pin() { let pin = Pin::new(); - let mut button = Switch::<_, ActiveLow>::new(pin); + let button = Switch::<_, ActiveLow>::new(pin); button .is_active() .expect_err("Expected uninitialized error"); diff --git a/tests/pin_into_switch.rs b/tests/pin_into_switch.rs index 3721e50..42c199b 100644 --- a/tests/pin_into_switch.rs +++ b/tests/pin_into_switch.rs @@ -35,14 +35,14 @@ mod input_pin { #[test] fn active_high() { let pin = Pin::with_state(State::High); - let mut switch = pin.into_active_high_switch(); + let switch = pin.into_active_high_switch(); assert!(switch.is_active().unwrap()); } #[test] fn active_low() { let pin = Pin::with_state(State::Low); - let mut switch = pin.into_active_low_switch(); + let switch = pin.into_active_low_switch(); assert!(switch.is_active().unwrap()); } } From fb5421622ad953c5e896c12d8c8d3661536640a3 Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Wed, 17 Apr 2024 15:19:31 +0300 Subject: [PATCH 08/10] Remove the "elevator pitch" from the docs --- src/lib.rs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8e7e920..c98788f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,23 +1,3 @@ -//! Switch-HAL is a no_std embedded Rust library for working with buttons, switches, LEDs, and transistors. Basically, anything that acts like a switch, whether an input or output. -//! -//! It is both a driver that uses the embedded-hal::digital traits and is an abstraction in it's own right. It provides a simple, zero-cost, abstraction to clarify the intent of your application code. -//! -//! Why Switch-HAL? Why not just use raw GPIO? -//! Did you mean to drive that line high? -//! Or did you mean to turn that LED off? -//! Wait a second... is that LED active high? -//! Where's the schematic? -//! Okay... cathode is wired to the input line... that means it's active low. -//! -//! Now repeat this every place in your code where you need to turn that LED on or off. -//! What happens when the hardware changes? -//! Using the raw GPIO to set pins high and low will have you making changes all over your code base. -//! -//! Wouldn't it be nicer if you only had to think about that once, when you initialize your application, -//! and from then on out, simply called led.on() or led.off(). -//! Having an abstraction at the proper level reduces cognitive load. -//! Specifying whether a simple peripheral is active high or low in a single place in your application reduces the maintenance burden. -//! //! "Async" feature enables async support for input switches. #![no_std] From c29e4d28463d5506a29dd5f4451eb208c153f5c7 Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Wed, 17 Apr 2024 15:30:28 +0300 Subject: [PATCH 09/10] Revert asserts to assert_eq style, but shut up clippy about it --- src/lib.rs | 4 ++-- src/mock.rs | 36 +++++++++++++++++++----------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c98788f..8416339 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -117,7 +117,7 @@ pub trait StatefulOutputSwitch { /// # let pin = mock::Pin::new(); /// let mut led = pin.into_active_high_switch(); /// led.off().ok(); - /// assert!(!led.is_on().unwrap()); + /// assert_eq!(false, led.is_on().unwrap()); /// ``` fn is_on(&mut self) -> Result; @@ -131,7 +131,7 @@ pub trait StatefulOutputSwitch { /// # let pin = mock::Pin::new(); /// let mut led = pin.into_active_high_switch(); /// led.off().ok(); - /// assert!(led.is_off().unwrap()); + /// assert_eq!(true, led.is_off().unwrap()); /// ``` fn is_off(&mut self) -> Result; } diff --git a/src/mock.rs b/src/mock.rs index c6aaa71..a38c1f8 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -6,6 +6,8 @@ //! This is part of the main crate so it is accessible to doctests. //! Otherwise, I would have created a tests/mock/mod.rs file. +#![allow(clippy::bool_assert_comparison)] + use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; #[cfg(feature = "async")] use embedded_hal_async::digital::Wait; @@ -164,13 +166,13 @@ mod test { #[test] fn returns_true_when_state_is_high() { let mut pin = Pin::with_state(State::High); - assert!(pin.is_high().unwrap()); + assert_eq!(true, pin.is_high().unwrap()); } #[test] fn returns_false_when_state_is_low() { let mut pin = Pin::with_state(State::Low); - assert!(!pin.is_high().unwrap()); + assert_eq!(false, pin.is_high().unwrap()); } } @@ -180,13 +182,13 @@ mod test { #[test] fn returns_false_when_state_is_high() { let mut pin = Pin::with_state(State::High); - assert!(!pin.is_low().unwrap()); + assert_eq!(false, pin.is_low().unwrap()); } #[test] fn returns_true_when_state_is_high() { let mut pin = Pin::with_state(State::Low); - assert!(pin.is_low().unwrap()); + assert_eq!(true, pin.is_low().unwrap()); } } @@ -206,7 +208,7 @@ mod test { let waker = noop_waker(); let mut cx = Context::from_waker(&waker); - assert!(matches!(future.as_mut().poll(&mut cx), Poll::Ready(_))) + assert_eq!(true, matches!(future.as_mut().poll(&mut cx), Poll::Ready(_))) } #[test] @@ -216,7 +218,7 @@ mod test { let waker = noop_waker(); let mut cx = Context::from_waker(&waker); - assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending)); + assert_eq!(true, matches!(future.as_mut().poll(&mut cx), Poll::Pending)); } #[test] @@ -226,7 +228,7 @@ mod test { let waker = noop_waker(); let mut cx = Context::from_waker(&waker); - assert!(matches!(future.as_mut().poll(&mut cx), Poll::Ready(_))); + assert_eq!(true, matches!(future.as_mut().poll(&mut cx), Poll::Ready(_))); } #[test] @@ -236,7 +238,7 @@ mod test { let waker = noop_waker(); let mut cx = Context::from_waker(&waker); - assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending)); + assert_eq!(true, matches!(future.as_mut().poll(&mut cx), Poll::Pending)); } #[test] @@ -246,7 +248,7 @@ mod test { let waker = noop_waker(); let mut cx = Context::from_waker(&waker); - assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending)); + assert_eq!(true, matches!(future.as_mut().poll(&mut cx), Poll::Pending)); } #[test] @@ -256,7 +258,7 @@ mod test { let waker = noop_waker(); let mut cx = Context::from_waker(&waker); - assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending)); + assert_eq!(true, matches!(future.as_mut().poll(&mut cx), Poll::Pending)); } } } @@ -269,7 +271,7 @@ mod test { let mut pin = Pin::new(); pin.set_low().unwrap(); - assert!(pin.is_low().unwrap()); + assert_eq!(true, pin.is_low().unwrap()); } #[test] @@ -277,7 +279,7 @@ mod test { let mut pin = Pin::new(); pin.set_high().unwrap(); - assert!(pin.is_high().unwrap()); + assert_eq!(true, pin.is_high().unwrap()); } } @@ -296,13 +298,13 @@ mod test { #[test] fn returns_false_when_state_is_high() { let mut pin = Pin::with_state(State::High); - assert!(!pin.is_set_low().unwrap()); + assert_eq!(false, pin.is_set_low().unwrap()); } #[test] fn returns_true_when_state_is_high() { let mut pin = Pin::with_state(State::Low); - assert!(pin.is_set_low().unwrap()); + assert_eq!(true, pin.is_set_low().unwrap()); } } @@ -312,13 +314,13 @@ mod test { #[test] fn returns_true_when_state_is_high() { let mut pin = Pin::with_state(State::High); - assert!(pin.is_set_high().unwrap()); + assert_eq!(true, pin.is_set_high().unwrap()); } #[test] fn returns_false_when_state_is_low() { let mut pin = Pin::with_state(State::Low); - assert!(!pin.is_set_high().unwrap()); + assert_eq!(false, pin.is_set_high().unwrap()); } } @@ -330,7 +332,7 @@ mod test { fn default_toggleable_impl() { let mut pin = Pin::with_state(State::Low); pin.toggle().unwrap(); - assert!(pin.is_set_high().unwrap()); + assert_eq!(true, pin.is_set_high().unwrap()); } } } From 67f038263aa85a8a547cc63660ae4d9c6499c930 Mon Sep 17 00:00:00 2001 From: Daniel Ginsburg Date: Wed, 17 Apr 2024 17:27:04 +0300 Subject: [PATCH 10/10] Revert more asserts --- tests/input.rs | 9 +++++---- tests/output.rs | 29 +++++++++++++++-------------- tests/pin_into_switch.rs | 9 +++++---- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/tests/input.rs b/tests/input.rs index db0c0d9..a5547c8 100644 --- a/tests/input.rs +++ b/tests/input.rs @@ -1,3 +1,4 @@ +#![allow(clippy::bool_assert_comparison)] extern crate switch_hal; use switch_hal::mock::{Pin, State}; @@ -16,7 +17,7 @@ mod active_high_switch { let pin = Pin::with_state(State::High); let button = Switch::<_, ActiveHigh>::new(pin); - assert!(button.is_active().unwrap()); + assert_eq!(true, button.is_active().unwrap()); } #[test] @@ -24,7 +25,7 @@ mod active_high_switch { let pin = Pin::with_state(State::Low); let button = Switch::<_, ActiveHigh>::new(pin); - assert!(!button.is_active().unwrap()); + assert_eq!(false, button.is_active().unwrap()); } #[test] @@ -51,7 +52,7 @@ mod active_low_switch { let pin = Pin::with_state(State::High); let button = Switch::<_, ActiveLow>::new(pin); - assert!(!button.is_active().unwrap()); + assert_eq!(false, button.is_active().unwrap()); } #[test] @@ -59,7 +60,7 @@ mod active_low_switch { let pin = Pin::with_state(State::Low); let button = Switch::<_, ActiveLow>::new(pin); - assert!(button.is_active().unwrap()); + assert_eq!(true, button.is_active().unwrap()); } #[test] diff --git a/tests/output.rs b/tests/output.rs index f9b11fe..81f5697 100644 --- a/tests/output.rs +++ b/tests/output.rs @@ -1,3 +1,4 @@ +#![allow(clippy::bool_assert_comparison)] extern crate switch_hal; use switch_hal::mock; @@ -15,7 +16,7 @@ mod active_high_switch { led.on().unwrap(); let mut pin = led.into_pin(); - assert!(pin.is_high().unwrap()); + assert_eq!(true, pin.is_high().unwrap()); } #[test] @@ -26,7 +27,7 @@ mod active_high_switch { led.off().unwrap(); let mut pin = led.into_pin(); - assert!(pin.is_low().unwrap()); + assert_eq!(true, pin.is_low().unwrap()); } #[test] @@ -41,7 +42,7 @@ mod active_high_switch { led.toggle().unwrap(); let mut pin = led.into_pin(); - assert!(pin.is_high().unwrap()); + assert_eq!(true, pin.is_high().unwrap()); } #[test] @@ -53,10 +54,10 @@ mod active_high_switch { let mut led = Switch::<_, ActiveHigh>::new(pin); led.off().unwrap(); - assert!(!led.is_on().unwrap()); + assert_eq!(false, led.is_on().unwrap()); let mut pin = led.into_pin(); - assert!(!pin.is_high().unwrap()); + assert_eq!(false, pin.is_high().unwrap()); } #[test] @@ -68,10 +69,10 @@ mod active_high_switch { let mut led = Switch::<_, ActiveHigh>::new(pin); led.on().unwrap(); - assert!(led.is_on().unwrap()); + assert_eq!(true, led.is_on().unwrap()); let mut pin = led.into_pin(); - assert!(pin.is_high().unwrap()); + assert_eq!(true, pin.is_high().unwrap()); } } @@ -88,7 +89,7 @@ mod active_low_switch { led.on().unwrap(); let mut pin = led.into_pin(); - assert!(pin.is_low().unwrap()); + assert_eq!(true, pin.is_low().unwrap()); } #[test] @@ -99,7 +100,7 @@ mod active_low_switch { led.off().unwrap(); let mut pin = led.into_pin(); - assert!(pin.is_high().unwrap()); + assert_eq!(true, pin.is_high().unwrap()); } #[test] @@ -114,7 +115,7 @@ mod active_low_switch { led.toggle().unwrap(); let mut pin = led.into_pin(); - assert!(pin.is_low().unwrap()); + assert_eq!(true, pin.is_low().unwrap()); } #[test] @@ -126,10 +127,10 @@ mod active_low_switch { let mut led = Switch::<_, ActiveLow>::new(pin); led.off().unwrap(); - assert!(!led.is_on().unwrap()); + assert_eq!(false, led.is_on().unwrap()); let mut pin = led.into_pin(); - assert!(!pin.is_low().unwrap()); + assert_eq!(false, pin.is_low().unwrap()); } #[test] @@ -141,9 +142,9 @@ mod active_low_switch { let mut led = Switch::<_, ActiveLow>::new(pin); led.on().unwrap(); - assert!(led.is_on().unwrap()); + assert_eq!(true, led.is_on().unwrap()); let mut pin = led.into_pin(); - assert!(pin.is_low().unwrap()); + assert_eq!(true, pin.is_low().unwrap()); } } diff --git a/tests/pin_into_switch.rs b/tests/pin_into_switch.rs index 42c199b..6a537b0 100644 --- a/tests/pin_into_switch.rs +++ b/tests/pin_into_switch.rs @@ -1,3 +1,4 @@ +#![allow(clippy::bool_assert_comparison)] use switch_hal::mock::{Pin, State}; use switch_hal::IntoSwitch; @@ -14,7 +15,7 @@ mod output_pin { switch.on().unwrap(); let mut pin = switch.into_pin(); - assert!(pin.is_high().unwrap()); + assert_eq!(true, pin.is_high().unwrap()); } #[test] @@ -24,7 +25,7 @@ mod output_pin { switch.on().unwrap(); let mut pin = switch.into_pin(); - assert!(pin.is_low().unwrap()); + assert_eq!(true, pin.is_low().unwrap()); } } @@ -36,13 +37,13 @@ mod input_pin { fn active_high() { let pin = Pin::with_state(State::High); let switch = pin.into_active_high_switch(); - assert!(switch.is_active().unwrap()); + assert_eq!(true, switch.is_active().unwrap()); } #[test] fn active_low() { let pin = Pin::with_state(State::Low); let switch = pin.into_active_low_switch(); - assert!(switch.is_active().unwrap()); + assert_eq!(true, switch.is_active().unwrap()); } }