use core::cell::RefCell;
use core::future::Future;
use core::task::{Context, Poll, Waker};
use critical_section::Mutex;
use super::{clear_event, read_level, set_trigger, Input, Pin, Trigger};
use crate::pac::GPIO;
const NUM_PINS: usize = 54;
enum State {
Idle,
Waiting(Waker),
Fired,
}
static STATES: Mutex<RefCell<[State; NUM_PINS]>> =
Mutex::new(RefCell::new([const { State::Idle }; NUM_PINS]));
fn pending_mask(gpio: &GPIO) -> u64 {
let low = gpio.gpeds0().read().bits() as u64;
let high = gpio.gpeds1().read().bits() as u64;
low | (high << 32)
}
pub fn on_irq() {
let gpio = unsafe { GPIO::steal() };
let pending = pending_mask(&gpio);
if pending == 0 {
return;
}
critical_section::with(|cs| {
let mut states = STATES.borrow_ref_mut(cs);
for pin in 0..NUM_PINS as u8 {
if pending & (1u64 << pin) == 0 {
continue;
}
let slot = &mut states[pin as usize];
if !matches!(slot, State::Waiting(_)) {
continue;
}
set_trigger(&gpio, pin, None);
clear_event(&gpio, pin);
if let State::Waiting(waker) = core::mem::replace(slot, State::Fired) {
waker.wake();
}
}
});
}
struct WaitForEvent<'a, const N: u8> {
pin: &'a Pin<N, Input>,
trigger: Trigger,
armed: bool,
}
impl<const N: u8> Future for WaitForEvent<'_, N> {
type Output = ();
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let this = self.get_mut();
critical_section::with(|cs| {
let mut states = STATES.borrow_ref_mut(cs);
let slot = &mut states[N as usize];
if matches!(slot, State::Fired) {
*slot = State::Idle;
this.armed = false;
return Poll::Ready(());
}
*slot = State::Waiting(cx.waker().clone());
if !this.armed {
set_trigger(&this.pin.gpio, N, Some(this.trigger));
this.armed = true;
}
Poll::Pending
})
}
}
impl<const N: u8> Drop for WaitForEvent<'_, N> {
fn drop(&mut self) {
if !self.armed {
return;
}
set_trigger(&self.pin.gpio, N, None);
critical_section::with(|cs| {
STATES.borrow_ref_mut(cs)[N as usize] = State::Idle;
});
}
}
impl<const N: u8> embedded_hal_async::digital::Wait for Pin<N, Input> {
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
if read_level(&self.gpio, N) {
return Ok(());
}
WaitForEvent {
pin: self,
trigger: Trigger::HighLevel,
armed: false,
}
.await;
Ok(())
}
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
if !read_level(&self.gpio, N) {
return Ok(());
}
WaitForEvent {
pin: self,
trigger: Trigger::LowLevel,
armed: false,
}
.await;
Ok(())
}
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
WaitForEvent {
pin: self,
trigger: Trigger::RisingEdge,
armed: false,
}
.await;
Ok(())
}
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
WaitForEvent {
pin: self,
trigger: Trigger::FallingEdge,
armed: false,
}
.await;
Ok(())
}
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
WaitForEvent {
pin: self,
trigger: Trigger::AnyEdge,
armed: false,
}
.await;
Ok(())
}
}