2021-06-07 07:30:38 +02:00
|
|
|
#![macro_use]
|
|
|
|
|
2022-04-26 18:25:04 +02:00
|
|
|
#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")]
|
2021-06-07 07:30:38 +02:00
|
|
|
#[cfg_attr(eth_v2, path = "v2/mod.rs")]
|
|
|
|
mod _version;
|
2022-04-26 03:57:09 +02:00
|
|
|
pub mod generic_smi;
|
2021-06-07 07:30:38 +02:00
|
|
|
|
2023-02-28 18:39:02 +01:00
|
|
|
use core::mem::MaybeUninit;
|
2022-12-26 03:33:49 +01:00
|
|
|
use core::task::Context;
|
|
|
|
|
|
|
|
use embassy_net_driver::{Capabilities, LinkState};
|
2022-12-09 03:18:45 +01:00
|
|
|
use embassy_sync::waitqueue::AtomicWaker;
|
2021-06-10 07:38:59 +02:00
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
pub use self::_version::*;
|
|
|
|
|
2022-12-09 03:18:45 +01:00
|
|
|
#[allow(unused)]
|
|
|
|
const MTU: usize = 1514;
|
|
|
|
const TX_BUFFER_SIZE: usize = 1514;
|
|
|
|
const RX_BUFFER_SIZE: usize = 1536;
|
|
|
|
|
|
|
|
#[repr(C, align(8))]
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub(crate) struct Packet<const N: usize>([u8; N]);
|
|
|
|
|
|
|
|
pub struct PacketQueue<const TX: usize, const RX: usize> {
|
|
|
|
tx_desc: [TDes; TX],
|
|
|
|
rx_desc: [RDes; RX],
|
|
|
|
tx_buf: [Packet<TX_BUFFER_SIZE>; TX],
|
|
|
|
rx_buf: [Packet<RX_BUFFER_SIZE>; RX],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
|
|
|
|
pub const fn new() -> Self {
|
2023-02-28 18:39:02 +01:00
|
|
|
const NEW_TDES: TDes = TDes::new();
|
|
|
|
const NEW_RDES: RDes = RDes::new();
|
|
|
|
Self {
|
|
|
|
tx_desc: [NEW_TDES; TX],
|
|
|
|
rx_desc: [NEW_RDES; RX],
|
|
|
|
tx_buf: [Packet([0; TX_BUFFER_SIZE]); TX],
|
|
|
|
rx_buf: [Packet([0; RX_BUFFER_SIZE]); RX],
|
2022-12-09 03:18:45 +01:00
|
|
|
}
|
|
|
|
}
|
2023-02-28 15:22:54 +01:00
|
|
|
|
|
|
|
// Allow to initialize a Self without requiring it to go on the stack
|
2023-02-28 19:04:43 +01:00
|
|
|
pub fn init(this: &mut MaybeUninit<Self>) {
|
|
|
|
unsafe {
|
|
|
|
this.as_mut_ptr().write_bytes(0u8, core::mem::size_of::<Self>());
|
|
|
|
}
|
2023-02-28 15:22:54 +01:00
|
|
|
}
|
2022-12-09 03:18:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static WAKER: AtomicWaker = AtomicWaker::new();
|
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> {
|
|
|
|
type RxToken<'a> = RxToken<'a, 'd> where Self: 'a;
|
|
|
|
type TxToken<'a> = TxToken<'a, 'd> where Self: 'a;
|
2022-12-09 03:18:45 +01:00
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
|
|
|
WAKER.register(cx.waker());
|
|
|
|
if self.rx.available().is_some() && self.tx.available().is_some() {
|
|
|
|
Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx }))
|
|
|
|
} else {
|
|
|
|
None
|
2022-12-09 03:18:45 +01:00
|
|
|
}
|
2022-12-26 03:33:49 +01:00
|
|
|
}
|
2022-12-09 03:18:45 +01:00
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
|
|
|
|
WAKER.register(cx.waker());
|
|
|
|
if self.tx.available().is_some() {
|
|
|
|
Some(TxToken { tx: &mut self.tx })
|
|
|
|
} else {
|
|
|
|
None
|
2022-12-09 03:18:45 +01:00
|
|
|
}
|
2022-12-26 03:33:49 +01:00
|
|
|
}
|
2022-12-09 03:18:45 +01:00
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
fn capabilities(&self) -> Capabilities {
|
|
|
|
let mut caps = Capabilities::default();
|
|
|
|
caps.max_transmission_unit = MTU;
|
|
|
|
caps.max_burst_size = Some(self.tx.len());
|
|
|
|
caps
|
|
|
|
}
|
2022-12-09 03:18:45 +01:00
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
fn link_state(&mut self, cx: &mut Context) -> LinkState {
|
|
|
|
// TODO: wake cx.waker on link state change
|
|
|
|
cx.waker().wake_by_ref();
|
|
|
|
if P::poll_link(self) {
|
|
|
|
LinkState::Up
|
|
|
|
} else {
|
|
|
|
LinkState::Down
|
2022-12-09 03:18:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
fn ethernet_address(&self) -> [u8; 6] {
|
|
|
|
self.mac_addr
|
2022-12-09 03:18:45 +01:00
|
|
|
}
|
2022-12-26 03:33:49 +01:00
|
|
|
}
|
2022-12-09 03:18:45 +01:00
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
pub struct RxToken<'a, 'd> {
|
|
|
|
rx: &'a mut RDesRing<'d>,
|
|
|
|
}
|
2022-12-09 03:18:45 +01:00
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> {
|
|
|
|
fn consume<R, F>(self, f: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(&mut [u8]) -> R,
|
|
|
|
{
|
|
|
|
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
|
|
|
let pkt = unwrap!(self.rx.available());
|
|
|
|
let r = f(pkt);
|
|
|
|
self.rx.pop_packet();
|
|
|
|
r
|
2022-12-09 03:18:45 +01:00
|
|
|
}
|
2022-12-26 03:33:49 +01:00
|
|
|
}
|
2022-12-09 03:18:45 +01:00
|
|
|
|
2022-12-26 03:33:49 +01:00
|
|
|
pub struct TxToken<'a, 'd> {
|
|
|
|
tx: &'a mut TDesRing<'d>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
|
|
|
|
fn consume<R, F>(self, len: usize, f: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(&mut [u8]) -> R,
|
|
|
|
{
|
|
|
|
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
|
|
|
let pkt = unwrap!(self.tx.available());
|
|
|
|
let r = f(&mut pkt[..len]);
|
|
|
|
self.tx.transmit(len);
|
|
|
|
r
|
2022-12-09 03:18:45 +01:00
|
|
|
}
|
|
|
|
}
|
2022-12-26 03:33:49 +01:00
|
|
|
|
2021-06-10 07:38:59 +02:00
|
|
|
/// Station Management Interface (SMI) on an ethernet PHY
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The methods cannot move out of self
|
|
|
|
pub unsafe trait StationManagement {
|
|
|
|
/// Read a register over SMI.
|
|
|
|
fn smi_read(&mut self, reg: u8) -> u16;
|
|
|
|
/// Write a register over SMI.
|
|
|
|
fn smi_write(&mut self, reg: u8, val: u16);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Traits for an Ethernet PHY
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The methods cannot move S
|
|
|
|
pub unsafe trait PHY {
|
|
|
|
/// Reset PHY and wait for it to come out of reset.
|
|
|
|
fn phy_reset<S: StationManagement>(sm: &mut S);
|
|
|
|
/// PHY initialisation.
|
|
|
|
fn phy_init<S: StationManagement>(sm: &mut S);
|
|
|
|
/// Poll link to see if it is up and FD with 100Mbps
|
|
|
|
fn poll_link<S: StationManagement>(sm: &mut S) -> bool;
|
|
|
|
}
|
2022-02-10 21:38:03 +01:00
|
|
|
|
|
|
|
pub(crate) mod sealed {
|
|
|
|
pub trait Instance {
|
|
|
|
fn regs() -> crate::pac::eth::Eth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait Instance: sealed::Instance + Send + 'static {}
|
|
|
|
|
|
|
|
impl sealed::Instance for crate::peripherals::ETH {
|
|
|
|
fn regs() -> crate::pac::eth::Eth {
|
|
|
|
crate::pac::ETH
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Instance for crate::peripherals::ETH {}
|
|
|
|
|
|
|
|
pin_trait!(RefClkPin, Instance);
|
|
|
|
pin_trait!(MDIOPin, Instance);
|
|
|
|
pin_trait!(MDCPin, Instance);
|
|
|
|
pin_trait!(CRSPin, Instance);
|
|
|
|
pin_trait!(RXD0Pin, Instance);
|
|
|
|
pin_trait!(RXD1Pin, Instance);
|
|
|
|
pin_trait!(TXD0Pin, Instance);
|
|
|
|
pin_trait!(TXD1Pin, Instance);
|
|
|
|
pin_trait!(TXEnPin, Instance);
|