use crate::message::rx;
use crate::reg;
use core::convert::Infallible;
use core::marker::PhantomData;
use reg::AccessRegisterBlock as _;
use vcell::VolatileCell;
pub struct RxFifo<'a, F, P, M: rx::AnyMessage> {
memory: &'a mut [VolatileCell<M>],
_markers: PhantomData<(F, P)>,
}
pub trait DynRxFifo {
type RxFifoId;
type CanId;
type Message;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn capacity(&self) -> usize;
fn receive(&mut self) -> nb::Result<Self::Message, Infallible>;
}
pub struct Fifo0;
pub struct Fifo1;
pub trait GetRxFifoRegs {
unsafe fn registers(&self) -> ®::RxFifoRegs;
}
impl<P: mcan_core::CanId, M: rx::AnyMessage> GetRxFifoRegs for RxFifo<'_, Fifo0, P, M> {
unsafe fn registers(&self) -> ®::RxFifoRegs {
&(*P::register_block()).rxf0
}
}
impl<P: mcan_core::CanId, M: rx::AnyMessage> GetRxFifoRegs for RxFifo<'_, Fifo1, P, M> {
unsafe fn registers(&self) -> ®::RxFifoRegs {
&(*P::register_block()).rxf1
}
}
impl<'a, F, P: mcan_core::CanId, M: rx::AnyMessage> RxFifo<'a, F, P, M>
where
Self: GetRxFifoRegs,
{
pub(crate) unsafe fn new(memory: &'a mut [VolatileCell<M>]) -> Self {
Self {
memory,
_markers: PhantomData,
}
}
fn regs(&self) -> ®::RxFifoRegs {
unsafe { self.registers() }
}
}
impl<F, P: mcan_core::CanId, M: rx::AnyMessage> DynRxFifo for RxFifo<'_, F, P, M>
where
Self: GetRxFifoRegs,
{
type RxFifoId = F;
type CanId = P;
type Message = M;
fn len(&self) -> usize {
self.regs().s.read().ffl().bits() as usize
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn capacity(&self) -> usize {
self.memory.len()
}
fn receive(&mut self) -> nb::Result<Self::Message, Infallible> {
let status = self.regs().s.read();
let len = status.ffl().bits();
if len == 0 {
return Err(nb::Error::WouldBlock);
}
let get_index = status.fgi().bits() as usize;
let message = self.memory[get_index].get();
unsafe {
self.regs().a.write(|w| w.fai().bits(get_index as u8));
}
Ok(message)
}
}
impl<F, P: mcan_core::CanId, M: rx::AnyMessage> Iterator for RxFifo<'_, F, P, M>
where
Self: GetRxFifoRegs,
{
type Item = M;
fn next(&mut self) -> Option<Self::Item> {
self.receive().ok()
}
}