implement interruptfuture

converts an interrupt to a future
This commit is contained in:
xoviat 2021-01-21 10:22:30 -06:00
parent 27831124a7
commit 6503f9dbf5
2 changed files with 74 additions and 0 deletions

View File

@ -2,6 +2,8 @@
#![feature(generic_associated_types)]
#![feature(const_fn)]
#![feature(const_fn_fn_ptr_basics)]
#![feature(const_in_array_repeat_expressions)]
#![feature(const_option)]
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;

View File

@ -1,8 +1,13 @@
use crate::executor;
use crate::fmt::panic;
use crate::interrupt::OwnedInterrupt;
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};
pub struct Signal<T> {
state: UnsafeCell<State<T>>,
@ -67,3 +72,70 @@ impl<T: Send> Signal<T> {
cortex_m::interrupt::free(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_)))
}
}
struct NrWrap(u8);
unsafe impl cortex_m::interrupt::Nr for NrWrap {
fn nr(&self) -> u8 {
self.0
}
}
pub struct InterruptFuture<'a, I: OwnedInterrupt> {
interrupt: &'a mut I,
}
impl<'a, I: OwnedInterrupt> Drop for InterruptFuture<'a, I> {
fn drop(&mut self) {
cortex_m::interrupt::free(|_| {
self.interrupt.remove_handler();
self.interrupt.disable();
});
}
}
impl<'a, I: OwnedInterrupt> InterruptFuture<'a, I> {
pub fn new(interrupt: &'a mut I) -> Self {
cortex_m::interrupt::free(|_| {
interrupt.set_handler(Self::interrupt_handler, ptr::null_mut());
interrupt.unpend();
interrupt.enable();
});
Self {
interrupt: interrupt,
}
}
unsafe fn interrupt_handler(ctx: *mut ()) {
let irq = match SCB::vect_active() {
scb::VectActive::Interrupt { irqn } => irqn,
_ => unreachable!(),
};
if ctx as *const _ != ptr::null() {
executor::raw::wake_task(ptr::NonNull::new_unchecked(ctx));
}
NVIC::mask(NrWrap(irq));
}
}
impl<'a, I: OwnedInterrupt> Future for InterruptFuture<'a, I> {
type Output = ();
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
cortex_m::interrupt::free(|_| unsafe {
let s = self.get_unchecked_mut();
if s.interrupt.is_enabled() {
s.interrupt.set_handler(
Self::interrupt_handler,
executor::raw::task_from_waker(&cx.waker()).cast().as_ptr(),
);
Poll::Pending
} else {
Poll::Ready(())
}
})
}
}