From 3b6b07d3e4d7d794becc2466419f5322d38b8443 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Jul 2022 15:50:37 +0200 Subject: [PATCH 1/8] Split nb and can traits to separate crates. --- Cargo.toml | 7 - embedded-can/Cargo.toml | 16 + embedded-can/README.md | 50 +++ {src/can => embedded-can/src}/blocking.rs | 4 +- {src/can => embedded-can/src}/id.rs | 0 src/can/mod.rs => embedded-can/src/lib.rs | 5 +- {src/can => embedded-can/src}/nb.rs | 4 +- embedded-hal-async/src/i2c.rs | 2 +- embedded-hal-async/src/spi.rs | 3 +- embedded-hal-bus/src/spi.rs | 128 +++--- embedded-hal-nb/Cargo.toml | 20 + embedded-hal-nb/README.md | 50 +++ embedded-hal-nb/src/lib.rs | 291 ++++++++++++++ .../nb.rs => embedded-hal-nb/src/serial.rs | 24 +- src/spi/nb.rs => embedded-hal-nb/src/spi.rs | 6 +- src/delay.rs | 55 ++- src/digital.rs | 151 ++++--- src/fmt.rs | 18 - src/i2c.rs | 372 +++++++++--------- src/lib.rs | 294 -------------- src/{serial/mod.rs => serial.rs} | 29 +- src/serial/blocking.rs | 27 -- .../shared-bus.svg => spi-shared-bus.svg} | 0 src/{spi/blocking.rs => spi.rs} | 137 ++++++- src/spi/mod.rs | 133 ------- 25 files changed, 965 insertions(+), 861 deletions(-) create mode 100644 embedded-can/Cargo.toml create mode 100644 embedded-can/README.md rename {src/can => embedded-can/src}/blocking.rs (87%) rename {src/can => embedded-can/src}/id.rs (100%) rename src/can/mod.rs => embedded-can/src/lib.rs (98%) rename {src/can => embedded-can/src}/nb.rs (93%) create mode 100644 embedded-hal-nb/Cargo.toml create mode 100644 embedded-hal-nb/README.md create mode 100644 embedded-hal-nb/src/lib.rs rename src/serial/nb.rs => embedded-hal-nb/src/serial.rs (62%) rename src/spi/nb.rs => embedded-hal-nb/src/spi.rs (89%) delete mode 100644 src/fmt.rs rename src/{serial/mod.rs => serial.rs} (70%) delete mode 100644 src/serial/blocking.rs rename src/{spi/shared-bus.svg => spi-shared-bus.svg} (100%) rename src/{spi/blocking.rs => spi.rs} (79%) delete mode 100644 src/spi/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 230893d82..70544070b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,10 +14,3 @@ name = "embedded-hal" readme = "README.md" repository = "https://github.com/rust-embedded/embedded-hal" version = "1.0.0-alpha.8" - -[dependencies] -nb = "1" - -[dev-dependencies.stm32f1] -version = "0.14" -features = ["stm32f103", "rt"] diff --git a/embedded-can/Cargo.toml b/embedded-can/Cargo.toml new file mode 100644 index 000000000..4700687ce --- /dev/null +++ b/embedded-can/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "embedded-can" +version = "0.4.0" +edition = "2018" + +description = "HAL traits for Controller Area Network (CAN) devices." +categories = ["embedded", "hardware-support", "no-std"] +documentation = "https://docs.rs/embedded-can" +keywords = ["hal", "IO"] +license = "MIT OR Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-embedded/embedded-hal" + +[dependencies] +embedded-hal = { version = "=1.0.0-alpha.8", path = ".." } +nb = "1" diff --git a/embedded-can/README.md b/embedded-can/README.md new file mode 100644 index 000000000..4cc5522d4 --- /dev/null +++ b/embedded-can/README.md @@ -0,0 +1,50 @@ +[![crates.io](https://img.shields.io/crates/d/embedded-hal-nb.svg)](https://crates.io/crates/embedded-hal-nb) +[![crates.io](https://img.shields.io/crates/v/embedded-hal-nb.svg)](https://crates.io/crates/embedded-hal-nb) +[![Documentation](https://docs.rs/embedded-hal-nb/badge.svg)](https://docs.rs/embedded-hal-nb) +![Minimum Supported Rust Version](https://img.shields.io/badge/rustc-1.54+-blue.svg) + +# `embedded-hal-nb` + +A non-blocking Hardware Abstraction Layer (HAL) for embedded systems, using the `nb` crate. + +This crate contains versions of some [`embedded-hal`] traits using `nb`, and shares its scope and [design goals]. + +This project is developed and maintained by the [HAL team][team]. + +## [API reference] + +[API reference]: https://docs.rs/embedded-hal-nb + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.54 and up. It *might* +compile with older versions but that may change in any new patch release. + +See [here](docs/msrv.md) for details on how the MSRV may be upgraded. + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: ../CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-hal-team +[`embedded-hal`]: https://crates.io/crates/embedded-hal +[design goals]: https://docs.rs/embedded-hal/latest/embedded_hal/#design-goals \ No newline at end of file diff --git a/src/can/blocking.rs b/embedded-can/src/blocking.rs similarity index 87% rename from src/can/blocking.rs rename to embedded-can/src/blocking.rs index b13885abe..943cfa7a3 100644 --- a/src/can/blocking.rs +++ b/embedded-can/src/blocking.rs @@ -3,10 +3,10 @@ /// A blocking CAN interface that is able to transmit and receive frames. pub trait Can { /// Associated frame type. - type Frame: crate::can::Frame; + type Frame: crate::Frame; /// Associated error type. - type Error: crate::can::Error; + type Error: crate::Error; /// Puts a frame in the transmit buffer. Blocks until space is available in /// the transmit buffer. diff --git a/src/can/id.rs b/embedded-can/src/id.rs similarity index 100% rename from src/can/id.rs rename to embedded-can/src/id.rs diff --git a/src/can/mod.rs b/embedded-can/src/lib.rs similarity index 98% rename from src/can/mod.rs rename to embedded-can/src/lib.rs index b70212bec..db80c455b 100644 --- a/src/can/mod.rs +++ b/embedded-can/src/lib.rs @@ -1,4 +1,7 @@ -//! Controller Area Network +//! Controller Area Network (CAN) traits + +#![warn(missing_docs)] +#![no_std] pub mod blocking; pub mod nb; diff --git a/src/can/nb.rs b/embedded-can/src/nb.rs similarity index 93% rename from src/can/nb.rs rename to embedded-can/src/nb.rs index 2ab6050a5..b17894602 100644 --- a/src/can/nb.rs +++ b/embedded-can/src/nb.rs @@ -3,10 +3,10 @@ /// A CAN interface that is able to transmit and receive frames. pub trait Can { /// Associated frame type. - type Frame: crate::can::Frame; + type Frame: crate::Frame; /// Associated error type. - type Error: crate::can::Error; + type Error: crate::Error; /// Puts a frame in the transmit buffer to be sent on the bus. /// diff --git a/embedded-hal-async/src/i2c.rs b/embedded-hal-async/src/i2c.rs index 51b6139ac..30133ce12 100644 --- a/embedded-hal-async/src/i2c.rs +++ b/embedded-hal-async/src/i2c.rs @@ -17,7 +17,7 @@ //! `SevenBitAddress` has been set as default mode and thus can be omitted if desired. use core::future::Future; -pub use embedded_hal::i2c::blocking::Operation; +pub use embedded_hal::i2c::Operation; pub use embedded_hal::i2c::{ AddressMode, Error, ErrorKind, ErrorType, NoAcknowledgeSource, SevenBitAddress, TenBitAddress, }; diff --git a/embedded-hal-async/src/spi.rs b/embedded-hal-async/src/spi.rs index da4f9cc7c..2b33af751 100644 --- a/embedded-hal-async/src/spi.rs +++ b/embedded-hal-async/src/spi.rs @@ -2,10 +2,11 @@ use core::{fmt::Debug, future::Future}; +use embedded_hal::digital::OutputPin; +use embedded_hal::spi as blocking; pub use embedded_hal::spi::{ Error, ErrorKind, ErrorType, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3, }; -use embedded_hal::{digital::blocking::OutputPin, spi::blocking}; type ReadFuture<'a, T, Word> where diff --git a/embedded-hal-bus/src/spi.rs b/embedded-hal-bus/src/spi.rs index 9302fffc8..22ef300be 100644 --- a/embedded-hal-bus/src/spi.rs +++ b/embedded-hal-bus/src/spi.rs @@ -1,86 +1,78 @@ //! SPI bus sharing mechanisms. -/// SPI bus sharing with blocking traits -pub mod blocking { - use core::fmt::Debug; - use embedded_hal::{ - digital::blocking::OutputPin, - spi::{ - blocking::{SpiBusFlush, SpiDevice}, - Error, ErrorKind, ErrorType, - }, - }; +use core::fmt::Debug; +use embedded_hal::digital::OutputPin; +use embedded_hal::spi::{Error, ErrorKind, ErrorType, SpiBusFlush, SpiDevice}; - /// Error type for [`ExclusiveDevice`] operations. - #[derive(Copy, Clone, Eq, PartialEq, Debug)] - pub enum ExclusiveDeviceError { - /// An inner SPI bus operation failed - Spi(BUS), - /// Asserting or deasserting CS failed - Cs(CS), - } +/// Error type for [`ExclusiveDevice`] operations. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum ExclusiveDeviceError { + /// An inner SPI bus operation failed + Spi(BUS), + /// Asserting or deasserting CS failed + Cs(CS), +} - impl Error for ExclusiveDeviceError - where - BUS: Error + Debug, - CS: Debug, - { - fn kind(&self) -> ErrorKind { - match self { - Self::Spi(e) => e.kind(), - Self::Cs(_) => ErrorKind::ChipSelectFault, - } +impl Error for ExclusiveDeviceError +where + BUS: Error + Debug, + CS: Debug, +{ + fn kind(&self) -> ErrorKind { + match self { + Self::Spi(e) => e.kind(), + Self::Cs(_) => ErrorKind::ChipSelectFault, } } +} - /// [`SpiDevice`] implementation with exclusive access to the bus (not shared). - /// - /// This is the most straightforward way of obtaining an [`SpiDevice`] from an [`SpiBus`](embedded_hal::spi::blocking::SpiBus), - /// ideal for when no sharing is required (only one SPI device is present on the bus). - pub struct ExclusiveDevice { - bus: BUS, - cs: CS, - } +/// [`SpiDevice`] implementation with exclusive access to the bus (not shared). +/// +/// This is the most straightforward way of obtaining an [`SpiDevice`] from an [`SpiBus`](embedded_hal::spi::blocking::SpiBus), +/// ideal for when no sharing is required (only one SPI device is present on the bus). +pub struct ExclusiveDevice { + bus: BUS, + cs: CS, +} - impl ExclusiveDevice { - /// Create a new ExclusiveDevice - pub fn new(bus: BUS, cs: CS) -> Self { - Self { bus, cs } - } +impl ExclusiveDevice { + /// Create a new ExclusiveDevice + pub fn new(bus: BUS, cs: CS) -> Self { + Self { bus, cs } } +} - impl ErrorType for ExclusiveDevice - where - BUS: ErrorType, - CS: OutputPin, - { - type Error = ExclusiveDeviceError; - } +impl ErrorType for ExclusiveDevice +where + BUS: ErrorType, + CS: OutputPin, +{ + type Error = ExclusiveDeviceError; +} - impl SpiDevice for ExclusiveDevice - where - BUS: SpiBusFlush, - CS: OutputPin, - { - type Bus = BUS; +impl SpiDevice for ExclusiveDevice +where + BUS: SpiBusFlush, + CS: OutputPin, +{ + type Bus = BUS; - fn transaction( - &mut self, - f: impl FnOnce(&mut Self::Bus) -> Result::Error>, - ) -> Result { - self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?; + fn transaction( + &mut self, + f: impl FnOnce(&mut Self::Bus) -> Result::Error>, + ) -> Result { + self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?; - let f_res = f(&mut self.bus); + let f_res = f(&mut self.bus); - // On failure, it's important to still flush and deassert CS. - let flush_res = self.bus.flush(); - let cs_res = self.cs.set_high(); + // On failure, it's important to still flush and deassert CS. + let flush_res = self.bus.flush(); + let cs_res = self.cs.set_high(); - let f_res = f_res.map_err(ExclusiveDeviceError::Spi)?; - flush_res.map_err(ExclusiveDeviceError::Spi)?; - cs_res.map_err(ExclusiveDeviceError::Cs)?; + let f_res = f_res.map_err(ExclusiveDeviceError::Spi)?; + flush_res.map_err(ExclusiveDeviceError::Spi)?; + cs_res.map_err(ExclusiveDeviceError::Cs)?; - Ok(f_res) - } + Ok(f_res) } } diff --git a/embedded-hal-nb/Cargo.toml b/embedded-hal-nb/Cargo.toml new file mode 100644 index 000000000..5ff5d3305 --- /dev/null +++ b/embedded-hal-nb/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "embedded-hal-nb" +version = "1.0.0-alpha.1" +edition = "2018" + +categories = ["embedded", "hardware-support", "no-std"] +description = "Non-blocking Hardware Abstraction Layer (HAL) for embedded systems using the `nb` crate." +documentation = "https://docs.rs/embedded-hal-nb" +keywords = ["hal", "IO"] +license = "MIT OR Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-embedded/embedded-hal" + +[dependencies] +embedded-hal = { version = "=1.0.0-alpha.8", path = ".." } +nb = "1" + +[dev-dependencies.stm32f1] +version = "0.14" +features = ["stm32f103", "rt"] diff --git a/embedded-hal-nb/README.md b/embedded-hal-nb/README.md new file mode 100644 index 000000000..4cc5522d4 --- /dev/null +++ b/embedded-hal-nb/README.md @@ -0,0 +1,50 @@ +[![crates.io](https://img.shields.io/crates/d/embedded-hal-nb.svg)](https://crates.io/crates/embedded-hal-nb) +[![crates.io](https://img.shields.io/crates/v/embedded-hal-nb.svg)](https://crates.io/crates/embedded-hal-nb) +[![Documentation](https://docs.rs/embedded-hal-nb/badge.svg)](https://docs.rs/embedded-hal-nb) +![Minimum Supported Rust Version](https://img.shields.io/badge/rustc-1.54+-blue.svg) + +# `embedded-hal-nb` + +A non-blocking Hardware Abstraction Layer (HAL) for embedded systems, using the `nb` crate. + +This crate contains versions of some [`embedded-hal`] traits using `nb`, and shares its scope and [design goals]. + +This project is developed and maintained by the [HAL team][team]. + +## [API reference] + +[API reference]: https://docs.rs/embedded-hal-nb + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.54 and up. It *might* +compile with older versions but that may change in any new patch release. + +See [here](docs/msrv.md) for details on how the MSRV may be upgraded. + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: ../CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-hal-team +[`embedded-hal`]: https://crates.io/crates/embedded-hal +[design goals]: https://docs.rs/embedded-hal/latest/embedded_hal/#design-goals \ No newline at end of file diff --git a/embedded-hal-nb/src/lib.rs b/embedded-hal-nb/src/lib.rs new file mode 100644 index 000000000..8262d008b --- /dev/null +++ b/embedded-hal-nb/src/lib.rs @@ -0,0 +1,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; +//! +//! /// 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/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<_, 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 } +//! +//! // convenience type alias +//! pub type Serial1 = Serial; +//! +//! impl serial::ErrorType for Serial { +//! type Error = serial::ErrorKind; +//! } +//! +//! impl embedded_hal_nb::serial::Read for Serial { +//! fn read(&mut self) -> nb::Result { +//! // 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 for Serial { +//! 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(serial: &mut S, buffer: &[u8]) -> Result<(), S::Error> +//! where +//! S: Write +//! { +//! 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(serial: &mut S, cb: &mut CircularBuffer) +//! where +//! S: Write, +//! { +//! 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 = { +//! // .. +//! # Mutex(CircularBuffer) +//! }; +//! static SERIAL1: Mutex = { +//! // .. +//! # 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); +//! # impl Mutex { +//! # fn lock(&self) -> RefMut { 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 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 { 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; diff --git a/src/serial/nb.rs b/embedded-hal-nb/src/serial.rs similarity index 62% rename from src/serial/nb.rs rename to embedded-hal-nb/src/serial.rs index dc2dde74e..e01803ab1 100644 --- a/src/serial/nb.rs +++ b/embedded-hal-nb/src/serial.rs @@ -1,10 +1,12 @@ //! Serial interface +pub use embedded_hal::serial::{Error, ErrorKind, ErrorType}; + /// Read half of a serial interface /// /// Some serial interfaces support different data sizes (8 bits, 9 bits, etc.); /// This can be encoded in this trait via the `Word` type parameter. -pub trait Read: super::ErrorType { +pub trait Read: ErrorType { /// Reads a single word from the serial interface fn read(&mut self) -> nb::Result; } @@ -16,7 +18,7 @@ impl, Word: Copy> Read for &mut T { } /// Write half of a serial interface -pub trait Write: super::ErrorType { +pub trait Write: ErrorType { /// Writes a single word to the serial interface fn write(&mut self, word: Word) -> nb::Result<(), Self::Error>; @@ -33,3 +35,21 @@ impl, Word: Copy> Write for &mut T { T::flush(self) } } + +/// Implementation of `core::fmt::Write` for the HAL's `serial::Write`. +/// +/// TODO write example of usage + +impl core::fmt::Write + for dyn Write + '_ +where + Word: Copy + From, +{ + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let _ = s + .bytes() + .map(|c| nb::block!(self.write(Word::from(c)))) + .last(); + Ok(()) + } +} diff --git a/src/spi/nb.rs b/embedded-hal-nb/src/spi.rs similarity index 89% rename from src/spi/nb.rs rename to embedded-hal-nb/src/spi.rs index 5257f930a..a9e7c94f0 100644 --- a/src/spi/nb.rs +++ b/embedded-hal-nb/src/spi.rs @@ -1,8 +1,10 @@ //! SPI master mode traits using `nb`. -use super::ErrorType; +pub use embedded_hal::spi::{ + Error, ErrorKind, ErrorType, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3, +}; -/// Full duplex (master mode) +/// Full duplex SPI (master mode) /// /// # Notes /// diff --git a/src/delay.rs b/src/delay.rs index e30bc5378..52c1fdd5a 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -1,40 +1,37 @@ //! Delays -/// Blocking delay traits -pub mod blocking { - /// Microsecond delay - /// - pub trait DelayUs { - /// Enumeration of `DelayUs` errors - type Error: core::fmt::Debug; +/// Microsecond delay +/// +pub trait DelayUs { + /// Enumeration of `DelayUs` errors + type Error: core::fmt::Debug; - /// Pauses execution for at minimum `us` microseconds. Pause can be longer - /// if the implementation requires it due to precision/timing issues. - fn delay_us(&mut self, us: u32) -> Result<(), Self::Error>; + /// Pauses execution for at minimum `us` microseconds. Pause can be longer + /// if the implementation requires it due to precision/timing issues. + fn delay_us(&mut self, us: u32) -> Result<(), Self::Error>; - /// Pauses execution for at minimum `ms` milliseconds. Pause can be longer - /// if the implementation requires it due to precision/timing issues. - fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { - for _ in 0..ms { - self.delay_us(1000)?; - } - - Ok(()) + /// Pauses execution for at minimum `ms` milliseconds. Pause can be longer + /// if the implementation requires it due to precision/timing issues. + fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + for _ in 0..ms { + self.delay_us(1000)?; } + + Ok(()) } +} - impl DelayUs for &mut T - where - T: DelayUs, - { - type Error = T::Error; +impl DelayUs for &mut T +where + T: DelayUs, +{ + type Error = T::Error; - fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { - T::delay_us(self, us) - } + fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { + T::delay_us(self, us) + } - fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { - T::delay_ms(self, ms) - } + fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + T::delay_ms(self, ms) } } diff --git a/src/digital.rs b/src/digital.rs index b0d67768b..c1fb82fe6 100644 --- a/src/digital.rs +++ b/src/digital.rs @@ -55,101 +55,96 @@ impl Not for PinState { } } -/// Blocking digital I/O traits -pub mod blocking { - use super::PinState; - - /// Single digital push-pull output pin - pub trait OutputPin: super::ErrorType { - /// 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) -> 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>; - - /// Drives the pin high or low depending on the provided value - /// - /// *NOTE* the actual electrical state of the pin may not actually be high or low, e.g. due to external - /// electrical sources - fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> { - match state { - PinState::Low => self.set_low(), - PinState::High => self.set_high(), - } +/// Single digital push-pull output pin +pub trait OutputPin: ErrorType { + /// 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) -> 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>; + + /// Drives the pin high or low depending on the provided value + /// + /// *NOTE* the actual electrical state of the pin may not actually be high or low, e.g. due to external + /// electrical sources + fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), } } +} - impl OutputPin for &mut T { - fn set_low(&mut self) -> Result<(), Self::Error> { - T::set_low(self) - } - - fn set_high(&mut self) -> Result<(), Self::Error> { - T::set_high(self) - } +impl OutputPin for &mut T { + fn set_low(&mut self) -> Result<(), Self::Error> { + T::set_low(self) + } - fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> { - T::set_state(self, state) - } + fn set_high(&mut self) -> Result<(), Self::Error> { + T::set_high(self) } - /// Push-pull output pin that can read its output state - 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; - - /// Is the pin in drive low mode? - /// - /// *NOTE* this does *not* read the electrical state of the pin - fn is_set_low(&self) -> Result; + fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> { + T::set_state(self, state) } +} - impl StatefulOutputPin for &mut T { - fn is_set_high(&self) -> Result { - T::is_set_high(self) - } +/// Push-pull output pin that can read its output state +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; + + /// Is the pin in drive low mode? + /// + /// *NOTE* this does *not* read the electrical state of the pin + fn is_set_low(&self) -> Result; +} - fn is_set_low(&self) -> Result { - T::is_set_low(self) - } +impl StatefulOutputPin for &mut T { + fn is_set_high(&self) -> Result { + T::is_set_high(self) } - /// Output pin that can be toggled - pub trait ToggleableOutputPin: super::ErrorType { - /// Toggle pin output. - fn toggle(&mut self) -> Result<(), Self::Error>; + fn is_set_low(&self) -> Result { + T::is_set_low(self) } +} - impl ToggleableOutputPin for &mut T { - fn toggle(&mut self) -> Result<(), Self::Error> { - T::toggle(self) - } +/// Output pin that can be toggled +pub trait ToggleableOutputPin: ErrorType { + /// Toggle pin output. + fn toggle(&mut self) -> Result<(), Self::Error>; +} + +impl ToggleableOutputPin for &mut T { + fn toggle(&mut self) -> Result<(), Self::Error> { + T::toggle(self) } +} - /// Single digital input pin - pub trait InputPin: super::ErrorType { - /// Is the input pin high? - fn is_high(&self) -> Result; +/// Single digital input pin +pub trait InputPin: ErrorType { + /// Is the input pin high? + fn is_high(&self) -> Result; - /// Is the input pin low? - fn is_low(&self) -> Result; - } + /// Is the input pin low? + fn is_low(&self) -> Result; +} - impl InputPin for &T { - fn is_high(&self) -> Result { - T::is_high(self) - } +impl InputPin for &T { + fn is_high(&self) -> Result { + T::is_high(self) + } - fn is_low(&self) -> Result { - T::is_low(self) - } + fn is_low(&self) -> Result { + T::is_low(self) } } diff --git a/src/fmt.rs b/src/fmt.rs deleted file mode 100644 index 7b89f71e4..000000000 --- a/src/fmt.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Implementation of `core::fmt::Write` for the HAL's `serial::Write`. -//! -//! TODO write example of usage -use core::fmt::{Result, Write}; - -impl Write - for dyn crate::serial::nb::Write + '_ -where - Word: Copy + From, -{ - fn write_str(&mut self, s: &str) -> Result { - let _ = s - .bytes() - .map(|c| nb::block!(self.write(Word::from(c)))) - .last(); - Ok(()) - } -} diff --git a/src/i2c.rs b/src/i2c.rs index 9b6298da4..f14348887 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -22,7 +22,7 @@ //! Here is an example of an embedded-hal implementation of the `Write` trait //! for both modes: //! ``` -//! # use embedded_hal::i2c::{ErrorKind, ErrorType, SevenBitAddress, TenBitAddress, blocking::{I2c, Operation}}; +//! # use embedded_hal::i2c::{ErrorKind, ErrorType, SevenBitAddress, TenBitAddress, I2c, Operation}; //! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing. //! pub struct I2c0; //! @@ -97,7 +97,7 @@ //! For demonstration purposes the address mode parameter has been omitted in this example. //! //! ``` -//! # use embedded_hal::i2c::{blocking::I2c, Error}; +//! # use embedded_hal::i2c::{I2c, Error}; //! const ADDR: u8 = 0x15; //! # const TEMP_REGISTER: u8 = 0x1; //! pub struct TemperatureSensorDriver { @@ -120,7 +120,7 @@ //! ### Device driver compatible only with 10-bit addresses //! //! ``` -//! # use embedded_hal::i2c::{Error, TenBitAddress, blocking::I2c}; +//! # use embedded_hal::i2c::{Error, TenBitAddress, I2c}; //! const ADDR: u16 = 0x158; //! # const TEMP_REGISTER: u8 = 0x1; //! pub struct TemperatureSensorDriver { @@ -256,202 +256,196 @@ impl AddressMode for SevenBitAddress {} impl AddressMode for TenBitAddress {} -/// Blocking I2C traits -pub mod blocking { - - use super::{AddressMode, ErrorType, SevenBitAddress}; +/// Transactional I2C operation. +/// +/// Several operations can be combined as part of a transaction. +#[derive(Debug, PartialEq)] +pub enum Operation<'a> { + /// Read data into the provided buffer + Read(&'a mut [u8]), + /// Write data from the provided buffer + Write(&'a [u8]), +} - /// Transactional I2C operation. +/// Blocking I2C +pub trait I2c: ErrorType { + /// Reads enough bytes from slave with `address` to fill `buffer` /// - /// Several operations can be combined as part of a transaction. - #[derive(Debug, PartialEq)] - pub enum Operation<'a> { - /// Read data into the provided buffer - Read(&'a mut [u8]), - /// Write data from the provided buffer - Write(&'a [u8]), - } - - /// Blocking I2C - pub trait I2c: ErrorType { - /// Reads enough bytes from slave with `address` to fill `buffer` - /// - /// # I2C Events (contract) - /// - /// ``` text - /// Master: ST SAD+R MAK MAK ... NMAK SP - /// Slave: SAK B0 B1 ... BN - /// ``` - /// - /// Where - /// - /// - `ST` = start condition - /// - `SAD+R` = slave address followed by bit 1 to indicate reading - /// - `SAK` = slave acknowledge - /// - `Bi` = ith byte of data - /// - `MAK` = master acknowledge - /// - `NMAK` = master no acknowledge - /// - `SP` = stop condition - fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error>; - - /// Writes bytes to slave with address `address` - /// - /// # I2C Events (contract) - /// - /// ``` text - /// Master: ST SAD+W B0 B1 ... BN SP - /// Slave: SAK SAK SAK ... SAK - /// ``` - /// - /// Where - /// - /// - `ST` = start condition - /// - `SAD+W` = slave address followed by bit 0 to indicate writing - /// - `SAK` = slave acknowledge - /// - `Bi` = ith byte of data - /// - `SP` = stop condition - fn write(&mut self, address: A, bytes: &[u8]) -> Result<(), Self::Error>; - - /// Writes bytes to slave with address `address` - /// - /// # I2C Events (contract) - /// - /// Same as the `write` method - fn write_iter(&mut self, address: A, bytes: B) -> Result<(), Self::Error> - where - B: IntoIterator; - - /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a - /// single transaction* - /// - /// # I2C Events (contract) - /// - /// ``` text - /// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP - /// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN - /// ``` - /// - /// Where - /// - /// - `ST` = start condition - /// - `SAD+W` = slave address followed by bit 0 to indicate writing - /// - `SAK` = slave acknowledge - /// - `Oi` = ith outgoing byte of data - /// - `SR` = repeated start condition - /// - `SAD+R` = slave address followed by bit 1 to indicate reading - /// - `Ii` = ith incoming byte of data - /// - `MAK` = master acknowledge - /// - `NMAK` = master no acknowledge - /// - `SP` = stop condition - fn write_read( - &mut self, - address: A, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), Self::Error>; - - /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a - /// single transaction* - /// - /// # I2C Events (contract) - /// - /// Same as the `write_read` method - fn write_iter_read( - &mut self, - address: A, - bytes: B, - buffer: &mut [u8], - ) -> Result<(), Self::Error> - where - B: IntoIterator; + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+R MAK MAK ... NMAK SP + /// Slave: SAK B0 B1 ... BN + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+R` = slave address followed by bit 1 to indicate reading + /// - `SAK` = slave acknowledge + /// - `Bi` = ith byte of data + /// - `MAK` = master acknowledge + /// - `NMAK` = master no acknowledge + /// - `SP` = stop condition + fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error>; + + /// Writes bytes to slave with address `address` + /// + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+W B0 B1 ... BN SP + /// Slave: SAK SAK SAK ... SAK + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+W` = slave address followed by bit 0 to indicate writing + /// - `SAK` = slave acknowledge + /// - `Bi` = ith byte of data + /// - `SP` = stop condition + fn write(&mut self, address: A, bytes: &[u8]) -> Result<(), Self::Error>; + + /// Writes bytes to slave with address `address` + /// + /// # I2C Events (contract) + /// + /// Same as the `write` method + fn write_iter(&mut self, address: A, bytes: B) -> Result<(), Self::Error> + where + B: IntoIterator; - /// Execute the provided operations on the I2C bus. - /// - /// Transaction contract: - /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. - /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. - /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. - /// - After executing the last operation an SP is sent automatically. - /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. - /// - /// - `ST` = start condition - /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing - /// - `SR` = repeated start condition - /// - `SP` = stop condition - fn transaction<'a>( - &mut self, - address: A, - operations: &mut [Operation<'a>], - ) -> Result<(), Self::Error>; + /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a + /// single transaction* + /// + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP + /// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+W` = slave address followed by bit 0 to indicate writing + /// - `SAK` = slave acknowledge + /// - `Oi` = ith outgoing byte of data + /// - `SR` = repeated start condition + /// - `SAD+R` = slave address followed by bit 1 to indicate reading + /// - `Ii` = ith incoming byte of data + /// - `MAK` = master acknowledge + /// - `NMAK` = master no acknowledge + /// - `SP` = stop condition + fn write_read( + &mut self, + address: A, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error>; + + /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a + /// single transaction* + /// + /// # I2C Events (contract) + /// + /// Same as the `write_read` method + fn write_iter_read( + &mut self, + address: A, + bytes: B, + buffer: &mut [u8], + ) -> Result<(), Self::Error> + where + B: IntoIterator; + + /// Execute the provided operations on the I2C bus. + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing + /// - `SR` = repeated start condition + /// - `SP` = stop condition + fn transaction<'a>( + &mut self, + address: A, + operations: &mut [Operation<'a>], + ) -> Result<(), Self::Error>; + + /// Execute the provided operations on the I2C bus (iterator version). + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing + /// - `SR` = repeated start condition + /// - `SP` = stop condition + fn transaction_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> + where + O: IntoIterator>; +} - /// Execute the provided operations on the I2C bus (iterator version). - /// - /// Transaction contract: - /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. - /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. - /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. - /// - After executing the last operation an SP is sent automatically. - /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. - /// - /// - `ST` = start condition - /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing - /// - `SR` = repeated start condition - /// - `SP` = stop condition - fn transaction_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> - where - O: IntoIterator>; +impl> I2c for &mut T { + fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error> { + T::read(self, address, buffer) } - impl> I2c for &mut T { - fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error> { - T::read(self, address, buffer) - } - - fn write(&mut self, address: A, bytes: &[u8]) -> Result<(), Self::Error> { - T::write(self, address, bytes) - } + fn write(&mut self, address: A, bytes: &[u8]) -> Result<(), Self::Error> { + T::write(self, address, bytes) + } - fn write_iter(&mut self, address: A, bytes: B) -> Result<(), Self::Error> - where - B: IntoIterator, - { - T::write_iter(self, address, bytes) - } + fn write_iter(&mut self, address: A, bytes: B) -> Result<(), Self::Error> + where + B: IntoIterator, + { + T::write_iter(self, address, bytes) + } - fn write_read( - &mut self, - address: A, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - T::write_read(self, address, bytes, buffer) - } + fn write_read( + &mut self, + address: A, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + T::write_read(self, address, bytes, buffer) + } - fn write_iter_read( - &mut self, - address: A, - bytes: B, - buffer: &mut [u8], - ) -> Result<(), Self::Error> - where - B: IntoIterator, - { - T::write_iter_read(self, address, bytes, buffer) - } + fn write_iter_read( + &mut self, + address: A, + bytes: B, + buffer: &mut [u8], + ) -> Result<(), Self::Error> + where + B: IntoIterator, + { + T::write_iter_read(self, address, bytes, buffer) + } - fn transaction<'a>( - &mut self, - address: A, - operations: &mut [Operation<'a>], - ) -> Result<(), Self::Error> { - T::transaction(self, address, operations) - } + fn transaction<'a>( + &mut self, + address: A, + operations: &mut [Operation<'a>], + ) -> Result<(), Self::Error> { + T::transaction(self, address, operations) + } - fn transaction_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> - where - O: IntoIterator>, - { - T::transaction_iter(self, address, operations) - } + fn transaction_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> + where + O: IntoIterator>, + { + T::transaction_iter(self, address, operations) } } diff --git a/src/lib.rs b/src/lib.rs index a178c51d6..5d8c485d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,304 +58,10 @@ //! If you are writing a platform agnostic driver yourself you are highly encouraged to [add the //! embedded-hal keyword](https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata) //! to your crate before publishing it! -//! -//! # Detailed design -//! -//! ## Traits -//! -//! The HAL is specified as traits to allow generic programming. These 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; -//! -//! /// 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/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<_, Infallible>` is used. -//! -//! ``` -//! use embedded_hal::nb; -//! -//! # 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 as hal; -//! use hal::nb; -//! -//! // device crate -//! use stm32f1::stm32f103::USART1; -//! -//! /// A serial interface -//! // NOTE generic over the USART peripheral -//! pub struct Serial { usart: USART } -//! -//! // convenience type alias -//! pub type Serial1 = Serial; -//! -//! impl hal::serial::ErrorType for Serial { -//! type Error = hal::serial::ErrorKind; -//! } -//! -//! impl hal::serial::nb::Read for Serial { -//! fn read(&mut self) -> nb::Result { -//! // 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 hal::serial::nb::Write for Serial { -//! 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 crate::stm32f1xx_hal::Serial1; -//! use embedded_hal::serial::nb::Write; -//! use embedded_hal::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 as hal; -//! use hal::nb::block; -//! use hal::serial::nb::Write; -//! -//! fn write_all(serial: &mut S, buffer: &[u8]) -> Result<(), S::Error> -//! where -//! S: hal::serial::nb::Write -//! { -//! 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 as hal; -//! use hal::nb; -//! -//! use hal::serial::{ErrorKind, nb::Write}; -//! -//! fn flush(serial: &mut S, cb: &mut CircularBuffer) -//! where -//! S: hal::serial::nb::Write, -//! { -//! 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 = { -//! // .. -//! # Mutex(CircularBuffer) -//! }; -//! static SERIAL1: Mutex = { -//! // .. -//! # 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); -//! # impl Mutex { -//! # fn lock(&self) -> RefMut { 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 hal::serial::ErrorType for Serial1 { -//! # type Error = ErrorKind; -//! # } -//! # impl hal::serial::nb::Write 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 { None } -//! # pub fn push(&mut self, _: u8) -> Result<(), ()> { Ok(()) } -//! # } -//! -//! # fn main() {} -//! ``` #![warn(missing_docs)] #![no_std] -pub mod fmt; -pub use nb; -pub mod can; pub mod delay; pub mod digital; pub mod i2c; diff --git a/src/serial/mod.rs b/src/serial.rs similarity index 70% rename from src/serial/mod.rs rename to src/serial.rs index 1dd4b23b5..f0c05f98b 100644 --- a/src/serial/mod.rs +++ b/src/serial.rs @@ -1,8 +1,5 @@ //! Serial traits -pub mod blocking; -pub mod nb; - /// Serial error pub trait Error: core::fmt::Debug { /// Convert error to a generic serial error kind @@ -75,3 +72,29 @@ pub trait ErrorType { impl ErrorType for &mut T { type Error = T::Error; } + +/// Write half of a serial interface (blocking variant) +pub trait Write: ErrorType { + /// Writes a slice, blocking until everything has been written + /// + /// 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 [`flush`] after this function returns. + /// + /// [`flush`]: #tymethod.flush + fn write(&mut self, buffer: &[Word]) -> Result<(), Self::Error>; + + /// Block until the serial interface has sent all buffered words + fn flush(&mut self) -> Result<(), Self::Error>; +} + +impl, Word: Copy> Write for &mut T { + fn write(&mut self, buffer: &[Word]) -> Result<(), Self::Error> { + T::write(self, buffer) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + T::flush(self) + } +} diff --git a/src/serial/blocking.rs b/src/serial/blocking.rs deleted file mode 100644 index c5cfad4f8..000000000 --- a/src/serial/blocking.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Blocking serial API - -/// Write half of a serial interface (blocking variant) -pub trait Write: super::ErrorType { - /// Writes a slice, blocking until everything has been written - /// - /// 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 [`flush`] after this function returns. - /// - /// [`flush`]: #tymethod.flush - fn write(&mut self, buffer: &[Word]) -> Result<(), Self::Error>; - - /// Block until the serial interface has sent all buffered words - fn flush(&mut self) -> Result<(), Self::Error>; -} - -impl, Word: Copy> Write for &mut T { - fn write(&mut self, buffer: &[Word]) -> Result<(), Self::Error> { - T::write(self, buffer) - } - - fn flush(&mut self) -> Result<(), Self::Error> { - T::flush(self) - } -} diff --git a/src/spi/shared-bus.svg b/src/spi-shared-bus.svg similarity index 100% rename from src/spi/shared-bus.svg rename to src/spi-shared-bus.svg diff --git a/src/spi/blocking.rs b/src/spi.rs similarity index 79% rename from src/spi/blocking.rs rename to src/spi.rs index 67f8adc1a..72be4bb1b 100644 --- a/src/spi/blocking.rs +++ b/src/spi.rs @@ -5,7 +5,7 @@ //! SPI allows sharing a single bus between many SPI devices. The SCK, MOSI and MISO lines are //! wired in parallel to all the devices, and each device gets a dedicated chip-select (CS) line from the MCU, like this: //! -#![doc= include_str!("shared-bus.svg")] +#![doc= include_str!("spi-shared-bus.svg")] //! //! CS is usually active-low. When CS is high (not asserted), SPI devices ignore all incoming data, and //! don't drive MISO. When CS is low (asserted), the device is active: reacts to incoming data on MOSI and @@ -59,7 +59,7 @@ //! By using [`SpiDevice`], your driver will cooperate nicely with other drivers for other devices in the same shared SPI bus. //! //! ``` -//! # use embedded_hal::spi::blocking::{SpiBus, SpiBusRead, SpiBusWrite, SpiDevice}; +//! # use embedded_hal::spi::{SpiBus, SpiBusRead, SpiBusWrite, SpiDevice}; //! pub struct MyDriver { //! spi: SPI, //! } @@ -98,7 +98,7 @@ //! a bus without CS pins. By requiring [`SpiBus`] you disallow sharing, ensuring correct operation. //! //! ``` -//! # use embedded_hal::spi::blocking::{SpiBus, SpiBusRead, SpiBusWrite}; +//! # use embedded_hal::spi::{SpiBus, SpiBusRead, SpiBusWrite}; //! pub struct MyDriver { //! spi: SPI, //! } @@ -167,7 +167,136 @@ //! for them to return before the bus is idle. For example, assuming SPI mode 0, the last bit is sampled on the first (rising) edge //! of SCK, at which point a method could return, but the second (falling) SCK edge still has to happen before the bus is idle. -use crate::spi::ErrorType; +use core::fmt::Debug; + +/// Clock polarity +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Polarity { + /// Clock signal low when idle + IdleLow, + /// Clock signal high when idle + IdleHigh, +} + +/// Clock phase +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Phase { + /// Data in "captured" on the first clock transition + CaptureOnFirstTransition, + /// Data in "captured" on the second clock transition + CaptureOnSecondTransition, +} + +/// SPI mode +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Mode { + /// Clock polarity + pub polarity: Polarity, + /// Clock phase + pub phase: Phase, +} + +/// Helper for CPOL = 0, CPHA = 0 +pub const MODE_0: Mode = Mode { + polarity: Polarity::IdleLow, + phase: Phase::CaptureOnFirstTransition, +}; + +/// Helper for CPOL = 0, CPHA = 1 +pub const MODE_1: Mode = Mode { + polarity: Polarity::IdleLow, + phase: Phase::CaptureOnSecondTransition, +}; + +/// Helper for CPOL = 1, CPHA = 0 +pub const MODE_2: Mode = Mode { + polarity: Polarity::IdleHigh, + phase: Phase::CaptureOnFirstTransition, +}; + +/// Helper for CPOL = 1, CPHA = 1 +pub const MODE_3: Mode = Mode { + polarity: Polarity::IdleHigh, + phase: Phase::CaptureOnSecondTransition, +}; + +/// SPI error +pub trait Error: core::fmt::Debug { + /// Convert error to a generic SPI error kind + /// + /// By using this method, SPI errors freely defined by HAL implementations + /// can be converted to a set of generic SPI errors upon which generic + /// code can act. + fn kind(&self) -> ErrorKind; +} + +impl Error for core::convert::Infallible { + fn kind(&self) -> ErrorKind { + match *self {} + } +} + +/// SPI error kind +/// +/// This represents a common set of SPI operation errors. HAL implementations are +/// free to define more specific or additional error types. However, by providing +/// a mapping to these common SPI errors, generic code can still react to them. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[non_exhaustive] +pub enum ErrorKind { + /// The peripheral receive buffer was overrun + Overrun, + /// Multiple devices on the SPI bus are trying to drive the slave select pin, e.g. in a multi-master setup + ModeFault, + /// Received data does not conform to the peripheral configuration + FrameFormat, + /// An error occured while asserting or deasserting the Chip Select pin. + ChipSelectFault, + /// A different error occurred. The original error may contain more information. + Other, +} + +impl Error for ErrorKind { + fn kind(&self) -> ErrorKind { + *self + } +} + +impl core::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Overrun => write!(f, "The peripheral receive buffer was overrun"), + Self::ModeFault => write!( + f, + "Multiple devices on the SPI bus are trying to drive the slave select pin" + ), + Self::FrameFormat => write!( + f, + "Received data does not conform to the peripheral configuration" + ), + Self::ChipSelectFault => write!( + f, + "An error occured while asserting or deasserting the Chip Select pin" + ), + Self::Other => write!( + f, + "A different error occurred. The original error may contain more information" + ), + } + } +} + +/// SPI error type trait +/// +/// This just defines the error type, to be used by the other SPI traits. +pub trait ErrorType { + /// Error type + type Error: Error; +} + +impl ErrorType for &mut T { + type Error = T::Error; +} /// SPI device trait /// diff --git a/src/spi/mod.rs b/src/spi/mod.rs deleted file mode 100644 index 85254e262..000000000 --- a/src/spi/mod.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! SPI master mode traits. - -pub mod blocking; -pub mod nb; - -/// Clock polarity -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Polarity { - /// Clock signal low when idle - IdleLow, - /// Clock signal high when idle - IdleHigh, -} - -/// Clock phase -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Phase { - /// Data in "captured" on the first clock transition - CaptureOnFirstTransition, - /// Data in "captured" on the second clock transition - CaptureOnSecondTransition, -} - -/// SPI mode -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Mode { - /// Clock polarity - pub polarity: Polarity, - /// Clock phase - pub phase: Phase, -} - -/// Helper for CPOL = 0, CPHA = 0 -pub const MODE_0: Mode = Mode { - polarity: Polarity::IdleLow, - phase: Phase::CaptureOnFirstTransition, -}; - -/// Helper for CPOL = 0, CPHA = 1 -pub const MODE_1: Mode = Mode { - polarity: Polarity::IdleLow, - phase: Phase::CaptureOnSecondTransition, -}; - -/// Helper for CPOL = 1, CPHA = 0 -pub const MODE_2: Mode = Mode { - polarity: Polarity::IdleHigh, - phase: Phase::CaptureOnFirstTransition, -}; - -/// Helper for CPOL = 1, CPHA = 1 -pub const MODE_3: Mode = Mode { - polarity: Polarity::IdleHigh, - phase: Phase::CaptureOnSecondTransition, -}; - -/// SPI error -pub trait Error: core::fmt::Debug { - /// Convert error to a generic SPI error kind - /// - /// By using this method, SPI errors freely defined by HAL implementations - /// can be converted to a set of generic SPI errors upon which generic - /// code can act. - fn kind(&self) -> ErrorKind; -} - -impl Error for core::convert::Infallible { - fn kind(&self) -> ErrorKind { - match *self {} - } -} - -/// SPI error kind -/// -/// This represents a common set of SPI operation errors. HAL implementations are -/// free to define more specific or additional error types. However, by providing -/// a mapping to these common SPI errors, generic code can still react to them. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[non_exhaustive] -pub enum ErrorKind { - /// The peripheral receive buffer was overrun - Overrun, - /// Multiple devices on the SPI bus are trying to drive the slave select pin, e.g. in a multi-master setup - ModeFault, - /// Received data does not conform to the peripheral configuration - FrameFormat, - /// An error occured while asserting or deasserting the Chip Select pin. - ChipSelectFault, - /// A different error occurred. The original error may contain more information. - Other, -} - -impl Error for ErrorKind { - fn kind(&self) -> ErrorKind { - *self - } -} - -impl core::fmt::Display for ErrorKind { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::Overrun => write!(f, "The peripheral receive buffer was overrun"), - Self::ModeFault => write!( - f, - "Multiple devices on the SPI bus are trying to drive the slave select pin" - ), - Self::FrameFormat => write!( - f, - "Received data does not conform to the peripheral configuration" - ), - Self::ChipSelectFault => write!( - f, - "An error occured while asserting or deasserting the Chip Select pin" - ), - Self::Other => write!( - f, - "A different error occurred. The original error may contain more information" - ), - } - } -} - -/// SPI error type trait -/// -/// This just defines the error type, to be used by the other SPI traits. -pub trait ErrorType { - /// Error type - type Error: Error; -} - -impl ErrorType for &mut T { - type Error = T::Error; -} From 6d22f986f107940d83934263ddf0bf232558daca Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 6 Sep 2022 21:37:53 +0200 Subject: [PATCH 2/8] Move embedded-hal to a subdir, add workspace, simplify CI. --- .github/workflows/ci-async.yml | 32 -------------- .github/workflows/ci-bus.yml | 32 -------------- .github/workflows/ci.yml | 43 ------------------- .github/workflows/clippy-async.yml | 19 -------- .github/workflows/clippy-bus.yml | 19 -------- .github/workflows/clippy.yml | 6 ++- .github/workflows/rustfmt.yml | 7 +-- .github/workflows/test.yml | 36 +++++++++------- Cargo.toml | 24 ++++------- embedded-can/Cargo.toml | 2 +- embedded-hal-async/Cargo.toml | 2 +- embedded-hal-bus/Cargo.toml | 2 +- embedded-hal-nb/Cargo.toml | 2 +- CHANGELOG.md => embedded-hal/CHANGELOG.md | 0 embedded-hal/Cargo.toml | 16 +++++++ LICENSE-APACHE => embedded-hal/LICENSE-APACHE | 0 LICENSE-MIT => embedded-hal/LICENSE-MIT | 0 README.md => embedded-hal/README.md | 0 {src => embedded-hal/src}/delay.rs | 0 {src => embedded-hal/src}/digital.rs | 0 {src => embedded-hal/src}/i2c.rs | 0 {src => embedded-hal/src}/lib.rs | 0 {src => embedded-hal/src}/serial.rs | 0 {src => embedded-hal/src}/spi-shared-bus.svg | 0 {src => embedded-hal/src}/spi.rs | 0 25 files changed, 55 insertions(+), 187 deletions(-) delete mode 100644 .github/workflows/ci-async.yml delete mode 100644 .github/workflows/ci-bus.yml delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/clippy-async.yml delete mode 100644 .github/workflows/clippy-bus.yml rename CHANGELOG.md => embedded-hal/CHANGELOG.md (100%) create mode 100644 embedded-hal/Cargo.toml rename LICENSE-APACHE => embedded-hal/LICENSE-APACHE (100%) rename LICENSE-MIT => embedded-hal/LICENSE-MIT (100%) rename README.md => embedded-hal/README.md (100%) rename {src => embedded-hal/src}/delay.rs (100%) rename {src => embedded-hal/src}/digital.rs (100%) rename {src => embedded-hal/src}/i2c.rs (100%) rename {src => embedded-hal/src}/lib.rs (100%) rename {src => embedded-hal/src}/serial.rs (100%) rename {src => embedded-hal/src}/spi-shared-bus.svg (100%) rename {src => embedded-hal/src}/spi.rs (100%) diff --git a/.github/workflows/ci-async.yml b/.github/workflows/ci-async.yml deleted file mode 100644 index 741d2be74..000000000 --- a/.github/workflows/ci-async.yml +++ /dev/null @@ -1,32 +0,0 @@ -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: CI Async - -env: - RUSTFLAGS: '--deny warnings' - -jobs: - ci-linux-async: - runs-on: ubuntu-latest - strategy: - matrix: - rust: [nightly] - TARGET: [x86_64-unknown-linux-gnu, thumbv6m-none-eabi, thumbv7m-none-eabi] - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - target: ${{ matrix.TARGET }} - override: true - - run: cargo check --target=${{ matrix.TARGET }} - working-directory: embedded-hal-async - - - run: cargo test --target=${{ matrix.TARGET }} - if: contains(matrix.TARGET, 'linux') - working-directory: embedded-hal-async diff --git a/.github/workflows/ci-bus.yml b/.github/workflows/ci-bus.yml deleted file mode 100644 index 2463ed4de..000000000 --- a/.github/workflows/ci-bus.yml +++ /dev/null @@ -1,32 +0,0 @@ -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: CI Bus - -env: - RUSTFLAGS: '--deny warnings' - -jobs: - ci-linux-bus: - runs-on: ubuntu-latest - strategy: - matrix: - rust: [nightly] - TARGET: [x86_64-unknown-linux-gnu, thumbv6m-none-eabi, thumbv7m-none-eabi] - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - target: ${{ matrix.TARGET }} - override: true - - run: cargo check --target=${{ matrix.TARGET }} - working-directory: embedded-hal-bus - - - run: cargo test --target=${{ matrix.TARGET }} - if: contains(matrix.TARGET, 'linux') - working-directory: embedded-hal-bus diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 93fe80602..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,43 +0,0 @@ -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: Continuous integration - -env: - RUSTFLAGS: '--deny warnings' - -jobs: - ci-linux: - runs-on: ubuntu-latest - strategy: - matrix: - # All generated code should be running on stable now - rust: [stable] - - # The default target we're compiling on and for - TARGET: [x86_64-unknown-linux-gnu, thumbv6m-none-eabi, thumbv7m-none-eabi] - - include: - # Test MSRV - - rust: 1.54.0 - TARGET: x86_64-unknown-linux-gnu - - # Test nightly but don't fail - - rust: nightly - experimental: true - TARGET: x86_64-unknown-linux-gnu - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - target: ${{ matrix.TARGET }} - override: true - - uses: actions-rs/cargo@v1 - with: - command: check - args: --target=${{ matrix.TARGET }} diff --git a/.github/workflows/clippy-async.yml b/.github/workflows/clippy-async.yml deleted file mode 100644 index ce6abdb9f..000000000 --- a/.github/workflows/clippy-async.yml +++ /dev/null @@ -1,19 +0,0 @@ -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: Clippy check -jobs: - clippy_check-async: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - components: clippy - - run: cargo clippy - working-directory: embedded-hal-async diff --git a/.github/workflows/clippy-bus.yml b/.github/workflows/clippy-bus.yml deleted file mode 100644 index bc08e1763..000000000 --- a/.github/workflows/clippy-bus.yml +++ /dev/null @@ -1,19 +0,0 @@ -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: Clippy check -jobs: - clippy_check-bus: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - components: clippy - - run: cargo clippy - working-directory: embedded-hal-bus diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index adc3a6ed1..c4f5fca7b 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -5,14 +5,16 @@ on: name: Clippy check jobs: - clippy_check: + clippy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + # embedded-hal-async needs nightly. + # Use a pinned version to avoid spontaneous breakages (new clippy lints are added often) + toolchain: nightly-2022-09-05 override: true components: clippy - uses: actions-rs/clippy-check@v1 diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml index 45b32bae4..7ffd30a99 100644 --- a/.github/workflows/rustfmt.yml +++ b/.github/workflows/rustfmt.yml @@ -16,9 +16,4 @@ jobs: toolchain: nightly override: true components: rustfmt - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check - - run: cargo fmt --all -- --check - working-directory: embedded-hal-async + - run: cargo fmt --check diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9307a27c8..46740f048 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,26 +3,27 @@ on: branches: [ staging, trying, master ] pull_request: -name: Test Suite +name: Continuous integration env: RUSTFLAGS: '--deny warnings' jobs: - ci-linux-test: + test: runs-on: ubuntu-latest strategy: matrix: - rust: [stable] + # All generated code should be running on stable now + rust: + - stable + - 1.54.0 # MSRV + - nightly - include: - - rust: 1.54.0 - TARGET: x86_64-unknown-linux-gnu - - # Test nightly but don't fail - - rust: nightly - experimental: true - TARGET: x86_64-unknown-linux-gnu + # The default target we're compiling on and for + target: + - x86_64-unknown-linux-gnu + - thumbv6m-none-eabi + - thumbv7m-none-eabi steps: - uses: actions/checkout@v2 @@ -30,8 +31,13 @@ jobs: with: profile: minimal toolchain: ${{ matrix.rust }} - target: ${{ matrix.TARGET }} + target: ${{ matrix.target }} override: true - - uses: actions-rs/cargo@v1 - with: - command: test + + - run: sed -i '/nightly-only/d' Cargo.toml + if: matrix.toolchain != 'nightly' + + - run: cargo check --target=${{ matrix.target }} + + - run: cargo test --target=${{ matrix.target }} + if: contains(matrix.target, 'linux') diff --git a/Cargo.toml b/Cargo.toml index 70544070b..4322dde4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,10 @@ -[package] -authors = [ - "The Embedded HAL Team ", - "Jorge Aparicio ", - "Jonathan 'theJPster' Pallant " +[workspace] + +# CI removes lines containing 'nightly-only' when not building with nightly. +members = [ + "embedded-hal", + "embedded-hal-async", # nightly-only + "embedded-hal-nb", + "embedded-hal-bus", + "embedded-can", ] -categories = ["asynchronous", "embedded", "hardware-support", "no-std"] -description = " A Hardware Abstraction Layer (HAL) for embedded systems " -documentation = "https://docs.rs/embedded-hal" -edition = "2018" -keywords = ["hal", "IO"] -license = "MIT OR Apache-2.0" -name = "embedded-hal" -readme = "README.md" -repository = "https://github.com/rust-embedded/embedded-hal" -version = "1.0.0-alpha.8" diff --git a/embedded-can/Cargo.toml b/embedded-can/Cargo.toml index 4700687ce..47b5ef404 100644 --- a/embedded-can/Cargo.toml +++ b/embedded-can/Cargo.toml @@ -12,5 +12,5 @@ readme = "README.md" repository = "https://github.com/rust-embedded/embedded-hal" [dependencies] -embedded-hal = { version = "=1.0.0-alpha.8", path = ".." } +embedded-hal = { version = "=1.0.0-alpha.8", path = "../embedded-hal" } nb = "1" diff --git a/embedded-hal-async/Cargo.toml b/embedded-hal-async/Cargo.toml index 198825e4b..d3ec056cf 100644 --- a/embedded-hal-async/Cargo.toml +++ b/embedded-hal-async/Cargo.toml @@ -14,4 +14,4 @@ repository = "https://github.com/rust-embedded/embedded-hal" version = "0.1.0-alpha.1" [dependencies] -embedded-hal = { version = "=1.0.0-alpha.8", path = ".." } +embedded-hal = { version = "=1.0.0-alpha.8", path = "../embedded-hal" } diff --git a/embedded-hal-bus/Cargo.toml b/embedded-hal-bus/Cargo.toml index 17037163a..78c759f56 100644 --- a/embedded-hal-bus/Cargo.toml +++ b/embedded-hal-bus/Cargo.toml @@ -14,4 +14,4 @@ repository = "https://github.com/rust-embedded/embedded-hal" version = "0.1.0-alpha.0" [dependencies] -embedded-hal = { version = "=1.0.0-alpha.8", path = ".." } +embedded-hal = { version = "=1.0.0-alpha.8", path = "../embedded-hal" } diff --git a/embedded-hal-nb/Cargo.toml b/embedded-hal-nb/Cargo.toml index 5ff5d3305..a7b644541 100644 --- a/embedded-hal-nb/Cargo.toml +++ b/embedded-hal-nb/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" repository = "https://github.com/rust-embedded/embedded-hal" [dependencies] -embedded-hal = { version = "=1.0.0-alpha.8", path = ".." } +embedded-hal = { version = "=1.0.0-alpha.8", path = "../embedded-hal" } nb = "1" [dev-dependencies.stm32f1] diff --git a/CHANGELOG.md b/embedded-hal/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to embedded-hal/CHANGELOG.md diff --git a/embedded-hal/Cargo.toml b/embedded-hal/Cargo.toml new file mode 100644 index 000000000..70544070b --- /dev/null +++ b/embedded-hal/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = [ + "The Embedded HAL Team ", + "Jorge Aparicio ", + "Jonathan 'theJPster' Pallant " +] +categories = ["asynchronous", "embedded", "hardware-support", "no-std"] +description = " A Hardware Abstraction Layer (HAL) for embedded systems " +documentation = "https://docs.rs/embedded-hal" +edition = "2018" +keywords = ["hal", "IO"] +license = "MIT OR Apache-2.0" +name = "embedded-hal" +readme = "README.md" +repository = "https://github.com/rust-embedded/embedded-hal" +version = "1.0.0-alpha.8" diff --git a/LICENSE-APACHE b/embedded-hal/LICENSE-APACHE similarity index 100% rename from LICENSE-APACHE rename to embedded-hal/LICENSE-APACHE diff --git a/LICENSE-MIT b/embedded-hal/LICENSE-MIT similarity index 100% rename from LICENSE-MIT rename to embedded-hal/LICENSE-MIT diff --git a/README.md b/embedded-hal/README.md similarity index 100% rename from README.md rename to embedded-hal/README.md diff --git a/src/delay.rs b/embedded-hal/src/delay.rs similarity index 100% rename from src/delay.rs rename to embedded-hal/src/delay.rs diff --git a/src/digital.rs b/embedded-hal/src/digital.rs similarity index 100% rename from src/digital.rs rename to embedded-hal/src/digital.rs diff --git a/src/i2c.rs b/embedded-hal/src/i2c.rs similarity index 100% rename from src/i2c.rs rename to embedded-hal/src/i2c.rs diff --git a/src/lib.rs b/embedded-hal/src/lib.rs similarity index 100% rename from src/lib.rs rename to embedded-hal/src/lib.rs diff --git a/src/serial.rs b/embedded-hal/src/serial.rs similarity index 100% rename from src/serial.rs rename to embedded-hal/src/serial.rs diff --git a/src/spi-shared-bus.svg b/embedded-hal/src/spi-shared-bus.svg similarity index 100% rename from src/spi-shared-bus.svg rename to embedded-hal/src/spi-shared-bus.svg diff --git a/src/spi.rs b/embedded-hal/src/spi.rs similarity index 100% rename from src/spi.rs rename to embedded-hal/src/spi.rs From 04a2825ff0e4313cd98a133733624cb263eb9ee5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 6 Sep 2022 22:14:29 +0200 Subject: [PATCH 3/8] Update bors config. --- .github/bors.toml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/bors.toml b/.github/bors.toml index 904b48136..cad44688f 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -2,11 +2,15 @@ block_labels = ["needs-decision"] delete_merged_branches = true required_approvals = 1 status = [ - "ci-linux (stable, x86_64-unknown-linux-gnu)", - "ci-linux (stable, thumbv6m-none-eabi)", - "ci-linux (stable, thumbv7m-none-eabi)", - "ci-linux (1.54.0, x86_64-unknown-linux-gnu)", - "ci-linux-test (stable)", - "ci-linux-test (1.54.0, x86_64-unknown-linux-gnu)", + "test (stable, x86_64-unknown-linux-gnu)", + "test (stable, thumbv6m-none-eabi)", + "test (stable, thumbv7m-none-eabi)", + "test (1.54.0, x86_64-unknown-linux-gnu)", + "test (1.54.0, thumbv6m-none-eabi)", + "test (1.54.0, thumbv7m-none-eabi)", + "test (nightly, x86_64-unknown-linux-gnu)", + "test (nightly, thumbv6m-none-eabi)", + "test (nightly, thumbv7m-none-eabi)", + "clippy", "fmt", ] From bc3fc45bb9d3e3cff0e2b7f9a91673c03c04ab34 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 6 Sep 2022 23:08:45 +0200 Subject: [PATCH 4/8] Reorganize READMEs - Move "project-wide" stuff (CoC, legal boilerplate) to the main README. - List crates in main README. --- README.md | 100 +++++++++++++++++++++++++++++++++++ embedded-can/README.md | 27 +++------- embedded-hal-async/README.md | 17 ++---- embedded-hal-bus/README.md | 14 +---- embedded-hal-nb/README.md | 15 +----- embedded-hal/README.md | 67 +---------------------- 6 files changed, 115 insertions(+), 125 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..9b83eea6d --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +# `embedded-hal` + +> A Hardware Abstraction Layer (HAL) for embedded systems + +This project is developed and maintained by the [HAL team][https://github.com/rust-embedded/wg#the-hal-team]. + +## Scope + +`embedded-hal` serves as a foundation for building an ecosystem of platform agnostic drivers. +(driver meaning library crates that let a target platform interface an external device like a digital +sensor or a wireless transceiver). + +The advantage of this system is that by writing the driver as a generic library on top +of `embedded-hal` driver authors can support any number of target +platforms (e.g. Cortex-M microcontrollers, AVR microcontrollers, embedded Linux, etc.). + +The advantage for application developers is that by adopting `embedded-hal` they can unlock all +these drivers for their platform. + +For functionality that goes beyond what is provided by `embedded-hal`, users are encouraged +to use the target platform directly. Abstractions of common functionality can be proposed to be +included into `embedded-hal` as described [in this guide](docs/how-to-add-a-new-trait.md), though. + +See more about the design goals in [this documentation section](https://docs.rs/embedded-hal/latest/embedded_hal/#design-goals). + +## Crates + +The main `embedded-hal` project is not tied to a specific execution model like blocking or non-blocking. + +| Crate | crates.io | Docs | | +|-|-|-|-| +| [embedded-hal](./embedded-hal) | [![crates.io](https://img.shields.io/crates/v/embedded-hal.svg)](https://crates.io/crates/embedded-hal) | [![Documentation](https://docs.rs/embedded-hal/badge.svg)](https://docs.rs/embedded-hal) | Core traits, blocking version | +| [embedded-hal-async](./embedded-hal-async) | [![crates.io](https://img.shields.io/crates/v/embedded-hal-async.svg)](https://crates.io/crates/embedded-hal-async) | [![Documentation](https://docs.rs/embedded-hal-async/badge.svg)](https://docs.rs/embedded-hal-async) | Core traits, async version | +| [embedded-hal-nb](./embedded-hal-nb) | [![crates.io](https://img.shields.io/crates/v/embedded-hal-nb.svg)](https://crates.io/crates/embedded-hal-nb) | [![Documentation](https://docs.rs/embedded-hal-nb/badge.svg)](https://docs.rs/embedded-hal-nb) | Core traits, polling version using the `nb` crate | +| [embedded-hal-bus](./embedded-hal-bus) | [![crates.io](https://img.shields.io/crates/v/embedded-hal-bus.svg)](https://crates.io/crates/embedded-hal-bus) | [![Documentation](https://docs.rs/embedded-hal-bus/badge.svg)](https://docs.rs/embedded-hal-bus) | Utilities for sharing SPI and I2C buses | +| [embedded-can](./embedded-can) | [![crates.io](https://img.shields.io/crates/v/embedded-can.svg)](https://crates.io/crates/embedded-can) | [![Documentation](https://docs.rs/embedded-can/badge.svg)](https://docs.rs/embedded-can) | Controller Area Network (CAN) traits | + +## Releases + +At the moment we are working towards a `1.0.0` release (see [#177]). During this process we will +release alpha versions like `1.0.0-alpha.1` and `1.0.0-alpha.2`. +Alpha releases are **not guaranteed** to be compatible with each other. +They are provided as early previews for community testing and preparation for the final release. +If you use an alpha release, we recommend you choose an exact version specification in your +`Cargo.toml` like: `embedded-hal = "=1.0.0-alpha.8"` + +See [this guide](docs/version-policy.md) for a way to implement both an `embedded-hal` `0.2.x` +version and an `-alpha` version side by side in a HAL. + +[#177]: https://github.com/rust-embedded/embedded-hal/issues/177 + +## Documents + +- [How-to: add a new trait](docs/how-to-add-a-new-trait.md) +- [Version policy](docs/version-policy.md) +- [MSRV](docs/msrv.md) + +## Implementations and drivers + +For a non-exhaustive list of `embedded-hal` implementations and driver crates check the +[awesome-embedded-rust] list. + +You may be able to find even more HAL implementation crates and driver crates by searching for the +[`embedded-hal-impl`], [`embedded-hal-driver`] and [`embedded-hal`][embedded-hal-kw] keywords +on crates.io. + +[`embedded-hal-impl`]: https://crates.io/keywords/embedded-hal-impl +[`embedded-hal-driver`]: https://crates.io/keywords/embedded-hal-driver +[embedded-hal-kw]: https://crates.io/keywords/embedded-hal + +[awesome-embedded-rust]: https://github.com/rust-embedded/awesome-embedded-rust#driver-crates + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.54 and up. It *might* +compile with older versions but that may change in any new patch release. + +See [here](docs/msrv.md) for details on how the MSRV may be upgraded. + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +## Code of Conduct + +Contribution to this repository is organized under the terms of the [Rust Code of +Conduct](CODE_OF_CONDUCT.md), the maintainers of this repository, the [HAL team](https://github.com/rust-embedded/wg#the-hal-team), promise +to intervene to uphold that code of conduct. diff --git a/embedded-can/README.md b/embedded-can/README.md index 4cc5522d4..fc3a90ab2 100644 --- a/embedded-can/README.md +++ b/embedded-can/README.md @@ -1,19 +1,17 @@ -[![crates.io](https://img.shields.io/crates/d/embedded-hal-nb.svg)](https://crates.io/crates/embedded-hal-nb) -[![crates.io](https://img.shields.io/crates/v/embedded-hal-nb.svg)](https://crates.io/crates/embedded-hal-nb) -[![Documentation](https://docs.rs/embedded-hal-nb/badge.svg)](https://docs.rs/embedded-hal-nb) +[![crates.io](https://img.shields.io/crates/d/embedded-can.svg)](https://crates.io/crates/embedded-can) +[![crates.io](https://img.shields.io/crates/v/embedded-can.svg)](https://crates.io/crates/embedded-can) +[![Documentation](https://docs.rs/embedded-can/badge.svg)](https://docs.rs/embedded-can) ![Minimum Supported Rust Version](https://img.shields.io/badge/rustc-1.54+-blue.svg) -# `embedded-hal-nb` +# `embedded-can` -A non-blocking Hardware Abstraction Layer (HAL) for embedded systems, using the `nb` crate. +An embedded Controller Area Network (CAN) abstraction layer. This crate defines generic traits to be implemented by CAN driver and MCU HAL crates. -This crate contains versions of some [`embedded-hal`] traits using `nb`, and shares its scope and [design goals]. - -This project is developed and maintained by the [HAL team][team]. +This project is developed and maintained by the [HAL team][https://github.com/rust-embedded/wg#the-hal-team]. ## [API reference] -[API reference]: https://docs.rs/embedded-hal-nb +[API reference]: https://docs.rs/embedded-can ## Minimum Supported Rust Version (MSRV) @@ -37,14 +35,3 @@ at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. - -## Code of Conduct - -Contribution to this crate is organized under the terms of the [Rust Code of -Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises -to intervene to uphold that code of conduct. - -[CoC]: ../CODE_OF_CONDUCT.md -[team]: https://github.com/rust-embedded/wg#the-hal-team -[`embedded-hal`]: https://crates.io/crates/embedded-hal -[design goals]: https://docs.rs/embedded-hal/latest/embedded_hal/#design-goals \ No newline at end of file diff --git a/embedded-hal-async/README.md b/embedded-hal-async/README.md index f2347f841..05153e593 100644 --- a/embedded-hal-async/README.md +++ b/embedded-hal-async/README.md @@ -9,12 +9,12 @@ An asynchronous Hardware Abstraction Layer (HAL) for embedded systems. -This crate contains asynchronous versions of the [`embedded-hal`] traits and shares its scope and [design goals]. -The purpose of this crate is to iterate over these trait versions before integrating them into [`embedded-hal`]. +This crate contains asynchronous versions of the [`embedded-hal`](https://crates.io/crates/embedded-hal) traits and shares its scope and [design goals]. +The purpose of this crate is to iterate over these trait versions before integrating them into [`embedded-hal`](https://crates.io/crates/embedded-hal). **NOTE** These traits are still experimental. At least one breaking change to this crate is expected in the future (changing from GATs to `async fn`), but there might be more. -This project is developed and maintained by the [HAL team][team]. +This project is developed and maintained by the [HAL team][https://github.com/rust-embedded/wg#the-hal-team]. ## [API reference] @@ -42,14 +42,3 @@ at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. - -## Code of Conduct - -Contribution to this crate is organized under the terms of the [Rust Code of -Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises -to intervene to uphold that code of conduct. - -[CoC]: ../CODE_OF_CONDUCT.md -[team]: https://github.com/rust-embedded/wg#the-hal-team -[`embedded-hal`]: https://crates.io/crates/embedded-hal -[design goals]: https://docs.rs/embedded-hal/latest/embedded_hal/#design-goals \ No newline at end of file diff --git a/embedded-hal-bus/README.md b/embedded-hal-bus/README.md index b95144c80..85ad7cd05 100644 --- a/embedded-hal-bus/README.md +++ b/embedded-hal-bus/README.md @@ -5,7 +5,7 @@ # `embedded-hal-bus` -Bus/Device connection mechanisms for [`embedded-hal`], a Hardware Abstraction Layer (HAL) for embedded systems. +Bus/Device connection mechanisms for [`embedded-hal`](https://crates.io/crates/embedded-hal), a Hardware Abstraction Layer (HAL) for embedded systems. It is possible to connect several peripherals to a bus like SPI or I2C. To support this, `embedded-hal` provides the `SpiBus` and `SpiDevice` traits in the case of SPI, for example. @@ -18,7 +18,7 @@ This crate provides mechanisms to connect a `...Bus` and a `...Device`. For further details on these traits, please consult the [`embedded-hal` documentation](https://docs.rs/embedded-hal). -This project is developed and maintained by the [HAL team][team]. +This project is developed and maintained by the [HAL team][https://github.com/rust-embedded/wg#the-hal-team]. ## [API reference] @@ -48,13 +48,3 @@ at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. - -## Code of Conduct - -Contribution to this crate is organized under the terms of the [Rust Code of -Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises -to intervene to uphold that code of conduct. - -[CoC]: ../CODE_OF_CONDUCT.md -[team]: https://github.com/rust-embedded/wg#the-hal-team -[`embedded-hal`]: https://crates.io/crates/embedded-hal \ No newline at end of file diff --git a/embedded-hal-nb/README.md b/embedded-hal-nb/README.md index 4cc5522d4..82f836651 100644 --- a/embedded-hal-nb/README.md +++ b/embedded-hal-nb/README.md @@ -7,9 +7,9 @@ A non-blocking Hardware Abstraction Layer (HAL) for embedded systems, using the `nb` crate. -This crate contains versions of some [`embedded-hal`] traits using `nb`, and shares its scope and [design goals]. +This crate contains versions of some [`embedded-hal`](https://crates.io/crates/embedded-hal) traits using `nb`, and shares its scope and [design goals]. -This project is developed and maintained by the [HAL team][team]. +This project is developed and maintained by the [HAL team][https://github.com/rust-embedded/wg#the-hal-team]. ## [API reference] @@ -37,14 +37,3 @@ at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. - -## Code of Conduct - -Contribution to this crate is organized under the terms of the [Rust Code of -Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises -to intervene to uphold that code of conduct. - -[CoC]: ../CODE_OF_CONDUCT.md -[team]: https://github.com/rust-embedded/wg#the-hal-team -[`embedded-hal`]: https://crates.io/crates/embedded-hal -[design goals]: https://docs.rs/embedded-hal/latest/embedded_hal/#design-goals \ No newline at end of file diff --git a/embedded-hal/README.md b/embedded-hal/README.md index 03f5bd1ce..3e36460d3 100644 --- a/embedded-hal/README.md +++ b/embedded-hal/README.md @@ -7,68 +7,12 @@ > A Hardware Abstraction Layer (HAL) for embedded systems -This project is developed and maintained by the [HAL team][team]. +This project is developed and maintained by the [HAL team][https://github.com/rust-embedded/wg#the-hal-team]. ## [API reference] [API reference]: https://docs.rs/embedded-hal -## Scope - -`embedded-hal` serves as a foundation for building an ecosystem of platform agnostic drivers. -(driver meaning library crates that let a target platform interface an external device like a digital -sensor or a wireless transceiver). - -The advantage of this system is that by writing the driver as a generic library on top -of `embedded-hal` driver authors can support any number of target -platforms (e.g. Cortex-M microcontrollers, AVR microcontrollers, embedded Linux, etc.). - -The advantage for application developers is that by adopting `embedded-hal` they can unlock all -these drivers for their platform. - -`embedded-hal` is not tied to a specific execution model like blocking or non-blocking. - -For functionality that goes beyond what is provided by `embedded-hal`, users are encouraged -to use the target platform directly. Abstractions of common functionality can be proposed to be -included into `embedded-hal` as described [in this guide](docs/how-to-add-a-new-trait.md), though. - -See more about the design goals in [this documentation section](https://docs.rs/embedded-hal/latest/embedded_hal/#design-goals). - -## Releases - -At the moment we are working towards a `1.0.0` release (see [#177]). During this process we will -release alpha versions like `1.0.0-alpha.1` and `1.0.0-alpha.2`. -Alpha releases are **not guaranteed** to be compatible with each other. -They are provided as early previews for community testing and preparation for the final release. -If you use an alpha release, we recommend you choose an exact version specification in your -`Cargo.toml` like: `embedded-hal = "=1.0.0-alpha.8"` - -See [this guide](docs/version-policy.md) for a way to implement both an `embedded-hal` `0.2.x` -version and an `-alpha` version side by side in a HAL. - -[#177]: https://github.com/rust-embedded/embedded-hal/issues/177 - -## Documents - -- [How-to: add a new trait](docs/how-to-add-a-new-trait.md) -- [Version policy](docs/version-policy.md) -- [MSRV](docs/msrv.md) - -## Implementations and drivers - -For a non-exhaustive list of `embedded-hal` implementations and driver crates check the -[awesome-embedded-rust] list. - -You may be able to find even more HAL implementation crates and driver crates by searching for the -[`embedded-hal-impl`], [`embedded-hal-driver`] and [`embedded-hal`][embedded-hal-kw] keywords -on crates.io. - -[`embedded-hal-impl`]: https://crates.io/keywords/embedded-hal-impl -[`embedded-hal-driver`]: https://crates.io/keywords/embedded-hal-driver -[embedded-hal-kw]: https://crates.io/keywords/embedded-hal - -[awesome-embedded-rust]: https://github.com/rust-embedded/awesome-embedded-rust#driver-crates - ## Minimum Supported Rust Version (MSRV) This crate is guaranteed to compile on stable Rust 1.54 and up. It *might* @@ -91,12 +35,3 @@ at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. - -## Code of Conduct - -Contribution to this crate is organized under the terms of the [Rust Code of -Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises -to intervene to uphold that code of conduct. - -[CoC]: CODE_OF_CONDUCT.md -[team]: https://github.com/rust-embedded/wg#the-hal-team From 1328ed7a7cc2adddd9af16bd4de164fb2a3927cf Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 6 Sep 2022 23:18:21 +0200 Subject: [PATCH 5/8] List creates in embedded-hal rustdocs. --- embedded-hal/src/lib.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/embedded-hal/src/lib.rs b/embedded-hal/src/lib.rs index 5d8c485d9..8b65ded47 100644 --- a/embedded-hal/src/lib.rs +++ b/embedded-hal/src/lib.rs @@ -7,6 +7,21 @@ //! **NOTE** If you want to use an alpha release of the 1.0.0 version, use an exact version //! specifier in your `Cargo.toml` like: `embedded-hal = "=1.0.0-alpha.2"`. //! +//! # Companion crates +//! +//! The main `embedded-hal` crate contains only blocking traits, where the operation is done +//! synchronously before returning. Check out the following crates, which contain versions +//! of the traits for other execution models: +//! +//! - [`embedded-hal-async`](https://docs.rs/embedded-hal-async): async/await-based. +//! - [`embedded-hal-nb`](https://docs.rs/embedded-hal-nb): polling-based, using the `nb` crate. +//! +//! The [`embedded-hal-bus`](https://docs.rs/embedded-hal-bus) crate provides utilities for sharing +//! SPI and I2C buses. +//! +//! Additionally, more domain-specific traits are available in separate crates: +//! - [`embedded-can`](https://docs.rs/embedded-can): Controller Area Network (CAN) +//! //! # Design goals //! //! The HAL From db070baa0dbf1d4ffaf1a0d4dd8852793b7c8b87 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 13 Sep 2022 19:48:42 +0200 Subject: [PATCH 6/8] Add crate split to changelog. --- embedded-hal/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embedded-hal/CHANGELOG.md b/embedded-hal/CHANGELOG.md index 87bde6573..67813d6e0 100644 --- a/embedded-hal/CHANGELOG.md +++ b/embedded-hal/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + +- The `embedded-hal` crate now contains blocking traits only. Import paths no longer contain `::blocking`. `nb` traits are now available in a separate `embedded-hal-nb` crate. +- Moved CAN traits to a separate `embedded-can` crate. + ### Added - Implement `PartialOrd`, `Ord`, `Hash` for `can::StandardId`, `can::ExtendedId` and `can::Id` according to CAN bus arbitration rules From d417c6015ac15d96cce9078d54a63f569c88e09d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 13 Sep 2022 19:52:00 +0200 Subject: [PATCH 7/8] Removed changelog check in CI. --- .github/workflows/changelog.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/changelog.yml diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml deleted file mode 100644 index 29ca1399b..000000000 --- a/.github/workflows/changelog.yml +++ /dev/null @@ -1,20 +0,0 @@ -on: - pull_request_target: - -name: Changelog check - -jobs: - changelog: - name: Changelog check - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Changelog updated - uses: Zomzog/changelog-checker@v1.2.0 - with: - fileName: CHANGELOG.md - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - From c48550ce0179a3e1c7d31217791fc1e4e0009fff Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Mon, 26 Sep 2022 16:31:12 +0200 Subject: [PATCH 8/8] Do not enforce clippy --- .github/bors.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/bors.toml b/.github/bors.toml index cad44688f..a7f0129db 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -11,6 +11,5 @@ status = [ "test (nightly, x86_64-unknown-linux-gnu)", "test (nightly, thumbv6m-none-eabi)", "test (nightly, thumbv7m-none-eabi)", - "clippy", "fmt", ]