From 0ef5e66a57e73e340c53cf026d828763b79ce3b9 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 6 Jan 2020 15:57:03 +1300 Subject: [PATCH 1/4] swap default pin impls, bump version --- Cargo.toml | 2 +- src/digital/mod.rs | 5 ++--- src/digital/v2.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0fc6ab3f7..05a02f2a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" name = "embedded-hal" readme = "README.md" repository = "https://github.com/rust-embedded/embedded-hal" -version = "0.2.3" +version = "0.3.0" [dependencies.nb] version = "0.1.1" diff --git a/src/digital/mod.rs b/src/digital/mod.rs index 7b5b57025..a35d5fb08 100644 --- a/src/digital/mod.rs +++ b/src/digital/mod.rs @@ -22,6 +22,5 @@ pub mod v1_compat; // These are implicit over v1 implementations pub mod v2_compat; -// Re-export old traits so this isn't a breaking change -#[allow(deprecated)] -pub use self::v1::*; +// Export V2 traits +pub use self::v2::*; diff --git a/src/digital/v2.rs b/src/digital/v2.rs index 0de0a877c..decd1421f 100644 --- a/src/digital/v2.rs +++ b/src/digital/v2.rs @@ -1,6 +1,6 @@ //! Digital I/O //! -//! Version 2 / fallible traits. Infallible implementations should set Error to `!`. +//! Version 2 / fallible traits. Infallible implementations should set Error to `core::convert::Infallible`. /// Single digital push-pull output pin pub trait OutputPin { From 2af3156468991f5cfdfdbbccad1d1add799e92e1 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 6 Jan 2020 16:11:22 +1300 Subject: [PATCH 2/4] cleanup old digital traits --- src/digital/mod.rs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/digital/mod.rs b/src/digital/mod.rs index a35d5fb08..82cd865fe 100644 --- a/src/digital/mod.rs +++ b/src/digital/mod.rs @@ -3,24 +3,8 @@ //! //! -// Deprecated / infallible traits -#[deprecated( - since = "0.2.2", - note = "Deprecated because the methods cannot return errors. \ - Users should use the traits in digital::v2." -)] -pub mod v1; - -// New / fallible traits +// Fallible digital traits pub mod v2; -// v2 -> v1 compatibility wrappers -// These require explicit casts from v2 -> v1 -pub mod v1_compat; - -// v1 -> v2 compatibility shims -// These are implicit over v1 implementations -pub mod v2_compat; - -// Export V2 traits +// Re-export default traits pub use self::v2::*; From 6db1fc8693379a6a9f6a4d6bab7970025d9eda57 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 6 Jan 2020 16:27:08 +1300 Subject: [PATCH 3/4] update changelog, remove old conversion methods, depricate digital::v2 direct access --- CHANGELOG.md | 13 +- src/digital/mod.rs | 6 + src/digital/v1.rs | 142 ------------------- src/digital/v1_compat.rs | 286 --------------------------------------- src/digital/v2_compat.rs | 226 ------------------------------- 5 files changed, 16 insertions(+), 657 deletions(-) delete mode 100644 src/digital/v1.rs delete mode 100644 src/digital/v1_compat.rs delete mode 100644 src/digital/v2_compat.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index ca0ead6de..1bc503129 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +### Changed + +## [v0.3.0] - 2020-01-06 ### Added -- A nonblocking trait for interfacing with random number generation hardware. +- A nonblocking `rng` trait for interfacing with random number generation hardware. ### Changed -- The current versions of `InputPin` have been proven. These are `digital::v1::InputPin` - and `digital::v2::InputPin`. +- `void::Void` type for infallible methods has been replaced with `core::convert::Infallible` +- `digital::v1` has been removed +- `digital::v2` has been promoted to the default +- `digital::v2::InputPin` has been proven ## [v0.2.3] - 2019-05-09 diff --git a/src/digital/mod.rs b/src/digital/mod.rs index 82cd865fe..e90621b3d 100644 --- a/src/digital/mod.rs +++ b/src/digital/mod.rs @@ -4,6 +4,12 @@ //! // Fallible digital traits +// This has been left as a submodule to smooth transitions from v0.2.x and +// may be removed in future +#[deprecated( + since = "0.3.0", + note = "Please use traits directly from `digital::` instead" +)] pub mod v2; // Re-export default traits diff --git a/src/digital/v1.rs b/src/digital/v1.rs deleted file mode 100644 index 9c0678b10..000000000 --- a/src/digital/v1.rs +++ /dev/null @@ -1,142 +0,0 @@ -//! Digital I/O -//! -//! The traits in this module are now deprecated. Please use the new versions included -//! in `digital::v2`. - -#![allow(deprecated)] - -/// Single digital push-pull output pin -/// -/// *This version of the trait is now deprecated. Please use the new `OutputPin` trait in -/// `digital::v2::OutputPin`*. - -pub trait OutputPin { - /// Drives the pin low - /// - /// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external - /// electrical sources - fn set_low(&mut self); - - /// Drives the pin high - /// - /// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external - /// electrical sources - fn set_high(&mut self); -} - -/// Push-pull output pin that can read its output state -/// -/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* -/// -/// *This version of the trait is now deprecated. Please use the new `StatefulOutputPin` trait in -/// `digital::v2::StatefulOutputPin`*. -#[cfg(feature = "unproven")] -pub trait StatefulOutputPin { - /// Is the pin in drive high mode? - /// - /// *NOTE* this does *not* read the electrical state of the pin - fn is_set_high(&self) -> bool; - - /// Is the pin in drive low mode? - /// - /// *NOTE* this does *not* read the electrical state of the pin - fn is_set_low(&self) -> bool; -} - -/// Output pin that can be toggled -/// -/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* -/// -/// *This version of the trait is now deprecated. Please use the new `ToggleableOutputPin` -/// trait in `digital::v2::ToggleableOutputPin`*. -/// -/// See [toggleable](toggleable) to use a software implementation if -/// both [OutputPin](trait.OutputPin.html) and -/// [StatefulOutputPin](trait.StatefulOutputPin.html) are -/// implemented. Otherwise, implement this using hardware mechanisms. -#[cfg(feature = "unproven")] -pub trait ToggleableOutputPin { - /// Toggle pin output. - fn toggle(&mut self); -} - -/// If you can read **and** write the output state, a pin is -/// toggleable by software. -/// -/// *This version of the module is now deprecated. Please use the new `toggleable` module in -/// `digital::v2::toggleable`*. -/// -/// ``` -/// use embedded_hal::digital::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; -/// use embedded_hal::digital::toggleable; -/// -/// /// A virtual output pin that exists purely in software -/// struct MyPin { -/// state: bool -/// } -/// -/// impl OutputPin for MyPin { -/// fn set_low(&mut self) { -/// self.state = false; -/// } -/// fn set_high(&mut self) { -/// self.state = true; -/// } -/// } -/// -/// impl StatefulOutputPin for MyPin { -/// fn is_set_low(&self) -> bool { -/// !self.state -/// } -/// fn is_set_high(&self) -> bool { -/// self.state -/// } -/// } -/// -/// /// Opt-in to the software implementation. -/// impl toggleable::Default for MyPin {} -/// -/// let mut pin = MyPin { state: false }; -/// pin.toggle(); -/// assert!(pin.is_set_high()); -/// pin.toggle(); -/// assert!(pin.is_set_low()); -/// ``` -#[cfg(feature = "unproven")] -pub mod toggleable { - #[allow(deprecated)] - use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; - - /// Software-driven `toggle()` implementation. - /// - /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* - #[allow(deprecated)] - pub trait Default: OutputPin + StatefulOutputPin {} - - #[allow(deprecated)] - impl

ToggleableOutputPin for P - where - P: Default, - { - /// Toggle pin output - fn toggle(&mut self) { - if self.is_set_low() { - self.set_high(); - } else { - self.set_low(); - } - } - } -} - -/// Single digital input pin -/// -/// *This version of the trait is now deprecated. Please use the new `InputPin` trait in -/// `digital::v2::InputPin`*. -pub trait InputPin { - /// Is the input pin high? - fn is_high(&self) -> bool; - - /// Is the input pin low? - fn is_low(&self) -> bool; -} diff --git a/src/digital/v1_compat.rs b/src/digital/v1_compat.rs deleted file mode 100644 index 856cbb9fc..000000000 --- a/src/digital/v1_compat.rs +++ /dev/null @@ -1,286 +0,0 @@ -//! v1 compatibility wrappers -//! -//! This module provides wrappers to support use of v2 implementations with -//! v1 consumers. v2 traits must be explicitly cast to the v1 version using -//! `.into()`, and will panic on internal errors -//! -//! ``` -//! extern crate embedded_hal; -//! use embedded_hal::digital::{v1, v2, v1_compat::OldOutputPin}; -//! -//! struct NewOutputPinImpl {} -//! -//! impl v2::OutputPin for NewOutputPinImpl { -//! type Error = (); -//! fn set_low(&mut self) -> Result<(), Self::Error> { Ok(()) } -//! fn set_high(&mut self) -> Result<(), Self::Error>{ Ok(()) } -//! } -//! -//! struct OldOutputPinConsumer { -//! _pin: T, -//! } -//! -//! impl OldOutputPinConsumer -//! where T: v1::OutputPin { -//! pub fn new(pin: T) -> OldOutputPinConsumer { -//! OldOutputPinConsumer{ _pin: pin } -//! } -//! } -//! -//! fn main() { -//! let pin = NewOutputPinImpl{}; -//! let _consumer: OldOutputPinConsumer> = OldOutputPinConsumer::new(pin.into()); -//! } -//! ``` -//! - -#[allow(deprecated)] -use super::v1; -use super::v2; - -/// Wrapper to allow fallible `v2::OutputPin` traits to be converted to `v1::OutputPin` traits -pub struct OldOutputPin { - pin: T, -} - -impl OldOutputPin -where - T: v2::OutputPin, - E: core::fmt::Debug, -{ - /// Create a new OldOutputPin wrapper around a `v2::OutputPin` - pub fn new(pin: T) -> Self { - Self { pin } - } - - /// Fetch a reference to the inner `v2::OutputPin` impl - #[cfg(test)] - fn inner(&self) -> &T { - &self.pin - } -} - -impl From for OldOutputPin -where - T: v2::OutputPin, - E: core::fmt::Debug, -{ - fn from(pin: T) -> Self { - OldOutputPin { pin } - } -} - -/// Implementation of `v1::OutputPin` trait for fallible `v2::OutputPin` output pins -/// where errors will panic. -#[allow(deprecated)] -impl v1::OutputPin for OldOutputPin -where - T: v2::OutputPin, - E: core::fmt::Debug, -{ - fn set_low(&mut self) { - self.pin.set_low().unwrap() - } - - fn set_high(&mut self) { - self.pin.set_high().unwrap() - } -} - -/// Implementation of `v1::StatefulOutputPin` trait for `v2::StatefulOutputPin` fallible pins -/// where errors will panic. -#[cfg(feature = "unproven")] -#[allow(deprecated)] -impl v1::StatefulOutputPin for OldOutputPin -where - T: v2::StatefulOutputPin, - E: core::fmt::Debug, -{ - fn is_set_low(&self) -> bool { - self.pin.is_set_low().unwrap() - } - - fn is_set_high(&self) -> bool { - self.pin.is_set_high().unwrap() - } -} - -/// Wrapper to allow fallible `v2::InputPin` traits to be converted to `v1::InputPin` traits -/// where errors will panic. -pub struct OldInputPin { - pin: T, -} - -impl OldInputPin -where - T: v2::OutputPin, - E: core::fmt::Debug, -{ - /// Create an `OldInputPin` wrapper around a `v2::InputPin`. - pub fn new(pin: T) -> Self { - Self { pin } - } -} - -impl From for OldInputPin -where - T: v2::InputPin, - E: core::fmt::Debug, -{ - fn from(pin: T) -> Self { - OldInputPin { pin } - } -} - -/// Implementation of `v1::InputPin` trait for `v2::InputPin` fallible pins -/// where errors will panic. -#[allow(deprecated)] -impl v1::InputPin for OldInputPin -where - T: v2::InputPin, - E: core::fmt::Debug, -{ - fn is_low(&self) -> bool { - self.pin.is_low().unwrap() - } - - fn is_high(&self) -> bool { - self.pin.is_high().unwrap() - } -} - -#[cfg(test)] -#[allow(deprecated)] -mod tests { - use super::*; - - #[allow(deprecated)] - use crate::digital::v1; - use crate::digital::v2; - - use crate::digital::v1::OutputPin; - - #[derive(Clone)] - struct NewOutputPinImpl { - state: bool, - res: Result<(), ()>, - } - - impl v2::OutputPin for NewOutputPinImpl { - type Error = (); - - fn set_low(&mut self) -> Result<(), Self::Error> { - self.state = false; - self.res - } - fn set_high(&mut self) -> Result<(), Self::Error> { - self.state = true; - self.res - } - } - - #[allow(deprecated)] - struct OldOutputPinConsumer { - _pin: T, - } - - #[allow(deprecated)] - impl OldOutputPinConsumer - where - T: v1::OutputPin, - { - pub fn new(pin: T) -> OldOutputPinConsumer { - OldOutputPinConsumer { _pin: pin } - } - } - - #[test] - fn v1_v2_output_explicit() { - let i = NewOutputPinImpl { - state: false, - res: Ok(()), - }; - let _c: OldOutputPinConsumer> = OldOutputPinConsumer::new(i.into()); - } - - #[test] - fn v1_v2_output_state() { - let mut o: OldOutputPin<_> = NewOutputPinImpl { - state: false, - res: Ok(()), - } - .into(); - - o.set_high(); - assert_eq!(o.inner().state, true); - - o.set_low(); - assert_eq!(o.inner().state, false); - } - - #[test] - #[should_panic] - fn v1_v2_output_panic() { - let mut o: OldOutputPin<_> = NewOutputPinImpl { - state: false, - res: Err(()), - } - .into(); - - o.set_high(); - } - - use crate::digital::v1::InputPin; - - struct NewInputPinImpl { - state: Result, - } - - impl v2::InputPin for NewInputPinImpl { - type Error = (); - - fn is_low(&self) -> Result { - self.state.map(|v| v == false) - } - fn is_high(&self) -> Result { - self.state.map(|v| v == true) - } - } - - #[allow(deprecated)] - struct OldInputPinConsumer { - _pin: T, - } - - #[allow(deprecated)] - impl OldInputPinConsumer - where - T: v1::InputPin, - { - pub fn new(pin: T) -> OldInputPinConsumer { - OldInputPinConsumer { _pin: pin } - } - } - - #[test] - fn v1_v2_input_explicit() { - let i = NewInputPinImpl { state: Ok(false) }; - let _c: OldInputPinConsumer> = OldInputPinConsumer::new(i.into()); - } - - #[test] - fn v1_v2_input_state() { - let i: OldInputPin<_> = NewInputPinImpl { state: Ok(false) }.into(); - - assert_eq!(i.is_low(), true); - assert_eq!(i.is_high(), false); - } - - #[test] - #[should_panic] - fn v1_v2_input_panic() { - let i: OldInputPin<_> = NewInputPinImpl { state: Err(()) }.into(); - - i.is_low(); - } -} diff --git a/src/digital/v2_compat.rs b/src/digital/v2_compat.rs deleted file mode 100644 index 4b6b4c805..000000000 --- a/src/digital/v2_compat.rs +++ /dev/null @@ -1,226 +0,0 @@ -//! v2 compatibility shims -//! -//! This module adds implicit forward support to v1 digital traits, -//! allowing v1 implementations to be directly used with v2 consumers. -//! -//! ``` -//! extern crate embedded_hal; -//! use embedded_hal::digital::{v1, v2}; -//! -//! struct OldOutputPinImpl { } -//! -//! impl v1::OutputPin for OldOutputPinImpl { -//! fn set_low(&mut self) { } -//! fn set_high(&mut self) { } -//! } -//! -//! struct NewOutputPinConsumer { -//! _pin: T, -//! } -//! -//! impl NewOutputPinConsumer -//! where T: v2::OutputPin { -//! pub fn new(pin: T) -> NewOutputPinConsumer { -//! NewOutputPinConsumer{ _pin: pin } -//! } -//! } -//! -//! fn main() { -//! let pin = OldOutputPinImpl{}; -//! let _consumer = NewOutputPinConsumer::new(pin); -//! } -//! ``` -//! - -use core::convert::Infallible; - -#[allow(deprecated)] -use super::v1; -use super::v2; - -/// Implementation of fallible `v2::OutputPin` for `v1::OutputPin` traits -#[allow(deprecated)] -impl v2::OutputPin for T -where - T: v1::OutputPin, -{ - type Error = Infallible; - - fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) - } - - fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) - } -} - -/// Implementation of fallible `v2::StatefulOutputPin` for `v1::StatefulOutputPin` digital traits -#[cfg(feature = "unproven")] -#[allow(deprecated)] -impl v2::StatefulOutputPin for T -where - T: v1::StatefulOutputPin + v1::OutputPin, -{ - fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) - } - - fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) - } -} - -#[cfg(feature = "unproven")] -#[allow(deprecated)] -impl v2::toggleable::Default for T where T: v1::toggleable::Default {} - -/// Implementation of fallible `v2::InputPin` for `v1::InputPin` digital traits -#[allow(deprecated)] -impl v2::InputPin for T -where - T: v1::InputPin, -{ - type Error = Infallible; - - fn is_low(&self) -> Result { - Ok(self.is_low()) - } - - fn is_high(&self) -> Result { - Ok(self.is_high()) - } -} - -#[cfg(test)] -mod tests { - - #[allow(deprecated)] - use crate::digital::v1; - use crate::digital::v2; - - #[allow(deprecated)] - struct OldOutputPinImpl { - state: bool, - } - - #[allow(deprecated)] - impl v1::OutputPin for OldOutputPinImpl { - fn set_low(&mut self) { - self.state = false; - } - fn set_high(&mut self) { - self.state = true; - } - } - - #[cfg(feature = "unproven")] - #[allow(deprecated)] - impl v1::StatefulOutputPin for OldOutputPinImpl { - fn is_set_low(&self) -> bool { - self.state == false - } - - fn is_set_high(&self) -> bool { - self.state == true - } - } - - #[cfg(feature = "unproven")] - #[allow(deprecated)] - impl v1::toggleable::Default for OldOutputPinImpl {} - - struct NewOutputPinConsumer { - _pin: T, - } - - impl NewOutputPinConsumer - where - T: v2::OutputPin, - { - pub fn new(pin: T) -> NewOutputPinConsumer { - NewOutputPinConsumer { _pin: pin } - } - } - - #[cfg(feature = "unproven")] - struct NewToggleablePinConsumer { - _pin: T, - } - - #[cfg(feature = "unproven")] - impl NewToggleablePinConsumer - where - T: v2::ToggleableOutputPin, - { - pub fn new(pin: T) -> NewToggleablePinConsumer { - NewToggleablePinConsumer { _pin: pin } - } - } - - #[cfg(feature = "unproven")] - #[test] - fn v2_v1_toggleable_implicit() { - let i = OldOutputPinImpl { state: false }; - let _c = NewToggleablePinConsumer::new(i); - } - - #[test] - fn v2_v1_output_implicit() { - let i = OldOutputPinImpl { state: false }; - let _c = NewOutputPinConsumer::new(i); - } - - #[test] - fn v2_v1_output_state() { - let mut o = OldOutputPinImpl { state: false }; - - v2::OutputPin::set_high(&mut o).unwrap(); - assert_eq!(o.state, true); - - v2::OutputPin::set_low(&mut o).unwrap(); - assert_eq!(o.state, false); - } - - #[allow(deprecated)] - struct OldInputPinImpl { - state: bool, - } - - #[allow(deprecated)] - impl v1::InputPin for OldInputPinImpl { - fn is_low(&self) -> bool { - !self.state - } - fn is_high(&self) -> bool { - self.state - } - } - - struct NewInputPinConsumer { - _pin: T, - } - - impl NewInputPinConsumer - where - T: v2::InputPin, - { - pub fn new(pin: T) -> NewInputPinConsumer { - NewInputPinConsumer { _pin: pin } - } - } - - #[test] - fn v2_v1_input_implicit() { - let i = OldInputPinImpl { state: false }; - let _c = NewInputPinConsumer::new(i); - } - - #[test] - fn v2_v1_input_state() { - let mut i = OldInputPinImpl { state: false }; - - assert_eq!(v2::InputPin::is_high(&mut i).unwrap(), false); - assert_eq!(v2::InputPin::is_low(&mut i).unwrap(), true); - } -} From b2487bdc657917b87d1629dfa5e69e1ea2a36fc4 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 6 Jan 2020 16:36:44 +1300 Subject: [PATCH 4/4] turns out compat has to come with us and be semver'd back --- CHANGELOG.md | 3 +- src/digital/mod.rs | 23 +++- src/digital/v1.rs | 142 +++++++++++++++++++ src/digital/v1_compat.rs | 286 +++++++++++++++++++++++++++++++++++++++ src/digital/v2_compat.rs | 226 +++++++++++++++++++++++++++++++ 5 files changed, 672 insertions(+), 8 deletions(-) create mode 100644 src/digital/v1.rs create mode 100644 src/digital/v1_compat.rs create mode 100644 src/digital/v2_compat.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bc503129..2bc39f4b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,9 +17,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - `void::Void` type for infallible methods has been replaced with `core::convert::Infallible` -- `digital::v1` has been removed - `digital::v2` has been promoted to the default -- `digital::v2::InputPin` has been proven +- `digital::v2::InputPin` and `digital::v2::InputPin` have been proven ## [v0.2.3] - 2019-05-09 diff --git a/src/digital/mod.rs b/src/digital/mod.rs index e90621b3d..0a18c4ffa 100644 --- a/src/digital/mod.rs +++ b/src/digital/mod.rs @@ -3,14 +3,25 @@ //! //! -// Fallible digital traits -// This has been left as a submodule to smooth transitions from v0.2.x and -// may be removed in future +// Deprecated / infallible traits #[deprecated( - since = "0.3.0", - note = "Please use traits directly from `digital::` instead" + since = "0.2.2", + note = "Deprecated because the methods cannot return errors. \ + Users should use the traits in digital::v2." )] +pub mod v1; + +// New / fallible traits pub mod v2; -// Re-export default traits +// v2 -> v1 compatibility wrappers +// These require explicit casts from v2 -> v1 +pub mod v1_compat; + +// v1 -> v2 compatibility shims +// These are implicit over v1 implementations +pub mod v2_compat; + +// Re-export old traits so this isn't a breaking change +#[allow(deprecated)] pub use self::v2::*; diff --git a/src/digital/v1.rs b/src/digital/v1.rs new file mode 100644 index 000000000..9c0678b10 --- /dev/null +++ b/src/digital/v1.rs @@ -0,0 +1,142 @@ +//! Digital I/O +//! +//! The traits in this module are now deprecated. Please use the new versions included +//! in `digital::v2`. + +#![allow(deprecated)] + +/// Single digital push-pull output pin +/// +/// *This version of the trait is now deprecated. Please use the new `OutputPin` trait in +/// `digital::v2::OutputPin`*. + +pub trait OutputPin { + /// Drives the pin low + /// + /// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external + /// electrical sources + fn set_low(&mut self); + + /// Drives the pin high + /// + /// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external + /// electrical sources + fn set_high(&mut self); +} + +/// Push-pull output pin that can read its output state +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +/// +/// *This version of the trait is now deprecated. Please use the new `StatefulOutputPin` trait in +/// `digital::v2::StatefulOutputPin`*. +#[cfg(feature = "unproven")] +pub trait StatefulOutputPin { + /// Is the pin in drive high mode? + /// + /// *NOTE* this does *not* read the electrical state of the pin + fn is_set_high(&self) -> bool; + + /// Is the pin in drive low mode? + /// + /// *NOTE* this does *not* read the electrical state of the pin + fn is_set_low(&self) -> bool; +} + +/// Output pin that can be toggled +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +/// +/// *This version of the trait is now deprecated. Please use the new `ToggleableOutputPin` +/// trait in `digital::v2::ToggleableOutputPin`*. +/// +/// See [toggleable](toggleable) to use a software implementation if +/// both [OutputPin](trait.OutputPin.html) and +/// [StatefulOutputPin](trait.StatefulOutputPin.html) are +/// implemented. Otherwise, implement this using hardware mechanisms. +#[cfg(feature = "unproven")] +pub trait ToggleableOutputPin { + /// Toggle pin output. + fn toggle(&mut self); +} + +/// If you can read **and** write the output state, a pin is +/// toggleable by software. +/// +/// *This version of the module is now deprecated. Please use the new `toggleable` module in +/// `digital::v2::toggleable`*. +/// +/// ``` +/// use embedded_hal::digital::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; +/// use embedded_hal::digital::toggleable; +/// +/// /// A virtual output pin that exists purely in software +/// struct MyPin { +/// state: bool +/// } +/// +/// impl OutputPin for MyPin { +/// fn set_low(&mut self) { +/// self.state = false; +/// } +/// fn set_high(&mut self) { +/// self.state = true; +/// } +/// } +/// +/// impl StatefulOutputPin for MyPin { +/// fn is_set_low(&self) -> bool { +/// !self.state +/// } +/// fn is_set_high(&self) -> bool { +/// self.state +/// } +/// } +/// +/// /// Opt-in to the software implementation. +/// impl toggleable::Default for MyPin {} +/// +/// let mut pin = MyPin { state: false }; +/// pin.toggle(); +/// assert!(pin.is_set_high()); +/// pin.toggle(); +/// assert!(pin.is_set_low()); +/// ``` +#[cfg(feature = "unproven")] +pub mod toggleable { + #[allow(deprecated)] + use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; + + /// Software-driven `toggle()` implementation. + /// + /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* + #[allow(deprecated)] + pub trait Default: OutputPin + StatefulOutputPin {} + + #[allow(deprecated)] + impl

ToggleableOutputPin for P + where + P: Default, + { + /// Toggle pin output + fn toggle(&mut self) { + if self.is_set_low() { + self.set_high(); + } else { + self.set_low(); + } + } + } +} + +/// Single digital input pin +/// +/// *This version of the trait is now deprecated. Please use the new `InputPin` trait in +/// `digital::v2::InputPin`*. +pub trait InputPin { + /// Is the input pin high? + fn is_high(&self) -> bool; + + /// Is the input pin low? + fn is_low(&self) -> bool; +} diff --git a/src/digital/v1_compat.rs b/src/digital/v1_compat.rs new file mode 100644 index 000000000..856cbb9fc --- /dev/null +++ b/src/digital/v1_compat.rs @@ -0,0 +1,286 @@ +//! v1 compatibility wrappers +//! +//! This module provides wrappers to support use of v2 implementations with +//! v1 consumers. v2 traits must be explicitly cast to the v1 version using +//! `.into()`, and will panic on internal errors +//! +//! ``` +//! extern crate embedded_hal; +//! use embedded_hal::digital::{v1, v2, v1_compat::OldOutputPin}; +//! +//! struct NewOutputPinImpl {} +//! +//! impl v2::OutputPin for NewOutputPinImpl { +//! type Error = (); +//! fn set_low(&mut self) -> Result<(), Self::Error> { Ok(()) } +//! fn set_high(&mut self) -> Result<(), Self::Error>{ Ok(()) } +//! } +//! +//! struct OldOutputPinConsumer { +//! _pin: T, +//! } +//! +//! impl OldOutputPinConsumer +//! where T: v1::OutputPin { +//! pub fn new(pin: T) -> OldOutputPinConsumer { +//! OldOutputPinConsumer{ _pin: pin } +//! } +//! } +//! +//! fn main() { +//! let pin = NewOutputPinImpl{}; +//! let _consumer: OldOutputPinConsumer> = OldOutputPinConsumer::new(pin.into()); +//! } +//! ``` +//! + +#[allow(deprecated)] +use super::v1; +use super::v2; + +/// Wrapper to allow fallible `v2::OutputPin` traits to be converted to `v1::OutputPin` traits +pub struct OldOutputPin { + pin: T, +} + +impl OldOutputPin +where + T: v2::OutputPin, + E: core::fmt::Debug, +{ + /// Create a new OldOutputPin wrapper around a `v2::OutputPin` + pub fn new(pin: T) -> Self { + Self { pin } + } + + /// Fetch a reference to the inner `v2::OutputPin` impl + #[cfg(test)] + fn inner(&self) -> &T { + &self.pin + } +} + +impl From for OldOutputPin +where + T: v2::OutputPin, + E: core::fmt::Debug, +{ + fn from(pin: T) -> Self { + OldOutputPin { pin } + } +} + +/// Implementation of `v1::OutputPin` trait for fallible `v2::OutputPin` output pins +/// where errors will panic. +#[allow(deprecated)] +impl v1::OutputPin for OldOutputPin +where + T: v2::OutputPin, + E: core::fmt::Debug, +{ + fn set_low(&mut self) { + self.pin.set_low().unwrap() + } + + fn set_high(&mut self) { + self.pin.set_high().unwrap() + } +} + +/// Implementation of `v1::StatefulOutputPin` trait for `v2::StatefulOutputPin` fallible pins +/// where errors will panic. +#[cfg(feature = "unproven")] +#[allow(deprecated)] +impl v1::StatefulOutputPin for OldOutputPin +where + T: v2::StatefulOutputPin, + E: core::fmt::Debug, +{ + fn is_set_low(&self) -> bool { + self.pin.is_set_low().unwrap() + } + + fn is_set_high(&self) -> bool { + self.pin.is_set_high().unwrap() + } +} + +/// Wrapper to allow fallible `v2::InputPin` traits to be converted to `v1::InputPin` traits +/// where errors will panic. +pub struct OldInputPin { + pin: T, +} + +impl OldInputPin +where + T: v2::OutputPin, + E: core::fmt::Debug, +{ + /// Create an `OldInputPin` wrapper around a `v2::InputPin`. + pub fn new(pin: T) -> Self { + Self { pin } + } +} + +impl From for OldInputPin +where + T: v2::InputPin, + E: core::fmt::Debug, +{ + fn from(pin: T) -> Self { + OldInputPin { pin } + } +} + +/// Implementation of `v1::InputPin` trait for `v2::InputPin` fallible pins +/// where errors will panic. +#[allow(deprecated)] +impl v1::InputPin for OldInputPin +where + T: v2::InputPin, + E: core::fmt::Debug, +{ + fn is_low(&self) -> bool { + self.pin.is_low().unwrap() + } + + fn is_high(&self) -> bool { + self.pin.is_high().unwrap() + } +} + +#[cfg(test)] +#[allow(deprecated)] +mod tests { + use super::*; + + #[allow(deprecated)] + use crate::digital::v1; + use crate::digital::v2; + + use crate::digital::v1::OutputPin; + + #[derive(Clone)] + struct NewOutputPinImpl { + state: bool, + res: Result<(), ()>, + } + + impl v2::OutputPin for NewOutputPinImpl { + type Error = (); + + fn set_low(&mut self) -> Result<(), Self::Error> { + self.state = false; + self.res + } + fn set_high(&mut self) -> Result<(), Self::Error> { + self.state = true; + self.res + } + } + + #[allow(deprecated)] + struct OldOutputPinConsumer { + _pin: T, + } + + #[allow(deprecated)] + impl OldOutputPinConsumer + where + T: v1::OutputPin, + { + pub fn new(pin: T) -> OldOutputPinConsumer { + OldOutputPinConsumer { _pin: pin } + } + } + + #[test] + fn v1_v2_output_explicit() { + let i = NewOutputPinImpl { + state: false, + res: Ok(()), + }; + let _c: OldOutputPinConsumer> = OldOutputPinConsumer::new(i.into()); + } + + #[test] + fn v1_v2_output_state() { + let mut o: OldOutputPin<_> = NewOutputPinImpl { + state: false, + res: Ok(()), + } + .into(); + + o.set_high(); + assert_eq!(o.inner().state, true); + + o.set_low(); + assert_eq!(o.inner().state, false); + } + + #[test] + #[should_panic] + fn v1_v2_output_panic() { + let mut o: OldOutputPin<_> = NewOutputPinImpl { + state: false, + res: Err(()), + } + .into(); + + o.set_high(); + } + + use crate::digital::v1::InputPin; + + struct NewInputPinImpl { + state: Result, + } + + impl v2::InputPin for NewInputPinImpl { + type Error = (); + + fn is_low(&self) -> Result { + self.state.map(|v| v == false) + } + fn is_high(&self) -> Result { + self.state.map(|v| v == true) + } + } + + #[allow(deprecated)] + struct OldInputPinConsumer { + _pin: T, + } + + #[allow(deprecated)] + impl OldInputPinConsumer + where + T: v1::InputPin, + { + pub fn new(pin: T) -> OldInputPinConsumer { + OldInputPinConsumer { _pin: pin } + } + } + + #[test] + fn v1_v2_input_explicit() { + let i = NewInputPinImpl { state: Ok(false) }; + let _c: OldInputPinConsumer> = OldInputPinConsumer::new(i.into()); + } + + #[test] + fn v1_v2_input_state() { + let i: OldInputPin<_> = NewInputPinImpl { state: Ok(false) }.into(); + + assert_eq!(i.is_low(), true); + assert_eq!(i.is_high(), false); + } + + #[test] + #[should_panic] + fn v1_v2_input_panic() { + let i: OldInputPin<_> = NewInputPinImpl { state: Err(()) }.into(); + + i.is_low(); + } +} diff --git a/src/digital/v2_compat.rs b/src/digital/v2_compat.rs new file mode 100644 index 000000000..4b6b4c805 --- /dev/null +++ b/src/digital/v2_compat.rs @@ -0,0 +1,226 @@ +//! v2 compatibility shims +//! +//! This module adds implicit forward support to v1 digital traits, +//! allowing v1 implementations to be directly used with v2 consumers. +//! +//! ``` +//! extern crate embedded_hal; +//! use embedded_hal::digital::{v1, v2}; +//! +//! struct OldOutputPinImpl { } +//! +//! impl v1::OutputPin for OldOutputPinImpl { +//! fn set_low(&mut self) { } +//! fn set_high(&mut self) { } +//! } +//! +//! struct NewOutputPinConsumer { +//! _pin: T, +//! } +//! +//! impl NewOutputPinConsumer +//! where T: v2::OutputPin { +//! pub fn new(pin: T) -> NewOutputPinConsumer { +//! NewOutputPinConsumer{ _pin: pin } +//! } +//! } +//! +//! fn main() { +//! let pin = OldOutputPinImpl{}; +//! let _consumer = NewOutputPinConsumer::new(pin); +//! } +//! ``` +//! + +use core::convert::Infallible; + +#[allow(deprecated)] +use super::v1; +use super::v2; + +/// Implementation of fallible `v2::OutputPin` for `v1::OutputPin` traits +#[allow(deprecated)] +impl v2::OutputPin for T +where + T: v1::OutputPin, +{ + type Error = Infallible; + + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } +} + +/// Implementation of fallible `v2::StatefulOutputPin` for `v1::StatefulOutputPin` digital traits +#[cfg(feature = "unproven")] +#[allow(deprecated)] +impl v2::StatefulOutputPin for T +where + T: v1::StatefulOutputPin + v1::OutputPin, +{ + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } + + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } +} + +#[cfg(feature = "unproven")] +#[allow(deprecated)] +impl v2::toggleable::Default for T where T: v1::toggleable::Default {} + +/// Implementation of fallible `v2::InputPin` for `v1::InputPin` digital traits +#[allow(deprecated)] +impl v2::InputPin for T +where + T: v1::InputPin, +{ + type Error = Infallible; + + fn is_low(&self) -> Result { + Ok(self.is_low()) + } + + fn is_high(&self) -> Result { + Ok(self.is_high()) + } +} + +#[cfg(test)] +mod tests { + + #[allow(deprecated)] + use crate::digital::v1; + use crate::digital::v2; + + #[allow(deprecated)] + struct OldOutputPinImpl { + state: bool, + } + + #[allow(deprecated)] + impl v1::OutputPin for OldOutputPinImpl { + fn set_low(&mut self) { + self.state = false; + } + fn set_high(&mut self) { + self.state = true; + } + } + + #[cfg(feature = "unproven")] + #[allow(deprecated)] + impl v1::StatefulOutputPin for OldOutputPinImpl { + fn is_set_low(&self) -> bool { + self.state == false + } + + fn is_set_high(&self) -> bool { + self.state == true + } + } + + #[cfg(feature = "unproven")] + #[allow(deprecated)] + impl v1::toggleable::Default for OldOutputPinImpl {} + + struct NewOutputPinConsumer { + _pin: T, + } + + impl NewOutputPinConsumer + where + T: v2::OutputPin, + { + pub fn new(pin: T) -> NewOutputPinConsumer { + NewOutputPinConsumer { _pin: pin } + } + } + + #[cfg(feature = "unproven")] + struct NewToggleablePinConsumer { + _pin: T, + } + + #[cfg(feature = "unproven")] + impl NewToggleablePinConsumer + where + T: v2::ToggleableOutputPin, + { + pub fn new(pin: T) -> NewToggleablePinConsumer { + NewToggleablePinConsumer { _pin: pin } + } + } + + #[cfg(feature = "unproven")] + #[test] + fn v2_v1_toggleable_implicit() { + let i = OldOutputPinImpl { state: false }; + let _c = NewToggleablePinConsumer::new(i); + } + + #[test] + fn v2_v1_output_implicit() { + let i = OldOutputPinImpl { state: false }; + let _c = NewOutputPinConsumer::new(i); + } + + #[test] + fn v2_v1_output_state() { + let mut o = OldOutputPinImpl { state: false }; + + v2::OutputPin::set_high(&mut o).unwrap(); + assert_eq!(o.state, true); + + v2::OutputPin::set_low(&mut o).unwrap(); + assert_eq!(o.state, false); + } + + #[allow(deprecated)] + struct OldInputPinImpl { + state: bool, + } + + #[allow(deprecated)] + impl v1::InputPin for OldInputPinImpl { + fn is_low(&self) -> bool { + !self.state + } + fn is_high(&self) -> bool { + self.state + } + } + + struct NewInputPinConsumer { + _pin: T, + } + + impl NewInputPinConsumer + where + T: v2::InputPin, + { + pub fn new(pin: T) -> NewInputPinConsumer { + NewInputPinConsumer { _pin: pin } + } + } + + #[test] + fn v2_v1_input_implicit() { + let i = OldInputPinImpl { state: false }; + let _c = NewInputPinConsumer::new(i); + } + + #[test] + fn v2_v1_input_state() { + let mut i = OldInputPinImpl { state: false }; + + assert_eq!(v2::InputPin::is_high(&mut i).unwrap(), false); + assert_eq!(v2::InputPin::is_low(&mut i).unwrap(), true); + } +}