Compare commits
6 Commits
enable-f44
...
embassy-ne
Author | SHA1 | Date | |
---|---|---|---|
|
51a67cb69a | ||
|
b8777eaea2 | ||
|
b0583b17cb | ||
|
246c49621c | ||
|
52a801fdb7 | ||
|
fc6e70caa5 |
3
ci.sh
3
ci.sh
@@ -213,6 +213,9 @@ cargo batch \
|
||||
rm out/tests/stm32wb55rg/wpan_mac
|
||||
rm out/tests/stm32wb55rg/wpan_ble
|
||||
|
||||
# not in CI yet.
|
||||
rm -rf out/tests/stm32f446re
|
||||
|
||||
# unstable, I think it's running out of RAM?
|
||||
rm out/tests/stm32f207zg/eth
|
||||
|
||||
|
@@ -6,8 +6,7 @@ keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethern
|
||||
categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
repository = "https://github.com/embassy-rs/embassy"
|
||||
|
||||
[dependencies]
|
||||
heapless = "0.8"
|
||||
|
@@ -1,3 +1,4 @@
|
||||
/// CRC32 lookup table.
|
||||
pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
|
||||
0x0000_0000,
|
||||
0x7707_3096,
|
||||
@@ -263,8 +264,9 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
|
||||
pub struct ETH_FCS(pub u32);
|
||||
|
||||
impl ETH_FCS {
|
||||
pub const CRC32_OK: u32 = 0x2144_df1c;
|
||||
const CRC32_OK: u32 = 0x2144_df1c;
|
||||
|
||||
/// Create a new frame check sequence from `data`.
|
||||
#[must_use]
|
||||
pub fn new(data: &[u8]) -> Self {
|
||||
let fcs = data.iter().fold(u32::MAX, |crc, byte| {
|
||||
@@ -274,6 +276,7 @@ impl ETH_FCS {
|
||||
Self(fcs)
|
||||
}
|
||||
|
||||
/// Update the frame check sequence with `data`.
|
||||
#[must_use]
|
||||
pub fn update(self, data: &[u8]) -> Self {
|
||||
let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| {
|
||||
@@ -283,16 +286,19 @@ impl ETH_FCS {
|
||||
Self(fcs)
|
||||
}
|
||||
|
||||
/// Check if the frame check sequence is correct.
|
||||
#[must_use]
|
||||
pub fn crc_ok(&self) -> bool {
|
||||
self.0 == Self::CRC32_OK
|
||||
}
|
||||
|
||||
/// Switch byte order.
|
||||
#[must_use]
|
||||
pub fn hton_bytes(&self) -> [u8; 4] {
|
||||
self.0.to_le_bytes()
|
||||
}
|
||||
|
||||
/// Switch byte order as a u32.
|
||||
#[must_use]
|
||||
pub fn hton(&self) -> u32 {
|
||||
self.0.to_le()
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
#![allow(clippy::missing_panics_doc)]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
// must go first!
|
||||
mod fmt;
|
||||
@@ -26,8 +27,9 @@ use embedded_hal_async::digital::Wait;
|
||||
use embedded_hal_async::spi::{Error, Operation, SpiDevice};
|
||||
use heapless::Vec;
|
||||
pub use mdio::MdioBus;
|
||||
pub use phy::{Phy10BaseT1x, RegsC22, RegsC45};
|
||||
pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1};
|
||||
pub use phy::Phy10BaseT1x;
|
||||
use phy::{RegsC22, RegsC45};
|
||||
use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1};
|
||||
|
||||
use crate::fmt::Bytes;
|
||||
use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader};
|
||||
@@ -446,6 +448,7 @@ pub struct Runner<'d, SPI, INT, RST> {
|
||||
}
|
||||
|
||||
impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
|
||||
/// Run the driver.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub async fn run(mut self) -> ! {
|
||||
loop {
|
||||
|
@@ -39,6 +39,7 @@ enum Reg13Op {
|
||||
///
|
||||
/// Clause 45 methodes are bases on <https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf>
|
||||
pub trait MdioBus {
|
||||
/// Error type.
|
||||
type Error;
|
||||
|
||||
/// Read, Clause 22
|
||||
|
@@ -2,6 +2,7 @@ use core::fmt::{Debug, Display};
|
||||
|
||||
use bitfield::{bitfield, bitfield_bitrange, bitfield_fields};
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#![no_std]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
// must go first!
|
||||
mod fmt;
|
||||
@@ -15,6 +16,9 @@ use embassy_sync::blocking_mutex::Mutex;
|
||||
use embassy_sync::waitqueue::WakerRegistration;
|
||||
use embassy_sync::zerocopy_channel;
|
||||
|
||||
/// Channel state.
|
||||
///
|
||||
/// Holds a buffer of packets with size MTU, for both TX and RX.
|
||||
pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
|
||||
rx: [PacketBuf<MTU>; N_RX],
|
||||
tx: [PacketBuf<MTU>; N_TX],
|
||||
@@ -24,6 +28,7 @@ pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
|
||||
impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_TX> {
|
||||
const NEW_PACKET: PacketBuf<MTU> = PacketBuf::new();
|
||||
|
||||
/// Create a new channel state.
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
rx: [Self::NEW_PACKET; N_RX],
|
||||
@@ -39,33 +44,45 @@ struct StateInner<'d, const MTU: usize> {
|
||||
shared: Mutex<NoopRawMutex, RefCell<Shared>>,
|
||||
}
|
||||
|
||||
/// State of the LinkState
|
||||
struct Shared {
|
||||
link_state: LinkState,
|
||||
waker: WakerRegistration,
|
||||
hardware_address: driver::HardwareAddress,
|
||||
}
|
||||
|
||||
/// Channel runner.
|
||||
///
|
||||
/// Holds the shared state and the lower end of channels for inbound and outbound packets.
|
||||
pub struct Runner<'d, const MTU: usize> {
|
||||
tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||
rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||
shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>,
|
||||
}
|
||||
|
||||
/// State runner.
|
||||
///
|
||||
/// Holds the shared state of the channel such as link state.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct StateRunner<'d> {
|
||||
shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>,
|
||||
}
|
||||
|
||||
/// RX runner.
|
||||
///
|
||||
/// Holds the lower end of the channel for passing inbound packets up the stack.
|
||||
pub struct RxRunner<'d, const MTU: usize> {
|
||||
rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||
}
|
||||
|
||||
/// TX runner.
|
||||
///
|
||||
/// Holds the lower end of the channel for passing outbound packets down the stack.
|
||||
pub struct TxRunner<'d, const MTU: usize> {
|
||||
tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||
}
|
||||
|
||||
impl<'d, const MTU: usize> Runner<'d, MTU> {
|
||||
/// Split the runner into separate runners for controlling state, rx and tx.
|
||||
pub fn split(self) -> (StateRunner<'d>, RxRunner<'d, MTU>, TxRunner<'d, MTU>) {
|
||||
(
|
||||
StateRunner { shared: self.shared },
|
||||
@@ -74,6 +91,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Split the runner into separate runners for controlling state, rx and tx borrowing the underlying state.
|
||||
pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) {
|
||||
(
|
||||
StateRunner { shared: self.shared },
|
||||
@@ -86,10 +104,12 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a state runner sharing the state channel.
|
||||
pub fn state_runner(&self) -> StateRunner<'d> {
|
||||
StateRunner { shared: self.shared }
|
||||
}
|
||||
|
||||
/// Set the link state.
|
||||
pub fn set_link_state(&mut self, state: LinkState) {
|
||||
self.shared.lock(|s| {
|
||||
let s = &mut *s.borrow_mut();
|
||||
@@ -98,6 +118,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
|
||||
});
|
||||
}
|
||||
|
||||
/// Set the hardware address.
|
||||
pub fn set_hardware_address(&mut self, address: driver::HardwareAddress) {
|
||||
self.shared.lock(|s| {
|
||||
let s = &mut *s.borrow_mut();
|
||||
@@ -106,16 +127,19 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
|
||||
});
|
||||
}
|
||||
|
||||
/// Wait until there is space for more inbound packets and return a slice they can be copied into.
|
||||
pub async fn rx_buf(&mut self) -> &mut [u8] {
|
||||
let p = self.rx_chan.send().await;
|
||||
&mut p.buf
|
||||
}
|
||||
|
||||
/// Check if there is space for more inbound packets right now.
|
||||
pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
|
||||
let p = self.rx_chan.try_send()?;
|
||||
Some(&mut p.buf)
|
||||
}
|
||||
|
||||
/// Polling the inbound channel if there is space for packets.
|
||||
pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||
match self.rx_chan.poll_send(cx) {
|
||||
Poll::Ready(p) => Poll::Ready(&mut p.buf),
|
||||
@@ -123,22 +147,26 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark packet of len bytes as pushed to the inbound channel.
|
||||
pub fn rx_done(&mut self, len: usize) {
|
||||
let p = self.rx_chan.try_send().unwrap();
|
||||
p.len = len;
|
||||
self.rx_chan.send_done();
|
||||
}
|
||||
|
||||
/// Wait until there is space for more outbound packets and return a slice they can be copied into.
|
||||
pub async fn tx_buf(&mut self) -> &mut [u8] {
|
||||
let p = self.tx_chan.receive().await;
|
||||
&mut p.buf[..p.len]
|
||||
}
|
||||
|
||||
/// Check if there is space for more outbound packets right now.
|
||||
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
|
||||
let p = self.tx_chan.try_receive()?;
|
||||
Some(&mut p.buf[..p.len])
|
||||
}
|
||||
|
||||
/// Polling the outbound channel if there is space for packets.
|
||||
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||
match self.tx_chan.poll_receive(cx) {
|
||||
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
|
||||
@@ -146,12 +174,14 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark outbound packet as copied.
|
||||
pub fn tx_done(&mut self) {
|
||||
self.tx_chan.receive_done();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> StateRunner<'d> {
|
||||
/// Set link state.
|
||||
pub fn set_link_state(&self, state: LinkState) {
|
||||
self.shared.lock(|s| {
|
||||
let s = &mut *s.borrow_mut();
|
||||
@@ -160,6 +190,7 @@ impl<'d> StateRunner<'d> {
|
||||
});
|
||||
}
|
||||
|
||||
/// Set the hardware address.
|
||||
pub fn set_hardware_address(&self, address: driver::HardwareAddress) {
|
||||
self.shared.lock(|s| {
|
||||
let s = &mut *s.borrow_mut();
|
||||
@@ -170,16 +201,19 @@ impl<'d> StateRunner<'d> {
|
||||
}
|
||||
|
||||
impl<'d, const MTU: usize> RxRunner<'d, MTU> {
|
||||
/// Wait until there is space for more inbound packets and return a slice they can be copied into.
|
||||
pub async fn rx_buf(&mut self) -> &mut [u8] {
|
||||
let p = self.rx_chan.send().await;
|
||||
&mut p.buf
|
||||
}
|
||||
|
||||
/// Check if there is space for more inbound packets right now.
|
||||
pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
|
||||
let p = self.rx_chan.try_send()?;
|
||||
Some(&mut p.buf)
|
||||
}
|
||||
|
||||
/// Polling the inbound channel if there is space for packets.
|
||||
pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||
match self.rx_chan.poll_send(cx) {
|
||||
Poll::Ready(p) => Poll::Ready(&mut p.buf),
|
||||
@@ -187,6 +221,7 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark packet of len bytes as pushed to the inbound channel.
|
||||
pub fn rx_done(&mut self, len: usize) {
|
||||
let p = self.rx_chan.try_send().unwrap();
|
||||
p.len = len;
|
||||
@@ -195,16 +230,19 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> {
|
||||
}
|
||||
|
||||
impl<'d, const MTU: usize> TxRunner<'d, MTU> {
|
||||
/// Wait until there is space for more outbound packets and return a slice they can be copied into.
|
||||
pub async fn tx_buf(&mut self) -> &mut [u8] {
|
||||
let p = self.tx_chan.receive().await;
|
||||
&mut p.buf[..p.len]
|
||||
}
|
||||
|
||||
/// Check if there is space for more outbound packets right now.
|
||||
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
|
||||
let p = self.tx_chan.try_receive()?;
|
||||
Some(&mut p.buf[..p.len])
|
||||
}
|
||||
|
||||
/// Polling the outbound channel if there is space for packets.
|
||||
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||
match self.tx_chan.poll_receive(cx) {
|
||||
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
|
||||
@@ -212,11 +250,18 @@ impl<'d, const MTU: usize> TxRunner<'d, MTU> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark outbound packet as copied.
|
||||
pub fn tx_done(&mut self) {
|
||||
self.tx_chan.receive_done();
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a channel.
|
||||
///
|
||||
/// Returns a pair of handles for interfacing with the peripheral and the networking stack.
|
||||
///
|
||||
/// The runner is interfacing with the peripheral at the lower part of the stack.
|
||||
/// The device is interfacing with the networking stack on the layer above.
|
||||
pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
|
||||
state: &'d mut State<MTU, N_RX, N_TX>,
|
||||
hardware_address: driver::HardwareAddress,
|
||||
@@ -257,17 +302,22 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
|
||||
)
|
||||
}
|
||||
|
||||
/// Represents a packet of size MTU.
|
||||
pub struct PacketBuf<const MTU: usize> {
|
||||
len: usize,
|
||||
buf: [u8; MTU],
|
||||
}
|
||||
|
||||
impl<const MTU: usize> PacketBuf<MTU> {
|
||||
/// Create a new packet buffer.
|
||||
pub const fn new() -> Self {
|
||||
Self { len: 0, buf: [0; MTU] }
|
||||
}
|
||||
}
|
||||
|
||||
/// Channel device.
|
||||
///
|
||||
/// Holds the shared state and upper end of channels for inbound and outbound packets.
|
||||
pub struct Device<'d, const MTU: usize> {
|
||||
rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||
tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||
@@ -314,6 +364,9 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A rx token.
|
||||
///
|
||||
/// Holds inbound receive channel and interfaces with embassy-net-driver.
|
||||
pub struct RxToken<'a, const MTU: usize> {
|
||||
rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf<MTU>>,
|
||||
}
|
||||
@@ -331,6 +384,9 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A tx token.
|
||||
///
|
||||
/// Holds outbound transmit channel and interfaces with embassy-net-driver.
|
||||
pub struct TxToken<'a, const MTU: usize> {
|
||||
tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>,
|
||||
}
|
||||
|
Reference in New Issue
Block a user