net-esp-hosted: enable heartbeats from esp32 to detect if it crashes.
This commit is contained in:
parent
ef7523e5b7
commit
1cb76e0d99
@ -53,6 +53,9 @@ impl<'a> Control<'a> {
|
|||||||
debug!("wait for init event...");
|
debug!("wait for init event...");
|
||||||
self.shared.init_wait().await;
|
self.shared.init_wait().await;
|
||||||
|
|
||||||
|
debug!("set heartbeat");
|
||||||
|
self.set_heartbeat(10).await?;
|
||||||
|
|
||||||
debug!("set wifi mode");
|
debug!("set wifi mode");
|
||||||
self.set_wifi_mode(WifiMode::Sta as _).await?;
|
self.set_wifi_mode(WifiMode::Sta as _).await?;
|
||||||
|
|
||||||
@ -83,6 +86,13 @@ impl<'a> Control<'a> {
|
|||||||
Ok(())
|
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> {
|
async fn get_mac_addr(&mut self) -> Result<[u8; 6], Error> {
|
||||||
let req = proto::CtrlMsgReqGetMacAddress {
|
let req = proto::CtrlMsgReqGetMacAddress {
|
||||||
mode: WifiMode::Sta as _,
|
mode: WifiMode::Sta as _,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#![no_std]
|
#![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 as ch;
|
||||||
|
use embassy_net_driver_channel::driver::LinkState;
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
use embedded_hal::digital::{InputPin, OutputPin};
|
use embedded_hal::digital::{InputPin, OutputPin};
|
||||||
use embedded_hal_async::digital::Wait;
|
use embedded_hal_async::digital::Wait;
|
||||||
@ -94,6 +95,7 @@ enum InterfaceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MAX_SPI_BUFFER_SIZE: usize = 1600;
|
const MAX_SPI_BUFFER_SIZE: usize = 1600;
|
||||||
|
const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20);
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
shared: Shared,
|
shared: Shared,
|
||||||
@ -135,6 +137,7 @@ where
|
|||||||
ready,
|
ready,
|
||||||
reset,
|
reset,
|
||||||
spi,
|
spi,
|
||||||
|
heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP,
|
||||||
};
|
};
|
||||||
runner.init().await;
|
runner.init().await;
|
||||||
|
|
||||||
@ -147,6 +150,7 @@ pub struct Runner<'a, SPI, IN, OUT> {
|
|||||||
shared: &'a Shared,
|
shared: &'a Shared,
|
||||||
|
|
||||||
next_seq: u16,
|
next_seq: u16,
|
||||||
|
heartbeat_deadline: Instant,
|
||||||
|
|
||||||
spi: SPI,
|
spi: SPI,
|
||||||
handshake: IN,
|
handshake: IN,
|
||||||
@ -178,9 +182,10 @@ where
|
|||||||
let ioctl = self.shared.ioctl_wait_pending();
|
let ioctl = self.shared.ioctl_wait_pending();
|
||||||
let tx = self.ch.tx_buf();
|
let tx = self.ch.tx_buf();
|
||||||
let ev = async { self.ready.wait_for_high().await.unwrap() };
|
let ev = async { self.ready.wait_for_high().await.unwrap() };
|
||||||
|
let hb = Timer::at(self.heartbeat_deadline);
|
||||||
|
|
||||||
match select3(ioctl, tx, ev).await {
|
match select4(ioctl, tx, ev, hb).await {
|
||||||
Either3::First(PendingIoctl { buf, req_len }) => {
|
Either4::First(PendingIoctl { buf, req_len }) => {
|
||||||
tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02");
|
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[24..26].copy_from_slice(&(req_len as u16).to_le_bytes());
|
||||||
tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]);
|
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]);
|
header.checksum = checksum(&tx_buf[..26 + req_len]);
|
||||||
tx_buf[0..12].copy_from_slice(&header.to_bytes());
|
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);
|
tx_buf[12..][..packet.len()].copy_from_slice(packet);
|
||||||
|
|
||||||
let mut header = PayloadHeader {
|
let mut header = PayloadHeader {
|
||||||
@ -218,9 +223,12 @@ where
|
|||||||
|
|
||||||
self.ch.tx_done();
|
self.ch.tx_done();
|
||||||
}
|
}
|
||||||
Either3::Third(()) => {
|
Either4::Third(()) => {
|
||||||
tx_buf[..PayloadHeader::SIZE].fill(0);
|
tx_buf[..PayloadHeader::SIZE].fill(0);
|
||||||
}
|
}
|
||||||
|
Either4::Fourth(()) => {
|
||||||
|
panic!("heartbeat from esp32 stopped")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tx_buf[0] != 0 {
|
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::<CtrlMsg>(data) else {
|
let Ok(event) = noproto::read::<CtrlMsg>(data) else {
|
||||||
warn!("failed to parse event");
|
warn!("failed to parse event");
|
||||||
return;
|
return;
|
||||||
@ -324,6 +332,7 @@ where
|
|||||||
|
|
||||||
match payload {
|
match payload {
|
||||||
CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(),
|
CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(),
|
||||||
|
CtrlMsgPayload::EventHeartbeat(_) => self.heartbeat_deadline = Instant::now() + HEARTBEAT_MAX_GAP,
|
||||||
CtrlMsgPayload::EventStationDisconnectFromAp(e) => {
|
CtrlMsgPayload::EventStationDisconnectFromAp(e) => {
|
||||||
info!("disconnected, code {}", e.resp);
|
info!("disconnected, code {}", e.resp);
|
||||||
self.state_ch.set_link_state(LinkState::Down);
|
self.state_ch.set_link_state(LinkState::Down);
|
||||||
|
Loading…
Reference in New Issue
Block a user