#![macro_use]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::{Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker;
use crate::interrupt::typelevel::Interrupt;
use crate::{interrupt, pac, ppi};
const EVENT_COUNT: usize = 16;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EventNumber {
Event0 = 0,
Event1 = 1,
Event2 = 2,
Event3 = 3,
Event4 = 4,
Event5 = 5,
Event6 = 6,
Event7 = 7,
Event8 = 8,
Event9 = 9,
Event10 = 10,
Event11 = 11,
Event12 = 12,
Event13 = 13,
Event14 = 14,
Event15 = 15,
}
const EVENTS: [EventNumber; EVENT_COUNT] = [
EventNumber::Event0,
EventNumber::Event1,
EventNumber::Event2,
EventNumber::Event3,
EventNumber::Event4,
EventNumber::Event5,
EventNumber::Event6,
EventNumber::Event7,
EventNumber::Event8,
EventNumber::Event9,
EventNumber::Event10,
EventNumber::Event11,
EventNumber::Event12,
EventNumber::Event13,
EventNumber::Event14,
EventNumber::Event15,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum IpcChannel {
Channel0,
Channel1,
Channel2,
Channel3,
Channel4,
Channel5,
Channel6,
Channel7,
Channel8,
Channel9,
Channel10,
Channel11,
Channel12,
Channel13,
Channel14,
Channel15,
}
impl IpcChannel {
fn mask(self) -> u32 {
1 << (self as u32)
}
}
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let regs = T::regs();
for event in EVENTS {
if regs.events_receive(event as usize).read() & 0x01 == 0x01 {
regs.intenclr().write(|w| w.0 = 0x01 << event as u32);
T::state().wakers[event as usize].wake();
}
}
}
}
#[non_exhaustive]
pub struct Ipc<'d> {
pub event0: Event<'d>,
pub event1: Event<'d>,
pub event2: Event<'d>,
pub event3: Event<'d>,
pub event4: Event<'d>,
pub event5: Event<'d>,
pub event6: Event<'d>,
pub event7: Event<'d>,
pub event8: Event<'d>,
pub event9: Event<'d>,
pub event10: Event<'d>,
pub event11: Event<'d>,
pub event12: Event<'d>,
pub event13: Event<'d>,
pub event14: Event<'d>,
pub event15: Event<'d>,
}
impl<'d> Ipc<'d> {
pub fn new<T: Instance>(
_p: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
) -> Self {
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
let r = T::regs();
let state = T::state();
#[rustfmt::skip]
let result = Self { event0: Event { number: EventNumber::Event0, r, state, _phantom: PhantomData },
event1: Event { number: EventNumber::Event1, r, state, _phantom: PhantomData },
event2: Event { number: EventNumber::Event2, r, state, _phantom: PhantomData },
event3: Event { number: EventNumber::Event3, r, state, _phantom: PhantomData },
event4: Event { number: EventNumber::Event4, r, state, _phantom: PhantomData },
event5: Event { number: EventNumber::Event5, r, state, _phantom: PhantomData },
event6: Event { number: EventNumber::Event6, r, state, _phantom: PhantomData },
event7: Event { number: EventNumber::Event7, r, state, _phantom: PhantomData },
event8: Event { number: EventNumber::Event8, r, state, _phantom: PhantomData },
event9: Event { number: EventNumber::Event9, r, state, _phantom: PhantomData },
event10: Event { number: EventNumber::Event10, r, state, _phantom: PhantomData },
event11: Event { number: EventNumber::Event11, r, state, _phantom: PhantomData },
event12: Event { number: EventNumber::Event12, r, state, _phantom: PhantomData },
event13: Event { number: EventNumber::Event13, r, state, _phantom: PhantomData },
event14: Event { number: EventNumber::Event14, r, state, _phantom: PhantomData },
event15: Event { number: EventNumber::Event15, r, state, _phantom: PhantomData },
};
result
}
}
pub struct Event<'d> {
number: EventNumber,
r: pac::ipc::Ipc,
state: &'static State,
_phantom: PhantomData<&'d ()>,
}
impl<'d> Event<'d> {
pub fn trigger(&self) {
let nr = self.number;
self.r.tasks_send(nr as usize).write_value(1);
}
pub async fn wait(&mut self) {
let nr = self.number as usize;
self.r.intenset().write(|w| w.0 = 1 << nr);
poll_fn(|cx| {
self.state.wakers[nr].register(cx.waker());
if self.r.events_receive(nr).read() == 1 {
self.r.events_receive(nr).write_value(0x00);
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
}
pub fn number(&self) -> EventNumber {
self.number
}
pub fn trigger_handle(&self) -> EventTrigger<'d> {
EventTrigger {
number: self.number,
r: self.r,
_phantom: PhantomData,
}
}
pub fn configure_trigger<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
self.r.send_cnf(self.number as usize).write(|w| {
for channel in channels {
w.0 |= channel.mask();
}
})
}
pub fn configure_wait<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
self.r.receive_cnf(self.number as usize).write(|w| {
for channel in channels {
w.0 |= channel.mask();
}
});
}
pub fn task(&self) -> ppi::Task<'d> {
let nr = self.number as usize;
ppi::Task::from_reg(self.r.tasks_send(nr))
}
pub fn event(&self) -> ppi::Event<'d> {
let nr = self.number as usize;
ppi::Event::from_reg(self.r.events_receive(nr))
}
pub fn reborrow(&mut self) -> Event<'_> {
Event {
number: self.number,
r: self.r,
state: self.state,
_phantom: PhantomData,
}
}
pub unsafe fn steal<T: Instance>(number: EventNumber) -> Self {
Self {
number,
r: T::regs(),
state: T::state(),
_phantom: PhantomData,
}
}
}
pub struct EventTrigger<'d> {
number: EventNumber,
r: pac::ipc::Ipc,
_phantom: PhantomData<&'d ()>,
}
impl EventTrigger<'_> {
pub fn trigger(&self) {
let nr = self.number;
self.r.tasks_send(nr as usize).write_value(1);
}
pub fn number(&self) -> EventNumber {
self.number
}
}
pub(crate) struct State {
wakers: [AtomicWaker; EVENT_COUNT],
}
impl State {
pub(crate) const fn new() -> Self {
Self {
wakers: [const { AtomicWaker::new() }; EVENT_COUNT],
}
}
}
pub(crate) trait SealedInstance {
fn regs() -> pac::ipc::Ipc;
fn state() -> &'static State;
}
#[allow(private_bounds)]
pub trait Instance: PeripheralType + SealedInstance + 'static + Send {
type Interrupt: interrupt::typelevel::Interrupt;
}
macro_rules! impl_ipc {
($type:ident, $pac_type:ident, $irq:ident) => {
impl crate::ipc::SealedInstance for peripherals::$type {
fn regs() -> pac::ipc::Ipc {
pac::$pac_type
}
fn state() -> &'static crate::ipc::State {
static STATE: crate::ipc::State = crate::ipc::State::new();
&STATE
}
}
impl crate::ipc::Instance for peripherals::$type {
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
}