aboutsummaryrefslogtreecommitdiff
path: root/embassy-net-esp-hosted/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-net-esp-hosted/src/lib.rs')
-rw-r--r--embassy-net-esp-hosted/src/lib.rs78
1 files changed, 41 insertions, 37 deletions
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index f05e2a70a..2c7377281 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -1,27 +1,34 @@
1#![no_std] 1#![no_std]
2#![doc = include_str!("../README.md")] 2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)] 3#![warn(missing_docs)]
4#![allow(async_fn_in_trait)]
4 5
5use embassy_futures::select::{select4, Either4}; 6use embassy_futures::select::{Either4, select4};
6use embassy_net_driver_channel as ch; 7use embassy_net_driver_channel as ch;
7use embassy_net_driver_channel::driver::LinkState; 8use embassy_net_driver_channel::driver::LinkState;
8use embassy_time::{Duration, Instant, Timer}; 9use embassy_time::{Duration, Instant, Timer};
9use embedded_hal::digital::{InputPin, OutputPin}; 10use embedded_hal::digital::OutputPin;
10use embedded_hal_async::digital::Wait;
11use embedded_hal_async::spi::SpiDevice;
12 11
13use crate::ioctl::{PendingIoctl, Shared}; 12use crate::ioctl::{PendingIoctl, Shared};
14use crate::proto::{CtrlMsg, CtrlMsgPayload}; 13use crate::proto::{CtrlMsg, CtrlMsg_};
15 14
15#[allow(unused)]
16#[allow(non_snake_case)]
17#[allow(non_camel_case_types)]
18#[allow(non_upper_case_globals)]
19#[allow(missing_docs)]
20#[allow(clippy::all)]
16mod proto; 21mod proto;
17 22
18// must be first 23// must be first
19mod fmt; 24mod fmt;
20 25
21mod control; 26mod control;
27mod iface;
22mod ioctl; 28mod ioctl;
23 29
24pub use control::*; 30pub use control::*;
31pub use iface::*;
25 32
26const MTU: usize = 1514; 33const MTU: usize = 1514;
27 34
@@ -118,20 +125,17 @@ impl State {
118/// Type alias for network driver. 125/// Type alias for network driver.
119pub type NetDriver<'a> = ch::Device<'a, MTU>; 126pub type NetDriver<'a> = ch::Device<'a, MTU>;
120 127
121/// Create a new esp-hosted driver using the provided state, SPI peripheral and pins. 128/// Create a new esp-hosted driver using the provided state, interface, and reset pin.
122/// 129///
123/// Returns a device handle for interfacing with embassy-net, a control handle for 130/// Returns a device handle for interfacing with embassy-net, a control handle for
124/// interacting with the driver, and a runner for communicating with the WiFi device. 131/// interacting with the driver, and a runner for communicating with the WiFi device.
125pub async fn new<'a, SPI, IN, OUT>( 132pub async fn new<'a, I, OUT>(
126 state: &'a mut State, 133 state: &'a mut State,
127 spi: SPI, 134 iface: I,
128 handshake: IN,
129 ready: IN,
130 reset: OUT, 135 reset: OUT,
131) -> (NetDriver<'a>, Control<'a>, Runner<'a, SPI, IN, OUT>) 136) -> (NetDriver<'a>, Control<'a>, Runner<'a, I, OUT>)
132where 137where
133 SPI: SpiDevice, 138 I: Interface,
134 IN: InputPin + Wait,
135 OUT: OutputPin, 139 OUT: OutputPin,
136{ 140{
137 let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6])); 141 let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
@@ -142,10 +146,8 @@ where
142 state_ch, 146 state_ch,
143 shared: &state.shared, 147 shared: &state.shared,
144 next_seq: 1, 148 next_seq: 1,
145 handshake,
146 ready,
147 reset, 149 reset,
148 spi, 150 iface,
149 heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP, 151 heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP,
150 }; 152 };
151 153
@@ -153,7 +155,7 @@ where
153} 155}
154 156
155/// Runner for communicating with the WiFi device. 157/// Runner for communicating with the WiFi device.
156pub struct Runner<'a, SPI, IN, OUT> { 158pub struct Runner<'a, I, OUT> {
157 ch: ch::Runner<'a, MTU>, 159 ch: ch::Runner<'a, MTU>,
158 state_ch: ch::StateRunner<'a>, 160 state_ch: ch::StateRunner<'a>,
159 shared: &'a Shared, 161 shared: &'a Shared,
@@ -161,16 +163,13 @@ pub struct Runner<'a, SPI, IN, OUT> {
161 next_seq: u16, 163 next_seq: u16,
162 heartbeat_deadline: Instant, 164 heartbeat_deadline: Instant,
163 165
164 spi: SPI, 166 iface: I,
165 handshake: IN,
166 ready: IN,
167 reset: OUT, 167 reset: OUT,
168} 168}
169 169
170impl<'a, SPI, IN, OUT> Runner<'a, SPI, IN, OUT> 170impl<'a, I, OUT> Runner<'a, I, OUT>
171where 171where
172 SPI: SpiDevice, 172 I: Interface,
173 IN: InputPin + Wait,
174 OUT: OutputPin, 173 OUT: OutputPin,
175{ 174{
176 /// Run the packet processing. 175 /// Run the packet processing.
@@ -185,11 +184,11 @@ where
185 let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE]; 184 let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
186 185
187 loop { 186 loop {
188 self.handshake.wait_for_high().await.unwrap(); 187 self.iface.wait_for_handshake().await;
189 188
190 let ioctl = self.shared.ioctl_wait_pending(); 189 let ioctl = self.shared.ioctl_wait_pending();
191 let tx = self.ch.tx_buf(); 190 let tx = self.ch.tx_buf();
192 let ev = async { self.ready.wait_for_high().await.unwrap() }; 191 let ev = async { self.iface.wait_for_ready().await };
193 let hb = Timer::at(self.heartbeat_deadline); 192 let hb = Timer::at(self.heartbeat_deadline);
194 193
195 match select4(ioctl, tx, ev, hb).await { 194 match select4(ioctl, tx, ev, hb).await {
@@ -235,6 +234,11 @@ where
235 tx_buf[..PayloadHeader::SIZE].fill(0); 234 tx_buf[..PayloadHeader::SIZE].fill(0);
236 } 235 }
237 Either4::Fourth(()) => { 236 Either4::Fourth(()) => {
237 // Extend the deadline if initializing
238 if let ioctl::ControlState::Reboot = self.shared.state() {
239 self.heartbeat_deadline = Instant::now() + HEARTBEAT_MAX_GAP;
240 continue;
241 }
238 panic!("heartbeat from esp32 stopped") 242 panic!("heartbeat from esp32 stopped")
239 } 243 }
240 } 244 }
@@ -243,15 +247,9 @@ where
243 trace!("tx: {:02x}", &tx_buf[..40]); 247 trace!("tx: {:02x}", &tx_buf[..40]);
244 } 248 }
245 249
246 self.spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); 250 self.iface.transfer(&mut rx_buf, &tx_buf).await;
247 251
248 // The esp-hosted firmware deasserts the HANSHAKE pin a few us AFTER ending the SPI transfer
249 // If we check it again too fast, we'll see it's high from the previous transfer, and if we send it
250 // data it will get lost.
251 // Make sure we check it after 100us at minimum.
252 let delay_until = Instant::now() + Duration::from_micros(100);
253 self.handle_rx(&mut rx_buf); 252 self.handle_rx(&mut rx_buf);
254 Timer::at(delay_until).await;
255 } 253 }
256 } 254 }
257 255
@@ -326,10 +324,12 @@ where
326 } 324 }
327 325
328 fn handle_event(&mut self, data: &[u8]) { 326 fn handle_event(&mut self, data: &[u8]) {
329 let Ok(event) = noproto::read::<CtrlMsg>(data) else { 327 use micropb::MessageDecode;
328 let mut event = CtrlMsg::default();
329 if event.decode_from_bytes(data).is_err() {
330 warn!("failed to parse event"); 330 warn!("failed to parse event");
331 return; 331 return;
332 }; 332 }
333 333
334 debug!("event: {:?}", &event); 334 debug!("event: {:?}", &event);
335 335
@@ -339,9 +339,13 @@ where
339 }; 339 };
340 340
341 match payload { 341 match payload {
342 CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(), 342 CtrlMsg_::Payload::EventEspInit(_) => self.shared.init_done(),
343 CtrlMsgPayload::EventHeartbeat(_) => self.heartbeat_deadline = Instant::now() + HEARTBEAT_MAX_GAP, 343 CtrlMsg_::Payload::EventHeartbeat(_) => self.heartbeat_deadline = Instant::now() + HEARTBEAT_MAX_GAP,
344 CtrlMsgPayload::EventStationDisconnectFromAp(e) => { 344 CtrlMsg_::Payload::EventStationConnectedToAp(e) => {
345 info!("connected, code {}", e.resp);
346 self.state_ch.set_link_state(LinkState::Up);
347 }
348 CtrlMsg_::Payload::EventStationDisconnectFromAp(e) => {
345 info!("disconnected, code {}", e.resp); 349 info!("disconnected, code {}", e.resp);
346 self.state_ch.set_link_state(LinkState::Down); 350 self.state_ch.set_link_state(LinkState::Down);
347 } 351 }