Merge remote-tracking branch 'origin/master' into nrf-pdm

This commit is contained in:
Quentin Smith 2022-08-23 23:01:51 -04:00
commit 2900ab79e7
164 changed files with 923 additions and 434 deletions

View File

@ -69,4 +69,4 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Test
run: cd embassy-util && cargo test
run: cd embassy-sync && cargo test

View File

@ -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",

View File

@ -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"

View File

@ -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" }

View File

@ -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" }

View File

@ -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"}

View File

@ -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 {

View File

@ -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 }

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 }

View File

@ -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)
///

View File

@ -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)
///

View File

@ -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)
///

View File

@ -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)) {

View File

@ -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)
///

View File

@ -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;
}

View File

@ -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}

View 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 }

View 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.

View 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::*;

View File

@ -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" }

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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" ] }

View File

@ -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;

View File

@ -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" }

View File

@ -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();

View File

@ -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 }

View File

@ -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 _;

View File

@ -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 }

View File

@ -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,
}

View File

@ -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);

View File

@ -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 _;

View File

@ -526,7 +526,7 @@ cfg_if::cfg_if! {
}
pub(crate) mod sealed {
use embassy_util::waitqueue::AtomicWaker;
use embassy_sync::waitqueue::AtomicWaker;
use super::*;

View File

@ -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;

View File

@ -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};

View File

@ -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::*;

View File

@ -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;

View File

@ -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};

View File

@ -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]

View File

@ -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};

View File

@ -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::*;

View File

@ -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;

View File

@ -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"

View File

@ -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,

View File

@ -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};

View File

@ -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"]

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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};

View File

@ -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};

View File

@ -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;

View File

@ -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;

View File

@ -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};

View File

@ -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
}
}

View File

@ -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};

View File

@ -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::*;

View File

@ -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};

View File

@ -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
View 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.

View File

@ -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
View 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
}
}

View File

@ -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::*;

View File

@ -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));

View File

@ -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

View File

@ -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,

View File

@ -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
View 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.

View File

@ -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.
//!

View File

@ -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;

View File

@ -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 }

View File

@ -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 }

View File

@ -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 }

View File

@ -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;

View File

@ -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 }

View File

@ -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,

View File

@ -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,

View File

@ -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<'_>;
}

View File

@ -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};

View File

@ -1,5 +0,0 @@
//! Async channels
pub mod mpmc;
pub mod pubsub;
pub mod signal;

View File

@ -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