//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip. #![no_std] mod device; mod socket; mod spi; use embassy_futures::select::{select, Either}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embassy_time::{Duration, Timer}; use embedded_hal::digital::OutputPin; use embedded_hal_async::digital::Wait; use embedded_hal_async::spi::SpiDevice; use crate::device::W5500; const MTU: usize = 1514; /// Type alias for the embassy-net driver for W5500 pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; /// Internal state for the embassy-net integration. pub struct State { ch_state: ch::State, } impl State { /// Create a new `State`. pub const fn new() -> Self { Self { ch_state: ch::State::new(), } } } /// Background runner for the W5500. /// /// You must call `.run()` in a background task for the W5500 to operate. pub struct Runner<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> { mac: W5500, ch: ch::Runner<'d, MTU>, int: INT, _reset: RST, } /// You must call this in a background task for the W5500 to operate. impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { 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); } } } } /// Obtain a driver for using the W5500 with [`embassy-net`](https://crates.io/crates/embassy-net). pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>( mac_addr: [u8; 6], state: &'a mut State, spi_dev: SPI, int: INT, mut reset: RST, ) -> (Device<'a>, Runner<'a, SPI, INT, RST>) { // Reset the W5500. reset.set_low().ok(); // Ensure the reset is registered. Timer::after(Duration::from_millis(1)).await; reset.set_high().ok(); // Wait for the W5500 to achieve PLL lock. Timer::after(Duration::from_millis(2)).await; let mac = W5500::new(spi_dev, mac_addr).await.unwrap(); let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr)); ( device, Runner { ch: runner, mac, int, _reset: reset, }, ) }