embedded_hal_nb/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
//! Non-blocking Hardware Abstraction Layer (HAL) traits for embedded systems, using the `nb` crate.
//!
//! The `embedded-hal-nb` traits 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://crates.io/crates/nb
//!
//! Here's how a HAL trait may look like:
//!
//! ```
//! use embedded_hal_nb;
//!
//! /// A serial interface
//! pub trait Serial {
//! /// Error type associated to this serial interface
//! type Error: core::fmt::Debug;
//!
//! /// Reads a single byte
//! fn read(&mut self) -> nb::Result<u8, Self::Error>;
//!
//! /// Writes a single byte
//! 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 explained in the documentation of the `nb` crate this single API,
//! when paired with the macros in the `nb` crate, can operate in a blocking manner, or be adapted
//! to other asynchronous execution schemes.
//!
//! [`WouldBlock`]: https://docs.rs/nb/1.0.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<_, Infallible>` is used.
//!
//! ```
//! # use std as core;
//! use ::core::convert::Infallible;
//!
//! /// A count down timer
//! pub trait CountDown {
//! // ..
//!
//! /// "waits" until the count down is over
//! fn wait(&mut self) -> nb::Result<(), Infallible>;
//! }
//!
//! # fn main() {}
//! ```
//!
//! ## Suggested implementation
//!
//! The HAL traits should be implemented for device crates generated via [`svd2rust`] to maximize
//! code reuse.
//!
//! [`svd2rust`]: https://crates.io/crates/svd2rust
//!
//! Shown below is an implementation of some of the HAL traits for the [`stm32f1xx-hal`] crate. This
//! single implementation will work for *any* microcontroller in the `STM32F1xx` family.
//!
//! [`stm32f1`]: https://crates.io/crates/stm32f1
//!
//! ```no_run
//! // crate: stm32f1xx-hal
//! // An implementation of the `embedded-hal` traits for STM32F1xx microcontrollers
//!
//! use embedded_hal_nb::serial;
//! use nb;
//!
//! // device crate
//! use stm32f1::stm32f103::USART1;
//!
//! /// A serial interface
//! // NOTE generic over the USART peripheral
//! pub struct Serial<USART> { usart: USART }
//!
//! // convenience type alias
//! pub type Serial1 = Serial<USART1>;
//!
//! impl serial::ErrorType for Serial<USART1> {
//! type Error = serial::ErrorKind;
//! }
//!
//! impl embedded_hal_nb::serial::Read<u8> for Serial<USART1> {
//! fn read(&mut self) -> nb::Result<u8, Self::Error> {
//! // read the status register
//! let isr = self.usart.sr.read();
//!
//! if isr.ore().bit_is_set() {
//! // Error: Buffer overrun
//! Err(nb::Error::Other(Self::Error::Overrun))
//! }
//! // omitted: checks for other errors
//! else if isr.rxne().bit_is_set() {
//! // Data available: read the data register
//! Ok(self.usart.dr.read().bits() as u8)
//! } else {
//! // No data available yet
//! Err(nb::Error::WouldBlock)
//! }
//! }
//! }
//!
//! impl embedded_hal_nb::serial::Write<u8> for Serial<USART1> {
//! fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
//! // Similar to the `read` implementation
//! # Ok(())
//! }
//!
//! fn flush(&mut self) -> nb::Result<(), Self::Error> {
//! // Similar to the `read` implementation
//! # Ok(())
//! }
//! }
//!
//! # fn main() {}
//! ```
//!
//! ## Intended usage
//!
//! Thanks to the [`nb`] crate the HAL API can be used in a blocking manner
//! with the [`block!`] macro or with `futures`.
//!
//! [`block!`]: https://docs.rs/nb/1.0.0/nb/macro.block.html
//!
//! ### Blocking mode
//!
//! An example of writing a string over the serial interface in a blocking
//! fashion:
//!
//! ```
//! use stm32f1xx_hal::Serial1;
//! use embedded_hal_nb::serial::Write;
//! use nb::block;
//!
//! # 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(*byte)).unwrap();
//! }
//! # }
//!
//! # mod stm32f1xx_hal {
//! # use embedded_hal_nb;
//! # use core::convert::Infallible;
//! # pub struct Serial1;
//! # impl Serial1 {
//! # pub fn write(&mut self, _: u8) -> nb::Result<(), Infallible> {
//! # Ok(())
//! # }
//! # }
//! # }
//! ```
//!
//! ## Generic programming and higher level abstractions
//!
//! The core of the HAL has been kept minimal on purpose to encourage building **generic** higher
//! level abstractions on top of it. Some higher level abstractions that pick an asynchronous model
//! or that have blocking behavior and that are deemed useful to build other abstractions can be
//! found in the `blocking` module.
//!
//! Some examples:
//!
//! **NOTE** All the functions shown below could have been written as trait
//! methods with default implementation to allow specialization, but they have
//! been written as functions to keep things simple.
//!
//! - Write a whole buffer to a serial device in blocking a fashion.
//!
//! ```
//! use embedded_hal_nb::serial::Write;
//! use nb::block;
//!
//! fn write_all<S>(serial: &mut S, buffer: &[u8]) -> Result<(), S::Error>
//! where
//! S: Write<u8>
//! {
//! for &byte in buffer {
//! block!(serial.write(byte))?;
//! }
//!
//! Ok(())
//! }
//!
//! # fn main() {}
//! ```
//!
//! - Buffered serial interface with periodic flushing in interrupt handler
//!
//! ```
//! # use std as core;
//! use embedded_hal_nb::serial::{ErrorKind, Write};
//! use nb::block;
//!
//! fn flush<S>(serial: &mut S, cb: &mut CircularBuffer)
//! where
//! S: Write<u8, Error = ErrorKind>,
//! {
//! loop {
//! if let Some(byte) = cb.peek() {
//! match serial.write(*byte) {
//! Err(nb::Error::Other(_)) => unreachable!(),
//! Err(nb::Error::WouldBlock) => return,
//! Ok(()) => {}, // keep flushing data
//! }
//! }
//!
//! cb.pop();
//! }
//! }
//!
//! // The stuff below could be in some other crate
//!
//! /// Global singleton
//! pub struct BufferedSerial1;
//!
//! // NOTE private
//! static BUFFER1: Mutex<CircularBuffer> = {
//! // ..
//! # Mutex(CircularBuffer)
//! };
//! static SERIAL1: Mutex<Serial1> = {
//! // ..
//! # Mutex(Serial1)
//! };
//!
//! impl BufferedSerial1 {
//! pub fn write(&self, byte: u8) {
//! self.write_all(&[byte])
//! }
//!
//! pub fn write_all(&self, bytes: &[u8]) {
//! let mut buffer = BUFFER1.lock();
//! for byte in bytes {
//! buffer.push(*byte).expect("buffer overrun");
//! }
//! // omitted: pend / enable interrupt_handler
//! }
//! }
//!
//! fn interrupt_handler() {
//! let mut serial = SERIAL1.lock();
//! let mut buffer = BUFFER1.lock();
//!
//! 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> ::core::ops::Deref for RefMut<'a, T> {
//! # type Target = T;
//! # fn deref(&self) -> &T { self.0 }
//! # }
//! # impl<'a, T> ::core::ops::DerefMut for RefMut<'a, T> {
//! # fn deref_mut(&mut self) -> &mut T { self.0 }
//! # }
//! # struct Serial1;
//! # impl embedded_hal_nb::serial::ErrorType for Serial1 {
//! # type Error = ErrorKind;
//! # }
//! # impl embedded_hal_nb::serial::Write<u8> for Serial1 {
//! # fn write(&mut self, _: u8) -> nb::Result<(), Self::Error> { Err(nb::Error::WouldBlock) }
//! # fn flush(&mut self) -> nb::Result<(), Self::Error> { 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() {}
//! ```
#![warn(missing_docs)]
#![no_std]
pub use nb;
pub mod serial;
pub mod spi;