aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-07-17 19:26:58 -0500
committerxoviat <[email protected]>2023-07-17 19:26:58 -0500
commit8f23b6faa6f04f83ece119e94335f892d516f6b3 (patch)
treea83d6eaa1623a3ff8a6e6536e4e59523ee499c38
parent1d2c47273db6593a53018b1643dcadb491afc3de (diff)
wpan: refactor control, driver
-rw-r--r--embassy-stm32-wpan/src/mac/control.rs446
-rw-r--r--embassy-stm32-wpan/src/mac/driver.rs162
-rw-r--r--embassy-stm32-wpan/src/mac/event.rs120
-rw-r--r--embassy-stm32-wpan/src/mac/ioctl.rs124
-rw-r--r--embassy-stm32-wpan/src/mac/mod.rs83
-rw-r--r--embassy-stm32-wpan/src/mac/runner.rs329
6 files changed, 106 insertions, 1158 deletions
diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs
index c67614dd6..6e45e595f 100644
--- a/embassy-stm32-wpan/src/mac/control.rs
+++ b/embassy-stm32-wpan/src/mac/control.rs
@@ -1,16 +1,4 @@
1use core::cmp::{max, min}; 1use crate::mac::runner::Runner;
2
3use ch::driver::LinkState;
4use embassy_net_driver_channel as ch;
5use embassy_time::{Duration, Timer};
6
7pub use crate::bus::SpiBusCyw43;
8use crate::consts::*;
9use crate::events::{Event, EventSubscriber, Events};
10use crate::fmt::Bytes;
11use crate::ioctl::{IoctlState, IoctlType};
12use crate::structs::*;
13use crate::{countries, events, PowerManagementMode};
14 2
15#[derive(Debug)] 3#[derive(Debug)]
16pub struct Error { 4pub struct Error {
@@ -18,437 +6,15 @@ pub struct Error {
18} 6}
19 7
20pub struct Control<'a> { 8pub struct Control<'a> {
21 state_ch: ch::StateRunner<'a>, 9 runner: &'a Runner,
22 events: &'a Events,
23 ioctl_state: &'a IoctlState,
24} 10}
25 11
26impl<'a> Control<'a> { 12impl<'a> Control<'a> {
27 pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { 13 pub(crate) fn new(runner: &'a Runner) -> Self {
28 Self { 14 Self { runner: runner }
29 state_ch,
30 events: event_sub,
31 ioctl_state,
32 }
33 }
34
35 pub async fn init(&mut self, clm: &[u8]) {
36 const CHUNK_SIZE: usize = 1024;
37
38 debug!("Downloading CLM...");
39
40 let mut offs = 0;
41 for chunk in clm.chunks(CHUNK_SIZE) {
42 let mut flag = DOWNLOAD_FLAG_HANDLER_VER;
43 if offs == 0 {
44 flag |= DOWNLOAD_FLAG_BEGIN;
45 }
46 offs += chunk.len();
47 if offs == clm.len() {
48 flag |= DOWNLOAD_FLAG_END;
49 }
50
51 let header = DownloadHeader {
52 flag,
53 dload_type: DOWNLOAD_TYPE_CLM,
54 len: chunk.len() as _,
55 crc: 0,
56 };
57 let mut buf = [0; 8 + 12 + CHUNK_SIZE];
58 buf[0..8].copy_from_slice(b"clmload\x00");
59 buf[8..20].copy_from_slice(&header.to_bytes());
60 buf[20..][..chunk.len()].copy_from_slice(&chunk);
61 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()])
62 .await;
63 }
64
65 // check clmload ok
66 assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
67
68 debug!("Configuring misc stuff...");
69
70 // Disable tx gloming which transfers multiple packets in one request.
71 // 'glom' is short for "conglomerate" which means "gather together into
72 // a compact mass".
73 self.set_iovar_u32("bus:txglom", 0).await;
74 self.set_iovar_u32("apsta", 1).await;
75
76 // read MAC addr.
77 let mut mac_addr = [0; 6];
78 assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
79 debug!("mac addr: {:02x}", Bytes(&mac_addr));
80
81 let country = countries::WORLD_WIDE_XX;
82 let country_info = CountryInfo {
83 country_abbrev: [country.code[0], country.code[1], 0, 0],
84 country_code: [country.code[0], country.code[1], 0, 0],
85 rev: if country.rev == 0 { -1 } else { country.rev as _ },
86 };
87 self.set_iovar("country", &country_info.to_bytes()).await;
88
89 // set country takes some time, next ioctls fail if we don't wait.
90 Timer::after(Duration::from_millis(100)).await;
91
92 // Set antenna to chip antenna
93 self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
94
95 self.set_iovar_u32("bus:txglom", 0).await;
96 Timer::after(Duration::from_millis(100)).await;
97 //self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
98 //Timer::after(Duration::from_millis(100)).await;
99 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
100 Timer::after(Duration::from_millis(100)).await;
101 self.set_iovar_u32("ampdu_mpdu", 4).await;
102 Timer::after(Duration::from_millis(100)).await;
103 //self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
104
105 //Timer::after(Duration::from_millis(100)).await;
106
107 // evts
108 let mut evts = EventMask {
109 iface: 0,
110 events: [0xFF; 24],
111 };
112
113 // Disable spammy uninteresting events.
114 evts.unset(Event::RADIO);
115 evts.unset(Event::IF);
116 evts.unset(Event::PROBREQ_MSG);
117 evts.unset(Event::PROBREQ_MSG_RX);
118 evts.unset(Event::PROBRESP_MSG);
119 evts.unset(Event::PROBRESP_MSG);
120 evts.unset(Event::ROAM);
121
122 self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
123
124 Timer::after(Duration::from_millis(100)).await;
125
126 // set wifi up
127 self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
128
129 Timer::after(Duration::from_millis(100)).await;
130
131 self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
132 self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
133
134 Timer::after(Duration::from_millis(100)).await;
135
136 self.state_ch.set_ethernet_address(mac_addr);
137
138 debug!("INIT DONE");
139 }
140
141 pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
142 // power save mode
143 let mode_num = mode.mode();
144 if mode_num == 2 {
145 self.set_iovar_u32("pm2_sleep_ret", mode.sleep_ret_ms() as u32).await;
146 self.set_iovar_u32("bcn_li_bcn", mode.beacon_period() as u32).await;
147 self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await;
148 self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await;
149 }
150 self.ioctl_set_u32(86, 0, mode_num).await;
151 }
152
153 pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> {
154 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
155
156 self.ioctl_set_u32(134, 0, 0).await; // wsec = open
157 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await;
158 self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1
159 self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0)
160
161 let mut i = SsidInfo {
162 len: ssid.len() as _,
163 ssid: [0; 32],
164 };
165 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
166
167 self.wait_for_join(i).await
168 }
169
170 pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> {
171 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
172
173 self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2
174 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await;
175 self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
176 self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
177
178 Timer::after(Duration::from_millis(100)).await;
179
180 let mut pfi = PassphraseInfo {
181 len: passphrase.len() as _,
182 flags: 1,
183 passphrase: [0; 64],
184 };
185 pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes());
186 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes())
187 .await; // WLC_SET_WSEC_PMK
188
189 self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1
190 self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open)
191 self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth
192
193 let mut i = SsidInfo {
194 len: ssid.len() as _,
195 ssid: [0; 32],
196 };
197 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
198
199 self.wait_for_join(i).await
200 }
201
202 async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> {
203 self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]);
204 let mut subscriber = self.events.queue.subscriber().unwrap();
205 // the actual join operation starts here
206 // we make sure to enable events before so we don't miss any
207
208 // set_ssid
209 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes())
210 .await;
211
212 // to complete the join, we wait for a SET_SSID event
213 // we also save the AUTH status for the user, it may be interesting
214 let mut auth_status = 0;
215 let status = loop {
216 let msg = subscriber.next_message_pure().await;
217 if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS {
218 auth_status = msg.header.status;
219 } else if msg.header.event_type == Event::SET_SSID {
220 // join operation ends with SET_SSID event
221 break msg.header.status;
222 }
223 };
224
225 self.events.mask.disable_all();
226 if status == EStatus::SUCCESS {
227 // successful join
228 self.state_ch.set_link_state(LinkState::Up);
229 debug!("JOINED");
230 Ok(())
231 } else {
232 warn!("JOIN failed with status={} auth={}", status, auth_status);
233 Err(Error { status })
234 }
235 }
236
237 pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) {
238 assert!(gpio_n < 3);
239 self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 })
240 .await
241 }
242
243 pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) {
244 self.start_ap(ssid, "", Security::OPEN, channel).await;
245 }
246
247 pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) {
248 self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await;
249 }
250
251 async fn start_ap(&mut self, ssid: &str, passphrase: &str, security: Security, channel: u8) {
252 if security != Security::OPEN
253 && (passphrase.as_bytes().len() < MIN_PSK_LEN || passphrase.as_bytes().len() > MAX_PSK_LEN)
254 {
255 panic!("Passphrase is too short or too long");
256 } 15 }
257 16
258 // Temporarily set wifi down 17 pub async fn init(&mut self) {
259 self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; 18 // TODO
260
261 // Turn off APSTA mode
262 self.set_iovar_u32("apsta", 0).await;
263
264 // Set wifi up again
265 self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
266
267 // Turn on AP mode
268 self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await;
269
270 // Set SSID
271 let mut i = SsidInfoWithIndex {
272 index: 0,
273 ssid_info: SsidInfo {
274 len: ssid.as_bytes().len() as _,
275 ssid: [0; 32],
276 },
277 };
278 i.ssid_info.ssid[..ssid.as_bytes().len()].copy_from_slice(ssid.as_bytes());
279 self.set_iovar("bsscfg:ssid", &i.to_bytes()).await;
280
281 // Set channel number
282 self.ioctl_set_u32(IOCTL_CMD_SET_CHANNEL, 0, channel as u32).await;
283
284 // Set security
285 self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await;
286
287 if security != Security::OPEN {
288 self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK
289
290 Timer::after(Duration::from_millis(100)).await;
291
292 // Set passphrase
293 let mut pfi = PassphraseInfo {
294 len: passphrase.as_bytes().len() as _,
295 flags: 1, // WSEC_PASSPHRASE
296 passphrase: [0; 64],
297 };
298 pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes());
299 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes())
300 .await;
301 }
302
303 // Change mutlicast rate from 1 Mbps to 11 Mbps
304 self.set_iovar_u32("2g_mrate", 11000000 / 500000).await;
305
306 // Start AP
307 self.set_iovar_u32x2("bss", 0, 1).await; // bss = BSS_UP
308 }
309
310 async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) {
311 let mut buf = [0; 8];
312 buf[0..4].copy_from_slice(&val1.to_le_bytes());
313 buf[4..8].copy_from_slice(&val2.to_le_bytes());
314 self.set_iovar(name, &buf).await
315 }
316
317 async fn set_iovar_u32(&mut self, name: &str, val: u32) {
318 self.set_iovar(name, &val.to_le_bytes()).await
319 }
320
321 async fn get_iovar_u32(&mut self, name: &str) -> u32 {
322 let mut buf = [0; 4];
323 let len = self.get_iovar(name, &mut buf).await;
324 assert_eq!(len, 4);
325 u32::from_le_bytes(buf)
326 }
327
328 async fn set_iovar(&mut self, name: &str, val: &[u8]) {
329 self.set_iovar_v::<64>(name, val).await
330 }
331
332 async fn set_iovar_v<const BUFSIZE: usize>(&mut self, name: &str, val: &[u8]) {
333 debug!("set {} = {:02x}", name, Bytes(val));
334
335 let mut buf = [0; BUFSIZE];
336 buf[..name.len()].copy_from_slice(name.as_bytes());
337 buf[name.len()] = 0;
338 buf[name.len() + 1..][..val.len()].copy_from_slice(val);
339
340 let total_len = name.len() + 1 + val.len();
341 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len])
342 .await;
343 }
344
345 // TODO this is not really working, it always returns all zeros.
346 async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize {
347 debug!("get {}", name);
348
349 let mut buf = [0; 64];
350 buf[..name.len()].copy_from_slice(name.as_bytes());
351 buf[name.len()] = 0;
352
353 let total_len = max(name.len() + 1, res.len());
354 let res_len = self
355 .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len])
356 .await;
357
358 let out_len = min(res.len(), res_len);
359 res[..out_len].copy_from_slice(&buf[..out_len]);
360 out_len
361 }
362
363 async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) {
364 let mut buf = val.to_le_bytes();
365 self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await;
366 }
367
368 async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
369 struct CancelOnDrop<'a>(&'a IoctlState);
370
371 impl CancelOnDrop<'_> {
372 fn defuse(self) {
373 core::mem::forget(self);
374 }
375 }
376
377 impl Drop for CancelOnDrop<'_> {
378 fn drop(&mut self) {
379 self.0.cancel_ioctl();
380 }
381 }
382
383 let ioctl = CancelOnDrop(self.ioctl_state);
384 let resp_len = ioctl.0.do_ioctl(kind, cmd, iface, buf).await;
385 ioctl.defuse();
386
387 resp_len
388 }
389
390 /// Start a wifi scan
391 ///
392 /// Returns a `Stream` of networks found by the device
393 ///
394 /// # Note
395 /// Device events are currently implemented using a bounded queue.
396 /// To not miss any events, you should make sure to always await the stream.
397 pub async fn scan(&mut self) -> Scanner<'_> {
398 const SCANTYPE_PASSIVE: u8 = 1;
399
400 let scan_params = ScanParams {
401 version: 1,
402 action: 1,
403 sync_id: 1,
404 ssid_len: 0,
405 ssid: [0; 32],
406 bssid: [0xff; 6],
407 bss_type: 2,
408 scan_type: SCANTYPE_PASSIVE,
409 nprobes: !0,
410 active_time: !0,
411 passive_time: !0,
412 home_time: !0,
413 channel_num: 0,
414 channel_list: [0; 1],
415 };
416
417 self.events.mask.enable(&[Event::ESCAN_RESULT]);
418 let subscriber = self.events.queue.subscriber().unwrap();
419 self.set_iovar_v::<256>("escan", &scan_params.to_bytes()).await;
420
421 Scanner {
422 subscriber,
423 events: &self.events,
424 }
425 }
426}
427
428pub struct Scanner<'a> {
429 subscriber: EventSubscriber<'a>,
430 events: &'a Events,
431}
432
433impl Scanner<'_> {
434 /// wait for the next found network
435 pub async fn next(&mut self) -> Option<BssInfo> {
436 let event = self.subscriber.next_message_pure().await;
437 if event.header.status != EStatus::PARTIAL {
438 self.events.mask.disable_all();
439 return None;
440 }
441
442 if let events::Payload::BssInfo(bss) = event.payload {
443 Some(bss)
444 } else {
445 None
446 }
447 }
448}
449
450impl Drop for Scanner<'_> {
451 fn drop(&mut self) {
452 self.events.mask.disable_all();
453 } 19 }
454} 20}
diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs
index 3171d61fe..00072749b 100644
--- a/embassy-stm32-wpan/src/mac/driver.rs
+++ b/embassy-stm32-wpan/src/mac/driver.rs
@@ -1,102 +1,110 @@
1#![no_std]
2#![no_main]
3#![allow(incomplete_features)] 1#![allow(incomplete_features)]
4#![feature(async_fn_in_trait, type_alias_impl_trait, concat_bytes)]
5#![deny(unused_must_use)] 2#![deny(unused_must_use)]
6 3
7use core::slice; 4use core::task::Context;
8 5
9use embassy_net_driver_channel as ch; 6use embassy_net_driver::{Capabilities, LinkState, Medium};
10use embedded_hal_1::digital::OutputPin;
11use events::Events;
12use ioctl::IoctlState;
13 7
14use crate::bus::Bus; 8use crate::mac::runner::Runner;
15pub use crate::bus::SpiBusCyw43; 9use crate::mac::MTU;
16pub use crate::control::{Control, Error as ControlError};
17pub use crate::runner::Runner;
18pub use crate::structs::BssInfo;
19 10
20const MTU: usize = 1514; 11pub struct Driver<'d> {
21 12 runner: &'d Runner,
22pub struct State {
23 ioctl_state: IoctlState,
24 ch: ch::State<MTU, 4, 4>,
25 events: Events,
26} 13}
27 14
28impl State { 15impl<'d> Driver<'d> {
29 pub fn new() -> Self { 16 pub(crate) fn new(runner: &'d Runner) -> Self {
30 Self { 17 Self { runner: runner }
31 ioctl_state: IoctlState::new(),
32 ch: ch::State::new(),
33 events: Events::new(),
34 }
35 } 18 }
36} 19}
37 20
38#[derive(Debug, Clone, Copy, PartialEq, Eq)] 21impl<'d> embassy_net_driver::Driver for Driver<'d> {
39pub enum PowerManagementMode { 22 // type RxToken<'a> = RxToken<'a, 'd> where Self: 'a;
40 /// Custom, officially unsupported mode. Use at your own risk. 23 // type TxToken<'a> = TxToken<'a, 'd> where Self: 'a;
41 /// All power-saving features set to their max at only a marginal decrease in power consumption 24 type RxToken<'a> = RxToken where Self: 'a;
42 /// as oppposed to `Aggressive`. 25 type TxToken<'a> = TxToken where Self: 'a;
43 SuperSave, 26
27 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
28 // WAKER.register(cx.waker());
29 // if self.rx.available().is_some() && self.tx.available().is_some() {
30 // Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx }))
31 // } else {
32 // None
33 // }
34
35 None
36 }
37
38 fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
39 // WAKER.register(cx.waker());
40 // / if self.tx.available().is_some() {
41 // / Some(TxToken { tx: &mut self.tx })
42 // / } else {
43 // / None
44 // / }
44 45
45 /// Aggressive power saving mode. 46 None
46 Aggressive, 47 }
47 48
48 /// The default mode. 49 fn capabilities(&self) -> Capabilities {
49 PowerSave, 50 let mut caps = Capabilities::default();
51 caps.max_transmission_unit = MTU;
52 // caps.max_burst_size = Some(self.tx.len());
50 53
51 /// Performance is prefered over power consumption but still some power is conserved as opposed to 54 caps.medium = Medium::Ieee802154;
52 /// `None`. 55 caps
53 Performance, 56 }
54 57
55 /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of 58 fn link_state(&mut self, cx: &mut Context) -> LinkState {
56 /// a much lower throughput. 59 // if self.phy.poll_link(&mut self.station_management, cx) {
57 ThroughputThrottling, 60 // LinkState::Up
61 // } else {
62 // LinkState::Down
63 // }
58 64
59 /// No power management is configured. This consumes the most power. 65 LinkState::Down
60 None, 66 }
61} 67
68 fn ethernet_address(&self) -> [u8; 6] {
69 // self.mac_addr
62 70
63impl Default for PowerManagementMode { 71 [0; 6]
64 fn default() -> Self {
65 Self::PowerSave
66 } 72 }
67} 73}
68 74
69impl PowerManagementMode { 75pub struct RxToken {
70 // TODO 76 // rx: &'a mut RDesRing<'d>,
77}
78
79impl embassy_net_driver::RxToken for RxToken {
80 fn consume<R, F>(self, f: F) -> R
81 where
82 F: FnOnce(&mut [u8]) -> R,
83 {
84 // NOTE(unwrap): we checked the queue wasn't full when creating the token.
85 // let pkt = unwrap!(self.rx.available());
86
87 let pkt = &[];
88 let r = f(&mut pkt[0..]);
89 // self.rx.pop_packet();
90 r
91 }
71} 92}
72 93
73pub type NetDriver<'a> = ch::Device<'a, MTU>; 94pub struct TxToken {
74 95 // tx: &'a mut TDesRing<'d>,
75pub async fn new<'a, PWR, SPI>(
76 state: &'a mut State,
77 pwr: PWR,
78 spi: SPI,
79 firmware: &[u8],
80) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>)
81where
82 PWR: OutputPin,
83 SPI: SpiBusCyw43,
84{
85 let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
86 let state_ch = ch_runner.state_runner();
87
88 let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events);
89
90 runner.init(firmware).await;
91
92 (
93 device,
94 Control::new(state_ch, &state.events, &state.ioctl_state),
95 runner,
96 )
97} 96}
98 97
99fn slice8_mut(x: &mut [u32]) -> &mut [u8] { 98impl embassy_net_driver::TxToken for TxToken {
100 let len = x.len() * 4; 99 fn consume<R, F>(self, len: usize, f: F) -> R
101 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } 100 where
101 F: FnOnce(&mut [u8]) -> R,
102 {
103 // NOTE(unwrap): we checked the queue wasn't full when creating the token.
104 // let pkt = unwrap!(self.tx.available());
105 let pkt = &[];
106 let r = f(&mut pkt[..len]);
107 // self.tx.transmit(len);
108 r
109 }
102} 110}
diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/mac/event.rs
index 661c06ac4..a2bb79222 100644
--- a/embassy-stm32-wpan/src/mac/event.rs
+++ b/embassy-stm32-wpan/src/mac/event.rs
@@ -1,9 +1,3 @@
1use core::cell::RefCell;
2
3use embassy_sync::blocking_mutex::raw::NoopRawMutex;
4use embassy_sync::pubsub::{PubSubChannel, Subscriber};
5
6use super::helpers::to_u16;
7use core::mem; 1use core::mem;
8 2
9use super::indications::{ 3use super::indications::{
@@ -80,7 +74,6 @@ impl Event {
80 } 74 }
81} 75}
82 76
83#[derive(Debug, Clone, PartialEq, Eq)]
84#[cfg_attr(feature = "defmt", derive(defmt::Format))] 77#[cfg_attr(feature = "defmt", derive(defmt::Format))]
85pub enum MacEvent<'a> { 78pub enum MacEvent<'a> {
86 MlmeAssociateCnf(&'a AssociateConfirm), 79 MlmeAssociateCnf(&'a AssociateConfirm),
@@ -109,116 +102,3 @@ pub enum MacEvent<'a> {
109 McpsDataInd(&'a DataIndication), 102 McpsDataInd(&'a DataIndication),
110 MlmePollInd(&'a PollIndication), 103 MlmePollInd(&'a PollIndication),
111} 104}
112
113// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient.
114pub type EventQueue = PubSubChannel<NoopRawMutex, Message, 2, 1, 1>;
115pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>;
116
117pub struct Events {
118 pub queue: EventQueue,
119 pub mask: SharedEventMask,
120}
121
122impl Events {
123 pub fn new() -> Self {
124 Self {
125 queue: EventQueue::new(),
126 mask: SharedEventMask::default(),
127 }
128 }
129}
130
131#[derive(Clone)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))]
133pub struct Status {
134 pub event_type: MacEvent,
135 pub status: u32,
136}
137
138#[derive(Clone, Copy)]
139pub enum Payload {
140 None,
141 // BssInfo(BssInfo),
142}
143
144#[derive(Clone)]
145
146pub struct Message {
147 pub header: Status,
148 pub payload: Payload,
149}
150
151impl Message {
152 pub fn new(status: Status, payload: Payload) -> Self {
153 Self {
154 header: status,
155 payload,
156 }
157 }
158}
159
160#[derive(Default)]
161struct EventMask {
162 mask: [u32; Self::WORD_COUNT],
163}
164
165impl EventMask {
166 const WORD_COUNT: usize = ((Event::LAST as u32 + (u32::BITS - 1)) / u32::BITS) as usize;
167
168 fn enable(&mut self, event: MacEvent) {
169 let n = event as u32;
170 let word = n / u32::BITS;
171 let bit = n % u32::BITS;
172
173 self.mask[word as usize] |= 1 << bit;
174 }
175
176 fn disable(&mut self, event: MacEvent) {
177 let n = event as u32;
178 let word = n / u32::BITS;
179 let bit = n % u32::BITS;
180
181 self.mask[word as usize] &= !(1 << bit);
182 }
183
184 fn is_enabled(&self, event: MacEvent) -> bool {
185 let n = event as u32;
186 let word = n / u32::BITS;
187 let bit = n % u32::BITS;
188
189 self.mask[word as usize] & (1 << bit) > 0
190 }
191}
192
193#[derive(Default)]
194
195pub struct SharedEventMask {
196 mask: RefCell<EventMask>,
197}
198
199impl SharedEventMask {
200 pub fn enable(&self, events: &[MacEvent]) {
201 let mut mask = self.mask.borrow_mut();
202 for event in events {
203 mask.enable(*event);
204 }
205 }
206
207 #[allow(dead_code)]
208 pub fn disable(&self, events: &[MacEvent]) {
209 let mut mask = self.mask.borrow_mut();
210 for event in events {
211 mask.disable(*event);
212 }
213 }
214
215 pub fn disable_all(&self) {
216 let mut mask = self.mask.borrow_mut();
217 mask.mask = Default::default();
218 }
219
220 pub fn is_enabled(&self, event: MacEvent) -> bool {
221 let mask = self.mask.borrow();
222 mask.is_enabled(event)
223 }
224}
diff --git a/embassy-stm32-wpan/src/mac/ioctl.rs b/embassy-stm32-wpan/src/mac/ioctl.rs
deleted file mode 100644
index 0fe55cd6c..000000000
--- a/embassy-stm32-wpan/src/mac/ioctl.rs
+++ /dev/null
@@ -1,124 +0,0 @@
1use core::cell::{Cell, RefCell};
2use core::future::poll_fn;
3use core::task::{Poll, Waker};
4
5use embassy_sync::waitqueue::WakerRegistration;
6
7#[derive(Clone, Copy)]
8pub enum IoctlType {
9 Get = 0,
10 Set = 2,
11}
12
13#[derive(Clone, Copy)]
14pub struct PendingIoctl {
15 pub buf: *mut [u8],
16 pub kind: IoctlType,
17 pub cmd: u32,
18 pub iface: u32,
19}
20
21#[derive(Clone, Copy)]
22enum IoctlStateInner {
23 Pending(PendingIoctl),
24 Sent { buf: *mut [u8] },
25 Done { resp_len: usize },
26}
27
28struct Wakers {
29 control: WakerRegistration,
30 runner: WakerRegistration,
31}
32
33impl Default for Wakers {
34 fn default() -> Self {
35 Self {
36 control: WakerRegistration::new(),
37 runner: WakerRegistration::new(),
38 }
39 }
40}
41
42pub struct IoctlState {
43 state: Cell<IoctlStateInner>,
44 wakers: RefCell<Wakers>,
45}
46
47impl IoctlState {
48 pub fn new() -> Self {
49 Self {
50 state: Cell::new(IoctlStateInner::Done { resp_len: 0 }),
51 wakers: Default::default(),
52 }
53 }
54
55 fn wake_control(&self) {
56 self.wakers.borrow_mut().control.wake();
57 }
58
59 fn register_control(&self, waker: &Waker) {
60 self.wakers.borrow_mut().control.register(waker);
61 }
62
63 fn wake_runner(&self) {
64 self.wakers.borrow_mut().runner.wake();
65 }
66
67 fn register_runner(&self, waker: &Waker) {
68 self.wakers.borrow_mut().runner.register(waker);
69 }
70
71 pub async fn wait_complete(&self) -> usize {
72 poll_fn(|cx| {
73 if let IoctlStateInner::Done { resp_len } = self.state.get() {
74 Poll::Ready(resp_len)
75 } else {
76 self.register_control(cx.waker());
77 Poll::Pending
78 }
79 })
80 .await
81 }
82
83 pub async fn wait_pending(&self) -> PendingIoctl {
84 let pending = poll_fn(|cx| {
85 if let IoctlStateInner::Pending(pending) = self.state.get() {
86 Poll::Ready(pending)
87 } else {
88 self.register_runner(cx.waker());
89 Poll::Pending
90 }
91 })
92 .await;
93
94 self.state.set(IoctlStateInner::Sent { buf: pending.buf });
95 pending
96 }
97
98 pub fn cancel_ioctl(&self) {
99 self.state.set(IoctlStateInner::Done { resp_len: 0 });
100 }
101
102 pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
103 self.state
104 .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface }));
105 self.wake_runner();
106 self.wait_complete().await
107 }
108
109 pub fn ioctl_done(&self, response: &[u8]) {
110 if let IoctlStateInner::Sent { buf } = self.state.get() {
111 // trace!("IOCTL Response: {:02x}", Bytes(response));
112
113 // TODO fix this
114 (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
115
116 self.state.set(IoctlStateInner::Done {
117 resp_len: response.len(),
118 });
119 self.wake_control();
120 } else {
121 warn!("IOCTL Response but no pending Ioctl");
122 }
123 }
124}
diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs
index df03e4236..e024aeae3 100644
--- a/embassy-stm32-wpan/src/mac/mod.rs
+++ b/embassy-stm32-wpan/src/mac/mod.rs
@@ -1,9 +1,9 @@
1pub mod commands; 1pub mod commands;
2mod consts; 2mod consts;
3pub mod control; 3pub mod control;
4mod driver;
4pub mod event; 5pub mod event;
5pub mod indications; 6pub mod indications;
6mod ioctl;
7mod macros; 7mod macros;
8mod opcodes; 8mod opcodes;
9pub mod responses; 9pub mod responses;
@@ -12,86 +12,19 @@ pub mod typedefs;
12 12
13use core::slice; 13use core::slice;
14 14
15use embassy_net_driver_channel as ch;
16
17pub use crate::mac::control::{Control, Error as ControlError}; 15pub use crate::mac::control::{Control, Error as ControlError};
18use crate::mac::event::Events; 16use crate::mac::driver::Driver;
19use crate::mac::ioctl::IoctlState;
20pub use crate::mac::runner::Runner; 17pub use crate::mac::runner::Runner;
21use crate::sub::mac::Mac; 18use crate::sub::mac::Mac;
22 19
23const MTU: usize = 1514; 20const MTU: usize = 127;
24
25pub struct State {
26 ioctl_state: IoctlState,
27 ch: ch::State<MTU, 4, 4>,
28 events: Events,
29}
30
31impl State {
32 pub fn new() -> Self {
33 Self {
34 ioctl_state: IoctlState::new(),
35 ch: ch::State::new(),
36 events: Events::new(),
37 }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum PowerManagementMode {
43 /// Custom, officially unsupported mode. Use at your own risk.
44 /// All power-saving features set to their max at only a marginal decrease in power consumption
45 /// as oppposed to `Aggressive`.
46 SuperSave,
47
48 /// Aggressive power saving mode.
49 Aggressive,
50
51 /// The default mode.
52 PowerSave,
53
54 /// Performance is prefered over power consumption but still some power is conserved as opposed to
55 /// `None`.
56 Performance,
57
58 /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of
59 /// a much lower throughput.
60 ThroughputThrottling,
61
62 /// No power management is configured. This consumes the most power.
63 None,
64}
65
66impl Default for PowerManagementMode {
67 fn default() -> Self {
68 Self::PowerSave
69 }
70}
71
72impl PowerManagementMode {
73 // TODO
74}
75
76pub type NetDriver<'a> = ch::Device<'a, MTU>;
77
78pub async fn new<'a>(
79 state: &'a mut State,
80 mac_subsystem: Mac,
81 firmware: &[u8],
82) -> (NetDriver<'a>, Control<'a>, Runner<'a>) {
83 let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
84 let state_ch = ch_runner.state_runner();
85
86 let mut runner = Runner::new(ch_runner, mac_subsystem, &state.ioctl_state, &state.events);
87 21
88 runner.init(firmware).await; 22pub async fn new<'a>(mac: Mac) -> (Runner, Control<'a>, Driver<'a>) {
23 let runner = Runner::new(mac);
24 let control = Control::new(&runner);
25 let driver = Driver::new(&runner);
89 26
90 ( 27 (runner, control, driver)
91 device,
92 Control::new(state_ch, &state.events, &state.ioctl_state),
93 runner,
94 )
95} 28}
96 29
97fn slice8_mut(x: &mut [u32]) -> &mut [u8] { 30fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs
index fbb7cb747..e97c9c8e2 100644
--- a/embassy-stm32-wpan/src/mac/runner.rs
+++ b/embassy-stm32-wpan/src/mac/runner.rs
@@ -1,342 +1,27 @@
1use embassy_futures::select::{select3, Either3}; 1use embassy_futures::select::{select3, Either3};
2use embassy_net_driver_channel as ch;
3use embassy_sync::pubsub::PubSubBehavior;
4 2
5use crate::mac::event::Events;
6use crate::mac::ioctl::{IoctlState, PendingIoctl};
7use crate::mac::MTU; 3use crate::mac::MTU;
8use crate::sub::mac::Mac; 4use crate::sub::mac::Mac;
9 5
10pub struct Runner<'a> { 6pub struct Runner {
11 ch: ch::Runner<'a, MTU>,
12 mac: Mac, 7 mac: Mac,
13 8 // TODO: tx_ring
14 ioctl_state: &'a IoctlState, 9 // TODO: rx_buf
15 ioctl_id: u16,
16 sdpcm_seq: u8,
17 sdpcm_seq_max: u8,
18
19 events: &'a Events,
20} 10}
21 11
22impl<'a> Runner<'a> { 12impl Runner {
23 pub(crate) fn new(ch: ch::Runner<'a, MTU>, mac: Mac, ioctl_state: &'a IoctlState, events: &'a Events) -> Self { 13 pub(crate) fn new(mac: Mac) -> Self {
24 Self { 14 Self { mac }
25 ch,
26 mac,
27 ioctl_state,
28 ioctl_id: 0,
29 sdpcm_seq: 0,
30 sdpcm_seq_max: 1,
31 events,
32 }
33 } 15 }
34 16
35 pub(crate) async fn init(&mut self, firmware: &[u8]) { 17 pub(crate) async fn init(&mut self, firmware: &[u8]) {
36 self.bus.init().await;
37
38 #[cfg(feature = "firmware-logs")]
39 self.log_init().await;
40
41 debug!("wifi init done"); 18 debug!("wifi init done");
42 } 19 }
43 20
44 pub async fn run(mut self) -> ! { 21 pub async fn run(mut self) -> ! {
45 let mut buf = [0; 512]; 22 let mut buf = [0; 512];
46 loop { 23 loop {
47 #[cfg(feature = "firmware-logs")] 24 // TODO
48 self.log_read().await;
49
50 if self.has_credit() {
51 let ioctl = self.ioctl_state.wait_pending();
52 let tx = self.ch.tx_buf();
53 let ev = self.bus.wait_for_event();
54
55 match select3(ioctl, tx, ev).await {
56 Either3::First(PendingIoctl {
57 buf: iobuf,
58 kind,
59 cmd,
60 iface,
61 }) => {
62 self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await;
63 self.check_status(&mut buf).await;
64 }
65 Either3::Second(packet) => {
66 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
67
68 let mut buf = [0; 512];
69 let buf8 = slice8_mut(&mut buf);
70
71 // There MUST be 2 bytes of padding between the SDPCM and BDC headers.
72 // And ONLY for data packets!
73 // No idea why, but the firmware will append two zero bytes to the tx'd packets
74 // otherwise. If the packet is exactly 1514 bytes (the max MTU), this makes it
75 // be oversized and get dropped.
76 // WHD adds it here https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/include/whd_sdpcm.h#L90
77 // and adds it to the header size her https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/whd_sdpcm.c#L597
78 // ¯\_(ツ)_/¯
79 const PADDING_SIZE: usize = 2;
80 let total_len = SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE + packet.len();
81
82 let seq = self.sdpcm_seq;
83 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
84
85 let sdpcm_header = SdpcmHeader {
86 len: total_len as u16, // TODO does this len need to be rounded up to u32?
87 len_inv: !total_len as u16,
88 sequence: seq,
89 channel_and_flags: CHANNEL_TYPE_DATA,
90 next_length: 0,
91 header_length: (SdpcmHeader::SIZE + PADDING_SIZE) as _,
92 wireless_flow_control: 0,
93 bus_data_credit: 0,
94 reserved: [0, 0],
95 };
96
97 let bdc_header = BdcHeader {
98 flags: BDC_VERSION << BDC_VERSION_SHIFT,
99 priority: 0,
100 flags2: 0,
101 data_offset: 0,
102 };
103 trace!("tx {:?}", sdpcm_header);
104 trace!(" {:?}", bdc_header);
105
106 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
107 buf8[SdpcmHeader::SIZE + PADDING_SIZE..][..BdcHeader::SIZE]
108 .copy_from_slice(&bdc_header.to_bytes());
109 buf8[SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE..][..packet.len()]
110 .copy_from_slice(packet);
111
112 let total_len = (total_len + 3) & !3; // round up to 4byte
113
114 trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)]));
115
116 self.bus.wlan_write(&buf[..(total_len / 4)]).await;
117 self.ch.tx_done();
118 self.check_status(&mut buf).await;
119 }
120 Either3::Third(()) => {
121 self.handle_irq(&mut buf).await;
122 }
123 }
124 } else {
125 warn!("TX stalled");
126 self.bus.wait_for_event().await;
127 self.handle_irq(&mut buf).await;
128 }
129 }
130 }
131
132 /// Wait for IRQ on F2 packet available
133 async fn handle_irq(&mut self, buf: &mut [u32; 512]) {
134 // Receive stuff
135 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
136 trace!("irq{}", FormatInterrupt(irq));
137
138 if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
139 self.check_status(buf).await;
140 }
141
142 if irq & IRQ_DATA_UNAVAILABLE != 0 {
143 // TODO what should we do here?
144 warn!("IRQ DATA_UNAVAILABLE, clearing...");
145 self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await;
146 }
147 }
148
149 /// Handle F2 events while status register is set
150 async fn check_status(&mut self, buf: &mut [u32; 512]) {
151 loop {
152 let status = self.bus.status();
153 trace!("check status{}", FormatStatus(status));
154
155 if status & STATUS_F2_PKT_AVAILABLE != 0 {
156 let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
157 self.bus.wlan_read(buf, len).await;
158 trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)]));
159 self.rx(&mut slice8_mut(buf)[..len as usize]);
160 } else {
161 break;
162 }
163 }
164 }
165
166 fn rx(&mut self, packet: &mut [u8]) {
167 let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else {
168 return;
169 };
170
171 self.update_credit(&sdpcm_header);
172
173 let channel = sdpcm_header.channel_and_flags & 0x0f;
174
175 match channel {
176 CHANNEL_TYPE_CONTROL => {
177 let Some((cdc_header, response)) = CdcHeader::parse(payload) else {
178 return;
179 };
180 trace!(" {:?}", cdc_header);
181
182 if cdc_header.id == self.ioctl_id {
183 if cdc_header.status != 0 {
184 // TODO: propagate error instead
185 panic!("IOCTL error {}", cdc_header.status as i32);
186 }
187
188 self.ioctl_state.ioctl_done(response);
189 }
190 }
191 CHANNEL_TYPE_EVENT => {
192 let Some((_, bdc_packet)) = BdcHeader::parse(payload) else {
193 warn!("BDC event, incomplete header");
194 return;
195 };
196
197 let Some((event_packet, evt_data)) = EventPacket::parse(bdc_packet) else {
198 warn!("BDC event, incomplete data");
199 return;
200 };
201
202 const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h
203 if event_packet.eth.ether_type != ETH_P_LINK_CTL {
204 warn!(
205 "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}",
206 event_packet.eth.ether_type, ETH_P_LINK_CTL
207 );
208 return;
209 }
210 const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18];
211 if event_packet.hdr.oui != BROADCOM_OUI {
212 warn!(
213 "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}",
214 Bytes(&event_packet.hdr.oui),
215 Bytes(BROADCOM_OUI)
216 );
217 return;
218 }
219 const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769;
220 if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG {
221 warn!("unexpected subtype {}", event_packet.hdr.subtype);
222 return;
223 }
224
225 const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1;
226 if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT {
227 warn!("unexpected user_subtype {}", event_packet.hdr.subtype);
228 return;
229 }
230
231 let evt_type = events::Event::from(event_packet.msg.event_type as u8);
232 debug!(
233 "=== EVENT {:?}: {:?} {:02x}",
234 evt_type,
235 event_packet.msg,
236 Bytes(evt_data)
237 );
238
239 if self.events.mask.is_enabled(evt_type) {
240 let status = event_packet.msg.status;
241 let event_payload = match evt_type {
242 Event::ESCAN_RESULT if status == EStatus::PARTIAL => {
243 let Some((_, bss_info)) = ScanResults::parse(evt_data) else {
244 return;
245 };
246 let Some(bss_info) = BssInfo::parse(bss_info) else {
247 return;
248 };
249 events::Payload::BssInfo(*bss_info)
250 }
251 Event::ESCAN_RESULT => events::Payload::None,
252 _ => events::Payload::None,
253 };
254
255 // this intentionally uses the non-blocking publish immediate
256 // publish() is a deadlock risk in the current design as awaiting here prevents ioctls
257 // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event
258 // (if they are actively awaiting the queue)
259 self.events.queue.publish_immediate(events::Message::new(
260 Status {
261 event_type: evt_type,
262 status,
263 },
264 event_payload,
265 ));
266 }
267 }
268 CHANNEL_TYPE_DATA => {
269 let Some((_, packet)) = BdcHeader::parse(payload) else {
270 return;
271 };
272 trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
273
274 match self.ch.try_rx_buf() {
275 Some(buf) => {
276 buf[..packet.len()].copy_from_slice(packet);
277 self.ch.rx_done(packet.len())
278 }
279 None => warn!("failed to push rxd packet to the channel."),
280 }
281 }
282 _ => {}
283 } 25 }
284 } 26 }
285
286 fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) {
287 if sdpcm_header.channel_and_flags & 0xf < 3 {
288 let mut sdpcm_seq_max = sdpcm_header.bus_data_credit;
289 if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 {
290 sdpcm_seq_max = self.sdpcm_seq + 2;
291 }
292 self.sdpcm_seq_max = sdpcm_seq_max;
293 }
294 }
295
296 fn has_credit(&self) -> bool {
297 self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0
298 }
299
300 async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) {
301 let mut buf = [0; 512];
302 let buf8 = slice8_mut(&mut buf);
303
304 let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
305
306 let sdpcm_seq = self.sdpcm_seq;
307 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
308 self.ioctl_id = self.ioctl_id.wrapping_add(1);
309
310 let sdpcm_header = SdpcmHeader {
311 len: total_len as u16, // TODO does this len need to be rounded up to u32?
312 len_inv: !total_len as u16,
313 sequence: sdpcm_seq,
314 channel_and_flags: CHANNEL_TYPE_CONTROL,
315 next_length: 0,
316 header_length: SdpcmHeader::SIZE as _,
317 wireless_flow_control: 0,
318 bus_data_credit: 0,
319 reserved: [0, 0],
320 };
321
322 let cdc_header = CdcHeader {
323 cmd: cmd,
324 len: data.len() as _,
325 flags: kind as u16 | (iface as u16) << 12,
326 id: self.ioctl_id,
327 status: 0,
328 };
329 trace!("tx {:?}", sdpcm_header);
330 trace!(" {:?}", cdc_header);
331
332 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
333 buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes());
334 buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data);
335
336 let total_len = (total_len + 3) & !3; // round up to 4byte
337
338 trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)]));
339
340 self.bus.wlan_write(&buf[..total_len / 4]).await;
341 }
342} 27}