Skip to content

Commit

Permalink
Merge pull request #1 from niclashoyer/1.0.0-alpha.6
Browse files Browse the repository at this point in the history
Refactor for embedded-hal 1.0.0-alpha.6
  • Loading branch information
niclashoyer committed Dec 22, 2021
2 parents de7304d + 9103bcc commit 2458e1b
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 105 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "embedded-hal-sync-pins"
version = "0.3.1"
version = "0.4.0"
authors = ["Niclas Hoyer <info@niclashoyer.de>"]
edition = "2018"
description = "embedded-hal pin implementations that can be shared between threads"
Expand All @@ -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]
Expand Down
160 changes: 100 additions & 60 deletions src/pins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<F>(&self, set_order: Ordering, fetch_order: Ordering, mut f: F)
where
F: FnMut(PinState) -> Option<PinState>,
{
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 {
Expand All @@ -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 {
Expand All @@ -114,11 +130,11 @@ impl InputPin {
impl hal::InputPin for InputPin {
type Error = Infallible;

fn try_is_high(&self) -> Result<bool, Self::Error> {
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.state.load(Ordering::SeqCst) == PinState::High)
}

fn try_is_low(&self) -> Result<bool, Self::Error> {
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.state.load(Ordering::SeqCst) == PinState::Low)
}
}
Expand All @@ -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 {
Expand All @@ -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<bool, Self::Error> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self.state.load(Ordering::SeqCst) == PinState::High)
}

fn try_is_set_low(&self) -> Result<bool, Self::Error> {
fn is_set_low(&self) -> Result<bool, Self::Error> {
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<bool, Self::Error> {
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.state.load(Ordering::SeqCst) == PinState::High)
}

fn try_is_low(&self) -> Result<bool, Self::Error> {
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.state.load(Ordering::SeqCst) == PinState::Low)
}
}
Expand All @@ -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)]
Expand All @@ -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<bool, Self::Error> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self.state.load(Ordering::SeqCst) == PinState::Low)
}

fn try_is_set_low(&self) -> Result<bool, Self::Error> {
fn is_set_low(&self) -> Result<bool, Self::Error> {
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<bool, Self::Error> {
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.state.load(Ordering::SeqCst) == PinState::High)
}

fn try_is_low(&self) -> Result<bool, Self::Error> {
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.state.load(Ordering::SeqCst) == PinState::Low)
}
}
Expand Down Expand Up @@ -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]
Expand All @@ -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]
Expand All @@ -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());
}
}

0 comments on commit 2458e1b

Please sign in to comment.