use crate::timer::Timer;
use crate::usb::control::{get_configuration_descriptor, set_configuration, vendor_in, vendor_out};
use crate::usb::descriptor::{ConfigurationDescriptor, Descriptors, EndpointDescriptor};
use crate::usb::dwc2::{Channel, ControlEndpoint, TransferError};
use crate::usb::Device;
pub const VENDOR_ID: u16 = 0x0424;
pub const PRODUCT_ID: u16 = 0xEC00;
const READ_REGISTER: u8 = 0xA1;
const WRITE_REGISTER: u8 = 0xA0;
const REG_ID_REV: u16 = 0x00;
const REG_TX_CFG: u16 = 0x10;
const REG_HW_CFG: u16 = 0x14;
const REG_RX_FIFO_INF: u16 = 0x18;
const REG_LED_GPIO_CFG: u16 = 0x24;
const REG_MAC_CR: u16 = 0x100;
const REG_ADDRH: u16 = 0x104;
const REG_ADDRL: u16 = 0x108;
const REG_MII_ADDR: u16 = 0x114;
const REG_MII_DATA: u16 = 0x118;
const HW_CFG_BIR: u32 = 0x0000_1000;
const LED_GPIO_CFG_SPD_LED: u32 = 0x0100_0000;
const LED_GPIO_CFG_LNK_LED: u32 = 0x0010_0000;
const LED_GPIO_CFG_FDX_LED: u32 = 0x0001_0000;
const MAC_CR_RCVOWN: u32 = 0x0080_0000;
const MAC_CR_TXEN: u32 = 0x0000_0008;
const MAC_CR_RXEN: u32 = 0x0000_0004;
const TX_CFG_ON: u32 = 0x0000_0004;
const MII_BUSY: u32 = 0x01;
const PHY_ID_INTERNAL: u32 = 0x01;
const PHY_REG_STATUS: u8 = 0x01;
const BMSR_LINK_UP: u16 = 1 << 2;
const TX_CMD_A_FIRST_SEG: u32 = 0x0000_2000;
const TX_CMD_A_LAST_SEG: u32 = 0x0000_1000;
const RX_STATUS_ERROR: u32 = 0x0000_8000;
const RX_STATUS_FRAME_LENGTH: u32 = 0x3FFF_0000;
const FRAME_BUFFER_SIZE: usize = 2048;
const MII_TIMEOUT_US: u64 = 1_000_000;
#[repr(C, align(64))]
struct FrameBuffer([u8; FRAME_BUFFER_SIZE]);
struct BulkEndpoint {
number: u8,
max_packet_size: u16,
toggle: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct IdRevision {
pub id: u16,
pub revision: u16,
}
pub struct Lan9514 {
endpoint: ControlEndpoint,
bulk_in: BulkEndpoint,
bulk_out: BulkEndpoint,
rx_buffer: FrameBuffer,
tx_buffer: FrameBuffer,
}
fn find_bulk_endpoints(config: &[u8]) -> Option<(BulkEndpoint, BulkEndpoint)> {
let mut bulk_in = None;
let mut bulk_out = None;
for descriptor in Descriptors::new(config) {
if let Some(endpoint) = EndpointDescriptor::parse(descriptor) {
if endpoint.is_bulk() {
let info = BulkEndpoint {
number: endpoint.number(),
max_packet_size: endpoint.max_packet_size(),
toggle: false,
};
if endpoint.is_in() {
bulk_in = Some(info);
} else {
bulk_out = Some(info);
}
}
}
}
Some((bulk_in?, bulk_out?))
}
impl Lan9514 {
pub fn from_device(
channel: &mut Channel,
timer: &Timer,
device: Device,
) -> Result<Option<Lan9514>, TransferError> {
if device.descriptor.vendor_id != VENDOR_ID || device.descriptor.product_id != PRODUCT_ID {
return Ok(None);
}
let mut config = [0u8; 64];
let len = get_configuration_descriptor(channel, timer, device.endpoint, 0, &mut config)?;
let Some(config_value) = ConfigurationDescriptor::parse(&config[..len]).map(|c| c.value())
else {
return Ok(None);
};
let Some((bulk_in, bulk_out)) = find_bulk_endpoints(&config[..len]) else {
return Ok(None);
};
set_configuration(channel, timer, device.endpoint, config_value)?;
Ok(Some(Lan9514 {
endpoint: device.endpoint,
bulk_in,
bulk_out,
rx_buffer: FrameBuffer([0; FRAME_BUFFER_SIZE]),
tx_buffer: FrameBuffer([0; FRAME_BUFFER_SIZE]),
}))
}
pub fn from_endpoint(
channel: &mut Channel,
timer: &Timer,
endpoint: ControlEndpoint,
) -> Result<Option<Lan9514>, TransferError> {
let mut config = [0u8; 64];
let len = get_configuration_descriptor(channel, timer, endpoint, 0, &mut config)?;
let Some((bulk_in, bulk_out)) = find_bulk_endpoints(&config[..len]) else {
return Ok(None);
};
Ok(Some(Lan9514 {
endpoint,
bulk_in,
bulk_out,
rx_buffer: FrameBuffer([0; FRAME_BUFFER_SIZE]),
tx_buffer: FrameBuffer([0; FRAME_BUFFER_SIZE]),
}))
}
pub fn read_register(
&self,
channel: &mut Channel,
timer: &Timer,
register: u16,
) -> Result<u32, TransferError> {
let mut value = [0u8; 4];
vendor_in(
channel,
timer,
self.endpoint,
READ_REGISTER,
0,
register,
&mut value,
)?;
Ok(u32::from_le_bytes(value))
}
pub fn write_register(
&self,
channel: &mut Channel,
timer: &Timer,
register: u16,
value: u32,
) -> Result<(), TransferError> {
vendor_out(
channel,
timer,
self.endpoint,
WRITE_REGISTER,
0,
register,
&value.to_le_bytes(),
)
}
pub fn id_revision(
&self,
channel: &mut Channel,
timer: &Timer,
) -> Result<IdRevision, TransferError> {
let value = self.read_register(channel, timer, REG_ID_REV)?;
Ok(IdRevision {
id: (value >> 16) as u16,
revision: (value & 0xFFFF) as u16,
})
}
pub fn set_mac_address(
&self,
channel: &mut Channel,
timer: &Timer,
mac: [u8; 6],
) -> Result<(), TransferError> {
let low = u32::from_le_bytes([mac[0], mac[1], mac[2], mac[3]]);
let high = u16::from_le_bytes([mac[4], mac[5]]) as u32;
self.write_register(channel, timer, REG_ADDRL, low)?;
self.write_register(channel, timer, REG_ADDRH, high)?;
Ok(())
}
pub fn mac_address(
&self,
channel: &mut Channel,
timer: &Timer,
) -> Result<[u8; 6], TransferError> {
let low = self.read_register(channel, timer, REG_ADDRL)?.to_le_bytes();
let high = self.read_register(channel, timer, REG_ADDRH)?.to_le_bytes();
Ok([low[0], low[1], low[2], low[3], high[0], high[1]])
}
pub fn start(
&mut self,
channel: &mut Channel,
timer: &Timer,
mac: [u8; 6],
) -> Result<(), TransferError> {
self.set_mac_address(channel, timer, mac)?;
let hw_cfg = self.read_register(channel, timer, REG_HW_CFG)?;
self.write_register(channel, timer, REG_HW_CFG, hw_cfg | HW_CFG_BIR)?;
self.write_register(
channel,
timer,
REG_LED_GPIO_CFG,
LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED | LED_GPIO_CFG_FDX_LED,
)?;
self.write_register(
channel,
timer,
REG_MAC_CR,
MAC_CR_RCVOWN | MAC_CR_TXEN | MAC_CR_RXEN,
)?;
self.write_register(channel, timer, REG_TX_CFG, TX_CFG_ON)?;
Ok(())
}
pub fn bulk_in_max_packet_size(&self) -> u16 {
self.bulk_in.max_packet_size
}
pub fn bulk_out_max_packet_size(&self) -> u16 {
self.bulk_out.max_packet_size
}
pub fn is_link_up(&self, channel: &mut Channel, timer: &Timer) -> Result<bool, TransferError> {
Ok(self.phy_read(channel, timer, PHY_REG_STATUS)? & BMSR_LINK_UP != 0)
}
pub fn send_frame(
&mut self,
channel: &mut Channel,
timer: &Timer,
frame: &[u8],
) -> Result<(), TransferError> {
debug_assert!(frame.len() <= FRAME_BUFFER_SIZE - 8);
let length = frame.len();
let command_a = TX_CMD_A_FIRST_SEG | TX_CMD_A_LAST_SEG | length as u32;
let command_b = length as u32;
self.tx_buffer.0[0..4].copy_from_slice(&command_a.to_le_bytes());
self.tx_buffer.0[4..8].copy_from_slice(&command_b.to_le_bytes());
self.tx_buffer.0[8..8 + length].copy_from_slice(frame);
let number = self.bulk_out.number;
let endpoint = ControlEndpoint {
max_packet_size: self.bulk_out.max_packet_size,
..self.endpoint
};
channel.bulk_out(
endpoint,
number,
&mut self.bulk_out.toggle,
&self.tx_buffer.0[..8 + length],
timer,
)?;
Ok(())
}
pub fn receive_frame(
&mut self,
channel: &mut Channel,
timer: &Timer,
) -> Result<Option<&[u8]>, TransferError> {
if self.read_register(channel, timer, REG_RX_FIFO_INF)? == 0 {
return Ok(None);
}
let number = self.bulk_in.number;
let endpoint = ControlEndpoint {
max_packet_size: self.bulk_in.max_packet_size,
..self.endpoint
};
let received = match channel.bulk_in(
endpoint,
number,
&mut self.bulk_in.toggle,
&mut self.rx_buffer.0,
timer,
) {
Ok(received) => received,
Err(TransferError::Nak) => return Ok(None),
Err(error) => return Err(error),
};
if received < 4 {
return Ok(None);
}
let status = u32::from_le_bytes([
self.rx_buffer.0[0],
self.rx_buffer.0[1],
self.rx_buffer.0[2],
self.rx_buffer.0[3],
]);
if status & RX_STATUS_ERROR != 0 {
return Ok(None);
}
let frame_length = ((status & RX_STATUS_FRAME_LENGTH) >> 16) as usize;
if frame_length <= 4 {
return Ok(None);
}
let end = frame_length.min(received);
Ok(Some(&self.rx_buffer.0[4..end]))
}
fn phy_read(
&self,
channel: &mut Channel,
timer: &Timer,
index: u8,
) -> Result<u16, TransferError> {
self.phy_wait_not_busy(channel, timer)?;
let mii_address = (PHY_ID_INTERNAL << 11) | ((index as u32) << 6);
self.write_register(channel, timer, REG_MII_ADDR, mii_address | MII_BUSY)?;
self.phy_wait_not_busy(channel, timer)?;
Ok(self.read_register(channel, timer, REG_MII_DATA)? as u16)
}
fn phy_wait_not_busy(&self, channel: &mut Channel, timer: &Timer) -> Result<(), TransferError> {
let start = timer.now_micros();
while self.read_register(channel, timer, REG_MII_ADDR)? & MII_BUSY != 0 {
if timer.now_micros() - start > MII_TIMEOUT_US {
return Err(TransferError::Timeout);
}
}
Ok(())
}
}
#[cfg(feature = "smoltcp")]
use smoltcp::phy::{Device as PhyDevice, DeviceCapabilities, Medium, RxToken, TxToken};
#[cfg(feature = "smoltcp")]
use smoltcp::time::Instant;
#[cfg(any(feature = "smoltcp", feature = "embassy-net-driver"))]
pub const MTU: usize = 1514;
#[cfg(feature = "smoltcp")]
pub struct Lan9514Phy<'a, 'c> {
lan9514: Lan9514,
channel: Channel<'c>,
timer: &'a Timer,
tx_scratch: [u8; MTU + 2],
}
#[cfg(feature = "smoltcp")]
impl<'a, 'c> Lan9514Phy<'a, 'c> {
pub fn new(lan9514: Lan9514, channel: Channel<'c>, timer: &'a Timer) -> Self {
Self {
lan9514,
channel,
timer,
tx_scratch: [0; MTU + 2],
}
}
}
#[cfg(feature = "smoltcp")]
impl<'c> PhyDevice for Lan9514Phy<'_, 'c> {
type RxToken<'t>
= Lan9514RxToken
where
Self: 't;
type TxToken<'t>
= Lan9514TxToken<'t, 'c>
where
Self: 't;
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
let frame = match self.lan9514.receive_frame(&mut self.channel, self.timer) {
Ok(Some(frame)) => frame,
Ok(None) => return None,
Err(_) => return None,
};
let len = frame.len().min(MTU);
let mut rx = Lan9514RxToken {
buffer: [0; MTU],
len,
};
rx.buffer[..len].copy_from_slice(&frame[..len]);
let tx = Lan9514TxToken {
lan9514: &mut self.lan9514,
channel: &mut self.channel,
timer: self.timer,
scratch: &mut self.tx_scratch,
};
Some((rx, tx))
}
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
Some(Lan9514TxToken {
lan9514: &mut self.lan9514,
channel: &mut self.channel,
timer: self.timer,
scratch: &mut self.tx_scratch,
})
}
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.medium = Medium::Ethernet;
caps.max_transmission_unit = MTU;
caps.max_burst_size = Some(1);
caps
}
}
#[cfg(feature = "smoltcp")]
pub struct Lan9514RxToken {
buffer: [u8; MTU],
len: usize,
}
#[cfg(feature = "smoltcp")]
impl RxToken for Lan9514RxToken {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
f(&self.buffer[..self.len])
}
}
#[cfg(feature = "smoltcp")]
pub struct Lan9514TxToken<'a, 'c> {
lan9514: &'a mut Lan9514,
channel: &'a mut Channel<'c>,
timer: &'a Timer,
scratch: &'a mut [u8],
}
#[cfg(feature = "smoltcp")]
impl TxToken for Lan9514TxToken<'_, '_> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let result = f(&mut self.scratch[..len]);
let _ = self
.lan9514
.send_frame(self.channel, self.timer, &self.scratch[..len]);
result
}
}
#[cfg(feature = "embassy-net-driver")]
static RX_WAKER: critical_section::Mutex<core::cell::RefCell<Option<core::task::Waker>>> =
critical_section::Mutex::new(core::cell::RefCell::new(None));
#[cfg(feature = "embassy-net-driver")]
pub fn wake_rx() {
critical_section::with(|cs| {
if let Some(waker) = RX_WAKER.borrow_ref_mut(cs).take() {
waker.wake();
}
});
}
#[cfg(feature = "embassy-net-driver")]
pub struct Lan9514Driver<'a, 'c> {
lan9514: Lan9514,
channel: Channel<'c>,
timer: &'a Timer,
mac: [u8; 6],
tx_scratch: [u8; MTU + 2],
}
#[cfg(feature = "embassy-net-driver")]
impl<'a, 'c> Lan9514Driver<'a, 'c> {
pub fn new(lan9514: Lan9514, channel: Channel<'c>, timer: &'a Timer, mac: [u8; 6]) -> Self {
Self {
lan9514,
channel,
timer,
mac,
tx_scratch: [0; MTU + 2],
}
}
}
#[cfg(feature = "embassy-net-driver")]
impl<'c> embassy_net_driver::Driver for Lan9514Driver<'_, 'c> {
type RxToken<'t>
= Lan9514NetRxToken
where
Self: 't;
type TxToken<'t>
= Lan9514NetTxToken<'t, 'c>
where
Self: 't;
fn receive(
&mut self,
cx: &mut core::task::Context,
) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
let frame = match self.lan9514.receive_frame(&mut self.channel, self.timer) {
Ok(Some(frame)) => frame,
Ok(None) | Err(_) => {
critical_section::with(|cs| {
*RX_WAKER.borrow_ref_mut(cs) = Some(cx.waker().clone());
});
return None;
}
};
let len = frame.len().min(MTU);
let mut rx = Lan9514NetRxToken {
buffer: [0; MTU],
len,
};
rx.buffer[..len].copy_from_slice(&frame[..len]);
let tx = Lan9514NetTxToken {
lan9514: &mut self.lan9514,
channel: &mut self.channel,
timer: self.timer,
scratch: &mut self.tx_scratch,
};
Some((rx, tx))
}
fn transmit(&mut self, _cx: &mut core::task::Context) -> Option<Self::TxToken<'_>> {
Some(Lan9514NetTxToken {
lan9514: &mut self.lan9514,
channel: &mut self.channel,
timer: self.timer,
scratch: &mut self.tx_scratch,
})
}
fn link_state(&mut self, _cx: &mut core::task::Context) -> embassy_net_driver::LinkState {
embassy_net_driver::LinkState::Up
}
fn capabilities(&self) -> embassy_net_driver::Capabilities {
let mut caps = embassy_net_driver::Capabilities::default();
caps.max_transmission_unit = MTU;
caps.max_burst_size = Some(1);
caps
}
fn hardware_address(&self) -> embassy_net_driver::HardwareAddress {
embassy_net_driver::HardwareAddress::Ethernet(self.mac)
}
}
#[cfg(feature = "embassy-net-driver")]
pub struct Lan9514NetRxToken {
buffer: [u8; MTU],
len: usize,
}
#[cfg(feature = "embassy-net-driver")]
impl embassy_net_driver::RxToken for Lan9514NetRxToken {
fn consume<R, F>(mut self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
f(&mut self.buffer[..self.len])
}
}
#[cfg(feature = "embassy-net-driver")]
pub struct Lan9514NetTxToken<'a, 'c> {
lan9514: &'a mut Lan9514,
channel: &'a mut Channel<'c>,
timer: &'a Timer,
scratch: &'a mut [u8],
}
#[cfg(feature = "embassy-net-driver")]
impl embassy_net_driver::TxToken for Lan9514NetTxToken<'_, '_> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let result = f(&mut self.scratch[..len]);
let _ = self
.lan9514
.send_frame(self.channel, self.timer, &self.scratch[..len]);
result
}
}