embassy: Refactor module structure to remove kitchen-sink util.
				
					
				
			This commit is contained in:
		
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -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, | ||||
|   | ||||
| @@ -1,4 +1,27 @@ | ||||
| use core::mem; | ||||
| use core::mem::MaybeUninit; | ||||
| 
 | ||||
| pub struct OnDrop<F: FnOnce()> { | ||||
|     f: MaybeUninit<F>, | ||||
| } | ||||
| 
 | ||||
| impl<F: FnOnce()> OnDrop<F> { | ||||
|     pub fn new(f: F) -> Self { | ||||
|         Self { | ||||
|             f: MaybeUninit::new(f), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn defuse(self) { | ||||
|         mem::forget(self) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<F: FnOnce()> Drop for OnDrop<F> { | ||||
|     fn drop(&mut self) { | ||||
|         unsafe { self.f.as_ptr().read()() } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// An explosive ordinance that panics if it is improperly disposed of.
 | ||||
| ///
 | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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")] | ||||
|   | ||||
| @@ -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}; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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<u8> for Spim<'d, T> { | ||||
| } | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
|     use embassy::waitqueue::AtomicWaker; | ||||
|  | ||||
|     use super::*; | ||||
|  | ||||
|     pub struct State { | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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] | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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}; | ||||
|  | ||||
|   | ||||
| @@ -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}; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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}; | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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}; | ||||
|   | ||||
| @@ -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 | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| //! Blocking mutex (not async)
 | ||||
| 
 | ||||
| use core::cell::UnsafeCell; | ||||
| use critical_section::CriticalSection; | ||||
| 
 | ||||
							
								
								
									
										4
									
								
								embassy/src/channel/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								embassy/src/channel/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| //! Async channels | ||||
|  | ||||
| pub mod mpsc; | ||||
| pub mod signal; | ||||
| @@ -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::<WithThreadModeOnly, u32, 3>::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::<WithNoThreads, u32, 3>::new();
 | ||||
							
								
								
									
										73
									
								
								embassy/src/channel/signal.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								embassy/src/channel/signal.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -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<T> { | ||||
|     state: UnsafeCell<State<T>>, | ||||
| } | ||||
|  | ||||
| enum State<T> { | ||||
|     None, | ||||
|     Waiting(Waker), | ||||
|     Signaled(T), | ||||
| } | ||||
|  | ||||
| unsafe impl<T: Send> Send for Signal<T> {} | ||||
| unsafe impl<T: Send> Sync for Signal<T> {} | ||||
|  | ||||
| impl<T: Send> Signal<T> { | ||||
|     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<T> { | ||||
|         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<Output = T> + '_ { | ||||
|         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(_))) | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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`. | ||||
|   | ||||
| @@ -1,24 +0,0 @@ | ||||
| use core::mem; | ||||
| use core::mem::MaybeUninit; | ||||
|  | ||||
| pub struct OnDrop<F: FnOnce()> { | ||||
|     f: MaybeUninit<F>, | ||||
| } | ||||
|  | ||||
| impl<F: FnOnce()> OnDrop<F> { | ||||
|     pub fn new(f: F) -> Self { | ||||
|         Self { | ||||
|             f: MaybeUninit::new(f), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn defuse(self) { | ||||
|         mem::forget(self) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<F: FnOnce()> Drop for OnDrop<F> { | ||||
|     fn drop(&mut self) { | ||||
|         unsafe { self.f.as_ptr().read()() } | ||||
|     } | ||||
| } | ||||
| @@ -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<T> { | ||||
|     state: UnsafeCell<State<T>>, | ||||
| } | ||||
|  | ||||
| enum State<T> { | ||||
|     None, | ||||
|     Waiting(Waker), | ||||
|     Signaled(T), | ||||
| } | ||||
|  | ||||
| unsafe impl<T: Send> Send for Signal<T> {} | ||||
| unsafe impl<T: Send> Sync for Signal<T> {} | ||||
|  | ||||
| impl<T: Send> Signal<T> { | ||||
|     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<T> { | ||||
|         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<Output = T> + '_ { | ||||
|         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(()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										5
									
								
								embassy/src/waitqueue/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								embassy/src/waitqueue/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| //! Async low-level wait queues | ||||
|  | ||||
| #[cfg_attr(feature = "executor-agnostic", path = "waker_agnostic.rs")] | ||||
| mod waker; | ||||
| pub use waker::*; | ||||
| @@ -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.
 | ||||
| @@ -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)] | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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"); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user