From ead987245d083b7e6be7158ea3fb63c8a47bf304 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 11 Sep 2021 01:53:53 +0200 Subject: [PATCH] embassy: Refactor module structure to remove kitchen-sink `util`. --- .vscode/settings.json | 3 +- .../src/drop.rs | 23 +++ embassy-hal-common/src/lib.rs | 1 + embassy-hal-common/src/usb/usb_serial.rs | 2 +- embassy-net/src/stack.rs | 4 +- embassy-nrf/src/buffered_uarte.rs | 3 +- embassy-nrf/src/gpiote.rs | 2 +- embassy-nrf/src/qspi.rs | 5 +- embassy-nrf/src/rng.rs | 4 +- embassy-nrf/src/saadc.rs | 3 +- embassy-nrf/src/spim.rs | 4 +- embassy-nrf/src/time_driver.rs | 2 +- embassy-nrf/src/timer.rs | 8 +- embassy-nrf/src/twim.rs | 3 +- embassy-nrf/src/uarte.rs | 5 +- embassy-rp/src/timer.rs | 2 +- embassy-stm32/src/dma/bdma.rs | 3 +- embassy-stm32/src/dma/dma.rs | 3 +- embassy-stm32/src/eth/v2/mod.rs | 3 +- embassy-stm32/src/exti.rs | 3 +- embassy-stm32/src/i2c/v2.rs | 4 +- embassy-stm32/src/rng.rs | 3 +- embassy-stm32/src/sdmmc/v2.rs | 8 +- embassy-stm32/src/usart/v2.rs | 3 +- .../{util/mutex.rs => blocking_mutex/mod.rs} | 2 + embassy/src/channel/mod.rs | 4 + embassy/src/{util => channel}/mpsc.rs | 15 +- embassy/src/channel/signal.rs | 73 ++++++++ embassy/src/lib.rs | 4 + embassy/src/util/mod.rs | 16 +- embassy/src/util/on_drop.rs | 24 --- embassy/src/util/signal.rs | 171 ------------------ embassy/src/waitqueue/mod.rs | 5 + embassy/src/{util => waitqueue}/waker.rs | 3 +- .../src/{util => waitqueue}/waker_agnostic.rs | 2 +- examples/nrf/src/bin/mpsc.rs | 5 +- examples/stm32wl55/src/bin/subghz.rs | 32 ++-- 37 files changed, 194 insertions(+), 266 deletions(-) rename embassy/src/util/drop_bomb.rs => embassy-hal-common/src/drop.rs (61%) rename embassy/src/{util/mutex.rs => blocking_mutex/mod.rs} (99%) create mode 100644 embassy/src/channel/mod.rs rename embassy/src/{util => channel}/mpsc.rs (98%) create mode 100644 embassy/src/channel/signal.rs delete mode 100644 embassy/src/util/on_drop.rs delete mode 100644 embassy/src/util/signal.rs create mode 100644 embassy/src/waitqueue/mod.rs rename embassy/src/{util => waitqueue}/waker.rs (99%) rename embassy/src/{util => waitqueue}/waker_agnostic.rs (97%) diff --git a/.vscode/settings.json b/.vscode/settings.json index ed01f755..a5a65663 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,11 +6,12 @@ "rust-analyzer.checkOnSave.allTargets": false, "rust-analyzer.cargo.noDefaultFeatures": true, "rust-analyzer.checkOnSave.noDefaultFeatures": true, - //"rust-analyzer.cargo.target": "thumbv7em-none-eabi", + "rust-analyzer.cargo.target": "thumbv7em-none-eabi", "rust-analyzer.cargo.features": [ // These are needed to prevent embassy-net from failing to build "embassy-net/medium-ethernet", "embassy-net/tcp", + "embassy-net/pool-16", ], "rust-analyzer.procMacro.enable": true, "rust-analyzer.cargo.runBuildScripts": true, diff --git a/embassy/src/util/drop_bomb.rs b/embassy-hal-common/src/drop.rs similarity index 61% rename from embassy/src/util/drop_bomb.rs rename to embassy-hal-common/src/drop.rs index efb36a97..74a484de 100644 --- a/embassy/src/util/drop_bomb.rs +++ b/embassy-hal-common/src/drop.rs @@ -1,4 +1,27 @@ use core::mem; +use core::mem::MaybeUninit; + +pub struct OnDrop { + f: MaybeUninit, +} + +impl OnDrop { + pub fn new(f: F) -> Self { + Self { + f: MaybeUninit::new(f), + } + } + + pub fn defuse(self) { + mem::forget(self) + } +} + +impl Drop for OnDrop { + fn drop(&mut self) { + unsafe { self.f.as_ptr().read()() } + } +} /// An explosive ordinance that panics if it is improperly disposed of. /// diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs index ea20747e..01e2d3ae 100644 --- a/embassy-hal-common/src/lib.rs +++ b/embassy-hal-common/src/lib.rs @@ -3,6 +3,7 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +pub mod drop; pub mod interrupt; mod macros; pub mod peripheral; diff --git a/embassy-hal-common/src/usb/usb_serial.rs b/embassy-hal-common/src/usb/usb_serial.rs index 8b27152b..ca43a4d7 100644 --- a/embassy-hal-common/src/usb/usb_serial.rs +++ b/embassy-hal-common/src/usb/usb_serial.rs @@ -4,7 +4,7 @@ use core::pin::Pin; use core::task::{Context, Poll}; use embassy::io::{self, AsyncBufRead, AsyncWrite}; -use embassy::util::WakerRegistration; +use embassy::waitqueue::WakerRegistration; use usb_device::bus::UsbBus; use usb_device::class_prelude::*; use usb_device::UsbError; diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs index 5f871bd1..f26808cd 100644 --- a/embassy-net/src/stack.rs +++ b/embassy-net/src/stack.rs @@ -2,9 +2,9 @@ use core::cell::RefCell; use core::future::Future; use core::task::Context; use core::task::Poll; +use embassy::blocking_mutex::ThreadModeMutex; use embassy::time::{Instant, Timer}; -use embassy::util::ThreadModeMutex; -use embassy::util::WakerRegistration; +use embassy::waitqueue::WakerRegistration; use futures::pin_mut; use smoltcp::iface::InterfaceBuilder; #[cfg(feature = "medium-ethernet")] diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 90ce4958..cd08875c 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -6,7 +6,8 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; use embassy::io::{AsyncBufRead, AsyncWrite, Result}; -use embassy::util::{Unborrow, WakerRegistration}; +use embassy::util::Unborrow; +use embassy::waitqueue::WakerRegistration; use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; use embassy_hal_common::ring_buffer::RingBuffer; use embassy_hal_common::{low_power_wait_until, unborrow}; diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 847b2fbf..001ee7fb 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::task::{Context, Poll}; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::traits::gpio::{WaitForAnyEdge, WaitForHigh, WaitForLow}; -use embassy::util::AtomicWaker; +use embassy::waitqueue::AtomicWaker; use embassy_hal_common::unsafe_impl_unborrow; use embedded_hal::digital::v2::{InputPin, StatefulOutputPin}; use futures::future::poll_fn; diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 28becfd5..e8709425 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -6,7 +6,8 @@ use core::ptr; use core::task::Poll; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::traits::flash::{Error, Flash}; -use embassy::util::{AtomicWaker, DropBomb, Unborrow}; +use embassy::util::Unborrow; +use embassy_hal_common::drop::DropBomb; use embassy_hal_common::unborrow; use futures::future::poll_fn; @@ -397,6 +398,8 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { } pub(crate) mod sealed { + use embassy::waitqueue::AtomicWaker; + use super::*; pub struct State { diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 6cdcccf3..20d033a1 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -8,9 +8,9 @@ use core::task::Poll; use embassy::interrupt::InterruptExt; use embassy::traits; -use embassy::util::AtomicWaker; -use embassy::util::OnDrop; use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; +use embassy_hal_common::drop::OnDrop; use embassy_hal_common::unborrow; use futures::future::poll_fn; use rand_core::RngCore; diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index bc7f3471..e909e7d5 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -3,7 +3,8 @@ use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::interrupt::InterruptExt; -use embassy::util::{AtomicWaker, Unborrow}; +use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; use embassy_hal_common::unborrow; use futures::future::poll_fn; diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 9a7fb4f6..e88fb460 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -6,7 +6,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::interrupt::InterruptExt; use embassy::traits; -use embassy::util::{AtomicWaker, Unborrow}; +use embassy::util::Unborrow; use embassy_hal_common::unborrow; use futures::future::poll_fn; use traits::spi::{FullDuplex, Read, Spi, Write}; @@ -359,6 +359,8 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spim<'d, T> { } pub(crate) mod sealed { + use embassy::waitqueue::AtomicWaker; + use super::*; pub struct State { diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index f93ebb54..19356c2d 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -2,9 +2,9 @@ use core::cell::Cell; use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use core::{mem, ptr}; use critical_section::CriticalSection; +use embassy::blocking_mutex::CriticalSectionMutex as Mutex; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::time::driver::{AlarmHandle, Driver}; -use embassy::util::CriticalSectionMutex as Mutex; use crate::interrupt; use crate::pac; diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 638fd822..5690ff0d 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -5,8 +5,9 @@ use core::task::Poll; use embassy::interrupt::Interrupt; use embassy::interrupt::InterruptExt; -use embassy::util::OnDrop; use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; +use embassy_hal_common::drop::OnDrop; use embassy_hal_common::unborrow; use futures::future::poll_fn; @@ -15,7 +16,6 @@ use crate::ppi::Event; use crate::ppi::Task; pub(crate) mod sealed { - use embassy::util::AtomicWaker; use super::*; @@ -43,8 +43,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::AtomicWaker { - use ::embassy::util::AtomicWaker; + fn waker(n: usize) -> &'static ::embassy::waitqueue::AtomicWaker { + use ::embassy::waitqueue::AtomicWaker; const NEW_AW: AtomicWaker = AtomicWaker::new(); static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs]; &WAKERS[n] diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index ac263bad..8173f66b 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -12,7 +12,8 @@ use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; use core::task::Poll; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::traits; -use embassy::util::{AtomicWaker, Unborrow}; +use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; use embassy_hal_common::unborrow; use futures::future::poll_fn; use traits::i2c::I2c; diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index a6909be6..32042606 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -8,7 +8,8 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::interrupt::InterruptExt; use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write}; -use embassy::util::{AtomicWaker, OnDrop, Unborrow}; +use embassy::util::Unborrow; +use embassy_hal_common::drop::OnDrop; use embassy_hal_common::unborrow; use futures::future::poll_fn; @@ -439,6 +440,8 @@ impl<'d, U: Instance, T: TimerInstance> Write for UarteWithIdle<'d, U, T> { } pub(crate) mod sealed { + use embassy::waitqueue::AtomicWaker; + use super::*; pub struct State { diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs index ed265c47..b3c047ca 100644 --- a/embassy-rp/src/timer.rs +++ b/embassy-rp/src/timer.rs @@ -1,9 +1,9 @@ use atomic_polyfill::{AtomicU8, Ordering}; use core::cell::Cell; use critical_section::CriticalSection; +use embassy::blocking_mutex::CriticalSectionMutex as Mutex; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::time::driver::{AlarmHandle, Driver}; -use embassy::util::CriticalSectionMutex as Mutex; use crate::{interrupt, pac}; diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index fbd753a7..35c0b3ee 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -5,7 +5,8 @@ use core::sync::atomic::{fence, Ordering}; use core::task::Poll; use embassy::interrupt::{Interrupt, InterruptExt}; -use embassy::util::{AtomicWaker, OnDrop}; +use embassy::waitqueue::AtomicWaker; +use embassy_hal_common::drop::OnDrop; use futures::future::poll_fn; use crate::dma::{Channel, Request}; diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index bce9656d..ec5ac98a 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -3,7 +3,8 @@ use core::sync::atomic::{fence, Ordering}; use core::task::Poll; use embassy::interrupt::{Interrupt, InterruptExt}; -use embassy::util::{AtomicWaker, OnDrop}; +use embassy::waitqueue::AtomicWaker; +use embassy_hal_common::drop::OnDrop; use futures::future::poll_fn; use crate::interrupt; diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 42eb0680..ff734f78 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -2,7 +2,8 @@ use core::marker::PhantomData; use core::sync::atomic::{fence, Ordering}; use core::task::Waker; -use embassy::util::{AtomicWaker, Unborrow}; +use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; use embassy_hal_common::unborrow; use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU}; diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 8e4989a3..6d3de3a1 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -4,7 +4,8 @@ use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; use embassy::traits::gpio::{WaitForAnyEdge, WaitForFallingEdge, WaitForRisingEdge}; -use embassy::util::{AtomicWaker, Unborrow}; +use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; use embassy_hal_common::unsafe_impl_unborrow; use embedded_hal::digital::v2::InputPin; diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index fc4f52cf..5e9e2439 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -4,7 +4,9 @@ use core::task::Poll; use atomic_polyfill::{AtomicUsize, Ordering}; use embassy::interrupt::InterruptExt; -use embassy::util::{AtomicWaker, OnDrop, Unborrow}; +use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; +use embassy_hal_common::drop::OnDrop; use embassy_hal_common::unborrow; use embedded_hal::blocking::i2c::Read; use embedded_hal::blocking::i2c::Write; diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 0afba3ba..5655ed96 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -3,7 +3,8 @@ use core::future::Future; use core::task::Poll; use embassy::traits; -use embassy::util::{AtomicWaker, Unborrow}; +use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; use embassy_hal_common::unborrow; use futures::future::poll_fn; use rand_core::{CryptoRng, RngCore}; diff --git a/embassy-stm32/src/sdmmc/v2.rs b/embassy-stm32/src/sdmmc/v2.rs index aa1d68ae..6032c2bb 100644 --- a/embassy-stm32/src/sdmmc/v2.rs +++ b/embassy-stm32/src/sdmmc/v2.rs @@ -5,7 +5,9 @@ use core::marker::PhantomData; use core::task::Poll; use embassy::interrupt::InterruptExt; -use embassy::util::{AtomicWaker, OnDrop, Unborrow}; +use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; +use embassy_hal_common::drop::OnDrop; use embassy_hal_common::unborrow; use futures::future::poll_fn; use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; @@ -1479,8 +1481,8 @@ crate::pac::peripherals!( INNER } - fn state() -> &'static ::embassy::util::AtomicWaker { - static WAKER: ::embassy::util::AtomicWaker = ::embassy::util::AtomicWaker::new(); + fn state() -> &'static ::embassy::waitqueue::AtomicWaker { + static WAKER: ::embassy::waitqueue::AtomicWaker = ::embassy::waitqueue::AtomicWaker::new(); &WAKER } } diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index 92c0cbc2..fc303640 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs @@ -4,7 +4,8 @@ use core::marker::PhantomData; use core::pin::Pin; use core::task::Context; use core::task::Poll; -use embassy::util::{Unborrow, WakerRegistration}; +use embassy::util::Unborrow; +use embassy::waitqueue::WakerRegistration; use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; use embassy_hal_common::ring_buffer::RingBuffer; use embassy_hal_common::unborrow; diff --git a/embassy/src/util/mutex.rs b/embassy/src/blocking_mutex/mod.rs similarity index 99% rename from embassy/src/util/mutex.rs rename to embassy/src/blocking_mutex/mod.rs index 9a00a409..d112d2ed 100644 --- a/embassy/src/util/mutex.rs +++ b/embassy/src/blocking_mutex/mod.rs @@ -1,3 +1,5 @@ +//! Blocking mutex (not async) + use core::cell::UnsafeCell; use critical_section::CriticalSection; diff --git a/embassy/src/channel/mod.rs b/embassy/src/channel/mod.rs new file mode 100644 index 00000000..9e8c67ee --- /dev/null +++ b/embassy/src/channel/mod.rs @@ -0,0 +1,4 @@ +//! Async channels + +pub mod mpsc; +pub mod signal; diff --git a/embassy/src/util/mpsc.rs b/embassy/src/channel/mpsc.rs similarity index 98% rename from embassy/src/util/mpsc.rs rename to embassy/src/channel/mpsc.rs index a0f884ec..b20d48a9 100644 --- a/embassy/src/util/mpsc.rs +++ b/embassy/src/channel/mpsc.rs @@ -49,11 +49,8 @@ use core::task::Waker; use futures::Future; -use super::CriticalSectionMutex; -use super::Mutex; -use super::NoopMutex; -use super::ThreadModeMutex; -use super::WakerRegistration; +use crate::blocking_mutex::{CriticalSectionMutex, Mutex, NoopMutex, ThreadModeMutex}; +use crate::waitqueue::WakerRegistration; /// Send values to the associated `Receiver`. /// @@ -108,8 +105,8 @@ unsafe impl<'ch, M, T, const N: usize> Sync for Receiver<'ch, M, T, N> where /// their channel. The following will therefore fail compilation: //// /// ```compile_fail -/// use embassy::util::mpsc; -/// use embassy::util::mpsc::{Channel, WithThreadModeOnly}; +/// use embassy::channel::mpsc; +/// use embassy::channel::mpsc::{Channel, WithThreadModeOnly}; /// /// let (sender, receiver) = { /// let mut channel = Channel::::with_thread_mode_only(); @@ -635,8 +632,8 @@ where /// Establish a new bounded channel. For example, to create one with a NoopMutex: /// /// ``` - /// use embassy::util::mpsc; - /// use embassy::util::mpsc::{Channel, WithNoThreads}; + /// use embassy::channel::mpsc; + /// use embassy::channel::mpsc::{Channel, WithNoThreads}; /// /// // Declare a bounded channel of 3 u32s. /// let mut channel = Channel::::new(); diff --git a/embassy/src/channel/signal.rs b/embassy/src/channel/signal.rs new file mode 100644 index 00000000..d5698732 --- /dev/null +++ b/embassy/src/channel/signal.rs @@ -0,0 +1,73 @@ +use core::cell::UnsafeCell; +use core::future::Future; +use core::mem; +use core::task::{Context, Poll, Waker}; + +/// Synchronization primitive. Allows creating awaitable signals that may be passed between tasks. +/// +/// For more advanced use cases, please consider [futures-intrusive](https://crates.io/crates/futures-intrusive) channels or mutexes. +pub struct Signal { + state: UnsafeCell>, +} + +enum State { + None, + Waiting(Waker), + Signaled(T), +} + +unsafe impl Send for Signal {} +unsafe impl Sync for Signal {} + +impl Signal { + pub const fn new() -> Self { + Self { + state: UnsafeCell::new(State::None), + } + } + + /// Mark this Signal as completed. + pub fn signal(&self, val: T) { + critical_section::with(|_| unsafe { + let state = &mut *self.state.get(); + if let State::Waiting(waker) = mem::replace(state, State::Signaled(val)) { + waker.wake(); + } + }) + } + + pub fn reset(&self) { + critical_section::with(|_| unsafe { + let state = &mut *self.state.get(); + *state = State::None + }) + } + + pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll { + critical_section::with(|_| unsafe { + let state = &mut *self.state.get(); + match state { + State::None => { + *state = State::Waiting(cx.waker().clone()); + Poll::Pending + } + State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending, + State::Waiting(_) => panic!("waker overflow"), + State::Signaled(_) => match mem::replace(state, State::None) { + State::Signaled(res) => Poll::Ready(res), + _ => unreachable!(), + }, + } + }) + } + + /// Future that completes when this Signal has been signaled. + pub fn wait(&self) -> impl Future + '_ { + futures::future::poll_fn(move |cx| self.poll_wait(cx)) + } + + /// non-blocking method to check whether this signal has been signaled. + pub fn signaled(&self) -> bool { + critical_section::with(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) + } +} diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs index 9e050a57..84714228 100644 --- a/embassy/src/lib.rs +++ b/embassy/src/lib.rs @@ -7,6 +7,10 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +pub mod blocking_mutex; +pub mod channel; +pub mod waitqueue; + pub mod executor; pub mod interrupt; pub mod io; diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index e66576b3..f832fa2f 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs @@ -1,21 +1,7 @@ -//! Async utilities -mod drop_bomb; +//! Misc utilities mod forever; -mod mutex; -mod on_drop; -mod signal; -#[cfg_attr(feature = "executor-agnostic", path = "waker_agnostic.rs")] -mod waker; - -pub use drop_bomb::*; pub use forever::*; -pub mod mpsc; -pub use mutex::*; -pub use on_drop::*; -pub use signal::*; -pub use waker::*; - /// Unsafely unborrow an owned singleton out of a `&mut`. /// /// It is intended to be implemented for owned peripheral singletons, such as `USART3` or `AnyPin`. diff --git a/embassy/src/util/on_drop.rs b/embassy/src/util/on_drop.rs deleted file mode 100644 index 10f3407f..00000000 --- a/embassy/src/util/on_drop.rs +++ /dev/null @@ -1,24 +0,0 @@ -use core::mem; -use core::mem::MaybeUninit; - -pub struct OnDrop { - f: MaybeUninit, -} - -impl OnDrop { - pub fn new(f: F) -> Self { - Self { - f: MaybeUninit::new(f), - } - } - - pub fn defuse(self) { - mem::forget(self) - } -} - -impl Drop for OnDrop { - fn drop(&mut self) { - unsafe { self.f.as_ptr().read()() } - } -} diff --git a/embassy/src/util/signal.rs b/embassy/src/util/signal.rs deleted file mode 100644 index bb832533..00000000 --- a/embassy/src/util/signal.rs +++ /dev/null @@ -1,171 +0,0 @@ -use core::cell::UnsafeCell; -use core::future::Future; -use core::mem; -use core::ptr; -use core::task::{Context, Poll, Waker}; -use cortex_m::peripheral::NVIC; -use cortex_m::peripheral::{scb, SCB}; -use executor::raw::TaskHeader; -use ptr::NonNull; - -use crate::executor; -use crate::interrupt::{Interrupt, InterruptExt}; - -/// Synchronization primitive. Allows creating awaitable signals that may be passed between tasks. -/// -/// For more advanced use cases, please consider [futures-intrusive](https://crates.io/crates/futures-intrusive) channels or mutexes. -pub struct Signal { - state: UnsafeCell>, -} - -enum State { - None, - Waiting(Waker), - Signaled(T), -} - -unsafe impl Send for Signal {} -unsafe impl Sync for Signal {} - -impl Signal { - pub const fn new() -> Self { - Self { - state: UnsafeCell::new(State::None), - } - } - - /// Mark this Signal as completed. - pub fn signal(&self, val: T) { - critical_section::with(|_| unsafe { - let state = &mut *self.state.get(); - if let State::Waiting(waker) = mem::replace(state, State::Signaled(val)) { - waker.wake(); - } - }) - } - - pub fn reset(&self) { - critical_section::with(|_| unsafe { - let state = &mut *self.state.get(); - *state = State::None - }) - } - - pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll { - critical_section::with(|_| unsafe { - let state = &mut *self.state.get(); - match state { - State::None => { - *state = State::Waiting(cx.waker().clone()); - Poll::Pending - } - State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending, - State::Waiting(_) => panic!("waker overflow"), - State::Signaled(_) => match mem::replace(state, State::None) { - State::Signaled(res) => Poll::Ready(res), - _ => unreachable!(), - }, - } - }) - } - - /// Future that completes when this Signal has been signaled. - pub fn wait(&self) -> impl Future + '_ { - futures::future::poll_fn(move |cx| self.poll_wait(cx)) - } - - /// non-blocking method to check whether this signal has been signaled. - pub fn signaled(&self) -> bool { - critical_section::with(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) - } -} - -// ========== - -pub fn wake_on_interrupt(interrupt: &mut impl Interrupt, waker: &Waker) { - interrupt.disable(); - interrupt.set_handler(irq_wake_handler); - interrupt.set_handler_context(unsafe { executor::raw::task_from_waker(waker) }.as_ptr() as _); - interrupt.enable(); -} - -unsafe fn irq_wake_handler(ctx: *mut ()) { - if let Some(task) = NonNull::new(ctx as *mut TaskHeader) { - executor::raw::wake_task(task); - } - - let irq = match SCB::vect_active() { - scb::VectActive::Interrupt { irqn } => irqn, - _ => unreachable!(), - }; - - NVIC::mask(crate::interrupt::NrWrap(irq as u16)); -} - -// ========== - -struct NrWrap(u8); -unsafe impl cortex_m::interrupt::Nr for NrWrap { - fn nr(&self) -> u8 { - self.0 - } -} - -/// Creates a future that completes when the specified Interrupt is triggered. -/// -/// The input handler is unregistered when this Future is dropped. -/// -/// Example: -/// ``` no_compile -/// use embassy::traits::*; -/// use embassy::util::InterruptFuture; -/// use embassy_stm32::interrupt; // Adjust this to your MCU's embassy HAL. -/// #[embassy::task] -/// async fn demo_interrupt_future() { -/// // Using STM32f446 interrupt names, adjust this to your application as necessary. -/// // Wait for TIM2 to tick. -/// let mut tim2_interrupt = interrupt::take!(TIM2); -/// InterruptFuture::new(&mut tim2_interrupt).await; -/// // TIM2 interrupt went off, do something... -/// } -/// ``` -pub struct InterruptFuture<'a, I: Interrupt> { - interrupt: &'a mut I, -} - -impl<'a, I: Interrupt> Drop for InterruptFuture<'a, I> { - fn drop(&mut self) { - self.interrupt.disable(); - self.interrupt.remove_handler(); - } -} - -impl<'a, I: Interrupt> InterruptFuture<'a, I> { - pub fn new(interrupt: &'a mut I) -> Self { - interrupt.disable(); - interrupt.set_handler(irq_wake_handler); - interrupt.set_handler_context(ptr::null_mut()); - interrupt.unpend(); - interrupt.enable(); - - Self { interrupt } - } -} - -impl<'a, I: Interrupt> Unpin for InterruptFuture<'a, I> {} - -impl<'a, I: Interrupt> Future for InterruptFuture<'a, I> { - type Output = (); - - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - let s = unsafe { self.get_unchecked_mut() }; - s.interrupt.set_handler_context(unsafe { - executor::raw::task_from_waker(&cx.waker()).cast().as_ptr() - }); - if s.interrupt.is_enabled() { - Poll::Pending - } else { - Poll::Ready(()) - } - } -} diff --git a/embassy/src/waitqueue/mod.rs b/embassy/src/waitqueue/mod.rs new file mode 100644 index 00000000..a2bafad9 --- /dev/null +++ b/embassy/src/waitqueue/mod.rs @@ -0,0 +1,5 @@ +//! Async low-level wait queues + +#[cfg_attr(feature = "executor-agnostic", path = "waker_agnostic.rs")] +mod waker; +pub use waker::*; diff --git a/embassy/src/util/waker.rs b/embassy/src/waitqueue/waker.rs similarity index 99% rename from embassy/src/util/waker.rs rename to embassy/src/waitqueue/waker.rs index 1ac6054f..9eddbdaa 100644 --- a/embassy/src/util/waker.rs +++ b/embassy/src/waitqueue/waker.rs @@ -1,8 +1,7 @@ +use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering}; use core::ptr::{self, NonNull}; use core::task::Waker; -use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering}; - use crate::executor::raw::{task_from_waker, wake_task, TaskHeader}; /// Utility struct to register and wake a waker. diff --git a/embassy/src/util/waker_agnostic.rs b/embassy/src/waitqueue/waker_agnostic.rs similarity index 97% rename from embassy/src/util/waker_agnostic.rs rename to embassy/src/waitqueue/waker_agnostic.rs index 1675c53a..f583fa6f 100644 --- a/embassy/src/util/waker_agnostic.rs +++ b/embassy/src/waitqueue/waker_agnostic.rs @@ -2,7 +2,7 @@ use core::cell::Cell; use core::mem; use core::task::Waker; -use crate::util::CriticalSectionMutex as Mutex; +use crate::blocking_mutex::CriticalSectionMutex as Mutex; /// Utility struct to register and wake a waker. #[derive(Debug)] diff --git a/examples/nrf/src/bin/mpsc.rs b/examples/nrf/src/bin/mpsc.rs index c8cc67d7..79fa3dfb 100644 --- a/examples/nrf/src/bin/mpsc.rs +++ b/examples/nrf/src/bin/mpsc.rs @@ -6,14 +6,13 @@ mod example_common; use defmt::unwrap; +use embassy::channel::mpsc::{self, Channel, Sender, TryRecvError, WithNoThreads}; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; -use embassy::util::mpsc::TryRecvError; -use embassy::util::{mpsc, Forever}; +use embassy::util::Forever; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::Peripherals; use embedded_hal::digital::v2::OutputPin; -use mpsc::{Channel, Sender, WithNoThreads}; enum LedState { On, diff --git a/examples/stm32wl55/src/bin/subghz.rs b/examples/stm32wl55/src/bin/subghz.rs index 1e406886..89549c76 100644 --- a/examples/stm32wl55/src/bin/subghz.rs +++ b/examples/stm32wl55/src/bin/subghz.rs @@ -8,16 +8,16 @@ #[path = "../example_common.rs"] mod example_common; -use embassy::{traits::gpio::WaitForRisingEdge, util::InterruptFuture}; -use embassy_stm32::{ - dbgmcu::Dbgmcu, - dma::NoDma, - exti::ExtiInput, - gpio::{Input, Level, Output, Pull, Speed}, - interrupt, - subghz::*, - Peripherals, -}; +use embassy::channel::signal::Signal; +use embassy::interrupt::{Interrupt, InterruptExt}; +use embassy::traits::gpio::WaitForRisingEdge; +use embassy_stm32::dbgmcu::Dbgmcu; +use embassy_stm32::dma::NoDma; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::interrupt; +use embassy_stm32::subghz::*; +use embassy_stm32::Peripherals; use embedded_hal::digital::v2::OutputPin; use example_common::unwrap; @@ -83,7 +83,13 @@ async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { let button = Input::new(p.PA0, Pull::Up); let mut pin = ExtiInput::new(button, p.EXTI0); - let mut radio_irq = interrupt::take!(SUBGHZ_RADIO); + static IRQ_SIGNAL: Signal<()> = Signal::new(); + let radio_irq = interrupt::take!(SUBGHZ_RADIO); + radio_irq.set_handler(|_| { + IRQ_SIGNAL.signal(()); + unsafe { interrupt::SUBGHZ_RADIO::steal() }.disable(); + }); + let mut radio = SubGhz::new(p.SUBGHZSPI, p.PA5, p.PA7, p.PA6, NoDma, NoDma); defmt::info!("Radio ready for use"); @@ -118,7 +124,9 @@ async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { unwrap!(radio.write_buffer(TX_BUF_OFFSET, PING_DATA_BYTES)); unwrap!(radio.set_tx(Timeout::DISABLED)); - InterruptFuture::new(&mut radio_irq).await; + radio_irq.enable(); + IRQ_SIGNAL.wait().await; + let (_, irq_status) = unwrap!(radio.irq_status()); if irq_status & Irq::TxDone.mask() != 0 { defmt::info!("TX done");