net-esp-hosted: sane error handling in control requests.

This commit is contained in:
Dario Nieuwenhuis 2023-08-17 00:11:15 +02:00
parent 2a4ebdc150
commit 065b0f34af
4 changed files with 79 additions and 64 deletions

View file

@ -5,9 +5,12 @@ use heapless::String;
use crate::ioctl::Shared;
use crate::proto::{self, CtrlMsg};
#[derive(Debug)]
pub struct Error {
pub status: u32,
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
Failed(u32),
Timeout,
Internal,
}
pub struct Control<'a> {
@ -23,58 +26,68 @@ enum WifiMode {
ApSta = 3,
}
macro_rules! ioctl {
($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => {
let mut msg = proto::CtrlMsg {
msg_id: proto::CtrlMsgId::$req_variant as _,
msg_type: proto::CtrlMsgType::Req as _,
payload: Some(proto::CtrlMsgPayload::$req_variant($req)),
};
$self.ioctl(&mut msg).await?;
let Some(proto::CtrlMsgPayload::$resp_variant($resp)) = msg.payload else {
warn!("unexpected response variant");
return Err(Error::Internal);
};
if $resp.resp != 0 {
return Err(Error::Failed($resp.resp));
}
};
}
impl<'a> Control<'a> {
pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self {
Self { state_ch, shared }
}
pub async fn init(&mut self) {
pub async fn init(&mut self) -> Result<(), Error> {
debug!("wait for init event...");
self.shared.init_wait().await;
debug!("set wifi mode");
self.set_wifi_mode(WifiMode::Sta as _).await;
self.set_wifi_mode(WifiMode::Sta as _).await?;
let mac_addr = self.get_mac_addr().await;
let mac_addr = self.get_mac_addr().await?;
debug!("mac addr: {:02x}", mac_addr);
self.state_ch.set_ethernet_address(mac_addr);
Ok(())
}
pub async fn join(&mut self, ssid: &str, password: &str) {
let req = proto::CtrlMsg {
msg_id: proto::CtrlMsgId::ReqConnectAp as _,
msg_type: proto::CtrlMsgType::Req as _,
payload: Some(proto::CtrlMsgPayload::ReqConnectAp(proto::CtrlMsgReqConnectAp {
ssid: String::from(ssid),
pwd: String::from(password),
bssid: String::new(),
listen_interval: 3,
is_wpa3_supported: false,
})),
pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> {
let req = proto::CtrlMsgReqConnectAp {
ssid: String::from(ssid),
pwd: String::from(password),
bssid: String::new(),
listen_interval: 3,
is_wpa3_supported: false,
};
let resp = self.ioctl(req).await;
let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else {
panic!("unexpected resp")
};
assert_eq!(resp.resp, 0);
ioctl!(self, ReqConnectAp, RespConnectAp, req, resp);
self.state_ch.set_link_state(LinkState::Up);
Ok(())
}
async fn get_mac_addr(&mut self) -> [u8; 6] {
let req = proto::CtrlMsg {
msg_id: proto::CtrlMsgId::ReqGetMacAddress as _,
msg_type: proto::CtrlMsgType::Req as _,
payload: Some(proto::CtrlMsgPayload::ReqGetMacAddress(
proto::CtrlMsgReqGetMacAddress {
mode: WifiMode::Sta as _,
},
)),
pub async fn disconnect(&mut self) -> Result<(), Error> {
let req = proto::CtrlMsgReqGetStatus {};
ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp);
self.state_ch.set_link_state(LinkState::Up);
Ok(())
}
async fn get_mac_addr(&mut self) -> Result<[u8; 6], Error> {
let req = proto::CtrlMsgReqGetMacAddress {
mode: WifiMode::Sta as _,
};
let resp = self.ioctl(req).await;
let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else {
panic!("unexpected resp")
};
assert_eq!(resp.resp, 0);
ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp);
// WHY IS THIS A STRING? WHYYYY
fn nibble_from_hex(b: u8) -> u8 {
@ -88,32 +101,32 @@ impl<'a> Control<'a> {
let mac = resp.mac.as_bytes();
let mut res = [0; 6];
assert_eq!(mac.len(), 17);
if mac.len() != 17 {
warn!("unexpected MAC respnse length");
return Err(Error::Internal);
}
for (i, b) in res.iter_mut().enumerate() {
*b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1])
}
res
Ok(res)
}
async fn set_wifi_mode(&mut self, mode: u32) {
let req = proto::CtrlMsg {
msg_id: proto::CtrlMsgId::ReqSetWifiMode as _,
msg_type: proto::CtrlMsgType::Req as _,
payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })),
};
let resp = self.ioctl(req).await;
let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else {
panic!("unexpected resp")
};
assert_eq!(resp.resp, 0);
async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> {
let req = proto::CtrlMsgReqSetMode { mode };
ioctl!(self, ReqSetWifiMode, RespSetWifiMode, req, resp);
Ok(())
}
async fn ioctl(&mut self, req: CtrlMsg) -> CtrlMsg {
debug!("ioctl req: {:?}", &req);
async fn ioctl(&mut self, msg: &mut CtrlMsg) -> Result<(), Error> {
debug!("ioctl req: {:?}", &msg);
let mut buf = [0u8; 128];
let req_len = noproto::write(&req, &mut buf).unwrap();
let req_len = noproto::write(msg, &mut buf).map_err(|_| {
warn!("failed to serialize control request");
Error::Internal
})?;
struct CancelOnDrop<'a>(&'a Shared);
@ -135,9 +148,12 @@ impl<'a> Control<'a> {
ioctl.defuse();
let res = noproto::read(&buf[..resp_len]).unwrap();
debug!("ioctl resp: {:?}", &res);
*msg = noproto::read(&buf[..resp_len]).map_err(|_| {
warn!("failed to serialize control request");
Error::Internal
})?;
debug!("ioctl resp: {:?}", msg);
res
Ok(())
}
}

View file

@ -1,17 +1,14 @@
#![no_std]
use control::Control;
use embassy_futures::select::{select3, Either3};
use embassy_net_driver_channel as ch;
use embassy_time::{Duration, Instant, Timer};
use embedded_hal::digital::{InputPin, OutputPin};
use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::SpiDevice;
use ioctl::Shared;
use proto::CtrlMsg;
use crate::ioctl::PendingIoctl;
use crate::proto::CtrlMsgPayload;
use crate::ioctl::{PendingIoctl, Shared};
use crate::proto::{CtrlMsg, CtrlMsgPayload};
mod proto;
@ -21,6 +18,8 @@ mod fmt;
mod control;
mod ioctl;
pub use control::*;
const MTU: usize = 1514;
macro_rules! impl_bytes {

View file

@ -72,8 +72,8 @@ async fn main(spawner: Spawner) {
unwrap!(spawner.spawn(wifi_task(runner)));
control.init().await;
control.join(WIFI_NETWORK, WIFI_PASSWORD).await;
unwrap!(control.init().await);
unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await);
let config = embassy_net::Config::dhcpv4(Default::default());
// let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {

View file

@ -76,8 +76,8 @@ async fn main(spawner: Spawner) {
unwrap!(spawner.spawn(wifi_task(runner)));
control.init().await;
control.join(WIFI_NETWORK, WIFI_PASSWORD).await;
unwrap!(control.init().await);
unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await);
// Generate random seed
let mut rng = Rng::new(p.RNG, Irqs);