make tests functional

This commit is contained in:
Jorge Aparicio
2018-01-11 00:02:59 +01:00
parent 52c10fffa2
commit 4044707e8c
3 changed files with 322 additions and 237 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
/target/
**/*.rs.bk
.#*
/target/
Cargo.lock

View File

@@ -3,11 +3,18 @@ authors = ["Jorge Aparicio <jorge@japaric.io>"]
categories = ["asynchronous", "embedded", "hardware-support", "no-std"]
description = "Minimal Hardware Abstraction Layer for embedded systems"
documentation = "https://docs.rs/embedded-hal"
keywords = ["hal", "I/O"]
keywords = ["hal", "IO"]
license = "MIT OR Apache-2.0"
name = "embedded-hal"
repository = "https://github.com/japaric/embedded-hal"
version = "0.1.0"
[dependencies.nb]
version = "0.1.0"
version = "0.1.1"
[dev-dependencies]
stm32f30x = { git = "https://github.com/japaric/stm32f30x" }
futures = "0.1.17"
[features]
unstable = ["nb/unstable"]

View File

@@ -31,25 +31,24 @@
//!
//! # Reference implementation
//!
//! The [`blue-pill`] crate contains a reference implementation of this HAL.
//! The [`f3`] crate contains a reference implementation of this HAL.
//!
//! [`blue-pill`]: https://github.com/japaric/blue-pill
//! [`f3`]: https://crates.io/crates/f3/0.5.0
//!
//! # Detailed design
//!
//! ## Traits
//!
//! The HAL is specified using traits to allow generic programming. These traits
//! traits will make use of the [`nb`][] [crate][] (*please go read that crate
//! traits will make use of the [`nb`][] crate (*please go read that crate
//! documentation before continuing*) to abstract over the asynchronous model
//! and to also provide a blocking operation mode.
//!
//! [`nb`]: https://github.com/japaric/nb
//! [crate]: https://japaric.github.io/nb/nb/
//! [`nb`]: https://crates.io/crates/nb
//!
//! Here's how a HAL trait may look like:
//!
//! ``` rust
//! ```
//! extern crate nb;
//!
//! /// A serial interface
@@ -58,24 +57,28 @@
//! type Error;
//!
//! /// Reads a single byte
//! fn read(&self) -> nb::Result<u8, Self::Error>;
//! fn read(&mut self) -> nb::Result<u8, Self::Error>;
//!
//! /// Writes a single byte
//! fn write(&self, byte: u8) -> nb::Result<(), Self::Error>;
//! fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error>;
//! }
//! ```
//!
//! The `nb::Result` enum is used to add a [`WouldBlock`] variant to the errors
//! of the serial interface. As we'll see below this extra error variant lets
//! this single API operate in a blocking manner, or in a non-blocking manner
//! compatible with `futures` and with the `await` operator.
//! compatible with `futures` and with the `await!` operator.
//!
//! [`WouldBlock`]: https://japaric.github.io/nb/nb/enum.Error.html
//! [`WouldBlock`]: https://docs.rs/nb/0.1.0/nb/enum.Error.html
//!
//! Some traits, like the one shown below, may expose possibly blocking APIs
//! that can't fail. In those cases `nb::Result<_, !>` should be used.
//!
//! ``` ignore
//! ```
//! #![feature(never_type)]
//!
//! extern crate nb;
//!
//! /// A timer used for timeouts
//! pub trait Timer {
//! /// A time unit that can be convert to a human time unit
@@ -99,6 +102,8 @@
//! /// "waits" until the timer times out
//! fn wait(&self) -> nb::Result<(), !>;
//! }
//!
//! # fn main() {}
//! ```
//!
//! ## Implementation
@@ -108,105 +113,74 @@
//!
//! [`svd2rust`]: https://crates.io/crates/svd2rust
//!
//! Shown below is an implementation of the HAL traits for the [`stm32f103xx`]
//! Shown below is an implementation of the HAL traits for the [`stm32f30x`]
//! crate. This single implementation will work for *any* microcontroller in the
//! STM32F103 family.
//! STM32F30x family.
//!
//! [`stm32f103xx`]: https://crates.io/crates/stm32f103xx
//! [`stm32f30x`]: https://crates.io/crates/stm32f30x
//!
//! ``` ignore
//! //! An implementation of the `embedded-hal` for STM32F103xx microcontrollers
//! ```
//! //! An implementation of the `embedded-hal` for STM32F30x microcontrollers
//!
//! extern crate core;
//! extern crate embedded_hal as hal;
//! extern crate nb;
//!
//! // device crate
//! extern crate stm32f103xx;
//! extern crate stm32f30x;
//!
//! use core::ops::Deref;
//! use stm32f30x::USART1;
//!
//! /// A serial interface
//! // NOTE generic over the USART peripheral. This works with USART1, USART2
//! // and USART3
//! pub struct Serial<'a, U>(pub &'a U)
//! where
//! U: Deref<Target=stm32f103xx::usart1::RegisterBlock> + 'static;
//! // NOTE generic over the USART peripheral
//! pub struct Serial<USART> { usart: USART }
//!
//! // convenience type alias
//! pub type Serial1 = Serial<USART1>;
//!
//! /// Serial interface error
//! pub enum Error {
//! /// Buffer overrun
//! Overrun,
//! // add more error variants here
//! // omitted other error variants
//! }
//!
//! impl<'a, U> hal::serial::Read<u8> for Serial<'a, U>
//! where
//! U: Deref<Target=stm32f103xx::usart1::RegisterBlock> + 'static
//! {
//! impl hal::serial::Read<u8> for Serial<USART1> {
//! type Error = Error;
//!
//! fn read(&mut self) -> nb::Result<u8, Error> {
//! // read the status register
//! let sr = self.0.sr.read();
//! let isr = self.usart.isr.read();
//!
//! if sr.ore().bit_is_set() {
//! if isr.ore().bit_is_set() {
//! // Error: Buffer overrun
//! Err(nb::Error::Other(Error::Overrun))
//! }
//! // Add additional `else if` statements to check for other errors
//! else if sr.rxne().bit_is_set() {
//! // omitted: checks for other errors
//! else if isr.rxne().bit_is_set() {
//! // Data available: read the data register
//! Ok(self.0.dr.read().bits() as u8)
//! }
//! else {
//! Ok(self.usart.rdr.read().bits() as u8)
//! } else {
//! // No data available yet
//! Err(nb::Error::WouldBlock)
//! }
//! }
//! }
//!
//! impl<'a, U> hal::serial::Write<u8> for Serial<'a, U>
//! where
//! U: Deref<Target=stm32f103xx::usart1::RegisterBlock> + 'static
//! {
//! impl hal::serial::Write<u8> for Serial<USART1> {
//! type Error = Error;
//!
//! fn write(&mut self, byte: u8) -> nb::Result<(), Error> {
//! // Very similar to the above implementation
//! Ok(())
//! // Similar to the `read` implementation
//! # Ok(())
//! }
//!
//! fn flush(&mut self) -> nb::Result<(), Error> {
//! // Similar to the `read` implementation
//! # Ok(())
//! }
//! }
//! ```
//!
//! Furthermore the above implementation of `hal::Serial` is generic over the
//! USART peripheral instance and will work with peripherals USART1, USART2,
//! USART3, etc.
//!
//! Note that the above implementation uses a newtype over a *reference* to the
//! USART register block. This pushes the concern of synchronization to the user
//! of the `Serial` abstraction. However it's also possible to *erase* that
//! reference by handling the synchronization within the `hal::Serial`
//! implementation:
//!
//! ``` ignore
//! extern crate embedded_hal as hal;
//! extern crate nb;
//!
//! /// A synchronized serial interface
//! // NOTE This is a global singleton
//! pub struct Serial1;
//!
//! // NOTE private
//! static USART1: Mutex<_> = Mutex::new(..);
//!
//! impl hal::serial::Read<u8> for Serial1 {
//! type Error = !;
//!
//! fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
//! hal::serial::Read::read(&Serial(&*USART1.lock()))
//! }
//! }
//! # fn main() {}
//! ```
//!
//! ## Intended usage
@@ -215,32 +189,45 @@
//! with `futures` or with the `await` operator using the [`block!`],
//! [`try_nb!`] and [`await!`] macros respectively.
//!
//! [`block!`]: https://japaric.github.io/nb/nb/macro.block.html
//! [`try_nb!`]: https://japaric.github.io/nb/nb/macro.try_nb.html
//! [`await!`]: https://japaric.github.io/nb/nb/macro.await.html
//! [`block!`]: https://docs.rs/nb/0.1.0/nb/macro.block.html
//! [`try_nb!`]: https://docs.rs/nb/0.1.0/nb/index.html#how-to-use-this-crate
//! [`await!`]: https://docs.rs/nb/0.1.0/nb/index.html#how-to-use-this-crate
//!
//! ### Blocking mode
//!
//! An example of sending a string over the serial interface in a blocking
//! fashion:
//!
//! ``` ignore
//! extern crate embedded_hal as hal;
//!
//! #[macro_use]
//! ```
//! # #![feature(never_type)]
//! extern crate embedded_hal;
//! #[macro_use(block)]
//! extern crate nb;
//!
//! extern crate stm32f103xx_hal_impl;
//! use stm32f30x_hal::Serial1;
//! use embedded_hal::serial::Write;
//!
//! use stm32f103xx_hal_impl::Serial;
//!
//! let serial = Serial(usart1);
//! # fn main() {
//! let mut serial: Serial1 = {
//! // ..
//! # Serial1
//! };
//!
//! for byte in b"Hello, world!" {
//! // NOTE `block!` blocks until `serial.write()` completes and returns
//! // `Result<(), Error>`
//! block!(serial.write()).unwrap();
//! block!(serial.write(*byte)).unwrap();
//! }
//! # }
//!
//! # mod stm32f30x_hal {
//! # pub struct Serial1;
//! # impl Serial1 {
//! # pub fn write(&mut self, _: u8) -> ::nb::Result<(), !> {
//! # Ok(())
//! # }
//! # }
//! # }
//! ```
//!
//! ### `futures`
@@ -248,13 +235,14 @@
//! An example of running two tasks concurrently. First task: blink an LED every
//! second. Second task: loop back data over the serial interface.
//!
//! ``` ignore
//! ```
//! #![feature(conservative_impl_trait)]
//! #![feature(never_type)]
//!
//! extern crate embedded_hal as hal;
//!
//! extern crate futures;
//! extern crate stm32f103xx_hal_impl;
//!
//! #[macro_use]
//! #[macro_use(try_nb)]
//! extern crate nb;
//!
//! use hal::prelude::*;
@@ -264,139 +252,216 @@
//! Future,
//! };
//! use futures::future::Loop;
//! use stm32f103xx_hal_impl::{Serial, Timer};
//! use stm32f30x_hal::{Led, Serial1, Timer6};
//!
//! /// `futures` version of `Timer.wait`
//! ///
//! /// This returns a future that must be polled to completion
//! fn wait<T>(timer: T) -> impl Future<Item = T, Error = !>
//! fn wait<T>(mut timer: T) -> impl Future<Item = T, Error = !>
//! where
//! T: hal::Timer,
//! {
//! future::loop_fn(timer, |timer| {
//! match timer.wait() {
//! Ok(()) => Ok(Loop::Break(timer)),
//! Err(nb::Error::WouldBlock) => Ok(Loop::Continue(timer)),
//! let mut timer = Some(timer);
//! future::poll_fn(move || {
//! if let Some(ref mut timer) = timer {
//! try_nb!(timer.wait());
//! }
//!
//! Ok(Async::Ready(timer.take().unwrap()))
//! })
//! }
//!
//! /// `futures` version of `Serial.read`
//! ///
//! /// This returns a future that must be polled to completion
//! fn read<S>(serial: S) -> impl Future<Item = (S, u8), Error = S::Error>
//! fn read<S>(mut serial: S) -> impl Future<Item = (S, u8), Error = S::Error>
//! where
//! S: hal::serial::Read<u8>,
//! {
//! future::loop_fn(serial, |mut serial| {
//! match serial.read() {
//! Ok(byte) => Ok(Loop::Break((serial, byte))),
//! Err(nb::Error::WouldBlock) => Ok(Loop::Continue(serial)),
//! Err(nb::Error::Other(error)) => Err(error),
//! }
//! let mut serial = Some(serial);
//! future::poll_fn(move || {
//! let byte = try_nb!(serial.as_mut().unwrap().read());
//!
//! Ok(Async::Ready((serial.take().unwrap(), byte)))
//! })
//! }
//!
//! /// `futures` version of `Serial.write`
//! ///
//! /// This returns a future that must be polled to completion
//! fn write<S>(serial: S, byte: u8) -> impl Future<Item = S, Error = S::Error>
//! fn write<S>(mut serial: S, byte: u8) -> impl Future<Item = S, Error = S::Error>
//! where
//! S: hal::serial::Write<u8>,
//! {
//! future::loop_fn(serial, move |mut serial| {
//! match serial.write(byte) {
//! Ok(()) => Ok(Loop::Break(serial)),
//! Err(nb::Error::WouldBlock) => Ok(Loop::Continue(serial)),
//! Err(nb::Error::Other(error)) => Err(error),
//! }
//! let mut serial = Some(serial);
//! future::poll_fn(move || {
//! try_nb!(serial.as_mut().unwrap().write(byte));
//!
//! Ok(Async::Ready(serial.take().unwrap()))
//! })
//! }
//!
//! # fn main() {
//! // HAL implementers
//! let timer = Timer(tim3);
//! let serial = Serial(usart1);
//! let timer: Timer6 = {
//! // ..
//! # Timer6
//! };
//! let serial: Serial1 = {
//! // ..
//! # Serial1
//! };
//! let led: Led = {
//! // ..
//! # Led
//! };
//!
//! // Tasks
//! let mut blinky = future::loop_fn(true, |state| {
//! wait(timer).map(|_| {
//! if state {
//! Led.on();
//! } else {
//! Led.off();
//! }
//! let mut blinky = future::loop_fn::<_, (), _, _>(
//! (led, timer, true),
//! |(mut led, mut timer, state)| {
//! wait(timer).map(move |timer| {
//! if state {
//! led.on();
//! } else {
//! led.off();
//! }
//!
//! Loop::Continue(!state)
//! Loop::Continue((led, timer, !state))
//! })
//! });
//! });
//!
//! let mut loopback = future::loop_fn((), |_| {
//! read(serial).and_then(|byte| {
//! let mut loopback = future::loop_fn::<_, (), _, _>(serial, |mut serial| {
//! read(serial).and_then(|(serial, byte)| {
//! write(serial, byte)
//! }).map(|_| {
//! Loop::Continue(())
//! });
//! }).map(|serial| {
//! Loop::Continue(serial)
//! })
//! });
//!
//! // Event loop
//! loop {
//! blinky().poll().unwrap(); // NOTE(unwrap) E = !
//! loopback().poll().unwrap();
//! blinky.poll().unwrap(); // NOTE(unwrap) E = !
//! loopback.poll().unwrap();
//! break;
//! }
//! # }
//!
//! # mod stm32f30x_hal {
//! # pub struct Timer6;
//! # impl ::hal::Timer for Timer6 {
//! # type Time = ();
//! #
//! # fn get_timeout(&self) {}
//! # fn pause(&mut self) {}
//! # fn restart(&mut self) {}
//! # fn resume(&mut self) {}
//! # fn set_timeout<T>(&mut self, _: T) where T: Into<()> {}
//! # fn wait(&mut self) -> ::nb::Result<(), !> { Err(::nb::Error::WouldBlock) }
//! # }
//! #
//! # pub struct Serial1;
//! # impl ::hal::serial::Read<u8> for Serial1 {
//! # type Error = !;
//! # fn read(&mut self) -> ::nb::Result<u8, !> { Err(::nb::Error::WouldBlock) }
//! # }
//! # impl ::hal::serial::Write<u8> for Serial1 {
//! # type Error = !;
//! # fn flush(&mut self) -> ::nb::Result<(), !> { Err(::nb::Error::WouldBlock) }
//! # fn write(&mut self, _: u8) -> ::nb::Result<(), !> { Err(::nb::Error::WouldBlock) }
//! # }
//! #
//! # pub struct Led;
//! # impl Led {
//! # pub fn off(&mut self) {}
//! # pub fn on(&mut self) {}
//! # }
//! # }
//! ```
//!
//! ### `await`
//!
//! Same example as above but using `await!` instead of `futures`.
//!
//! **NOTE** The `await!` macro requires language support for generators, which
//! is not yet in the compiler.
//! ```
//! #![feature(generator_trait)]
//! #![feature(generators)]
//! # #![feature(never_type)]
//!
//! ``` ignore
//! extern crate embedded_hal as hal;
//!
//! extern crate stm32f103xx_hal_impl;
//!
//! #[macro_use]
//! #[macro_use(await)]
//! extern crate nb;
//!
//! use std::ops::Generator;
//!
//! use hal::prelude::*;
//! use stm32f103xx_hal_impl::{Serial, Timer};
//! use stm32f30x_hal::{Led, Serial1, Timer6};
//!
//! // HAL implementers
//! let timer = Timer(tim3);
//! let serial = Serial(usart1);
//! fn main() {
//! // HAL implementers
//! let mut timer: Timer6 = {
//! // ..
//! # Timer6
//! };
//! let mut serial: Serial1 = {
//! // ..
//! # Serial1
//! };
//! let mut led: Led = {
//! // ..
//! # Led
//! };
//!
//! // Tasks
//! let mut blinky = (|| {
//! let mut state = false;
//! loop {
//! // `await!` means "suspend / yield here" instead of "block until
//! // completion"
//! await!(timer.wait()).unwrap(); // NOTE(unwrap) E = !
//! // Tasks
//! let mut blinky = (move || {
//! let mut state = false;
//! loop {
//! // `await!` means "suspend / yield here" instead of "block until
//! // completion"
//! await!(timer.wait()).unwrap(); // NOTE(unwrap) E = !
//!
//! state = !state;
//! state = !state;
//!
//! if state {
//! Led.on();
//! } else {
//! Led.off();
//! if state {
//! led.on();
//! } else {
//! led.off();
//! }
//! }
//! }
//! })();
//! });
//!
//! let mut loopback = (|| {
//! let mut loopback = (move || {
//! loop {
//! let byte = await!(serial.read()).unwrap();
//! await!(serial.write(byte)).unwrap();
//! }
//! });
//!
//! // Event loop
//! loop {
//! let byte = await!(serial.read()).unwrap();
//! await!(serial.write(byte)).unwrap();
//! blinky.resume();
//! loopback.resume();
//! # break;
//! }
//! })();
//!
//! // Event loop
//! loop {
//! blinky.resume();
//! serial.resume();
//! }
//!
//! # mod stm32f30x_hal {
//! # pub struct Serial1;
//! # impl Serial1 {
//! # pub fn read(&mut self) -> ::nb::Result<u8, !> { Err(::nb::Error::WouldBlock) }
//! # pub fn write(&mut self, _: u8) -> ::nb::Result<(), !> { Err(::nb::Error::WouldBlock) }
//! # }
//! # pub struct Timer6;
//! # impl Timer6 {
//! # pub fn wait(&mut self) -> ::nb::Result<(), !> { Err(::nb::Error::WouldBlock) }
//! # }
//! # pub struct Led;
//! # impl Led {
//! # pub fn off(&mut self) {}
//! # pub fn on(&mut self) {}
//! # }
//! # }
//! ```
//!
//! ## Generic programming and higher level abstractions
@@ -410,11 +475,11 @@
//! methods with default implementation to allow specialization, but they have
//! been written as functions to keep things simple.
//!
//! - Write a whole buffer in blocking fashion.
//! - Write a whole buffer in blocking a fashion.
//!
//! ``` ignore
//! ```
//! extern crate embedded_hal as hal;
//! #[macro_use]
//! #[macro_use(block)]
//! extern crate nb;
//!
//! use hal::prelude::*;
@@ -429,11 +494,13 @@
//!
//! Ok(())
//! }
//!
//! # fn main() {}
//! ```
//!
//! - Blocking read with timeout
//!
//! ``` ignore
//! ```
//! extern crate embedded_hal as hal;
//! extern crate nb;
//!
@@ -461,9 +528,10 @@
//!
//! loop {
//! match serial.read() {
//! // raise error
//! Err(nb::Error::Other(e)) => return Err(Error::Serial(e)),
//! Err(nb::Error::WouldBlock) => {
//! // no data available, check the timer below
//! // no data available yet, check the timer below
//! },
//! Ok(byte) => return Ok(byte),
//! }
@@ -473,61 +541,74 @@
//! // The error type specified by `timer.wait()` is `!`, which
//! // means no error can actually occur. The Rust compiler
//! // still forces us to provide this match arm, though.
//! e
//! unreachable!()
//! },
//! // no timeout yet, try again
//! Err(nb::Error::WouldBlock) => continue,
//! Ok(()) => {
//! timer.pause();
//! return Err(Error::TimedOut);
//! },
//! Ok(()) => return Err(Error::TimedOut),
//! }
//! }
//! }
//!
//! # fn main() {}
//! ```
//!
//! - Asynchronous SPI transfer
//!
//! ``` ignore
//! ```
//! #![feature(conservative_impl_trait)]
//! #![feature(generators)]
//! #![feature(generator_trait)]
//!
//! extern crate embedded_hal as hal;
//! #[macro_use(await)]
//! extern crate nb;
//!
//! use std::ops::Generator;
//!
//! /// Transfers a byte buffer of size N
//! ///
//! /// Returns the same byte buffer but filled with the data received from the
//! /// slave device
//! #[async]
//! fn transfer<const N: usize, S>(
//! spi: &S,
//! mut buffer: [u8; N],
//! ) -> Result<[u8; N], S::Error>
//! fn transfer<S, B>(
//! mut spi: S,
//! mut buffer: [u8; 16], // NOTE this should be generic over the size of the array
//! ) -> impl Generator<Return = Result<(S, [u8; 16]), S::Error>, Yield = ()>
//! where
//! S: hal::Spi,
//! S: hal::spi::FullDuplex<u8>,
//! {
//! for byte in &mut buffer {
//! await!(spi.send(byte))?;
//! *byte = await!(spi.receive())?;
//! }
//! move || {
//! let n = buffer.len();
//! for i in 0..n {
//! await!(spi.send(buffer[i]))?;
//! buffer[i] = await!(spi.read())?;
//! }
//!
//! buffer
//! Ok((spi, buffer))
//! }
//! }
//!
//! # fn main() {}
//! ```
//!
//! - Buffered serial interface with periodic flushing in interrupt handler
//!
//! ``` ignore
//! ```
//! # #![feature(never_type)]
//! extern crate embedded_hal as hal;
//! extern crate nb;
//!
//! use hal::prelude::*;
//!
//! fn flush<S>(serial: &mut S, cb: &mut CircularBuffer) -> Result<(), S::Error>
//! fn flush<S>(serial: &mut S, cb: &mut CircularBuffer)
//! where
//! S: hal::serial::Write<u8>,
//! S: hal::serial::Write<u8, Error = !>,
//! {
//! loop {
//! if let Some(byte) = cb.peek() {
//! match serial.write(*byte) {
//! Err(nb::Error::Other(e)) => return Err(e),
//! Err(nb::Error::WouldBlock) => return Ok(()),
//! Err(nb::Error::Other(_)) => unreachable!(),
//! Err(nb::Error::WouldBlock) => return,
//! Ok(()) => {}, // keep flushing data
//! }
//! }
@@ -539,70 +620,66 @@
//! // The stuff below could be in some other crate
//!
//! /// Global singleton
//! pub struct BufferedSerial;
//! pub struct BufferedSerial1;
//!
//! // NOTE private
//! static BUFFER: Mutex<CircularBuffer> = ..;
//! static SERIAL: Mutex<impl hal::serial::Write<u8>> = ..;
//! static BUFFER1: Mutex<CircularBuffer> = {
//! // ..
//! # Mutex(CircularBuffer)
//! };
//! static SERIAL1: Mutex<Serial1> = {
//! // ..
//! # Mutex(Serial1)
//! };
//!
//! impl BufferedSerial {
//! pub fn write(&self, bytes: &[u8]) {
//! let mut buffer = BUFFER.lock();
//! for byte in bytes {
//! buffer.push(*byte).unwrap();
//! }
//! impl BufferedSerial1 {
//! pub fn write(&self, byte: u8) {
//! self.write_all(&[byte])
//! }
//!
//! pub fn write_all(&self, bytes: &[u8]) {
//! let mut buffer = BUFFER.lock();
//! let mut buffer = BUFFER1.lock();
//! for byte in bytes {
//! buffer.push(*byte).unwrap();
//! buffer.push(*byte).expect("buffer overrun");
//! }
//! // omitted: pend / enable interrupt_handler
//! }
//! }
//!
//! fn interrupt_handler() {
//! let serial = SERIAL.lock();
//! let buffer = BUFFER.lock();
//! let mut serial = SERIAL1.lock();
//! let mut buffer = BUFFER1.lock();
//!
//! flush(&mut serial, &mut buffer).unwrap();
//! flush(&mut *serial, &mut buffer);
//! }
//!
//! # struct Mutex<T>(T);
//! # impl<T> Mutex<T> {
//! # 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> {
//! # type Target = T;
//! # fn deref(&self) -> &T { self.0 }
//! # }
//! # impl<'a, T> ::std::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 = !;
//! # fn write(&mut self, _: u8) -> nb::Result<(), !> { Err(::nb::Error::WouldBlock) }
//! # fn flush(&mut self) -> nb::Result<(), !> { Err(::nb::Error::WouldBlock) }
//! # }
//! # struct CircularBuffer;
//! # impl CircularBuffer {
//! # pub fn peek(&mut self) -> Option<&u8> { None }
//! # pub fn pop(&mut self) -> Option<u8> { None }
//! # pub fn push(&mut self, _: u8) -> Result<(), ()> { Ok(()) }
//! # }
//!
//! # fn main() {}
//! ```
//!
//! # A note on time units
//!
//! Implementers of this HAL are encouraged to use *application agnostic* time
//! units in their implementations. Is it usually the case that the application
//! will want to pick the clock frequencies of the different peripherals so
//! using a unit like `apb1::Ticks` instead of `Seconds` lets the application
//! perform the conversions cheaply without register / memory accesses.
//!
//! For example: a `Timer` implementation uses the peripheral TIM1 which is
//! connected to the APB1 bus. This implementation uses the time unit
//! `apb1::Ticks` where 1 tick is equal to `1 / apb1::FREQUENCY` seconds where
//! `apb1::FREQUENCY` is picked by the application.
//!
//! Now each application can declare the `apb1::FREQUENCY` using a macro that
//! expands into conversions (implementations of [the `From` trait]) from human
//! time units like `Milliseconds` to `apb1::Ticks`.
//!
//! [the `From` trait]: https://doc.rust-lang.org/core/convert/trait.From.html
//!
//! With this setup the application can use human time units with the `Timer`
//! API:
//!
//! ``` ignore
//! frequency!(apb1, 8_000_000); // Hz
//!
//! let timer: impl Timer = ..;
//!
//! // All these are equivalent
//! timer.set_timeout(apb1::Ticks(8_000));
//! timer.set_timeout(Milliseconds(1));
//! timer.set_timeout(1.ms());
//! ```
//!
//! See the [`blue-pill`] crate for an example implementation of this approach.
#![deny(missing_docs)]
#![deny(warnings)]