diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index 37f220da..b722bdd7 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -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(()) } } diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index 96fddce5..b1fa775c 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -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 { diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index e114e50b..a60822fd 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -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 { diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index 16055fae..4b221a81 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -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);