mirror of
https://github.com/rust-embedded/embedded-hal.git
synced 2026-04-10 08:25:17 +00:00
Merge #192
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:
@@ -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
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
22
src/adc.rs
22
src/adc.rs
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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::*;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
239
src/lib.rs
239
src/lib.rs
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
30
src/timer.rs
30
src/timer.rs
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user