From 6503f9dbf58c36d89b0f1bf9e70587905fbf3d07 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 21 Jan 2021 10:22:30 -0600 Subject: [PATCH 1/2] implement interruptfuture converts an interrupt to a future --- embassy/src/lib.rs | 2 ++ embassy/src/util/signal.rs | 72 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs index 4fa37a55..74c69b54 100644 --- a/embassy/src/lib.rs +++ b/embassy/src/lib.rs @@ -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; diff --git a/embassy/src/util/signal.rs b/embassy/src/util/signal.rs index 8e778d1e..28f86505 100644 --- a/embassy/src/util/signal.rs +++ b/embassy/src/util/signal.rs @@ -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 { state: UnsafeCell>, @@ -67,3 +72,70 @@ impl Signal { 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(()) + } + }) + } +} From e0183f4495d937e1b11bd2ecb2871f42aac86c3e Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 21 Jan 2021 10:59:14 -0600 Subject: [PATCH 2/2] optimize interruptfuture remove critical secitons, impl. Unpin --- embassy/src/util/signal.rs | 40 +++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/embassy/src/util/signal.rs b/embassy/src/util/signal.rs index 28f86505..2c9c52f1 100644 --- a/embassy/src/util/signal.rs +++ b/embassy/src/util/signal.rs @@ -86,20 +86,17 @@ pub struct InterruptFuture<'a, I: OwnedInterrupt> { impl<'a, I: OwnedInterrupt> Drop for InterruptFuture<'a, I> { fn drop(&mut self) { - cortex_m::interrupt::free(|_| { - self.interrupt.remove_handler(); - self.interrupt.disable(); - }); + self.interrupt.disable(); + self.interrupt.remove_handler(); } } 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(); - }); + interrupt.disable(); + interrupt.set_handler(Self::interrupt_handler, ptr::null_mut()); + interrupt.unpend(); + interrupt.enable(); Self { interrupt: interrupt, @@ -120,22 +117,21 @@ impl<'a, I: OwnedInterrupt> InterruptFuture<'a, I> { } } +impl<'a, I: OwnedInterrupt> Unpin for InterruptFuture<'a, I> {} + 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(()) - } - }) + let s = unsafe { self.get_unchecked_mut() }; + s.interrupt.set_handler( + Self::interrupt_handler, + executor::raw::task_from_waker(&cx.waker()).cast().as_ptr(), + ); + if s.interrupt.is_enabled() { + Poll::Pending + } else { + Poll::Ready(()) + } } }