aboutsummaryrefslogtreecommitdiff
path: root/embassy-net-wiznet/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-net-wiznet/src/lib.rs')
-rw-r--r--embassy-net-wiznet/src/lib.rs117
1 files changed, 117 insertions, 0 deletions
diff --git a/embassy-net-wiznet/src/lib.rs b/embassy-net-wiznet/src/lib.rs
new file mode 100644
index 000000000..3030dfb90
--- /dev/null
+++ b/embassy-net-wiznet/src/lib.rs
@@ -0,0 +1,117 @@
1//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for WIZnet ethernet chips.
2#![no_std]
3#![feature(async_fn_in_trait)]
4
5pub mod chip;
6mod device;
7
8use embassy_futures::select::{select, Either};
9use embassy_net_driver_channel as ch;
10use embassy_net_driver_channel::driver::LinkState;
11use embassy_time::{Duration, Timer};
12use embedded_hal::digital::OutputPin;
13use embedded_hal_async::digital::Wait;
14use embedded_hal_async::spi::SpiDevice;
15
16use crate::chip::Chip;
17use crate::device::WiznetDevice;
18
19const MTU: usize = 1514;
20
21/// Type alias for the embassy-net driver.
22pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
23
24/// Internal state for the embassy-net integration.
25pub struct State<const N_RX: usize, const N_TX: usize> {
26 ch_state: ch::State<MTU, N_RX, N_TX>,
27}
28
29impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
30 /// Create a new `State`.
31 pub const fn new() -> Self {
32 Self {
33 ch_state: ch::State::new(),
34 }
35 }
36}
37
38/// Background runner for the driver.
39///
40/// You must call `.run()` in a background task for the driver to operate.
41pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> {
42 mac: WiznetDevice<C, SPI>,
43 ch: ch::Runner<'d, MTU>,
44 int: INT,
45 _reset: RST,
46}
47
48/// You must call this in a background task for the driver to operate.
49impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> {
50 pub async fn run(mut self) -> ! {
51 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
52 loop {
53 if self.mac.is_link_up().await {
54 state_chan.set_link_state(LinkState::Up);
55 loop {
56 match select(
57 async {
58 self.int.wait_for_low().await.ok();
59 rx_chan.rx_buf().await
60 },
61 tx_chan.tx_buf(),
62 )
63 .await
64 {
65 Either::First(p) => {
66 if let Ok(n) = self.mac.read_frame(p).await {
67 rx_chan.rx_done(n);
68 }
69 }
70 Either::Second(p) => {
71 self.mac.write_frame(p).await.ok();
72 tx_chan.tx_done();
73 }
74 }
75 }
76 } else {
77 state_chan.set_link_state(LinkState::Down);
78 }
79 }
80 }
81}
82
83/// Create a Wiznet ethernet chip driver for [`embassy-net`](https://crates.io/crates/embassy-net).
84///
85/// This returns two structs:
86/// - a `Device` that you must pass to the `embassy-net` stack.
87/// - a `Runner`. You must call `.run()` on it in a background task.
88pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin>(
89 mac_addr: [u8; 6],
90 state: &'a mut State<N_RX, N_TX>,
91 spi_dev: SPI,
92 int: INT,
93 mut reset: RST,
94) -> (Device<'a>, Runner<'a, C, SPI, INT, RST>) {
95 // Reset the chip.
96 reset.set_low().ok();
97 // Ensure the reset is registered.
98 Timer::after(Duration::from_millis(1)).await;
99 reset.set_high().ok();
100
101 // Wait for PLL lock. Some chips are slower than others.
102 // Slowest is w5100s which is 100ms, so let's just wait that.
103 Timer::after(Duration::from_millis(100)).await;
104
105 let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap();
106
107 let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr));
108 (
109 device,
110 Runner {
111 ch: runner,
112 mac,
113 int,
114 _reset: reset,
115 },
116 )
117}