Skip to content

Commit

Permalink
Merge branch 'master' into embedded-hal-bus-atomic-device
Browse files Browse the repository at this point in the history
  • Loading branch information
9names authored Jul 27, 2024
2 parents 3ddc31a + f91fcbc commit 25c1b8f
Show file tree
Hide file tree
Showing 30 changed files with 274 additions and 138 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
- uses: dtolnay/rust-toolchain@stable
with:
# embedded-hal-async needs nightly.
# Use a pinned version to avoid spontaneous breakages (new clippy lints are added often)
toolchain: nightly-2023-10-14
components: clippy
- run: cargo clippy --all-features -- --deny=warnings
2 changes: 1 addition & 1 deletion .github/workflows/rustdoc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2023-10-14
toolchain: nightly-2024-07-26
# tokio/net required to workaround https://github.com/tokio-rs/tokio/issues/6165
- run: RUSTDOCFLAGS="--deny=warnings --cfg=docsrs" cargo doc --all-features --features tokio/net
3 changes: 1 addition & 2 deletions .github/workflows/rustfmt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: nightly
components: rustfmt
- run: cargo fmt --check
4 changes: 4 additions & 0 deletions embedded-can/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ repository = "https://github.com/rust-embedded/embedded-hal"

[dependencies]
nb = "1"
defmt = { version = "0.3", optional = true }

[features]
defmt-03 = ["dep:defmt"]
4 changes: 4 additions & 0 deletions embedded-can/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ This project is developed and maintained by the [HAL team](https://github.com/ru

[API reference]: https://docs.rs/embedded-can

## Optional features

- **`defmt-03`**: Derive `defmt::Format` from `defmt` 0.3 for enums and structs.

## Minimum Supported Rust Version (MSRV)

This crate is guaranteed to compile on stable Rust 1.60 and up. It *might*
Expand Down
3 changes: 3 additions & 0 deletions embedded-can/src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/// Standard 11-bit CAN Identifier (`0..=0x7FF`).
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub struct StandardId(u16);

impl StandardId {
Expand Down Expand Up @@ -44,6 +45,7 @@ impl StandardId {

/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`).
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub struct ExtendedId(u32);

impl ExtendedId {
Expand Down Expand Up @@ -93,6 +95,7 @@ impl ExtendedId {

/// A CAN Identifier (standard or extended).
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub enum Id {
/// Standard 11-bit Identifier (`0..=0x7FF`).
Standard(StandardId),
Expand Down
1 change: 1 addition & 0 deletions embedded-can/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ impl Error for core::convert::Infallible {
/// free to define more specific or additional error types. However, by providing
/// a mapping to these common CAN errors, generic code can still react to them.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
#[non_exhaustive]
pub enum ErrorKind {
/// The peripheral receive buffer was overrun.
Expand Down
18 changes: 0 additions & 18 deletions embedded-hal-async/build.rs

This file was deleted.

6 changes: 0 additions & 6 deletions embedded-hal-async/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
#![no_std]
// disable warning for already-stabilized features.
// Needed to pass CI, because we deny warnings.
// We don't immediately remove them to not immediately break older nightlies.
// When all features are stable, we'll remove them.
#![cfg_attr(nightly, allow(stable_features, unknown_lints))]
#![cfg_attr(nightly, feature(async_fn_in_trait, impl_trait_projections))]
#![allow(async_fn_in_trait)]

pub mod delay;
Expand Down
3 changes: 2 additions & 1 deletion embedded-hal-bus/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

(Add unreleased changes here)
- Added the `alloc` feature.
- Added a new `RcDevice` for I2C and SPI, a reference-counting equivalent to `RefCellDevice`.

## [v0.2.0] - 2024-04-23

Expand Down
4 changes: 3 additions & 1 deletion embedded-hal-bus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ version = "0.2.0"

[features]
# Enable shared bus implementations using `std::sync::Mutex`, and implement `std::error::Error` for `DeviceError`
std = []
std = ["alloc"]
# Use `portable-atomic` to enable `atomic-device` on devices without native atomic CAS
#
# `portable-atomic` emulates atomic CAS functionality, allowing `embedded-hal-bus` to use `atomic-device` on hardware
Expand All @@ -28,6 +28,8 @@ portable-atomic = []
async = ["dep:embedded-hal-async"]
# Derive `defmt::Format` from `defmt` 0.3 for enums and structs. See https://github.com/knurling-rs/defmt for more info
defmt-03 = ["dep:defmt-03", "embedded-hal/defmt-03", "embedded-hal-async?/defmt-03"]
# Enables additional utilities requiring a global allocator.
alloc = []

[dependencies]
embedded-hal = { version = "1.0.0", path = "../embedded-hal" }
Expand Down
1 change: 1 addition & 0 deletions embedded-hal-bus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ provides mechanisms to obtain multiple `I2c` instances out of a single `I2c` ins

- **`async`**: enable `embedded-hal-async` support.
- **`defmt-03`**: Derive `defmt::Format` from `defmt` 0.3 for enums and structs.
- **`alloc`**: enable implementations using `alloc` (for instance, `spi::RcDevice`, which makes use of `alloc::rc::Rc`)
- **`portable-atomic`**: Use `portable-atomic` to enable `atomic-device` on devices without native atomic CAS

`portable-atomic` emulates atomic CAS functionality, allowing `embedded-hal-bus` to use `atomic-device` on hardware
Expand Down
18 changes: 0 additions & 18 deletions embedded-hal-bus/build.rs

This file was deleted.

5 changes: 5 additions & 0 deletions embedded-hal-bus/src/i2c/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ pub use self::critical_section::*;
mod atomic;
#[cfg(any(feature = "portable-atomic", target_has_atomic = "8"))]
pub use atomic::*;

#[cfg(feature = "alloc")]
mod rc;
#[cfg(feature = "alloc")]
pub use rc::*;
75 changes: 75 additions & 0 deletions embedded-hal-bus/src/i2c/rc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
extern crate alloc;
use alloc::rc::Rc;

use core::cell::RefCell;
use embedded_hal::i2c::{ErrorType, I2c};

/// `Rc<RefCell<T>>`-based shared bus [`I2c`] implementation.
/// This is the reference-counting equivalent of [`RefCellDevice`](super::RefCellDevice).
///
/// Sharing is implemented with a [`RefCell`] and ownership is managed by [`Rc`].
/// Like [`RefCellDevice`](super::RefCellDevice), `RcDevice` instances are not [`Send`],
/// so they can only be shared within a single thread (interrupt priority level).
///
/// When this `RcDevice` is dropped, the reference count of the I2C bus will be decremented.
/// Once that reference count hits zero, it will be cleaned up.
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
pub struct RcDevice<Bus> {
bus: Rc<RefCell<Bus>>,
}

impl<Bus> RcDevice<Bus> {
/// Creates a new `RcDevice`.
///
/// This function does not increment the reference count for the bus:
/// you will need to call `Rc::clone(&bus)` if you only have a `&Rc<RefCell<Bus>>`.
#[inline]
pub fn new(bus: Rc<RefCell<Bus>>) -> Self {
Self { bus }
}
}

impl<Bus> ErrorType for RcDevice<Bus>
where
Bus: ErrorType,
{
type Error = Bus::Error;
}

impl<Bus> I2c for RcDevice<Bus>
where
Bus: I2c,
{
#[inline]
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
let bus = &mut *self.bus.borrow_mut();
bus.read(address, read)
}

#[inline]
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
let bus = &mut *self.bus.borrow_mut();
bus.write(address, write)
}

#[inline]
fn write_read(
&mut self,
address: u8,
write: &[u8],
read: &mut [u8],
) -> Result<(), Self::Error> {
let bus = &mut *self.bus.borrow_mut();
bus.write_read(address, write, read)
}

#[inline]
fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
let bus = &mut *self.bus.borrow_mut();
bus.transaction(address, operations)
}
}
9 changes: 0 additions & 9 deletions embedded-hal-bus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,6 @@
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
// disable warning for already-stabilized features.
// Needed to pass CI, because we deny warnings.
// We don't immediately remove them to not immediately break older nightlies.
// When all features are stable, we'll remove them.
#![cfg_attr(all(feature = "async", nightly), allow(stable_features))]
#![cfg_attr(
all(feature = "async", nightly),
feature(async_fn_in_trait, impl_trait_projections)
)]

// needed to prevent defmt macros from breaking, since they emit code that does `defmt::blahblah`.
#[cfg(feature = "defmt-03")]
Expand Down
5 changes: 5 additions & 0 deletions embedded-hal-bus/src/spi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ mod shared;
#[cfg(any(feature = "portable-atomic", target_has_atomic = "8"))]
pub use atomic::*;

#[cfg(feature = "alloc")]
mod rc;
#[cfg(feature = "alloc")]
pub use rc::*;

pub use self::critical_section::*;

#[cfg(feature = "defmt-03")]
Expand Down
90 changes: 90 additions & 0 deletions embedded-hal-bus/src/spi/rc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
extern crate alloc;
use alloc::rc::Rc;

use core::cell::RefCell;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};

use super::DeviceError;
use crate::spi::shared::transaction;

/// Implementation of [`SpiDevice`] around a bus shared with `Rc<RefCell<T>>`.
/// This is the reference-counting equivalent of [`RefCellDevice`](super::RefCellDevice), requiring allocation.
///
/// A single [`SpiBus`] is shared via [`RefCell`], and its ownership is handled by [`Rc`].
/// Both of these mechanisms only allow sharing within a single thread (or interrupt priority level).
/// For this reason, this does not implement [`Send`].
///
/// When this structure is dropped, the reference count of the `Bus` instance will be decremented,
/// and it will be cleaned up once the reference count reaches zero.
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
pub struct RcDevice<Bus, Cs, Delay> {
bus: Rc<RefCell<Bus>>,
cs: Cs,
delay: Delay,
}

impl<Bus, Cs, Delay> RcDevice<Bus, Cs, Delay> {
/// Creates a new [`RcDevice`].
///
/// This sets the `cs` pin high, and returns an error if that fails.
/// It is recommended to have already set that pin high the moment it has been configured as an output, to avoid glitches.
///
/// This function does not increment the reference count:
/// you will need to call `Rc::clone(&bus)` if you only have a `&Rc<RefCell<Bus>>`.
#[inline]
pub fn new(bus: Rc<RefCell<Bus>>, mut cs: Cs, delay: Delay) -> Result<Self, Cs::Error>
where
Cs: OutputPin,
{
cs.set_high()?;

Ok(Self { bus, cs, delay })
}
}

impl<Bus, Cs> RcDevice<Bus, Cs, super::NoDelay> {
/// Creates a new [`RcDevice`] without support for in-transaction delays.
///
/// **Warning**: It's advised to prefer [`RcDevice::new`],
/// as the contract of [`SpiDevice`] requests support for in-transaction delays.
///
/// Refer to [`RefCellDevice::new_no_delay`](super::RefCellDevice::new_no_delay) for more information.
#[inline]
pub fn new_no_delay(bus: Rc<RefCell<Bus>>, mut cs: Cs) -> Result<Self, Cs::Error>
where
Cs: OutputPin,
{
cs.set_high()?;

Ok(Self {
bus,
cs,
delay: super::NoDelay,
})
}
}

impl<Bus, Cs, Delay> ErrorType for RcDevice<Bus, Cs, Delay>
where
Bus: ErrorType,
Cs: OutputPin,
{
type Error = DeviceError<Bus::Error, Cs::Error>;
}

impl<Word, Bus, Cs, Delay> SpiDevice<Word> for RcDevice<Bus, Cs, Delay>
where
Word: Copy + 'static,
Bus: SpiBus<Word>,
Cs: OutputPin,
Delay: DelayNs,
{
#[inline]
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
let bus = &mut *self.bus.borrow_mut();

transaction(operations, bus, &mut self.delay, &mut self.cs)
}
}
6 changes: 3 additions & 3 deletions embedded-hal-nb/src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ pub use embedded_hal::spi::{
/// - Due to how full duplex SPI works each `read` call must be preceded by a `write` call.
///
/// - `read` calls only return the data received with the last `write` call.
/// Previously received data is discarded
/// Previously received data is discarded
///
/// - Data is only guaranteed to be clocked out when the `read` call succeeds.
/// The slave select line shouldn't be released before that.
/// The slave select line shouldn't be released before that.
///
/// - Some SPIs can work with 8-bit *and* 16-bit words. You can overload this trait with different
/// `Word` types to allow operation in both modes.
/// `Word` types to allow operation in both modes.
pub trait FullDuplex<Word: Copy = u8>: ErrorType {
/// Reads the word stored in the shift register
///
Expand Down
Loading

0 comments on commit 25c1b8f

Please sign in to comment.