192: [towards 1.0]: Fallible proven traits r=thejpster a=eldruin

Here some work towards 1.0 following https://github.com/rust-embedded/embedded-hal/issues/177#issuecomment-597682592.

Co-authored-by: Diego Barrios Romero <eldruin@gmail.com>
This commit is contained in:
bors[bot]
2020-03-16 00:05:41 +00:00
committed by GitHub
22 changed files with 231 additions and 939 deletions

View File

@@ -11,8 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- A nonblocking 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`.
- All traits have been marked as proven (`unproven` feature has been removed).
- All trait methods have been made fallible.
- All trait methods have been renamed `try_*` (i.e. `try_send`) for consistency.
- The minimum supported Rust version is 1.35 due to [this issue](https://github.com/rust-lang/rust/issues/54973).
## [v0.2.3] - 2019-05-09

View File

@@ -14,15 +14,10 @@ readme = "README.md"
repository = "https://github.com/rust-embedded/embedded-hal"
version = "0.2.3"
[dependencies.nb]
version = "0.1.1"
[dependencies]
nb = { version = "0.1.1", features = ["unstable"] }
[dev-dependencies]
stm32f3 = { version = "0.8", features = ["stm32f303", "rt"] }
futures = "0.1.17"
[features]
unproven = ["nb/unstable"]
[package.metadata.docs.rs]
features = ["unproven"]

View File

@@ -2,11 +2,10 @@ set -euxo pipefail
main() {
cargo check --target $TARGET
cargo check --target $TARGET --features unproven
cargo fmt -- --check
if [ $TRAVIS_RUST_VERSION = nightly ]; then
cargo test --target $TARGET --features unproven
cargo test --target $TARGET
fi
}

View File

@@ -1,6 +1,5 @@
//! Analog-digital conversion traits
#[cfg(feature = "unproven")]
use nb;
/// A marker trait to identify MCU pins that can be used as inputs to an ADC channel.
@@ -10,7 +9,7 @@ use nb;
/// between the physical interface and the ADC sampling buffer.
///
/// ```
/// # use std::marker::PhantomData;
/// # use core::marker::PhantomData;
/// # use embedded_hal::adc::Channel;
///
/// struct Adc1; // Example ADC with single bank of 8 channels
@@ -21,7 +20,7 @@ use nb;
/// impl Channel<Adc1> for Gpio1Pin1<Analog> {
/// type ID = u8; // ADC channels are identified numerically
///
/// fn channel() -> u8 { 7_u8 } // GPIO pin 1 is connected to ADC channel 7
/// const CHANNEL: u8 = 7_u8; // GPIO pin 1 is connected to ADC channel 7
/// }
///
/// struct Adc2; // ADC with two banks of 16 channels
@@ -32,10 +31,9 @@ use nb;
/// impl Channel<Adc2> for Gpio2PinA<AltFun> {
/// type ID = (u8, u8); // ADC channels are identified by bank number and channel number
///
/// fn channel() -> (u8, u8) { (0, 3) } // bank 0 channel 3
/// const CHANNEL: (u8, u8) = (0, 3); // bank 0 channel 3
/// }
/// ```
#[cfg(feature = "unproven")]
pub trait Channel<ADC> {
/// Channel ID type
///
@@ -46,12 +44,7 @@ pub trait Channel<ADC> {
/// Get the specific ID that identifies this channel, for example `0_u8` for the first ADC
/// channel, if Self::ID is u8.
fn channel() -> Self::ID;
// `channel` is a function due to [this reported
// issue](https://github.com/rust-lang/rust/issues/54973). Something about blanket impls
// combined with `type ID; const CHANNEL: Self::ID;` causes problems.
//const CHANNEL: Self::ID;
const CHANNEL: Self::ID;
}
/// ADCs that sample on single channels per request, and do so at the time of the request.
@@ -76,8 +69,8 @@ pub trait Channel<ADC> {
/// {
/// type Error = ();
///
/// fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
/// let chan = 1 << PIN::channel();
/// fn try_read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
/// let chan = 1 << PIN::CHANNEL;
/// self.power_up();
/// let result = self.do_conversion(chan);
/// self.power_down();
@@ -85,7 +78,6 @@ pub trait Channel<ADC> {
/// }
/// }
/// ```
#[cfg(feature = "unproven")]
pub trait OneShot<ADC, Word, Pin: Channel<ADC>> {
/// Error type returned by ADC methods
type Error;
@@ -94,5 +86,5 @@ pub trait OneShot<ADC, Word, Pin: Channel<ADC>> {
///
/// This method takes a `Pin` reference, as it is expected that the ADC will be able to sample
/// whatever channel underlies the pin.
fn read(&mut self, pin: &mut Pin) -> nb::Result<Word, Self::Error>;
fn try_read(&mut self, pin: &mut Pin) -> nb::Result<Word, Self::Error>;
}

View File

@@ -12,8 +12,11 @@
/// `UXX` denotes the range type of the delay time. `UXX` can be `u8`, `u16`, etc. A single type can
/// implement this trait for different types of `UXX`.
pub trait DelayMs<UXX> {
/// Enumeration of `DelayMs` errors
type Error;
/// Pauses execution for `ms` milliseconds
fn delay_ms(&mut self, ms: UXX);
fn try_delay_ms(&mut self, ms: UXX) -> Result<(), Self::Error>;
}
/// Microsecond delay
@@ -21,6 +24,9 @@ pub trait DelayMs<UXX> {
/// `UXX` denotes the range type of the delay time. `UXX` can be `u8`, `u16`, etc. A single type can
/// implement this trait for different types of `UXX`.
pub trait DelayUs<UXX> {
/// Enumeration of `DelayMs` errors
type Error;
/// Pauses execution for `us` microseconds
fn delay_us(&mut self, us: UXX);
fn try_delay_us(&mut self, us: UXX) -> Result<(), Self::Error>;
}

View File

@@ -28,7 +28,7 @@ pub trait Read {
/// - `MAK` = master acknowledge
/// - `NMAK` = master no acknowledge
/// - `SP` = stop condition
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error>;
fn try_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error>;
}
/// Blocking write
@@ -52,11 +52,10 @@ pub trait Write {
/// - `SAK` = slave acknowledge
/// - `Bi` = ith byte of data
/// - `SP` = stop condition
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error>;
fn try_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error>;
}
/// Blocking write (iterator version)
#[cfg(feature = "unproven")]
pub trait WriteIter {
/// Error type
type Error;
@@ -66,7 +65,7 @@ pub trait WriteIter {
/// # I2C Events (contract)
///
/// Same as `Write`
fn write<B>(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error>
fn try_write<B>(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error>
where
B: IntoIterator<Item = u8>;
}
@@ -98,7 +97,7 @@ pub trait WriteRead {
/// - `MAK` = master acknowledge
/// - `NMAK` = master no acknowledge
/// - `SP` = stop condition
fn write_read(
fn try_write_read(
&mut self,
address: u8,
bytes: &[u8],
@@ -107,7 +106,6 @@ pub trait WriteRead {
}
/// Blocking write (iterator version) + read
#[cfg(feature = "unproven")]
pub trait WriteIterRead {
/// Error type
type Error;
@@ -118,7 +116,7 @@ pub trait WriteIterRead {
/// # I2C Events (contract)
///
/// Same as the `WriteRead` trait
fn write_iter_read<B>(
fn try_write_iter_read<B>(
&mut self,
address: u8,
bytes: B,

View File

@@ -1,9 +1,6 @@
//! Blocking hardware random number generator
/// Blocking read
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
#[cfg(feature = "unproven")]
pub trait Read {
/// Error type
type Error;
@@ -15,5 +12,5 @@ pub trait Read {
///
/// If this function returns an error, it is unspecified how many bytes it has read, but it
/// will never read more than would be necessary to completely fill the buffer.
fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error>;
fn try_read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error>;
}

View File

@@ -10,13 +10,13 @@ pub trait Write<Word> {
/// An implementation can choose to buffer the write, returning `Ok(())`
/// after the complete slice has been written to a buffer, but before all
/// words have been sent via the serial interface. To make sure that
/// everything has been sent, call [`bflush`] after this function returns.
/// everything has been sent, call [`try_bflush`] after this function returns.
///
/// [`bflush`]: #tymethod.bflush
fn bwrite_all(&mut self, buffer: &[Word]) -> Result<(), Self::Error>;
/// [`try_bflush`]: #tymethod.bflush
fn try_bwrite_all(&mut self, buffer: &[Word]) -> Result<(), Self::Error>;
/// Block until the serial interface has sent all buffered words
fn bflush(&mut self) -> Result<(), Self::Error>;
fn try_bflush(&mut self) -> Result<(), Self::Error>;
}
/// Blocking serial write
@@ -38,16 +38,16 @@ pub mod write {
{
type Error = S::Error;
fn bwrite_all(&mut self, buffer: &[Word]) -> Result<(), Self::Error> {
fn try_bwrite_all(&mut self, buffer: &[Word]) -> Result<(), Self::Error> {
for word in buffer {
block!(self.write(word.clone()))?;
block!(self.try_write(word.clone()))?;
}
Ok(())
}
fn bflush(&mut self) -> Result<(), Self::Error> {
block!(self.flush())?;
fn try_bflush(&mut self) -> Result<(), Self::Error> {
block!(self.try_flush())?;
Ok(())
}
}

View File

@@ -6,7 +6,7 @@ pub trait Transfer<W> {
type Error;
/// Sends `words` to the slave. Returns the `words` received from the slave
fn transfer<'w>(&mut self, words: &'w mut [W]) -> Result<&'w [W], Self::Error>;
fn try_transfer<'w>(&mut self, words: &'w mut [W]) -> Result<&'w [W], Self::Error>;
}
/// Blocking write
@@ -15,17 +15,16 @@ pub trait Write<W> {
type Error;
/// Sends `words` to the slave, ignoring all the incoming words
fn write(&mut self, words: &[W]) -> Result<(), Self::Error>;
fn try_write(&mut self, words: &[W]) -> Result<(), Self::Error>;
}
/// Blocking write (iterator version)
#[cfg(feature = "unproven")]
pub trait WriteIter<W> {
/// Error type
type Error;
/// Sends `words` to the slave, ignoring all the incoming words
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
fn try_write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
where
WI: IntoIterator<Item = W>;
}
@@ -43,10 +42,10 @@ pub mod transfer {
{
type Error = S::Error;
fn transfer<'w>(&mut self, words: &'w mut [W]) -> Result<&'w [W], S::Error> {
fn try_transfer<'w>(&mut self, words: &'w mut [W]) -> Result<&'w [W], S::Error> {
for word in words.iter_mut() {
block!(self.send(word.clone()))?;
*word = block!(self.read())?;
block!(self.try_send(word.clone()))?;
*word = block!(self.try_read())?;
}
Ok(words)
@@ -66,10 +65,10 @@ pub mod write {
{
type Error = S::Error;
fn write(&mut self, words: &[W]) -> Result<(), S::Error> {
fn try_write(&mut self, words: &[W]) -> Result<(), S::Error> {
for word in words {
block!(self.send(word.clone()))?;
block!(self.read())?;
block!(self.try_send(word.clone()))?;
block!(self.try_read())?;
}
Ok(())
@@ -78,7 +77,6 @@ pub mod write {
}
/// Blocking write (iterator version)
#[cfg(feature = "unproven")]
pub mod write_iter {
/// Default implementation of `blocking::spi::WriteIter<W>` for implementers of
/// `spi::FullDuplex<W>`
@@ -91,13 +89,13 @@ pub mod write_iter {
{
type Error = S::Error;
fn write_iter<WI>(&mut self, words: WI) -> Result<(), S::Error>
fn try_write_iter<WI>(&mut self, words: WI) -> Result<(), S::Error>
where
WI: IntoIterator<Item = W>,
{
for word in words.into_iter() {
block!(self.send(word.clone()))?;
block!(self.read())?;
block!(self.try_send(word.clone()))?;
block!(self.try_read())?;
}
Ok(())

View File

@@ -1,6 +1,4 @@
//! Digital I/O
//!
//! Version 2 / fallible traits. Infallible implementations should set Error to `!`.
/// Single digital push-pull output pin
pub trait OutputPin {
@@ -11,55 +9,49 @@ pub trait OutputPin {
///
/// *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) -> Result<(), Self::Error>;
fn try_set_low(&mut self) -> Result<(), Self::Error>;
/// 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) -> Result<(), Self::Error>;
fn try_set_high(&mut self) -> Result<(), Self::Error>;
}
/// Push-pull output pin that can read its output state
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
#[cfg(feature = "unproven")]
pub trait StatefulOutputPin: OutputPin {
/// Is the pin in drive high mode?
///
/// *NOTE* this does *not* read the electrical state of the pin
fn is_set_high(&self) -> Result<bool, Self::Error>;
fn try_is_set_high(&self) -> Result<bool, Self::Error>;
/// Is the pin in drive low mode?
///
/// *NOTE* this does *not* read the electrical state of the pin
fn is_set_low(&self) -> Result<bool, Self::Error>;
fn try_is_set_low(&self) -> Result<bool, Self::Error>;
}
/// Output pin that can be toggled
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
///
/// 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 {
/// Error type
type Error;
/// Toggle pin output.
fn toggle(&mut self) -> Result<(), Self::Error>;
fn try_toggle(&mut self) -> Result<(), Self::Error>;
}
/// If you can read **and** write the output state, a pin is
/// toggleable by software.
///
/// ```
/// use embedded_hal::digital::v2::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
/// use embedded_hal::digital::v2::toggleable;
/// use std::convert::Infallible;
/// use embedded_hal::digital::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
/// use embedded_hal::digital::toggleable;
/// use core::convert::Infallible;
///
/// /// A virtual output pin that exists purely in software
/// struct MyPin {
@@ -69,21 +61,21 @@ pub trait ToggleableOutputPin {
/// impl OutputPin for MyPin {
/// type Error = Infallible;
///
/// fn set_low(&mut self) -> Result<(), Self::Error> {
/// fn try_set_low(&mut self) -> Result<(), Self::Error> {
/// self.state = false;
/// Ok(())
/// }
/// fn set_high(&mut self) -> Result<(), Self::Error> {
/// fn try_set_high(&mut self) -> Result<(), Self::Error> {
/// self.state = true;
/// Ok(())
/// }
/// }
///
/// impl StatefulOutputPin for MyPin {
/// fn is_set_low(&self) -> Result<bool, Self::Error> {
/// fn try_is_set_low(&self) -> Result<bool, Self::Error> {
/// Ok(!self.state)
/// }
/// fn is_set_high(&self) -> Result<bool, Self::Error> {
/// fn try_is_set_high(&self) -> Result<bool, Self::Error> {
/// Ok(self.state)
/// }
/// }
@@ -92,18 +84,15 @@ pub trait ToggleableOutputPin {
/// impl toggleable::Default for MyPin {}
///
/// let mut pin = MyPin { state: false };
/// pin.toggle().unwrap();
/// assert!(pin.is_set_high().unwrap());
/// pin.toggle().unwrap();
/// assert!(pin.is_set_low().unwrap());
/// pin.try_toggle().unwrap();
/// assert!(pin.try_is_set_high().unwrap());
/// pin.try_toggle().unwrap();
/// assert!(pin.try_is_set_low().unwrap());
/// ```
#[cfg(feature = "unproven")]
pub mod toggleable {
use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
/// Software-driven `toggle()` implementation.
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
pub trait Default: OutputPin + StatefulOutputPin {}
impl<P> ToggleableOutputPin for P
@@ -113,11 +102,11 @@ pub mod toggleable {
type Error = P::Error;
/// Toggle pin output
fn toggle(&mut self) -> Result<(), Self::Error> {
if self.is_set_low()? {
self.set_high()
fn try_toggle(&mut self) -> Result<(), Self::Error> {
if self.try_is_set_low()? {
self.try_set_high()
} else {
self.set_low()
self.try_set_low()
}
}
}
@@ -129,8 +118,8 @@ pub trait InputPin {
type Error;
/// Is the input pin high?
fn is_high(&self) -> Result<bool, Self::Error>;
fn try_is_high(&self) -> Result<bool, Self::Error>;
/// Is the input pin low?
fn is_low(&self) -> Result<bool, Self::Error>;
fn try_is_low(&self) -> Result<bool, Self::Error>;
}

View File

@@ -1,27 +0,0 @@
//! Digital I/O
//!
//!
//!
// 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
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;
// Re-export old traits so this isn't a breaking change
#[allow(deprecated)]
pub use self::v1::*;

View File

@@ -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<P> 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;
}

View File

@@ -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<T: v1::OutputPin> {
//! _pin: T,
//! }
//!
//! impl <T>OldOutputPinConsumer<T>
//! where T: v1::OutputPin {
//! pub fn new(pin: T) -> OldOutputPinConsumer<T> {
//! OldOutputPinConsumer{ _pin: pin }
//! }
//! }
//!
//! fn main() {
//! let pin = NewOutputPinImpl{};
//! let _consumer: OldOutputPinConsumer<OldOutputPin<_>> = 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<T> {
pin: T,
}
impl<T, E> OldOutputPin<T>
where
T: v2::OutputPin<Error = E>,
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<T, E> From<T> for OldOutputPin<T>
where
T: v2::OutputPin<Error = E>,
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<T, E> v1::OutputPin for OldOutputPin<T>
where
T: v2::OutputPin<Error = E>,
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<T, E> v1::StatefulOutputPin for OldOutputPin<T>
where
T: v2::StatefulOutputPin<Error = E>,
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<T> {
pin: T,
}
impl<T, E> OldInputPin<T>
where
T: v2::OutputPin<Error = E>,
E: core::fmt::Debug,
{
/// Create an `OldInputPin` wrapper around a `v2::InputPin`.
pub fn new(pin: T) -> Self {
Self { pin }
}
}
impl<T, E> From<T> for OldInputPin<T>
where
T: v2::InputPin<Error = E>,
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<T, E> v1::InputPin for OldInputPin<T>
where
T: v2::InputPin<Error = E>,
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<T: v1::OutputPin> {
_pin: T,
}
#[allow(deprecated)]
impl<T> OldOutputPinConsumer<T>
where
T: v1::OutputPin,
{
pub fn new(pin: T) -> OldOutputPinConsumer<T> {
OldOutputPinConsumer { _pin: pin }
}
}
#[test]
fn v1_v2_output_explicit() {
let i = NewOutputPinImpl {
state: false,
res: Ok(()),
};
let _c: OldOutputPinConsumer<OldOutputPin<_>> = 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<bool, ()>,
}
impl v2::InputPin for NewInputPinImpl {
type Error = ();
fn is_low(&self) -> Result<bool, Self::Error> {
self.state.map(|v| v == false)
}
fn is_high(&self) -> Result<bool, Self::Error> {
self.state.map(|v| v == true)
}
}
#[allow(deprecated)]
struct OldInputPinConsumer<T: v1::InputPin> {
_pin: T,
}
#[allow(deprecated)]
impl<T> OldInputPinConsumer<T>
where
T: v1::InputPin,
{
pub fn new(pin: T) -> OldInputPinConsumer<T> {
OldInputPinConsumer { _pin: pin }
}
}
#[test]
fn v1_v2_input_explicit() {
let i = NewInputPinImpl { state: Ok(false) };
let _c: OldInputPinConsumer<OldInputPin<_>> = 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();
}
}

View File

@@ -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<T: v2::OutputPin> {
//! _pin: T,
//! }
//!
//! impl <T>NewOutputPinConsumer<T>
//! where T: v2::OutputPin {
//! pub fn new(pin: T) -> NewOutputPinConsumer<T> {
//! 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<T> 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<T> v2::StatefulOutputPin for T
where
T: v1::StatefulOutputPin + v1::OutputPin,
{
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_low())
}
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_high())
}
}
#[cfg(feature = "unproven")]
#[allow(deprecated)]
impl<T> v2::toggleable::Default for T where T: v1::toggleable::Default {}
/// Implementation of fallible `v2::InputPin` for `v1::InputPin` digital traits
#[allow(deprecated)]
impl<T> v2::InputPin for T
where
T: v1::InputPin,
{
type Error = Infallible;
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_low())
}
fn is_high(&self) -> Result<bool, Self::Error> {
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<T: v2::OutputPin> {
_pin: T,
}
impl<T> NewOutputPinConsumer<T>
where
T: v2::OutputPin,
{
pub fn new(pin: T) -> NewOutputPinConsumer<T> {
NewOutputPinConsumer { _pin: pin }
}
}
#[cfg(feature = "unproven")]
struct NewToggleablePinConsumer<T: v2::ToggleableOutputPin> {
_pin: T,
}
#[cfg(feature = "unproven")]
impl<T> NewToggleablePinConsumer<T>
where
T: v2::ToggleableOutputPin,
{
pub fn new(pin: T) -> NewToggleablePinConsumer<T> {
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<T: v2::InputPin> {
_pin: T,
}
impl<T> NewInputPinConsumer<T>
where
T: v2::InputPin,
{
pub fn new(pin: T) -> NewInputPinConsumer<T> {
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);
}
}

View File

@@ -11,7 +11,7 @@ where
let _ = s
.as_bytes()
.into_iter()
.map(|c| block!(self.write(Word::from(*c))))
.map(|c| block!(self.try_write(Word::from(*c))))
.last();
Ok(())
}

View File

@@ -2,10 +2,7 @@
//!
//! **NOTE** This HAL is still is active development. Expect the traits presented here to be
//! tweaked, split or be replaced wholesale before being stabilized, i.e. before hitting the 1.0.0
//! release. That being said there's a part of the HAL that's currently considered unproven and is
//! hidden behind an "unproven" Cargo feature. This API is even more volatile and it's exempt from
//! semver rules: it can change in a non-backward compatible fashion or even disappear in between
//! patch releases.
//! release.
//!
//! # Design goals
//!
@@ -75,10 +72,10 @@
//! type Error;
//!
//! /// Reads a single byte
//! fn read(&mut self) -> nb::Result<u8, Self::Error>;
//! fn try_read(&mut self) -> nb::Result<u8, Self::Error>;
//!
//! /// Writes a single byte
//! fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error>;
//! fn try_write(&mut self, byte: u8) -> nb::Result<(), Self::Error>;
//! }
//! ```
//!
@@ -103,7 +100,7 @@
//! // ..
//!
//! /// "waits" until the count down is over
//! fn wait(&mut self) -> nb::Result<(), Infallible>;
//! fn try_wait(&mut self) -> nb::Result<(), Infallible>;
//! }
//!
//! # fn main() {}
@@ -150,7 +147,7 @@
//! impl hal::serial::Read<u8> for Serial<USART1> {
//! type Error = Error;
//!
//! fn read(&mut self) -> nb::Result<u8, Error> {
//! fn try_read(&mut self) -> nb::Result<u8, Error> {
//! // read the status register
//! let isr = self.usart.isr.read();
//!
@@ -172,13 +169,13 @@
//! impl hal::serial::Write<u8> for Serial<USART1> {
//! type Error = Error;
//!
//! fn write(&mut self, byte: u8) -> nb::Result<(), Error> {
//! // Similar to the `read` implementation
//! fn try_write(&mut self, byte: u8) -> nb::Result<(), Error> {
//! // Similar to the `try_read` implementation
//! # Ok(())
//! }
//!
//! fn flush(&mut self) -> nb::Result<(), Error> {
//! // Similar to the `read` implementation
//! fn try_flush(&mut self) -> nb::Result<(), Error> {
//! // Similar to the `try_read` implementation
//! # Ok(())
//! }
//! }
@@ -216,17 +213,17 @@
//! };
//!
//! for byte in b"Hello, world!" {
//! // NOTE `block!` blocks until `serial.write()` completes and returns
//! // NOTE `block!` blocks until `serial.try_write()` completes and returns
//! // `Result<(), Error>`
//! block!(serial.write(*byte)).unwrap();
//! block!(serial.try_write(*byte)).unwrap();
//! }
//! # }
//!
//! # mod stm32f30x_hal {
//! # use std::convert::Infallible;
//! # use core::convert::Infallible;
//! # pub struct Serial1;
//! # impl Serial1 {
//! # pub fn write(&mut self, _: u8) -> ::nb::Result<(), Infallible> {
//! # pub fn try_write(&mut self, _: u8) -> ::nb::Result<(), Infallible> {
//! # Ok(())
//! # }
//! # }
@@ -255,9 +252,9 @@
//! };
//! use futures::future::Loop;
//! use stm32f30x_hal::{Led, Serial1, Timer6};
//! use std::convert::Infallible;
//! use core::convert::Infallible;
//!
//! /// `futures` version of `CountDown.wait`
//! /// `futures` version of `CountDown.try_wait`
//! ///
//! /// This returns a future that must be polled to completion
//! fn wait<T>(mut timer: T) -> impl Future<Item = T, Error = Infallible>
@@ -266,7 +263,7 @@
//! {
//! let mut timer = Some(timer);
//! future::poll_fn(move || {
//! try_nb!(timer.as_mut().unwrap().wait());
//! try_nb!(timer.as_mut().unwrap().try_wait());
//!
//! Ok(Async::Ready(timer.take().unwrap()))
//! })
@@ -281,7 +278,7 @@
//! {
//! let mut serial = Some(serial);
//! future::poll_fn(move || {
//! let byte = try_nb!(serial.as_mut().unwrap().read());
//! let byte = try_nb!(serial.as_mut().unwrap().try_read());
//!
//! Ok(Async::Ready((serial.take().unwrap(), byte)))
//! })
@@ -296,7 +293,7 @@
//! {
//! let mut serial = Some(serial);
//! future::poll_fn(move || {
//! try_nb!(serial.as_mut().unwrap().write(byte));
//! try_nb!(serial.as_mut().unwrap().try_write(byte));
//!
//! Ok(Async::Ready(serial.take().unwrap()))
//! })
@@ -349,24 +346,24 @@
//! }
//!
//! # mod stm32f30x_hal {
//! # use std::convert::Infallible;
//! # use core::convert::Infallible;
//! # pub struct Timer6;
//! # impl ::hal::timer::CountDown for Timer6 {
//! # type Time = ();
//! #
//! # fn start<T>(&mut self, _: T) where T: Into<()> {}
//! # fn wait(&mut self) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # fn try_start<T>(&mut self, _: T) -> Result<(), Infallible> where T: Into<()> {}
//! # fn try_wait(&mut self) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # }
//! #
//! # pub struct Serial1;
//! # impl ::hal::serial::Read<u8> for Serial1 {
//! # type Error = Infallible;
//! # fn read(&mut self) -> ::nb::Result<u8, Infallible> { Err(::nb::Error::WouldBlock) }
//! # fn try_read(&mut self) -> ::nb::Result<u8, Infallible> { Err(::nb::Error::WouldBlock) }
//! # }
//! # impl ::hal::serial::Write<u8> for Serial1 {
//! # type Error = Infallible;
//! # fn flush(&mut self) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # fn write(&mut self, _: u8) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # fn try_flush(&mut self) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # fn try_write(&mut self, _: u8) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # }
//! #
//! # pub struct Led;
@@ -392,8 +389,8 @@
//! #[macro_use(r#await)]
//! extern crate nb;
//!
//! use std::ops::Generator;
//! use std::pin::Pin;
//! use core::ops::Generator;
//! use core::pin::Pin;
//!
//! use hal::prelude::*;
//! use stm32f30x_hal::{Led, Serial1, Timer6};
@@ -419,7 +416,7 @@
//! loop {
//! // `await!` means "suspend / yield here" instead of "block until
//! // completion"
//! nb::r#await!(timer.wait()).unwrap(); // NOTE(unwrap) E = Infallible
//! nb::r#await!(timer.try_wait()).unwrap(); // NOTE(unwrap) E = Infallible
//!
//! state = !state;
//!
@@ -433,8 +430,8 @@
//!
//! let mut loopback = (move || {
//! loop {
//! let byte = nb::r#await!(serial.read()).unwrap();
//! nb::r#await!(serial.write(byte)).unwrap();
//! let byte = nb::r#await!(serial.try_read()).unwrap();
//! nb::r#await!(serial.try_write(byte)).unwrap();
//! }
//! });
//!
@@ -447,15 +444,15 @@
//! }
//!
//! # mod stm32f30x_hal {
//! # use std::convert::Infallible;
//! # use core::convert::Infallible;
//! # pub struct Serial1;
//! # impl Serial1 {
//! # pub fn read(&mut self) -> ::nb::Result<u8, Infallible> { Err(::nb::Error::WouldBlock) }
//! # pub fn write(&mut self, _: u8) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # pub fn try_read(&mut self) -> ::nb::Result<u8, Infallible> { Err(::nb::Error::WouldBlock) }
//! # pub fn try_write(&mut self, _: u8) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # }
//! # pub struct Timer6;
//! # impl Timer6 {
//! # pub fn wait(&mut self) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # pub fn try_wait(&mut self) -> ::nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # }
//! # pub struct Led;
//! # impl Led {
@@ -492,7 +489,7 @@
//! S: hal::serial::Write<u8>
//! {
//! for &byte in buffer {
//! block!(serial.write(byte))?;
//! block!(serial.try_write(byte))?;
//! }
//!
//! Ok(())
@@ -509,25 +506,26 @@
//!
//! use hal::prelude::*;
//!
//! enum Error<E> {
//! enum Error<SE, TE> {
//! /// Serial interface error
//! Serial(E),
//! TimedOut,
//! Serial(SE),
//! /// Timeout error
//! TimedOut(TE),
//! }
//!
//! fn read_with_timeout<S, T>(
//! serial: &mut S,
//! timer: &mut T,
//! timeout: T::Time,
//! ) -> Result<u8, Error<S::Error>>
//! ) -> Result<u8, Error<S::Error, T::Error>>
//! where
//! T: hal::timer::CountDown,
//! T: hal::timer::CountDown<Error = ()>,
//! S: hal::serial::Read<u8>,
//! {
//! timer.start(timeout);
//! timer.try_start(timeout).map_err(Error::TimedOut)?;
//!
//! loop {
//! match serial.read() {
//! match serial.try_read() {
//! // raise error
//! Err(nb::Error::Other(e)) => return Err(Error::Serial(e)),
//! Err(nb::Error::WouldBlock) => {
@@ -536,16 +534,16 @@
//! Ok(byte) => return Ok(byte),
//! }
//!
//! match timer.wait() {
//! match timer.try_wait() {
//! Err(nb::Error::Other(e)) => {
//! // The error type specified by `timer.wait()` is `!`, which
//! // The error type specified by `timer.try_wait()` is `!`, which
//! // means no error can actually occur. The Rust compiler
//! // still forces us to provide this match arm, though.
//! unreachable!()
//! },
//! // no timeout yet, try again
//! Err(nb::Error::WouldBlock) => continue,
//! Ok(()) => return Err(Error::TimedOut),
//! Ok(()) => return Err(Error::TimedOut(())),
//! }
//! }
//! }
@@ -564,7 +562,7 @@
//! #[macro_use(r#await)]
//! extern crate nb;
//!
//! use std::ops::Generator;
//! use core::ops::Generator;
//!
//! /// Transfers a byte buffer of size N
//! ///
@@ -580,8 +578,8 @@
//! move || {
//! let n = buffer.len();
//! for i in 0..n {
//! nb::r#await!(spi.send(buffer[i]))?;
//! buffer[i] = nb::r#await!(spi.read())?;
//! nb::r#await!(spi.try_send(buffer[i]))?;
//! buffer[i] = nb::r#await!(spi.try_read())?;
//! }
//!
//! Ok((spi, buffer))
@@ -607,7 +605,7 @@
//! {
//! loop {
//! if let Some(byte) = cb.peek() {
//! match serial.write(*byte) {
//! match serial.try_write(*byte) {
//! Err(nb::Error::Other(_)) => unreachable!(),
//! Err(nb::Error::WouldBlock) => return,
//! Ok(()) => {}, // keep flushing data
@@ -659,18 +657,18 @@
//! # fn lock(&self) -> RefMut<T> { unimplemented!() }
//! # }
//! # struct RefMut<'a, T>(&'a mut T) where T: 'a;
//! # impl<'a, T> ::std::ops::Deref for RefMut<'a, T> {
//! # impl<'a, T> ::core::ops::Deref for RefMut<'a, T> {
//! # type Target = T;
//! # fn deref(&self) -> &T { self.0 }
//! # }
//! # impl<'a, T> ::std::ops::DerefMut for RefMut<'a, T> {
//! # impl<'a, T> ::core::ops::DerefMut for RefMut<'a, T> {
//! # fn deref_mut(&mut self) -> &mut T { self.0 }
//! # }
//! # struct Serial1;
//! # impl ::hal::serial::Write<u8> for Serial1 {
//! # type Error = Infallible;
//! # fn write(&mut self, _: u8) -> nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # fn flush(&mut self) -> nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # fn try_write(&mut self, _: u8) -> nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # fn try_flush(&mut self) -> nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
//! # }
//! # struct CircularBuffer;
//! # impl CircularBuffer {
@@ -701,8 +699,6 @@ pub mod watchdog;
/// Input capture
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
///
/// # Examples
///
/// You can use this interface to measure the period of (quasi) periodic signals
@@ -721,36 +717,35 @@ pub mod watchdog;
/// # Capture1
/// };
///
/// capture.set_resolution(1.ms());
/// capture.try_set_resolution(1.ms()).unwrap();
///
/// let before = block!(capture.capture(Channel::_1)).unwrap();
/// let after = block!(capture.capture(Channel::_1)).unwrap();
/// let before = block!(capture.try_capture(Channel::_1)).unwrap();
/// let after = block!(capture.try_capture(Channel::_1)).unwrap();
///
/// let period = after.wrapping_sub(before);
///
/// println!("Period: {} ms", period);
/// }
///
/// # use std::convert::Infallible;
/// # use core::convert::Infallible;
/// # struct MilliSeconds(u32);
/// # trait U32Ext { fn ms(self) -> MilliSeconds; }
/// # impl U32Ext for u32 { fn ms(self) -> MilliSeconds { MilliSeconds(self) } }
/// # struct Capture1;
/// # enum Channel { _1 }
/// # impl hal::Capture for Capture1 {
/// # type Error = Infallible;
/// # type Capture = u16;
/// # type Channel = Channel;
/// # type Error = Infallible;
/// # type Time = MilliSeconds;
/// # fn capture(&mut self, _: Channel) -> ::nb::Result<u16, Infallible> { Ok(0) }
/// # fn disable(&mut self, _: Channel) { unimplemented!() }
/// # fn enable(&mut self, _: Channel) { unimplemented!() }
/// # fn get_resolution(&self) -> MilliSeconds { unimplemented!() }
/// # fn set_resolution<T>(&mut self, _: T) where T: Into<MilliSeconds> {}
/// # fn try_capture(&mut self, _: Channel) -> ::nb::Result<u16, Self::Error> { Ok(0) }
/// # fn try_disable(&mut self, _: Channel) -> Result<(), Self::Error> { unimplemented!() }
/// # fn try_enable(&mut self, _: Channel) -> Result<(), Self::Error> { unimplemented!() }
/// # fn try_get_resolution(&self) -> Result<MilliSeconds, Self::Error> { unimplemented!() }
/// # fn try_set_resolution<T>(&mut self, _: T) -> Result<(), Self::Error> where T: Into<MilliSeconds> { Ok(()) }
/// # }
/// ```
#[cfg(feature = "unproven")]
// reason: pre-singletons API. With singletons a `CapturePin` (cf. `PwmPin`) trait seems more
// unproven reason: pre-singletons API. With singletons a `CapturePin` (cf. `PwmPin`) trait seems more
// appropriate
pub trait Capture {
/// Enumeration of `Capture` errors
@@ -778,27 +773,25 @@ pub trait Capture {
///
/// NOTE that you must multiply the returned value by the *resolution* of
/// this `Capture` interface to get a human time unit (e.g. seconds)
fn capture(&mut self, channel: Self::Channel) -> nb::Result<Self::Capture, Self::Error>;
fn try_capture(&mut self, channel: Self::Channel) -> nb::Result<Self::Capture, Self::Error>;
/// Disables a capture `channel`
fn disable(&mut self, channel: Self::Channel);
fn try_disable(&mut self, channel: Self::Channel) -> Result<(), Self::Error>;
/// Enables a capture `channel`
fn enable(&mut self, channel: Self::Channel);
fn try_enable(&mut self, channel: Self::Channel) -> Result<(), Self::Error>;
/// Returns the current resolution
fn get_resolution(&self) -> Self::Time;
fn try_get_resolution(&self) -> Result<Self::Time, Self::Error>;
/// Sets the resolution of the capture timer
fn set_resolution<R>(&mut self, resolution: R)
fn try_set_resolution<R>(&mut self, resolution: R) -> Result<(), Self::Error>
where
R: Into<Self::Time>;
}
/// Pulse Width Modulation
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
///
/// # Examples
///
/// Use this interface to control the power output of some actuator
@@ -814,39 +807,43 @@ pub trait Capture {
/// # Pwm1
/// };
///
/// pwm.set_period(1.khz());
/// pwm.try_set_period(1.khz()).unwrap();
///
/// let max_duty = pwm.get_max_duty();
/// let max_duty = pwm.try_get_max_duty().unwrap();
///
/// // brightest LED
/// pwm.set_duty(Channel::_1, max_duty);
/// pwm.try_set_duty(Channel::_1, max_duty).unwrap();
///
/// // dimmer LED
/// pwm.set_duty(Channel::_2, max_duty / 4);
/// pwm.try_set_duty(Channel::_2, max_duty / 4).unwrap();
/// }
///
/// # use core::convert::Infallible;
/// # struct KiloHertz(u32);
/// # trait U32Ext { fn khz(self) -> KiloHertz; }
/// # impl U32Ext for u32 { fn khz(self) -> KiloHertz { KiloHertz(self) } }
/// # enum Channel { _1, _2 }
/// # struct Pwm1;
/// # impl hal::Pwm for Pwm1 {
/// # type Error = Infallible;
/// # type Channel = Channel;
/// # type Time = KiloHertz;
/// # type Duty = u16;
/// # fn disable(&mut self, _: Channel) { unimplemented!() }
/// # fn enable(&mut self, _: Channel) { unimplemented!() }
/// # fn get_duty(&self, _: Channel) -> u16 { unimplemented!() }
/// # fn get_max_duty(&self) -> u16 { 0 }
/// # fn set_duty(&mut self, _: Channel, _: u16) {}
/// # fn get_period(&self) -> KiloHertz { unimplemented!() }
/// # fn set_period<T>(&mut self, _: T) where T: Into<KiloHertz> {}
/// # fn try_disable(&mut self, _: Channel) -> Result<(), Self::Error> { unimplemented!() }
/// # fn try_enable(&mut self, _: Channel) -> Result<(), Self::Error> { unimplemented!() }
/// # fn try_get_duty(&self, _: Channel) -> Result<u16, Self::Error> { unimplemented!() }
/// # fn try_get_max_duty(&self) -> Result<u16, Self::Error> { Ok(0) }
/// # fn try_set_duty(&mut self, _: Channel, _: u16) -> Result<(), Self::Error> { Ok(()) }
/// # fn try_get_period(&self) -> Result<KiloHertz, Self::Error> { unimplemented!() }
/// # fn try_set_period<T>(&mut self, _: T) -> Result<(), Self::Error> where T: Into<KiloHertz> { Ok(()) }
/// # }
/// ```
#[cfg(feature = "unproven")]
// reason: pre-singletons API. The `PwmPin` trait seems more useful because it models independent
// unproven reason: pre-singletons API. The `PwmPin` trait seems more useful because it models independent
// PWM channels. Here a certain number of channels are multiplexed in a single implementer.
pub trait Pwm {
/// Enumeration of `Pwm` errors
type Error;
/// Enumeration of channels that can be used with this `Pwm` interface
///
/// If your `Pwm` interface has no channels you can use the type `()`
@@ -863,25 +860,26 @@ pub trait Pwm {
type Duty;
/// Disables a PWM `channel`
fn disable(&mut self, channel: Self::Channel);
fn try_disable(&mut self, channel: Self::Channel) -> Result<(), Self::Error>;
/// Enables a PWM `channel`
fn enable(&mut self, channel: Self::Channel);
fn try_enable(&mut self, channel: Self::Channel) -> Result<(), Self::Error>;
/// Returns the current PWM period
fn get_period(&self) -> Self::Time;
fn try_get_period(&self) -> Result<Self::Time, Self::Error>;
/// Returns the current duty cycle
fn get_duty(&self, channel: Self::Channel) -> Self::Duty;
fn try_get_duty(&self, channel: Self::Channel) -> Result<Self::Duty, Self::Error>;
/// Returns the maximum duty cycle value
fn get_max_duty(&self) -> Self::Duty;
fn try_get_max_duty(&self) -> Result<Self::Duty, Self::Error>;
/// Sets a new duty cycle
fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty);
fn try_set_duty(&mut self, channel: Self::Channel, duty: Self::Duty)
-> Result<(), Self::Error>;
/// Sets a new PWM period
fn set_period<P>(&mut self, period: P)
fn try_set_period<P>(&mut self, period: P) -> Result<(), Self::Error>
where
P: Into<Self::Time>;
}
@@ -890,6 +888,9 @@ pub trait Pwm {
///
/// See `Pwm` for details
pub trait PwmPin {
/// Enumeration of `PwmPin` errors
type Error;
/// Type for the `duty` methods
///
/// The implementer is free to choose a float / percentage representation
@@ -897,25 +898,23 @@ pub trait PwmPin {
type Duty;
/// Disables a PWM `channel`
fn disable(&mut self);
fn try_disable(&mut self) -> Result<(), Self::Error>;
/// Enables a PWM `channel`
fn enable(&mut self);
fn try_enable(&mut self) -> Result<(), Self::Error>;
/// Returns the current duty cycle
fn get_duty(&self) -> Self::Duty;
fn try_get_duty(&self) -> Result<Self::Duty, Self::Error>;
/// Returns the maximum duty cycle value
fn get_max_duty(&self) -> Self::Duty;
fn try_get_max_duty(&self) -> Result<Self::Duty, Self::Error>;
/// Sets a new duty cycle
fn set_duty(&mut self, duty: Self::Duty);
fn try_set_duty(&mut self, duty: Self::Duty) -> Result<(), Self::Error>;
}
/// Quadrature encoder interface
///
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
///
/// # Examples
///
/// You can use this interface to measure the speed of a motor
@@ -938,52 +937,52 @@ pub trait PwmPin {
/// };
///
///
/// let before = qei.count();
/// timer.start(1.s());
/// block!(timer.wait());
/// let after = qei.count();
/// let before = qei.try_count().unwrap();
/// timer.try_start(1.s()).unwrap();
/// block!(timer.try_wait());
/// let after = qei.try_count().unwrap();
///
/// let speed = after.wrapping_sub(before);
/// println!("Speed: {} pulses per second", speed);
/// }
///
/// # use std::convert::Infallible;
/// # use core::convert::Infallible;
/// # struct Seconds(u32);
/// # trait U32Ext { fn s(self) -> Seconds; }
/// # impl U32Ext for u32 { fn s(self) -> Seconds { Seconds(self) } }
/// # struct Qei1;
/// # impl hal::Qei for Qei1 {
/// # type Error = Infallible;
/// # type Count = u16;
/// # fn count(&self) -> u16 { 0 }
/// # fn direction(&self) -> ::hal::Direction { unimplemented!() }
/// # fn try_count(&self) -> Result<u16, Self::Error> { Ok(0) }
/// # fn try_direction(&self) -> Result<::hal::Direction, Self::Error> { unimplemented!() }
/// # }
/// # struct Timer6;
/// # impl hal::timer::CountDown for Timer6 {
/// # type Error = Infallible;
/// # type Time = Seconds;
/// # fn start<T>(&mut self, _: T) where T: Into<Seconds> {}
/// # fn wait(&mut self) -> ::nb::Result<(), Infallible> { Ok(()) }
/// # fn try_start<T>(&mut self, _: T) -> Result<(), Infallible> where T: Into<Seconds> { Ok(()) }
/// # fn try_wait(&mut self) -> ::nb::Result<(), Infallible> { Ok(()) }
/// # }
/// ```
#[cfg(feature = "unproven")]
// reason: needs to be re-evaluated in the new singletons world. At the very least this needs a
// unproven reason: needs to be re-evaluated in the new singletons world. At the very least this needs a
// reference implementation
pub trait Qei {
/// Enumeration of `Qei` errors
type Error;
/// The type of the value returned by `count`
type Count;
/// Returns the current pulse count of the encoder
fn count(&self) -> Self::Count;
fn try_count(&self) -> Result<Self::Count, Self::Error>;
/// Returns the count direction
fn direction(&self) -> Direction;
fn try_direction(&self) -> Result<Direction, Self::Error>;
}
/// Count direction
///
/// *This enumeration is available if embedded-hal is built with the `"unproven"` feature.*
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg(feature = "unproven")]
// reason: part of the unproven `Qei` interface
pub enum Direction {
/// 3, 2, 1
Downcounting,

View File

@@ -3,7 +3,6 @@
//! The traits have been renamed to avoid collisions with other items when
//! performing a glob import.
#[cfg(feature = "unproven")]
pub use crate::adc::OneShot as _embedded_hal_adc_OneShot;
pub use crate::blocking::delay::DelayMs as _embedded_hal_blocking_delay_DelayMs;
pub use crate::blocking::delay::DelayUs as _embedded_hal_blocking_delay_DelayUs;
@@ -11,36 +10,23 @@ pub use crate::blocking::i2c::{
Read as _embedded_hal_blocking_i2c_Read, Write as _embedded_hal_blocking_i2c_Write,
WriteRead as _embedded_hal_blocking_i2c_WriteRead,
};
#[cfg(feature = "unproven")]
pub use crate::blocking::rng::Read as _embedded_hal_blocking_rng_Read;
pub use crate::blocking::serial::Write as _embedded_hal_blocking_serial_Write;
pub use crate::blocking::spi::{
Transfer as _embedded_hal_blocking_spi_Transfer, Write as _embedded_hal_blocking_spi_Write,
};
#[allow(deprecated)]
#[cfg(feature = "unproven")]
pub use crate::digital::InputPin as _embedded_hal_digital_InputPin;
#[allow(deprecated)]
pub use crate::digital::OutputPin as _embedded_hal_digital_OutputPin;
#[cfg(feature = "unproven")]
#[allow(deprecated)]
pub use crate::digital::ToggleableOutputPin as _embedded_hal_digital_ToggleableOutputPin;
#[cfg(feature = "unproven")]
pub use crate::rng::Read as _embedded_hal_rng_Read;
pub use crate::serial::Read as _embedded_hal_serial_Read;
pub use crate::serial::Write as _embedded_hal_serial_Write;
pub use crate::spi::FullDuplex as _embedded_hal_spi_FullDuplex;
pub use crate::timer::CountDown as _embedded_hal_timer_CountDown;
#[cfg(feature = "unproven")]
pub use crate::watchdog::Watchdog as _embedded_hal_watchdog_Watchdog;
#[cfg(feature = "unproven")]
pub use crate::watchdog::WatchdogDisable as _embedded_hal_watchdog_WatchdogDisable;
#[cfg(feature = "unproven")]
pub use crate::watchdog::WatchdogEnable as _embedded_hal_watchdog_WatchdogEnable;
#[cfg(feature = "unproven")]
pub use crate::Capture as _embedded_hal_Capture;
#[cfg(feature = "unproven")]
pub use crate::Pwm as _embedded_hal_Pwm;
pub use crate::PwmPin as _embedded_hal_PwmPin;
#[cfg(feature = "unproven")]
pub use crate::Qei as _embedded_hal_Qei;

View File

@@ -1,11 +1,8 @@
//! Random Number Generator Interface
#[cfg(feature = "unproven")]
use nb;
/// Nonblocking stream of random bytes.
#[cfg(feature = "unproven")]
// reason: No implementation or users yet
pub trait Read {
/// An enumeration of RNG errors.
///
@@ -13,5 +10,5 @@ pub trait Read {
type Error;
/// Get a number of bytes from the RNG.
fn read(&mut self, buf: &mut [u8]) -> nb::Result<usize, Self::Error>;
fn try_read(&mut self, buf: &mut [u8]) -> nb::Result<usize, Self::Error>;
}

View File

@@ -11,7 +11,7 @@ pub trait Read<Word> {
type Error;
/// Reads a single word from the serial interface
fn read(&mut self) -> nb::Result<Word, Self::Error>;
fn try_read(&mut self) -> nb::Result<Word, Self::Error>;
}
/// Write half of a serial interface
@@ -20,8 +20,8 @@ pub trait Write<Word> {
type Error;
/// Writes a single word to the serial interface
fn write(&mut self, word: Word) -> nb::Result<(), Self::Error>;
fn try_write(&mut self, word: Word) -> nb::Result<(), Self::Error>;
/// Ensures that none of the previously written words are still buffered
fn flush(&mut self) -> nb::Result<(), Self::Error>;
fn try_flush(&mut self) -> nb::Result<(), Self::Error>;
}

View File

@@ -20,10 +20,10 @@ pub trait FullDuplex<Word> {
///
/// **NOTE** A word must be sent to the slave before attempting to call this
/// method.
fn read(&mut self) -> nb::Result<Word, Self::Error>;
fn try_read(&mut self) -> nb::Result<Word, Self::Error>;
/// Sends a word to the slave
fn send(&mut self, word: Word) -> nb::Result<(), Self::Error>;
fn try_send(&mut self, word: Word) -> nb::Result<(), Self::Error>;
}
/// Clock polarity

View File

@@ -1,13 +1,12 @@
//! Timers
use core::convert::Infallible;
use nb;
/// A count down timer
///
/// # Contract
///
/// - `self.start(count); block!(self.wait());` MUST block for AT LEAST the time specified by
/// - `self.start(count); block!(self.try_wait());` MUST block for AT LEAST the time specified by
/// `count`.
///
/// *Note* that the implementer doesn't necessarily have to be a *downcounting* timer; it could also
@@ -35,12 +34,12 @@ use nb;
/// };
///
/// Led.on();
/// timer.start(1.s());
/// block!(timer.wait()); // blocks for 1 second
/// timer.try_start(1.s()).unwrap();
/// block!(timer.try_wait()); // blocks for 1 second
/// Led.off();
/// }
///
/// # use std::convert::Infallible;
/// # use core::convert::Infallible;
/// # struct Seconds(u32);
/// # trait U32Ext { fn s(self) -> Seconds; }
/// # impl U32Ext for u32 { fn s(self) -> Seconds { Seconds(self) } }
@@ -51,17 +50,23 @@ use nb;
/// # }
/// # struct Timer6;
/// # impl hal::timer::CountDown for Timer6 {
/// # type Error = Infallible;
/// # type Time = Seconds;
/// # fn start<T>(&mut self, _: T) where T: Into<Seconds> {}
/// # fn wait(&mut self) -> ::nb::Result<(), Infallible> { Ok(()) }
/// # fn try_start<T>(&mut self, _: T) -> Result<(), Self::Error> where T: Into<Seconds> { Ok(()) }
/// # fn try_wait(&mut self) -> ::nb::Result<(), Infallible> { Ok(()) }
/// # }
/// ```
pub trait CountDown {
/// An enumeration of `CountDown` errors.
///
/// For infallible implementations, will be `Infallible`
type Error;
/// The unit of time used by this timer
type Time;
/// Starts a new count down
fn start<T>(&mut self, count: T)
fn try_start<T>(&mut self, count: T) -> Result<(), Self::Error>
where
T: Into<Self::Time>;
@@ -71,9 +76,9 @@ pub trait CountDown {
///
/// - If `Self: Periodic`, the timer will start a new count down right after the last one
/// finishes.
/// - Otherwise the behavior of calling `wait` after the last call returned `Ok` is UNSPECIFIED.
/// - Otherwise the behavior of calling `try_wait` after the last call returned `Ok` is UNSPECIFIED.
/// Implementers are suggested to panic on this scenario to signal a programmer error.
fn wait(&mut self) -> nb::Result<(), Infallible>;
fn try_wait(&mut self) -> nb::Result<(), Self::Error>;
}
/// Marker trait that indicates that a timer is periodic
@@ -81,14 +86,11 @@ pub trait Periodic {}
/// Trait for cancelable countdowns.
pub trait Cancel: CountDown {
/// Error returned when a countdown can't be canceled.
type Error;
/// Tries to cancel this countdown.
///
/// # Errors
///
/// An error will be returned if the countdown has already been canceled or was never started.
/// An error is also returned if the countdown is not `Periodic` and has already expired.
fn cancel(&mut self) -> Result<(), Self::Error>;
fn try_cancel(&mut self) -> Result<(), Self::Error>;
}

View File

@@ -2,29 +2,42 @@
/// Feeds an existing watchdog to ensure the processor isn't reset. Sometimes
/// commonly referred to as "kicking" or "refreshing".
#[cfg(feature = "unproven")]
pub trait Watchdog {
/// An enumeration of `Watchdog` errors.
///
/// For infallible implementations, will be `Infallible`
type Error;
/// Triggers the watchdog. This must be done once the watchdog is started
/// to prevent the processor being reset.
fn feed(&mut self);
fn try_feed(&mut self) -> Result<(), Self::Error>;
}
/// Enables A watchdog timer to reset the processor if software is frozen or
/// stalled.
#[cfg(feature = "unproven")]
pub trait WatchdogEnable {
/// An enumeration of `WatchdogEnable` errors.
///
/// For infallible implementations, will be `Infallible`
type Error;
/// Unit of time used by the watchdog
type Time;
/// Starts the watchdog with a given period, typically once this is done
/// the watchdog needs to be kicked periodically or the processor is reset.
fn start<T>(&mut self, period: T)
fn try_start<T>(&mut self, period: T) -> Result<(), Self::Error>
where
T: Into<Self::Time>;
}
/// Disables a running watchdog timer so the processor won't be reset.
#[cfg(feature = "unproven")]
pub trait WatchdogDisable {
/// An enumeration of `WatchdogDisable` errors.
///
/// For infallible implementations, will be `Infallible`
type Error;
/// Disables the watchdog
fn disable(&mut self);
fn try_disable(&mut self) -> Result<(), Self::Error>;
}