diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index b722bdd71..6cd57f68a 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -53,6 +53,9 @@ impl<'a> Control<'a> { debug!("wait for init event..."); self.shared.init_wait().await; + debug!("set heartbeat"); + self.set_heartbeat(10).await?; + debug!("set wifi mode"); self.set_wifi_mode(WifiMode::Sta as _).await?; @@ -83,6 +86,13 @@ impl<'a> Control<'a> { Ok(()) } + /// duration in seconds, clamped to [10, 3600] + async fn set_heartbeat(&mut self, duration: u32) -> Result<(), Error> { + let req = proto::CtrlMsgReqConfigHeartbeat { enable: true, duration }; + ioctl!(self, ReqConfigHeartbeat, RespConfigHeartbeat, req, resp); + Ok(()) + } + async fn get_mac_addr(&mut self) -> Result<[u8; 6], Error> { let req = proto::CtrlMsgReqGetMacAddress { mode: WifiMode::Sta as _, diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index c2d9d6097..4a318b20d 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -1,7 +1,8 @@ #![no_std] -use embassy_futures::select::{select3, Either3}; +use embassy_futures::select::{select4, Either4}; use embassy_net_driver_channel as ch; +use embassy_net_driver_channel::driver::LinkState; use embassy_time::{Duration, Instant, Timer}; use embedded_hal::digital::{InputPin, OutputPin}; use embedded_hal_async::digital::Wait; @@ -94,6 +95,7 @@ enum InterfaceType { } const MAX_SPI_BUFFER_SIZE: usize = 1600; +const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20); pub struct State { shared: Shared, @@ -135,6 +137,7 @@ where ready, reset, spi, + heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP, }; runner.init().await; @@ -147,6 +150,7 @@ pub struct Runner<'a, SPI, IN, OUT> { shared: &'a Shared, next_seq: u16, + heartbeat_deadline: Instant, spi: SPI, handshake: IN, @@ -178,9 +182,10 @@ where let ioctl = self.shared.ioctl_wait_pending(); let tx = self.ch.tx_buf(); let ev = async { self.ready.wait_for_high().await.unwrap() }; + let hb = Timer::at(self.heartbeat_deadline); - match select3(ioctl, tx, ev).await { - Either3::First(PendingIoctl { buf, req_len }) => { + match select4(ioctl, tx, ev, hb).await { + Either4::First(PendingIoctl { buf, req_len }) => { tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02"); tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes()); tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]); @@ -199,7 +204,7 @@ where header.checksum = checksum(&tx_buf[..26 + req_len]); tx_buf[0..12].copy_from_slice(&header.to_bytes()); } - Either3::Second(packet) => { + Either4::Second(packet) => { tx_buf[12..][..packet.len()].copy_from_slice(packet); let mut header = PayloadHeader { @@ -218,9 +223,12 @@ where self.ch.tx_done(); } - Either3::Third(()) => { + Either4::Third(()) => { tx_buf[..PayloadHeader::SIZE].fill(0); } + Either4::Fourth(()) => { + panic!("heartbeat from esp32 stopped") + } } if tx_buf[0] != 0 { @@ -309,7 +317,7 @@ where } } - fn handle_event(&self, data: &[u8]) { + fn handle_event(&mut self, data: &[u8]) { let Ok(event) = noproto::read::(data) else { warn!("failed to parse event"); return; @@ -324,6 +332,7 @@ where match payload { CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(), + CtrlMsgPayload::EventHeartbeat(_) => self.heartbeat_deadline = Instant::now() + HEARTBEAT_MAX_GAP, CtrlMsgPayload::EventStationDisconnectFromAp(e) => { info!("disconnected, code {}", e.resp); self.state_ch.set_link_state(LinkState::Down);