Merge branch 'master' into spi-trait
This commit is contained in:
commit
5bd705caa5
37 changed files with 368 additions and 39 deletions
|
@ -45,7 +45,7 @@ GPIO pins are set up for the `nrf52840-dk` board (PCA10056)
|
|||
- Install `probe-run` with defmt support.
|
||||
|
||||
```
|
||||
cargo install --git https://github.com/knurling-rs/probe-run --branch main --features defmt
|
||||
cargo install probe-run
|
||||
```
|
||||
|
||||
- Run the example
|
||||
|
|
|
@ -157,17 +157,17 @@ pub fn interrupt_take(item: TokenStream) -> TokenStream {
|
|||
static HANDLER: ::embassy::interrupt::Handler;
|
||||
}
|
||||
|
||||
let func = HANDLER.func.load(::embassy::atomic::Ordering::Acquire);
|
||||
let ctx = HANDLER.ctx.load(::embassy::atomic::Ordering::Acquire);
|
||||
let func = HANDLER.func.load(::embassy::export::atomic::Ordering::Acquire);
|
||||
let ctx = HANDLER.ctx.load(::embassy::export::atomic::Ordering::Acquire);
|
||||
if !func.is_null() {
|
||||
let func: fn(*mut ()) = ::core::mem::transmute(func);
|
||||
func(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static TAKEN: ::embassy::atomic::AtomicBool = ::embassy::atomic::AtomicBool::new(false);
|
||||
static TAKEN: ::embassy::export::atomic::AtomicBool = ::embassy::export::atomic::AtomicBool::new(false);
|
||||
|
||||
if TAKEN.compare_exchange(false, true, ::embassy::atomic::Ordering::AcqRel, ::embassy::atomic::Ordering::Acquire).is_err() {
|
||||
if TAKEN.compare_exchange(false, true, ::embassy::export::atomic::Ordering::AcqRel, ::embassy::export::atomic::Ordering::Acquire).is_err() {
|
||||
panic!("IRQ Already taken");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#![no_std]
|
||||
#![feature(generic_associated_types)]
|
||||
#![feature(asm)]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../serial_port.rs"]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy::executor::task;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#[path = "../example_common.rs"]
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::hal::gpio;
|
|||
use crate::hal::gpio::{Edge, ExtiPin as HalExtiPin};
|
||||
use crate::hal::syscfg::SysCfg;
|
||||
use crate::pac::EXTI;
|
||||
use embedded_hal::digital::v2 as digital;
|
||||
|
||||
use crate::interrupt;
|
||||
|
||||
|
@ -42,6 +43,52 @@ pub struct ExtiPin<T: HalExtiPin + WithInterrupt> {
|
|||
_mgr: &'static ExtiManager,
|
||||
}
|
||||
|
||||
impl<T: HalExtiPin + WithInterrupt + digital::OutputPin> digital::OutputPin for ExtiPin<T> {
|
||||
type Error = T::Error;
|
||||
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
self.pin.set_low()
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
self.pin.set_high()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HalExtiPin + WithInterrupt + digital::StatefulOutputPin> digital::StatefulOutputPin
|
||||
for ExtiPin<T>
|
||||
{
|
||||
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||
self.pin.is_set_low()
|
||||
}
|
||||
|
||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||
self.pin.is_set_high()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HalExtiPin + WithInterrupt + digital::ToggleableOutputPin> digital::ToggleableOutputPin
|
||||
for ExtiPin<T>
|
||||
{
|
||||
type Error = T::Error;
|
||||
|
||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||
self.pin.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HalExtiPin + WithInterrupt + digital::InputPin> digital::InputPin for ExtiPin<T> {
|
||||
type Error = T::Error;
|
||||
|
||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||
self.pin.is_high()
|
||||
}
|
||||
|
||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||
self.pin.is_low()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Irq Handler Description
|
||||
EXTI0_IRQn EXTI0_IRQHandler Handler for pins connected to line 0
|
||||
|
@ -482,7 +529,7 @@ exti!(gpioj, [
|
|||
feature = "stm32f469",
|
||||
feature = "stm32f479"
|
||||
))]
|
||||
exti!(gpioj, [
|
||||
exti!(gpiok, [
|
||||
EXTI0 => PK0,
|
||||
EXTI1 => PK1,
|
||||
EXTI2 => PK2,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#![no_std]
|
||||
#![feature(generic_associated_types)]
|
||||
#![feature(asm)]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
|
@ -313,5 +315,6 @@ pub(crate) mod fmt;
|
|||
|
||||
pub mod exti;
|
||||
pub mod interrupt;
|
||||
pub mod qei;
|
||||
pub mod rtc;
|
||||
pub mod serial;
|
||||
|
|
95
embassy-stm32f4/src/qei.rs
Normal file
95
embassy-stm32f4/src/qei.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
use crate::interrupt;
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
use embassy::interrupt::Interrupt;
|
||||
use embassy::traits::qei::WaitForRotate;
|
||||
use embedded_hal::Direction;
|
||||
use embedded_hal::Qei as THQei;
|
||||
use stm32f4xx_hal::pac::TIM2;
|
||||
use stm32f4xx_hal::qei::{Pins, Qei as HalQei};
|
||||
|
||||
pub struct Qei<T: Instance, PINS> {
|
||||
qei: HalQei<T, PINS>,
|
||||
int: T::Interrupt,
|
||||
}
|
||||
|
||||
impl<PINS: Pins<TIM2>> Qei<TIM2, PINS> {
|
||||
pub fn tim2(tim: TIM2, pins: PINS, interrupt: interrupt::TIM2) -> Self {
|
||||
let qei = HalQei::tim2(tim, pins);
|
||||
|
||||
let tim = unsafe {
|
||||
&mut *(stm32f4xx_hal::stm32::TIM2::ptr()
|
||||
as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock)
|
||||
};
|
||||
/*
|
||||
enable qei interrupt
|
||||
*/
|
||||
tim.dier.write(|w| w.uie().set_bit());
|
||||
|
||||
Qei {
|
||||
qei: qei,
|
||||
int: interrupt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<PINS: Pins<TIM2> + 'static> WaitForRotate for Qei<TIM2, PINS> {
|
||||
type RotateFuture<'a> = impl Future<Output = Direction> + 'a;
|
||||
|
||||
fn wait_for_rotate<'a>(
|
||||
self: Pin<&'a mut Self>,
|
||||
count_down: u16,
|
||||
count_up: u16,
|
||||
) -> Self::RotateFuture<'a> {
|
||||
let s = unsafe { self.get_unchecked_mut() };
|
||||
|
||||
let tim = unsafe {
|
||||
&mut *(stm32f4xx_hal::stm32::TIM2::ptr()
|
||||
as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock)
|
||||
};
|
||||
|
||||
/*
|
||||
the interrupt will be reached at zero or the max count
|
||||
write the total range to the qei.
|
||||
*/
|
||||
tim.arr
|
||||
.write(|w| unsafe { w.bits((count_down + count_up) as u32) });
|
||||
|
||||
/*
|
||||
set timer to the correct value in the range
|
||||
*/
|
||||
tim.cnt.write(|w| unsafe { w.bits(count_down as u32) });
|
||||
|
||||
/*
|
||||
clear interrupt flag
|
||||
*/
|
||||
tim.sr.write(|w| w.uif().clear_bit());
|
||||
|
||||
async move {
|
||||
embassy::util::InterruptFuture::new(&mut s.int).await;
|
||||
|
||||
if tim.cnt.read().bits() == 0 {
|
||||
Direction::Downcounting
|
||||
} else if tim.cnt.read() == count_down + count_up {
|
||||
Direction::Upcounting
|
||||
} else {
|
||||
panic!("unexpected value")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
pub trait Instance: sealed::Sealed {
|
||||
type Interrupt: interrupt::Interrupt;
|
||||
}
|
||||
|
||||
#[cfg(feature = "stm32f405")]
|
||||
impl sealed::Sealed for TIM2 {}
|
||||
#[cfg(feature = "stm32f405")]
|
||||
impl Instance for TIM2 {
|
||||
type Interrupt = interrupt::TIM2;
|
||||
}
|
|
@ -9,3 +9,4 @@ std = []
|
|||
|
||||
[dependencies]
|
||||
defmt = { version = "0.2.0", optional = true }
|
||||
embedded-hal = { version = "0.2.3", features = ["unproven"] }
|
||||
|
|
|
@ -91,8 +91,7 @@ impl AddressMode for SevenBitAddress {}
|
|||
|
||||
impl AddressMode for TenBitAddress {}
|
||||
|
||||
/// Blocking read
|
||||
pub trait Read<A: AddressMode = SevenBitAddress> {
|
||||
pub trait I2c<A: AddressMode = SevenBitAddress> {
|
||||
/// Error type
|
||||
type Error;
|
||||
|
||||
|
|
|
@ -4,11 +4,14 @@
|
|||
#![feature(const_fn_fn_ptr_basics)]
|
||||
#![feature(const_option)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
pub mod delay;
|
||||
pub mod flash;
|
||||
pub mod gpio;
|
||||
pub mod i2c;
|
||||
pub mod qei;
|
||||
pub mod spi;
|
||||
pub mod uart;
|
||||
|
|
22
embassy-traits/src/qei.rs
Normal file
22
embassy-traits/src/qei.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
use embedded_hal::Direction;
|
||||
|
||||
// Wait for a specified number of rotations either up or down
|
||||
pub trait WaitForRotate {
|
||||
type RotateFuture<'a>: Future<Output = Direction> + 'a;
|
||||
|
||||
/// Wait for a specified number of rotations, in ticks, either up or down.
|
||||
///
|
||||
/// Return Direction::Upcounting if the high bound is reached.
|
||||
/// Return Direction::Downcounting if the low bound is reached.
|
||||
///
|
||||
/// Number of ticks is encoder dependent. As an example, if we connect
|
||||
/// the Bourns PEC11H-4120F-S0020, we have 20 ticks per full rotation.
|
||||
/// Other encoders may vary.
|
||||
fn wait_for_rotate<'a>(
|
||||
self: Pin<&'a mut Self>,
|
||||
count_down: u16,
|
||||
count_up: u16,
|
||||
) -> Self::RotateFuture<'a>;
|
||||
}
|
|
@ -13,6 +13,8 @@ defmt-info = []
|
|||
defmt-warn = []
|
||||
defmt-error = []
|
||||
|
||||
executor-agnostic = []
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.2.0", optional = true }
|
||||
log = { version = "0.4.11", optional = true }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub use embassy_macros::task;
|
||||
|
||||
use atomic_polyfill::Ordering;
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomData;
|
||||
use core::pin::Pin;
|
||||
|
@ -15,7 +16,6 @@ mod util;
|
|||
mod waker;
|
||||
|
||||
use self::util::UninitCell;
|
||||
use crate::atomic::Ordering;
|
||||
use crate::fmt::panic;
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::time::Alarm;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use atomic_polyfill::{AtomicU32, Ordering};
|
||||
use core::cell::Cell;
|
||||
use core::cmp::min;
|
||||
use core::marker::PhantomData;
|
||||
|
@ -9,7 +10,6 @@ use super::run_queue::{RunQueue, RunQueueItem};
|
|||
use super::timer_queue::{TimerQueue, TimerQueueItem};
|
||||
use super::util::UninitCell;
|
||||
use super::waker;
|
||||
use crate::atomic::{AtomicU32, Ordering};
|
||||
use crate::time::{Alarm, Instant};
|
||||
|
||||
/// Task is spawned (has a future)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use atomic_polyfill::{AtomicPtr, Ordering};
|
||||
use core::ptr;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use super::raw::Task;
|
||||
use crate::atomic::{AtomicPtr, Ordering};
|
||||
|
||||
pub(crate) struct RunQueueItem {
|
||||
next: AtomicPtr<Task>,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use atomic_polyfill::{AtomicPtr, Ordering};
|
||||
use core::cell::Cell;
|
||||
use core::cmp::min;
|
||||
use core::ptr;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use super::raw::{Task, STATE_TIMER_QUEUED};
|
||||
use crate::atomic::{AtomicPtr, Ordering};
|
||||
use crate::time::Instant;
|
||||
|
||||
pub(crate) struct TimerQueueItem {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use core::ptr;
|
||||
use cortex_m::peripheral::NVIC;
|
||||
|
||||
use crate::atomic::{AtomicBool, AtomicPtr, Ordering};
|
||||
use atomic_polyfill::{AtomicBool, AtomicPtr, Ordering};
|
||||
|
||||
pub use embassy_macros::interrupt_declare as declare;
|
||||
pub use embassy_macros::interrupt_take as take;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#![feature(const_fn_fn_ptr_basics)]
|
||||
#![feature(const_option)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(min_type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
// This mod MUST go first, so that the others see its macros.
|
||||
|
@ -16,4 +18,9 @@ pub mod time;
|
|||
pub mod util;
|
||||
|
||||
pub use embassy_traits as traits;
|
||||
pub use atomic_polyfill as atomic;
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Implementation details for embassy macros. DO NOT USE.
|
||||
pub mod export {
|
||||
pub use atomic_polyfill as atomic;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use core::cell::UnsafeCell;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use crate::atomic::{AtomicBool, Ordering};
|
||||
use atomic_polyfill::{AtomicBool, Ordering};
|
||||
|
||||
pub struct Forever<T> {
|
||||
used: AtomicBool,
|
||||
|
|
|
@ -3,6 +3,8 @@ mod forever;
|
|||
mod mutex;
|
||||
mod portal;
|
||||
mod signal;
|
||||
|
||||
#[cfg_attr(feature = "executor-agnostic", path = "waker_agnostic.rs")]
|
||||
mod waker;
|
||||
|
||||
pub use drop_bomb::*;
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use core::mem;
|
||||
use core::task::Context;
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::task::Waker;
|
||||
|
||||
use atomic_polyfill::{AtomicPtr, Ordering};
|
||||
|
||||
use crate::executor::raw::{task_from_waker, wake_task, Task};
|
||||
|
||||
/// Utility struct to register and wake a waker.
|
||||
#[derive(Debug)]
|
||||
pub struct WakerRegistration {
|
||||
waker: Option<Waker>,
|
||||
waker: Option<NonNull<Task>>,
|
||||
}
|
||||
|
||||
impl WakerRegistration {
|
||||
|
@ -15,37 +18,61 @@ impl WakerRegistration {
|
|||
|
||||
/// Register a waker. Overwrites the previous waker, if any.
|
||||
pub fn register(&mut self, w: &Waker) {
|
||||
let w = unsafe { task_from_waker(w) };
|
||||
match self.waker {
|
||||
// Optimization: If both the old and new Wakers wake the same task, we can simply
|
||||
// keep the old waker, skipping the clone. (In most executor implementations,
|
||||
// cloning a waker is somewhat expensive, comparable to cloning an Arc).
|
||||
Some(ref w2) if (w2.will_wake(w)) => {}
|
||||
_ => {
|
||||
// clone the new waker and store it
|
||||
if let Some(old_waker) = mem::replace(&mut self.waker, Some(w.clone())) {
|
||||
// We had a waker registered for another task. Wake it, so the other task can
|
||||
// reregister itself if it's still interested.
|
||||
//
|
||||
// If two tasks are waiting on the same thing concurrently, this will cause them
|
||||
// to wake each other in a loop fighting over this WakerRegistration. This wastes
|
||||
// CPU but things will still work.
|
||||
//
|
||||
// If the user wants to have two tasks waiting on the same thing they should use
|
||||
// a more appropriate primitive that can store multiple wakers.
|
||||
old_waker.wake()
|
||||
}
|
||||
// Optimization: If both the old and new Wakers wake the same task, do nothing.
|
||||
Some(w2) if w == w2 => {}
|
||||
Some(w2) => {
|
||||
// We had a waker registered for another task. Wake it, so the other task can
|
||||
// reregister itself if it's still interested.
|
||||
//
|
||||
// If two tasks are waiting on the same thing concurrently, this will cause them
|
||||
// to wake each other in a loop fighting over this WakerRegistration. This wastes
|
||||
// CPU but things will still work.
|
||||
//
|
||||
// If the user wants to have two tasks waiting on the same thing they should use
|
||||
// a more appropriate primitive that can store multiple wakers.
|
||||
|
||||
unsafe { wake_task(w2) }
|
||||
self.waker = Some(w);
|
||||
}
|
||||
None => self.waker = Some(w),
|
||||
}
|
||||
}
|
||||
|
||||
/// Wake the registered waker, if any.
|
||||
pub fn wake(&mut self) {
|
||||
if let Some(w) = self.waker.take() {
|
||||
w.wake()
|
||||
unsafe { wake_task(w) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AtomicWakerRegistration {
|
||||
waker: AtomicPtr<Task>,
|
||||
}
|
||||
|
||||
impl AtomicWakerRegistration {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
waker: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context(&self) -> Option<Context<'_>> {
|
||||
self.waker.as_ref().map(|w| Context::from_waker(w))
|
||||
/// Register a waker. Overwrites the previous waker, if any.
|
||||
pub fn register(&self, w: &Waker) {
|
||||
let w = unsafe { task_from_waker(w) };
|
||||
let w2 = self.waker.swap(w.as_ptr(), Ordering::Relaxed);
|
||||
if !w2.is_null() && w2 != w.as_ptr() {
|
||||
unsafe { wake_task(NonNull::new_unchecked(w2)) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Wake the registered waker, if any.
|
||||
pub fn wake(&self) {
|
||||
let w2 = self.waker.swap(ptr::null_mut(), Ordering::Relaxed);
|
||||
if !w2.is_null() {
|
||||
unsafe { wake_task(NonNull::new_unchecked(w2)) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
87
embassy/src/util/waker_agnostic.rs
Normal file
87
embassy/src/util/waker_agnostic.rs
Normal file
|
@ -0,0 +1,87 @@
|
|||
use core::cell::Cell;
|
||||
use core::mem;
|
||||
use core::task::Waker;
|
||||
|
||||
use cortex_m::interrupt::Mutex;
|
||||
|
||||
/// Utility struct to register and wake a waker.
|
||||
#[derive(Debug)]
|
||||
pub struct WakerRegistration {
|
||||
waker: Option<Waker>,
|
||||
}
|
||||
|
||||
impl WakerRegistration {
|
||||
pub const fn new() -> Self {
|
||||
Self { waker: None }
|
||||
}
|
||||
|
||||
/// Register a waker. Overwrites the previous waker, if any.
|
||||
pub fn register(&mut self, w: &Waker) {
|
||||
match self.waker {
|
||||
// Optimization: If both the old and new Wakers wake the same task, we can simply
|
||||
// keep the old waker, skipping the clone. (In most executor implementations,
|
||||
// cloning a waker is somewhat expensive, comparable to cloning an Arc).
|
||||
Some(ref w2) if (w2.will_wake(w)) => {}
|
||||
_ => {
|
||||
// clone the new waker and store it
|
||||
if let Some(old_waker) = mem::replace(&mut self.waker, Some(w.clone())) {
|
||||
// We had a waker registered for another task. Wake it, so the other task can
|
||||
// reregister itself if it's still interested.
|
||||
//
|
||||
// If two tasks are waiting on the same thing concurrently, this will cause them
|
||||
// to wake each other in a loop fighting over this WakerRegistration. This wastes
|
||||
// CPU but things will still work.
|
||||
//
|
||||
// If the user wants to have two tasks waiting on the same thing they should use
|
||||
// a more appropriate primitive that can store multiple wakers.
|
||||
old_waker.wake()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wake the registered waker, if any.
|
||||
pub fn wake(&mut self) {
|
||||
if let Some(w) = self.waker.take() {
|
||||
w.wake()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility struct to register and wake a waker.
|
||||
pub struct AtomicWakerRegistration {
|
||||
waker: Mutex<Cell<Option<Waker>>>,
|
||||
}
|
||||
|
||||
impl AtomicWakerRegistration {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
waker: Mutex::new(Cell::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a waker. Overwrites the previous waker, if any.
|
||||
pub fn register(&mut self, w: &Waker) {
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
let cell = self.waker.borrow(cs);
|
||||
cell.set(match cell.replace(None) {
|
||||
Some(w2) if (w2.will_wake(w)) => Some(w2),
|
||||
Some(w2) => {
|
||||
w2.wake();
|
||||
Some(w.clone())
|
||||
}
|
||||
None => Some(w.clone()),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Wake the registered waker, if any.
|
||||
pub fn wake(&mut self) {
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
let cell = self.waker.borrow(cs);
|
||||
if let Some(w) = cell.replace(None) {
|
||||
w.wake()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue