aboutsummaryrefslogtreecommitdiff
path: root/cyw43/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-05-30 22:42:49 +0200
committerDario Nieuwenhuis <[email protected]>2023-05-30 22:42:49 +0200
commitc327c6cd6fc3c11cfaf83cf64591940d401c5f6b (patch)
tree1e9f693a74b01ae930caa145ae282c24276510e3 /cyw43/src
parent3cc0ec654a1e46fe7b8fa168942452303343cd84 (diff)
cyw43: move crate to subdir.
Diffstat (limited to 'cyw43/src')
-rw-r--r--cyw43/src/bus.rs328
-rw-r--r--cyw43/src/consts.rs318
-rw-r--r--cyw43/src/control.rs457
-rw-r--r--cyw43/src/countries.rs481
-rw-r--r--cyw43/src/events.rs400
-rw-r--r--cyw43/src/fmt.rs257
-rw-r--r--cyw43/src/ioctl.rs126
-rw-r--r--cyw43/src/lib.rs236
-rw-r--r--cyw43/src/nvram.rs54
-rw-r--r--cyw43/src/runner.rs575
-rw-r--r--cyw43/src/structs.rs496
11 files changed, 3728 insertions, 0 deletions
diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs
new file mode 100644
index 000000000..e26f11120
--- /dev/null
+++ b/cyw43/src/bus.rs
@@ -0,0 +1,328 @@
1use embassy_futures::yield_now;
2use embassy_time::{Duration, Timer};
3use embedded_hal_1::digital::OutputPin;
4use futures::FutureExt;
5
6use crate::consts::*;
7use crate::slice8_mut;
8
9/// Custom Spi Trait that _only_ supports the bus operation of the cyw43
10/// Implementors are expected to hold the CS pin low during an operation.
11pub trait SpiBusCyw43 {
12 /// Issues a write command on the bus
13 /// First 32 bits of `word` are expected to be a cmd word
14 async fn cmd_write(&mut self, write: &[u32]) -> u32;
15
16 /// Issues a read command on the bus
17 /// `write` is expected to be a 32 bit cmd word
18 /// `read` will contain the response of the device
19 /// Backplane reads have a response delay that produces one extra unspecified word at the beginning of `read`.
20 /// Callers that want to read `n` word from the backplane, have to provide a slice that is `n+1` words long.
21 async fn cmd_read(&mut self, write: u32, read: &mut [u32]) -> u32;
22
23 /// Wait for events from the Device. A typical implementation would wait for the IRQ pin to be high.
24 /// The default implementation always reports ready, resulting in active polling of the device.
25 async fn wait_for_event(&mut self) {
26 yield_now().await;
27 }
28}
29
30pub(crate) struct Bus<PWR, SPI> {
31 backplane_window: u32,
32 pwr: PWR,
33 spi: SPI,
34 status: u32,
35}
36
37impl<PWR, SPI> Bus<PWR, SPI>
38where
39 PWR: OutputPin,
40 SPI: SpiBusCyw43,
41{
42 pub(crate) fn new(pwr: PWR, spi: SPI) -> Self {
43 Self {
44 backplane_window: 0xAAAA_AAAA,
45 pwr,
46 spi,
47 status: 0,
48 }
49 }
50
51 pub async fn init(&mut self) {
52 // Reset
53 self.pwr.set_low().unwrap();
54 Timer::after(Duration::from_millis(20)).await;
55 self.pwr.set_high().unwrap();
56 Timer::after(Duration::from_millis(250)).await;
57
58 while self
59 .read32_swapped(REG_BUS_TEST_RO)
60 .inspect(|v| trace!("{:#x}", v))
61 .await
62 != FEEDBEAD
63 {}
64
65 self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await;
66 let val = self.read32_swapped(REG_BUS_TEST_RW).await;
67 trace!("{:#x}", val);
68 assert_eq!(val, TEST_PATTERN);
69
70 let val = self.read32_swapped(REG_BUS_CTRL).await;
71 trace!("{:#010b}", (val & 0xff));
72
73 // 32-bit word length, little endian (which is the default endianess).
74 self.write32_swapped(
75 REG_BUS_CTRL,
76 WORD_LENGTH_32 | HIGH_SPEED | INTERRUPT_HIGH | WAKE_UP | STATUS_ENABLE | INTERRUPT_WITH_STATUS,
77 )
78 .await;
79
80 let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await;
81 trace!("{:#b}", val);
82
83 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await;
84 trace!("{:#x}", val);
85 assert_eq!(val, FEEDBEAD);
86 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await;
87 trace!("{:#x}", val);
88 assert_eq!(val, TEST_PATTERN);
89 }
90
91 pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) {
92 let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, len_in_u8);
93 let len_in_u32 = (len_in_u8 as usize + 3) / 4;
94
95 self.status = self.spi.cmd_read(cmd, &mut buf[..len_in_u32]).await;
96 }
97
98 pub async fn wlan_write(&mut self, buf: &[u32]) {
99 let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, buf.len() as u32 * 4);
100 //TODO try to remove copy?
101 let mut cmd_buf = [0_u32; 513];
102 cmd_buf[0] = cmd;
103 cmd_buf[1..][..buf.len()].copy_from_slice(buf);
104
105 self.status = self.spi.cmd_write(&cmd_buf).await;
106 }
107
108 #[allow(unused)]
109 pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) {
110 // It seems the HW force-aligns the addr
111 // to 2 if data.len() >= 2
112 // to 4 if data.len() >= 4
113 // To simplify, enforce 4-align for now.
114 assert!(addr % 4 == 0);
115
116 // Backplane read buffer has one extra word for the response delay.
117 let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1];
118
119 while !data.is_empty() {
120 // Ensure transfer doesn't cross a window boundary.
121 let window_offs = addr & BACKPLANE_ADDRESS_MASK;
122 let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize;
123
124 let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining);
125
126 self.backplane_set_window(addr).await;
127
128 let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32);
129
130 // round `buf` to word boundary, add one extra word for the response delay
131 self.status = self.spi.cmd_read(cmd, &mut buf[..(len + 3) / 4 + 1]).await;
132
133 // when writing out the data, we skip the response-delay byte
134 data[..len].copy_from_slice(&slice8_mut(&mut buf[1..])[..len]);
135
136 // Advance ptr.
137 addr += len as u32;
138 data = &mut data[len..];
139 }
140 }
141
142 pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) {
143 // It seems the HW force-aligns the addr
144 // to 2 if data.len() >= 2
145 // to 4 if data.len() >= 4
146 // To simplify, enforce 4-align for now.
147 assert!(addr % 4 == 0);
148
149 let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1];
150
151 while !data.is_empty() {
152 // Ensure transfer doesn't cross a window boundary.
153 let window_offs = addr & BACKPLANE_ADDRESS_MASK;
154 let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize;
155
156 let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining);
157 slice8_mut(&mut buf[1..])[..len].copy_from_slice(&data[..len]);
158
159 self.backplane_set_window(addr).await;
160
161 let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32);
162 buf[0] = cmd;
163
164 self.status = self.spi.cmd_write(&buf[..(len + 3) / 4 + 1]).await;
165
166 // Advance ptr.
167 addr += len as u32;
168 data = &data[len..];
169 }
170 }
171
172 pub async fn bp_read8(&mut self, addr: u32) -> u8 {
173 self.backplane_readn(addr, 1).await as u8
174 }
175
176 pub async fn bp_write8(&mut self, addr: u32, val: u8) {
177 self.backplane_writen(addr, val as u32, 1).await
178 }
179
180 pub async fn bp_read16(&mut self, addr: u32) -> u16 {
181 self.backplane_readn(addr, 2).await as u16
182 }
183
184 #[allow(unused)]
185 pub async fn bp_write16(&mut self, addr: u32, val: u16) {
186 self.backplane_writen(addr, val as u32, 2).await
187 }
188
189 #[allow(unused)]
190 pub async fn bp_read32(&mut self, addr: u32) -> u32 {
191 self.backplane_readn(addr, 4).await
192 }
193
194 pub async fn bp_write32(&mut self, addr: u32, val: u32) {
195 self.backplane_writen(addr, val, 4).await
196 }
197
198 async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 {
199 self.backplane_set_window(addr).await;
200
201 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
202 if len == 4 {
203 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG
204 }
205 self.readn(FUNC_BACKPLANE, bus_addr, len).await
206 }
207
208 async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) {
209 self.backplane_set_window(addr).await;
210
211 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
212 if len == 4 {
213 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG
214 }
215 self.writen(FUNC_BACKPLANE, bus_addr, val, len).await
216 }
217
218 async fn backplane_set_window(&mut self, addr: u32) {
219 let new_window = addr & !BACKPLANE_ADDRESS_MASK;
220
221 if (new_window >> 24) as u8 != (self.backplane_window >> 24) as u8 {
222 self.write8(
223 FUNC_BACKPLANE,
224 REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH,
225 (new_window >> 24) as u8,
226 )
227 .await;
228 }
229 if (new_window >> 16) as u8 != (self.backplane_window >> 16) as u8 {
230 self.write8(
231 FUNC_BACKPLANE,
232 REG_BACKPLANE_BACKPLANE_ADDRESS_MID,
233 (new_window >> 16) as u8,
234 )
235 .await;
236 }
237 if (new_window >> 8) as u8 != (self.backplane_window >> 8) as u8 {
238 self.write8(
239 FUNC_BACKPLANE,
240 REG_BACKPLANE_BACKPLANE_ADDRESS_LOW,
241 (new_window >> 8) as u8,
242 )
243 .await;
244 }
245 self.backplane_window = new_window;
246 }
247
248 pub async fn read8(&mut self, func: u32, addr: u32) -> u8 {
249 self.readn(func, addr, 1).await as u8
250 }
251
252 pub async fn write8(&mut self, func: u32, addr: u32, val: u8) {
253 self.writen(func, addr, val as u32, 1).await
254 }
255
256 pub async fn read16(&mut self, func: u32, addr: u32) -> u16 {
257 self.readn(func, addr, 2).await as u16
258 }
259
260 #[allow(unused)]
261 pub async fn write16(&mut self, func: u32, addr: u32, val: u16) {
262 self.writen(func, addr, val as u32, 2).await
263 }
264
265 pub async fn read32(&mut self, func: u32, addr: u32) -> u32 {
266 self.readn(func, addr, 4).await
267 }
268
269 #[allow(unused)]
270 pub async fn write32(&mut self, func: u32, addr: u32, val: u32) {
271 self.writen(func, addr, val, 4).await
272 }
273
274 async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 {
275 let cmd = cmd_word(READ, INC_ADDR, func, addr, len);
276 let mut buf = [0; 2];
277 // if we are reading from the backplane, we need an extra word for the response delay
278 let len = if func == FUNC_BACKPLANE { 2 } else { 1 };
279
280 self.status = self.spi.cmd_read(cmd, &mut buf[..len]).await;
281
282 // if we read from the backplane, the result is in the second word, after the response delay
283 if func == FUNC_BACKPLANE {
284 buf[1]
285 } else {
286 buf[0]
287 }
288 }
289
290 async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) {
291 let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len);
292
293 self.status = self.spi.cmd_write(&[cmd, val]).await;
294 }
295
296 async fn read32_swapped(&mut self, addr: u32) -> u32 {
297 let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4);
298 let cmd = swap16(cmd);
299 let mut buf = [0; 1];
300
301 self.status = self.spi.cmd_read(cmd, &mut buf).await;
302
303 swap16(buf[0])
304 }
305
306 async fn write32_swapped(&mut self, addr: u32, val: u32) {
307 let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4);
308 let buf = [swap16(cmd), swap16(val)];
309
310 self.status = self.spi.cmd_write(&buf).await;
311 }
312
313 pub async fn wait_for_event(&mut self) {
314 self.spi.wait_for_event().await;
315 }
316
317 pub fn status(&self) -> u32 {
318 self.status
319 }
320}
321
322fn swap16(x: u32) -> u32 {
323 x.rotate_left(16)
324}
325
326fn cmd_word(write: bool, incr: bool, func: u32, addr: u32, len: u32) -> u32 {
327 (write as u32) << 31 | (incr as u32) << 30 | (func & 0b11) << 28 | (addr & 0x1FFFF) << 11 | (len & 0x7FF)
328}
diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs
new file mode 100644
index 000000000..1f6551589
--- /dev/null
+++ b/cyw43/src/consts.rs
@@ -0,0 +1,318 @@
1#![allow(unused)]
2
3pub(crate) const FUNC_BUS: u32 = 0;
4pub(crate) const FUNC_BACKPLANE: u32 = 1;
5pub(crate) const FUNC_WLAN: u32 = 2;
6pub(crate) const FUNC_BT: u32 = 3;
7
8pub(crate) const REG_BUS_CTRL: u32 = 0x0;
9pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status
10pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask
11pub(crate) const REG_BUS_STATUS: u32 = 0x8;
12pub(crate) const REG_BUS_TEST_RO: u32 = 0x14;
13pub(crate) const REG_BUS_TEST_RW: u32 = 0x18;
14pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c;
15pub(crate) const WORD_LENGTH_32: u32 = 0x1;
16pub(crate) const HIGH_SPEED: u32 = 0x10;
17pub(crate) const INTERRUPT_HIGH: u32 = 1 << 5;
18pub(crate) const WAKE_UP: u32 = 1 << 7;
19pub(crate) const STATUS_ENABLE: u32 = 1 << 16;
20pub(crate) const INTERRUPT_WITH_STATUS: u32 = 1 << 17;
21
22// SPI_STATUS_REGISTER bits
23pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001;
24pub(crate) const STATUS_UNDERFLOW: u32 = 0x00000002;
25pub(crate) const STATUS_OVERFLOW: u32 = 0x00000004;
26pub(crate) const STATUS_F2_INTR: u32 = 0x00000008;
27pub(crate) const STATUS_F3_INTR: u32 = 0x00000010;
28pub(crate) const STATUS_F2_RX_READY: u32 = 0x00000020;
29pub(crate) const STATUS_F3_RX_READY: u32 = 0x00000040;
30pub(crate) const STATUS_HOST_CMD_DATA_ERR: u32 = 0x00000080;
31pub(crate) const STATUS_F2_PKT_AVAILABLE: u32 = 0x00000100;
32pub(crate) const STATUS_F2_PKT_LEN_MASK: u32 = 0x000FFE00;
33pub(crate) const STATUS_F2_PKT_LEN_SHIFT: u32 = 9;
34pub(crate) const STATUS_F3_PKT_AVAILABLE: u32 = 0x00100000;
35pub(crate) const STATUS_F3_PKT_LEN_MASK: u32 = 0xFFE00000;
36pub(crate) const STATUS_F3_PKT_LEN_SHIFT: u32 = 21;
37
38pub(crate) const REG_BACKPLANE_GPIO_SELECT: u32 = 0x10005;
39pub(crate) const REG_BACKPLANE_GPIO_OUTPUT: u32 = 0x10006;
40pub(crate) const REG_BACKPLANE_GPIO_ENABLE: u32 = 0x10007;
41pub(crate) const REG_BACKPLANE_FUNCTION2_WATERMARK: u32 = 0x10008;
42pub(crate) const REG_BACKPLANE_DEVICE_CONTROL: u32 = 0x10009;
43pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_LOW: u32 = 0x1000A;
44pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_MID: u32 = 0x1000B;
45pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH: u32 = 0x1000C;
46pub(crate) const REG_BACKPLANE_FRAME_CONTROL: u32 = 0x1000D;
47pub(crate) const REG_BACKPLANE_CHIP_CLOCK_CSR: u32 = 0x1000E;
48pub(crate) const REG_BACKPLANE_PULL_UP: u32 = 0x1000F;
49pub(crate) const REG_BACKPLANE_READ_FRAME_BC_LOW: u32 = 0x1001B;
50pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C;
51pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E;
52pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F;
53
54pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000;
55pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF;
56pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000;
57pub(crate) const BACKPLANE_MAX_TRANSFER_SIZE: usize = 64;
58// Active Low Power (ALP) clock constants
59pub(crate) const BACKPLANE_ALP_AVAIL_REQ: u8 = 0x08;
60pub(crate) const BACKPLANE_ALP_AVAIL: u8 = 0x40;
61
62// Broadcom AMBA (Advanced Microcontroller Bus Architecture) Interconnect
63// (AI) pub (crate) constants
64pub(crate) const AI_IOCTRL_OFFSET: u32 = 0x408;
65pub(crate) const AI_IOCTRL_BIT_FGC: u8 = 0x0002;
66pub(crate) const AI_IOCTRL_BIT_CLOCK_EN: u8 = 0x0001;
67pub(crate) const AI_IOCTRL_BIT_CPUHALT: u8 = 0x0020;
68
69pub(crate) const AI_RESETCTRL_OFFSET: u32 = 0x800;
70pub(crate) const AI_RESETCTRL_BIT_RESET: u8 = 1;
71
72pub(crate) const AI_RESETSTATUS_OFFSET: u32 = 0x804;
73
74pub(crate) const TEST_PATTERN: u32 = 0x12345678;
75pub(crate) const FEEDBEAD: u32 = 0xFEEDBEAD;
76
77// SPI_INTERRUPT_REGISTER and SPI_INTERRUPT_ENABLE_REGISTER Bits
78pub(crate) const IRQ_DATA_UNAVAILABLE: u16 = 0x0001; // Requested data not available; Clear by writing a "1"
79pub(crate) const IRQ_F2_F3_FIFO_RD_UNDERFLOW: u16 = 0x0002;
80pub(crate) const IRQ_F2_F3_FIFO_WR_OVERFLOW: u16 = 0x0004;
81pub(crate) const IRQ_COMMAND_ERROR: u16 = 0x0008; // Cleared by writing 1
82pub(crate) const IRQ_DATA_ERROR: u16 = 0x0010; // Cleared by writing 1
83pub(crate) const IRQ_F2_PACKET_AVAILABLE: u16 = 0x0020;
84pub(crate) const IRQ_F3_PACKET_AVAILABLE: u16 = 0x0040;
85pub(crate) const IRQ_F1_OVERFLOW: u16 = 0x0080; // Due to last write. Bkplane has pending write requests
86pub(crate) const IRQ_MISC_INTR0: u16 = 0x0100;
87pub(crate) const IRQ_MISC_INTR1: u16 = 0x0200;
88pub(crate) const IRQ_MISC_INTR2: u16 = 0x0400;
89pub(crate) const IRQ_MISC_INTR3: u16 = 0x0800;
90pub(crate) const IRQ_MISC_INTR4: u16 = 0x1000;
91pub(crate) const IRQ_F1_INTR: u16 = 0x2000;
92pub(crate) const IRQ_F2_INTR: u16 = 0x4000;
93pub(crate) const IRQ_F3_INTR: u16 = 0x8000;
94
95pub(crate) const IOCTL_CMD_UP: u32 = 2;
96pub(crate) const IOCTL_CMD_DOWN: u32 = 3;
97pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26;
98pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30;
99pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64;
100pub(crate) const IOCTL_CMD_SET_AP: u32 = 118;
101pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263;
102pub(crate) const IOCTL_CMD_GET_VAR: u32 = 262;
103pub(crate) const IOCTL_CMD_SET_PASSPHRASE: u32 = 268;
104
105pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0;
106pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1;
107pub(crate) const CHANNEL_TYPE_DATA: u8 = 2;
108
109// CYW_SPID command structure constants.
110pub(crate) const WRITE: bool = true;
111pub(crate) const READ: bool = false;
112pub(crate) const INC_ADDR: bool = true;
113pub(crate) const FIXED_ADDR: bool = false;
114
115pub(crate) const AES_ENABLED: u32 = 0x0004;
116pub(crate) const WPA2_SECURITY: u32 = 0x00400000;
117
118pub(crate) const MIN_PSK_LEN: usize = 8;
119pub(crate) const MAX_PSK_LEN: usize = 64;
120
121// Security type (authentication and encryption types are combined using bit mask)
122#[allow(non_camel_case_types)]
123#[derive(Copy, Clone, PartialEq)]
124#[repr(u32)]
125pub(crate) enum Security {
126 OPEN = 0,
127 WPA2_AES_PSK = WPA2_SECURITY | AES_ENABLED,
128}
129
130#[allow(non_camel_case_types)]
131#[derive(Copy, Clone)]
132#[repr(u8)]
133pub enum EStatus {
134 /// operation was successful
135 SUCCESS = 0,
136 /// operation failed
137 FAIL = 1,
138 /// operation timed out
139 TIMEOUT = 2,
140 /// failed due to no matching network found
141 NO_NETWORKS = 3,
142 /// operation was aborted
143 ABORT = 4,
144 /// protocol failure: packet not ack'd
145 NO_ACK = 5,
146 /// AUTH or ASSOC packet was unsolicited
147 UNSOLICITED = 6,
148 /// attempt to assoc to an auto auth configuration
149 ATTEMPT = 7,
150 /// scan results are incomplete
151 PARTIAL = 8,
152 /// scan aborted by another scan
153 NEWSCAN = 9,
154 /// scan aborted due to assoc in progress
155 NEWASSOC = 10,
156 /// 802.11h quiet period started
157 _11HQUIET = 11,
158 /// user disabled scanning (WLC_SET_SCANSUPPRESS)
159 SUPPRESS = 12,
160 /// no allowable channels to scan
161 NOCHANS = 13,
162 /// scan aborted due to CCX fast roam
163 CCXFASTRM = 14,
164 /// abort channel select
165 CS_ABORT = 15,
166}
167
168impl PartialEq<EStatus> for u32 {
169 fn eq(&self, other: &EStatus) -> bool {
170 *self == *other as Self
171 }
172}
173
174#[allow(dead_code)]
175pub(crate) struct FormatStatus(pub u32);
176
177#[cfg(feature = "defmt")]
178impl defmt::Format for FormatStatus {
179 fn format(&self, fmt: defmt::Formatter) {
180 macro_rules! implm {
181 ($($name:ident),*) => {
182 $(
183 if self.0 & $name > 0 {
184 defmt::write!(fmt, " | {}", &stringify!($name)[7..]);
185 }
186 )*
187 };
188 }
189
190 implm!(
191 STATUS_DATA_NOT_AVAILABLE,
192 STATUS_UNDERFLOW,
193 STATUS_OVERFLOW,
194 STATUS_F2_INTR,
195 STATUS_F3_INTR,
196 STATUS_F2_RX_READY,
197 STATUS_F3_RX_READY,
198 STATUS_HOST_CMD_DATA_ERR,
199 STATUS_F2_PKT_AVAILABLE,
200 STATUS_F3_PKT_AVAILABLE
201 );
202 }
203}
204
205#[cfg(feature = "log")]
206impl core::fmt::Debug for FormatStatus {
207 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
208 macro_rules! implm {
209 ($($name:ident),*) => {
210 $(
211 if self.0 & $name > 0 {
212 core::write!(fmt, " | {}", &stringify!($name)[7..])?;
213 }
214 )*
215 };
216 }
217
218 implm!(
219 STATUS_DATA_NOT_AVAILABLE,
220 STATUS_UNDERFLOW,
221 STATUS_OVERFLOW,
222 STATUS_F2_INTR,
223 STATUS_F3_INTR,
224 STATUS_F2_RX_READY,
225 STATUS_F3_RX_READY,
226 STATUS_HOST_CMD_DATA_ERR,
227 STATUS_F2_PKT_AVAILABLE,
228 STATUS_F3_PKT_AVAILABLE
229 );
230 Ok(())
231 }
232}
233
234#[cfg(feature = "log")]
235impl core::fmt::Display for FormatStatus {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 core::fmt::Debug::fmt(self, f)
238 }
239}
240
241#[allow(dead_code)]
242pub(crate) struct FormatInterrupt(pub u16);
243
244#[cfg(feature = "defmt")]
245impl defmt::Format for FormatInterrupt {
246 fn format(&self, fmt: defmt::Formatter) {
247 macro_rules! implm {
248 ($($name:ident),*) => {
249 $(
250 if self.0 & $name > 0 {
251 defmt::write!(fmt, " | {}", &stringify!($name)[4..]);
252 }
253 )*
254 };
255 }
256
257 implm!(
258 IRQ_DATA_UNAVAILABLE,
259 IRQ_F2_F3_FIFO_RD_UNDERFLOW,
260 IRQ_F2_F3_FIFO_WR_OVERFLOW,
261 IRQ_COMMAND_ERROR,
262 IRQ_DATA_ERROR,
263 IRQ_F2_PACKET_AVAILABLE,
264 IRQ_F3_PACKET_AVAILABLE,
265 IRQ_F1_OVERFLOW,
266 IRQ_MISC_INTR0,
267 IRQ_MISC_INTR1,
268 IRQ_MISC_INTR2,
269 IRQ_MISC_INTR3,
270 IRQ_MISC_INTR4,
271 IRQ_F1_INTR,
272 IRQ_F2_INTR,
273 IRQ_F3_INTR
274 );
275 }
276}
277
278#[cfg(feature = "log")]
279impl core::fmt::Debug for FormatInterrupt {
280 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
281 macro_rules! implm {
282 ($($name:ident),*) => {
283 $(
284 if self.0 & $name > 0 {
285 core::write!(fmt, " | {}", &stringify!($name)[7..])?;
286 }
287 )*
288 };
289 }
290
291 implm!(
292 IRQ_DATA_UNAVAILABLE,
293 IRQ_F2_F3_FIFO_RD_UNDERFLOW,
294 IRQ_F2_F3_FIFO_WR_OVERFLOW,
295 IRQ_COMMAND_ERROR,
296 IRQ_DATA_ERROR,
297 IRQ_F2_PACKET_AVAILABLE,
298 IRQ_F3_PACKET_AVAILABLE,
299 IRQ_F1_OVERFLOW,
300 IRQ_MISC_INTR0,
301 IRQ_MISC_INTR1,
302 IRQ_MISC_INTR2,
303 IRQ_MISC_INTR3,
304 IRQ_MISC_INTR4,
305 IRQ_F1_INTR,
306 IRQ_F2_INTR,
307 IRQ_F3_INTR
308 );
309 Ok(())
310 }
311}
312
313#[cfg(feature = "log")]
314impl core::fmt::Display for FormatInterrupt {
315 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
316 core::fmt::Debug::fmt(self, f)
317 }
318}
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
new file mode 100644
index 000000000..6919d569e
--- /dev/null
+++ b/cyw43/src/control.rs
@@ -0,0 +1,457 @@
1use core::cmp::{max, min};
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
15#[derive(Debug)]
16pub struct Error {
17 pub status: u32,
18}
19
20pub struct Control<'a> {
21 state_ch: ch::StateRunner<'a>,
22 events: &'a Events,
23 ioctl_state: &'a IoctlState,
24}
25
26impl<'a> Control<'a> {
27 pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self {
28 Self {
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 }
257
258 // Temporarily set wifi down
259 self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await;
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
385 ioctl.0.do_ioctl(kind, cmd, iface, buf).await;
386 let resp_len = ioctl.0.wait_complete().await;
387
388 ioctl.defuse();
389
390 resp_len
391 }
392
393 /// Start a wifi scan
394 ///
395 /// Returns a `Stream` of networks found by the device
396 ///
397 /// # Note
398 /// Device events are currently implemented using a bounded queue.
399 /// To not miss any events, you should make sure to always await the stream.
400 pub async fn scan(&mut self) -> Scanner<'_> {
401 const SCANTYPE_PASSIVE: u8 = 1;
402
403 let scan_params = ScanParams {
404 version: 1,
405 action: 1,
406 sync_id: 1,
407 ssid_len: 0,
408 ssid: [0; 32],
409 bssid: [0xff; 6],
410 bss_type: 2,
411 scan_type: SCANTYPE_PASSIVE,
412 nprobes: !0,
413 active_time: !0,
414 passive_time: !0,
415 home_time: !0,
416 channel_num: 0,
417 channel_list: [0; 1],
418 };
419
420 self.events.mask.enable(&[Event::ESCAN_RESULT]);
421 let subscriber = self.events.queue.subscriber().unwrap();
422 self.set_iovar_v::<256>("escan", &scan_params.to_bytes()).await;
423
424 Scanner {
425 subscriber,
426 events: &self.events,
427 }
428 }
429}
430
431pub struct Scanner<'a> {
432 subscriber: EventSubscriber<'a>,
433 events: &'a Events,
434}
435
436impl Scanner<'_> {
437 /// wait for the next found network
438 pub async fn next(&mut self) -> Option<BssInfo> {
439 let event = self.subscriber.next_message_pure().await;
440 if event.header.status != EStatus::PARTIAL {
441 self.events.mask.disable_all();
442 return None;
443 }
444
445 if let events::Payload::BssInfo(bss) = event.payload {
446 Some(bss)
447 } else {
448 None
449 }
450 }
451}
452
453impl Drop for Scanner<'_> {
454 fn drop(&mut self) {
455 self.events.mask.disable_all();
456 }
457}
diff --git a/cyw43/src/countries.rs b/cyw43/src/countries.rs
new file mode 100644
index 000000000..fa1e8cace
--- /dev/null
+++ b/cyw43/src/countries.rs
@@ -0,0 +1,481 @@
1#![allow(unused)]
2
3pub struct Country {
4 pub code: [u8; 2],
5 pub rev: u16,
6}
7
8/// AF Afghanistan
9pub const AFGHANISTAN: Country = Country { code: *b"AF", rev: 0 };
10/// AL Albania
11pub const ALBANIA: Country = Country { code: *b"AL", rev: 0 };
12/// DZ Algeria
13pub const ALGERIA: Country = Country { code: *b"DZ", rev: 0 };
14/// AS American_Samoa
15pub const AMERICAN_SAMOA: Country = Country { code: *b"AS", rev: 0 };
16/// AO Angola
17pub const ANGOLA: Country = Country { code: *b"AO", rev: 0 };
18/// AI Anguilla
19pub const ANGUILLA: Country = Country { code: *b"AI", rev: 0 };
20/// AG Antigua_and_Barbuda
21pub const ANTIGUA_AND_BARBUDA: Country = Country { code: *b"AG", rev: 0 };
22/// AR Argentina
23pub const ARGENTINA: Country = Country { code: *b"AR", rev: 0 };
24/// AM Armenia
25pub const ARMENIA: Country = Country { code: *b"AM", rev: 0 };
26/// AW Aruba
27pub const ARUBA: Country = Country { code: *b"AW", rev: 0 };
28/// AU Australia
29pub const AUSTRALIA: Country = Country { code: *b"AU", rev: 0 };
30/// AT Austria
31pub const AUSTRIA: Country = Country { code: *b"AT", rev: 0 };
32/// AZ Azerbaijan
33pub const AZERBAIJAN: Country = Country { code: *b"AZ", rev: 0 };
34/// BS Bahamas
35pub const BAHAMAS: Country = Country { code: *b"BS", rev: 0 };
36/// BH Bahrain
37pub const BAHRAIN: Country = Country { code: *b"BH", rev: 0 };
38/// 0B Baker_Island
39pub const BAKER_ISLAND: Country = Country { code: *b"0B", rev: 0 };
40/// BD Bangladesh
41pub const BANGLADESH: Country = Country { code: *b"BD", rev: 0 };
42/// BB Barbados
43pub const BARBADOS: Country = Country { code: *b"BB", rev: 0 };
44/// BY Belarus
45pub const BELARUS: Country = Country { code: *b"BY", rev: 0 };
46/// BE Belgium
47pub const BELGIUM: Country = Country { code: *b"BE", rev: 0 };
48/// BZ Belize
49pub const BELIZE: Country = Country { code: *b"BZ", rev: 0 };
50/// BJ Benin
51pub const BENIN: Country = Country { code: *b"BJ", rev: 0 };
52/// BM Bermuda
53pub const BERMUDA: Country = Country { code: *b"BM", rev: 0 };
54/// BT Bhutan
55pub const BHUTAN: Country = Country { code: *b"BT", rev: 0 };
56/// BO Bolivia
57pub const BOLIVIA: Country = Country { code: *b"BO", rev: 0 };
58/// BA Bosnia_and_Herzegovina
59pub const BOSNIA_AND_HERZEGOVINA: Country = Country { code: *b"BA", rev: 0 };
60/// BW Botswana
61pub const BOTSWANA: Country = Country { code: *b"BW", rev: 0 };
62/// BR Brazil
63pub const BRAZIL: Country = Country { code: *b"BR", rev: 0 };
64/// IO British_Indian_Ocean_Territory
65pub const BRITISH_INDIAN_OCEAN_TERRITORY: Country = Country { code: *b"IO", rev: 0 };
66/// BN Brunei_Darussalam
67pub const BRUNEI_DARUSSALAM: Country = Country { code: *b"BN", rev: 0 };
68/// BG Bulgaria
69pub const BULGARIA: Country = Country { code: *b"BG", rev: 0 };
70/// BF Burkina_Faso
71pub const BURKINA_FASO: Country = Country { code: *b"BF", rev: 0 };
72/// BI Burundi
73pub const BURUNDI: Country = Country { code: *b"BI", rev: 0 };
74/// KH Cambodia
75pub const CAMBODIA: Country = Country { code: *b"KH", rev: 0 };
76/// CM Cameroon
77pub const CAMEROON: Country = Country { code: *b"CM", rev: 0 };
78/// CA Canada
79pub const CANADA: Country = Country { code: *b"CA", rev: 0 };
80/// CA Canada Revision 950
81pub const CANADA_REV950: Country = Country { code: *b"CA", rev: 950 };
82/// CV Cape_Verde
83pub const CAPE_VERDE: Country = Country { code: *b"CV", rev: 0 };
84/// KY Cayman_Islands
85pub const CAYMAN_ISLANDS: Country = Country { code: *b"KY", rev: 0 };
86/// CF Central_African_Republic
87pub const CENTRAL_AFRICAN_REPUBLIC: Country = Country { code: *b"CF", rev: 0 };
88/// TD Chad
89pub const CHAD: Country = Country { code: *b"TD", rev: 0 };
90/// CL Chile
91pub const CHILE: Country = Country { code: *b"CL", rev: 0 };
92/// CN China
93pub const CHINA: Country = Country { code: *b"CN", rev: 0 };
94/// CX Christmas_Island
95pub const CHRISTMAS_ISLAND: Country = Country { code: *b"CX", rev: 0 };
96/// CO Colombia
97pub const COLOMBIA: Country = Country { code: *b"CO", rev: 0 };
98/// KM Comoros
99pub const COMOROS: Country = Country { code: *b"KM", rev: 0 };
100/// CG Congo
101pub const CONGO: Country = Country { code: *b"CG", rev: 0 };
102/// CD Congo,_The_Democratic_Republic_Of_The
103pub const CONGO_THE_DEMOCRATIC_REPUBLIC_OF_THE: Country = Country { code: *b"CD", rev: 0 };
104/// CR Costa_Rica
105pub const COSTA_RICA: Country = Country { code: *b"CR", rev: 0 };
106/// CI Cote_D'ivoire
107pub const COTE_DIVOIRE: Country = Country { code: *b"CI", rev: 0 };
108/// HR Croatia
109pub const CROATIA: Country = Country { code: *b"HR", rev: 0 };
110/// CU Cuba
111pub const CUBA: Country = Country { code: *b"CU", rev: 0 };
112/// CY Cyprus
113pub const CYPRUS: Country = Country { code: *b"CY", rev: 0 };
114/// CZ Czech_Republic
115pub const CZECH_REPUBLIC: Country = Country { code: *b"CZ", rev: 0 };
116/// DK Denmark
117pub const DENMARK: Country = Country { code: *b"DK", rev: 0 };
118/// DJ Djibouti
119pub const DJIBOUTI: Country = Country { code: *b"DJ", rev: 0 };
120/// DM Dominica
121pub const DOMINICA: Country = Country { code: *b"DM", rev: 0 };
122/// DO Dominican_Republic
123pub const DOMINICAN_REPUBLIC: Country = Country { code: *b"DO", rev: 0 };
124/// AU G'Day mate!
125pub const DOWN_UNDER: Country = Country { code: *b"AU", rev: 0 };
126/// EC Ecuador
127pub const ECUADOR: Country = Country { code: *b"EC", rev: 0 };
128/// EG Egypt
129pub const EGYPT: Country = Country { code: *b"EG", rev: 0 };
130/// SV El_Salvador
131pub const EL_SALVADOR: Country = Country { code: *b"SV", rev: 0 };
132/// GQ Equatorial_Guinea
133pub const EQUATORIAL_GUINEA: Country = Country { code: *b"GQ", rev: 0 };
134/// ER Eritrea
135pub const ERITREA: Country = Country { code: *b"ER", rev: 0 };
136/// EE Estonia
137pub const ESTONIA: Country = Country { code: *b"EE", rev: 0 };
138/// ET Ethiopia
139pub const ETHIOPIA: Country = Country { code: *b"ET", rev: 0 };
140/// FK Falkland_Islands_(Malvinas)
141pub const FALKLAND_ISLANDS_MALVINAS: Country = Country { code: *b"FK", rev: 0 };
142/// FO Faroe_Islands
143pub const FAROE_ISLANDS: Country = Country { code: *b"FO", rev: 0 };
144/// FJ Fiji
145pub const FIJI: Country = Country { code: *b"FJ", rev: 0 };
146/// FI Finland
147pub const FINLAND: Country = Country { code: *b"FI", rev: 0 };
148/// FR France
149pub const FRANCE: Country = Country { code: *b"FR", rev: 0 };
150/// GF French_Guina
151pub const FRENCH_GUINA: Country = Country { code: *b"GF", rev: 0 };
152/// PF French_Polynesia
153pub const FRENCH_POLYNESIA: Country = Country { code: *b"PF", rev: 0 };
154/// TF French_Southern_Territories
155pub const FRENCH_SOUTHERN_TERRITORIES: Country = Country { code: *b"TF", rev: 0 };
156/// GA Gabon
157pub const GABON: Country = Country { code: *b"GA", rev: 0 };
158/// GM Gambia
159pub const GAMBIA: Country = Country { code: *b"GM", rev: 0 };
160/// GE Georgia
161pub const GEORGIA: Country = Country { code: *b"GE", rev: 0 };
162/// DE Germany
163pub const GERMANY: Country = Country { code: *b"DE", rev: 0 };
164/// E0 European_Wide Revision 895
165pub const EUROPEAN_WIDE_REV895: Country = Country { code: *b"E0", rev: 895 };
166/// GH Ghana
167pub const GHANA: Country = Country { code: *b"GH", rev: 0 };
168/// GI Gibraltar
169pub const GIBRALTAR: Country = Country { code: *b"GI", rev: 0 };
170/// GR Greece
171pub const GREECE: Country = Country { code: *b"GR", rev: 0 };
172/// GD Grenada
173pub const GRENADA: Country = Country { code: *b"GD", rev: 0 };
174/// GP Guadeloupe
175pub const GUADELOUPE: Country = Country { code: *b"GP", rev: 0 };
176/// GU Guam
177pub const GUAM: Country = Country { code: *b"GU", rev: 0 };
178/// GT Guatemala
179pub const GUATEMALA: Country = Country { code: *b"GT", rev: 0 };
180/// GG Guernsey
181pub const GUERNSEY: Country = Country { code: *b"GG", rev: 0 };
182/// GN Guinea
183pub const GUINEA: Country = Country { code: *b"GN", rev: 0 };
184/// GW Guinea-bissau
185pub const GUINEA_BISSAU: Country = Country { code: *b"GW", rev: 0 };
186/// GY Guyana
187pub const GUYANA: Country = Country { code: *b"GY", rev: 0 };
188/// HT Haiti
189pub const HAITI: Country = Country { code: *b"HT", rev: 0 };
190/// VA Holy_See_(Vatican_City_State)
191pub const HOLY_SEE_VATICAN_CITY_STATE: Country = Country { code: *b"VA", rev: 0 };
192/// HN Honduras
193pub const HONDURAS: Country = Country { code: *b"HN", rev: 0 };
194/// HK Hong_Kong
195pub const HONG_KONG: Country = Country { code: *b"HK", rev: 0 };
196/// HU Hungary
197pub const HUNGARY: Country = Country { code: *b"HU", rev: 0 };
198/// IS Iceland
199pub const ICELAND: Country = Country { code: *b"IS", rev: 0 };
200/// IN India
201pub const INDIA: Country = Country { code: *b"IN", rev: 0 };
202/// ID Indonesia
203pub const INDONESIA: Country = Country { code: *b"ID", rev: 0 };
204/// IR Iran,_Islamic_Republic_Of
205pub const IRAN_ISLAMIC_REPUBLIC_OF: Country = Country { code: *b"IR", rev: 0 };
206/// IQ Iraq
207pub const IRAQ: Country = Country { code: *b"IQ", rev: 0 };
208/// IE Ireland
209pub const IRELAND: Country = Country { code: *b"IE", rev: 0 };
210/// IL Israel
211pub const ISRAEL: Country = Country { code: *b"IL", rev: 0 };
212/// IT Italy
213pub const ITALY: Country = Country { code: *b"IT", rev: 0 };
214/// JM Jamaica
215pub const JAMAICA: Country = Country { code: *b"JM", rev: 0 };
216/// JP Japan
217pub const JAPAN: Country = Country { code: *b"JP", rev: 0 };
218/// JE Jersey
219pub const JERSEY: Country = Country { code: *b"JE", rev: 0 };
220/// JO Jordan
221pub const JORDAN: Country = Country { code: *b"JO", rev: 0 };
222/// KZ Kazakhstan
223pub const KAZAKHSTAN: Country = Country { code: *b"KZ", rev: 0 };
224/// KE Kenya
225pub const KENYA: Country = Country { code: *b"KE", rev: 0 };
226/// KI Kiribati
227pub const KIRIBATI: Country = Country { code: *b"KI", rev: 0 };
228/// KR Korea,_Republic_Of
229pub const KOREA_REPUBLIC_OF: Country = Country { code: *b"KR", rev: 1 };
230/// 0A Kosovo
231pub const KOSOVO: Country = Country { code: *b"0A", rev: 0 };
232/// KW Kuwait
233pub const KUWAIT: Country = Country { code: *b"KW", rev: 0 };
234/// KG Kyrgyzstan
235pub const KYRGYZSTAN: Country = Country { code: *b"KG", rev: 0 };
236/// LA Lao_People's_Democratic_Repubic
237pub const LAO_PEOPLES_DEMOCRATIC_REPUBIC: Country = Country { code: *b"LA", rev: 0 };
238/// LV Latvia
239pub const LATVIA: Country = Country { code: *b"LV", rev: 0 };
240/// LB Lebanon
241pub const LEBANON: Country = Country { code: *b"LB", rev: 0 };
242/// LS Lesotho
243pub const LESOTHO: Country = Country { code: *b"LS", rev: 0 };
244/// LR Liberia
245pub const LIBERIA: Country = Country { code: *b"LR", rev: 0 };
246/// LY Libyan_Arab_Jamahiriya
247pub const LIBYAN_ARAB_JAMAHIRIYA: Country = Country { code: *b"LY", rev: 0 };
248/// LI Liechtenstein
249pub const LIECHTENSTEIN: Country = Country { code: *b"LI", rev: 0 };
250/// LT Lithuania
251pub const LITHUANIA: Country = Country { code: *b"LT", rev: 0 };
252/// LU Luxembourg
253pub const LUXEMBOURG: Country = Country { code: *b"LU", rev: 0 };
254/// MO Macao
255pub const MACAO: Country = Country { code: *b"MO", rev: 0 };
256/// MK Macedonia,_Former_Yugoslav_Republic_Of
257pub const MACEDONIA_FORMER_YUGOSLAV_REPUBLIC_OF: Country = Country { code: *b"MK", rev: 0 };
258/// MG Madagascar
259pub const MADAGASCAR: Country = Country { code: *b"MG", rev: 0 };
260/// MW Malawi
261pub const MALAWI: Country = Country { code: *b"MW", rev: 0 };
262/// MY Malaysia
263pub const MALAYSIA: Country = Country { code: *b"MY", rev: 0 };
264/// MV Maldives
265pub const MALDIVES: Country = Country { code: *b"MV", rev: 0 };
266/// ML Mali
267pub const MALI: Country = Country { code: *b"ML", rev: 0 };
268/// MT Malta
269pub const MALTA: Country = Country { code: *b"MT", rev: 0 };
270/// IM Man,_Isle_Of
271pub const MAN_ISLE_OF: Country = Country { code: *b"IM", rev: 0 };
272/// MQ Martinique
273pub const MARTINIQUE: Country = Country { code: *b"MQ", rev: 0 };
274/// MR Mauritania
275pub const MAURITANIA: Country = Country { code: *b"MR", rev: 0 };
276/// MU Mauritius
277pub const MAURITIUS: Country = Country { code: *b"MU", rev: 0 };
278/// YT Mayotte
279pub const MAYOTTE: Country = Country { code: *b"YT", rev: 0 };
280/// MX Mexico
281pub const MEXICO: Country = Country { code: *b"MX", rev: 0 };
282/// FM Micronesia,_Federated_States_Of
283pub const MICRONESIA_FEDERATED_STATES_OF: Country = Country { code: *b"FM", rev: 0 };
284/// MD Moldova,_Republic_Of
285pub const MOLDOVA_REPUBLIC_OF: Country = Country { code: *b"MD", rev: 0 };
286/// MC Monaco
287pub const MONACO: Country = Country { code: *b"MC", rev: 0 };
288/// MN Mongolia
289pub const MONGOLIA: Country = Country { code: *b"MN", rev: 0 };
290/// ME Montenegro
291pub const MONTENEGRO: Country = Country { code: *b"ME", rev: 0 };
292/// MS Montserrat
293pub const MONTSERRAT: Country = Country { code: *b"MS", rev: 0 };
294/// MA Morocco
295pub const MOROCCO: Country = Country { code: *b"MA", rev: 0 };
296/// MZ Mozambique
297pub const MOZAMBIQUE: Country = Country { code: *b"MZ", rev: 0 };
298/// MM Myanmar
299pub const MYANMAR: Country = Country { code: *b"MM", rev: 0 };
300/// NA Namibia
301pub const NAMIBIA: Country = Country { code: *b"NA", rev: 0 };
302/// NR Nauru
303pub const NAURU: Country = Country { code: *b"NR", rev: 0 };
304/// NP Nepal
305pub const NEPAL: Country = Country { code: *b"NP", rev: 0 };
306/// NL Netherlands
307pub const NETHERLANDS: Country = Country { code: *b"NL", rev: 0 };
308/// AN Netherlands_Antilles
309pub const NETHERLANDS_ANTILLES: Country = Country { code: *b"AN", rev: 0 };
310/// NC New_Caledonia
311pub const NEW_CALEDONIA: Country = Country { code: *b"NC", rev: 0 };
312/// NZ New_Zealand
313pub const NEW_ZEALAND: Country = Country { code: *b"NZ", rev: 0 };
314/// NI Nicaragua
315pub const NICARAGUA: Country = Country { code: *b"NI", rev: 0 };
316/// NE Niger
317pub const NIGER: Country = Country { code: *b"NE", rev: 0 };
318/// NG Nigeria
319pub const NIGERIA: Country = Country { code: *b"NG", rev: 0 };
320/// NF Norfolk_Island
321pub const NORFOLK_ISLAND: Country = Country { code: *b"NF", rev: 0 };
322/// MP Northern_Mariana_Islands
323pub const NORTHERN_MARIANA_ISLANDS: Country = Country { code: *b"MP", rev: 0 };
324/// NO Norway
325pub const NORWAY: Country = Country { code: *b"NO", rev: 0 };
326/// OM Oman
327pub const OMAN: Country = Country { code: *b"OM", rev: 0 };
328/// PK Pakistan
329pub const PAKISTAN: Country = Country { code: *b"PK", rev: 0 };
330/// PW Palau
331pub const PALAU: Country = Country { code: *b"PW", rev: 0 };
332/// PA Panama
333pub const PANAMA: Country = Country { code: *b"PA", rev: 0 };
334/// PG Papua_New_Guinea
335pub const PAPUA_NEW_GUINEA: Country = Country { code: *b"PG", rev: 0 };
336/// PY Paraguay
337pub const PARAGUAY: Country = Country { code: *b"PY", rev: 0 };
338/// PE Peru
339pub const PERU: Country = Country { code: *b"PE", rev: 0 };
340/// PH Philippines
341pub const PHILIPPINES: Country = Country { code: *b"PH", rev: 0 };
342/// PL Poland
343pub const POLAND: Country = Country { code: *b"PL", rev: 0 };
344/// PT Portugal
345pub const PORTUGAL: Country = Country { code: *b"PT", rev: 0 };
346/// PR Pueto_Rico
347pub const PUETO_RICO: Country = Country { code: *b"PR", rev: 0 };
348/// QA Qatar
349pub const QATAR: Country = Country { code: *b"QA", rev: 0 };
350/// RE Reunion
351pub const REUNION: Country = Country { code: *b"RE", rev: 0 };
352/// RO Romania
353pub const ROMANIA: Country = Country { code: *b"RO", rev: 0 };
354/// RU Russian_Federation
355pub const RUSSIAN_FEDERATION: Country = Country { code: *b"RU", rev: 0 };
356/// RW Rwanda
357pub const RWANDA: Country = Country { code: *b"RW", rev: 0 };
358/// KN Saint_Kitts_and_Nevis
359pub const SAINT_KITTS_AND_NEVIS: Country = Country { code: *b"KN", rev: 0 };
360/// LC Saint_Lucia
361pub const SAINT_LUCIA: Country = Country { code: *b"LC", rev: 0 };
362/// PM Saint_Pierre_and_Miquelon
363pub const SAINT_PIERRE_AND_MIQUELON: Country = Country { code: *b"PM", rev: 0 };
364/// VC Saint_Vincent_and_The_Grenadines
365pub const SAINT_VINCENT_AND_THE_GRENADINES: Country = Country { code: *b"VC", rev: 0 };
366/// WS Samoa
367pub const SAMOA: Country = Country { code: *b"WS", rev: 0 };
368/// MF Sanit_Martin_/_Sint_Marteen
369pub const SANIT_MARTIN_SINT_MARTEEN: Country = Country { code: *b"MF", rev: 0 };
370/// ST Sao_Tome_and_Principe
371pub const SAO_TOME_AND_PRINCIPE: Country = Country { code: *b"ST", rev: 0 };
372/// SA Saudi_Arabia
373pub const SAUDI_ARABIA: Country = Country { code: *b"SA", rev: 0 };
374/// SN Senegal
375pub const SENEGAL: Country = Country { code: *b"SN", rev: 0 };
376/// RS Serbia
377pub const SERBIA: Country = Country { code: *b"RS", rev: 0 };
378/// SC Seychelles
379pub const SEYCHELLES: Country = Country { code: *b"SC", rev: 0 };
380/// SL Sierra_Leone
381pub const SIERRA_LEONE: Country = Country { code: *b"SL", rev: 0 };
382/// SG Singapore
383pub const SINGAPORE: Country = Country { code: *b"SG", rev: 0 };
384/// SK Slovakia
385pub const SLOVAKIA: Country = Country { code: *b"SK", rev: 0 };
386/// SI Slovenia
387pub const SLOVENIA: Country = Country { code: *b"SI", rev: 0 };
388/// SB Solomon_Islands
389pub const SOLOMON_ISLANDS: Country = Country { code: *b"SB", rev: 0 };
390/// SO Somalia
391pub const SOMALIA: Country = Country { code: *b"SO", rev: 0 };
392/// ZA South_Africa
393pub const SOUTH_AFRICA: Country = Country { code: *b"ZA", rev: 0 };
394/// ES Spain
395pub const SPAIN: Country = Country { code: *b"ES", rev: 0 };
396/// LK Sri_Lanka
397pub const SRI_LANKA: Country = Country { code: *b"LK", rev: 0 };
398/// SR Suriname
399pub const SURINAME: Country = Country { code: *b"SR", rev: 0 };
400/// SZ Swaziland
401pub const SWAZILAND: Country = Country { code: *b"SZ", rev: 0 };
402/// SE Sweden
403pub const SWEDEN: Country = Country { code: *b"SE", rev: 0 };
404/// CH Switzerland
405pub const SWITZERLAND: Country = Country { code: *b"CH", rev: 0 };
406/// SY Syrian_Arab_Republic
407pub const SYRIAN_ARAB_REPUBLIC: Country = Country { code: *b"SY", rev: 0 };
408/// TW Taiwan,_Province_Of_China
409pub const TAIWAN_PROVINCE_OF_CHINA: Country = Country { code: *b"TW", rev: 0 };
410/// TJ Tajikistan
411pub const TAJIKISTAN: Country = Country { code: *b"TJ", rev: 0 };
412/// TZ Tanzania,_United_Republic_Of
413pub const TANZANIA_UNITED_REPUBLIC_OF: Country = Country { code: *b"TZ", rev: 0 };
414/// TH Thailand
415pub const THAILAND: Country = Country { code: *b"TH", rev: 0 };
416/// TG Togo
417pub const TOGO: Country = Country { code: *b"TG", rev: 0 };
418/// TO Tonga
419pub const TONGA: Country = Country { code: *b"TO", rev: 0 };
420/// TT Trinidad_and_Tobago
421pub const TRINIDAD_AND_TOBAGO: Country = Country { code: *b"TT", rev: 0 };
422/// TN Tunisia
423pub const TUNISIA: Country = Country { code: *b"TN", rev: 0 };
424/// TR Turkey
425pub const TURKEY: Country = Country { code: *b"TR", rev: 0 };
426/// TM Turkmenistan
427pub const TURKMENISTAN: Country = Country { code: *b"TM", rev: 0 };
428/// TC Turks_and_Caicos_Islands
429pub const TURKS_AND_CAICOS_ISLANDS: Country = Country { code: *b"TC", rev: 0 };
430/// TV Tuvalu
431pub const TUVALU: Country = Country { code: *b"TV", rev: 0 };
432/// UG Uganda
433pub const UGANDA: Country = Country { code: *b"UG", rev: 0 };
434/// UA Ukraine
435pub const UKRAINE: Country = Country { code: *b"UA", rev: 0 };
436/// AE United_Arab_Emirates
437pub const UNITED_ARAB_EMIRATES: Country = Country { code: *b"AE", rev: 0 };
438/// GB United_Kingdom
439pub const UNITED_KINGDOM: Country = Country { code: *b"GB", rev: 0 };
440/// US United_States
441pub const UNITED_STATES: Country = Country { code: *b"US", rev: 0 };
442/// US United_States Revision 4
443pub const UNITED_STATES_REV4: Country = Country { code: *b"US", rev: 4 };
444/// Q1 United_States Revision 931
445pub const UNITED_STATES_REV931: Country = Country { code: *b"Q1", rev: 931 };
446/// Q2 United_States_(No_DFS)
447pub const UNITED_STATES_NO_DFS: Country = Country { code: *b"Q2", rev: 0 };
448/// UM United_States_Minor_Outlying_Islands
449pub const UNITED_STATES_MINOR_OUTLYING_ISLANDS: Country = Country { code: *b"UM", rev: 0 };
450/// UY Uruguay
451pub const URUGUAY: Country = Country { code: *b"UY", rev: 0 };
452/// UZ Uzbekistan
453pub const UZBEKISTAN: Country = Country { code: *b"UZ", rev: 0 };
454/// VU Vanuatu
455pub const VANUATU: Country = Country { code: *b"VU", rev: 0 };
456/// VE Venezuela
457pub const VENEZUELA: Country = Country { code: *b"VE", rev: 0 };
458/// VN Viet_Nam
459pub const VIET_NAM: Country = Country { code: *b"VN", rev: 0 };
460/// VG Virgin_Islands,_British
461pub const VIRGIN_ISLANDS_BRITISH: Country = Country { code: *b"VG", rev: 0 };
462/// VI Virgin_Islands,_U.S.
463pub const VIRGIN_ISLANDS_US: Country = Country { code: *b"VI", rev: 0 };
464/// WF Wallis_and_Futuna
465pub const WALLIS_AND_FUTUNA: Country = Country { code: *b"WF", rev: 0 };
466/// 0C West_Bank
467pub const WEST_BANK: Country = Country { code: *b"0C", rev: 0 };
468/// EH Western_Sahara
469pub const WESTERN_SAHARA: Country = Country { code: *b"EH", rev: 0 };
470/// Worldwide Locale Revision 983
471pub const WORLD_WIDE_XV_REV983: Country = Country { code: *b"XV", rev: 983 };
472/// Worldwide Locale (passive Ch12-14)
473pub const WORLD_WIDE_XX: Country = Country { code: *b"XX", rev: 0 };
474/// Worldwide Locale (passive Ch12-14) Revision 17
475pub const WORLD_WIDE_XX_REV17: Country = Country { code: *b"XX", rev: 17 };
476/// YE Yemen
477pub const YEMEN: Country = Country { code: *b"YE", rev: 0 };
478/// ZM Zambia
479pub const ZAMBIA: Country = Country { code: *b"ZM", rev: 0 };
480/// ZW Zimbabwe
481pub const ZIMBABWE: Country = Country { code: *b"ZW", rev: 0 };
diff --git a/cyw43/src/events.rs b/cyw43/src/events.rs
new file mode 100644
index 000000000..a94c49a0c
--- /dev/null
+++ b/cyw43/src/events.rs
@@ -0,0 +1,400 @@
1#![allow(dead_code)]
2#![allow(non_camel_case_types)]
3
4use core::cell::RefCell;
5
6use embassy_sync::blocking_mutex::raw::NoopRawMutex;
7use embassy_sync::pubsub::{PubSubChannel, Subscriber};
8
9use crate::structs::BssInfo;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13#[repr(u8)]
14pub enum Event {
15 #[num_enum(default)]
16 Unknown = 0xFF,
17 /// indicates status of set SSID
18 SET_SSID = 0,
19 /// differentiates join IBSS from found (START) IBSS
20 JOIN = 1,
21 /// STA founded an IBSS or AP started a BSS
22 START = 2,
23 /// 802.11 AUTH request
24 AUTH = 3,
25 /// 802.11 AUTH indication
26 AUTH_IND = 4,
27 /// 802.11 DEAUTH request
28 DEAUTH = 5,
29 /// 802.11 DEAUTH indication
30 DEAUTH_IND = 6,
31 /// 802.11 ASSOC request
32 ASSOC = 7,
33 /// 802.11 ASSOC indication
34 ASSOC_IND = 8,
35 /// 802.11 REASSOC request
36 REASSOC = 9,
37 /// 802.11 REASSOC indication
38 REASSOC_IND = 10,
39 /// 802.11 DISASSOC request
40 DISASSOC = 11,
41 /// 802.11 DISASSOC indication
42 DISASSOC_IND = 12,
43 /// 802.11h Quiet period started
44 QUIET_START = 13,
45 /// 802.11h Quiet period ended
46 QUIET_END = 14,
47 /// BEACONS received/lost indication
48 BEACON_RX = 15,
49 /// generic link indication
50 LINK = 16,
51 /// TKIP MIC error occurred
52 MIC_ERROR = 17,
53 /// NDIS style link indication
54 NDIS_LINK = 18,
55 /// roam attempt occurred: indicate status & reason
56 ROAM = 19,
57 /// change in dot11FailedCount (txfail)
58 TXFAIL = 20,
59 /// WPA2 pmkid cache indication
60 PMKID_CACHE = 21,
61 /// current AP's TSF value went backward
62 RETROGRADE_TSF = 22,
63 /// AP was pruned from join list for reason
64 PRUNE = 23,
65 /// report AutoAuth table entry match for join attempt
66 AUTOAUTH = 24,
67 /// Event encapsulating an EAPOL message
68 EAPOL_MSG = 25,
69 /// Scan results are ready or scan was aborted
70 SCAN_COMPLETE = 26,
71 /// indicate to host addts fail/success
72 ADDTS_IND = 27,
73 /// indicate to host delts fail/success
74 DELTS_IND = 28,
75 /// indicate to host of beacon transmit
76 BCNSENT_IND = 29,
77 /// Send the received beacon up to the host
78 BCNRX_MSG = 30,
79 /// indicate to host loss of beacon
80 BCNLOST_MSG = 31,
81 /// before attempting to roam
82 ROAM_PREP = 32,
83 /// PFN network found event
84 PFN_NET_FOUND = 33,
85 /// PFN network lost event
86 PFN_NET_LOST = 34,
87 RESET_COMPLETE = 35,
88 JOIN_START = 36,
89 ROAM_START = 37,
90 ASSOC_START = 38,
91 IBSS_ASSOC = 39,
92 RADIO = 40,
93 /// PSM microcode watchdog fired
94 PSM_WATCHDOG = 41,
95 /// CCX association start
96 CCX_ASSOC_START = 42,
97 /// CCX association abort
98 CCX_ASSOC_ABORT = 43,
99 /// probe request received
100 PROBREQ_MSG = 44,
101 SCAN_CONFIRM_IND = 45,
102 /// WPA Handshake
103 PSK_SUP = 46,
104 COUNTRY_CODE_CHANGED = 47,
105 /// WMMAC excedded medium time
106 EXCEEDED_MEDIUM_TIME = 48,
107 /// WEP ICV error occurred
108 ICV_ERROR = 49,
109 /// Unsupported unicast encrypted frame
110 UNICAST_DECODE_ERROR = 50,
111 /// Unsupported multicast encrypted frame
112 MULTICAST_DECODE_ERROR = 51,
113 TRACE = 52,
114 /// BT-AMP HCI event
115 BTA_HCI_EVENT = 53,
116 /// I/F change (for wlan host notification)
117 IF = 54,
118 /// P2P Discovery listen state expires
119 P2P_DISC_LISTEN_COMPLETE = 55,
120 /// indicate RSSI change based on configured levels
121 RSSI = 56,
122 /// PFN best network batching event
123 PFN_BEST_BATCHING = 57,
124 EXTLOG_MSG = 58,
125 /// Action frame reception
126 ACTION_FRAME = 59,
127 /// Action frame Tx complete
128 ACTION_FRAME_COMPLETE = 60,
129 /// assoc request received
130 PRE_ASSOC_IND = 61,
131 /// re-assoc request received
132 PRE_REASSOC_IND = 62,
133 /// channel adopted (xxx: obsoleted)
134 CHANNEL_ADOPTED = 63,
135 /// AP started
136 AP_STARTED = 64,
137 /// AP stopped due to DFS
138 DFS_AP_STOP = 65,
139 /// AP resumed due to DFS
140 DFS_AP_RESUME = 66,
141 /// WAI stations event
142 WAI_STA_EVENT = 67,
143 /// event encapsulating an WAI message
144 WAI_MSG = 68,
145 /// escan result event
146 ESCAN_RESULT = 69,
147 /// action frame off channel complete
148 ACTION_FRAME_OFF_CHAN_COMPLETE = 70,
149 /// probe response received
150 PROBRESP_MSG = 71,
151 /// P2P Probe request received
152 P2P_PROBREQ_MSG = 72,
153 DCS_REQUEST = 73,
154 /// credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM]
155 FIFO_CREDIT_MAP = 74,
156 /// Received action frame event WITH wl_event_rx_frame_data_t header
157 ACTION_FRAME_RX = 75,
158 /// Wake Event timer fired, used for wake WLAN test mode
159 WAKE_EVENT = 76,
160 /// Radio measurement complete
161 RM_COMPLETE = 77,
162 /// Synchronize TSF with the host
163 HTSFSYNC = 78,
164 /// request an overlay IOCTL/iovar from the host
165 OVERLAY_REQ = 79,
166 CSA_COMPLETE_IND = 80,
167 /// excess PM Wake Event to inform host
168 EXCESS_PM_WAKE_EVENT = 81,
169 /// no PFN networks around
170 PFN_SCAN_NONE = 82,
171 /// last found PFN network gets lost
172 PFN_SCAN_ALLGONE = 83,
173 GTK_PLUMBED = 84,
174 /// 802.11 ASSOC indication for NDIS only
175 ASSOC_IND_NDIS = 85,
176 /// 802.11 REASSOC indication for NDIS only
177 REASSOC_IND_NDIS = 86,
178 ASSOC_REQ_IE = 87,
179 ASSOC_RESP_IE = 88,
180 /// association recreated on resume
181 ASSOC_RECREATED = 89,
182 /// rx action frame event for NDIS only
183 ACTION_FRAME_RX_NDIS = 90,
184 /// authentication request received
185 AUTH_REQ = 91,
186 /// fast assoc recreation failed
187 SPEEDY_RECREATE_FAIL = 93,
188 /// port-specific event and payload (e.g. NDIS)
189 NATIVE = 94,
190 /// event for tx pkt delay suddently jump
191 PKTDELAY_IND = 95,
192 /// AWDL AW period starts
193 AWDL_AW = 96,
194 /// AWDL Master/Slave/NE master role event
195 AWDL_ROLE = 97,
196 /// Generic AWDL event
197 AWDL_EVENT = 98,
198 /// NIC AF txstatus
199 NIC_AF_TXS = 99,
200 /// NAN event
201 NAN = 100,
202 BEACON_FRAME_RX = 101,
203 /// desired service found
204 SERVICE_FOUND = 102,
205 /// GAS fragment received
206 GAS_FRAGMENT_RX = 103,
207 /// GAS sessions all complete
208 GAS_COMPLETE = 104,
209 /// New device found by p2p offload
210 P2PO_ADD_DEVICE = 105,
211 /// device has been removed by p2p offload
212 P2PO_DEL_DEVICE = 106,
213 /// WNM event to notify STA enter sleep mode
214 WNM_STA_SLEEP = 107,
215 /// Indication of MAC tx failures (exhaustion of 802.11 retries) exceeding threshold(s)
216 TXFAIL_THRESH = 108,
217 /// Proximity Detection event
218 PROXD = 109,
219 /// AWDL RX Probe response
220 AWDL_RX_PRB_RESP = 111,
221 /// AWDL RX Action Frames
222 AWDL_RX_ACT_FRAME = 112,
223 /// AWDL Wowl nulls
224 AWDL_WOWL_NULLPKT = 113,
225 /// AWDL Phycal status
226 AWDL_PHYCAL_STATUS = 114,
227 /// AWDL OOB AF status
228 AWDL_OOB_AF_STATUS = 115,
229 /// Interleaved Scan status
230 AWDL_SCAN_STATUS = 116,
231 /// AWDL AW Start
232 AWDL_AW_START = 117,
233 /// AWDL AW End
234 AWDL_AW_END = 118,
235 /// AWDL AW Extensions
236 AWDL_AW_EXT = 119,
237 AWDL_PEER_CACHE_CONTROL = 120,
238 CSA_START_IND = 121,
239 CSA_DONE_IND = 122,
240 CSA_FAILURE_IND = 123,
241 /// CCA based channel quality report
242 CCA_CHAN_QUAL = 124,
243 /// to report change in BSSID while roaming
244 BSSID = 125,
245 /// tx error indication
246 TX_STAT_ERROR = 126,
247 /// credit check for BCMC supported
248 BCMC_CREDIT_SUPPORT = 127,
249 /// psta primary interface indication
250 PSTA_PRIMARY_INTF_IND = 128,
251 /// Handover Request Initiated
252 BT_WIFI_HANDOVER_REQ = 130,
253 /// Southpaw TxInhibit notification
254 SPW_TXINHIBIT = 131,
255 /// FBT Authentication Request Indication
256 FBT_AUTH_REQ_IND = 132,
257 /// Enhancement addition for RSSI
258 RSSI_LQM = 133,
259 /// Full probe/beacon (IEs etc) results
260 PFN_GSCAN_FULL_RESULT = 134,
261 /// Significant change in rssi of bssids being tracked
262 PFN_SWC = 135,
263 /// a STA been authroized for traffic
264 AUTHORIZED = 136,
265 /// probe req with wl_event_rx_frame_data_t header
266 PROBREQ_MSG_RX = 137,
267 /// PFN completed scan of network list
268 PFN_SCAN_COMPLETE = 138,
269 /// RMC Event
270 RMC_EVENT = 139,
271 /// DPSTA interface indication
272 DPSTA_INTF_IND = 140,
273 /// RRM Event
274 RRM = 141,
275 /// ULP entry event
276 ULP = 146,
277 /// TCP Keep Alive Offload Event
278 TKO = 151,
279 /// authentication request received
280 EXT_AUTH_REQ = 187,
281 /// authentication request received
282 EXT_AUTH_FRAME_RX = 188,
283 /// mgmt frame Tx complete
284 MGMT_FRAME_TXSTATUS = 189,
285 /// highest val + 1 for range checking
286 LAST = 190,
287}
288
289// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient.
290pub type EventQueue = PubSubChannel<NoopRawMutex, Message, 2, 1, 1>;
291pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>;
292
293pub struct Events {
294 pub queue: EventQueue,
295 pub mask: SharedEventMask,
296}
297
298impl Events {
299 pub fn new() -> Self {
300 Self {
301 queue: EventQueue::new(),
302 mask: SharedEventMask::default(),
303 }
304 }
305}
306
307#[derive(Clone, Copy)]
308#[cfg_attr(feature = "defmt", derive(defmt::Format))]
309pub struct Status {
310 pub event_type: Event,
311 pub status: u32,
312}
313
314#[derive(Clone, Copy)]
315pub enum Payload {
316 None,
317 BssInfo(BssInfo),
318}
319
320#[derive(Clone, Copy)]
321
322pub struct Message {
323 pub header: Status,
324 pub payload: Payload,
325}
326
327impl Message {
328 pub fn new(status: Status, payload: Payload) -> Self {
329 Self {
330 header: status,
331 payload,
332 }
333 }
334}
335
336#[derive(Default)]
337struct EventMask {
338 mask: [u32; Self::WORD_COUNT],
339}
340
341impl EventMask {
342 const WORD_COUNT: usize = ((Event::LAST as u32 + (u32::BITS - 1)) / u32::BITS) as usize;
343
344 fn enable(&mut self, event: Event) {
345 let n = event as u32;
346 let word = n / u32::BITS;
347 let bit = n % u32::BITS;
348
349 self.mask[word as usize] |= 1 << bit;
350 }
351
352 fn disable(&mut self, event: Event) {
353 let n = event as u32;
354 let word = n / u32::BITS;
355 let bit = n % u32::BITS;
356
357 self.mask[word as usize] &= !(1 << bit);
358 }
359
360 fn is_enabled(&self, event: Event) -> bool {
361 let n = event as u32;
362 let word = n / u32::BITS;
363 let bit = n % u32::BITS;
364
365 self.mask[word as usize] & (1 << bit) > 0
366 }
367}
368
369#[derive(Default)]
370
371pub struct SharedEventMask {
372 mask: RefCell<EventMask>,
373}
374
375impl SharedEventMask {
376 pub fn enable(&self, events: &[Event]) {
377 let mut mask = self.mask.borrow_mut();
378 for event in events {
379 mask.enable(*event);
380 }
381 }
382
383 #[allow(dead_code)]
384 pub fn disable(&self, events: &[Event]) {
385 let mut mask = self.mask.borrow_mut();
386 for event in events {
387 mask.disable(*event);
388 }
389 }
390
391 pub fn disable_all(&self) {
392 let mut mask = self.mask.borrow_mut();
393 mask.mask = Default::default();
394 }
395
396 pub fn is_enabled(&self, event: Event) -> bool {
397 let mask = self.mask.borrow();
398 mask.is_enabled(event)
399 }
400}
diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs
new file mode 100644
index 000000000..5730447b3
--- /dev/null
+++ b/cyw43/src/fmt.rs
@@ -0,0 +1,257 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4use core::fmt::{Debug, Display, LowerHex};
5
6#[cfg(all(feature = "defmt", feature = "log"))]
7compile_error!("You may not enable both `defmt` and `log` features.");
8
9macro_rules! assert {
10 ($($x:tt)*) => {
11 {
12 #[cfg(not(feature = "defmt"))]
13 ::core::assert!($($x)*);
14 #[cfg(feature = "defmt")]
15 ::defmt::assert!($($x)*);
16 }
17 };
18}
19
20macro_rules! assert_eq {
21 ($($x:tt)*) => {
22 {
23 #[cfg(not(feature = "defmt"))]
24 ::core::assert_eq!($($x)*);
25 #[cfg(feature = "defmt")]
26 ::defmt::assert_eq!($($x)*);
27 }
28 };
29}
30
31macro_rules! assert_ne {
32 ($($x:tt)*) => {
33 {
34 #[cfg(not(feature = "defmt"))]
35 ::core::assert_ne!($($x)*);
36 #[cfg(feature = "defmt")]
37 ::defmt::assert_ne!($($x)*);
38 }
39 };
40}
41
42macro_rules! debug_assert {
43 ($($x:tt)*) => {
44 {
45 #[cfg(not(feature = "defmt"))]
46 ::core::debug_assert!($($x)*);
47 #[cfg(feature = "defmt")]
48 ::defmt::debug_assert!($($x)*);
49 }
50 };
51}
52
53macro_rules! debug_assert_eq {
54 ($($x:tt)*) => {
55 {
56 #[cfg(not(feature = "defmt"))]
57 ::core::debug_assert_eq!($($x)*);
58 #[cfg(feature = "defmt")]
59 ::defmt::debug_assert_eq!($($x)*);
60 }
61 };
62}
63
64macro_rules! debug_assert_ne {
65 ($($x:tt)*) => {
66 {
67 #[cfg(not(feature = "defmt"))]
68 ::core::debug_assert_ne!($($x)*);
69 #[cfg(feature = "defmt")]
70 ::defmt::debug_assert_ne!($($x)*);
71 }
72 };
73}
74
75macro_rules! todo {
76 ($($x:tt)*) => {
77 {
78 #[cfg(not(feature = "defmt"))]
79 ::core::todo!($($x)*);
80 #[cfg(feature = "defmt")]
81 ::defmt::todo!($($x)*);
82 }
83 };
84}
85
86macro_rules! unreachable {
87 ($($x:tt)*) => {
88 {
89 #[cfg(not(feature = "defmt"))]
90 ::core::unreachable!($($x)*);
91 #[cfg(feature = "defmt")]
92 ::defmt::unreachable!($($x)*);
93 }
94 };
95}
96
97macro_rules! panic {
98 ($($x:tt)*) => {
99 {
100 #[cfg(not(feature = "defmt"))]
101 ::core::panic!($($x)*);
102 #[cfg(feature = "defmt")]
103 ::defmt::panic!($($x)*);
104 }
105 };
106}
107
108macro_rules! trace {
109 ($s:literal $(, $x:expr)* $(,)?) => {
110 {
111 #[cfg(feature = "log")]
112 ::log::trace!($s $(, $x)*);
113 #[cfg(feature = "defmt")]
114 ::defmt::trace!($s $(, $x)*);
115 #[cfg(not(any(feature = "log", feature="defmt")))]
116 let _ = ($( & $x ),*);
117 }
118 };
119}
120
121macro_rules! debug {
122 ($s:literal $(, $x:expr)* $(,)?) => {
123 {
124 #[cfg(feature = "log")]
125 ::log::debug!($s $(, $x)*);
126 #[cfg(feature = "defmt")]
127 ::defmt::debug!($s $(, $x)*);
128 #[cfg(not(any(feature = "log", feature="defmt")))]
129 let _ = ($( & $x ),*);
130 }
131 };
132}
133
134macro_rules! info {
135 ($s:literal $(, $x:expr)* $(,)?) => {
136 {
137 #[cfg(feature = "log")]
138 ::log::info!($s $(, $x)*);
139 #[cfg(feature = "defmt")]
140 ::defmt::info!($s $(, $x)*);
141 #[cfg(not(any(feature = "log", feature="defmt")))]
142 let _ = ($( & $x ),*);
143 }
144 };
145}
146
147macro_rules! warn {
148 ($s:literal $(, $x:expr)* $(,)?) => {
149 {
150 #[cfg(feature = "log")]
151 ::log::warn!($s $(, $x)*);
152 #[cfg(feature = "defmt")]
153 ::defmt::warn!($s $(, $x)*);
154 #[cfg(not(any(feature = "log", feature="defmt")))]
155 let _ = ($( & $x ),*);
156 }
157 };
158}
159
160macro_rules! error {
161 ($s:literal $(, $x:expr)* $(,)?) => {
162 {
163 #[cfg(feature = "log")]
164 ::log::error!($s $(, $x)*);
165 #[cfg(feature = "defmt")]
166 ::defmt::error!($s $(, $x)*);
167 #[cfg(not(any(feature = "log", feature="defmt")))]
168 let _ = ($( & $x ),*);
169 }
170 };
171}
172
173#[cfg(feature = "defmt")]
174macro_rules! unwrap {
175 ($($x:tt)*) => {
176 ::defmt::unwrap!($($x)*)
177 };
178}
179
180#[cfg(not(feature = "defmt"))]
181macro_rules! unwrap {
182 ($arg:expr) => {
183 match $crate::fmt::Try::into_result($arg) {
184 ::core::result::Result::Ok(t) => t,
185 ::core::result::Result::Err(e) => {
186 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
187 }
188 }
189 };
190 ($arg:expr, $($msg:expr),+ $(,)? ) => {
191 match $crate::fmt::Try::into_result($arg) {
192 ::core::result::Result::Ok(t) => t,
193 ::core::result::Result::Err(e) => {
194 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
195 }
196 }
197 }
198}
199
200#[cfg(feature = "defmt-timestamp-uptime")]
201defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
202
203#[derive(Debug, Copy, Clone, Eq, PartialEq)]
204pub struct NoneError;
205
206pub trait Try {
207 type Ok;
208 type Error;
209 fn into_result(self) -> Result<Self::Ok, Self::Error>;
210}
211
212impl<T> Try for Option<T> {
213 type Ok = T;
214 type Error = NoneError;
215
216 #[inline]
217 fn into_result(self) -> Result<T, NoneError> {
218 self.ok_or(NoneError)
219 }
220}
221
222impl<T, E> Try for Result<T, E> {
223 type Ok = T;
224 type Error = E;
225
226 #[inline]
227 fn into_result(self) -> Self {
228 self
229 }
230}
231
232pub struct Bytes<'a>(pub &'a [u8]);
233
234impl<'a> Debug for Bytes<'a> {
235 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
236 write!(f, "{:#02x?}", self.0)
237 }
238}
239
240impl<'a> Display for Bytes<'a> {
241 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
242 write!(f, "{:#02x?}", self.0)
243 }
244}
245
246impl<'a> LowerHex for Bytes<'a> {
247 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
248 write!(f, "{:#02x?}", self.0)
249 }
250}
251
252#[cfg(feature = "defmt")]
253impl<'a> defmt::Format for Bytes<'a> {
254 fn format(&self, fmt: defmt::Formatter) {
255 defmt::write!(fmt, "{:02x}", self.0)
256 }
257}
diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs
new file mode 100644
index 000000000..61524c274
--- /dev/null
+++ b/cyw43/src/ioctl.rs
@@ -0,0 +1,126 @@
1use core::cell::{Cell, RefCell};
2use core::future::poll_fn;
3use core::task::{Poll, Waker};
4
5use embassy_sync::waitqueue::WakerRegistration;
6
7use crate::fmt::Bytes;
8
9#[derive(Clone, Copy)]
10pub enum IoctlType {
11 Get = 0,
12 Set = 2,
13}
14
15#[derive(Clone, Copy)]
16pub struct PendingIoctl {
17 pub buf: *mut [u8],
18 pub kind: IoctlType,
19 pub cmd: u32,
20 pub iface: u32,
21}
22
23#[derive(Clone, Copy)]
24enum IoctlStateInner {
25 Pending(PendingIoctl),
26 Sent { buf: *mut [u8] },
27 Done { resp_len: usize },
28}
29
30struct Wakers {
31 control: WakerRegistration,
32 runner: WakerRegistration,
33}
34
35impl Default for Wakers {
36 fn default() -> Self {
37 Self {
38 control: WakerRegistration::new(),
39 runner: WakerRegistration::new(),
40 }
41 }
42}
43
44pub struct IoctlState {
45 state: Cell<IoctlStateInner>,
46 wakers: RefCell<Wakers>,
47}
48
49impl IoctlState {
50 pub fn new() -> Self {
51 Self {
52 state: Cell::new(IoctlStateInner::Done { resp_len: 0 }),
53 wakers: Default::default(),
54 }
55 }
56
57 fn wake_control(&self) {
58 self.wakers.borrow_mut().control.wake();
59 }
60
61 fn register_control(&self, waker: &Waker) {
62 self.wakers.borrow_mut().control.register(waker);
63 }
64
65 fn wake_runner(&self) {
66 self.wakers.borrow_mut().runner.wake();
67 }
68
69 fn register_runner(&self, waker: &Waker) {
70 self.wakers.borrow_mut().runner.register(waker);
71 }
72
73 pub async fn wait_complete(&self) -> usize {
74 poll_fn(|cx| {
75 if let IoctlStateInner::Done { resp_len } = self.state.get() {
76 Poll::Ready(resp_len)
77 } else {
78 self.register_control(cx.waker());
79 Poll::Pending
80 }
81 })
82 .await
83 }
84
85 pub async fn wait_pending(&self) -> PendingIoctl {
86 let pending = poll_fn(|cx| {
87 if let IoctlStateInner::Pending(pending) = self.state.get() {
88 Poll::Ready(pending)
89 } else {
90 self.register_runner(cx.waker());
91 Poll::Pending
92 }
93 })
94 .await;
95
96 self.state.set(IoctlStateInner::Sent { buf: pending.buf });
97 pending
98 }
99
100 pub fn cancel_ioctl(&self) {
101 self.state.set(IoctlStateInner::Done { resp_len: 0 });
102 }
103
104 pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
105 self.state
106 .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface }));
107 self.wake_runner();
108 self.wait_complete().await
109 }
110
111 pub fn ioctl_done(&self, response: &[u8]) {
112 if let IoctlStateInner::Sent { buf } = self.state.get() {
113 trace!("IOCTL Response: {:02x}", Bytes(response));
114
115 // TODO fix this
116 (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
117
118 self.state.set(IoctlStateInner::Done {
119 resp_len: response.len(),
120 });
121 self.wake_control();
122 } else {
123 warn!("IOCTL Response but no pending Ioctl");
124 }
125 }
126}
diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs
new file mode 100644
index 000000000..fd11f3674
--- /dev/null
+++ b/cyw43/src/lib.rs
@@ -0,0 +1,236 @@
1#![no_std]
2#![no_main]
3#![allow(incomplete_features)]
4#![feature(async_fn_in_trait, type_alias_impl_trait, concat_bytes)]
5#![deny(unused_must_use)]
6
7// This mod MUST go first, so that the others see its macros.
8pub(crate) mod fmt;
9
10mod bus;
11mod consts;
12mod countries;
13mod events;
14mod ioctl;
15mod structs;
16
17mod control;
18mod nvram;
19mod runner;
20
21use core::slice;
22
23use embassy_net_driver_channel as ch;
24use embedded_hal_1::digital::OutputPin;
25use events::Events;
26use ioctl::IoctlState;
27
28use crate::bus::Bus;
29pub use crate::bus::SpiBusCyw43;
30pub use crate::control::{Control, Error as ControlError};
31pub use crate::runner::Runner;
32pub use crate::structs::BssInfo;
33
34const MTU: usize = 1514;
35
36#[allow(unused)]
37#[derive(Clone, Copy, PartialEq, Eq)]
38enum Core {
39 WLAN = 0,
40 SOCSRAM = 1,
41 SDIOD = 2,
42}
43
44impl Core {
45 fn base_addr(&self) -> u32 {
46 match self {
47 Self::WLAN => CHIP.arm_core_base_address,
48 Self::SOCSRAM => CHIP.socsram_wrapper_base_address,
49 Self::SDIOD => CHIP.sdiod_core_base_address,
50 }
51 }
52}
53
54#[allow(unused)]
55struct Chip {
56 arm_core_base_address: u32,
57 socsram_base_address: u32,
58 socsram_wrapper_base_address: u32,
59 sdiod_core_base_address: u32,
60 pmu_base_address: u32,
61 chip_ram_size: u32,
62 atcm_ram_base_address: u32,
63 socram_srmem_size: u32,
64 chanspec_band_mask: u32,
65 chanspec_band_2g: u32,
66 chanspec_band_5g: u32,
67 chanspec_band_shift: u32,
68 chanspec_bw_10: u32,
69 chanspec_bw_20: u32,
70 chanspec_bw_40: u32,
71 chanspec_bw_mask: u32,
72 chanspec_bw_shift: u32,
73 chanspec_ctl_sb_lower: u32,
74 chanspec_ctl_sb_upper: u32,
75 chanspec_ctl_sb_none: u32,
76 chanspec_ctl_sb_mask: u32,
77}
78
79const WRAPPER_REGISTER_OFFSET: u32 = 0x100000;
80
81// Data for CYW43439
82const CHIP: Chip = Chip {
83 arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET,
84 socsram_base_address: 0x18004000,
85 socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET,
86 sdiod_core_base_address: 0x18002000,
87 pmu_base_address: 0x18000000,
88 chip_ram_size: 512 * 1024,
89 atcm_ram_base_address: 0,
90 socram_srmem_size: 64 * 1024,
91 chanspec_band_mask: 0xc000,
92 chanspec_band_2g: 0x0000,
93 chanspec_band_5g: 0xc000,
94 chanspec_band_shift: 14,
95 chanspec_bw_10: 0x0800,
96 chanspec_bw_20: 0x1000,
97 chanspec_bw_40: 0x1800,
98 chanspec_bw_mask: 0x3800,
99 chanspec_bw_shift: 11,
100 chanspec_ctl_sb_lower: 0x0000,
101 chanspec_ctl_sb_upper: 0x0100,
102 chanspec_ctl_sb_none: 0x0000,
103 chanspec_ctl_sb_mask: 0x0700,
104};
105
106pub struct State {
107 ioctl_state: IoctlState,
108 ch: ch::State<MTU, 4, 4>,
109 events: Events,
110}
111
112impl State {
113 pub fn new() -> Self {
114 Self {
115 ioctl_state: IoctlState::new(),
116 ch: ch::State::new(),
117 events: Events::new(),
118 }
119 }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub enum PowerManagementMode {
124 /// Custom, officially unsupported mode. Use at your own risk.
125 /// All power-saving features set to their max at only a marginal decrease in power consumption
126 /// as oppposed to `Aggressive`.
127 SuperSave,
128
129 /// Aggressive power saving mode.
130 Aggressive,
131
132 /// The default mode.
133 PowerSave,
134
135 /// Performance is prefered over power consumption but still some power is conserved as opposed to
136 /// `None`.
137 Performance,
138
139 /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of
140 /// a much lower throughput.
141 ThroughputThrottling,
142
143 /// No power management is configured. This consumes the most power.
144 None,
145}
146
147impl Default for PowerManagementMode {
148 fn default() -> Self {
149 Self::PowerSave
150 }
151}
152
153impl PowerManagementMode {
154 fn sleep_ret_ms(&self) -> u16 {
155 match self {
156 PowerManagementMode::SuperSave => 2000,
157 PowerManagementMode::Aggressive => 2000,
158 PowerManagementMode::PowerSave => 200,
159 PowerManagementMode::Performance => 20,
160 PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter
161 PowerManagementMode::None => 0, // value doesn't matter
162 }
163 }
164
165 fn beacon_period(&self) -> u8 {
166 match self {
167 PowerManagementMode::SuperSave => 255,
168 PowerManagementMode::Aggressive => 1,
169 PowerManagementMode::PowerSave => 1,
170 PowerManagementMode::Performance => 1,
171 PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter
172 PowerManagementMode::None => 0, // value doesn't matter
173 }
174 }
175
176 fn dtim_period(&self) -> u8 {
177 match self {
178 PowerManagementMode::SuperSave => 255,
179 PowerManagementMode::Aggressive => 1,
180 PowerManagementMode::PowerSave => 1,
181 PowerManagementMode::Performance => 1,
182 PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter
183 PowerManagementMode::None => 0, // value doesn't matter
184 }
185 }
186
187 fn assoc(&self) -> u8 {
188 match self {
189 PowerManagementMode::SuperSave => 255,
190 PowerManagementMode::Aggressive => 10,
191 PowerManagementMode::PowerSave => 10,
192 PowerManagementMode::Performance => 1,
193 PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter
194 PowerManagementMode::None => 0, // value doesn't matter
195 }
196 }
197
198 fn mode(&self) -> u32 {
199 match self {
200 PowerManagementMode::ThroughputThrottling => 1,
201 PowerManagementMode::None => 0,
202 _ => 2,
203 }
204 }
205}
206
207pub type NetDriver<'a> = ch::Device<'a, MTU>;
208
209pub async fn new<'a, PWR, SPI>(
210 state: &'a mut State,
211 pwr: PWR,
212 spi: SPI,
213 firmware: &[u8],
214) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>)
215where
216 PWR: OutputPin,
217 SPI: SpiBusCyw43,
218{
219 let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
220 let state_ch = ch_runner.state_runner();
221
222 let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events);
223
224 runner.init(firmware).await;
225
226 (
227 device,
228 Control::new(state_ch, &state.events, &state.ioctl_state),
229 runner,
230 )
231}
232
233fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
234 let len = x.len() * 4;
235 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
236}
diff --git a/cyw43/src/nvram.rs b/cyw43/src/nvram.rs
new file mode 100644
index 000000000..964a3128d
--- /dev/null
+++ b/cyw43/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/cyw43/src/runner.rs b/cyw43/src/runner.rs
new file mode 100644
index 000000000..5706696b4
--- /dev/null
+++ b/cyw43/src/runner.rs
@@ -0,0 +1,575 @@
1use embassy_futures::select::{select3, Either3};
2use embassy_net_driver_channel as ch;
3use embassy_sync::pubsub::PubSubBehavior;
4use embassy_time::{block_for, Duration, Timer};
5use embedded_hal_1::digital::OutputPin;
6
7use crate::bus::Bus;
8pub use crate::bus::SpiBusCyw43;
9use crate::consts::*;
10use crate::events::{Event, Events, Status};
11use crate::fmt::Bytes;
12use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
13use crate::nvram::NVRAM;
14use crate::structs::*;
15use crate::{events, slice8_mut, Core, CHIP, MTU};
16
17#[cfg(feature = "firmware-logs")]
18struct LogState {
19 addr: u32,
20 last_idx: usize,
21 buf: [u8; 256],
22 buf_count: usize,
23}
24
25#[cfg(feature = "firmware-logs")]
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 IoctlState,
42 ioctl_id: u16,
43 sdpcm_seq: u8,
44 sdpcm_seq_max: u8,
45
46 events: &'a Events,
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 IoctlState,
61 events: &'a Events,
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 debug!("waiting for clock...");
84 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
85 debug!("clock ok");
86
87 let chip_id = self.bus.bp_read16(0x1800_0000).await;
88 debug!("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 debug!("loading fw");
99 self.bus.bp_write(ram_addr, firmware).await;
100
101 debug!("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 debug!("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 self.bus
125 .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE)
126 .await;
127
128 // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
129 // Sounds scary...
130 self.bus
131 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32)
132 .await;
133
134 // wait for wifi startup
135 debug!("waiting for wifi init...");
136 while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
137
138 // Some random configs related to sleep.
139 // These aren't needed if we don't want to sleep the bus.
140 // TODO do we need to sleep the bus to read the irq line, due to
141 // being on the same pin as MOSI/MISO?
142
143 /*
144 let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL).await;
145 val |= 0x02; // WAKE_TILL_HT_AVAIL
146 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL, val).await;
147 self.bus.write8(FUNC_BUS, 0xF0, 0x08).await; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1
148 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x02).await; // SBSDIO_FORCE_HT
149
150 let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR).await;
151 val |= 0x01; // SBSDIO_SLPCSR_KEEP_SDIO_ON
152 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR, val).await;
153 */
154
155 // clear pulls
156 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
157 let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
158
159 // start HT clock
160 //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await;
161 //debug!("waiting for HT clock...");
162 //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
163 //debug!("clock ok");
164
165 #[cfg(feature = "firmware-logs")]
166 self.log_init().await;
167
168 debug!("wifi init done");
169 }
170
171 #[cfg(feature = "firmware-logs")]
172 async fn log_init(&mut self) {
173 // Initialize shared memory for logging.
174
175 let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size;
176 let shared_addr = self.bus.bp_read32(addr).await;
177 debug!("shared_addr {:08x}", shared_addr);
178
179 let mut shared = [0; SharedMemData::SIZE];
180 self.bus.bp_read(shared_addr, &mut shared).await;
181 let shared = SharedMemData::from_bytes(&shared);
182
183 self.log.addr = shared.console_addr + 8;
184 }
185
186 #[cfg(feature = "firmware-logs")]
187 async fn log_read(&mut self) {
188 // Read log struct
189 let mut log = [0; SharedMemLog::SIZE];
190 self.bus.bp_read(self.log.addr, &mut log).await;
191 let log = SharedMemLog::from_bytes(&log);
192
193 let idx = log.idx as usize;
194
195 // If pointer hasn't moved, no need to do anything.
196 if idx == self.log.last_idx {
197 return;
198 }
199
200 // Read entire buf for now. We could read only what we need, but then we
201 // run into annoying alignment issues in `bp_read`.
202 let mut buf = [0; 0x400];
203 self.bus.bp_read(log.buf, &mut buf).await;
204
205 while self.log.last_idx != idx as usize {
206 let b = buf[self.log.last_idx];
207 if b == b'\r' || b == b'\n' {
208 if self.log.buf_count != 0 {
209 let s = unsafe { core::str::from_utf8_unchecked(&self.log.buf[..self.log.buf_count]) };
210 debug!("LOGS: {}", s);
211 self.log.buf_count = 0;
212 }
213 } else if self.log.buf_count < self.log.buf.len() {
214 self.log.buf[self.log.buf_count] = b;
215 self.log.buf_count += 1;
216 }
217
218 self.log.last_idx += 1;
219 if self.log.last_idx == 0x400 {
220 self.log.last_idx = 0;
221 }
222 }
223 }
224
225 pub async fn run(mut self) -> ! {
226 let mut buf = [0; 512];
227 loop {
228 #[cfg(feature = "firmware-logs")]
229 self.log_read().await;
230
231 if self.has_credit() {
232 let ioctl = self.ioctl_state.wait_pending();
233 let tx = self.ch.tx_buf();
234 let ev = self.bus.wait_for_event();
235
236 match select3(ioctl, tx, ev).await {
237 Either3::First(PendingIoctl {
238 buf: iobuf,
239 kind,
240 cmd,
241 iface,
242 }) => {
243 self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await;
244 self.check_status(&mut buf).await;
245 }
246 Either3::Second(packet) => {
247 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
248
249 let mut buf = [0; 512];
250 let buf8 = slice8_mut(&mut buf);
251
252 // There MUST be 2 bytes of padding between the SDPCM and BDC headers.
253 // And ONLY for data packets!
254 // No idea why, but the firmware will append two zero bytes to the tx'd packets
255 // otherwise. If the packet is exactly 1514 bytes (the max MTU), this makes it
256 // be oversized and get dropped.
257 // WHD adds it here https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/include/whd_sdpcm.h#L90
258 // 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
259 // ¯\_(ツ)_/¯
260 const PADDING_SIZE: usize = 2;
261 let total_len = SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE + packet.len();
262
263 let seq = self.sdpcm_seq;
264 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
265
266 let sdpcm_header = SdpcmHeader {
267 len: total_len as u16, // TODO does this len need to be rounded up to u32?
268 len_inv: !total_len as u16,
269 sequence: seq,
270 channel_and_flags: CHANNEL_TYPE_DATA,
271 next_length: 0,
272 header_length: (SdpcmHeader::SIZE + PADDING_SIZE) as _,
273 wireless_flow_control: 0,
274 bus_data_credit: 0,
275 reserved: [0, 0],
276 };
277
278 let bdc_header = BdcHeader {
279 flags: BDC_VERSION << BDC_VERSION_SHIFT,
280 priority: 0,
281 flags2: 0,
282 data_offset: 0,
283 };
284 trace!("tx {:?}", sdpcm_header);
285 trace!(" {:?}", bdc_header);
286
287 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
288 buf8[SdpcmHeader::SIZE + PADDING_SIZE..][..BdcHeader::SIZE]
289 .copy_from_slice(&bdc_header.to_bytes());
290 buf8[SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE..][..packet.len()]
291 .copy_from_slice(packet);
292
293 let total_len = (total_len + 3) & !3; // round up to 4byte
294
295 trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)]));
296
297 self.bus.wlan_write(&buf[..(total_len / 4)]).await;
298 self.ch.tx_done();
299 self.check_status(&mut buf).await;
300 }
301 Either3::Third(()) => {
302 self.handle_irq(&mut buf).await;
303 }
304 }
305 } else {
306 warn!("TX stalled");
307 self.bus.wait_for_event().await;
308 self.handle_irq(&mut buf).await;
309 }
310 }
311 }
312
313 /// Wait for IRQ on F2 packet available
314 async fn handle_irq(&mut self, buf: &mut [u32; 512]) {
315 // Receive stuff
316 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
317 trace!("irq{}", FormatInterrupt(irq));
318
319 if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
320 self.check_status(buf).await;
321 }
322
323 if irq & IRQ_DATA_UNAVAILABLE != 0 {
324 // TODO what should we do here?
325 warn!("IRQ DATA_UNAVAILABLE, clearing...");
326 self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await;
327 }
328 }
329
330 /// Handle F2 events while status register is set
331 async fn check_status(&mut self, buf: &mut [u32; 512]) {
332 loop {
333 let status = self.bus.status();
334 trace!("check status{}", FormatStatus(status));
335
336 if status & STATUS_F2_PKT_AVAILABLE != 0 {
337 let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
338 self.bus.wlan_read(buf, len).await;
339 trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)]));
340 self.rx(&mut slice8_mut(buf)[..len as usize]);
341 } else {
342 break;
343 }
344 }
345 }
346
347 fn rx(&mut self, packet: &mut [u8]) {
348 let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else { return };
349
350 self.update_credit(&sdpcm_header);
351
352 let channel = sdpcm_header.channel_and_flags & 0x0f;
353
354 match channel {
355 CHANNEL_TYPE_CONTROL => {
356 let Some((cdc_header, response)) = CdcHeader::parse(payload) else { return; };
357 trace!(" {:?}", cdc_header);
358
359 if cdc_header.id == self.ioctl_id {
360 if cdc_header.status != 0 {
361 // TODO: propagate error instead
362 panic!("IOCTL error {}", cdc_header.status as i32);
363 }
364
365 self.ioctl_state.ioctl_done(response);
366 }
367 }
368 CHANNEL_TYPE_EVENT => {
369 let Some((_, bdc_packet)) = BdcHeader::parse(payload) else {
370 warn!("BDC event, incomplete header");
371 return;
372 };
373
374 let Some((event_packet, evt_data)) = EventPacket::parse(bdc_packet) else {
375 warn!("BDC event, incomplete data");
376 return;
377 };
378
379 const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h
380 if event_packet.eth.ether_type != ETH_P_LINK_CTL {
381 warn!(
382 "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}",
383 event_packet.eth.ether_type, ETH_P_LINK_CTL
384 );
385 return;
386 }
387 const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18];
388 if event_packet.hdr.oui != BROADCOM_OUI {
389 warn!(
390 "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}",
391 Bytes(&event_packet.hdr.oui),
392 Bytes(BROADCOM_OUI)
393 );
394 return;
395 }
396 const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769;
397 if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG {
398 warn!("unexpected subtype {}", event_packet.hdr.subtype);
399 return;
400 }
401
402 const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1;
403 if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT {
404 warn!("unexpected user_subtype {}", event_packet.hdr.subtype);
405 return;
406 }
407
408 let evt_type = events::Event::from(event_packet.msg.event_type as u8);
409 debug!(
410 "=== EVENT {:?}: {:?} {:02x}",
411 evt_type,
412 event_packet.msg,
413 Bytes(evt_data)
414 );
415
416 if self.events.mask.is_enabled(evt_type) {
417 let status = event_packet.msg.status;
418 let event_payload = match evt_type {
419 Event::ESCAN_RESULT if status == EStatus::PARTIAL => {
420 let Some((_, bss_info)) = ScanResults::parse(evt_data) else { return };
421 let Some(bss_info) = BssInfo::parse(bss_info) else { return };
422 events::Payload::BssInfo(*bss_info)
423 }
424 Event::ESCAN_RESULT => events::Payload::None,
425 _ => events::Payload::None,
426 };
427
428 // this intentionally uses the non-blocking publish immediate
429 // publish() is a deadlock risk in the current design as awaiting here prevents ioctls
430 // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event
431 // (if they are actively awaiting the queue)
432 self.events.queue.publish_immediate(events::Message::new(
433 Status {
434 event_type: evt_type,
435 status,
436 },
437 event_payload,
438 ));
439 }
440 }
441 CHANNEL_TYPE_DATA => {
442 let Some((_, packet)) = BdcHeader::parse(payload) else { return };
443 trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
444
445 match self.ch.try_rx_buf() {
446 Some(buf) => {
447 buf[..packet.len()].copy_from_slice(packet);
448 self.ch.rx_done(packet.len())
449 }
450 None => warn!("failed to push rxd packet to the channel."),
451 }
452 }
453 _ => {}
454 }
455 }
456
457 fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) {
458 if sdpcm_header.channel_and_flags & 0xf < 3 {
459 let mut sdpcm_seq_max = sdpcm_header.bus_data_credit;
460 if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 {
461 sdpcm_seq_max = self.sdpcm_seq + 2;
462 }
463 self.sdpcm_seq_max = sdpcm_seq_max;
464 }
465 }
466
467 fn has_credit(&self) -> bool {
468 self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0
469 }
470
471 async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) {
472 let mut buf = [0; 512];
473 let buf8 = slice8_mut(&mut buf);
474
475 let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
476
477 let sdpcm_seq = self.sdpcm_seq;
478 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
479 self.ioctl_id = self.ioctl_id.wrapping_add(1);
480
481 let sdpcm_header = SdpcmHeader {
482 len: total_len as u16, // TODO does this len need to be rounded up to u32?
483 len_inv: !total_len as u16,
484 sequence: sdpcm_seq,
485 channel_and_flags: CHANNEL_TYPE_CONTROL,
486 next_length: 0,
487 header_length: SdpcmHeader::SIZE as _,
488 wireless_flow_control: 0,
489 bus_data_credit: 0,
490 reserved: [0, 0],
491 };
492
493 let cdc_header = CdcHeader {
494 cmd: cmd,
495 len: data.len() as _,
496 flags: kind as u16 | (iface as u16) << 12,
497 id: self.ioctl_id,
498 status: 0,
499 };
500 trace!("tx {:?}", sdpcm_header);
501 trace!(" {:?}", cdc_header);
502
503 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
504 buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes());
505 buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data);
506
507 let total_len = (total_len + 3) & !3; // round up to 4byte
508
509 trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)]));
510
511 self.bus.wlan_write(&buf[..total_len / 4]).await;
512 }
513
514 async fn core_disable(&mut self, core: Core) {
515 let base = core.base_addr();
516
517 // Dummy read?
518 let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
519
520 // Check it isn't already reset
521 let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
522 if r & AI_RESETCTRL_BIT_RESET != 0 {
523 return;
524 }
525
526 self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await;
527 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
528
529 block_for(Duration::from_millis(1));
530
531 self.bus
532 .bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET)
533 .await;
534 let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
535 }
536
537 async fn core_reset(&mut self, core: Core) {
538 self.core_disable(core).await;
539
540 let base = core.base_addr();
541 self.bus
542 .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN)
543 .await;
544 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
545
546 self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
547
548 Timer::after(Duration::from_millis(1)).await;
549
550 self.bus
551 .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
552 .await;
553 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
554
555 Timer::after(Duration::from_millis(1)).await;
556 }
557
558 async fn core_is_up(&mut self, core: Core) -> bool {
559 let base = core.base_addr();
560
561 let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
562 if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN {
563 debug!("core_is_up: returning false due to bad ioctrl {:02x}", io);
564 return false;
565 }
566
567 let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
568 if r & (AI_RESETCTRL_BIT_RESET) != 0 {
569 debug!("core_is_up: returning false due to bad resetctrl {:02x}", r);
570 return false;
571 }
572
573 true
574 }
575}
diff --git a/cyw43/src/structs.rs b/cyw43/src/structs.rs
new file mode 100644
index 000000000..5ba633c74
--- /dev/null
+++ b/cyw43/src/structs.rs
@@ -0,0 +1,496 @@
1use crate::events::Event;
2use crate::fmt::Bytes;
3
4macro_rules! impl_bytes {
5 ($t:ident) => {
6 impl $t {
7 pub const SIZE: usize = core::mem::size_of::<Self>();
8
9 #[allow(unused)]
10 pub fn to_bytes(&self) -> [u8; Self::SIZE] {
11 unsafe { core::mem::transmute(*self) }
12 }
13
14 #[allow(unused)]
15 pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self {
16 let alignment = core::mem::align_of::<Self>();
17 assert_eq!(
18 bytes.as_ptr().align_offset(alignment),
19 0,
20 "{} is not aligned",
21 core::any::type_name::<Self>()
22 );
23 unsafe { core::mem::transmute(bytes) }
24 }
25
26 #[allow(unused)]
27 pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self {
28 let alignment = core::mem::align_of::<Self>();
29 assert_eq!(
30 bytes.as_ptr().align_offset(alignment),
31 0,
32 "{} is not aligned",
33 core::any::type_name::<Self>()
34 );
35
36 unsafe { core::mem::transmute(bytes) }
37 }
38 }
39 };
40}
41
42#[derive(Clone, Copy)]
43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
44#[repr(C)]
45pub struct SharedMemData {
46 pub flags: u32,
47 pub trap_addr: u32,
48 pub assert_exp_addr: u32,
49 pub assert_file_addr: u32,
50 pub assert_line: u32,
51 pub console_addr: u32,
52 pub msgtrace_addr: u32,
53 pub fwid: u32,
54}
55impl_bytes!(SharedMemData);
56
57#[derive(Clone, Copy)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59#[repr(C)]
60pub struct SharedMemLog {
61 pub buf: u32,
62 pub buf_size: u32,
63 pub idx: u32,
64 pub out_idx: u32,
65}
66impl_bytes!(SharedMemLog);
67
68#[derive(Debug, Clone, Copy)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70#[repr(C)]
71pub struct SdpcmHeader {
72 pub len: u16,
73 pub len_inv: u16,
74 /// Rx/Tx sequence number
75 pub sequence: u8,
76 /// 4 MSB Channel number, 4 LSB arbitrary flag
77 pub channel_and_flags: u8,
78 /// Length of next data frame, reserved for Tx
79 pub next_length: u8,
80 /// Data offset
81 pub header_length: u8,
82 /// Flow control bits, reserved for Tx
83 pub wireless_flow_control: u8,
84 /// Maximum Sequence number allowed by firmware for Tx
85 pub bus_data_credit: u8,
86 /// Reserved
87 pub reserved: [u8; 2],
88}
89impl_bytes!(SdpcmHeader);
90
91impl SdpcmHeader {
92 pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> {
93 let packet_len = packet.len();
94 if packet_len < Self::SIZE {
95 warn!("packet too short, len={}", packet.len());
96 return None;
97 }
98 let (sdpcm_header, sdpcm_packet) = packet.split_at_mut(Self::SIZE);
99 let sdpcm_header = Self::from_bytes_mut(sdpcm_header.try_into().unwrap());
100 trace!("rx {:?}", sdpcm_header);
101
102 if sdpcm_header.len != !sdpcm_header.len_inv {
103 warn!("len inv mismatch");
104 return None;
105 }
106
107 if sdpcm_header.len as usize != packet_len {
108 warn!("len from header doesn't match len from spi");
109 return None;
110 }
111
112 let sdpcm_packet = &mut sdpcm_packet[(sdpcm_header.header_length as usize - Self::SIZE)..];
113 Some((sdpcm_header, sdpcm_packet))
114 }
115}
116
117#[derive(Debug, Clone, Copy)]
118#[repr(C, packed(2))]
119pub struct CdcHeader {
120 pub cmd: u32,
121 pub len: u32,
122 pub flags: u16,
123 pub id: u16,
124 pub status: u32,
125}
126impl_bytes!(CdcHeader);
127
128#[cfg(feature = "defmt")]
129impl defmt::Format for CdcHeader {
130 fn format(&self, fmt: defmt::Formatter) {
131 fn copy<T: Copy>(t: T) -> T {
132 t
133 }
134
135 defmt::write!(
136 fmt,
137 "CdcHeader{{cmd: {=u32:08x}, len: {=u32:08x}, flags: {=u16:04x}, id: {=u16:04x}, status: {=u32:08x}}}",
138 copy(self.cmd),
139 copy(self.len),
140 copy(self.flags),
141 copy(self.id),
142 copy(self.status),
143 )
144 }
145}
146
147impl CdcHeader {
148 pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> {
149 if packet.len() < Self::SIZE {
150 warn!("payload too short, len={}", packet.len());
151 return None;
152 }
153
154 let (cdc_header, payload) = packet.split_at_mut(Self::SIZE);
155 let cdc_header = Self::from_bytes_mut(cdc_header.try_into().unwrap());
156
157 let payload = &mut payload[..cdc_header.len as usize];
158 Some((cdc_header, payload))
159 }
160}
161
162pub const BDC_VERSION: u8 = 2;
163pub const BDC_VERSION_SHIFT: u8 = 4;
164
165#[derive(Debug, Clone, Copy)]
166#[cfg_attr(feature = "defmt", derive(defmt::Format))]
167#[repr(C)]
168pub struct BdcHeader {
169 pub flags: u8,
170 /// 802.1d Priority (low 3 bits)
171 pub priority: u8,
172 pub flags2: u8,
173 /// Offset from end of BDC header to packet data, in 4-uint8_t words. Leaves room for optional headers.
174 pub data_offset: u8,
175}
176impl_bytes!(BdcHeader);
177
178impl BdcHeader {
179 pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> {
180 if packet.len() < Self::SIZE {
181 return None;
182 }
183
184 let (bdc_header, bdc_packet) = packet.split_at_mut(Self::SIZE);
185 let bdc_header = Self::from_bytes_mut(bdc_header.try_into().unwrap());
186 trace!(" {:?}", bdc_header);
187
188 let packet_start = 4 * bdc_header.data_offset as usize;
189
190 let bdc_packet = bdc_packet.get_mut(packet_start..)?;
191 trace!(" {:02x}", Bytes(&bdc_packet[..bdc_packet.len().min(36)]));
192
193 Some((bdc_header, bdc_packet))
194 }
195}
196
197#[derive(Clone, Copy)]
198#[cfg_attr(feature = "defmt", derive(defmt::Format))]
199#[repr(C)]
200pub struct EthernetHeader {
201 pub destination_mac: [u8; 6],
202 pub source_mac: [u8; 6],
203 pub ether_type: u16,
204}
205
206impl EthernetHeader {
207 pub fn byteswap(&mut self) {
208 self.ether_type = self.ether_type.to_be();
209 }
210}
211
212#[derive(Clone, Copy)]
213#[cfg_attr(feature = "defmt", derive(defmt::Format))]
214#[repr(C)]
215pub struct EventHeader {
216 pub subtype: u16,
217 pub length: u16,
218 pub version: u8,
219 pub oui: [u8; 3],
220 pub user_subtype: u16,
221}
222
223impl EventHeader {
224 pub fn byteswap(&mut self) {
225 self.subtype = self.subtype.to_be();
226 self.length = self.length.to_be();
227 self.user_subtype = self.user_subtype.to_be();
228 }
229}
230
231#[derive(Debug, Clone, Copy)]
232// #[cfg_attr(feature = "defmt", derive(defmt::Format))]
233#[repr(C, packed(2))]
234pub struct EventMessage {
235 /// version
236 pub version: u16,
237 /// see flags below
238 pub flags: u16,
239 /// Message (see below)
240 pub event_type: u32,
241 /// Status code (see below)
242 pub status: u32,
243 /// Reason code (if applicable)
244 pub reason: u32,
245 /// WLC_E_AUTH
246 pub auth_type: u32,
247 /// data buf
248 pub datalen: u32,
249 /// Station address (if applicable)
250 pub addr: [u8; 6],
251 /// name of the incoming packet interface
252 pub ifname: [u8; 16],
253 /// destination OS i/f index
254 pub ifidx: u8,
255 /// source bsscfg index
256 pub bsscfgidx: u8,
257}
258impl_bytes!(EventMessage);
259
260#[cfg(feature = "defmt")]
261impl defmt::Format for EventMessage {
262 fn format(&self, fmt: defmt::Formatter) {
263 let event_type = self.event_type;
264 let status = self.status;
265 let reason = self.reason;
266 let auth_type = self.auth_type;
267 let datalen = self.datalen;
268
269 defmt::write!(
270 fmt,
271 "EventMessage {{ \
272 version: {=u16}, \
273 flags: {=u16}, \
274 event_type: {=u32}, \
275 status: {=u32}, \
276 reason: {=u32}, \
277 auth_type: {=u32}, \
278 datalen: {=u32}, \
279 addr: {=[u8; 6]:x}, \
280 ifname: {=[u8; 16]:x}, \
281 ifidx: {=u8}, \
282 bsscfgidx: {=u8}, \
283 }} ",
284 self.version,
285 self.flags,
286 event_type,
287 status,
288 reason,
289 auth_type,
290 datalen,
291 self.addr,
292 self.ifname,
293 self.ifidx,
294 self.bsscfgidx
295 );
296 }
297}
298
299impl EventMessage {
300 pub fn byteswap(&mut self) {
301 self.version = self.version.to_be();
302 self.flags = self.flags.to_be();
303 self.event_type = self.event_type.to_be();
304 self.status = self.status.to_be();
305 self.reason = self.reason.to_be();
306 self.auth_type = self.auth_type.to_be();
307 self.datalen = self.datalen.to_be();
308 }
309}
310
311#[derive(Clone, Copy)]
312#[cfg_attr(feature = "defmt", derive(defmt::Format))]
313#[repr(C, packed(2))]
314pub struct EventPacket {
315 pub eth: EthernetHeader,
316 pub hdr: EventHeader,
317 pub msg: EventMessage,
318}
319impl_bytes!(EventPacket);
320
321impl EventPacket {
322 pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> {
323 if packet.len() < Self::SIZE {
324 return None;
325 }
326
327 let (event_header, event_packet) = packet.split_at_mut(Self::SIZE);
328 let event_header = Self::from_bytes_mut(event_header.try_into().unwrap());
329 // warn!("event_header {:x}", event_header as *const _);
330 event_header.byteswap();
331
332 let event_packet = event_packet.get_mut(..event_header.msg.datalen as usize)?;
333
334 Some((event_header, event_packet))
335 }
336
337 pub fn byteswap(&mut self) {
338 self.eth.byteswap();
339 self.hdr.byteswap();
340 self.msg.byteswap();
341 }
342}
343
344#[derive(Clone, Copy)]
345#[repr(C)]
346pub struct DownloadHeader {
347 pub flag: u16, //
348 pub dload_type: u16,
349 pub len: u32,
350 pub crc: u32,
351}
352impl_bytes!(DownloadHeader);
353
354#[allow(unused)]
355pub const DOWNLOAD_FLAG_NO_CRC: u16 = 0x0001;
356pub const DOWNLOAD_FLAG_BEGIN: u16 = 0x0002;
357pub const DOWNLOAD_FLAG_END: u16 = 0x0004;
358pub const DOWNLOAD_FLAG_HANDLER_VER: u16 = 0x1000;
359
360// Country Locale Matrix (CLM)
361pub const DOWNLOAD_TYPE_CLM: u16 = 2;
362
363#[derive(Clone, Copy)]
364#[cfg_attr(feature = "defmt", derive(defmt::Format))]
365#[repr(C)]
366pub struct CountryInfo {
367 pub country_abbrev: [u8; 4],
368 pub rev: i32,
369 pub country_code: [u8; 4],
370}
371impl_bytes!(CountryInfo);
372
373#[derive(Clone, Copy)]
374#[cfg_attr(feature = "defmt", derive(defmt::Format))]
375#[repr(C)]
376pub struct SsidInfo {
377 pub len: u32,
378 pub ssid: [u8; 32],
379}
380impl_bytes!(SsidInfo);
381
382#[derive(Clone, Copy)]
383#[cfg_attr(feature = "defmt", derive(defmt::Format))]
384#[repr(C)]
385pub struct PassphraseInfo {
386 pub len: u16,
387 pub flags: u16,
388 pub passphrase: [u8; 64],
389}
390impl_bytes!(PassphraseInfo);
391
392#[derive(Clone, Copy)]
393#[cfg_attr(feature = "defmt", derive(defmt::Format))]
394#[repr(C)]
395pub struct SsidInfoWithIndex {
396 pub index: u32,
397 pub ssid_info: SsidInfo,
398}
399impl_bytes!(SsidInfoWithIndex);
400
401#[derive(Clone, Copy)]
402#[cfg_attr(feature = "defmt", derive(defmt::Format))]
403#[repr(C)]
404pub struct EventMask {
405 pub iface: u32,
406 pub events: [u8; 24],
407}
408impl_bytes!(EventMask);
409
410impl EventMask {
411 pub fn unset(&mut self, evt: Event) {
412 let evt = evt as u8 as usize;
413 self.events[evt / 8] &= !(1 << (evt % 8));
414 }
415}
416
417/// Parameters for a wifi scan
418#[derive(Clone, Copy)]
419#[cfg_attr(feature = "defmt", derive(defmt::Format))]
420#[repr(C)]
421pub struct ScanParams {
422 pub version: u32,
423 pub action: u16,
424 pub sync_id: u16,
425 pub ssid_len: u32,
426 pub ssid: [u8; 32],
427 pub bssid: [u8; 6],
428 pub bss_type: u8,
429 pub scan_type: u8,
430 pub nprobes: u32,
431 pub active_time: u32,
432 pub passive_time: u32,
433 pub home_time: u32,
434 pub channel_num: u32,
435 pub channel_list: [u16; 1],
436}
437impl_bytes!(ScanParams);
438
439/// Wifi Scan Results Header, followed by `bss_count` `BssInfo`
440#[derive(Clone, Copy)]
441// #[cfg_attr(feature = "defmt", derive(defmt::Format))]
442#[repr(C, packed(2))]
443pub struct ScanResults {
444 pub buflen: u32,
445 pub version: u32,
446 pub sync_id: u16,
447 pub bss_count: u16,
448}
449impl_bytes!(ScanResults);
450
451impl ScanResults {
452 pub fn parse(packet: &mut [u8]) -> Option<(&mut ScanResults, &mut [u8])> {
453 if packet.len() < ScanResults::SIZE {
454 return None;
455 }
456
457 let (scan_results, bssinfo) = packet.split_at_mut(ScanResults::SIZE);
458 let scan_results = ScanResults::from_bytes_mut(scan_results.try_into().unwrap());
459
460 if scan_results.bss_count > 0 && bssinfo.len() < BssInfo::SIZE {
461 warn!("Scan result, incomplete BssInfo");
462 return None;
463 }
464
465 Some((scan_results, bssinfo))
466 }
467}
468
469/// Wifi Scan Result
470#[derive(Clone, Copy)]
471// #[cfg_attr(feature = "defmt", derive(defmt::Format))]
472#[repr(C, packed(2))]
473#[non_exhaustive]
474pub struct BssInfo {
475 pub version: u32,
476 pub length: u32,
477 pub bssid: [u8; 6],
478 pub beacon_period: u16,
479 pub capability: u16,
480 pub ssid_len: u8,
481 pub ssid: [u8; 32],
482 // there will be more stuff here
483}
484impl_bytes!(BssInfo);
485
486impl BssInfo {
487 pub fn parse(packet: &mut [u8]) -> Option<&mut Self> {
488 if packet.len() < BssInfo::SIZE {
489 return None;
490 }
491
492 Some(BssInfo::from_bytes_mut(
493 packet[..BssInfo::SIZE].as_mut().try_into().unwrap(),
494 ))
495 }
496}