diff --git a/.gitignore b/.gitignore index 6aa1064..f8d7c8b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -/target/ **/*.rs.bk +.#* +/target/ Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 96c69a6..54db9b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,11 +3,18 @@ authors = ["Jorge Aparicio "] 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" \ No newline at end of file +version = "0.1.1" + +[dev-dependencies] +stm32f30x = { git = "https://github.com/japaric/stm32f30x" } +futures = "0.1.17" + +[features] +unstable = ["nb/unstable"] diff --git a/src/lib.rs b/src/lib.rs index 2fb100f..6383ba4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; +//! fn read(&mut self) -> nb::Result; //! //! /// 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 + 'static; +//! // NOTE generic over the USART peripheral +//! pub struct Serial { usart: USART } +//! +//! // convenience type alias +//! pub type Serial1 = Serial; //! //! /// Serial interface error //! pub enum Error { //! /// Buffer overrun //! Overrun, -//! // add more error variants here +//! // omitted other error variants //! } //! -//! impl<'a, U> hal::serial::Read for Serial<'a, U> -//! where -//! U: Deref + 'static -//! { +//! impl hal::serial::Read for Serial { //! type Error = Error; //! //! fn read(&mut self) -> nb::Result { //! // 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 for Serial<'a, U> -//! where -//! U: Deref + 'static -//! { +//! impl hal::serial::Write for Serial { //! 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 for Serial1 { -//! type Error = !; -//! -//! fn read(&mut self) -> Result> { -//! 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(timer: T) -> impl Future +//! fn wait(mut timer: T) -> impl Future //! 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(serial: S) -> impl Future +//! fn read(mut serial: S) -> impl Future //! where //! S: hal::serial::Read, //! { -//! 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(serial: S, byte: u8) -> impl Future +//! fn write(mut serial: S, byte: u8) -> impl Future //! where //! S: hal::serial::Write, //! { -//! 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(&mut self, _: T) where T: Into<()> {} +//! # fn wait(&mut self) -> ::nb::Result<(), !> { Err(::nb::Error::WouldBlock) } +//! # } +//! # +//! # pub struct Serial1; +//! # impl ::hal::serial::Read for Serial1 { +//! # type Error = !; +//! # fn read(&mut self) -> ::nb::Result { Err(::nb::Error::WouldBlock) } +//! # } +//! # impl ::hal::serial::Write 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 { 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( -//! spi: &S, -//! mut buffer: [u8; N], -//! ) -> Result<[u8; N], S::Error> +//! fn transfer( +//! mut spi: S, +//! mut buffer: [u8; 16], // NOTE this should be generic over the size of the array +//! ) -> impl Generator, Yield = ()> //! where -//! S: hal::Spi, +//! S: hal::spi::FullDuplex, //! { -//! 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(serial: &mut S, cb: &mut CircularBuffer) -> Result<(), S::Error> +//! fn flush(serial: &mut S, cb: &mut CircularBuffer) //! where -//! S: hal::serial::Write, +//! S: hal::serial::Write, //! { //! 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 = ..; -//! static SERIAL: Mutex> = ..; +//! static BUFFER1: Mutex = { +//! // .. +//! # Mutex(CircularBuffer) +//! }; +//! static SERIAL1: Mutex = { +//! // .. +//! # 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); +//! # impl Mutex { +//! # fn lock(&self) -> RefMut { 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 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 { 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)]