Skip to content

Commit

Permalink
Merge pull request #607 from 9names/embedded-hal-bus-atomic-device
Browse files Browse the repository at this point in the history
Add embedded-hal-bus atomic-device features
  • Loading branch information
Dirbaio authored Jul 28, 2024
2 parents f91fcbc + 2acbd77 commit 987dc68
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 6 deletions.
12 changes: 11 additions & 1 deletion embedded-hal-bus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,18 @@ repository = "https://github.com/rust-embedded/embedded-hal"
version = "0.2.0"

[features]
# Enable shared bus implementations using `std::sync::Mutex`, and implement `std::error::Error` for `DeviceError`
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
# that does not natively support atomic CAS. If you enable this, you must also add `portable-atomic` to your crate with
# a feature flag such as `unsafe-assume-single-core` or `critical-section` to choose how atomic CAS is implemented.
# See https://docs.rs/portable-atomic/1.7.0/portable_atomic/#optional-features for more info.
portable-atomic = ["dep:portable-atomic"]
# Enable `embedded-hal-async` support.
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 = []
Expand All @@ -26,7 +36,7 @@ embedded-hal = { version = "1.0.0", path = "../embedded-hal" }
embedded-hal-async = { version = "1.0.0", path = "../embedded-hal-async", optional = true }
critical-section = { version = "1.0" }
defmt-03 = { package = "defmt", version = "0.3", optional = true }
portable-atomic = {version = "1", default-features = false}
portable-atomic = {version = "1.3", default-features = false, optional = true, features = ["require-cas"]}

[package.metadata.docs.rs]
features = ["std", "async"]
Expand Down
10 changes: 8 additions & 2 deletions embedded-hal-bus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ provides mechanisms to obtain multiple `I2c` instances out of a single `I2c` ins

## Optional Cargo features

- **`std`**: enable shared bus implementations using `std::sync::Mutex`, and implement
`std::error::Error` for `DeviceError`.
- **`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
that does not natively support atomic CAS. If you enable this, you must also add `portable-atomic` to your crate with
a feature flag such as `unsafe-assume-single-core` or `critical-section` to choose how atomic CAS is implemented.
See <https://docs.rs/portable-atomic/1.7.0/portable_atomic/#optional-features> for more info.
- **`std`**: enable shared bus implementations using `std::sync::Mutex`, and implement
`std::error::Error` for `DeviceError`.

## Minimum Supported Rust Version (MSRV)

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

#[cfg(feature = "alloc")]
Expand Down
2 changes: 2 additions & 0 deletions embedded-hal-bus/src/spi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ pub use refcell::*;
mod mutex;
#[cfg(feature = "std")]
pub use mutex::*;
#[cfg(any(feature = "portable-atomic", target_has_atomic = "8"))]
mod atomic;
mod critical_section;
mod shared;
#[cfg(any(feature = "portable-atomic", target_has_atomic = "8"))]
pub use atomic::*;

#[cfg(feature = "alloc")]
Expand Down
15 changes: 12 additions & 3 deletions embedded-hal-bus/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
//! Utilities shared by all bus types.
#[allow(unused_imports)]
use core::cell::UnsafeCell;

#[cfg(not(feature = "portable-atomic"))]
use core::sync::atomic::AtomicBool;
#[cfg(feature = "portable-atomic")]
use portable_atomic::AtomicBool;

#[cfg(any(feature = "portable-atomic", target_has_atomic = "8"))]
/// Cell type used by [`spi::AtomicDevice`](crate::spi::AtomicDevice) and [`i2c::AtomicDevice`](crate::i2c::AtomicDevice).
///
/// To use `AtomicDevice`, you must wrap the bus with this struct, and then
/// construct multiple `AtomicDevice` instances with references to it.
pub struct AtomicCell<BUS> {
pub(crate) bus: UnsafeCell<BUS>,
pub(crate) busy: portable_atomic::AtomicBool,
pub(crate) busy: AtomicBool,
}

#[cfg(any(feature = "portable-atomic", target_has_atomic = "8"))]
unsafe impl<BUS: Send> Send for AtomicCell<BUS> {}
#[cfg(any(feature = "portable-atomic", target_has_atomic = "8"))]
unsafe impl<BUS: Send> Sync for AtomicCell<BUS> {}

#[cfg(any(feature = "portable-atomic", target_has_atomic = "8"))]
impl<BUS> AtomicCell<BUS> {
/// Create a new `AtomicCell`
pub fn new(bus: BUS) -> Self {
Self {
bus: UnsafeCell::new(bus),
busy: portable_atomic::AtomicBool::from(false),
busy: AtomicBool::from(false),
}
}
}

0 comments on commit 987dc68

Please sign in to comment.