aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkbleeke <[email protected]>2023-03-02 12:10:13 +0100
committerkbleeke <[email protected]>2023-03-22 15:35:02 +0100
commit20923080e6ea313278b5f3aa8ec21055c6208527 (patch)
treeb30e9545302fa9ef68dfa25748602877f838f722 /src
parent8b24fe3df02862991b2574f9d5c9ada7bd27706b (diff)
split lib.rs into multiple files
Diffstat (limited to 'src')
-rw-r--r--src/control.rs299
-rw-r--r--src/lib.rs888
-rw-r--r--src/nvram.rs54
-rw-r--r--src/runner.rs564
4 files changed, 925 insertions, 880 deletions
diff --git a/src/control.rs b/src/control.rs
new file mode 100644
index 000000000..7f1c9fe86
--- /dev/null
+++ b/src/control.rs
@@ -0,0 +1,299 @@
1use core::cell::Cell;
2use core::cmp::{max, min};
3
4use ch::driver::LinkState;
5use embassy_futures::yield_now;
6use embassy_net_driver_channel as ch;
7use embassy_time::{Duration, Timer};
8
9pub use crate::bus::SpiBusCyw43;
10use crate::consts::*;
11use crate::events::{Event, EventQueue};
12use crate::structs::*;
13use crate::{countries, IoctlState, IoctlType, PowerManagementMode};
14
15pub struct Control<'a> {
16 state_ch: ch::StateRunner<'a>,
17 event_sub: &'a EventQueue,
18 ioctl_state: &'a Cell<IoctlState>,
19}
20
21impl<'a> Control<'a> {
22 pub(crate) fn new(
23 state_ch: ch::StateRunner<'a>,
24 event_sub: &'a EventQueue,
25 ioctl_state: &'a Cell<IoctlState>,
26 ) -> Self {
27 Self {
28 state_ch,
29 event_sub,
30 ioctl_state,
31 }
32 }
33
34 pub async fn init(&mut self, clm: &[u8]) {
35 const CHUNK_SIZE: usize = 1024;
36
37 info!("Downloading CLM...");
38
39 let mut offs = 0;
40 for chunk in clm.chunks(CHUNK_SIZE) {
41 let mut flag = DOWNLOAD_FLAG_HANDLER_VER;
42 if offs == 0 {
43 flag |= DOWNLOAD_FLAG_BEGIN;
44 }
45 offs += chunk.len();
46 if offs == clm.len() {
47 flag |= DOWNLOAD_FLAG_END;
48 }
49
50 let header = DownloadHeader {
51 flag,
52 dload_type: DOWNLOAD_TYPE_CLM,
53 len: chunk.len() as _,
54 crc: 0,
55 };
56 let mut buf = [0; 8 + 12 + CHUNK_SIZE];
57 buf[0..8].copy_from_slice(b"clmload\x00");
58 buf[8..20].copy_from_slice(&header.to_bytes());
59 buf[20..][..chunk.len()].copy_from_slice(&chunk);
60 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()])
61 .await;
62 }
63
64 // check clmload ok
65 assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
66
67 info!("Configuring misc stuff...");
68
69 // Disable tx gloming which transfers multiple packets in one request.
70 // 'glom' is short for "conglomerate" which means "gather together into
71 // a compact mass".
72 self.set_iovar_u32("bus:txglom", 0).await;
73 self.set_iovar_u32("apsta", 1).await;
74
75 // read MAC addr.
76 let mut mac_addr = [0; 6];
77 assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
78 info!("mac addr: {:02x}", mac_addr);
79
80 let country = countries::WORLD_WIDE_XX;
81 let country_info = CountryInfo {
82 country_abbrev: [country.code[0], country.code[1], 0, 0],
83 country_code: [country.code[0], country.code[1], 0, 0],
84 rev: if country.rev == 0 { -1 } else { country.rev as _ },
85 };
86 self.set_iovar("country", &country_info.to_bytes()).await;
87
88 // set country takes some time, next ioctls fail if we don't wait.
89 Timer::after(Duration::from_millis(100)).await;
90
91 // Set antenna to chip antenna
92 self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
93
94 self.set_iovar_u32("bus:txglom", 0).await;
95 Timer::after(Duration::from_millis(100)).await;
96 //self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
97 //Timer::after(Duration::from_millis(100)).await;
98 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
99 Timer::after(Duration::from_millis(100)).await;
100 self.set_iovar_u32("ampdu_mpdu", 4).await;
101 Timer::after(Duration::from_millis(100)).await;
102 //self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
103
104 //Timer::after(Duration::from_millis(100)).await;
105
106 // evts
107 let mut evts = EventMask {
108 iface: 0,
109 events: [0xFF; 24],
110 };
111
112 // Disable spammy uninteresting events.
113 evts.unset(Event::RADIO);
114 evts.unset(Event::IF);
115 evts.unset(Event::PROBREQ_MSG);
116 evts.unset(Event::PROBREQ_MSG_RX);
117 evts.unset(Event::PROBRESP_MSG);
118 evts.unset(Event::PROBRESP_MSG);
119 evts.unset(Event::ROAM);
120
121 self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
122
123 Timer::after(Duration::from_millis(100)).await;
124
125 // set wifi up
126 self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
127
128 Timer::after(Duration::from_millis(100)).await;
129
130 self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
131 self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
132
133 Timer::after(Duration::from_millis(100)).await;
134
135 self.state_ch.set_ethernet_address(mac_addr);
136 self.state_ch.set_link_state(LinkState::Up); // TODO do on join/leave
137
138 info!("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) {
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 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes())
167 .await; // set_ssid
168
169 info!("JOINED");
170 }
171
172 pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) {
173 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
174
175 self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2
176 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await;
177 self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
178 self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
179
180 Timer::after(Duration::from_millis(100)).await;
181
182 let mut pfi = PassphraseInfo {
183 len: passphrase.len() as _,
184 flags: 1,
185 passphrase: [0; 64],
186 };
187 pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes());
188 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes())
189 .await; // WLC_SET_WSEC_PMK
190
191 self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1
192 self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open)
193 self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth
194
195 let mut i = SsidInfo {
196 len: ssid.len() as _,
197 ssid: [0; 32],
198 };
199 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
200
201 let mut subscriber = self.event_sub.subscriber().unwrap();
202 self.ioctl(IoctlType::Set, 26, 0, &mut i.to_bytes()).await; // set_ssid
203
204 loop {
205 let msg = subscriber.next_message_pure().await;
206 if msg.event_type == Event::AUTH && msg.status != 0 {
207 // retry
208 defmt::warn!("JOIN failed with status={}", msg.status);
209 self.ioctl(IoctlType::Set, 26, 0, &mut i.to_bytes()).await;
210 } else if msg.event_type == Event::JOIN && msg.status == 0 {
211 // successful join
212 break;
213 }
214 }
215
216 info!("JOINED");
217 }
218
219 pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) {
220 assert!(gpio_n < 3);
221 self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 })
222 .await
223 }
224
225 async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) {
226 let mut buf = [0; 8];
227 buf[0..4].copy_from_slice(&val1.to_le_bytes());
228 buf[4..8].copy_from_slice(&val2.to_le_bytes());
229 self.set_iovar(name, &buf).await
230 }
231
232 async fn set_iovar_u32(&mut self, name: &str, val: u32) {
233 self.set_iovar(name, &val.to_le_bytes()).await
234 }
235
236 async fn get_iovar_u32(&mut self, name: &str) -> u32 {
237 let mut buf = [0; 4];
238 let len = self.get_iovar(name, &mut buf).await;
239 assert_eq!(len, 4);
240 u32::from_le_bytes(buf)
241 }
242
243 async fn set_iovar(&mut self, name: &str, val: &[u8]) {
244 info!("set {} = {:02x}", name, val);
245
246 let mut buf = [0; 64];
247 buf[..name.len()].copy_from_slice(name.as_bytes());
248 buf[name.len()] = 0;
249 buf[name.len() + 1..][..val.len()].copy_from_slice(val);
250
251 let total_len = name.len() + 1 + val.len();
252 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len])
253 .await;
254 }
255
256 // TODO this is not really working, it always returns all zeros.
257 async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize {
258 info!("get {}", name);
259
260 let mut buf = [0; 64];
261 buf[..name.len()].copy_from_slice(name.as_bytes());
262 buf[name.len()] = 0;
263
264 let total_len = max(name.len() + 1, res.len());
265 let res_len = self
266 .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len])
267 .await;
268
269 let out_len = min(res.len(), res_len);
270 res[..out_len].copy_from_slice(&buf[..out_len]);
271 out_len
272 }
273
274 async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) {
275 let mut buf = val.to_le_bytes();
276 self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await;
277 }
278
279 async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
280 // TODO cancel ioctl on future drop.
281
282 while !matches!(self.ioctl_state.get(), IoctlState::Idle) {
283 yield_now().await;
284 }
285
286 self.ioctl_state.set(IoctlState::Pending { kind, cmd, iface, buf });
287
288 let resp_len = loop {
289 if let IoctlState::Done { resp_len } = self.ioctl_state.get() {
290 break resp_len;
291 }
292 yield_now().await;
293 };
294
295 self.ioctl_state.set(IoctlState::Idle);
296
297 resp_len
298 }
299}
diff --git a/src/lib.rs b/src/lib.rs
index 1b7d603d7..af8f74a6d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,23 +13,20 @@ mod countries;
13mod events; 13mod events;
14mod structs; 14mod structs;
15 15
16mod control;
17mod nvram;
18mod runner;
19
16use core::cell::Cell; 20use core::cell::Cell;
17use core::cmp::{max, min};
18use core::slice;
19 21
20use ch::driver::LinkState;
21use embassy_futures::yield_now;
22use embassy_net_driver_channel as ch; 22use embassy_net_driver_channel as ch;
23use embassy_sync::pubsub::PubSubBehavior;
24use embassy_time::{block_for, Duration, Timer};
25use embedded_hal_1::digital::OutputPin; 23use embedded_hal_1::digital::OutputPin;
26use events::EventQueue; 24use events::EventQueue;
27 25
28use crate::bus::Bus; 26use crate::bus::Bus;
29pub use crate::bus::SpiBusCyw43; 27pub use crate::bus::SpiBusCyw43;
30use crate::consts::*; 28pub use crate::control::Control;
31use crate::events::{Event, EventStatus}; 29pub use crate::runner::Runner;
32use crate::structs::*;
33 30
34const MTU: usize = 1514; 31const MTU: usize = 1514;
35 32
@@ -143,12 +140,6 @@ impl State {
143 } 140 }
144} 141}
145 142
146pub struct Control<'a> {
147 state_ch: ch::StateRunner<'a>,
148 event_sub: &'a EventQueue,
149 ioctl_state: &'a Cell<IoctlState>,
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq)] 143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
153pub enum PowerManagementMode { 144pub enum PowerManagementMode {
154 /// Custom, officially unsupported mode. Use at your own risk. 145 /// Custom, officially unsupported mode. Use at your own risk.
@@ -233,297 +224,6 @@ impl PowerManagementMode {
233 } 224 }
234} 225}
235 226
236impl<'a> Control<'a> {
237 pub async fn init(&mut self, clm: &[u8]) {
238 const CHUNK_SIZE: usize = 1024;
239
240 info!("Downloading CLM...");
241
242 let mut offs = 0;
243 for chunk in clm.chunks(CHUNK_SIZE) {
244 let mut flag = DOWNLOAD_FLAG_HANDLER_VER;
245 if offs == 0 {
246 flag |= DOWNLOAD_FLAG_BEGIN;
247 }
248 offs += chunk.len();
249 if offs == clm.len() {
250 flag |= DOWNLOAD_FLAG_END;
251 }
252
253 let header = DownloadHeader {
254 flag,
255 dload_type: DOWNLOAD_TYPE_CLM,
256 len: chunk.len() as _,
257 crc: 0,
258 };
259 let mut buf = [0; 8 + 12 + CHUNK_SIZE];
260 buf[0..8].copy_from_slice(b"clmload\x00");
261 buf[8..20].copy_from_slice(&header.to_bytes());
262 buf[20..][..chunk.len()].copy_from_slice(&chunk);
263 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()])
264 .await;
265 }
266
267 // check clmload ok
268 assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
269
270 info!("Configuring misc stuff...");
271
272 // Disable tx gloming which transfers multiple packets in one request.
273 // 'glom' is short for "conglomerate" which means "gather together into
274 // a compact mass".
275 self.set_iovar_u32("bus:txglom", 0).await;
276 self.set_iovar_u32("apsta", 1).await;
277
278 // read MAC addr.
279 let mut mac_addr = [0; 6];
280 assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
281 info!("mac addr: {:02x}", mac_addr);
282
283 let country = countries::WORLD_WIDE_XX;
284 let country_info = CountryInfo {
285 country_abbrev: [country.code[0], country.code[1], 0, 0],
286 country_code: [country.code[0], country.code[1], 0, 0],
287 rev: if country.rev == 0 { -1 } else { country.rev as _ },
288 };
289 self.set_iovar("country", &country_info.to_bytes()).await;
290
291 // set country takes some time, next ioctls fail if we don't wait.
292 Timer::after(Duration::from_millis(100)).await;
293
294 // Set antenna to chip antenna
295 self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
296
297 self.set_iovar_u32("bus:txglom", 0).await;
298 Timer::after(Duration::from_millis(100)).await;
299 //self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
300 //Timer::after(Duration::from_millis(100)).await;
301 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
302 Timer::after(Duration::from_millis(100)).await;
303 self.set_iovar_u32("ampdu_mpdu", 4).await;
304 Timer::after(Duration::from_millis(100)).await;
305 //self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
306
307 //Timer::after(Duration::from_millis(100)).await;
308
309 // evts
310 let mut evts = EventMask {
311 iface: 0,
312 events: [0xFF; 24],
313 };
314
315 // Disable spammy uninteresting events.
316 evts.unset(Event::RADIO);
317 evts.unset(Event::IF);
318 evts.unset(Event::PROBREQ_MSG);
319 evts.unset(Event::PROBREQ_MSG_RX);
320 evts.unset(Event::PROBRESP_MSG);
321 evts.unset(Event::PROBRESP_MSG);
322 evts.unset(Event::ROAM);
323
324 self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
325
326 Timer::after(Duration::from_millis(100)).await;
327
328 // set wifi up
329 self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
330
331 Timer::after(Duration::from_millis(100)).await;
332
333 self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
334 self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
335
336 Timer::after(Duration::from_millis(100)).await;
337
338 self.state_ch.set_ethernet_address(mac_addr);
339 self.state_ch.set_link_state(LinkState::Up); // TODO do on join/leave
340
341 info!("INIT DONE");
342 }
343
344 pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
345 // power save mode
346 let mode_num = mode.mode();
347 if mode_num == 2 {
348 self.set_iovar_u32("pm2_sleep_ret", mode.sleep_ret_ms() as u32).await;
349 self.set_iovar_u32("bcn_li_bcn", mode.beacon_period() as u32).await;
350 self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await;
351 self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await;
352 }
353 self.ioctl_set_u32(86, 0, mode_num).await;
354 }
355
356 pub async fn join_open(&mut self, ssid: &str) {
357 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
358
359 self.ioctl_set_u32(134, 0, 0).await; // wsec = open
360 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await;
361 self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1
362 self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0)
363
364 let mut i = SsidInfo {
365 len: ssid.len() as _,
366 ssid: [0; 32],
367 };
368 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
369 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes())
370 .await; // set_ssid
371
372 info!("JOINED");
373 }
374
375 pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) {
376 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
377
378 self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2
379 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await;
380 self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
381 self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
382
383 Timer::after(Duration::from_millis(100)).await;
384
385 let mut pfi = PassphraseInfo {
386 len: passphrase.len() as _,
387 flags: 1,
388 passphrase: [0; 64],
389 };
390 pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes());
391 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes())
392 .await; // WLC_SET_WSEC_PMK
393
394 self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1
395 self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open)
396 self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth
397
398 let mut i = SsidInfo {
399 len: ssid.len() as _,
400 ssid: [0; 32],
401 };
402 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
403
404 let mut subscriber = self.event_sub.subscriber().unwrap();
405 self.ioctl(IoctlType::Set, 26, 0, &mut i.to_bytes()).await; // set_ssid
406
407 loop {
408 let msg = subscriber.next_message_pure().await;
409 if msg.event_type == Event::AUTH && msg.status != 0 {
410 // retry
411 defmt::warn!("JOIN failed with status={}", msg.status);
412 self.ioctl(IoctlType::Set, 26, 0, &mut i.to_bytes()).await;
413 } else if msg.event_type == Event::JOIN && msg.status == 0 {
414 // successful join
415 break;
416 }
417 }
418
419 info!("JOINED");
420 }
421
422 pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) {
423 assert!(gpio_n < 3);
424 self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 })
425 .await
426 }
427
428 async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) {
429 let mut buf = [0; 8];
430 buf[0..4].copy_from_slice(&val1.to_le_bytes());
431 buf[4..8].copy_from_slice(&val2.to_le_bytes());
432 self.set_iovar(name, &buf).await
433 }
434
435 async fn set_iovar_u32(&mut self, name: &str, val: u32) {
436 self.set_iovar(name, &val.to_le_bytes()).await
437 }
438
439 async fn get_iovar_u32(&mut self, name: &str) -> u32 {
440 let mut buf = [0; 4];
441 let len = self.get_iovar(name, &mut buf).await;
442 assert_eq!(len, 4);
443 u32::from_le_bytes(buf)
444 }
445
446 async fn set_iovar(&mut self, name: &str, val: &[u8]) {
447 info!("set {} = {:02x}", name, val);
448
449 let mut buf = [0; 64];
450 buf[..name.len()].copy_from_slice(name.as_bytes());
451 buf[name.len()] = 0;
452 buf[name.len() + 1..][..val.len()].copy_from_slice(val);
453
454 let total_len = name.len() + 1 + val.len();
455 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len])
456 .await;
457 }
458
459 // TODO this is not really working, it always returns all zeros.
460 async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize {
461 info!("get {}", name);
462
463 let mut buf = [0; 64];
464 buf[..name.len()].copy_from_slice(name.as_bytes());
465 buf[name.len()] = 0;
466
467 let total_len = max(name.len() + 1, res.len());
468 let res_len = self
469 .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len])
470 .await;
471
472 let out_len = min(res.len(), res_len);
473 res[..out_len].copy_from_slice(&buf[..out_len]);
474 out_len
475 }
476
477 async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) {
478 let mut buf = val.to_le_bytes();
479 self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await;
480 }
481
482 async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
483 // TODO cancel ioctl on future drop.
484
485 while !matches!(self.ioctl_state.get(), IoctlState::Idle) {
486 yield_now().await;
487 }
488
489 self.ioctl_state.set(IoctlState::Pending { kind, cmd, iface, buf });
490
491 let resp_len = loop {
492 if let IoctlState::Done { resp_len } = self.ioctl_state.get() {
493 break resp_len;
494 }
495 yield_now().await;
496 };
497
498 self.ioctl_state.set(IoctlState::Idle);
499
500 resp_len
501 }
502}
503
504pub struct Runner<'a, PWR, SPI> {
505 ch: ch::Runner<'a, MTU>,
506 bus: Bus<PWR, SPI>,
507
508 ioctl_state: &'a Cell<IoctlState>,
509 ioctl_id: u16,
510 sdpcm_seq: u8,
511 sdpcm_seq_max: u8,
512
513 events: &'a EventQueue,
514
515 #[cfg(feature = "firmware-logs")]
516 log: LogState,
517}
518
519#[cfg(feature = "firmware-logs")]
520struct LogState {
521 addr: u32,
522 last_idx: usize,
523 buf: [u8; 256],
524 buf_count: usize,
525}
526
527pub type NetDriver<'a> = ch::Device<'a, MTU>; 227pub type NetDriver<'a> = ch::Device<'a, MTU>;
528 228
529pub async fn new<'a, PWR, SPI>( 229pub async fn new<'a, PWR, SPI>(
@@ -539,585 +239,13 @@ where
539 let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); 239 let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
540 let state_ch = ch_runner.state_runner(); 240 let state_ch = ch_runner.state_runner();
541 241
542 let mut runner = Runner { 242 let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events);
543 ch: ch_runner,
544 bus: Bus::new(pwr, spi),
545
546 ioctl_state: &state.ioctl_state,
547 ioctl_id: 0,
548 sdpcm_seq: 0,
549 sdpcm_seq_max: 1,
550
551 events: &state.events,
552
553 #[cfg(feature = "firmware-logs")]
554 log: LogState {
555 addr: 0,
556 last_idx: 0,
557 buf: [0; 256],
558 buf_count: 0,
559 },
560 };
561 243
562 runner.init(firmware).await; 244 runner.init(firmware).await;
563 245
564 ( 246 (
565 device, 247 device,
566 Control { 248 Control::new(state_ch, &state.events, &state.ioctl_state),
567 state_ch,
568 event_sub: &&state.events,
569 ioctl_state: &state.ioctl_state,
570 },
571 runner, 249 runner,
572 ) 250 )
573} 251}
574
575impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
576where
577 PWR: OutputPin,
578 SPI: SpiBusCyw43,
579{
580 async fn init(&mut self, firmware: &[u8]) {
581 self.bus.init().await;
582
583 // Init ALP (Active Low Power) clock
584 self.bus
585 .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ)
586 .await;
587 info!("waiting for clock...");
588 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
589 info!("clock ok");
590
591 let chip_id = self.bus.bp_read16(0x1800_0000).await;
592 info!("chip ID: {}", chip_id);
593
594 // Upload firmware.
595 self.core_disable(Core::WLAN).await;
596 self.core_reset(Core::SOCSRAM).await;
597 self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await;
598 self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await;
599
600 let ram_addr = CHIP.atcm_ram_base_address;
601
602 info!("loading fw");
603 self.bus.bp_write(ram_addr, firmware).await;
604
605 info!("loading nvram");
606 // Round up to 4 bytes.
607 let nvram_len = (NVRAM.len() + 3) / 4 * 4;
608 self.bus
609 .bp_write(ram_addr + CHIP.chip_ram_size - 4 - nvram_len as u32, NVRAM)
610 .await;
611
612 let nvram_len_words = nvram_len as u32 / 4;
613 let nvram_len_magic = (!nvram_len_words << 16) | nvram_len_words;
614 self.bus
615 .bp_write32(ram_addr + CHIP.chip_ram_size - 4, nvram_len_magic)
616 .await;
617
618 // Start core!
619 info!("starting up core...");
620 self.core_reset(Core::WLAN).await;
621 assert!(self.core_is_up(Core::WLAN).await);
622
623 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
624
625 // "Set up the interrupt mask and enable interrupts"
626 self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await;
627
628 // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
629 // Sounds scary...
630 self.bus
631 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32)
632 .await;
633
634 // wait for wifi startup
635 info!("waiting for wifi init...");
636 while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
637
638 // Some random configs related to sleep.
639 // These aren't needed if we don't want to sleep the bus.
640 // TODO do we need to sleep the bus to read the irq line, due to
641 // being on the same pin as MOSI/MISO?
642
643 /*
644 let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL).await;
645 val |= 0x02; // WAKE_TILL_HT_AVAIL
646 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL, val).await;
647 self.bus.write8(FUNC_BUS, 0xF0, 0x08).await; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1
648 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x02).await; // SBSDIO_FORCE_HT
649
650 let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR).await;
651 val |= 0x01; // SBSDIO_SLPCSR_KEEP_SDIO_ON
652 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR, val).await;
653 */
654
655 // clear pulls
656 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
657 let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
658
659 // start HT clock
660 //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await;
661 //info!("waiting for HT clock...");
662 //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
663 //info!("clock ok");
664
665 #[cfg(feature = "firmware-logs")]
666 self.log_init().await;
667
668 info!("init done ");
669 }
670
671 #[cfg(feature = "firmware-logs")]
672 async fn log_init(&mut self) {
673 // Initialize shared memory for logging.
674
675 let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size;
676 let shared_addr = self.bus.bp_read32(addr).await;
677 info!("shared_addr {:08x}", shared_addr);
678
679 let mut shared = [0; SharedMemData::SIZE];
680 self.bus.bp_read(shared_addr, &mut shared).await;
681 let shared = SharedMemData::from_bytes(&shared);
682 info!("shared: {:08x}", shared);
683
684 self.log.addr = shared.console_addr + 8;
685 }
686
687 #[cfg(feature = "firmware-logs")]
688 async fn log_read(&mut self) {
689 // Read log struct
690 let mut log = [0; SharedMemLog::SIZE];
691 self.bus.bp_read(self.log.addr, &mut log).await;
692 let log = SharedMemLog::from_bytes(&log);
693
694 let idx = log.idx as usize;
695
696 // If pointer hasn't moved, no need to do anything.
697 if idx == self.log.last_idx {
698 return;
699 }
700
701 // Read entire buf for now. We could read only what we need, but then we
702 // run into annoying alignment issues in `bp_read`.
703 let mut buf = [0; 0x400];
704 self.bus.bp_read(log.buf, &mut buf).await;
705
706 while self.log.last_idx != idx as usize {
707 let b = buf[self.log.last_idx];
708 if b == b'\r' || b == b'\n' {
709 if self.log.buf_count != 0 {
710 let s = unsafe { core::str::from_utf8_unchecked(&self.log.buf[..self.log.buf_count]) };
711 debug!("LOGS: {}", s);
712 self.log.buf_count = 0;
713 }
714 } else if self.log.buf_count < self.log.buf.len() {
715 self.log.buf[self.log.buf_count] = b;
716 self.log.buf_count += 1;
717 }
718
719 self.log.last_idx += 1;
720 if self.log.last_idx == 0x400 {
721 self.log.last_idx = 0;
722 }
723 }
724 }
725
726 pub async fn run(mut self) -> ! {
727 let mut buf = [0; 512];
728 loop {
729 #[cfg(feature = "firmware-logs")]
730 self.log_read().await;
731
732 // Send stuff
733 // TODO flow control not yet complete
734 if !self.has_credit() {
735 warn!("TX stalled");
736 } else {
737 if let IoctlState::Pending { kind, cmd, iface, buf } = self.ioctl_state.get() {
738 self.send_ioctl(kind, cmd, iface, unsafe { &*buf }).await;
739 self.ioctl_state.set(IoctlState::Sent { buf });
740 }
741 if !self.has_credit() {
742 warn!("TX stalled");
743 } else {
744 if let Some(packet) = self.ch.try_tx_buf() {
745 trace!("tx pkt {:02x}", &packet[..packet.len().min(48)]);
746
747 let mut buf = [0; 512];
748 let buf8 = slice8_mut(&mut buf);
749
750 let total_len = SdpcmHeader::SIZE + BcdHeader::SIZE + packet.len();
751
752 let seq = self.sdpcm_seq;
753 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
754
755 let sdpcm_header = SdpcmHeader {
756 len: total_len as u16, // TODO does this len need to be rounded up to u32?
757 len_inv: !total_len as u16,
758 sequence: seq,
759 channel_and_flags: CHANNEL_TYPE_DATA,
760 next_length: 0,
761 header_length: SdpcmHeader::SIZE as _,
762 wireless_flow_control: 0,
763 bus_data_credit: 0,
764 reserved: [0, 0],
765 };
766
767 let bcd_header = BcdHeader {
768 flags: BDC_VERSION << BDC_VERSION_SHIFT,
769 priority: 0,
770 flags2: 0,
771 data_offset: 0,
772 };
773 trace!("tx {:?}", sdpcm_header);
774 trace!(" {:?}", bcd_header);
775
776 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
777 buf8[SdpcmHeader::SIZE..][..BcdHeader::SIZE].copy_from_slice(&bcd_header.to_bytes());
778 buf8[SdpcmHeader::SIZE + BcdHeader::SIZE..][..packet.len()].copy_from_slice(packet);
779
780 let total_len = (total_len + 3) & !3; // round up to 4byte
781
782 trace!(" {:02x}", &buf8[..total_len.min(48)]);
783
784 self.bus.wlan_write(&buf[..(total_len / 4)]).await;
785 self.ch.tx_done();
786 }
787 }
788 }
789
790 // Receive stuff
791 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
792
793 if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
794 let mut status = 0xFFFF_FFFF;
795 while status == 0xFFFF_FFFF {
796 status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await;
797 }
798
799 if status & STATUS_F2_PKT_AVAILABLE != 0 {
800 let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
801 self.bus.wlan_read(&mut buf, len).await;
802 trace!("rx {:02x}", &slice8_mut(&mut buf)[..(len as usize).min(48)]);
803 self.rx(&slice8_mut(&mut buf)[..len as usize]);
804 }
805 }
806
807 // TODO use IRQs
808 yield_now().await;
809 }
810 }
811
812 fn rx(&mut self, packet: &[u8]) {
813 if packet.len() < SdpcmHeader::SIZE {
814 warn!("packet too short, len={}", packet.len());
815 return;
816 }
817
818 let sdpcm_header = SdpcmHeader::from_bytes(packet[..SdpcmHeader::SIZE].try_into().unwrap());
819 trace!("rx {:?}", sdpcm_header);
820 if sdpcm_header.len != !sdpcm_header.len_inv {
821 warn!("len inv mismatch");
822 return;
823 }
824 if sdpcm_header.len as usize != packet.len() {
825 // TODO: is this guaranteed??
826 warn!("len from header doesn't match len from spi");
827 return;
828 }
829
830 self.update_credit(&sdpcm_header);
831
832 let channel = sdpcm_header.channel_and_flags & 0x0f;
833
834 let payload = &packet[sdpcm_header.header_length as _..];
835
836 match channel {
837 CHANNEL_TYPE_CONTROL => {
838 if payload.len() < CdcHeader::SIZE {
839 warn!("payload too short, len={}", payload.len());
840 return;
841 }
842
843 let cdc_header = CdcHeader::from_bytes(payload[..CdcHeader::SIZE].try_into().unwrap());
844 trace!(" {:?}", cdc_header);
845
846 if let IoctlState::Sent { buf } = self.ioctl_state.get() {
847 if cdc_header.id == self.ioctl_id {
848 if cdc_header.status != 0 {
849 // TODO: propagate error instead
850 panic!("IOCTL error {=i32}", cdc_header.status as i32);
851 }
852
853 let resp_len = cdc_header.len as usize;
854 info!("IOCTL Response: {:02x}", &payload[CdcHeader::SIZE..][..resp_len]);
855
856 (unsafe { &mut *buf }[..resp_len]).copy_from_slice(&payload[CdcHeader::SIZE..][..resp_len]);
857 self.ioctl_state.set(IoctlState::Done { resp_len });
858 }
859 }
860 }
861 CHANNEL_TYPE_EVENT => {
862 let bcd_header = BcdHeader::from_bytes(&payload[..BcdHeader::SIZE].try_into().unwrap());
863 trace!(" {:?}", bcd_header);
864
865 let packet_start = BcdHeader::SIZE + 4 * bcd_header.data_offset as usize;
866
867 if packet_start + EventPacket::SIZE > payload.len() {
868 warn!("BCD event, incomplete header");
869 return;
870 }
871 let bcd_packet = &payload[packet_start..];
872 trace!(" {:02x}", &bcd_packet[..(bcd_packet.len() as usize).min(36)]);
873
874 let mut event_packet = EventPacket::from_bytes(&bcd_packet[..EventPacket::SIZE].try_into().unwrap());
875 event_packet.byteswap();
876
877 const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h
878 if event_packet.eth.ether_type != ETH_P_LINK_CTL {
879 warn!(
880 "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}",
881 event_packet.eth.ether_type, ETH_P_LINK_CTL
882 );
883 return;
884 }
885 const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18];
886 if event_packet.hdr.oui != BROADCOM_OUI {
887 warn!(
888 "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}",
889 event_packet.hdr.oui, BROADCOM_OUI
890 );
891 return;
892 }
893 const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769;
894 if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG {
895 warn!("unexpected subtype {}", event_packet.hdr.subtype);
896 return;
897 }
898
899 const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1;
900 if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT {
901 warn!("unexpected user_subtype {}", event_packet.hdr.subtype);
902 return;
903 }
904
905 if event_packet.msg.datalen as usize >= (bcd_packet.len() - EventMessage::SIZE) {
906 warn!("BCD event, incomplete data");
907 return;
908 }
909
910 let evt_type = events::Event::from(event_packet.msg.event_type as u8);
911 let evt_data = &bcd_packet[EventMessage::SIZE..][..event_packet.msg.datalen as usize];
912 debug!("=== EVENT {}: {} {:02x}", evt_type, event_packet.msg, evt_data);
913
914 if evt_type == events::Event::AUTH || evt_type == events::Event::JOIN {
915 self.events.publish_immediate(EventStatus {
916 status: event_packet.msg.status,
917 event_type: evt_type,
918 });
919 }
920 }
921 CHANNEL_TYPE_DATA => {
922 let bcd_header = BcdHeader::from_bytes(&payload[..BcdHeader::SIZE].try_into().unwrap());
923 trace!(" {:?}", bcd_header);
924
925 let packet_start = BcdHeader::SIZE + 4 * bcd_header.data_offset as usize;
926 if packet_start > payload.len() {
927 warn!("packet start out of range.");
928 return;
929 }
930 let packet = &payload[packet_start..];
931 trace!("rx pkt {:02x}", &packet[..(packet.len() as usize).min(48)]);
932
933 match self.ch.try_rx_buf() {
934 Some(buf) => {
935 buf[..packet.len()].copy_from_slice(packet);
936 self.ch.rx_done(packet.len())
937 }
938 None => warn!("failed to push rxd packet to the channel."),
939 }
940 }
941 _ => {}
942 }
943 }
944
945 fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) {
946 if sdpcm_header.channel_and_flags & 0xf < 3 {
947 let mut sdpcm_seq_max = sdpcm_header.bus_data_credit;
948 if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 {
949 sdpcm_seq_max = self.sdpcm_seq + 2;
950 }
951 self.sdpcm_seq_max = sdpcm_seq_max;
952 }
953 }
954
955 fn has_credit(&self) -> bool {
956 self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0
957 }
958
959 async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) {
960 let mut buf = [0; 512];
961 let buf8 = slice8_mut(&mut buf);
962
963 let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
964
965 let sdpcm_seq = self.sdpcm_seq;
966 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
967 self.ioctl_id = self.ioctl_id.wrapping_add(1);
968
969 let sdpcm_header = SdpcmHeader {
970 len: total_len as u16, // TODO does this len need to be rounded up to u32?
971 len_inv: !total_len as u16,
972 sequence: sdpcm_seq,
973 channel_and_flags: CHANNEL_TYPE_CONTROL,
974 next_length: 0,
975 header_length: SdpcmHeader::SIZE as _,
976 wireless_flow_control: 0,
977 bus_data_credit: 0,
978 reserved: [0, 0],
979 };
980
981 let cdc_header = CdcHeader {
982 cmd: cmd,
983 len: data.len() as _,
984 flags: kind as u16 | (iface as u16) << 12,
985 id: self.ioctl_id,
986 status: 0,
987 };
988 trace!("tx {:?}", sdpcm_header);
989 trace!(" {:?}", cdc_header);
990
991 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
992 buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes());
993 buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data);
994
995 let total_len = (total_len + 3) & !3; // round up to 4byte
996
997 trace!(" {:02x}", &buf8[..total_len.min(48)]);
998
999 self.bus.wlan_write(&buf[..total_len / 4]).await;
1000 }
1001
1002 async fn core_disable(&mut self, core: Core) {
1003 let base = core.base_addr();
1004
1005 // Dummy read?
1006 let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
1007
1008 // Check it isn't already reset
1009 let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
1010 if r & AI_RESETCTRL_BIT_RESET != 0 {
1011 return;
1012 }
1013
1014 self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await;
1015 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
1016
1017 block_for(Duration::from_millis(1));
1018
1019 self.bus
1020 .bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET)
1021 .await;
1022 let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
1023 }
1024
1025 async fn core_reset(&mut self, core: Core) {
1026 self.core_disable(core).await;
1027
1028 let base = core.base_addr();
1029 self.bus
1030 .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN)
1031 .await;
1032 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
1033
1034 self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
1035
1036 Timer::after(Duration::from_millis(1)).await;
1037
1038 self.bus
1039 .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
1040 .await;
1041 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
1042
1043 Timer::after(Duration::from_millis(1)).await;
1044 }
1045
1046 async fn core_is_up(&mut self, core: Core) -> bool {
1047 let base = core.base_addr();
1048
1049 let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
1050 if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN {
1051 debug!("core_is_up: returning false due to bad ioctrl {:02x}", io);
1052 return false;
1053 }
1054
1055 let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
1056 if r & (AI_RESETCTRL_BIT_RESET) != 0 {
1057 debug!("core_is_up: returning false due to bad resetctrl {:02x}", r);
1058 return false;
1059 }
1060
1061 true
1062 }
1063}
1064
1065fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
1066 let len = x.len() * 4;
1067 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
1068}
1069
1070macro_rules! nvram {
1071 ($($s:literal,)*) => {
1072 concat_bytes!($($s, b"\x00",)* b"\x00\x00")
1073 };
1074}
1075
1076static NVRAM: &'static [u8] = &*nvram!(
1077 b"NVRAMRev=$Rev$",
1078 b"manfid=0x2d0",
1079 b"prodid=0x0727",
1080 b"vendid=0x14e4",
1081 b"devid=0x43e2",
1082 b"boardtype=0x0887",
1083 b"boardrev=0x1100",
1084 b"boardnum=22",
1085 b"macaddr=00:A0:50:b5:59:5e",
1086 b"sromrev=11",
1087 b"boardflags=0x00404001",
1088 b"boardflags3=0x04000000",
1089 b"xtalfreq=37400",
1090 b"nocrc=1",
1091 b"ag0=255",
1092 b"aa2g=1",
1093 b"ccode=ALL",
1094 b"pa0itssit=0x20",
1095 b"extpagain2g=0",
1096 b"pa2ga0=-168,6649,-778",
1097 b"AvVmid_c0=0x0,0xc8",
1098 b"cckpwroffset0=5",
1099 b"maxp2ga0=84",
1100 b"txpwrbckof=6",
1101 b"cckbw202gpo=0",
1102 b"legofdmbw202gpo=0x66111111",
1103 b"mcsbw202gpo=0x77711111",
1104 b"propbw202gpo=0xdd",
1105 b"ofdmdigfilttype=18",
1106 b"ofdmdigfilttypebe=18",
1107 b"papdmode=1",
1108 b"papdvalidtest=1",
1109 b"pacalidx2g=45",
1110 b"papdepsoffset=-30",
1111 b"papdendidx=58",
1112 b"ltecxmux=0",
1113 b"ltecxpadnum=0x0102",
1114 b"ltecxfnsel=0x44",
1115 b"ltecxgcigpio=0x01",
1116 b"il0macaddr=00:90:4c:c5:12:38",
1117 b"wl0id=0x431b",
1118 b"deadman_to=0xffffffff",
1119 b"muxenab=0x100",
1120 b"spurconfig=0x3",
1121 b"glitch_based_crsmin=1",
1122 b"btc_mode=1",
1123);
diff --git a/src/nvram.rs b/src/nvram.rs
new file mode 100644
index 000000000..964a3128d
--- /dev/null
+++ b/src/nvram.rs
@@ -0,0 +1,54 @@
1macro_rules! nvram {
2 ($($s:literal,)*) => {
3 concat_bytes!($($s, b"\x00",)* b"\x00\x00")
4 };
5}
6
7pub static NVRAM: &'static [u8] = &*nvram!(
8 b"NVRAMRev=$Rev$",
9 b"manfid=0x2d0",
10 b"prodid=0x0727",
11 b"vendid=0x14e4",
12 b"devid=0x43e2",
13 b"boardtype=0x0887",
14 b"boardrev=0x1100",
15 b"boardnum=22",
16 b"macaddr=00:A0:50:b5:59:5e",
17 b"sromrev=11",
18 b"boardflags=0x00404001",
19 b"boardflags3=0x04000000",
20 b"xtalfreq=37400",
21 b"nocrc=1",
22 b"ag0=255",
23 b"aa2g=1",
24 b"ccode=ALL",
25 b"pa0itssit=0x20",
26 b"extpagain2g=0",
27 b"pa2ga0=-168,6649,-778",
28 b"AvVmid_c0=0x0,0xc8",
29 b"cckpwroffset0=5",
30 b"maxp2ga0=84",
31 b"txpwrbckof=6",
32 b"cckbw202gpo=0",
33 b"legofdmbw202gpo=0x66111111",
34 b"mcsbw202gpo=0x77711111",
35 b"propbw202gpo=0xdd",
36 b"ofdmdigfilttype=18",
37 b"ofdmdigfilttypebe=18",
38 b"papdmode=1",
39 b"papdvalidtest=1",
40 b"pacalidx2g=45",
41 b"papdepsoffset=-30",
42 b"papdendidx=58",
43 b"ltecxmux=0",
44 b"ltecxpadnum=0x0102",
45 b"ltecxfnsel=0x44",
46 b"ltecxgcigpio=0x01",
47 b"il0macaddr=00:90:4c:c5:12:38",
48 b"wl0id=0x431b",
49 b"deadman_to=0xffffffff",
50 b"muxenab=0x100",
51 b"spurconfig=0x3",
52 b"glitch_based_crsmin=1",
53 b"btc_mode=1",
54);
diff --git a/src/runner.rs b/src/runner.rs
new file mode 100644
index 000000000..5d840bc59
--- /dev/null
+++ b/src/runner.rs
@@ -0,0 +1,564 @@
1use core::cell::Cell;
2use core::slice;
3
4use embassy_futures::yield_now;
5use embassy_net_driver_channel as ch;
6use embassy_sync::pubsub::PubSubBehavior;
7use embassy_time::{block_for, Duration, Timer};
8use embedded_hal_1::digital::OutputPin;
9
10use crate::bus::Bus;
11pub use crate::bus::SpiBusCyw43;
12use crate::consts::*;
13use crate::events::{EventQueue, EventStatus};
14use crate::nvram::NVRAM;
15use crate::structs::*;
16use crate::{events, Core, IoctlState, IoctlType, CHIP, MTU};
17
18#[cfg(feature = "firmware-logs")]
19struct LogState {
20 addr: u32,
21 last_idx: usize,
22 buf: [u8; 256],
23 buf_count: usize,
24}
25
26impl Default for LogState {
27 fn default() -> Self {
28 Self {
29 addr: Default::default(),
30 last_idx: Default::default(),
31 buf: [0; 256],
32 buf_count: Default::default(),
33 }
34 }
35}
36
37pub struct Runner<'a, PWR, SPI> {
38 ch: ch::Runner<'a, MTU>,
39 bus: Bus<PWR, SPI>,
40
41 ioctl_state: &'a Cell<IoctlState>,
42 ioctl_id: u16,
43 sdpcm_seq: u8,
44 sdpcm_seq_max: u8,
45
46 events: &'a EventQueue,
47
48 #[cfg(feature = "firmware-logs")]
49 log: LogState,
50}
51
52impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
53where
54 PWR: OutputPin,
55 SPI: SpiBusCyw43,
56{
57 pub(crate) fn new(
58 ch: ch::Runner<'a, MTU>,
59 bus: Bus<PWR, SPI>,
60 ioctl_state: &'a Cell<IoctlState>,
61 events: &'a EventQueue,
62 ) -> Self {
63 Self {
64 ch,
65 bus,
66 ioctl_state,
67 ioctl_id: 0,
68 sdpcm_seq: 0,
69 sdpcm_seq_max: 1,
70 events,
71 #[cfg(feature = "firmware-logs")]
72 log: LogState::default(),
73 }
74 }
75
76 pub(crate) async fn init(&mut self, firmware: &[u8]) {
77 self.bus.init().await;
78
79 // Init ALP (Active Low Power) clock
80 self.bus
81 .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ)
82 .await;
83 info!("waiting for clock...");
84 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
85 info!("clock ok");
86
87 let chip_id = self.bus.bp_read16(0x1800_0000).await;
88 info!("chip ID: {}", chip_id);
89
90 // Upload firmware.
91 self.core_disable(Core::WLAN).await;
92 self.core_reset(Core::SOCSRAM).await;
93 self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await;
94 self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await;
95
96 let ram_addr = CHIP.atcm_ram_base_address;
97
98 info!("loading fw");
99 self.bus.bp_write(ram_addr, firmware).await;
100
101 info!("loading nvram");
102 // Round up to 4 bytes.
103 let nvram_len = (NVRAM.len() + 3) / 4 * 4;
104 self.bus
105 .bp_write(ram_addr + CHIP.chip_ram_size - 4 - nvram_len as u32, NVRAM)
106 .await;
107
108 let nvram_len_words = nvram_len as u32 / 4;
109 let nvram_len_magic = (!nvram_len_words << 16) | nvram_len_words;
110 self.bus
111 .bp_write32(ram_addr + CHIP.chip_ram_size - 4, nvram_len_magic)
112 .await;
113
114 // Start core!
115 info!("starting up core...");
116 self.core_reset(Core::WLAN).await;
117 assert!(self.core_is_up(Core::WLAN).await);
118
119 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
120
121 // "Set up the interrupt mask and enable interrupts"
122 self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await;
123
124 // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
125 // Sounds scary...
126 self.bus
127 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32)
128 .await;
129
130 // wait for wifi startup
131 info!("waiting for wifi init...");
132 while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
133
134 // Some random configs related to sleep.
135 // These aren't needed if we don't want to sleep the bus.
136 // TODO do we need to sleep the bus to read the irq line, due to
137 // being on the same pin as MOSI/MISO?
138
139 /*
140 let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL).await;
141 val |= 0x02; // WAKE_TILL_HT_AVAIL
142 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL, val).await;
143 self.bus.write8(FUNC_BUS, 0xF0, 0x08).await; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1
144 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x02).await; // SBSDIO_FORCE_HT
145
146 let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR).await;
147 val |= 0x01; // SBSDIO_SLPCSR_KEEP_SDIO_ON
148 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR, val).await;
149 */
150
151 // clear pulls
152 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
153 let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
154
155 // start HT clock
156 //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await;
157 //info!("waiting for HT clock...");
158 //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
159 //info!("clock ok");
160
161 #[cfg(feature = "firmware-logs")]
162 self.log_init().await;
163
164 info!("init done ");
165 }
166
167 #[cfg(feature = "firmware-logs")]
168 async fn log_init(&mut self) {
169 // Initialize shared memory for logging.
170
171 let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size;
172 let shared_addr = self.bus.bp_read32(addr).await;
173 info!("shared_addr {:08x}", shared_addr);
174
175 let mut shared = [0; SharedMemData::SIZE];
176 self.bus.bp_read(shared_addr, &mut shared).await;
177 let shared = SharedMemData::from_bytes(&shared);
178 info!("shared: {:08x}", shared);
179
180 self.log.addr = shared.console_addr + 8;
181 }
182
183 #[cfg(feature = "firmware-logs")]
184 async fn log_read(&mut self) {
185 // Read log struct
186 let mut log = [0; SharedMemLog::SIZE];
187 self.bus.bp_read(self.log.addr, &mut log).await;
188 let log = SharedMemLog::from_bytes(&log);
189
190 let idx = log.idx as usize;
191
192 // If pointer hasn't moved, no need to do anything.
193 if idx == self.log.last_idx {
194 return;
195 }
196
197 // Read entire buf for now. We could read only what we need, but then we
198 // run into annoying alignment issues in `bp_read`.
199 let mut buf = [0; 0x400];
200 self.bus.bp_read(log.buf, &mut buf).await;
201
202 while self.log.last_idx != idx as usize {
203 let b = buf[self.log.last_idx];
204 if b == b'\r' || b == b'\n' {
205 if self.log.buf_count != 0 {
206 let s = unsafe { core::str::from_utf8_unchecked(&self.log.buf[..self.log.buf_count]) };
207 debug!("LOGS: {}", s);
208 self.log.buf_count = 0;
209 }
210 } else if self.log.buf_count < self.log.buf.len() {
211 self.log.buf[self.log.buf_count] = b;
212 self.log.buf_count += 1;
213 }
214
215 self.log.last_idx += 1;
216 if self.log.last_idx == 0x400 {
217 self.log.last_idx = 0;
218 }
219 }
220 }
221
222 pub async fn run(mut self) -> ! {
223 let mut buf = [0; 512];
224 loop {
225 #[cfg(feature = "firmware-logs")]
226 self.log_read().await;
227
228 // Send stuff
229 // TODO flow control not yet complete
230 if !self.has_credit() {
231 warn!("TX stalled");
232 } else {
233 if let IoctlState::Pending { kind, cmd, iface, buf } = self.ioctl_state.get() {
234 self.send_ioctl(kind, cmd, iface, unsafe { &*buf }).await;
235 self.ioctl_state.set(IoctlState::Sent { buf });
236 }
237 if !self.has_credit() {
238 warn!("TX stalled");
239 } else {
240 if let Some(packet) = self.ch.try_tx_buf() {
241 trace!("tx pkt {:02x}", &packet[..packet.len().min(48)]);
242
243 let mut buf = [0; 512];
244 let buf8 = slice8_mut(&mut buf);
245
246 let total_len = SdpcmHeader::SIZE + BcdHeader::SIZE + packet.len();
247
248 let seq = self.sdpcm_seq;
249 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
250
251 let sdpcm_header = SdpcmHeader {
252 len: total_len as u16, // TODO does this len need to be rounded up to u32?
253 len_inv: !total_len as u16,
254 sequence: seq,
255 channel_and_flags: CHANNEL_TYPE_DATA,
256 next_length: 0,
257 header_length: SdpcmHeader::SIZE as _,
258 wireless_flow_control: 0,
259 bus_data_credit: 0,
260 reserved: [0, 0],
261 };
262
263 let bcd_header = BcdHeader {
264 flags: BDC_VERSION << BDC_VERSION_SHIFT,
265 priority: 0,
266 flags2: 0,
267 data_offset: 0,
268 };
269 trace!("tx {:?}", sdpcm_header);
270 trace!(" {:?}", bcd_header);
271
272 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
273 buf8[SdpcmHeader::SIZE..][..BcdHeader::SIZE].copy_from_slice(&bcd_header.to_bytes());
274 buf8[SdpcmHeader::SIZE + BcdHeader::SIZE..][..packet.len()].copy_from_slice(packet);
275
276 let total_len = (total_len + 3) & !3; // round up to 4byte
277
278 trace!(" {:02x}", &buf8[..total_len.min(48)]);
279
280 self.bus.wlan_write(&buf[..(total_len / 4)]).await;
281 self.ch.tx_done();
282 }
283 }
284 }
285
286 // Receive stuff
287 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
288
289 if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
290 let mut status = 0xFFFF_FFFF;
291 while status == 0xFFFF_FFFF {
292 status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await;
293 }
294
295 if status & STATUS_F2_PKT_AVAILABLE != 0 {
296 let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
297 self.bus.wlan_read(&mut buf, len).await;
298 trace!("rx {:02x}", &slice8_mut(&mut buf)[..(len as usize).min(48)]);
299 self.rx(&slice8_mut(&mut buf)[..len as usize]);
300 }
301 }
302
303 // TODO use IRQs
304 yield_now().await;
305 }
306 }
307
308 fn rx(&mut self, packet: &[u8]) {
309 if packet.len() < SdpcmHeader::SIZE {
310 warn!("packet too short, len={}", packet.len());
311 return;
312 }
313
314 let sdpcm_header = SdpcmHeader::from_bytes(packet[..SdpcmHeader::SIZE].try_into().unwrap());
315 trace!("rx {:?}", sdpcm_header);
316 if sdpcm_header.len != !sdpcm_header.len_inv {
317 warn!("len inv mismatch");
318 return;
319 }
320 if sdpcm_header.len as usize != packet.len() {
321 // TODO: is this guaranteed??
322 warn!("len from header doesn't match len from spi");
323 return;
324 }
325
326 self.update_credit(&sdpcm_header);
327
328 let channel = sdpcm_header.channel_and_flags & 0x0f;
329
330 let payload = &packet[sdpcm_header.header_length as _..];
331
332 match channel {
333 CHANNEL_TYPE_CONTROL => {
334 if payload.len() < CdcHeader::SIZE {
335 warn!("payload too short, len={}", payload.len());
336 return;
337 }
338
339 let cdc_header = CdcHeader::from_bytes(payload[..CdcHeader::SIZE].try_into().unwrap());
340 trace!(" {:?}", cdc_header);
341
342 if let IoctlState::Sent { buf } = self.ioctl_state.get() {
343 if cdc_header.id == self.ioctl_id {
344 if cdc_header.status != 0 {
345 // TODO: propagate error instead
346 panic!("IOCTL error {=i32}", cdc_header.status as i32);
347 }
348
349 let resp_len = cdc_header.len as usize;
350 info!("IOCTL Response: {:02x}", &payload[CdcHeader::SIZE..][..resp_len]);
351
352 (unsafe { &mut *buf }[..resp_len]).copy_from_slice(&payload[CdcHeader::SIZE..][..resp_len]);
353 self.ioctl_state.set(IoctlState::Done { resp_len });
354 }
355 }
356 }
357 CHANNEL_TYPE_EVENT => {
358 let bcd_header = BcdHeader::from_bytes(&payload[..BcdHeader::SIZE].try_into().unwrap());
359 trace!(" {:?}", bcd_header);
360
361 let packet_start = BcdHeader::SIZE + 4 * bcd_header.data_offset as usize;
362
363 if packet_start + EventPacket::SIZE > payload.len() {
364 warn!("BCD event, incomplete header");
365 return;
366 }
367 let bcd_packet = &payload[packet_start..];
368 trace!(" {:02x}", &bcd_packet[..(bcd_packet.len() as usize).min(36)]);
369
370 let mut event_packet = EventPacket::from_bytes(&bcd_packet[..EventPacket::SIZE].try_into().unwrap());
371 event_packet.byteswap();
372
373 const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h
374 if event_packet.eth.ether_type != ETH_P_LINK_CTL {
375 warn!(
376 "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}",
377 event_packet.eth.ether_type, ETH_P_LINK_CTL
378 );
379 return;
380 }
381 const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18];
382 if event_packet.hdr.oui != BROADCOM_OUI {
383 warn!(
384 "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}",
385 event_packet.hdr.oui, BROADCOM_OUI
386 );
387 return;
388 }
389 const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769;
390 if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG {
391 warn!("unexpected subtype {}", event_packet.hdr.subtype);
392 return;
393 }
394
395 const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1;
396 if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT {
397 warn!("unexpected user_subtype {}", event_packet.hdr.subtype);
398 return;
399 }
400
401 if event_packet.msg.datalen as usize >= (bcd_packet.len() - EventMessage::SIZE) {
402 warn!("BCD event, incomplete data");
403 return;
404 }
405
406 let evt_type = events::Event::from(event_packet.msg.event_type as u8);
407 let evt_data = &bcd_packet[EventMessage::SIZE..][..event_packet.msg.datalen as usize];
408 debug!("=== EVENT {}: {} {:02x}", evt_type, event_packet.msg, evt_data);
409
410 if evt_type == events::Event::AUTH || evt_type == events::Event::JOIN {
411 self.events.publish_immediate(EventStatus {
412 status: event_packet.msg.status,
413 event_type: evt_type,
414 });
415 }
416 }
417 CHANNEL_TYPE_DATA => {
418 let bcd_header = BcdHeader::from_bytes(&payload[..BcdHeader::SIZE].try_into().unwrap());
419 trace!(" {:?}", bcd_header);
420
421 let packet_start = BcdHeader::SIZE + 4 * bcd_header.data_offset as usize;
422 if packet_start > payload.len() {
423 warn!("packet start out of range.");
424 return;
425 }
426 let packet = &payload[packet_start..];
427 trace!("rx pkt {:02x}", &packet[..(packet.len() as usize).min(48)]);
428
429 match self.ch.try_rx_buf() {
430 Some(buf) => {
431 buf[..packet.len()].copy_from_slice(packet);
432 self.ch.rx_done(packet.len())
433 }
434 None => warn!("failed to push rxd packet to the channel."),
435 }
436 }
437 _ => {}
438 }
439 }
440
441 fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) {
442 if sdpcm_header.channel_and_flags & 0xf < 3 {
443 let mut sdpcm_seq_max = sdpcm_header.bus_data_credit;
444 if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 {
445 sdpcm_seq_max = self.sdpcm_seq + 2;
446 }
447 self.sdpcm_seq_max = sdpcm_seq_max;
448 }
449 }
450
451 fn has_credit(&self) -> bool {
452 self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0
453 }
454
455 async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) {
456 let mut buf = [0; 512];
457 let buf8 = slice8_mut(&mut buf);
458
459 let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
460
461 let sdpcm_seq = self.sdpcm_seq;
462 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
463 self.ioctl_id = self.ioctl_id.wrapping_add(1);
464
465 let sdpcm_header = SdpcmHeader {
466 len: total_len as u16, // TODO does this len need to be rounded up to u32?
467 len_inv: !total_len as u16,
468 sequence: sdpcm_seq,
469 channel_and_flags: CHANNEL_TYPE_CONTROL,
470 next_length: 0,
471 header_length: SdpcmHeader::SIZE as _,
472 wireless_flow_control: 0,
473 bus_data_credit: 0,
474 reserved: [0, 0],
475 };
476
477 let cdc_header = CdcHeader {
478 cmd: cmd,
479 len: data.len() as _,
480 flags: kind as u16 | (iface as u16) << 12,
481 id: self.ioctl_id,
482 status: 0,
483 };
484 trace!("tx {:?}", sdpcm_header);
485 trace!(" {:?}", cdc_header);
486
487 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
488 buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes());
489 buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data);
490
491 let total_len = (total_len + 3) & !3; // round up to 4byte
492
493 trace!(" {:02x}", &buf8[..total_len.min(48)]);
494
495 self.bus.wlan_write(&buf[..total_len / 4]).await;
496 }
497
498 async fn core_disable(&mut self, core: Core) {
499 let base = core.base_addr();
500
501 // Dummy read?
502 let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
503
504 // Check it isn't already reset
505 let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
506 if r & AI_RESETCTRL_BIT_RESET != 0 {
507 return;
508 }
509
510 self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await;
511 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
512
513 block_for(Duration::from_millis(1));
514
515 self.bus
516 .bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET)
517 .await;
518 let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
519 }
520
521 async fn core_reset(&mut self, core: Core) {
522 self.core_disable(core).await;
523
524 let base = core.base_addr();
525 self.bus
526 .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN)
527 .await;
528 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
529
530 self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
531
532 Timer::after(Duration::from_millis(1)).await;
533
534 self.bus
535 .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
536 .await;
537 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
538
539 Timer::after(Duration::from_millis(1)).await;
540 }
541
542 async fn core_is_up(&mut self, core: Core) -> bool {
543 let base = core.base_addr();
544
545 let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
546 if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN {
547 debug!("core_is_up: returning false due to bad ioctrl {:02x}", io);
548 return false;
549 }
550
551 let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
552 if r & (AI_RESETCTRL_BIT_RESET) != 0 {
553 debug!("core_is_up: returning false due to bad resetctrl {:02x}", r);
554 return false;
555 }
556
557 true
558 }
559}
560
561fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
562 let len = x.len() * 4;
563 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
564}