use core::task::{Context, Poll};
use psoc_macros::{optional_interrupt, require_interrupt};
use psoc_utils::waker::*;
use crate::{gpio::*, interrupt};
use embedded_hal_async::digital::Wait;
macro_rules! impl_port {
($port:literal) => { paste::paste! {
#[cfg([< gpio $port >])]
mod [< port $port >] {
use super::*;
impl<const PIN: u8, Mode: InputMode, Sec: Security> Pin<$port, PIN, Mode, Sec> {
pub async fn wait_for_high(&mut self) {
if self.is_high() {
return;
}
let interrupt = Interrupt::new(self, InterruptEdge::Rising, self.security);
if interrupt.pin.is_high() {
return;
}
interrupt.await;
}
pub async fn wait_for_low(&mut self) {
if self.is_low() {
return;
}
let interrupt = Interrupt::new(self, InterruptEdge::Falling, self.security);
if interrupt.pin.is_low() {
return;
}
interrupt.await;
}
pub async fn wait_for_rising_edge(&mut self) {
Interrupt::new(self, InterruptEdge::Rising, self.security).await;
}
pub async fn wait_for_falling_edge(&mut self) {
Interrupt::new(self, InterruptEdge::Falling, self.security).await;
}
pub async fn wait_for_any_edge(&mut self) {
Interrupt::new(self, InterruptEdge::RisingFalling, self.security).await;
}
}
impl<const PIN: u8, Mode: InputMode, Sec: Security> Wait for Pin<$port, PIN, Mode, Sec> {
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_high().await)
}
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_low().await)
}
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_rising_edge().await)
}
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_falling_edge().await)
}
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_any_edge().await)
}
}
struct Interrupt<'a, P> {
pin: &'a mut P,
waker: WakerRegistration,
}
impl<'a, P> Interrupt<'a, P>
where
for<'p> &'p mut P: Into<AnyPin<'p>>,
{
fn new(pin: &'a mut P, edge: InterruptEdge, security: impl Into<SecurityAttribute>) -> Self {
#[cfg(trustzone)]
require_interrupt!(handle_secure_interrupt);
require_interrupt!(handle_nonsecure_interrupt);
{
let mut pin = pin.into();
pin.set_interrupt_edge(edge);
pin.clear_interrupt();
if security.into().is_secure() {
#[cfg(trustzone)]
interrupt::unmask(regs::interrupt::[< IOSS_INTERRUPTS_SEC_GPIO_ $port >]);
} else {
interrupt::unmask(regs::interrupt::[< IOSS_INTERRUPTS_GPIO_ $port >]);
}
}
Self {
pin,
waker: WakerRegistration::new(),
}
}
}
impl<'a, P> Future for Interrupt<'a, P>
where
for<'p> &'p mut P: Into<AnyPin<'p>>,
{
type Output = ();
fn poll(mut self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let (mut pin, waker) = unsafe {
let this = self.as_mut().get_unchecked_mut();
(
this.pin.into(),
core::pin::Pin::new_unchecked(&mut this.waker),
)
};
if pin.interrupt_asserted() {
pin.clear_interrupt();
Poll::Ready(())
} else {
critical_section::with(|cs| {
core::pin::Pin::static_ref(&WAKERS).insert(waker, cx.waker().clone(), cs);
pin.set_interrupt_enabled_cs(true, cs);
});
Poll::Pending
}
}
}
static WAKERS: WakerRegistry = WakerRegistry::new();
#[allow(clippy::extra_unused_type_parameters)]
fn handle_interrupt<T>() {
unsafe {
regs::GPIO.prt()[$port].intr_mask().init(|r| r);
critical_section::with(|cs| core::pin::Pin::static_ref(&WAKERS).wake(cs));
}
}
#[cfg(trustzone)]
#[optional_interrupt([< IOSS_INTERRUPTS_SEC_GPIO_ $port >])]
fn handle_secure_interrupt() {
handle_interrupt::<()>();
}
#[optional_interrupt([< IOSS_INTERRUPTS_GPIO_ $port >])]
fn handle_nonsecure_interrupt() {
handle_interrupt::<()>();
}
}
}}
}
impl_port!(0);
impl_port!(1);
impl_port!(2);
impl_port!(3);
impl_port!(4);
impl_port!(5);
impl_port!(6);
impl_port!(7);
impl_port!(8);
impl_port!(9);
impl_port!(10);
impl_port!(11);
impl_port!(12);
impl_port!(13);
impl_port!(14);
impl_port!(15);