use crate::message::rx;
use crate::reg;
use core::convert::Infallible;
use core::marker::PhantomData;
use reg::AccessRegisterBlock as _;
use vcell::VolatileCell;
#[derive(Debug)]
pub struct OutOfBounds;
pub struct RxDedicatedBuffer<'a, P, M: rx::AnyMessage> {
memory: &'a mut [VolatileCell<M>],
_markers: PhantomData<P>,
}
pub trait DynRxDedicatedBuffer {
type Id;
type Message;
fn receive(&mut self, index: usize) -> nb::Result<Self::Message, OutOfBounds>;
fn receive_any(&mut self) -> nb::Result<Self::Message, Infallible>;
}
impl<'a, P: mcan_core::CanId, M: rx::AnyMessage> RxDedicatedBuffer<'a, P, M> {
pub(crate) unsafe fn new(memory: &'a mut [VolatileCell<M>]) -> Self {
Self {
memory,
_markers: PhantomData,
}
}
unsafe fn regs(&self) -> ®::RegisterBlock {
&(*P::register_block())
}
fn ndat1(&self) -> ®::NDAT1 {
unsafe { &self.regs().ndat1 }
}
fn ndat2(&self) -> ®::NDAT2 {
unsafe { &self.regs().ndat2 }
}
fn has_new_data(&self, index: usize) -> bool {
if index < 32 {
self.ndat1().read().bits() & (1 << index) != 0
} else if index < 64 {
self.ndat2().read().bits() & (1 << (index - 32)) != 0
} else {
false
}
}
fn has_new_data_checked(&self, index: usize) -> Result<bool, OutOfBounds> {
if index < 64 {
Ok(self.has_new_data(index))
} else {
Err(OutOfBounds)
}
}
fn mark_buffer_read(&self, index: usize) {
if index < 32 {
unsafe {
self.ndat1().write(|w| w.bits(1 << index));
}
} else if index < 64 {
unsafe {
self.ndat2().write(|w| w.bits(1 << index));
}
}
}
fn peek(&self, index: usize) -> nb::Result<M, OutOfBounds> {
if self.has_new_data_checked(index)? {
Ok(self
.memory
.get(index)
.ok_or(nb::Error::Other(OutOfBounds))?
.get())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<P: mcan_core::CanId, M: rx::AnyMessage> DynRxDedicatedBuffer for RxDedicatedBuffer<'_, P, M> {
type Id = P;
type Message = M;
fn receive(&mut self, index: usize) -> nb::Result<Self::Message, OutOfBounds> {
let message = self.peek(index)?;
self.mark_buffer_read(index);
Ok(message)
}
fn receive_any(&mut self) -> nb::Result<Self::Message, Infallible> {
self.memory
.iter()
.enumerate()
.filter(|&(i, _)| self.has_new_data(i))
.map(|(i, m)| (i, m.get()))
.min_by_key(|(_, m)| m.id())
.map(|(i, m)| {
self.mark_buffer_read(i);
m
})
.ok_or(nb::Error::WouldBlock)
}
}
impl<P: mcan_core::CanId, M: rx::AnyMessage> Iterator for RxDedicatedBuffer<'_, P, M> {
type Item = M;
fn next(&mut self) -> Option<Self::Item> {
self.receive_any().ok()
}
}