pub(crate) use self::descriptor::RxDescriptor;
use self::descriptor::RxDescriptorError;
pub use self::descriptor::RxRingEntry;
use super::PacketId;
use crate::peripherals::ETHERNET_DMA;
mod descriptor;
#[cfg(feature = "ptp")]
use crate::{dma::PacketIdNotFound, ptp::Timestamp};
#[cfg(feature = "async-await")]
use core::task::Poll;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, PartialEq)]
pub enum RxError {
Truncated,
DmaError,
WouldBlock,
}
impl From<RxDescriptorError> for RxError {
fn from(value: RxDescriptorError) -> Self {
match value {
RxDescriptorError::Truncated => Self::Truncated,
RxDescriptorError::DmaError => Self::DmaError,
}
}
}
pub struct RxRing<'a> {
entries: &'a mut [RxRingEntry],
next_entry: usize,
}
impl<'a> RxRing<'a> {
pub(crate) fn new(entries: &'a mut [RxRingEntry]) -> Self {
RxRing {
entries,
next_entry: 0,
}
}
pub(crate) fn start(&mut self, eth_dma: ÐERNET_DMA) {
{
let mut previous: Option<&mut RxRingEntry> = None;
for entry in self.entries.iter_mut() {
if let Some(prev_entry) = &mut previous {
prev_entry.setup(Some(entry));
}
previous = Some(entry);
}
if let Some(entry) = &mut previous {
entry.setup(None);
}
}
self.next_entry = 0;
let ring_ptr = self.entries[0].desc() as *const RxDescriptor;
eth_dma
.dmardlar
.write(|w| unsafe { w.srl().bits(ring_ptr as u32) });
eth_dma.dmaomr.modify(|_, w| w.sr().set_bit());
self.demand_poll();
}
pub(crate) fn stop(&self, eth_dma: ÐERNET_DMA) {
eth_dma.dmaomr.modify(|_, w| w.sr().clear_bit());
while self.running_state().is_running() {}
}
fn demand_poll(&self) {
let eth_dma = unsafe { &*ETHERNET_DMA::ptr() };
eth_dma.dmarpdr.write(|w| unsafe { w.rpd().bits(1) });
}
pub fn running_state(&self) -> RunningState {
let eth_dma = unsafe { &*ETHERNET_DMA::ptr() };
match eth_dma.dmasr.read().rps().bits() {
0b000 => RunningState::Stopped,
0b001 => RunningState::Running,
0b011 => RunningState::Running,
0b100 => RunningState::Stopped,
0b101 => RunningState::Running,
0b111 => RunningState::Running,
_ => RunningState::Unknown,
}
}
pub fn next_entry_available(&self) -> bool {
if !self.running_state().is_running() {
self.demand_poll();
}
self.entries[self.next_entry].is_available()
}
fn recv_next_impl(
&mut self,
#[allow(unused_variables)] packet_id: Option<PacketId>,
) -> Result<(usize, usize), RxError> {
if !self.running_state().is_running() {
self.demand_poll();
}
let entries_len = self.entries.len();
let entry_num = self.next_entry;
let entry = &mut self.entries[entry_num];
if entry.is_available() {
let length = entry.recv(packet_id)?;
self.next_entry = (self.next_entry + 1) % entries_len;
Ok((entry_num, length))
} else {
Err(RxError::WouldBlock)
}
}
pub fn recv_next(&'_ mut self, packet_id: Option<PacketId>) -> Result<RxPacket<'_>, RxError> {
let (entry, length) = self.recv_next_impl(packet_id.map(|p| p.into()))?;
Ok(RxPacket {
entry: &mut self.entries[entry],
length,
})
}
#[cfg(feature = "async-await")]
pub async fn recv(&'_ mut self, packet_id: Option<PacketId>) -> RxPacket<'_> {
let (entry, length) = core::future::poll_fn(|ctx| {
let res = self.recv_next_impl(packet_id.clone());
match res {
Ok(value) => Poll::Ready(value),
Err(_) => {
crate::dma::EthernetDMA::rx_waker().register(ctx.waker());
Poll::Pending
}
}
})
.await;
RxPacket {
entry: &mut self.entries[entry],
length,
}
}
}
#[cfg(feature = "ptp")]
impl<'a> RxRing<'a> {
pub fn timestamp(&self, id: &PacketId) -> Result<Option<Timestamp>, PacketIdNotFound> {
let entry = self.entries.iter().find(|e| e.has_packet_id(id));
let entry = entry.ok_or(PacketIdNotFound)?;
Ok(entry.read_timestamp())
}
}
#[derive(PartialEq, Eq, Debug)]
pub enum RunningState {
Unknown,
Stopped,
Running,
}
impl RunningState {
pub fn is_running(&self) -> bool {
*self == RunningState::Running
}
}
pub struct RxPacket<'a> {
entry: &'a mut RxRingEntry,
length: usize,
}
impl<'a> core::ops::Deref for RxPacket<'a> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.entry.as_slice()[0..self.length]
}
}
impl<'a> core::ops::DerefMut for RxPacket<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.entry.as_mut_slice()[0..self.length]
}
}
impl<'a> Drop for RxPacket<'a> {
fn drop(&mut self) {
self.entry.desc_mut().set_owned();
}
}
impl<'a> RxPacket<'a> {
pub fn free(self) {
drop(self)
}
#[cfg(feature = "ptp")]
pub fn timestamp(&self) -> Option<Timestamp> {
self.entry.read_timestamp()
}
}