use core::task::Context;
use embassy_net_driver_02::{
Capabilities,
Checksum,
Driver,
HardwareAddress,
LinkState,
RxToken,
TxToken,
};
use super::{Ethernet, RX_WAKER, TX_WAKER, mac::EmacRegs};
use crate::{
Async,
ethernet::{
dma::{RDesRing, TDesRing},
phy::Phy,
},
};
const MTU: usize = 1514;
pub struct EthernetRxToken<'a, 'd> {
rx: &'a mut RDesRing<'d>,
}
pub struct EthernetTxToken<'a, 'd> {
tx: &'a mut TDesRing<'d>,
}
impl<'a, 'd> RxToken for EthernetRxToken<'a, 'd> {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let pkt = unwrap!(self.rx.receive(), "RX packet vanished");
let r = f(pkt);
self.rx.pop();
EmacRegs.demand_rx_poll();
r
}
}
impl<'a, 'd> TxToken for EthernetTxToken<'a, 'd> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let capped = len.min(MTU);
let buf = unwrap!(self.tx.available_buf(), "TX slot vanished");
let r = f(&mut buf[..capped]);
self.tx.commit(capped);
EmacRegs.demand_tx_poll();
r
}
}
impl<'d, P: Phy> Driver for Ethernet<'d, Async, P> {
type RxToken<'a>
= EthernetRxToken<'a, 'd>
where
Self: 'a;
type TxToken<'a>
= EthernetTxToken<'a, 'd>
where
Self: 'a;
fn receive(&mut self, cx: &mut Context<'_>) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
RX_WAKER.register(cx.waker());
TX_WAKER.register(cx.waker());
let rx_ready = self.rx.receive().is_some();
EmacRegs.demand_rx_poll();
let tx_ready = self.tx.available_buf().is_some();
if rx_ready && tx_ready {
Some((
EthernetRxToken { rx: &mut self.rx },
EthernetTxToken { tx: &mut self.tx },
))
} else {
None
}
}
fn transmit(&mut self, cx: &mut Context<'_>) -> Option<Self::TxToken<'_>> {
TX_WAKER.register(cx.waker());
if self.tx.available_buf().is_some() {
Some(EthernetTxToken { tx: &mut self.tx })
} else {
None
}
}
fn link_state(&mut self, cx: &mut Context<'_>) -> LinkState {
let state = self.poll_link(Some(cx));
if state.up {
self.set_speed(state.speed);
self.set_duplex(state.duplex);
LinkState::Up
} else {
LinkState::Down
}
}
fn capabilities(&self) -> Capabilities {
let mut caps = Capabilities::default();
caps.max_transmission_unit = MTU;
caps.max_burst_size = Some(self.tx.len());
caps.checksum.ipv4 = Checksum::None;
caps.checksum.tcp = Checksum::None;
caps.checksum.udp = Checksum::None;
caps.checksum.icmpv4 = Checksum::None;
caps.checksum.icmpv6 = Checksum::None;
caps
}
fn hardware_address(&self) -> HardwareAddress {
HardwareAddress::Ethernet(self.mac_addr())
}
}