aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-08-18 14:21:10 +0000
committerGitHub <[email protected]>2023-08-18 14:21:10 +0000
commitd327b626e30b5073cf3534c44b608bdb6598222c (patch)
treeb0f8d7e9cd28ee891e7573ae433f1c60606c4aab
parentf48d13a16a5bc9b1027ea39bfd86d548b460edd5 (diff)
parent1cb76e0d99f8da12891491b31176c8247a7a81a4 (diff)
Merge pull request #1788 from embassy-rs/esp-hosted-cleanup
net-esp-hosted: misc improvements.
-rw-r--r--embassy-net-esp-hosted/src/control.rs136
-rw-r--r--embassy-net-esp-hosted/src/lib.rs36
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs4
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs4
4 files changed, 110 insertions, 70 deletions
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index 37f220da0..6cd57f68a 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -5,9 +5,12 @@ use heapless::String;
5use crate::ioctl::Shared; 5use crate::ioctl::Shared;
6use crate::proto::{self, CtrlMsg}; 6use crate::proto::{self, CtrlMsg};
7 7
8#[derive(Debug)] 8#[derive(Copy, Clone, PartialEq, Eq, Debug)]
9pub struct Error { 9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10 pub status: u32, 10pub enum Error {
11 Failed(u32),
12 Timeout,
13 Internal,
11} 14}
12 15
13pub struct Control<'a> { 16pub struct Control<'a> {
@@ -23,58 +26,78 @@ enum WifiMode {
23 ApSta = 3, 26 ApSta = 3,
24} 27}
25 28
29macro_rules! ioctl {
30 ($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => {
31 let mut msg = proto::CtrlMsg {
32 msg_id: proto::CtrlMsgId::$req_variant as _,
33 msg_type: proto::CtrlMsgType::Req as _,
34 payload: Some(proto::CtrlMsgPayload::$req_variant($req)),
35 };
36 $self.ioctl(&mut msg).await?;
37 let Some(proto::CtrlMsgPayload::$resp_variant($resp)) = msg.payload else {
38 warn!("unexpected response variant");
39 return Err(Error::Internal);
40 };
41 if $resp.resp != 0 {
42 return Err(Error::Failed($resp.resp));
43 }
44 };
45}
46
26impl<'a> Control<'a> { 47impl<'a> Control<'a> {
27 pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self { 48 pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self {
28 Self { state_ch, shared } 49 Self { state_ch, shared }
29 } 50 }
30 51
31 pub async fn init(&mut self) { 52 pub async fn init(&mut self) -> Result<(), Error> {
32 debug!("wait for init event..."); 53 debug!("wait for init event...");
33 self.shared.init_wait().await; 54 self.shared.init_wait().await;
34 55
56 debug!("set heartbeat");
57 self.set_heartbeat(10).await?;
58
35 debug!("set wifi mode"); 59 debug!("set wifi mode");
36 self.set_wifi_mode(WifiMode::Sta as _).await; 60 self.set_wifi_mode(WifiMode::Sta as _).await?;
37 61
38 let mac_addr = self.get_mac_addr().await; 62 let mac_addr = self.get_mac_addr().await?;
39 debug!("mac addr: {:02x}", mac_addr); 63 debug!("mac addr: {:02x}", mac_addr);
40 self.state_ch.set_ethernet_address(mac_addr); 64 self.state_ch.set_ethernet_address(mac_addr);
65
66 Ok(())
41 } 67 }
42 68
43 pub async fn join(&mut self, ssid: &str, password: &str) { 69 pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> {
44 let req = proto::CtrlMsg { 70 let req = proto::CtrlMsgReqConnectAp {
45 msg_id: proto::CtrlMsgId::ReqConnectAp as _, 71 ssid: String::from(ssid),
46 msg_type: proto::CtrlMsgType::Req as _, 72 pwd: String::from(password),
47 payload: Some(proto::CtrlMsgPayload::ReqConnectAp(proto::CtrlMsgReqConnectAp { 73 bssid: String::new(),
48 ssid: String::from(ssid), 74 listen_interval: 3,
49 pwd: String::from(password), 75 is_wpa3_supported: false,
50 bssid: String::new(),
51 listen_interval: 3,
52 is_wpa3_supported: false,
53 })),
54 };
55 let resp = self.ioctl(req).await;
56 let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else {
57 panic!("unexpected resp")
58 }; 76 };
59 assert_eq!(resp.resp, 0); 77 ioctl!(self, ReqConnectAp, RespConnectAp, req, resp);
60 self.state_ch.set_link_state(LinkState::Up); 78 self.state_ch.set_link_state(LinkState::Up);
79 Ok(())
61 } 80 }
62 81
63 async fn get_mac_addr(&mut self) -> [u8; 6] { 82 pub async fn disconnect(&mut self) -> Result<(), Error> {
64 let req = proto::CtrlMsg { 83 let req = proto::CtrlMsgReqGetStatus {};
65 msg_id: proto::CtrlMsgId::ReqGetMacAddress as _, 84 ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp);
66 msg_type: proto::CtrlMsgType::Req as _, 85 self.state_ch.set_link_state(LinkState::Up);
67 payload: Some(proto::CtrlMsgPayload::ReqGetMacAddress( 86 Ok(())
68 proto::CtrlMsgReqGetMacAddress { 87 }
69 mode: WifiMode::Sta as _, 88
70 }, 89 /// duration in seconds, clamped to [10, 3600]
71 )), 90 async fn set_heartbeat(&mut self, duration: u32) -> Result<(), Error> {
72 }; 91 let req = proto::CtrlMsgReqConfigHeartbeat { enable: true, duration };
73 let resp = self.ioctl(req).await; 92 ioctl!(self, ReqConfigHeartbeat, RespConfigHeartbeat, req, resp);
74 let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else { 93 Ok(())
75 panic!("unexpected resp") 94 }
95
96 async fn get_mac_addr(&mut self) -> Result<[u8; 6], Error> {
97 let req = proto::CtrlMsgReqGetMacAddress {
98 mode: WifiMode::Sta as _,
76 }; 99 };
77 assert_eq!(resp.resp, 0); 100 ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp);
78 101
79 // WHY IS THIS A STRING? WHYYYY 102 // WHY IS THIS A STRING? WHYYYY
80 fn nibble_from_hex(b: u8) -> u8 { 103 fn nibble_from_hex(b: u8) -> u8 {
@@ -88,32 +111,32 @@ impl<'a> Control<'a> {
88 111
89 let mac = resp.mac.as_bytes(); 112 let mac = resp.mac.as_bytes();
90 let mut res = [0; 6]; 113 let mut res = [0; 6];
91 assert_eq!(mac.len(), 17); 114 if mac.len() != 17 {
115 warn!("unexpected MAC respnse length");
116 return Err(Error::Internal);
117 }
92 for (i, b) in res.iter_mut().enumerate() { 118 for (i, b) in res.iter_mut().enumerate() {
93 *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1]) 119 *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1])
94 } 120 }
95 res 121 Ok(res)
96 } 122 }
97 123
98 async fn set_wifi_mode(&mut self, mode: u32) { 124 async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> {
99 let req = proto::CtrlMsg { 125 let req = proto::CtrlMsgReqSetMode { mode };
100 msg_id: proto::CtrlMsgId::ReqSetWifiMode as _, 126 ioctl!(self, ReqSetWifiMode, RespSetWifiMode, req, resp);
101 msg_type: proto::CtrlMsgType::Req as _, 127
102 payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })), 128 Ok(())
103 };
104 let resp = self.ioctl(req).await;
105 let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else {
106 panic!("unexpected resp")
107 };
108 assert_eq!(resp.resp, 0);
109 } 129 }
110 130
111 async fn ioctl(&mut self, req: CtrlMsg) -> CtrlMsg { 131 async fn ioctl(&mut self, msg: &mut CtrlMsg) -> Result<(), Error> {
112 debug!("ioctl req: {:?}", &req); 132 debug!("ioctl req: {:?}", &msg);
113 133
114 let mut buf = [0u8; 128]; 134 let mut buf = [0u8; 128];
115 135
116 let req_len = noproto::write(&req, &mut buf).unwrap(); 136 let req_len = noproto::write(msg, &mut buf).map_err(|_| {
137 warn!("failed to serialize control request");
138 Error::Internal
139 })?;
117 140
118 struct CancelOnDrop<'a>(&'a Shared); 141 struct CancelOnDrop<'a>(&'a Shared);
119 142
@@ -135,9 +158,12 @@ impl<'a> Control<'a> {
135 158
136 ioctl.defuse(); 159 ioctl.defuse();
137 160
138 let res = noproto::read(&buf[..resp_len]).unwrap(); 161 *msg = noproto::read(&buf[..resp_len]).map_err(|_| {
139 debug!("ioctl resp: {:?}", &res); 162 warn!("failed to serialize control request");
163 Error::Internal
164 })?;
165 debug!("ioctl resp: {:?}", msg);
140 166
141 res 167 Ok(())
142 } 168 }
143} 169}
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index 96fddce58..4a318b20d 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -1,17 +1,15 @@
1#![no_std] 1#![no_std]
2 2
3use control::Control; 3use embassy_futures::select::{select4, Either4};
4use embassy_futures::select::{select3, Either3};
5use embassy_net_driver_channel as ch; 4use embassy_net_driver_channel as ch;
5use embassy_net_driver_channel::driver::LinkState;
6use embassy_time::{Duration, Instant, Timer}; 6use embassy_time::{Duration, Instant, Timer};
7use embedded_hal::digital::{InputPin, OutputPin}; 7use embedded_hal::digital::{InputPin, OutputPin};
8use embedded_hal_async::digital::Wait; 8use embedded_hal_async::digital::Wait;
9use embedded_hal_async::spi::SpiDevice; 9use embedded_hal_async::spi::SpiDevice;
10use ioctl::Shared;
11use proto::CtrlMsg;
12 10
13use crate::ioctl::PendingIoctl; 11use crate::ioctl::{PendingIoctl, Shared};
14use crate::proto::CtrlMsgPayload; 12use crate::proto::{CtrlMsg, CtrlMsgPayload};
15 13
16mod proto; 14mod proto;
17 15
@@ -21,6 +19,8 @@ mod fmt;
21mod control; 19mod control;
22mod ioctl; 20mod ioctl;
23 21
22pub use control::*;
23
24const MTU: usize = 1514; 24const MTU: usize = 1514;
25 25
26macro_rules! impl_bytes { 26macro_rules! impl_bytes {
@@ -95,6 +95,7 @@ enum InterfaceType {
95} 95}
96 96
97const MAX_SPI_BUFFER_SIZE: usize = 1600; 97const MAX_SPI_BUFFER_SIZE: usize = 1600;
98const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20);
98 99
99pub struct State { 100pub struct State {
100 shared: Shared, 101 shared: Shared,
@@ -129,12 +130,14 @@ where
129 130
130 let mut runner = Runner { 131 let mut runner = Runner {
131 ch: ch_runner, 132 ch: ch_runner,
133 state_ch,
132 shared: &state.shared, 134 shared: &state.shared,
133 next_seq: 1, 135 next_seq: 1,
134 handshake, 136 handshake,
135 ready, 137 ready,
136 reset, 138 reset,
137 spi, 139 spi,
140 heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP,
138 }; 141 };
139 runner.init().await; 142 runner.init().await;
140 143
@@ -143,9 +146,11 @@ where
143 146
144pub struct Runner<'a, SPI, IN, OUT> { 147pub struct Runner<'a, SPI, IN, OUT> {
145 ch: ch::Runner<'a, MTU>, 148 ch: ch::Runner<'a, MTU>,
149 state_ch: ch::StateRunner<'a>,
146 shared: &'a Shared, 150 shared: &'a Shared,
147 151
148 next_seq: u16, 152 next_seq: u16,
153 heartbeat_deadline: Instant,
149 154
150 spi: SPI, 155 spi: SPI,
151 handshake: IN, 156 handshake: IN,
@@ -177,9 +182,10 @@ where
177 let ioctl = self.shared.ioctl_wait_pending(); 182 let ioctl = self.shared.ioctl_wait_pending();
178 let tx = self.ch.tx_buf(); 183 let tx = self.ch.tx_buf();
179 let ev = async { self.ready.wait_for_high().await.unwrap() }; 184 let ev = async { self.ready.wait_for_high().await.unwrap() };
185 let hb = Timer::at(self.heartbeat_deadline);
180 186
181 match select3(ioctl, tx, ev).await { 187 match select4(ioctl, tx, ev, hb).await {
182 Either3::First(PendingIoctl { buf, req_len }) => { 188 Either4::First(PendingIoctl { buf, req_len }) => {
183 tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02"); 189 tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02");
184 tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes()); 190 tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes());
185 tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]); 191 tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]);
@@ -198,7 +204,7 @@ where
198 header.checksum = checksum(&tx_buf[..26 + req_len]); 204 header.checksum = checksum(&tx_buf[..26 + req_len]);
199 tx_buf[0..12].copy_from_slice(&header.to_bytes()); 205 tx_buf[0..12].copy_from_slice(&header.to_bytes());
200 } 206 }
201 Either3::Second(packet) => { 207 Either4::Second(packet) => {
202 tx_buf[12..][..packet.len()].copy_from_slice(packet); 208 tx_buf[12..][..packet.len()].copy_from_slice(packet);
203 209
204 let mut header = PayloadHeader { 210 let mut header = PayloadHeader {
@@ -217,9 +223,12 @@ where
217 223
218 self.ch.tx_done(); 224 self.ch.tx_done();
219 } 225 }
220 Either3::Third(()) => { 226 Either4::Third(()) => {
221 tx_buf[..PayloadHeader::SIZE].fill(0); 227 tx_buf[..PayloadHeader::SIZE].fill(0);
222 } 228 }
229 Either4::Fourth(()) => {
230 panic!("heartbeat from esp32 stopped")
231 }
223 } 232 }
224 233
225 if tx_buf[0] != 0 { 234 if tx_buf[0] != 0 {
@@ -308,7 +317,7 @@ where
308 } 317 }
309 } 318 }
310 319
311 fn handle_event(&self, data: &[u8]) { 320 fn handle_event(&mut self, data: &[u8]) {
312 let Ok(event) = noproto::read::<CtrlMsg>(data) else { 321 let Ok(event) = noproto::read::<CtrlMsg>(data) else {
313 warn!("failed to parse event"); 322 warn!("failed to parse event");
314 return; 323 return;
@@ -323,6 +332,11 @@ where
323 332
324 match payload { 333 match payload {
325 CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(), 334 CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(),
335 CtrlMsgPayload::EventHeartbeat(_) => self.heartbeat_deadline = Instant::now() + HEARTBEAT_MAX_GAP,
336 CtrlMsgPayload::EventStationDisconnectFromAp(e) => {
337 info!("disconnected, code {}", e.resp);
338 self.state_ch.set_link_state(LinkState::Down);
339 }
326 _ => {} 340 _ => {}
327 } 341 }
328 } 342 }
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index e114e50b9..a60822fd9 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) {
72 72
73 unwrap!(spawner.spawn(wifi_task(runner))); 73 unwrap!(spawner.spawn(wifi_task(runner)));
74 74
75 control.init().await; 75 unwrap!(control.init().await);
76 control.join(WIFI_NETWORK, WIFI_PASSWORD).await; 76 unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await);
77 77
78 let config = embassy_net::Config::dhcpv4(Default::default()); 78 let config = embassy_net::Config::dhcpv4(Default::default());
79 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { 79 // 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 ee46af2a3..97ebafec8 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -73,8 +73,8 @@ async fn main(spawner: Spawner) {
73 73
74 unwrap!(spawner.spawn(wifi_task(runner))); 74 unwrap!(spawner.spawn(wifi_task(runner)));
75 75
76 control.init().await; 76 unwrap!(control.init().await);
77 control.join(WIFI_NETWORK, WIFI_PASSWORD).await; 77 unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await);
78 78
79 // Generate random seed 79 // Generate random seed
80 let mut rng = Rng::new(p.RNG, Irqs); 80 let mut rng = Rng::new(p.RNG, Irqs);