Merge remote-tracking branch 'origin/master' into nrf-pdm
This commit is contained in:
commit
2900ab79e7
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
@ -69,4 +69,4 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test
|
||||
run: cd embassy-util && cargo test
|
||||
run: cd embassy-sync && cargo test
|
||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -18,7 +18,7 @@
|
||||
"rust-analyzer.linkedProjects": [
|
||||
// Declare for the target you wish to develop
|
||||
//"embassy-executor/Cargo.toml",
|
||||
//"embassy-util/Cargo.toml",
|
||||
//"embassy-sync/Cargo.toml",
|
||||
"examples/nrf/Cargo.toml",
|
||||
// "examples/rp/Cargo.toml",
|
||||
// "examples/std/Cargo.toml",
|
||||
|
@ -14,7 +14,7 @@ target = "thumbv7em-none-eabi"
|
||||
[dependencies]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4", optional = true }
|
||||
embassy-util = { version = "0.1.0", path = "../../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../../embassy-sync" }
|
||||
embedded-storage = "0.3.0"
|
||||
embedded-storage-async = "0.3.0"
|
||||
|
||||
|
@ -15,7 +15,7 @@ target = "thumbv7em-none-eabi"
|
||||
[dependencies]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
||||
embassy-util = { path = "../../embassy-util" }
|
||||
embassy-sync = { path = "../../embassy-sync" }
|
||||
embassy-nrf = { path = "../../embassy-nrf", default-features = false, features = ["nightly"] }
|
||||
embassy-boot = { path = "../boot", default-features = false }
|
||||
cortex-m = { version = "0.7.6" }
|
||||
|
@ -17,7 +17,7 @@ defmt = { version = "0.3", optional = true }
|
||||
defmt-rtt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4", optional = true }
|
||||
|
||||
embassy-util = { path = "../../embassy-util" }
|
||||
embassy-sync = { path = "../../embassy-sync" }
|
||||
embassy-stm32 = { path = "../../embassy-stm32", default-features = false, features = ["nightly"] }
|
||||
embassy-boot = { path = "../boot", default-features = false }
|
||||
cortex-m = { version = "0.7.6" }
|
||||
|
@ -35,7 +35,7 @@ prio-bits-8 = []
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embassy-executor = { version = "0.1.0", path = "../embassy-executor"}
|
||||
embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
|
||||
embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common"}
|
||||
|
@ -71,7 +71,7 @@ impl<I: Interrupt> InterruptExecutor<I> {
|
||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||
/// access. There's a few ways to do this:
|
||||
///
|
||||
/// - a [Forever](embassy_util::Forever) (safe)
|
||||
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
|
||||
/// - a `static mut` (unsafe)
|
||||
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
||||
pub fn start(&'static mut self) -> SendSpawner {
|
||||
|
@ -16,7 +16,7 @@ std = []
|
||||
nightly = ["embedded-hal-async", "embedded-storage-async"]
|
||||
|
||||
[dependencies]
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }
|
||||
embedded-hal-async = { version = "0.1.0-alpha.1", optional = true }
|
||||
|
@ -4,15 +4,15 @@
|
||||
//!
|
||||
//! ```rust
|
||||
//! use embassy_embedded_hal::shared_bus::i2c::I2cDevice;
|
||||
//! use embassy_util::mutex::Mutex;
|
||||
//! use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
|
||||
//! use embassy_sync::mutex::Mutex;
|
||||
//! use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||
//!
|
||||
//! static I2C_BUS: Forever<Mutex::<ThreadModeRawMutex, Twim<TWISPI0>>> = Forever::new();
|
||||
//! static I2C_BUS: StaticCell<Mutex::<ThreadModeRawMutex, Twim<TWISPI0>>> = StaticCell::new();
|
||||
//! let config = twim::Config::default();
|
||||
//! let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
||||
//! let i2c = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
|
||||
//! let i2c_bus = Mutex::<ThreadModeRawMutex, _>::new(i2c);
|
||||
//! let i2c_bus = I2C_BUS.put(i2c_bus);
|
||||
//! let i2c_bus = I2C_BUS.init(i2c_bus);
|
||||
//!
|
||||
//! // Device 1, using embedded-hal-async compatible driver for QMC5883L compass
|
||||
//! let i2c_dev1 = I2cDevice::new(i2c_bus);
|
||||
@ -24,8 +24,8 @@
|
||||
//! ```
|
||||
use core::future::Future;
|
||||
|
||||
use embassy_util::blocking_mutex::raw::RawMutex;
|
||||
use embassy_util::mutex::Mutex;
|
||||
use embassy_sync::blocking_mutex::raw::RawMutex;
|
||||
use embassy_sync::mutex::Mutex;
|
||||
use embedded_hal_async::i2c;
|
||||
|
||||
use crate::shared_bus::I2cDeviceError;
|
||||
|
@ -4,16 +4,16 @@
|
||||
//!
|
||||
//! ```rust
|
||||
//! use embassy_embedded_hal::shared_bus::spi::SpiDevice;
|
||||
//! use embassy_util::mutex::Mutex;
|
||||
//! use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
|
||||
//! use embassy_sync::mutex::Mutex;
|
||||
//! use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||
//!
|
||||
//! static SPI_BUS: Forever<Mutex<ThreadModeRawMutex, spim::Spim<SPI3>>> = Forever::new();
|
||||
//! static SPI_BUS: StaticCell<Mutex<ThreadModeRawMutex, spim::Spim<SPI3>>> = StaticCell::new();
|
||||
//! let mut config = spim::Config::default();
|
||||
//! config.frequency = spim::Frequency::M32;
|
||||
//! let irq = interrupt::take!(SPIM3);
|
||||
//! let spi = spim::Spim::new_txonly(p.SPI3, irq, p.P0_15, p.P0_18, config);
|
||||
//! let spi_bus = Mutex::<ThreadModeRawMutex, _>::new(spi);
|
||||
//! let spi_bus = SPI_BUS.put(spi_bus);
|
||||
//! let spi_bus = SPI_BUS.init(spi_bus);
|
||||
//!
|
||||
//! // Device 1, using embedded-hal-async compatible driver for ST7735 LCD display
|
||||
//! let cs_pin1 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard);
|
||||
@ -27,8 +27,8 @@
|
||||
//! ```
|
||||
use core::future::Future;
|
||||
|
||||
use embassy_util::blocking_mutex::raw::RawMutex;
|
||||
use embassy_util::mutex::Mutex;
|
||||
use embassy_sync::blocking_mutex::raw::RawMutex;
|
||||
use embassy_sync::mutex::Mutex;
|
||||
use embedded_hal_1::digital::blocking::OutputPin;
|
||||
use embedded_hal_1::spi::ErrorType;
|
||||
use embedded_hal_async::spi;
|
||||
|
@ -4,13 +4,13 @@
|
||||
//!
|
||||
//! ```rust
|
||||
//! use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
|
||||
//! use embassy_util::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
|
||||
//! use embassy_sync::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
|
||||
//!
|
||||
//! static I2C_BUS: Forever<NoopMutex<RefCell<Twim<TWISPI0>>>> = Forever::new();
|
||||
//! static I2C_BUS: StaticCell<NoopMutex<RefCell<Twim<TWISPI0>>>> = StaticCell::new();
|
||||
//! let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
||||
//! let i2c = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, Config::default());
|
||||
//! let i2c_bus = NoopMutex::new(RefCell::new(i2c));
|
||||
//! let i2c_bus = I2C_BUS.put(i2c_bus);
|
||||
//! let i2c_bus = I2C_BUS.init(i2c_bus);
|
||||
//!
|
||||
//! let i2c_dev1 = I2cDevice::new(i2c_bus);
|
||||
//! let mpu = Mpu6050::new(i2c_dev1);
|
||||
@ -18,8 +18,8 @@
|
||||
|
||||
use core::cell::RefCell;
|
||||
|
||||
use embassy_util::blocking_mutex::raw::RawMutex;
|
||||
use embassy_util::blocking_mutex::Mutex;
|
||||
use embassy_sync::blocking_mutex::raw::RawMutex;
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
use embedded_hal_1::i2c::blocking::{I2c, Operation};
|
||||
use embedded_hal_1::i2c::ErrorType;
|
||||
|
||||
|
@ -4,13 +4,13 @@
|
||||
//!
|
||||
//! ```rust
|
||||
//! use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
||||
//! use embassy_util::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
|
||||
//! use embassy_sync::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
|
||||
//!
|
||||
//! static SPI_BUS: Forever<NoopMutex<RefCell<Spim<SPI3>>>> = Forever::new();
|
||||
//! static SPI_BUS: StaticCell<NoopMutex<RefCell<Spim<SPI3>>>> = StaticCell::new();
|
||||
//! let irq = interrupt::take!(SPIM3);
|
||||
//! let spi = Spim::new_txonly(p.SPI3, irq, p.P0_15, p.P0_18, Config::default());
|
||||
//! let spi_bus = NoopMutex::new(RefCell::new(spi));
|
||||
//! let spi_bus = SPI_BUS.put(spi_bus);
|
||||
//! let spi_bus = SPI_BUS.init(spi_bus);
|
||||
//!
|
||||
//! // Device 1, using embedded-hal compatible driver for ST7735 LCD display
|
||||
//! let cs_pin1 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard);
|
||||
@ -20,8 +20,8 @@
|
||||
|
||||
use core::cell::RefCell;
|
||||
|
||||
use embassy_util::blocking_mutex::raw::RawMutex;
|
||||
use embassy_util::blocking_mutex::Mutex;
|
||||
use embassy_sync::blocking_mutex::raw::RawMutex;
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
use embedded_hal_1::digital::blocking::OutputPin;
|
||||
use embedded_hal_1::spi;
|
||||
use embedded_hal_1::spi::blocking::SpiBusFlush;
|
||||
|
@ -30,9 +30,13 @@ nightly = []
|
||||
|
||||
integrated-timers = ["dep:embassy-time"]
|
||||
|
||||
# Trace interrupt invocations with rtos-trace.
|
||||
rtos-trace-interrupt = ["rtos-trace"]
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
rtos-trace = { version = "0.1.2", optional = true }
|
||||
|
||||
futures-util = { version = "0.3.17", default-features = false }
|
||||
embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
|
||||
@ -40,7 +44,8 @@ embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true}
|
||||
atomic-polyfill = "1.0.1"
|
||||
critical-section = "1.1"
|
||||
cfg-if = "1.0.0"
|
||||
static_cell = "1.0"
|
||||
|
||||
# WASM dependencies
|
||||
wasm-bindgen = { version = "0.2.76", features = ["nightly"], optional = true }
|
||||
wasm-bindgen = { version = "0.2.82", optional = true }
|
||||
js-sys = { version = "0.3", optional = true }
|
@ -41,7 +41,7 @@ impl Executor {
|
||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||
/// access. There's a few ways to do this:
|
||||
///
|
||||
/// - a [Forever](crate::util::Forever) (safe)
|
||||
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
|
||||
/// - a `static mut` (unsafe)
|
||||
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
||||
///
|
||||
|
@ -43,7 +43,7 @@ impl Executor {
|
||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||
/// access. There's a few ways to do this:
|
||||
///
|
||||
/// - a [Forever](crate::util::Forever) (safe)
|
||||
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
|
||||
/// - a `static mut` (unsafe)
|
||||
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
||||
///
|
||||
|
@ -40,7 +40,7 @@ impl Executor {
|
||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||
/// access. There's a few ways to do this:
|
||||
///
|
||||
/// - a [Forever](crate::util::Forever) (safe)
|
||||
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
|
||||
/// - a `static mut` (unsafe)
|
||||
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
||||
///
|
||||
|
@ -59,7 +59,7 @@ impl Executor {
|
||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||
/// access. There's a few ways to do this:
|
||||
///
|
||||
/// - a [Forever](crate::util::Forever) (safe)
|
||||
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
|
||||
/// - a `static mut` (unsafe)
|
||||
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
||||
pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
|
||||
|
@ -43,7 +43,7 @@ impl Executor {
|
||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||
/// access. There's a few ways to do this:
|
||||
///
|
||||
/// - a [Forever](crate::util::Forever) (safe)
|
||||
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
|
||||
/// - a `static mut` (unsafe)
|
||||
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
||||
///
|
||||
|
@ -38,7 +38,38 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Implementation details for embassy macros. DO NOT USE.
|
||||
pub mod export {
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
pub use rtos_trace::trace;
|
||||
|
||||
/// Expands the given block of code when `embassy-executor` is compiled with
|
||||
/// the `rtos-trace-interrupt` feature.
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[cfg(feature = "rtos-trace-interrupt")]
|
||||
macro_rules! rtos_trace_interrupt {
|
||||
($($tt:tt)*) => { $($tt)* };
|
||||
}
|
||||
|
||||
/// Does not expand the given block of code when `embassy-executor` is
|
||||
/// compiled without the `rtos-trace-interrupt` feature.
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[cfg(not(feature = "rtos-trace-interrupt"))]
|
||||
macro_rules! rtos_trace_interrupt {
|
||||
($($tt:tt)*) => {};
|
||||
}
|
||||
}
|
||||
|
||||
pub mod raw;
|
||||
|
||||
mod spawner;
|
||||
pub use spawner::*;
|
||||
|
||||
/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
|
||||
#[doc(hidden)]
|
||||
pub mod _export {
|
||||
pub use static_cell::StaticCell;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
//! ## WARNING: here be dragons!
|
||||
//!
|
||||
//! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe
|
||||
//! executor wrappers in [`executor`](crate::executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe.
|
||||
//! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe.
|
||||
|
||||
mod run_queue;
|
||||
#[cfg(feature = "integrated-timers")]
|
||||
@ -26,6 +26,8 @@ use critical_section::CriticalSection;
|
||||
use embassy_time::driver::{self, AlarmHandle};
|
||||
#[cfg(feature = "integrated-timers")]
|
||||
use embassy_time::Instant;
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
use rtos_trace::trace;
|
||||
|
||||
use self::run_queue::{RunQueue, RunQueueItem};
|
||||
use self::util::UninitCell;
|
||||
@ -247,7 +249,7 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
|
||||
///
|
||||
/// This is the core of the Embassy executor. It is low-level, requiring manual
|
||||
/// handling of wakeups and task polling. If you can, prefer using one of the
|
||||
/// higher level executors in [`crate::executor`].
|
||||
/// [higher level executors](crate::Executor).
|
||||
///
|
||||
/// The raw executor leaves it up to you to handle wakeups and scheduling:
|
||||
///
|
||||
@ -306,6 +308,9 @@ impl Executor {
|
||||
/// - `task` must NOT be already enqueued (in this executor or another one).
|
||||
#[inline(always)]
|
||||
unsafe fn enqueue(&self, cs: CriticalSection, task: NonNull<TaskHeader>) {
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
trace::task_ready_begin(task.as_ptr() as u32);
|
||||
|
||||
if self.run_queue.enqueue(cs, task) {
|
||||
(self.signal_fn)(self.signal_ctx)
|
||||
}
|
||||
@ -323,6 +328,9 @@ impl Executor {
|
||||
pub(super) unsafe fn spawn(&'static self, task: NonNull<TaskHeader>) {
|
||||
task.as_ref().executor.set(self);
|
||||
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
trace::task_new(task.as_ptr() as u32);
|
||||
|
||||
critical_section::with(|cs| {
|
||||
self.enqueue(cs, task);
|
||||
})
|
||||
@ -365,9 +373,15 @@ impl Executor {
|
||||
return;
|
||||
}
|
||||
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
trace::task_exec_begin(p.as_ptr() as u32);
|
||||
|
||||
// Run the task
|
||||
task.poll_fn.read()(p as _);
|
||||
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
trace::task_exec_end();
|
||||
|
||||
// Enqueue or update into timer_queue
|
||||
#[cfg(feature = "integrated-timers")]
|
||||
self.timer_queue.update(p);
|
||||
@ -381,6 +395,9 @@ impl Executor {
|
||||
let next_expiration = self.timer_queue.next_expiration();
|
||||
driver::set_alarm(self.alarm, next_expiration.as_ticks());
|
||||
}
|
||||
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
trace::system_idle();
|
||||
}
|
||||
|
||||
/// Get a spawner that spawns tasks in this executor.
|
||||
@ -426,3 +443,21 @@ unsafe fn _embassy_time_schedule_wake(at: Instant, waker: &core::task::Waker) {
|
||||
let expires_at = task.expires_at.get();
|
||||
task.expires_at.set(expires_at.min(at));
|
||||
}
|
||||
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
impl rtos_trace::RtosTraceOSCallbacks for Executor {
|
||||
fn task_list() {
|
||||
// We don't know what tasks exist, so we can't send them.
|
||||
}
|
||||
#[cfg(feature = "integrated-timers")]
|
||||
fn time() -> u64 {
|
||||
Instant::now().as_micros()
|
||||
}
|
||||
#[cfg(not(feature = "integrated-timers"))]
|
||||
fn time() -> u64 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
rtos_trace::global_os_callbacks! {Executor}
|
||||
|
14
embassy-futures/Cargo.toml
Normal file
14
embassy-futures/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "embassy-futures"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-futures-v$VERSION/embassy-futures/src/"
|
||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-futures/src/"
|
||||
features = ["nightly"]
|
||||
target = "thumbv7em-none-eabi"
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
9
embassy-futures/README.md
Normal file
9
embassy-futures/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# embassy-futures
|
||||
|
||||
Utilities for working with futures:
|
||||
|
||||
- [`select`](select::select) - waiting for one out of two futures to complete.
|
||||
- [`select3`](select::select3) - waiting for one out of three futures to complete.
|
||||
- [`select4`](select::select4) - waiting for one out of four futures to complete.
|
||||
- [`select_all`](select::select_all) - waiting for one future in a list of futures to complete.
|
||||
- [`yield_now`](yield_now::yield_now) - yielding the current task.
|
12
embassy-futures/src/lib.rs
Normal file
12
embassy-futures/src/lib.rs
Normal file
@ -0,0 +1,12 @@
|
||||
#![no_std]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
// This mod MUST go first, so that the others see its macros.
|
||||
pub(crate) mod fmt;
|
||||
|
||||
mod select;
|
||||
mod yield_now;
|
||||
|
||||
pub use select::*;
|
||||
pub use yield_now::*;
|
@ -25,7 +25,7 @@ defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy-time = { version = "0.1.0", path = "../embassy-time" }
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
|
||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }
|
||||
embedded-hal-async = { version = "0.1.0-alpha.1" }
|
||||
|
@ -12,7 +12,7 @@ use embassy_stm32::subghz::{
|
||||
Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams,
|
||||
};
|
||||
use embassy_stm32::Peripheral;
|
||||
use embassy_util::channel::signal::Signal;
|
||||
use embassy_sync::signal::Signal;
|
||||
use lorawan_device::async_device::radio::{Bandwidth, PhyRxTx, RfConfig, RxQuality, SpreadingFactor, TxConfig};
|
||||
use lorawan_device::async_device::Timings;
|
||||
|
||||
|
@ -19,7 +19,13 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
|
||||
let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed);
|
||||
let ctx = HANDLER.ctx.load(interrupt::_export::atomic::Ordering::Relaxed);
|
||||
let func: fn(*mut ()) = ::core::mem::transmute(func);
|
||||
func(ctx)
|
||||
::embassy_executor::rtos_trace_interrupt! {
|
||||
::embassy_executor::export::trace::isr_enter();
|
||||
}
|
||||
func(ctx);
|
||||
::embassy_executor::rtos_trace_interrupt! {
|
||||
::embassy_executor::export::trace::isr_exit();
|
||||
}
|
||||
}
|
||||
|
||||
static TAKEN: interrupt::_export::atomic::AtomicBool = interrupt::_export::atomic::AtomicBool::new(false);
|
||||
|
@ -34,8 +34,8 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
|
||||
let main = quote! {
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(start)]
|
||||
pub fn main() -> Result<(), wasm_bindgen::JsValue> {
|
||||
static EXECUTOR: ::embassy_util::Forever<::embassy_executor::Executor> = ::embassy_util::Forever::new();
|
||||
let executor = EXECUTOR.put(::embassy_executor::Executor::new());
|
||||
static EXECUTOR: ::embassy_executor::_export::StaticCell<::embassy_executor::Executor> = ::embassy_executor::_export::StaticCell::new();
|
||||
let executor = EXECUTOR.init(::embassy_executor::Executor::new());
|
||||
|
||||
executor.start(|spawner| {
|
||||
spawner.spawn(__embassy_main(spawner)).unwrap();
|
||||
|
@ -38,7 +38,7 @@ defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy-time = { version = "0.1.0", path = "../embassy-time" }
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embedded-io = { version = "0.3.0", features = [ "async" ] }
|
||||
|
||||
managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
|
||||
|
@ -2,8 +2,8 @@ use core::cell::UnsafeCell;
|
||||
use core::future::Future;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use embassy_sync::waitqueue::WakerRegistration;
|
||||
use embassy_time::{Instant, Timer};
|
||||
use embassy_util::waitqueue::WakerRegistration;
|
||||
use futures::future::poll_fn;
|
||||
use futures::pin_mut;
|
||||
use heapless::Vec;
|
||||
|
@ -18,7 +18,7 @@ flavors = [
|
||||
|
||||
time = ["dep:embassy-time"]
|
||||
|
||||
defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-util/defmt", "embassy-usb?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
|
||||
defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
|
||||
|
||||
# Enable nightly-only features
|
||||
nightly = ["embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"]
|
||||
@ -66,7 +66,7 @@ _gpio-p1 = []
|
||||
[dependencies]
|
||||
embassy-executor = { version = "0.1.0", path = "../embassy-executor", optional = true }
|
||||
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]}
|
||||
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
|
||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
|
@ -21,7 +21,7 @@ use core::task::Poll;
|
||||
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
|
||||
use embassy_hal_common::ring_buffer::RingBuffer;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::WakerRegistration;
|
||||
use embassy_sync::waitqueue::WakerRegistration;
|
||||
use futures::future::poll_fn;
|
||||
// Re-export SVD variants to allow user to directly set values
|
||||
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
||||
@ -45,8 +45,10 @@ enum TxState {
|
||||
Transmitting(usize),
|
||||
}
|
||||
|
||||
/// A type for storing the state of the UARTE peripheral that can be stored in a static.
|
||||
pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>);
|
||||
impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> {
|
||||
/// Create an instance for storing UARTE peripheral state.
|
||||
pub fn new() -> Self {
|
||||
Self(StateStorage::new())
|
||||
}
|
||||
@ -75,6 +77,12 @@ pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
|
||||
impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
|
||||
|
||||
impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
||||
/// Create a new instance of a BufferedUarte.
|
||||
///
|
||||
/// See the [module documentation](crate::buffered_uarte) for more details about the intended use.
|
||||
///
|
||||
/// The BufferedUarte uses the provided state to store the buffers and peripheral state. The timer and ppi channels are used to 'emulate' idle line detection so that read operations
|
||||
/// can return early if there is no data to receive.
|
||||
pub fn new(
|
||||
state: &'d mut State<'d, U, T>,
|
||||
peri: impl Peripheral<P = U> + 'd,
|
||||
@ -178,6 +186,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Adjust the baud rate to the provided value.
|
||||
pub fn set_baudrate(&mut self, baudrate: Baudrate) {
|
||||
self.inner.with(|state| {
|
||||
let r = U::regs();
|
||||
|
@ -1,3 +1,4 @@
|
||||
//! General purpose input/output for nRF.
|
||||
#![macro_use]
|
||||
|
||||
use core::convert::Infallible;
|
||||
@ -26,8 +27,11 @@ pub enum Port {
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Pull {
|
||||
/// No pull.
|
||||
None,
|
||||
/// Internal pull-up resistor.
|
||||
Up,
|
||||
/// Internal pull-down resistor.
|
||||
Down,
|
||||
}
|
||||
|
||||
@ -37,6 +41,7 @@ pub struct Input<'d, T: Pin> {
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> Input<'d, T> {
|
||||
/// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
|
||||
#[inline]
|
||||
pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self {
|
||||
let mut pin = Flex::new(pin);
|
||||
@ -45,11 +50,13 @@ impl<'d, T: Pin> Input<'d, T> {
|
||||
Self { pin }
|
||||
}
|
||||
|
||||
/// Test if current pin level is high.
|
||||
#[inline]
|
||||
pub fn is_high(&self) -> bool {
|
||||
self.pin.is_high()
|
||||
}
|
||||
|
||||
/// Test if current pin level is low.
|
||||
#[inline]
|
||||
pub fn is_low(&self) -> bool {
|
||||
self.pin.is_low()
|
||||
@ -66,7 +73,9 @@ impl<'d, T: Pin> Input<'d, T> {
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Level {
|
||||
/// Logical low.
|
||||
Low,
|
||||
/// Logical high.
|
||||
High,
|
||||
}
|
||||
|
||||
@ -88,6 +97,7 @@ impl Into<bool> for Level {
|
||||
}
|
||||
}
|
||||
|
||||
/// Drive strength settings for an output pin.
|
||||
// These numbers match DRIVE_A exactly so hopefully the compiler will unify them.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
@ -117,6 +127,7 @@ pub struct Output<'d, T: Pin> {
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> Output<'d, T> {
|
||||
/// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDriver] configuration.
|
||||
#[inline]
|
||||
pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, drive: OutputDrive) -> Self {
|
||||
let mut pin = Flex::new(pin);
|
||||
@ -264,11 +275,13 @@ impl<'d, T: Pin> Flex<'d, T> {
|
||||
self.pin.conf().reset();
|
||||
}
|
||||
|
||||
/// Test if current pin level is high.
|
||||
#[inline]
|
||||
pub fn is_high(&self) -> bool {
|
||||
!self.is_low()
|
||||
}
|
||||
|
||||
/// Test if current pin level is low.
|
||||
#[inline]
|
||||
pub fn is_low(&self) -> bool {
|
||||
self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0
|
||||
@ -374,6 +387,7 @@ pub(crate) mod sealed {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin].
|
||||
pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static {
|
||||
/// Number of the pin within the port (0..31)
|
||||
#[inline]
|
||||
@ -392,6 +406,7 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
|
||||
}
|
||||
}
|
||||
|
||||
/// Peripheral port register value
|
||||
#[inline]
|
||||
fn psel_bits(&self) -> u32 {
|
||||
self.pin_port() as u32
|
||||
@ -406,12 +421,16 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
|
||||
}
|
||||
}
|
||||
|
||||
// Type-erased GPIO pin
|
||||
/// Type-erased GPIO pin
|
||||
pub struct AnyPin {
|
||||
pin_port: u8,
|
||||
}
|
||||
|
||||
impl AnyPin {
|
||||
/// Create an [AnyPin] for a specific pin.
|
||||
///
|
||||
/// # Safety
|
||||
/// - `pin_port` should not in use by another driver.
|
||||
#[inline]
|
||||
pub unsafe fn steal(pin_port: u8) -> Self {
|
||||
Self { pin_port }
|
||||
|
@ -3,7 +3,7 @@ use core::future::Future;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use embassy_hal_common::{impl_peripheral, Peripheral, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Nvmcerature sensor interface.
|
||||
//! Non-Volatile Memory Controller (NVMC) module.
|
||||
|
||||
use core::{ptr, slice};
|
||||
|
||||
@ -10,13 +10,19 @@ use embedded_storage::nor_flash::{
|
||||
use crate::peripherals::NVMC;
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
/// Erase size of NVMC flash in bytes.
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
/// Size of NVMC flash in bytes.
|
||||
pub const FLASH_SIZE: usize = crate::chip::FLASH_SIZE;
|
||||
|
||||
/// Error type for NVMC operations.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Error {
|
||||
/// Opration using a location not in flash.
|
||||
OutOfBounds,
|
||||
/// Unaligned operation or using unaligned buffers.
|
||||
Unaligned,
|
||||
}
|
||||
|
||||
@ -29,11 +35,13 @@ impl NorFlashError for Error {
|
||||
}
|
||||
}
|
||||
|
||||
/// Non-Volatile Memory Controller (NVMC) that implements the `embedded-storage` traits.
|
||||
pub struct Nvmc<'d> {
|
||||
_p: PeripheralRef<'d, NVMC>,
|
||||
}
|
||||
|
||||
impl<'d> Nvmc<'d> {
|
||||
/// Create Nvmc driver.
|
||||
pub fn new(_p: impl Peripheral<P = NVMC> + 'd) -> Self {
|
||||
into_ref!(_p);
|
||||
Self { _p }
|
||||
|
@ -26,6 +26,7 @@ mod dppi;
|
||||
#[cfg(feature = "_ppi")]
|
||||
mod ppi;
|
||||
|
||||
/// An instance of the Programmable peripheral interconnect on nRF devices.
|
||||
pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
|
||||
ch: PeripheralRef<'d, C>,
|
||||
#[cfg(feature = "_dppi")]
|
||||
@ -34,20 +35,32 @@ pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize
|
||||
tasks: [Task; TASK_COUNT],
|
||||
}
|
||||
|
||||
#[cfg(feature = "_dppi")]
|
||||
const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
|
||||
|
||||
/// Represents a task that a peripheral can do.
|
||||
/// When a task is subscribed to a PPI channel it will run when the channel is triggered by
|
||||
/// a published event.
|
||||
///
|
||||
/// The pointer is to a task register
|
||||
/// When a task is subscribed to a PPI channel, it will run when the channel is triggered by
|
||||
/// a published event.
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Task(pub NonNull<u32>);
|
||||
pub struct Task(NonNull<u32>);
|
||||
|
||||
impl Task {
|
||||
/// Create a new `Task` from a task register pointer
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `ptr` must be a pointer to a valid `TASKS_*` register from an nRF peripheral.
|
||||
pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self {
|
||||
Self(ptr)
|
||||
}
|
||||
|
||||
pub(crate) fn from_reg<T>(reg: &T) -> Self {
|
||||
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
|
||||
}
|
||||
|
||||
/// Address of subscription register for this task.
|
||||
#[cfg(feature = "_dppi")]
|
||||
pub fn subscribe_reg(&self) -> *mut u32 {
|
||||
unsafe { self.0.as_ptr().add(REGISTER_DPPI_CONFIG_OFFSET) }
|
||||
}
|
||||
@ -59,16 +72,27 @@ impl Task {
|
||||
unsafe impl Send for Task {}
|
||||
|
||||
/// Represents an event that a peripheral can publish.
|
||||
/// An event can be set to publish on a PPI channel when the event happens.
|
||||
///
|
||||
/// The pointer is to an event register
|
||||
/// An event can be set to publish on a PPI channel when the event happens.
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Event(pub NonNull<u32>);
|
||||
pub struct Event(NonNull<u32>);
|
||||
|
||||
impl Event {
|
||||
/// Create a new `Event` from an event register pointer
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `ptr` must be a pointer to a valid `EVENTS_*` register from an nRF peripheral.
|
||||
pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self {
|
||||
Self(ptr)
|
||||
}
|
||||
|
||||
pub(crate) fn from_reg<T>(reg: &T) -> Self {
|
||||
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
|
||||
}
|
||||
|
||||
/// Address of publish register for this event.
|
||||
#[cfg(feature = "_dppi")]
|
||||
pub fn publish_reg(&self) -> *mut u32 {
|
||||
unsafe { self.0.as_ptr().add(REGISTER_DPPI_CONFIG_OFFSET) }
|
||||
}
|
||||
@ -87,21 +111,29 @@ pub(crate) mod sealed {
|
||||
pub trait Group {}
|
||||
}
|
||||
|
||||
/// Interface for PPI channels.
|
||||
pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized {
|
||||
/// Returns the number of the channel
|
||||
fn number(&self) -> usize;
|
||||
}
|
||||
|
||||
/// Interface for PPI channels that can be configured.
|
||||
pub trait ConfigurableChannel: Channel + Into<AnyConfigurableChannel> {
|
||||
/// Convert into a type erased configurable channel.
|
||||
fn degrade(self) -> AnyConfigurableChannel;
|
||||
}
|
||||
|
||||
/// Interface for PPI channels that cannot be configured.
|
||||
pub trait StaticChannel: Channel + Into<AnyStaticChannel> {
|
||||
/// Convert into a type erased static channel.
|
||||
fn degrade(self) -> AnyStaticChannel;
|
||||
}
|
||||
|
||||
/// Interface for a group of PPI channels.
|
||||
pub trait Group: sealed::Group + Sized {
|
||||
/// Returns the number of the group.
|
||||
fn number(&self) -> usize;
|
||||
/// Convert into a type erased group.
|
||||
fn degrade(self) -> AnyGroup {
|
||||
AnyGroup {
|
||||
number: self.number() as u8,
|
||||
@ -196,6 +228,7 @@ macro_rules! impl_ppi_channel {
|
||||
// ======================
|
||||
// groups
|
||||
|
||||
/// A type erased PPI group.
|
||||
pub struct AnyGroup {
|
||||
number: u8,
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ fn regs() -> &'static pac::ppi::RegisterBlock {
|
||||
|
||||
#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
|
||||
impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> {
|
||||
/// Configure PPI channel to trigger `task`.
|
||||
pub fn new_zero_to_one(ch: impl Peripheral<P = C> + 'd, task: Task) -> Self {
|
||||
into_ref!(ch);
|
||||
|
||||
@ -32,6 +33,7 @@ impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> {
|
||||
}
|
||||
|
||||
impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
|
||||
/// Configure PPI channel to trigger `task` on `event`.
|
||||
pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self {
|
||||
into_ref!(ch);
|
||||
|
||||
@ -46,6 +48,7 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
|
||||
|
||||
#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
|
||||
impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
|
||||
/// Configure PPI channel to trigger `task1` and `task2` on `event`.
|
||||
pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self {
|
||||
into_ref!(ch);
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
|
@ -526,7 +526,7 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -4,7 +4,7 @@ use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use crate::interrupt::InterruptExt;
|
||||
|
@ -4,7 +4,7 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
use pac::{saadc, SAADC};
|
||||
use saadc::ch::config::{GAIN_A, REFSEL_A, RESP_A, TACQ_A};
|
||||
|
@ -363,7 +363,7 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -4,7 +4,7 @@ use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use fixed::types::I30F2;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
|
@ -3,9 +3,9 @@ use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
|
||||
use core::{mem, ptr};
|
||||
|
||||
use critical_section::CriticalSection;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
|
||||
use embassy_time::driver::{AlarmHandle, Driver};
|
||||
use embassy_util::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_util::blocking_mutex::CriticalSectionMutex as Mutex;
|
||||
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::{interrupt, pac};
|
||||
|
@ -5,7 +5,7 @@ use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
@ -40,8 +40,8 @@ macro_rules! impl_timer {
|
||||
fn regs() -> &'static pac::timer0::RegisterBlock {
|
||||
unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) }
|
||||
}
|
||||
fn waker(n: usize) -> &'static ::embassy_util::waitqueue::AtomicWaker {
|
||||
use ::embassy_util::waitqueue::AtomicWaker;
|
||||
fn waker(n: usize) -> &'static ::embassy_sync::waitqueue::AtomicWaker {
|
||||
use ::embassy_sync::waitqueue::AtomicWaker;
|
||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||
static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs];
|
||||
&WAKERS[n]
|
||||
|
@ -13,9 +13,9 @@ use core::task::Poll;
|
||||
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
#[cfg(feature = "time")]
|
||||
use embassy_time::{Duration, Instant};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
|
@ -932,7 +932,7 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> {
|
||||
pub(crate) mod sealed {
|
||||
use core::sync::atomic::AtomicU8;
|
||||
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -7,10 +7,10 @@ use core::task::Poll;
|
||||
|
||||
use cortex_m::peripheral::NVIC;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
pub use embassy_usb;
|
||||
use embassy_usb::driver::{self, EndpointError, Event, Unsupported};
|
||||
use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
use futures::Future;
|
||||
use pac::usbd::RegisterBlock;
|
||||
|
@ -27,10 +27,10 @@ nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "
|
||||
unstable-traits = ["embedded-hal-1"]
|
||||
|
||||
[dependencies]
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
|
||||
embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-1mhz" ] }
|
||||
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]}
|
||||
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]}
|
||||
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
|
||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
atomic-polyfill = "1.0.1"
|
||||
|
@ -5,7 +5,7 @@ use core::task::{Context, Poll};
|
||||
|
||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
||||
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::pac::common::{Reg, RW};
|
||||
use crate::pac::SIO;
|
||||
@ -189,7 +189,7 @@ impl<'d, T: Pin> InputFuture<'d, T> {
|
||||
unsafe {
|
||||
let irq = interrupt::IO_IRQ_BANK0::steal();
|
||||
irq.disable();
|
||||
irq.set_priority(interrupt::Priority::P6);
|
||||
irq.set_priority(interrupt::Priority::P3);
|
||||
|
||||
// Each INTR register is divided into 8 groups, one group for each
|
||||
// pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
|
||||
|
@ -2,9 +2,9 @@ use core::cell::Cell;
|
||||
|
||||
use atomic_polyfill::{AtomicU8, Ordering};
|
||||
use critical_section::CriticalSection;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
use embassy_time::driver::{AlarmHandle, Driver};
|
||||
use embassy_util::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_util::blocking_mutex::Mutex;
|
||||
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::{interrupt, pac};
|
||||
|
@ -31,7 +31,7 @@ flavors = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
|
||||
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
|
||||
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]}
|
||||
@ -72,7 +72,7 @@ quote = "1.0.15"
|
||||
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]}
|
||||
|
||||
[features]
|
||||
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-util/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embedded-io?/defmt", "embassy-usb?/defmt"]
|
||||
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embedded-io?/defmt", "embassy-usb?/defmt"]
|
||||
sdmmc-rs = ["embedded-sdmmc"]
|
||||
net = ["embassy-net" ]
|
||||
memory-x = ["stm32-metapac/memory-x"]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use crate::gpio::sealed::AFType;
|
||||
|
@ -3,7 +3,7 @@
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
use core::task::Waker;
|
||||
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::{TransferOptions, Word, WordSize};
|
||||
use crate::_generated::BDMA_CHANNEL_COUNT;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
use core::task::Waker;
|
||||
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize};
|
||||
use crate::_generated::DMA_CHANNEL_COUNT;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
use core::task::Waker;
|
||||
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::{Request, TransferOptions, Word, WordSize};
|
||||
use crate::_generated::GPDMA_CHANNEL_COUNT;
|
||||
|
@ -7,7 +7,7 @@ use core::task::Waker;
|
||||
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::sealed::{AFType, Pin as __GpioPin};
|
||||
use crate::gpio::{AnyPin, Speed};
|
||||
|
@ -5,7 +5,7 @@ use core::task::Waker;
|
||||
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::sealed::{AFType, Pin as _};
|
||||
use crate::gpio::{AnyPin, Speed};
|
||||
|
@ -4,7 +4,7 @@ use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use embassy_hal_common::impl_peripheral;
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::{AnyPin, Input, Pin as GpioPin};
|
||||
use crate::pac::exti::regs::Lines;
|
||||
|
@ -5,7 +5,7 @@ use atomic_polyfill::{AtomicUsize, Ordering};
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use crate::dma::NoDma;
|
||||
|
@ -3,7 +3,7 @@
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
|
@ -5,7 +5,7 @@ use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR};
|
||||
|
||||
@ -1514,8 +1514,8 @@ foreach_peripheral!(
|
||||
INNER
|
||||
}
|
||||
|
||||
fn state() -> &'static ::embassy_util::waitqueue::AtomicWaker {
|
||||
static WAKER: ::embassy_util::waitqueue::AtomicWaker = ::embassy_util::waitqueue::AtomicWaker::new();
|
||||
fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker {
|
||||
static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new();
|
||||
&WAKER
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::{mem, ptr};
|
||||
|
||||
use atomic_polyfill::{AtomicU32, AtomicU8};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
use embassy_time::driver::{AlarmHandle, Driver};
|
||||
use embassy_time::TICKS_PER_SECOND;
|
||||
use embassy_util::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_util::blocking_mutex::Mutex;
|
||||
use stm32_metapac::timer::regs;
|
||||
|
||||
use crate::interrupt::{CriticalSection, InterruptExt};
|
||||
|
@ -4,7 +4,7 @@ use core::task::Poll;
|
||||
use atomic_polyfill::{compiler_fence, Ordering};
|
||||
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
|
||||
use embassy_hal_common::ring_buffer::RingBuffer;
|
||||
use embassy_util::waitqueue::WakerRegistration;
|
||||
use embassy_sync::waitqueue::WakerRegistration;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use super::*;
|
||||
|
@ -6,10 +6,10 @@ use core::task::Poll;
|
||||
|
||||
use atomic_polyfill::{AtomicBool, AtomicU8};
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_time::{block_for, Duration};
|
||||
use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported};
|
||||
use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
|
||||
use embassy_util::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
use futures::Future;
|
||||
use pac::common::{Reg, RW};
|
||||
|
@ -1,11 +1,11 @@
|
||||
[package]
|
||||
name = "embassy-util"
|
||||
name = "embassy-sync"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-util-v$VERSION/embassy-util/src/"
|
||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-util/src/"
|
||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-sync-v$VERSION/embassy-sync/src/"
|
||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-sync/src/"
|
||||
features = ["nightly"]
|
||||
target = "thumbv7em-none-eabi"
|
||||
|
||||
@ -31,3 +31,4 @@ futures-util = { version = "0.3.17", features = [ "channel" ] }
|
||||
|
||||
# Enable critical-section implementation for std, for tests
|
||||
critical-section = { version = "1.1", features = ["std"] }
|
||||
static_cell = "1.0"
|
12
embassy-sync/README.md
Normal file
12
embassy-sync/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# embassy-sync
|
||||
|
||||
Synchronization primitives and data structures with an async API:
|
||||
|
||||
- [`Channel`](channel::Channel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer.
|
||||
- [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers.
|
||||
- [`Signal`](signal::Signal) - Signalling latest value to a single consumer.
|
||||
- [`Mutex`](mutex::Mutex) - A Mutex for synchronizing state between asynchronous tasks.
|
||||
- [`Pipe`](pipe::Pipe) - Byte stream implementing `embedded_io` traits.
|
||||
- [`WakerRegistration`](waitqueue::WakerRegistration) - Utility to register and wake a `Waker`.
|
||||
- [`AtomicWaker`](waitqueue::AtomicWaker) - A variant of `WakerRegistration` accessible using a non-mut API.
|
||||
- [`MultiWakerRegistration`](waitqueue::MultiWakerRegistration) - Utility registering and waking multiple `Waker`'s.
|
@ -373,8 +373,8 @@ where
|
||||
/// Establish a new bounded channel. For example, to create one with a NoopMutex:
|
||||
///
|
||||
/// ```
|
||||
/// use embassy_util::channel::mpmc::Channel;
|
||||
/// use embassy_util::blocking_mutex::raw::NoopRawMutex;
|
||||
/// use embassy_sync::channel::Channel;
|
||||
/// use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
///
|
||||
/// // Declare a bounded channel of 3 u32s.
|
||||
/// let mut channel = Channel::<NoopRawMutex, u32, 3>::new();
|
||||
@ -471,10 +471,10 @@ mod tests {
|
||||
use futures_executor::ThreadPool;
|
||||
use futures_timer::Delay;
|
||||
use futures_util::task::SpawnExt;
|
||||
use static_cell::StaticCell;
|
||||
|
||||
use super::*;
|
||||
use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
|
||||
use crate::Forever;
|
||||
|
||||
fn capacity<T, const N: usize>(c: &ChannelState<T, N>) -> usize {
|
||||
c.queue.capacity() - c.queue.len()
|
||||
@ -549,8 +549,8 @@ mod tests {
|
||||
async fn receiver_receives_given_try_send_async() {
|
||||
let executor = ThreadPool::new().unwrap();
|
||||
|
||||
static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 3>> = Forever::new();
|
||||
let c = &*CHANNEL.put(Channel::new());
|
||||
static CHANNEL: StaticCell<Channel<CriticalSectionRawMutex, u32, 3>> = StaticCell::new();
|
||||
let c = &*CHANNEL.init(Channel::new());
|
||||
let c2 = c;
|
||||
assert!(executor
|
||||
.spawn(async move {
|
||||
@ -571,8 +571,8 @@ mod tests {
|
||||
async fn senders_sends_wait_until_capacity() {
|
||||
let executor = ThreadPool::new().unwrap();
|
||||
|
||||
static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 1>> = Forever::new();
|
||||
let c = &*CHANNEL.put(Channel::new());
|
||||
static CHANNEL: StaticCell<Channel<CriticalSectionRawMutex, u32, 1>> = StaticCell::new();
|
||||
let c = &*CHANNEL.init(Channel::new());
|
||||
assert!(c.try_send(1).is_ok());
|
||||
|
||||
let c2 = c;
|
228
embassy-sync/src/fmt.rs
Normal file
228
embassy-sync/src/fmt.rs
Normal file
@ -0,0 +1,228 @@
|
||||
#![macro_use]
|
||||
#![allow(unused_macros)]
|
||||
|
||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||
|
||||
macro_rules! assert {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::assert!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::assert!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assert_eq {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::assert_eq!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::assert_eq!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assert_ne {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::assert_ne!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::assert_ne!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! debug_assert {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::debug_assert!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug_assert!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! debug_assert_eq {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::debug_assert_eq!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug_assert_eq!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! debug_assert_ne {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::debug_assert_ne!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug_assert_ne!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! todo {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::todo!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::todo!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! panic {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::panic!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::panic!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! trace {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::trace!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::trace!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! debug {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::debug!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! info {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::info!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::info!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! warn {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::warn!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::warn!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! error {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::error!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::error!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
macro_rules! unwrap {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unwrap!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
macro_rules! unwrap {
|
||||
($arg:expr) => {
|
||||
match $crate::fmt::Try::into_result($arg) {
|
||||
::core::result::Result::Ok(t) => t,
|
||||
::core::result::Result::Err(e) => {
|
||||
::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
($arg:expr, $($msg:expr),+ $(,)? ) => {
|
||||
match $crate::fmt::Try::into_result($arg) {
|
||||
::core::result::Result::Ok(t) => t,
|
||||
::core::result::Result::Err(e) => {
|
||||
::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt-timestamp-uptime")]
|
||||
defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct NoneError;
|
||||
|
||||
pub trait Try {
|
||||
type Ok;
|
||||
type Error;
|
||||
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
impl<T> Try for Option<T> {
|
||||
type Ok = T;
|
||||
type Error = NoneError;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Result<T, NoneError> {
|
||||
self.ok_or(NoneError)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Try for Result<T, E> {
|
||||
type Ok = T;
|
||||
type Error = E;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
|
||||
#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))]
|
||||
#![allow(clippy::new_without_default)]
|
||||
#![doc = include_str!("../../README.md")]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
// This mod MUST go first, so that the others see its macros.
|
||||
@ -14,12 +14,6 @@ pub mod blocking_mutex;
|
||||
pub mod channel;
|
||||
pub mod mutex;
|
||||
pub mod pipe;
|
||||
pub mod pubsub;
|
||||
pub mod signal;
|
||||
pub mod waitqueue;
|
||||
|
||||
mod forever;
|
||||
mod select;
|
||||
mod yield_now;
|
||||
|
||||
pub use forever::*;
|
||||
pub use select::*;
|
||||
pub use yield_now::*;
|
@ -241,8 +241,8 @@ where
|
||||
/// Establish a new bounded pipe. For example, to create one with a NoopMutex:
|
||||
///
|
||||
/// ```
|
||||
/// use embassy_util::pipe::Pipe;
|
||||
/// use embassy_util::blocking_mutex::raw::NoopRawMutex;
|
||||
/// use embassy_sync::pipe::Pipe;
|
||||
/// use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
///
|
||||
/// // Declare a bounded pipe, with a buffer of 256 bytes.
|
||||
/// let mut pipe = Pipe::<NoopRawMutex, 256>::new();
|
||||
@ -461,10 +461,10 @@ mod io_impls {
|
||||
mod tests {
|
||||
use futures_executor::ThreadPool;
|
||||
use futures_util::task::SpawnExt;
|
||||
use static_cell::StaticCell;
|
||||
|
||||
use super::*;
|
||||
use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
|
||||
use crate::Forever;
|
||||
|
||||
fn capacity<const N: usize>(c: &PipeState<N>) -> usize {
|
||||
N - c.buffer.len()
|
||||
@ -528,8 +528,8 @@ mod tests {
|
||||
async fn receiver_receives_given_try_write_async() {
|
||||
let executor = ThreadPool::new().unwrap();
|
||||
|
||||
static CHANNEL: Forever<Pipe<CriticalSectionRawMutex, 3>> = Forever::new();
|
||||
let c = &*CHANNEL.put(Pipe::new());
|
||||
static CHANNEL: StaticCell<Pipe<CriticalSectionRawMutex, 3>> = StaticCell::new();
|
||||
let c = &*CHANNEL.init(Pipe::new());
|
||||
let c2 = c;
|
||||
let f = async move {
|
||||
assert_eq!(c2.try_write(&[42]), Ok(1));
|
@ -33,9 +33,9 @@ pub use subscriber::{DynSubscriber, Subscriber};
|
||||
/// ## Example
|
||||
///
|
||||
/// ```
|
||||
/// # use embassy_util::blocking_mutex::raw::NoopRawMutex;
|
||||
/// # use embassy_util::channel::pubsub::WaitResult;
|
||||
/// # use embassy_util::channel::pubsub::PubSubChannel;
|
||||
/// # use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
/// # use embassy_sync::pubsub::WaitResult;
|
||||
/// # use embassy_sync::pubsub::PubSubChannel;
|
||||
/// # use futures_executor::block_on;
|
||||
/// # let test = async {
|
||||
/// // Create the channel. This can be static as well
|
@ -6,7 +6,7 @@ use core::task::{Context, Poll, Waker};
|
||||
|
||||
/// Single-slot signaling primitive.
|
||||
///
|
||||
/// This is similar to a [`Channel`](crate::channel::mpmc::Channel) with a buffer size of 1, except
|
||||
/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except
|
||||
/// "sending" to it (calling [`Signal::signal`]) when full will overwrite the previous value instead
|
||||
/// of waiting for the receiver to pop the previous value.
|
||||
///
|
||||
@ -14,12 +14,12 @@ use core::task::{Context, Poll, Waker};
|
||||
/// the latest data, and therefore it's fine to "lose" messages. This is often the case for "state"
|
||||
/// updates.
|
||||
///
|
||||
/// For more advanced use cases, you might want to use [`Channel`](crate::channel::mpmc::Channel) instead.
|
||||
/// For more advanced use cases, you might want to use [`Channel`](crate::channel::Channel) instead.
|
||||
///
|
||||
/// Signals are generally declared as `static`s and then borrowed as required.
|
||||
///
|
||||
/// ```
|
||||
/// use embassy_util::channel::signal::Signal;
|
||||
/// use embassy_sync::signal::Signal;
|
||||
///
|
||||
/// enum SomeCommand {
|
||||
/// On,
|
@ -49,6 +49,6 @@ critical-section = "1.1"
|
||||
cfg-if = "1.0.0"
|
||||
|
||||
# WASM dependencies
|
||||
wasm-bindgen = { version = "0.2.76", features = ["nightly"], optional = true }
|
||||
wasm-bindgen = { version = "0.2.81", optional = true }
|
||||
js-sys = { version = "0.3", optional = true }
|
||||
wasm-timer = { version = "0.2.5", optional = true }
|
43
embassy-time/README.md
Normal file
43
embassy-time/README.md
Normal file
@ -0,0 +1,43 @@
|
||||
# embassy-time
|
||||
|
||||
Timekeeping, delays and timeouts.
|
||||
|
||||
Timekeeping is done with elapsed time since system boot. Time is represented in
|
||||
ticks, where the tick rate is defined by the current driver, usually to match
|
||||
the tick rate of the hardware.
|
||||
|
||||
Tick counts are 64 bits. At the highest supported tick rate of 1Mhz this supports
|
||||
representing time spans of up to ~584558 years, which is big enough for all practical
|
||||
purposes and allows not having to worry about overflows.
|
||||
|
||||
[`Instant`] represents a given instant of time (relative to system boot), and [`Duration`]
|
||||
represents the duration of a span of time. They implement the math operations you'd expect,
|
||||
like addition and substraction.
|
||||
|
||||
# Delays and timeouts
|
||||
|
||||
[`Timer`] allows performing async delays. [`Ticker`] allows periodic delays without drifting over time.
|
||||
|
||||
An implementation of the `embedded-hal` delay traits is provided by [`Delay`], for compatibility
|
||||
with libraries from the ecosystem.
|
||||
|
||||
# Wall-clock time
|
||||
|
||||
The `time` module deals exclusively with a monotonically increasing tick count.
|
||||
Therefore it has no direct support for wall-clock time ("real life" datetimes
|
||||
like `2021-08-24 13:33:21`).
|
||||
|
||||
If persistence across reboots is not needed, support can be built on top of
|
||||
`embassy_time` by storing the offset between "seconds elapsed since boot"
|
||||
and "seconds since unix epoch".
|
||||
|
||||
# Time driver
|
||||
|
||||
The `time` module is backed by a global "time driver" specified at build time.
|
||||
Only one driver can be active in a program.
|
||||
|
||||
All methods and structs transparently call into the active driver. This makes it
|
||||
possible for libraries to use `embassy_time` in a driver-agnostic way without
|
||||
requiring generic parameters.
|
||||
|
||||
For more details, check the [`driver`] module.
|
@ -6,7 +6,7 @@
|
||||
//!
|
||||
//! - Define a struct `MyDriver`
|
||||
//! - Implement [`Driver`] for it
|
||||
//! - Register it as the global driver with [`time_driver_impl`].
|
||||
//! - Register it as the global driver with [`time_driver_impl`](crate::time_driver_impl).
|
||||
//! - Enable the Cargo features `embassy-executor/time` and one of `embassy-time/tick-*` corresponding to the
|
||||
//! tick rate of your driver.
|
||||
//!
|
||||
|
@ -1,50 +1,9 @@
|
||||
#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
|
||||
#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![allow(clippy::new_without_default)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
//! Timekeeping, delays and timeouts.
|
||||
//!
|
||||
//! Timekeeping is done with elapsed time since system boot. Time is represented in
|
||||
//! ticks, where the tick rate is defined by the current driver, usually to match
|
||||
//! the tick rate of the hardware.
|
||||
//!
|
||||
//! Tick counts are 64 bits. At the highest supported tick rate of 1Mhz this supports
|
||||
//! representing time spans of up to ~584558 years, which is big enough for all practical
|
||||
//! purposes and allows not having to worry about overflows.
|
||||
//!
|
||||
//! [`Instant`] represents a given instant of time (relative to system boot), and [`Duration`]
|
||||
//! represents the duration of a span of time. They implement the math operations you'd expect,
|
||||
//! like addition and substraction.
|
||||
//!
|
||||
//! # Delays and timeouts
|
||||
//!
|
||||
//! [`Timer`] allows performing async delays. [`Ticker`] allows periodic delays without drifting over time.
|
||||
//!
|
||||
//! An implementation of the `embedded-hal` delay traits is provided by [`Delay`], for compatibility
|
||||
//! with libraries from the ecosystem.
|
||||
//!
|
||||
//! # Wall-clock time
|
||||
//!
|
||||
//! The `time` module deals exclusively with a monotonically increasing tick count.
|
||||
//! Therefore it has no direct support for wall-clock time ("real life" datetimes
|
||||
//! like `2021-08-24 13:33:21`).
|
||||
//!
|
||||
//! If persistence across reboots is not needed, support can be built on top of
|
||||
//! `embassy_time` by storing the offset between "seconds elapsed since boot"
|
||||
//! and "seconds since unix epoch".
|
||||
//!
|
||||
//! # Time driver
|
||||
//!
|
||||
//! The `time` module is backed by a global "time driver" specified at build time.
|
||||
//! Only one driver can be active in a program.
|
||||
//!
|
||||
//! All methods and structs transparently call into the active driver. This makes it
|
||||
//! possible for libraries to use `embassy_time` in a driver-agnostic way without
|
||||
//! requiring generic parameters.
|
||||
//!
|
||||
//! For more details, check the [`driver`] module.
|
||||
|
||||
// This mod MUST go first, so that the others see its macros.
|
||||
pub(crate) mod fmt;
|
||||
|
||||
|
@ -14,7 +14,7 @@ default = ["usbd-hid"]
|
||||
usbd-hid = ["dep:usbd-hid", "ssmarshal"]
|
||||
|
||||
[dependencies]
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
@ -10,7 +10,7 @@ features = ["defmt"]
|
||||
target = "thumbv7em-none-eabi"
|
||||
|
||||
[dependencies]
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
@ -10,7 +10,7 @@ features = ["defmt"]
|
||||
target = "thumbv7em-none-eabi"
|
||||
|
||||
[dependencies]
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
@ -9,11 +9,11 @@ use core::cell::Cell;
|
||||
use core::mem::{self, MaybeUninit};
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use embassy_sync::blocking_mutex::CriticalSectionMutex;
|
||||
use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
|
||||
use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||
use embassy_usb::types::*;
|
||||
use embassy_usb::Builder;
|
||||
use embassy_util::blocking_mutex::CriticalSectionMutex;
|
||||
|
||||
/// This should be used as `device_class` when building the `UsbDevice`.
|
||||
pub const USB_CLASS_CDC: u8 = 0x02;
|
||||
|
@ -10,7 +10,7 @@ features = ["defmt"]
|
||||
target = "thumbv7em-none-eabi"
|
||||
|
||||
[dependencies]
|
||||
embassy-util = { version = "0.1.0", path = "../embassy-util" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
@ -10,6 +10,7 @@ use crate::{Interface, STRING_INDEX_CUSTOM_START};
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
/// Configuration used when creating [UsbDevice].
|
||||
pub struct Config<'a> {
|
||||
pub(crate) vendor_id: u16,
|
||||
pub(crate) product_id: u16,
|
||||
@ -96,6 +97,7 @@ pub struct Config<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Config<'a> {
|
||||
/// Create default configuration with the provided vid and pid values.
|
||||
pub fn new(vid: u16, pid: u16) -> Self {
|
||||
Self {
|
||||
device_class: 0x00,
|
||||
|
@ -1,3 +1,4 @@
|
||||
//! USB control data types.
|
||||
use core::mem;
|
||||
|
||||
use super::types::*;
|
||||
@ -8,7 +9,7 @@ use super::types::*;
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum RequestType {
|
||||
/// Request is a USB standard request. Usually handled by
|
||||
/// [`UsbDevice`](crate::device::UsbDevice).
|
||||
/// [`UsbDevice`](crate::UsbDevice).
|
||||
Standard = 0,
|
||||
/// Request is intended for a USB class.
|
||||
Class = 1,
|
||||
|
@ -12,7 +12,7 @@ pub trait Driver<'a> {
|
||||
|
||||
/// Allocates an endpoint and specified endpoint parameters. This method is called by the device
|
||||
/// and class implementations to allocate endpoints, and can only be called before
|
||||
/// [`start`](UsbBus::start) is called.
|
||||
/// [`start`](Self::start) is called.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@ -95,7 +95,7 @@ pub trait Bus {
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * [`Unsupported`](crate::UsbError::Unsupported) - This UsbBus implementation doesn't support
|
||||
/// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support
|
||||
/// simulating a disconnect or it has not been enabled at creation time.
|
||||
fn force_reset(&mut self) -> Result<(), Unsupported> {
|
||||
Err(Unsupported)
|
||||
@ -105,7 +105,7 @@ pub trait Bus {
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * [`Unsupported`](crate::UsbError::Unsupported) - This UsbBus implementation doesn't support
|
||||
/// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support
|
||||
/// remote wakeup or it has not been enabled at creation time.
|
||||
fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_>;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ mod descriptor_reader;
|
||||
pub mod driver;
|
||||
pub mod types;
|
||||
|
||||
use embassy_util::{select, Either};
|
||||
use embassy_futures::{select, Either};
|
||||
use heapless::Vec;
|
||||
|
||||
pub use self::builder::{Builder, Config};
|
||||
|
@ -1,5 +0,0 @@
|
||||
//! Async channels
|
||||
|
||||
pub mod mpmc;
|
||||
pub mod pubsub;
|
||||
pub mod signal;
|
@ -1,95 +0,0 @@
|
||||
use core::cell::UnsafeCell;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use atomic_polyfill::{AtomicBool, Ordering};
|
||||
|
||||
/// Type with static lifetime that may be written to once at runtime.
|
||||
///
|
||||
/// This may be used to initialize static objects at runtime, typically in the init routine.
|
||||
/// This is useful for objects such as Embassy's RTC, which cannot be initialized in a const
|
||||
/// context.
|
||||
///
|
||||
/// Note: IF a global mutable variable is desired, use a CriticalSectionMutex or ThreadModeMutex instead.
|
||||
///
|
||||
/// ```
|
||||
/// use embassy_util::Forever;
|
||||
/// // Using an integer for the sake of keeping this example self-contained,
|
||||
/// // see https://github.com/embassy-rs/embassy/wiki/Getting-Started for a more "proper" example.
|
||||
/// static SOME_INT: Forever<u32> =Forever::new();
|
||||
///
|
||||
/// // put returns a mutable pointer to the object stored in the forever, which may then be passed
|
||||
/// // around.
|
||||
/// let mut x = SOME_INT.put(42);
|
||||
/// assert_eq!(*x, 42);
|
||||
/// ```
|
||||
pub struct Forever<T> {
|
||||
used: AtomicBool,
|
||||
t: UnsafeCell<MaybeUninit<T>>,
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for Forever<T> {}
|
||||
unsafe impl<T> Sync for Forever<T> {}
|
||||
|
||||
impl<T> Forever<T> {
|
||||
/// Create a new `Forever`.
|
||||
#[inline(always)]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
used: AtomicBool::new(false),
|
||||
t: UnsafeCell::new(MaybeUninit::uninit()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Store a value in this `Forever`, returning a mutable reference to it.
|
||||
///
|
||||
/// Using this method, the compiler usually constructs `val` in the stack and then moves
|
||||
/// it into the `Forever`. If `T` is big, this is likely to cause stack overflows.
|
||||
/// Considering using [`Signal::put_with`] instead, which will construct it in-place inside the `Forever`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this `Forever` already has a value stored in it.
|
||||
#[inline(always)]
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub fn put(&'static self, val: T) -> &'static mut T {
|
||||
self.put_with(|| val)
|
||||
}
|
||||
|
||||
/// Store the closure return value in this `Forever`, returning a mutable reference to it.
|
||||
///
|
||||
/// The advantage over [`Forever::put`] is that this method allows the closure to construct
|
||||
/// the `T` value in-place directly inside the `Forever`, saving stack space.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this `Forever` already has a value stored in it.
|
||||
#[inline(always)]
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub fn put_with(&'static self, val: impl FnOnce() -> T) -> &'static mut T {
|
||||
if self
|
||||
.used
|
||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
panic!("Forever.put() called multiple times");
|
||||
}
|
||||
|
||||
let p: &'static mut MaybeUninit<T> = unsafe { &mut *self.t.get() };
|
||||
p.write(val())
|
||||
}
|
||||
|
||||
/// Unsafely get a mutable reference to the contents of this Forever.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is undefined behavior if:
|
||||
///
|
||||
/// - The `Forever` has not been initialized yet (with `put' or `put_with`), or
|
||||
/// - A reference to the contents (mutable or not) already exists.
|
||||
#[inline(always)]
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub unsafe fn steal(&self) -> &mut T {
|
||||
let p: &mut MaybeUninit<T> = &mut *self.t.get();
|
||||
p.assume_init_mut()
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user