diff --git a/CHANGELOG.md b/CHANGELOG.md index 52dabbd..c17e32e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.4.0] - 2021-12-23 +### Changed + - Updated `embedded-hal` to `1.0.0-alpha.6` + +### Removed + - `ToggleableOutputPin` implementation for `wire` was removed, as the default + implementation was removed from `embedded-hal` and an explicit implementation + on the wire requires more work + ## [0.3.1] - 2021-02-05 ### Fixed - Fixed implementation of `embedded_hal::digital::ToggleableOutputPin` for wire pins diff --git a/Cargo.lock b/Cargo.lock index 356fd6c..ce4c4f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "autocfg" version = "1.0.1" @@ -8,16 +10,16 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "embedded-hal" -version = "1.0.0-alpha.4" +version = "1.0.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2260cabeacf4bda1df1a8d54f67047a9aadf02fe14cfab07649f2cec6a4693b" +checksum = "570e765da7319a256dfe1542f14501a53f74e020b68aa666a98b1ad31a614c7e" dependencies = [ "nb", ] [[package]] name = "embedded-hal-sync-pins" -version = "0.3.0" +version = "0.3.1" dependencies = [ "embedded-hal", "embedded-time", diff --git a/Cargo.toml b/Cargo.toml index 46f8f9f..1473fab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embedded-hal-sync-pins" -version = "0.3.1" +version = "0.4.0" authors = ["Niclas Hoyer "] edition = "2018" description = "embedded-hal pin implementations that can be shared between threads" @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" embedded-time = "0.10" num-derive = "0.3" num-traits = "0.2" -embedded-hal = "1.0.0-alpha.4" +embedded-hal = "1.0.0-alpha.6" vcd = { version = "0.6", optional = true } [features] diff --git a/src/pins.rs b/src/pins.rs index 8106410..92ef733 100644 --- a/src/pins.rs +++ b/src/pins.rs @@ -2,15 +2,15 @@ //! //! This module provides implementations of atomic pin types that //! can be used by any [`embedded_hal`] implementation that use -//! [`Input`-](`embedded_hal::digital::InputPin`) or -//! [`OutputPin`s](`embedded_hal::digital::OutputPin`). +//! [`Input`-](`embedded_hal::digital::blocking::InputPin`) or +//! [`OutputPin`s](`embedded_hal::digital::blocking::OutputPin`). //! //! As atomic types these pins use primitive [`atomic`](`std::sync::atomic`) types, //! so that these pins can be shared safely between threads. Especially useful //! for integration testing. use core::convert::Infallible; -use embedded_hal::digital as hal; +use embedded_hal::digital::blocking as hal; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive}; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -73,6 +73,22 @@ impl AtomicPinState { pub fn store(&self, state: PinState, order: Ordering) { self.state.store(state.to_usize().unwrap(), order); } + + /// Updates the state of this atomic pin state based on a stored value. + /// + /// `toggle` takes an [`Ordering`] argument which describes the memory + /// ordering of this operation. For more information see [`AtomicUsize::store`]. + pub fn fetch_update(&self, set_order: Ordering, fetch_order: Ordering, mut f: F) + where + F: FnMut(PinState) -> Option, + { + self.state + .fetch_update(set_order, fetch_order, |pin| { + let pin = PinState::from_usize(pin).unwrap(); + f(pin).map(|x| x.to_usize().unwrap()) + }) + .unwrap(); + } } impl Default for AtomicPinState { @@ -90,14 +106,14 @@ impl Default for AtomicPinState { /// /// ``` /// use embedded_hal_sync_pins::pins::{AtomicPinState, InputPin, PinState}; -/// use embedded_hal::digital::InputPin as HalInputPin; +/// use embedded_hal::digital::blocking::InputPin as HalInputPin; /// use std::sync::{Arc, atomic::Ordering}; /// /// let state = Arc::new(AtomicPinState::new_with_state(PinState::Low)); /// let pin = InputPin::new(state.clone()); -/// assert_eq!(Ok(true), pin.try_is_low()); +/// assert_eq!(Ok(true), pin.is_low()); /// state.store(PinState::High, Ordering::SeqCst); -/// assert_eq!(Ok(true), pin.try_is_high()); +/// assert_eq!(Ok(true), pin.is_high()); /// ``` #[derive(Clone, Debug)] pub struct InputPin { @@ -114,11 +130,11 @@ impl InputPin { impl hal::InputPin for InputPin { type Error = Infallible; - fn try_is_high(&self) -> Result { + fn is_high(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::High) } - fn try_is_low(&self) -> Result { + fn is_low(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::Low) } } @@ -135,15 +151,15 @@ impl hal::InputPin for InputPin { /// /// ``` /// use embedded_hal_sync_pins::pins::{AtomicPinState, PushPullPin, PinState}; -/// use embedded_hal::digital::{InputPin as HalInputPin, OutputPin}; +/// use embedded_hal::digital::blocking::{InputPin as HalInputPin, OutputPin}; /// use std::sync::Arc; /// /// let state = Arc::new(AtomicPinState::new()); /// let mut pin = PushPullPin::new(state.clone()); -/// pin.try_set_low().unwrap(); -/// assert_eq!(Ok(true), pin.try_is_low()); -/// pin.try_set_high().unwrap(); -/// assert_eq!(Ok(true), pin.try_is_high()); +/// pin.set_low().unwrap(); +/// assert_eq!(Ok(true), pin.is_low()); +/// pin.set_high().unwrap(); +/// assert_eq!(Ok(true), pin.is_high()); /// ``` #[derive(Clone, Debug)] pub struct PushPullPin { @@ -159,37 +175,49 @@ impl PushPullPin { impl hal::OutputPin for PushPullPin { type Error = Infallible; - fn try_set_high(&mut self) -> Result<(), Self::Error> { + fn set_high(&mut self) -> Result<(), Self::Error> { self.state.store(PinState::High, Ordering::SeqCst); Ok(()) } - fn try_set_low(&mut self) -> Result<(), Self::Error> { + fn set_low(&mut self) -> Result<(), Self::Error> { self.state.store(PinState::Low, Ordering::SeqCst); Ok(()) } } impl hal::StatefulOutputPin for PushPullPin { - fn try_is_set_high(&self) -> Result { + fn is_set_high(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::High) } - fn try_is_set_low(&self) -> Result { + fn is_set_low(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::Low) } } -impl hal::toggleable::Default for PushPullPin {} +impl hal::ToggleableOutputPin for PushPullPin { + type Error = Infallible; + + fn toggle(&mut self) -> Result<(), Self::Error> { + self.state + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| match x { + PinState::Low => Some(PinState::High), + PinState::High => Some(PinState::Low), + _ => None, + }); + Ok(()) + } +} impl hal::InputPin for PushPullPin { type Error = Infallible; - fn try_is_high(&self) -> Result { + fn is_high(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::High) } - fn try_is_low(&self) -> Result { + fn is_low(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::Low) } } @@ -209,18 +237,18 @@ impl hal::InputPin for PushPullPin { /// /// ``` /// use embedded_hal_sync_pins::pins::{AtomicPinState, OpenDrainPin, PinState}; -/// use embedded_hal::digital::{InputPin as HalInputPin, OutputPin}; +/// use embedded_hal::digital::blocking::{InputPin as HalInputPin, OutputPin}; /// use std::sync::{Arc, atomic::Ordering}; /// /// let state = Arc::new(AtomicPinState::new()); /// let mut pin = OpenDrainPin::new(state.clone()); -/// pin.try_set_low().unwrap(); -/// assert_eq!(Ok(false), pin.try_is_low()); -/// assert_eq!(Ok(false), pin.try_is_high()); +/// pin.set_low().unwrap(); +/// assert_eq!(Ok(false), pin.is_low()); +/// assert_eq!(Ok(false), pin.is_high()); /// assert_eq!(PinState::Floating, state.load(Ordering::SeqCst)); -/// pin.try_set_high().unwrap(); -/// assert_eq!(Ok(false), pin.try_is_high()); -/// assert_eq!(Ok(true), pin.try_is_low()); +/// pin.set_high().unwrap(); +/// assert_eq!(Ok(false), pin.is_high()); +/// assert_eq!(Ok(true), pin.is_low()); /// ``` #[derive(Clone, Debug)] @@ -237,37 +265,49 @@ impl OpenDrainPin { impl hal::OutputPin for OpenDrainPin { type Error = Infallible; - fn try_set_high(&mut self) -> Result<(), Self::Error> { + fn set_high(&mut self) -> Result<(), Self::Error> { self.state.store(PinState::Low, Ordering::SeqCst); Ok(()) } - fn try_set_low(&mut self) -> Result<(), Self::Error> { + fn set_low(&mut self) -> Result<(), Self::Error> { self.state.store(PinState::Floating, Ordering::SeqCst); Ok(()) } } impl hal::StatefulOutputPin for OpenDrainPin { - fn try_is_set_high(&self) -> Result { + fn is_set_high(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::Low) } - fn try_is_set_low(&self) -> Result { + fn is_set_low(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::Floating) } } -impl hal::toggleable::Default for OpenDrainPin {} +impl hal::ToggleableOutputPin for OpenDrainPin { + type Error = Infallible; + + fn toggle(&mut self) -> Result<(), Self::Error> { + self.state + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| match x { + PinState::Low => Some(PinState::Floating), + PinState::Floating => Some(PinState::Low), + _ => None, + }); + Ok(()) + } +} impl hal::InputPin for OpenDrainPin { type Error = Infallible; - fn try_is_high(&self) -> Result { + fn is_high(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::High) } - fn try_is_low(&self) -> Result { + fn is_low(&self) -> Result { Ok(self.state.load(Ordering::SeqCst) == PinState::Low) } } @@ -337,14 +377,14 @@ mod tests { use PinState::*; let state = Arc::new(AtomicPinState::new()); let pin = InputPin::new(state.clone()); - assert_eq!(Ok(false), pin.try_is_high()); - assert_eq!(Ok(false), pin.try_is_low()); + assert_eq!(Ok(false), pin.is_high()); + assert_eq!(Ok(false), pin.is_low()); state.store(High, Ordering::SeqCst); - assert_eq!(Ok(true), pin.try_is_high()); - assert_eq!(Ok(false), pin.try_is_low()); + assert_eq!(Ok(true), pin.is_high()); + assert_eq!(Ok(false), pin.is_low()); state.store(Low, Ordering::SeqCst); - assert_eq!(Ok(false), pin.try_is_high()); - assert_eq!(Ok(true), pin.try_is_low()); + assert_eq!(Ok(false), pin.is_high()); + assert_eq!(Ok(true), pin.is_low()); } #[test] @@ -356,18 +396,18 @@ mod tests { let state = Arc::new(AtomicPinState::new()); let mut pin = PushPullPin::new(state.clone()); assert_eq!(Floating, state.load(Ordering::SeqCst)); - assert_eq!(Ok(()), pin.try_set_high()); + assert_eq!(Ok(()), pin.set_high()); assert_eq!(High, state.load(Ordering::SeqCst)); - assert_eq!(Ok(true), pin.try_is_high()); - assert_eq!(Ok(false), pin.try_is_low()); - assert_eq!(Ok(false), pin.try_is_set_low()); - assert_eq!(Ok(true), pin.try_is_set_high()); - assert_eq!(Ok(()), pin.try_set_low()); - assert_eq!(Ok(true), pin.try_is_set_low()); - assert_eq!(Ok(false), pin.try_is_set_high()); + assert_eq!(Ok(true), pin.is_high()); + assert_eq!(Ok(false), pin.is_low()); + assert_eq!(Ok(false), pin.is_set_low()); + assert_eq!(Ok(true), pin.is_set_high()); + assert_eq!(Ok(()), pin.set_low()); + assert_eq!(Ok(true), pin.is_set_low()); + assert_eq!(Ok(false), pin.is_set_high()); assert_eq!(Low, state.load(Ordering::SeqCst)); - assert_eq!(Ok(false), pin.try_is_high()); - assert_eq!(Ok(true), pin.try_is_low()); + assert_eq!(Ok(false), pin.is_high()); + assert_eq!(Ok(true), pin.is_low()); } #[test] @@ -379,17 +419,17 @@ mod tests { let state = Arc::new(AtomicPinState::new()); let mut pin = OpenDrainPin::new(state.clone()); assert_eq!(Floating, state.load(Ordering::SeqCst)); - assert_eq!(Ok(()), pin.try_set_high()); + assert_eq!(Ok(()), pin.set_high()); assert_eq!(Low, state.load(Ordering::SeqCst)); - assert_eq!(Ok(false), pin.try_is_high()); - assert_eq!(Ok(true), pin.try_is_low()); - assert_eq!(Ok(false), pin.try_is_set_low()); - assert_eq!(Ok(true), pin.try_is_set_high()); - assert_eq!(Ok(()), pin.try_set_low()); + assert_eq!(Ok(false), pin.is_high()); + assert_eq!(Ok(true), pin.is_low()); + assert_eq!(Ok(false), pin.is_set_low()); + assert_eq!(Ok(true), pin.is_set_high()); + assert_eq!(Ok(()), pin.set_low()); assert_eq!(Floating, state.load(Ordering::SeqCst)); - assert_eq!(Ok(false), pin.try_is_high()); - assert_eq!(Ok(false), pin.try_is_low()); - assert_eq!(Ok(true), pin.try_is_set_low()); - assert_eq!(Ok(false), pin.try_is_set_high()); + assert_eq!(Ok(false), pin.is_high()); + assert_eq!(Ok(false), pin.is_low()); + assert_eq!(Ok(true), pin.is_set_low()); + assert_eq!(Ok(false), pin.is_set_high()); } } diff --git a/src/wire.rs b/src/wire.rs index 380e630..48f1591 100644 --- a/src/wire.rs +++ b/src/wire.rs @@ -1,5 +1,4 @@ -use embedded_hal::digital::toggleable::Default as ToggleDefault; -use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin}; +use embedded_hal::digital::blocking::{InputPin, OutputPin, StatefulOutputPin}; use std::convert::Infallible; use std::sync::Arc; use std::sync::Mutex; @@ -75,7 +74,7 @@ impl Wire { continue; } if s != Floating && *state != Floating && *state != s { - panic!(format!("short circuit: {:?}", wire.state)); + panic!("short circuit: {:?}", wire.state); } s = *state; } @@ -124,11 +123,11 @@ pub struct InputOnlyPin { impl InputPin for InputOnlyPin { type Error = Infallible; - fn try_is_high(&self) -> Result { + fn is_high(&self) -> Result { Ok(self.wire.get_state() == WireState::High) } - fn try_is_low(&self) -> Result { + fn is_low(&self) -> Result { Ok(self.wire.get_state() == WireState::Low) } } @@ -141,11 +140,11 @@ pub struct PushPullPin { impl InputPin for PushPullPin { type Error = Infallible; - fn try_is_high(&self) -> Result { + fn is_high(&self) -> Result { Ok(self.wire.get_state() == WireState::High) } - fn try_is_low(&self) -> Result { + fn is_low(&self) -> Result { Ok(self.wire.get_state() == WireState::Low) } } @@ -153,29 +152,27 @@ impl InputPin for PushPullPin { impl OutputPin for PushPullPin { type Error = Infallible; - fn try_set_low(&mut self) -> Result<(), Self::Error> { + fn set_low(&mut self) -> Result<(), Self::Error> { self.wire.set_state(self.id, WireState::Low); Ok(()) } - fn try_set_high(&mut self) -> Result<(), Self::Error> { + fn set_high(&mut self) -> Result<(), Self::Error> { self.wire.set_state(self.id, WireState::High); Ok(()) } } impl StatefulOutputPin for PushPullPin { - fn try_is_set_high(&self) -> Result { + fn is_set_high(&self) -> Result { Ok(self.wire.get_pin_state(self.id) == WireState::High) } - fn try_is_set_low(&self) -> Result { + fn is_set_low(&self) -> Result { Ok(self.wire.get_pin_state(self.id) == WireState::Low) } } -impl ToggleDefault for PushPullPin {} - pub struct OpenDrainPin { wire: Wire, id: PinId, @@ -184,11 +181,11 @@ pub struct OpenDrainPin { impl InputPin for OpenDrainPin { type Error = Infallible; - fn try_is_high(&self) -> Result { + fn is_high(&self) -> Result { Ok(self.wire.get_state() == WireState::High) } - fn try_is_low(&self) -> Result { + fn is_low(&self) -> Result { Ok(self.wire.get_state() == WireState::Low) } } @@ -196,29 +193,27 @@ impl InputPin for OpenDrainPin { impl OutputPin for OpenDrainPin { type Error = Infallible; - fn try_set_low(&mut self) -> Result<(), Self::Error> { + fn set_low(&mut self) -> Result<(), Self::Error> { self.wire.set_state(self.id, WireState::Floating); Ok(()) } - fn try_set_high(&mut self) -> Result<(), Self::Error> { + fn set_high(&mut self) -> Result<(), Self::Error> { self.wire.set_state(self.id, WireState::Low); Ok(()) } } impl StatefulOutputPin for OpenDrainPin { - fn try_is_set_high(&self) -> Result { + fn is_set_high(&self) -> Result { Ok(self.wire.get_pin_state(self.id) == WireState::Low) } - fn try_is_set_low(&self) -> Result { + fn is_set_low(&self) -> Result { Ok(self.wire.get_pin_state(self.id) == WireState::Floating) } } -impl ToggleDefault for OpenDrainPin {} - #[cfg(test)] mod tests { use super::*; @@ -237,10 +232,10 @@ mod tests { let wire = Wire::new_with_pull(High); let mut pin = wire.as_open_drain_pin(); assert_eq!(High, wire.get_state()); - assert_eq!(Ok(()), pin.try_set_high()); + assert_eq!(Ok(()), pin.set_high()); assert_eq!(Low, wire.get_state()); - assert_eq!(Ok(false), pin.try_is_set_low()); - assert_eq!(Ok(true), pin.try_is_set_high()); + assert_eq!(Ok(false), pin.is_set_low()); + assert_eq!(Ok(true), pin.is_set_high()); } #[test] @@ -248,14 +243,14 @@ mod tests { let wire = Wire::new_with_pull(Low); let mut pin = wire.as_push_pull_pin(); assert_eq!(Low, wire.get_state()); - assert_eq!(Ok(()), pin.try_set_high()); - assert_eq!(Ok(false), pin.try_is_set_low()); - assert_eq!(Ok(true), pin.try_is_set_high()); + assert_eq!(Ok(()), pin.set_high()); + assert_eq!(Ok(false), pin.is_set_low()); + assert_eq!(Ok(true), pin.is_set_high()); assert_eq!(High, wire.get_state()); - assert_eq!(Ok(()), pin.try_set_low()); + assert_eq!(Ok(()), pin.set_low()); assert_eq!(Low, wire.get_state()); - assert_eq!(Ok(true), pin.try_is_set_low()); - assert_eq!(Ok(false), pin.try_is_set_high()); + assert_eq!(Ok(true), pin.is_set_low()); + assert_eq!(Ok(false), pin.is_set_high()); } #[test] @@ -264,16 +259,16 @@ mod tests { let mut pin_out = wire.as_push_pull_pin(); let pin_in = wire.as_input_pin(); assert_eq!(Floating, wire.get_state()); - assert_eq!(Ok(false), pin_in.try_is_high()); - assert_eq!(Ok(false), pin_in.try_is_low()); - assert_eq!(Ok(()), pin_out.try_set_low()); + assert_eq!(Ok(false), pin_in.is_high()); + assert_eq!(Ok(false), pin_in.is_low()); + assert_eq!(Ok(()), pin_out.set_low()); assert_eq!(Low, wire.get_state()); - assert_eq!(Ok(false), pin_in.try_is_high()); - assert_eq!(Ok(true), pin_in.try_is_low()); - assert_eq!(Ok(()), pin_out.try_set_high()); + assert_eq!(Ok(false), pin_in.is_high()); + assert_eq!(Ok(true), pin_in.is_low()); + assert_eq!(Ok(()), pin_out.set_high()); assert_eq!(High, wire.get_state()); - assert_eq!(Ok(true), pin_in.try_is_high()); - assert_eq!(Ok(false), pin_in.try_is_low()); + assert_eq!(Ok(true), pin_in.is_high()); + assert_eq!(Ok(false), pin_in.is_low()); } #[test] @@ -282,8 +277,8 @@ mod tests { let wire = Wire::new(); let mut pin1 = wire.as_push_pull_pin(); let mut pin2 = wire.as_push_pull_pin(); - assert_eq!(Ok(()), pin1.try_set_high()); + assert_eq!(Ok(()), pin1.set_high()); // this will cause a short circuit and panic - assert_eq!(Ok(()), pin2.try_set_low()); + assert_eq!(Ok(()), pin2.set_low()); } }