use core::cell::Cell;
use core::future::Future;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use critical_section::Mutex;
use portable_atomic::{AtomicBool, Ordering};
static VTABLE: RawWakerVTable = RawWakerVTable::new(|_| RAW_WAKER, |_| {}, |_| {}, |_| {});
const RAW_WAKER: RawWaker = RawWaker::new(core::ptr::null(), &VTABLE);
#[inline]
fn wait_for_interrupt() {
#[cfg(target_arch = "riscv32")]
unsafe {
core::arch::asm!("wfi", options(nomem, nostack));
}
#[cfg(not(target_arch = "riscv32"))]
core::hint::spin_loop();
}
pub fn block_on<F: Future>(fut: F) -> F::Output {
let mut fut = core::pin::pin!(fut);
let waker = unsafe { Waker::from_raw(RAW_WAKER) };
let mut cx = Context::from_waker(&waker);
loop {
if let Poll::Ready(v) = fut.as_mut().poll(&mut cx) {
return v;
}
wait_for_interrupt();
}
}
pub struct IrqSignal {
fired: AtomicBool,
waker: Mutex<Cell<Option<Waker>>>,
}
impl IrqSignal {
pub const fn new() -> Self {
Self { fired: AtomicBool::new(false), waker: Mutex::new(Cell::new(None)) }
}
pub fn signal(&self) {
self.fired.store(true, Ordering::Release);
critical_section::with(|cs| {
if let Some(w) = self.waker.borrow(cs).take() {
w.wake();
}
});
}
pub fn register(&self, waker: &Waker) {
critical_section::with(|cs| self.waker.borrow(cs).set(Some(waker.clone())));
}
pub fn take_fired(&self) -> bool {
self.fired.swap(false, Ordering::Acquire)
}
pub fn reset(&self) {
self.fired.store(false, Ordering::Relaxed);
critical_section::with(|cs| self.waker.borrow(cs).set(None));
}
}
impl Default for IrqSignal {
fn default() -> Self {
Self::new()
}
}