2023-08-15 18:19:03 +02:00
|
|
|
//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for WIZnet ethernet chips.
|
2023-05-09 01:51:08 +02:00
|
|
|
#![no_std]
|
2023-08-15 17:50:56 +02:00
|
|
|
#![feature(async_fn_in_trait)]
|
2023-06-29 19:51:16 +02:00
|
|
|
|
2023-08-15 17:50:56 +02:00
|
|
|
pub mod chip;
|
2023-05-09 01:51:08 +02:00
|
|
|
mod device;
|
|
|
|
|
|
|
|
use embassy_futures::select::{select, Either};
|
|
|
|
use embassy_net_driver_channel as ch;
|
|
|
|
use embassy_net_driver_channel::driver::LinkState;
|
2023-10-15 01:57:25 +02:00
|
|
|
use embassy_time::Timer;
|
2023-05-09 01:51:08 +02:00
|
|
|
use embedded_hal::digital::OutputPin;
|
|
|
|
use embedded_hal_async::digital::Wait;
|
|
|
|
use embedded_hal_async::spi::SpiDevice;
|
2023-05-31 01:01:30 +02:00
|
|
|
|
2023-08-15 17:50:56 +02:00
|
|
|
use crate::chip::Chip;
|
|
|
|
use crate::device::WiznetDevice;
|
|
|
|
|
2023-05-09 01:51:08 +02:00
|
|
|
const MTU: usize = 1514;
|
|
|
|
|
2023-08-15 18:19:03 +02:00
|
|
|
/// Type alias for the embassy-net driver.
|
2023-05-09 01:51:08 +02:00
|
|
|
pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
|
|
|
|
|
|
|
|
/// Internal state for the embassy-net integration.
|
|
|
|
pub struct State<const N_RX: usize, const N_TX: usize> {
|
|
|
|
ch_state: ch::State<MTU, N_RX, N_TX>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
|
|
|
|
/// Create a new `State`.
|
|
|
|
pub const fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
ch_state: ch::State::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-15 18:19:03 +02:00
|
|
|
/// Background runner for the driver.
|
2023-05-09 01:51:08 +02:00
|
|
|
///
|
2023-08-15 18:19:03 +02:00
|
|
|
/// You must call `.run()` in a background task for the driver to operate.
|
2023-08-15 17:50:56 +02:00
|
|
|
pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> {
|
|
|
|
mac: WiznetDevice<C, SPI>,
|
2023-05-09 01:51:08 +02:00
|
|
|
ch: ch::Runner<'d, MTU>,
|
|
|
|
int: INT,
|
|
|
|
_reset: RST,
|
|
|
|
}
|
|
|
|
|
2023-08-15 18:19:03 +02:00
|
|
|
/// You must call this in a background task for the driver to operate.
|
2023-08-15 17:50:56 +02:00
|
|
|
impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> {
|
2023-05-09 01:51:08 +02:00
|
|
|
pub async fn run(mut self) -> ! {
|
|
|
|
let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
|
|
|
|
loop {
|
|
|
|
if self.mac.is_link_up().await {
|
|
|
|
state_chan.set_link_state(LinkState::Up);
|
|
|
|
loop {
|
|
|
|
match select(
|
|
|
|
async {
|
|
|
|
self.int.wait_for_low().await.ok();
|
|
|
|
rx_chan.rx_buf().await
|
|
|
|
},
|
|
|
|
tx_chan.tx_buf(),
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
{
|
|
|
|
Either::First(p) => {
|
|
|
|
if let Ok(n) = self.mac.read_frame(p).await {
|
|
|
|
rx_chan.rx_done(n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Either::Second(p) => {
|
|
|
|
self.mac.write_frame(p).await.ok();
|
|
|
|
tx_chan.tx_done();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
state_chan.set_link_state(LinkState::Down);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-15 18:19:03 +02:00
|
|
|
/// Create a Wiznet ethernet chip driver for [`embassy-net`](https://crates.io/crates/embassy-net).
|
|
|
|
///
|
|
|
|
/// This returns two structs:
|
|
|
|
/// - a `Device` that you must pass to the `embassy-net` stack.
|
|
|
|
/// - a `Runner`. You must call `.run()` on it in a background task.
|
2023-08-15 17:50:56 +02:00
|
|
|
pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin>(
|
2023-05-09 01:51:08 +02:00
|
|
|
mac_addr: [u8; 6],
|
|
|
|
state: &'a mut State<N_RX, N_TX>,
|
|
|
|
spi_dev: SPI,
|
|
|
|
int: INT,
|
|
|
|
mut reset: RST,
|
2023-08-15 17:50:56 +02:00
|
|
|
) -> (Device<'a>, Runner<'a, C, SPI, INT, RST>) {
|
2023-08-15 18:19:03 +02:00
|
|
|
// Reset the chip.
|
2023-05-09 01:51:08 +02:00
|
|
|
reset.set_low().ok();
|
|
|
|
// Ensure the reset is registered.
|
2023-10-15 01:57:25 +02:00
|
|
|
Timer::after_millis(1).await;
|
2023-05-09 01:51:08 +02:00
|
|
|
reset.set_high().ok();
|
2023-08-15 18:19:03 +02:00
|
|
|
|
|
|
|
// Wait for PLL lock. Some chips are slower than others.
|
|
|
|
// Slowest is w5100s which is 100ms, so let's just wait that.
|
2023-10-15 01:57:25 +02:00
|
|
|
Timer::after_millis(100).await;
|
2023-05-09 01:51:08 +02:00
|
|
|
|
2023-08-15 17:50:56 +02:00
|
|
|
let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap();
|
2023-05-09 01:51:08 +02:00
|
|
|
|
2023-07-31 10:40:48 +02:00
|
|
|
let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr));
|
2023-05-09 01:51:08 +02:00
|
|
|
(
|
|
|
|
device,
|
|
|
|
Runner {
|
|
|
|
ch: runner,
|
|
|
|
mac,
|
|
|
|
int,
|
|
|
|
_reset: reset,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|