aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-05-30 22:43:40 +0200
committerDario Nieuwenhuis <[email protected]>2023-05-30 22:43:40 +0200
commitb3bbe5eb2d0f7ec6c8cae6e0486cb46a433fe11a (patch)
tree620783af45d908710b53bf792f4a449a274c98df
parentf5d0d28ac3cfcb74eaa59bbe984b7969a0743724 (diff)
parentc327c6cd6fc3c11cfaf83cf64591940d401c5f6b (diff)
Merge remote-tracking branch 'cyw43/master' into cyw43
-rwxr-xr-xcyw43-firmware/43439A0.binbin0 -> 224190 bytes
-rwxr-xr-xcyw43-firmware/43439A0_clm.binbin0 -> 4752 bytes
-rw-r--r--cyw43-firmware/LICENSE-permissive-binary-license-1.0.txt49
-rw-r--r--cyw43-firmware/README.md5
-rw-r--r--cyw43-pio/Cargo.toml17
-rw-r--r--cyw43-pio/src/lib.rs229
-rw-r--r--cyw43/Cargo.toml40
-rw-r--r--cyw43/README.md57
-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
-rw-r--r--examples/rpi-pico-w/.cargo/config.toml8
-rw-r--r--examples/rpi-pico-w/Cargo.lock1707
-rw-r--r--examples/rpi-pico-w/Cargo.toml67
-rw-r--r--examples/rpi-pico-w/build.rs36
-rw-r--r--examples/rpi-pico-w/memory.x5
-rw-r--r--examples/rpi-pico-w/src/bin/tcp_server.rs160
-rw-r--r--examples/rpi-pico-w/src/bin/tcp_server_ap.rs150
-rw-r--r--examples/rpi-pico-w/src/bin/wifi_scan.rs87
27 files changed, 6345 insertions, 0 deletions
diff --git a/cyw43-firmware/43439A0.bin b/cyw43-firmware/43439A0.bin
new file mode 100755
index 000000000..b46b3beff
--- /dev/null
+++ b/cyw43-firmware/43439A0.bin
Binary files differ
diff --git a/cyw43-firmware/43439A0_clm.bin b/cyw43-firmware/43439A0_clm.bin
new file mode 100755
index 000000000..6e3ba786b
--- /dev/null
+++ b/cyw43-firmware/43439A0_clm.bin
Binary files differ
diff --git a/cyw43-firmware/LICENSE-permissive-binary-license-1.0.txt b/cyw43-firmware/LICENSE-permissive-binary-license-1.0.txt
new file mode 100644
index 000000000..cbb51f9c9
--- /dev/null
+++ b/cyw43-firmware/LICENSE-permissive-binary-license-1.0.txt
@@ -0,0 +1,49 @@
1Permissive Binary License
2
3Version 1.0, July 2019
4
5Redistribution. Redistribution and use in binary form, without
6modification, are permitted provided that the following conditions are
7met:
8
91) Redistributions must reproduce the above copyright notice and the
10 following disclaimer in the documentation and/or other materials
11 provided with the distribution.
12
132) Unless to the extent explicitly permitted by law, no reverse
14 engineering, decompilation, or disassembly of this software is
15 permitted.
16
173) Redistribution as part of a software development kit must include the
18 accompanying file named �DEPENDENCIES� and any dependencies listed in
19 that file.
20
214) Neither the name of the copyright holder nor the names of its
22 contributors may be used to endorse or promote products derived from
23 this software without specific prior written permission.
24
25Limited patent license. The copyright holders (and contributors) grant a
26worldwide, non-exclusive, no-charge, royalty-free patent license to
27make, have made, use, offer to sell, sell, import, and otherwise
28transfer this software, where such license applies only to those patent
29claims licensable by the copyright holders (and contributors) that are
30necessarily infringed by this software. This patent license shall not
31apply to any combinations that include this software. No hardware is
32licensed hereunder.
33
34If you institute patent litigation against any entity (including a
35cross-claim or counterclaim in a lawsuit) alleging that the software
36itself infringes your patent(s), then your rights granted under this
37license shall terminate as of the date such litigation is filed.
38
39DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
40CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
41NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
42FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
43HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
45TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
46PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
47LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
48NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
49SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/cyw43-firmware/README.md b/cyw43-firmware/README.md
new file mode 100644
index 000000000..7381fdc56
--- /dev/null
+++ b/cyw43-firmware/README.md
@@ -0,0 +1,5 @@
1# WiFi firmware
2
3Firmware obtained from https://github.com/Infineon/wifi-host-driver/tree/master/WiFi_Host_Driver/resources/firmware/COMPONENT_43439
4
5Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt) \ No newline at end of file
diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml
new file mode 100644
index 000000000..a7af2c8e2
--- /dev/null
+++ b/cyw43-pio/Cargo.toml
@@ -0,0 +1,17 @@
1[package]
2name = "cyw43-pio"
3version = "0.1.0"
4edition = "2021"
5
6[features]
7# If disabled, SPI runs at 31.25MHz
8# If enabled, SPI runs at 62.5MHz, which is 25% higher than 50Mhz which is the maximum according to the CYW43439 datasheet.
9overclock = []
10
11[dependencies]
12cyw43 = { path = "../cyw43" }
13embassy-rp = { version = "0.1.0", features = ["unstable-traits", "nightly", "unstable-pac", "time-driver"] }
14pio-proc = "0.2"
15pio = "0.2.1"
16fixed = "1.23.1"
17defmt = { version = "0.3", optional = true } \ No newline at end of file
diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs
new file mode 100644
index 000000000..dca30c74d
--- /dev/null
+++ b/cyw43-pio/src/lib.rs
@@ -0,0 +1,229 @@
1#![no_std]
2#![allow(incomplete_features)]
3#![feature(async_fn_in_trait)]
4
5use core::slice;
6
7use cyw43::SpiBusCyw43;
8use embassy_rp::dma::Channel;
9use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate};
10use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine};
11use embassy_rp::relocate::RelocatedProgram;
12use embassy_rp::{pio_instr_util, Peripheral, PeripheralRef};
13use fixed::FixedU32;
14use pio_proc::pio_asm;
15
16pub struct PioSpi<'d, CS: Pin, PIO: Instance, const SM: usize, DMA> {
17 cs: Output<'d, CS>,
18 sm: StateMachine<'d, PIO, SM>,
19 irq: Irq<'d, PIO, 0>,
20 dma: PeripheralRef<'d, DMA>,
21 wrap_target: u8,
22}
23
24impl<'d, CS, PIO, const SM: usize, DMA> PioSpi<'d, CS, PIO, SM, DMA>
25where
26 DMA: Channel,
27 CS: Pin,
28 PIO: Instance,
29{
30 pub fn new<DIO, CLK>(
31 common: &mut Common<'d, PIO>,
32 mut sm: StateMachine<'d, PIO, SM>,
33 irq: Irq<'d, PIO, 0>,
34 cs: Output<'d, CS>,
35 dio: DIO,
36 clk: CLK,
37 dma: impl Peripheral<P = DMA> + 'd,
38 ) -> Self
39 where
40 DIO: PioPin,
41 CLK: PioPin,
42 {
43 #[cfg(feature = "overclock")]
44 let program = pio_asm!(
45 ".side_set 1"
46
47 ".wrap_target"
48 // write out x-1 bits
49 "lp:"
50 "out pins, 1 side 0"
51 "jmp x-- lp side 1"
52 // switch directions
53 "set pindirs, 0 side 0"
54 "nop side 1" // necessary for clkdiv=1.
55 "nop side 0"
56 // read in y-1 bits
57 "lp2:"
58 "in pins, 1 side 1"
59 "jmp y-- lp2 side 0"
60
61 // wait for event and irq host
62 "wait 1 pin 0 side 0"
63 "irq 0 side 0"
64
65 ".wrap"
66 );
67 #[cfg(not(feature = "overclock"))]
68 let program = pio_asm!(
69 ".side_set 1"
70
71 ".wrap_target"
72 // write out x-1 bits
73 "lp:"
74 "out pins, 1 side 0"
75 "jmp x-- lp side 1"
76 // switch directions
77 "set pindirs, 0 side 0"
78 "nop side 0"
79 // read in y-1 bits
80 "lp2:"
81 "in pins, 1 side 1"
82 "jmp y-- lp2 side 0"
83
84 // wait for event and irq host
85 "wait 1 pin 0 side 0"
86 "irq 0 side 0"
87
88 ".wrap"
89 );
90
91 let relocated = RelocatedProgram::new(&program.program);
92
93 let mut pin_io: embassy_rp::pio::Pin<PIO> = common.make_pio_pin(dio);
94 pin_io.set_pull(Pull::None);
95 pin_io.set_schmitt(true);
96 pin_io.set_input_sync_bypass(true);
97 pin_io.set_drive_strength(Drive::_12mA);
98 pin_io.set_slew_rate(SlewRate::Fast);
99
100 let mut pin_clk = common.make_pio_pin(clk);
101 pin_clk.set_drive_strength(Drive::_12mA);
102 pin_clk.set_slew_rate(SlewRate::Fast);
103
104 let mut cfg = Config::default();
105 cfg.use_program(&common.load_program(&relocated), &[&pin_clk]);
106 cfg.set_out_pins(&[&pin_io]);
107 cfg.set_in_pins(&[&pin_io]);
108 cfg.set_set_pins(&[&pin_io]);
109 cfg.shift_out.direction = ShiftDirection::Left;
110 cfg.shift_out.auto_fill = true;
111 //cfg.shift_out.threshold = 32;
112 cfg.shift_in.direction = ShiftDirection::Left;
113 cfg.shift_in.auto_fill = true;
114 //cfg.shift_in.threshold = 32;
115
116 #[cfg(feature = "overclock")]
117 {
118 // 125mhz Pio => 62.5Mhz SPI Freq. 25% higher than theoretical maximum according to
119 // data sheet, but seems to work fine.
120 cfg.clock_divider = FixedU32::from_bits(0x0100);
121 }
122
123 #[cfg(not(feature = "overclock"))]
124 {
125 // same speed as pico-sdk, 62.5Mhz
126 // This is actually the fastest we can go without overclocking.
127 // According to data sheet, the theoretical maximum is 100Mhz Pio => 50Mhz SPI Freq.
128 // However, the PIO uses a fractional divider, which works by introducing jitter when
129 // the divider is not an integer. It does some clocks at 125mhz and others at 62.5mhz
130 // so that it averages out to the desired frequency of 100mhz. The 125mhz clock cycles
131 // violate the maximum from the data sheet.
132 cfg.clock_divider = FixedU32::from_bits(0x0200);
133 }
134
135 sm.set_config(&cfg);
136
137 sm.set_pin_dirs(Direction::Out, &[&pin_clk, &pin_io]);
138 sm.set_pins(Level::Low, &[&pin_clk, &pin_io]);
139
140 Self {
141 cs,
142 sm,
143 irq,
144 dma: dma.into_ref(),
145 wrap_target: relocated.wrap().target,
146 }
147 }
148
149 pub async fn write(&mut self, write: &[u32]) -> u32 {
150 self.sm.set_enable(false);
151 let write_bits = write.len() * 32 - 1;
152 let read_bits = 31;
153
154 #[cfg(feature = "defmt")]
155 defmt::trace!("write={} read={}", write_bits, read_bits);
156
157 unsafe {
158 pio_instr_util::set_x(&mut self.sm, write_bits as u32);
159 pio_instr_util::set_y(&mut self.sm, read_bits as u32);
160 pio_instr_util::set_pindir(&mut self.sm, 0b1);
161 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target);
162 }
163
164 self.sm.set_enable(true);
165
166 self.sm.tx().dma_push(self.dma.reborrow(), write).await;
167
168 let mut status = 0;
169 self.sm
170 .rx()
171 .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status))
172 .await;
173 status
174 }
175
176 pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) -> u32 {
177 self.sm.set_enable(false);
178 let write_bits = 31;
179 let read_bits = read.len() * 32 + 32 - 1;
180
181 #[cfg(feature = "defmt")]
182 defmt::trace!("write={} read={}", write_bits, read_bits);
183
184 unsafe {
185 pio_instr_util::set_y(&mut self.sm, read_bits as u32);
186 pio_instr_util::set_x(&mut self.sm, write_bits as u32);
187 pio_instr_util::set_pindir(&mut self.sm, 0b1);
188 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target);
189 }
190
191 // self.cs.set_low();
192 self.sm.set_enable(true);
193
194 self.sm.tx().dma_push(self.dma.reborrow(), slice::from_ref(&cmd)).await;
195 self.sm.rx().dma_pull(self.dma.reborrow(), read).await;
196
197 let mut status = 0;
198 self.sm
199 .rx()
200 .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status))
201 .await;
202 status
203 }
204}
205
206impl<'d, CS, PIO, const SM: usize, DMA> SpiBusCyw43 for PioSpi<'d, CS, PIO, SM, DMA>
207where
208 CS: Pin,
209 PIO: Instance,
210 DMA: Channel,
211{
212 async fn cmd_write(&mut self, write: &[u32]) -> u32 {
213 self.cs.set_low();
214 let status = self.write(write).await;
215 self.cs.set_high();
216 status
217 }
218
219 async fn cmd_read(&mut self, write: u32, read: &mut [u32]) -> u32 {
220 self.cs.set_low();
221 let status = self.cmd_read(write, read).await;
222 self.cs.set_high();
223 status
224 }
225
226 async fn wait_for_event(&mut self) {
227 self.irq.wait().await;
228 }
229}
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
new file mode 100644
index 000000000..2bb2b8d93
--- /dev/null
+++ b/cyw43/Cargo.toml
@@ -0,0 +1,40 @@
1[package]
2name = "cyw43"
3version = "0.1.0"
4edition = "2021"
5
6[features]
7defmt = ["dep:defmt"]
8log = ["dep:log"]
9
10# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`.
11firmware-logs = []
12
13[dependencies]
14embassy-time = { version = "0.1.0" }
15embassy-sync = { version = "0.2.0" }
16embassy-futures = { version = "0.1.0" }
17embassy-net-driver-channel = { version = "0.1.0" }
18atomic-polyfill = "0.1.5"
19
20defmt = { version = "0.3", optional = true }
21log = { version = "0.4.17", optional = true }
22
23cortex-m = "0.7.6"
24cortex-m-rt = "0.7.0"
25futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
26
27embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" }
28num_enum = { version = "0.5.7", default-features = false }
29
30[patch.crates-io]
31embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
32embassy-futures = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
33embassy-sync = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
34embassy-net-driver-channel = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
35embassy-rp = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
36
37[workspace]
38members = ["cyw43-pio"]
39default-members = ["cyw43-pio", "."]
40exclude = ["examples"] \ No newline at end of file
diff --git a/cyw43/README.md b/cyw43/README.md
new file mode 100644
index 000000000..defea489f
--- /dev/null
+++ b/cyw43/README.md
@@ -0,0 +1,57 @@
1# cyw43
2
3WIP driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver).
4
5## Current status
6
7Working:
8
9- Station mode (joining an AP).
10- AP mode (creating an AP)
11- Scanning
12- Sending and receiving Ethernet frames.
13- Using the default MAC address.
14- [`embassy-net`](https://embassy.dev) integration.
15- RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W.
16- Using IRQ for device events
17- GPIO support (for LED on the Pico W)
18
19TODO:
20
21- Setting a custom MAC address.
22- Bus sleep (unclear what the benefit is. Is it needed for IRQs? or is it just power consumption optimization?)
23
24## Running the examples
25
26- `cargo install probe-rs-cli`
27- `cd examples/rpi-pico-w`
28### Example 1: Scan the wifi stations
29- `cargo run --release --bin wifi_scan`
30### Example 2: Create an access point (IP and credentials in the code)
31- `cargo run --release --bin tcp_server_ap`
32### Example 3: Connect to an existing network and create a server
33- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release`
34
35After a few seconds, you should see that DHCP picks up an IP address like this
36```
3711.944489 DEBUG Acquired IP configuration:
3811.944517 DEBUG IP address: 192.168.0.250/24
3911.944620 DEBUG Default gateway: 192.168.0.33
4011.944722 DEBUG DNS server 0: 192.168.0.33
41```
42This example implements a TCP echo server on port 1234. You can try connecting to it with:
43```
44nc 192.168.0.250 1234
45```
46Send it some data, you should see it echoed back and printed in the firmware's logs.
47
48## License
49
50This work is licensed under either of
51
52- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
53 <http://www.apache.org/licenses/LICENSE-2.0>)
54- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
55
56at your option.
57
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}
diff --git a/examples/rpi-pico-w/.cargo/config.toml b/examples/rpi-pico-w/.cargo/config.toml
new file mode 100644
index 000000000..f1ed8af96
--- /dev/null
+++ b/examples/rpi-pico-w/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs-cli run --chip RP2040"
3
4[build]
5target = "thumbv6m-none-eabi"
6
7[env]
8DEFMT_LOG = "debug"
diff --git a/examples/rpi-pico-w/Cargo.lock b/examples/rpi-pico-w/Cargo.lock
new file mode 100644
index 000000000..16095835b
--- /dev/null
+++ b/examples/rpi-pico-w/Cargo.lock
@@ -0,0 +1,1707 @@
1# This file is automatically @generated by Cargo.
2# It is not intended for manual editing.
3version = 3
4
5[[package]]
6name = "aho-corasick"
7version = "1.0.1"
8source = "registry+https://github.com/rust-lang/crates.io-index"
9checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
10dependencies = [
11 "memchr",
12]
13
14[[package]]
15name = "arrayvec"
16version = "0.7.2"
17source = "registry+https://github.com/rust-lang/crates.io-index"
18checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
19
20[[package]]
21name = "as-slice"
22version = "0.1.5"
23source = "registry+https://github.com/rust-lang/crates.io-index"
24checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0"
25dependencies = [
26 "generic-array 0.12.4",
27 "generic-array 0.13.3",
28 "generic-array 0.14.7",
29 "stable_deref_trait",
30]
31
32[[package]]
33name = "as-slice"
34version = "0.2.1"
35source = "registry+https://github.com/rust-lang/crates.io-index"
36checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
37dependencies = [
38 "stable_deref_trait",
39]
40
41[[package]]
42name = "ascii-canvas"
43version = "3.0.0"
44source = "registry+https://github.com/rust-lang/crates.io-index"
45checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
46dependencies = [
47 "term",
48]
49
50[[package]]
51name = "atomic-polyfill"
52version = "0.1.11"
53source = "registry+https://github.com/rust-lang/crates.io-index"
54checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28"
55dependencies = [
56 "critical-section 1.1.1",
57]
58
59[[package]]
60name = "atomic-polyfill"
61version = "1.0.2"
62source = "registry+https://github.com/rust-lang/crates.io-index"
63checksum = "c314e70d181aa6053b26e3f7fbf86d1dfff84f816a6175b967666b3506ef7289"
64dependencies = [
65 "critical-section 1.1.1",
66]
67
68[[package]]
69name = "atomic-pool"
70version = "1.0.1"
71source = "registry+https://github.com/rust-lang/crates.io-index"
72checksum = "58c5fc22e05ec2884db458bf307dc7b278c9428888d2b6e6fad9c0ae7804f5f6"
73dependencies = [
74 "as-slice 0.1.5",
75 "as-slice 0.2.1",
76 "atomic-polyfill 1.0.2",
77 "stable_deref_trait",
78]
79
80[[package]]
81name = "autocfg"
82version = "1.1.0"
83source = "registry+https://github.com/rust-lang/crates.io-index"
84checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
85
86[[package]]
87name = "az"
88version = "1.2.1"
89source = "registry+https://github.com/rust-lang/crates.io-index"
90checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
91
92[[package]]
93name = "bare-metal"
94version = "0.2.5"
95source = "registry+https://github.com/rust-lang/crates.io-index"
96checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
97dependencies = [
98 "rustc_version 0.2.3",
99]
100
101[[package]]
102name = "bare-metal"
103version = "1.0.0"
104source = "registry+https://github.com/rust-lang/crates.io-index"
105checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
106
107[[package]]
108name = "bit-set"
109version = "0.5.3"
110source = "registry+https://github.com/rust-lang/crates.io-index"
111checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
112dependencies = [
113 "bit-vec",
114]
115
116[[package]]
117name = "bit-vec"
118version = "0.6.3"
119source = "registry+https://github.com/rust-lang/crates.io-index"
120checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
121
122[[package]]
123name = "bitfield"
124version = "0.13.2"
125source = "registry+https://github.com/rust-lang/crates.io-index"
126checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
127
128[[package]]
129name = "bitflags"
130version = "1.3.2"
131source = "registry+https://github.com/rust-lang/crates.io-index"
132checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
133
134[[package]]
135name = "bytemuck"
136version = "1.13.1"
137source = "registry+https://github.com/rust-lang/crates.io-index"
138checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
139
140[[package]]
141name = "byteorder"
142version = "1.4.3"
143source = "registry+https://github.com/rust-lang/crates.io-index"
144checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
145
146[[package]]
147name = "cc"
148version = "1.0.79"
149source = "registry+https://github.com/rust-lang/crates.io-index"
150checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
151
152[[package]]
153name = "cfg-if"
154version = "1.0.0"
155source = "registry+https://github.com/rust-lang/crates.io-index"
156checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
157
158[[package]]
159name = "codespan-reporting"
160version = "0.11.1"
161source = "registry+https://github.com/rust-lang/crates.io-index"
162checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
163dependencies = [
164 "termcolor",
165 "unicode-width",
166]
167
168[[package]]
169name = "cortex-m"
170version = "0.7.7"
171source = "registry+https://github.com/rust-lang/crates.io-index"
172checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
173dependencies = [
174 "bare-metal 0.2.5",
175 "bitfield",
176 "critical-section 1.1.1",
177 "embedded-hal 0.2.7",
178 "volatile-register",
179]
180
181[[package]]
182name = "cortex-m-rt"
183version = "0.7.3"
184source = "registry+https://github.com/rust-lang/crates.io-index"
185checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1"
186dependencies = [
187 "cortex-m-rt-macros",
188]
189
190[[package]]
191name = "cortex-m-rt-macros"
192version = "0.7.0"
193source = "registry+https://github.com/rust-lang/crates.io-index"
194checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
195dependencies = [
196 "proc-macro2",
197 "quote",
198 "syn 1.0.109",
199]
200
201[[package]]
202name = "crc-any"
203version = "2.4.3"
204source = "registry+https://github.com/rust-lang/crates.io-index"
205checksum = "774646b687f63643eb0f4bf13dc263cb581c8c9e57973b6ddf78bda3994d88df"
206dependencies = [
207 "debug-helper",
208]
209
210[[package]]
211name = "critical-section"
212version = "0.2.8"
213source = "registry+https://github.com/rust-lang/crates.io-index"
214checksum = "c1706d332edc22aef4d9f23a6bb1c92360a403013c291af51247a737472dcae6"
215dependencies = [
216 "bare-metal 1.0.0",
217 "critical-section 1.1.1",
218]
219
220[[package]]
221name = "critical-section"
222version = "1.1.1"
223source = "registry+https://github.com/rust-lang/crates.io-index"
224checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52"
225
226[[package]]
227name = "crunchy"
228version = "0.2.2"
229source = "registry+https://github.com/rust-lang/crates.io-index"
230checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
231
232[[package]]
233name = "cyw43"
234version = "0.1.0"
235dependencies = [
236 "atomic-polyfill 0.1.11",
237 "cortex-m",
238 "cortex-m-rt",
239 "defmt",
240 "embassy-futures",
241 "embassy-net-driver-channel",
242 "embassy-sync",
243 "embassy-time",
244 "embedded-hal 1.0.0-alpha.10",
245 "futures",
246 "num_enum",
247]
248
249[[package]]
250name = "cyw43-example-rpi-pico-w"
251version = "0.1.0"
252dependencies = [
253 "atomic-polyfill 0.1.11",
254 "cortex-m",
255 "cortex-m-rt",
256 "cyw43",
257 "cyw43-pio",
258 "defmt",
259 "defmt-rtt",
260 "embassy-executor",
261 "embassy-net",
262 "embassy-rp",
263 "embassy-time",
264 "embedded-io",
265 "futures",
266 "heapless",
267 "panic-probe",
268 "static_cell",
269]
270
271[[package]]
272name = "cyw43-pio"
273version = "0.1.0"
274dependencies = [
275 "cyw43",
276 "defmt",
277 "embassy-rp",
278 "fixed",
279 "pio",
280 "pio-proc",
281]
282
283[[package]]
284name = "darling"
285version = "0.13.4"
286source = "registry+https://github.com/rust-lang/crates.io-index"
287checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
288dependencies = [
289 "darling_core",
290 "darling_macro",
291]
292
293[[package]]
294name = "darling_core"
295version = "0.13.4"
296source = "registry+https://github.com/rust-lang/crates.io-index"
297checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
298dependencies = [
299 "fnv",
300 "ident_case",
301 "proc-macro2",
302 "quote",
303 "strsim",
304 "syn 1.0.109",
305]
306
307[[package]]
308name = "darling_macro"
309version = "0.13.4"
310source = "registry+https://github.com/rust-lang/crates.io-index"
311checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
312dependencies = [
313 "darling_core",
314 "quote",
315 "syn 1.0.109",
316]
317
318[[package]]
319name = "debug-helper"
320version = "0.3.13"
321source = "registry+https://github.com/rust-lang/crates.io-index"
322checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e"
323
324[[package]]
325name = "defmt"
326version = "0.3.4"
327source = "registry+https://github.com/rust-lang/crates.io-index"
328checksum = "956673bd3cb347512bf988d1e8d89ac9a82b64f6eec54d3c01c3529dac019882"
329dependencies = [
330 "bitflags",
331 "defmt-macros",
332]
333
334[[package]]
335name = "defmt-macros"
336version = "0.3.5"
337source = "registry+https://github.com/rust-lang/crates.io-index"
338checksum = "b4abc4821bd84d3d8f49945ddb24d029be9385ed9b77c99bf2f6296847a6a9f0"
339dependencies = [
340 "defmt-parser",
341 "proc-macro-error",
342 "proc-macro2",
343 "quote",
344 "syn 1.0.109",
345]
346
347[[package]]
348name = "defmt-parser"
349version = "0.3.3"
350source = "registry+https://github.com/rust-lang/crates.io-index"
351checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0"
352dependencies = [
353 "thiserror",
354]
355
356[[package]]
357name = "defmt-rtt"
358version = "0.3.2"
359source = "registry+https://github.com/rust-lang/crates.io-index"
360checksum = "1d2cbbbd58847d508d97629b32cd9730a2d28532f71e219714614406029f18b1"
361dependencies = [
362 "critical-section 0.2.8",
363 "defmt",
364]
365
366[[package]]
367name = "diff"
368version = "0.1.13"
369source = "registry+https://github.com/rust-lang/crates.io-index"
370checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
371
372[[package]]
373name = "dirs-next"
374version = "2.0.0"
375source = "registry+https://github.com/rust-lang/crates.io-index"
376checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
377dependencies = [
378 "cfg-if",
379 "dirs-sys-next",
380]
381
382[[package]]
383name = "dirs-sys-next"
384version = "0.1.2"
385source = "registry+https://github.com/rust-lang/crates.io-index"
386checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
387dependencies = [
388 "libc",
389 "redox_users",
390 "winapi",
391]
392
393[[package]]
394name = "either"
395version = "1.8.1"
396source = "registry+https://github.com/rust-lang/crates.io-index"
397checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
398
399[[package]]
400name = "embassy-cortex-m"
401version = "0.1.0"
402source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
403dependencies = [
404 "atomic-polyfill 1.0.2",
405 "cfg-if",
406 "cortex-m",
407 "critical-section 1.1.1",
408 "embassy-executor",
409 "embassy-hal-common",
410 "embassy-macros",
411 "embassy-sync",
412]
413
414[[package]]
415name = "embassy-embedded-hal"
416version = "0.1.0"
417source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
418dependencies = [
419 "embassy-sync",
420 "embedded-hal 0.2.7",
421 "embedded-hal 1.0.0-alpha.10",
422 "embedded-hal-async",
423 "embedded-storage",
424 "embedded-storage-async",
425 "nb 1.1.0",
426]
427
428[[package]]
429name = "embassy-executor"
430version = "0.2.0"
431source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
432dependencies = [
433 "atomic-polyfill 1.0.2",
434 "cortex-m",
435 "critical-section 1.1.1",
436 "defmt",
437 "embassy-macros",
438 "embassy-time",
439 "futures-util",
440 "static_cell",
441]
442
443[[package]]
444name = "embassy-futures"
445version = "0.1.0"
446source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
447
448[[package]]
449name = "embassy-hal-common"
450version = "0.1.0"
451source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
452dependencies = [
453 "defmt",
454 "num-traits",
455]
456
457[[package]]
458name = "embassy-macros"
459version = "0.2.0"
460source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
461dependencies = [
462 "darling",
463 "proc-macro2",
464 "quote",
465 "syn 1.0.109",
466]
467
468[[package]]
469name = "embassy-net"
470version = "0.1.0"
471source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
472dependencies = [
473 "as-slice 0.2.1",
474 "atomic-polyfill 1.0.2",
475 "atomic-pool",
476 "defmt",
477 "embassy-hal-common",
478 "embassy-net-driver",
479 "embassy-sync",
480 "embassy-time",
481 "embedded-io",
482 "embedded-nal-async",
483 "futures",
484 "generic-array 0.14.7",
485 "heapless",
486 "managed",
487 "smoltcp",
488 "stable_deref_trait",
489]
490
491[[package]]
492name = "embassy-net-driver"
493version = "0.1.0"
494source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
495dependencies = [
496 "defmt",
497]
498
499[[package]]
500name = "embassy-net-driver-channel"
501version = "0.1.0"
502source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
503dependencies = [
504 "embassy-futures",
505 "embassy-net-driver",
506 "embassy-sync",
507]
508
509[[package]]
510name = "embassy-rp"
511version = "0.1.0"
512source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
513dependencies = [
514 "atomic-polyfill 1.0.2",
515 "cfg-if",
516 "cortex-m",
517 "cortex-m-rt",
518 "critical-section 1.1.1",
519 "defmt",
520 "embassy-cortex-m",
521 "embassy-embedded-hal",
522 "embassy-executor",
523 "embassy-futures",
524 "embassy-hal-common",
525 "embassy-sync",
526 "embassy-time",
527 "embassy-usb-driver",
528 "embedded-hal 0.2.7",
529 "embedded-hal 1.0.0-alpha.10",
530 "embedded-hal-async",
531 "embedded-hal-nb",
532 "embedded-io",
533 "embedded-storage",
534 "fixed",
535 "futures",
536 "nb 1.1.0",
537 "paste",
538 "pio",
539 "pio-proc",
540 "rand_core",
541 "rp-pac",
542 "rp2040-boot2",
543]
544
545[[package]]
546name = "embassy-sync"
547version = "0.2.0"
548source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
549dependencies = [
550 "cfg-if",
551 "critical-section 1.1.1",
552 "embedded-io",
553 "futures-util",
554 "heapless",
555]
556
557[[package]]
558name = "embassy-time"
559version = "0.1.1"
560source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
561dependencies = [
562 "atomic-polyfill 1.0.2",
563 "cfg-if",
564 "critical-section 1.1.1",
565 "defmt",
566 "embedded-hal 0.2.7",
567 "futures-util",
568 "heapless",
569]
570
571[[package]]
572name = "embassy-usb-driver"
573version = "0.1.0"
574source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7"
575dependencies = [
576 "defmt",
577]
578
579[[package]]
580name = "embedded-hal"
581version = "0.2.7"
582source = "registry+https://github.com/rust-lang/crates.io-index"
583checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
584dependencies = [
585 "nb 0.1.3",
586 "void",
587]
588
589[[package]]
590name = "embedded-hal"
591version = "1.0.0-alpha.10"
592source = "registry+https://github.com/rust-lang/crates.io-index"
593checksum = "f65c4d073f5d91c66e629b216818a4c9747eeda0debedf2deda9a0a947e4e93b"
594
595[[package]]
596name = "embedded-hal-async"
597version = "0.2.0-alpha.1"
598source = "registry+https://github.com/rust-lang/crates.io-index"
599checksum = "8042370aa7af48de36d5312cda14c18ed8ca6b7ce64f5a07832fedc9dc83063f"
600dependencies = [
601 "embedded-hal 1.0.0-alpha.10",
602]
603
604[[package]]
605name = "embedded-hal-nb"
606version = "1.0.0-alpha.2"
607source = "registry+https://github.com/rust-lang/crates.io-index"
608checksum = "1465fffd56a95bbc105c17965bca1c1d5815027b1cc6bb183bc05d04563d065c"
609dependencies = [
610 "embedded-hal 1.0.0-alpha.10",
611 "nb 1.1.0",
612]
613
614[[package]]
615name = "embedded-io"
616version = "0.4.0"
617source = "registry+https://github.com/rust-lang/crates.io-index"
618checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
619dependencies = [
620 "defmt",
621]
622
623[[package]]
624name = "embedded-nal"
625version = "0.6.0"
626source = "registry+https://github.com/rust-lang/crates.io-index"
627checksum = "db9efecb57ab54fa918730f2874d7d37647169c50fa1357fecb81abee840b113"
628dependencies = [
629 "heapless",
630 "nb 1.1.0",
631 "no-std-net 0.5.0",
632]
633
634[[package]]
635name = "embedded-nal-async"
636version = "0.4.0"
637source = "registry+https://github.com/rust-lang/crates.io-index"
638checksum = "27ce84f518ca912777ec143db235f4d615e3bf8d4e46d507d6ef12daf5b1df98"
639dependencies = [
640 "embedded-io",
641 "embedded-nal",
642 "heapless",
643 "no-std-net 0.6.0",
644]
645
646[[package]]
647name = "embedded-storage"
648version = "0.3.0"
649source = "registry+https://github.com/rust-lang/crates.io-index"
650checksum = "156d7a2fdd98ebbf9ae579cbceca3058cff946e13f8e17b90e3511db0508c723"
651
652[[package]]
653name = "embedded-storage-async"
654version = "0.4.0"
655source = "registry+https://github.com/rust-lang/crates.io-index"
656checksum = "052997a894670d0cde873faa7405bc98e2fd29f569d2acd568561bc1c396b35a"
657dependencies = [
658 "embedded-storage",
659]
660
661[[package]]
662name = "ena"
663version = "0.14.2"
664source = "registry+https://github.com/rust-lang/crates.io-index"
665checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
666dependencies = [
667 "log",
668]
669
670[[package]]
671name = "errno"
672version = "0.3.1"
673source = "registry+https://github.com/rust-lang/crates.io-index"
674checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
675dependencies = [
676 "errno-dragonfly",
677 "libc",
678 "windows-sys 0.48.0",
679]
680
681[[package]]
682name = "errno-dragonfly"
683version = "0.1.2"
684source = "registry+https://github.com/rust-lang/crates.io-index"
685checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
686dependencies = [
687 "cc",
688 "libc",
689]
690
691[[package]]
692name = "fixed"
693version = "1.23.1"
694source = "registry+https://github.com/rust-lang/crates.io-index"
695checksum = "79386fdcec5e0fde91b1a6a5bcd89677d1f9304f7f986b154a1b9109038854d9"
696dependencies = [
697 "az",
698 "bytemuck",
699 "half",
700 "typenum",
701]
702
703[[package]]
704name = "fixedbitset"
705version = "0.4.2"
706source = "registry+https://github.com/rust-lang/crates.io-index"
707checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
708
709[[package]]
710name = "fnv"
711version = "1.0.7"
712source = "registry+https://github.com/rust-lang/crates.io-index"
713checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
714
715[[package]]
716name = "futures"
717version = "0.3.28"
718source = "registry+https://github.com/rust-lang/crates.io-index"
719checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
720dependencies = [
721 "futures-channel",
722 "futures-core",
723 "futures-io",
724 "futures-sink",
725 "futures-task",
726 "futures-util",
727]
728
729[[package]]
730name = "futures-channel"
731version = "0.3.28"
732source = "registry+https://github.com/rust-lang/crates.io-index"
733checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
734dependencies = [
735 "futures-core",
736 "futures-sink",
737]
738
739[[package]]
740name = "futures-core"
741version = "0.3.28"
742source = "registry+https://github.com/rust-lang/crates.io-index"
743checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
744
745[[package]]
746name = "futures-io"
747version = "0.3.28"
748source = "registry+https://github.com/rust-lang/crates.io-index"
749checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
750
751[[package]]
752name = "futures-macro"
753version = "0.3.28"
754source = "registry+https://github.com/rust-lang/crates.io-index"
755checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
756dependencies = [
757 "proc-macro2",
758 "quote",
759 "syn 2.0.18",
760]
761
762[[package]]
763name = "futures-sink"
764version = "0.3.28"
765source = "registry+https://github.com/rust-lang/crates.io-index"
766checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
767
768[[package]]
769name = "futures-task"
770version = "0.3.28"
771source = "registry+https://github.com/rust-lang/crates.io-index"
772checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
773
774[[package]]
775name = "futures-util"
776version = "0.3.28"
777source = "registry+https://github.com/rust-lang/crates.io-index"
778checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
779dependencies = [
780 "futures-core",
781 "futures-macro",
782 "futures-sink",
783 "futures-task",
784 "pin-project-lite",
785 "pin-utils",
786]
787
788[[package]]
789name = "generic-array"
790version = "0.12.4"
791source = "registry+https://github.com/rust-lang/crates.io-index"
792checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
793dependencies = [
794 "typenum",
795]
796
797[[package]]
798name = "generic-array"
799version = "0.13.3"
800source = "registry+https://github.com/rust-lang/crates.io-index"
801checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309"
802dependencies = [
803 "typenum",
804]
805
806[[package]]
807name = "generic-array"
808version = "0.14.7"
809source = "registry+https://github.com/rust-lang/crates.io-index"
810checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
811dependencies = [
812 "typenum",
813 "version_check",
814]
815
816[[package]]
817name = "getrandom"
818version = "0.2.9"
819source = "registry+https://github.com/rust-lang/crates.io-index"
820checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
821dependencies = [
822 "cfg-if",
823 "libc",
824 "wasi",
825]
826
827[[package]]
828name = "half"
829version = "2.2.1"
830source = "registry+https://github.com/rust-lang/crates.io-index"
831checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0"
832dependencies = [
833 "crunchy",
834]
835
836[[package]]
837name = "hash32"
838version = "0.2.1"
839source = "registry+https://github.com/rust-lang/crates.io-index"
840checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
841dependencies = [
842 "byteorder",
843]
844
845[[package]]
846name = "hashbrown"
847version = "0.12.3"
848source = "registry+https://github.com/rust-lang/crates.io-index"
849checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
850
851[[package]]
852name = "heapless"
853version = "0.7.16"
854source = "registry+https://github.com/rust-lang/crates.io-index"
855checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743"
856dependencies = [
857 "atomic-polyfill 0.1.11",
858 "defmt",
859 "hash32",
860 "rustc_version 0.4.0",
861 "spin",
862 "stable_deref_trait",
863]
864
865[[package]]
866name = "hermit-abi"
867version = "0.3.1"
868source = "registry+https://github.com/rust-lang/crates.io-index"
869checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
870
871[[package]]
872name = "ident_case"
873version = "1.0.1"
874source = "registry+https://github.com/rust-lang/crates.io-index"
875checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
876
877[[package]]
878name = "indexmap"
879version = "1.9.3"
880source = "registry+https://github.com/rust-lang/crates.io-index"
881checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
882dependencies = [
883 "autocfg",
884 "hashbrown",
885]
886
887[[package]]
888name = "io-lifetimes"
889version = "1.0.11"
890source = "registry+https://github.com/rust-lang/crates.io-index"
891checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
892dependencies = [
893 "hermit-abi",
894 "libc",
895 "windows-sys 0.48.0",
896]
897
898[[package]]
899name = "is-terminal"
900version = "0.4.7"
901source = "registry+https://github.com/rust-lang/crates.io-index"
902checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
903dependencies = [
904 "hermit-abi",
905 "io-lifetimes",
906 "rustix",
907 "windows-sys 0.48.0",
908]
909
910[[package]]
911name = "itertools"
912version = "0.10.5"
913source = "registry+https://github.com/rust-lang/crates.io-index"
914checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
915dependencies = [
916 "either",
917]
918
919[[package]]
920name = "lalrpop"
921version = "0.19.12"
922source = "registry+https://github.com/rust-lang/crates.io-index"
923checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b"
924dependencies = [
925 "ascii-canvas",
926 "bit-set",
927 "diff",
928 "ena",
929 "is-terminal",
930 "itertools",
931 "lalrpop-util",
932 "petgraph",
933 "regex",
934 "regex-syntax 0.6.29",
935 "string_cache",
936 "term",
937 "tiny-keccak",
938 "unicode-xid",
939]
940
941[[package]]
942name = "lalrpop-util"
943version = "0.19.12"
944source = "registry+https://github.com/rust-lang/crates.io-index"
945checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed"
946dependencies = [
947 "regex",
948]
949
950[[package]]
951name = "libc"
952version = "0.2.144"
953source = "registry+https://github.com/rust-lang/crates.io-index"
954checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
955
956[[package]]
957name = "linux-raw-sys"
958version = "0.3.8"
959source = "registry+https://github.com/rust-lang/crates.io-index"
960checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
961
962[[package]]
963name = "lock_api"
964version = "0.4.9"
965source = "registry+https://github.com/rust-lang/crates.io-index"
966checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
967dependencies = [
968 "autocfg",
969 "scopeguard",
970]
971
972[[package]]
973name = "log"
974version = "0.4.18"
975source = "registry+https://github.com/rust-lang/crates.io-index"
976checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
977
978[[package]]
979name = "managed"
980version = "0.8.0"
981source = "registry+https://github.com/rust-lang/crates.io-index"
982checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
983
984[[package]]
985name = "memchr"
986version = "2.5.0"
987source = "registry+https://github.com/rust-lang/crates.io-index"
988checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
989
990[[package]]
991name = "nb"
992version = "0.1.3"
993source = "registry+https://github.com/rust-lang/crates.io-index"
994checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
995dependencies = [
996 "nb 1.1.0",
997]
998
999[[package]]
1000name = "nb"
1001version = "1.1.0"
1002source = "registry+https://github.com/rust-lang/crates.io-index"
1003checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
1004
1005[[package]]
1006name = "new_debug_unreachable"
1007version = "1.0.4"
1008source = "registry+https://github.com/rust-lang/crates.io-index"
1009checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
1010
1011[[package]]
1012name = "no-std-net"
1013version = "0.5.0"
1014source = "registry+https://github.com/rust-lang/crates.io-index"
1015checksum = "1bcece43b12349917e096cddfa66107277f123e6c96a5aea78711dc601a47152"
1016
1017[[package]]
1018name = "no-std-net"
1019version = "0.6.0"
1020source = "registry+https://github.com/rust-lang/crates.io-index"
1021checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65"
1022
1023[[package]]
1024name = "num-traits"
1025version = "0.2.15"
1026source = "registry+https://github.com/rust-lang/crates.io-index"
1027checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
1028dependencies = [
1029 "autocfg",
1030]
1031
1032[[package]]
1033name = "num_enum"
1034version = "0.5.11"
1035source = "registry+https://github.com/rust-lang/crates.io-index"
1036checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
1037dependencies = [
1038 "num_enum_derive",
1039]
1040
1041[[package]]
1042name = "num_enum_derive"
1043version = "0.5.11"
1044source = "registry+https://github.com/rust-lang/crates.io-index"
1045checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
1046dependencies = [
1047 "proc-macro2",
1048 "quote",
1049 "syn 1.0.109",
1050]
1051
1052[[package]]
1053name = "once_cell"
1054version = "1.17.2"
1055source = "registry+https://github.com/rust-lang/crates.io-index"
1056checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b"
1057
1058[[package]]
1059name = "panic-probe"
1060version = "0.3.1"
1061source = "registry+https://github.com/rust-lang/crates.io-index"
1062checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9"
1063dependencies = [
1064 "cortex-m",
1065 "defmt",
1066]
1067
1068[[package]]
1069name = "parking_lot"
1070version = "0.12.1"
1071source = "registry+https://github.com/rust-lang/crates.io-index"
1072checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
1073dependencies = [
1074 "lock_api",
1075 "parking_lot_core",
1076]
1077
1078[[package]]
1079name = "parking_lot_core"
1080version = "0.9.7"
1081source = "registry+https://github.com/rust-lang/crates.io-index"
1082checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
1083dependencies = [
1084 "cfg-if",
1085 "libc",
1086 "redox_syscall",
1087 "smallvec",
1088 "windows-sys 0.45.0",
1089]
1090
1091[[package]]
1092name = "paste"
1093version = "1.0.12"
1094source = "registry+https://github.com/rust-lang/crates.io-index"
1095checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
1096
1097[[package]]
1098name = "petgraph"
1099version = "0.6.3"
1100source = "registry+https://github.com/rust-lang/crates.io-index"
1101checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
1102dependencies = [
1103 "fixedbitset",
1104 "indexmap",
1105]
1106
1107[[package]]
1108name = "phf_shared"
1109version = "0.10.0"
1110source = "registry+https://github.com/rust-lang/crates.io-index"
1111checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
1112dependencies = [
1113 "siphasher",
1114]
1115
1116[[package]]
1117name = "pin-project-lite"
1118version = "0.2.9"
1119source = "registry+https://github.com/rust-lang/crates.io-index"
1120checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
1121
1122[[package]]
1123name = "pin-utils"
1124version = "0.1.0"
1125source = "registry+https://github.com/rust-lang/crates.io-index"
1126checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
1127
1128[[package]]
1129name = "pio"
1130version = "0.2.1"
1131source = "registry+https://github.com/rust-lang/crates.io-index"
1132checksum = "76e09694b50f89f302ed531c1f2a7569f0be5867aee4ab4f8f729bbeec0078e3"
1133dependencies = [
1134 "arrayvec",
1135 "num_enum",
1136 "paste",
1137]
1138
1139[[package]]
1140name = "pio-parser"
1141version = "0.2.2"
1142source = "registry+https://github.com/rust-lang/crates.io-index"
1143checksum = "77532c2b8279aef98dfc7207ef15298a5a3d6b6cc76ccc8b65913d69f3a8dd6b"
1144dependencies = [
1145 "lalrpop",
1146 "lalrpop-util",
1147 "pio",
1148 "regex-syntax 0.6.29",
1149]
1150
1151[[package]]
1152name = "pio-proc"
1153version = "0.2.2"
1154source = "registry+https://github.com/rust-lang/crates.io-index"
1155checksum = "6b04dc870fb3a4fd8b3e4ca8c61b53bc8ac4eb78b66805d2b3c2e5c4829e0d7a"
1156dependencies = [
1157 "codespan-reporting",
1158 "lalrpop-util",
1159 "pio",
1160 "pio-parser",
1161 "proc-macro-error",
1162 "proc-macro2",
1163 "quote",
1164 "regex-syntax 0.6.29",
1165 "syn 1.0.109",
1166]
1167
1168[[package]]
1169name = "precomputed-hash"
1170version = "0.1.1"
1171source = "registry+https://github.com/rust-lang/crates.io-index"
1172checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
1173
1174[[package]]
1175name = "proc-macro-error"
1176version = "1.0.4"
1177source = "registry+https://github.com/rust-lang/crates.io-index"
1178checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
1179dependencies = [
1180 "proc-macro-error-attr",
1181 "proc-macro2",
1182 "quote",
1183 "syn 1.0.109",
1184 "version_check",
1185]
1186
1187[[package]]
1188name = "proc-macro-error-attr"
1189version = "1.0.4"
1190source = "registry+https://github.com/rust-lang/crates.io-index"
1191checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
1192dependencies = [
1193 "proc-macro2",
1194 "quote",
1195 "version_check",
1196]
1197
1198[[package]]
1199name = "proc-macro2"
1200version = "1.0.59"
1201source = "registry+https://github.com/rust-lang/crates.io-index"
1202checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
1203dependencies = [
1204 "unicode-ident",
1205]
1206
1207[[package]]
1208name = "quote"
1209version = "1.0.28"
1210source = "registry+https://github.com/rust-lang/crates.io-index"
1211checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
1212dependencies = [
1213 "proc-macro2",
1214]
1215
1216[[package]]
1217name = "rand_core"
1218version = "0.6.4"
1219source = "registry+https://github.com/rust-lang/crates.io-index"
1220checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
1221
1222[[package]]
1223name = "redox_syscall"
1224version = "0.2.16"
1225source = "registry+https://github.com/rust-lang/crates.io-index"
1226checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
1227dependencies = [
1228 "bitflags",
1229]
1230
1231[[package]]
1232name = "redox_users"
1233version = "0.4.3"
1234source = "registry+https://github.com/rust-lang/crates.io-index"
1235checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
1236dependencies = [
1237 "getrandom",
1238 "redox_syscall",
1239 "thiserror",
1240]
1241
1242[[package]]
1243name = "regex"
1244version = "1.8.3"
1245source = "registry+https://github.com/rust-lang/crates.io-index"
1246checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
1247dependencies = [
1248 "aho-corasick",
1249 "memchr",
1250 "regex-syntax 0.7.2",
1251]
1252
1253[[package]]
1254name = "regex-syntax"
1255version = "0.6.29"
1256source = "registry+https://github.com/rust-lang/crates.io-index"
1257checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
1258
1259[[package]]
1260name = "regex-syntax"
1261version = "0.7.2"
1262source = "registry+https://github.com/rust-lang/crates.io-index"
1263checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
1264
1265[[package]]
1266name = "rp-pac"
1267version = "4.0.0"
1268source = "registry+https://github.com/rust-lang/crates.io-index"
1269checksum = "a76e426cd8377db668fba1fe885028788b126b7cef91059cd478de8b076c2915"
1270dependencies = [
1271 "cortex-m",
1272 "cortex-m-rt",
1273]
1274
1275[[package]]
1276name = "rp2040-boot2"
1277version = "0.3.0"
1278source = "registry+https://github.com/rust-lang/crates.io-index"
1279checksum = "7c92f344f63f950ee36cf4080050e4dce850839b9175da38f9d2ffb69b4dbb21"
1280dependencies = [
1281 "crc-any",
1282]
1283
1284[[package]]
1285name = "rustc_version"
1286version = "0.2.3"
1287source = "registry+https://github.com/rust-lang/crates.io-index"
1288checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
1289dependencies = [
1290 "semver 0.9.0",
1291]
1292
1293[[package]]
1294name = "rustc_version"
1295version = "0.4.0"
1296source = "registry+https://github.com/rust-lang/crates.io-index"
1297checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
1298dependencies = [
1299 "semver 1.0.17",
1300]
1301
1302[[package]]
1303name = "rustix"
1304version = "0.37.19"
1305source = "registry+https://github.com/rust-lang/crates.io-index"
1306checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
1307dependencies = [
1308 "bitflags",
1309 "errno",
1310 "io-lifetimes",
1311 "libc",
1312 "linux-raw-sys",
1313 "windows-sys 0.48.0",
1314]
1315
1316[[package]]
1317name = "rustversion"
1318version = "1.0.12"
1319source = "registry+https://github.com/rust-lang/crates.io-index"
1320checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
1321
1322[[package]]
1323name = "scopeguard"
1324version = "1.1.0"
1325source = "registry+https://github.com/rust-lang/crates.io-index"
1326checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
1327
1328[[package]]
1329name = "semver"
1330version = "0.9.0"
1331source = "registry+https://github.com/rust-lang/crates.io-index"
1332checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
1333dependencies = [
1334 "semver-parser",
1335]
1336
1337[[package]]
1338name = "semver"
1339version = "1.0.17"
1340source = "registry+https://github.com/rust-lang/crates.io-index"
1341checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
1342
1343[[package]]
1344name = "semver-parser"
1345version = "0.7.0"
1346source = "registry+https://github.com/rust-lang/crates.io-index"
1347checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1348
1349[[package]]
1350name = "siphasher"
1351version = "0.3.10"
1352source = "registry+https://github.com/rust-lang/crates.io-index"
1353checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
1354
1355[[package]]
1356name = "smallvec"
1357version = "1.10.0"
1358source = "registry+https://github.com/rust-lang/crates.io-index"
1359checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
1360
1361[[package]]
1362name = "smoltcp"
1363version = "0.9.1"
1364source = "registry+https://github.com/rust-lang/crates.io-index"
1365checksum = "7e9786ac45091b96f946693e05bfa4d8ca93e2d3341237d97a380107a6b38dea"
1366dependencies = [
1367 "bitflags",
1368 "byteorder",
1369 "cfg-if",
1370 "defmt",
1371 "heapless",
1372 "managed",
1373]
1374
1375[[package]]
1376name = "spin"
1377version = "0.9.8"
1378source = "registry+https://github.com/rust-lang/crates.io-index"
1379checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
1380dependencies = [
1381 "lock_api",
1382]
1383
1384[[package]]
1385name = "stable_deref_trait"
1386version = "1.2.0"
1387source = "registry+https://github.com/rust-lang/crates.io-index"
1388checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
1389
1390[[package]]
1391name = "static_cell"
1392version = "1.0.0"
1393source = "registry+https://github.com/rust-lang/crates.io-index"
1394checksum = "e4c37c250d21f53fa7165e76e5401d7e6539c211a8d2cf449e3962956a5cc2ce"
1395dependencies = [
1396 "atomic-polyfill 1.0.2",
1397]
1398
1399[[package]]
1400name = "string_cache"
1401version = "0.8.7"
1402source = "registry+https://github.com/rust-lang/crates.io-index"
1403checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
1404dependencies = [
1405 "new_debug_unreachable",
1406 "once_cell",
1407 "parking_lot",
1408 "phf_shared",
1409 "precomputed-hash",
1410]
1411
1412[[package]]
1413name = "strsim"
1414version = "0.10.0"
1415source = "registry+https://github.com/rust-lang/crates.io-index"
1416checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
1417
1418[[package]]
1419name = "syn"
1420version = "1.0.109"
1421source = "registry+https://github.com/rust-lang/crates.io-index"
1422checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
1423dependencies = [
1424 "proc-macro2",
1425 "quote",
1426 "unicode-ident",
1427]
1428
1429[[package]]
1430name = "syn"
1431version = "2.0.18"
1432source = "registry+https://github.com/rust-lang/crates.io-index"
1433checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
1434dependencies = [
1435 "proc-macro2",
1436 "quote",
1437 "unicode-ident",
1438]
1439
1440[[package]]
1441name = "term"
1442version = "0.7.0"
1443source = "registry+https://github.com/rust-lang/crates.io-index"
1444checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
1445dependencies = [
1446 "dirs-next",
1447 "rustversion",
1448 "winapi",
1449]
1450
1451[[package]]
1452name = "termcolor"
1453version = "1.2.0"
1454source = "registry+https://github.com/rust-lang/crates.io-index"
1455checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
1456dependencies = [
1457 "winapi-util",
1458]
1459
1460[[package]]
1461name = "thiserror"
1462version = "1.0.40"
1463source = "registry+https://github.com/rust-lang/crates.io-index"
1464checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
1465dependencies = [
1466 "thiserror-impl",
1467]
1468
1469[[package]]
1470name = "thiserror-impl"
1471version = "1.0.40"
1472source = "registry+https://github.com/rust-lang/crates.io-index"
1473checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
1474dependencies = [
1475 "proc-macro2",
1476 "quote",
1477 "syn 2.0.18",
1478]
1479
1480[[package]]
1481name = "tiny-keccak"
1482version = "2.0.2"
1483source = "registry+https://github.com/rust-lang/crates.io-index"
1484checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
1485dependencies = [
1486 "crunchy",
1487]
1488
1489[[package]]
1490name = "typenum"
1491version = "1.16.0"
1492source = "registry+https://github.com/rust-lang/crates.io-index"
1493checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
1494
1495[[package]]
1496name = "unicode-ident"
1497version = "1.0.9"
1498source = "registry+https://github.com/rust-lang/crates.io-index"
1499checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
1500
1501[[package]]
1502name = "unicode-width"
1503version = "0.1.10"
1504source = "registry+https://github.com/rust-lang/crates.io-index"
1505checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
1506
1507[[package]]
1508name = "unicode-xid"
1509version = "0.2.4"
1510source = "registry+https://github.com/rust-lang/crates.io-index"
1511checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
1512
1513[[package]]
1514name = "vcell"
1515version = "0.1.3"
1516source = "registry+https://github.com/rust-lang/crates.io-index"
1517checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
1518
1519[[package]]
1520name = "version_check"
1521version = "0.9.4"
1522source = "registry+https://github.com/rust-lang/crates.io-index"
1523checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
1524
1525[[package]]
1526name = "void"
1527version = "1.0.2"
1528source = "registry+https://github.com/rust-lang/crates.io-index"
1529checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
1530
1531[[package]]
1532name = "volatile-register"
1533version = "0.2.1"
1534source = "registry+https://github.com/rust-lang/crates.io-index"
1535checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
1536dependencies = [
1537 "vcell",
1538]
1539
1540[[package]]
1541name = "wasi"
1542version = "0.11.0+wasi-snapshot-preview1"
1543source = "registry+https://github.com/rust-lang/crates.io-index"
1544checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1545
1546[[package]]
1547name = "winapi"
1548version = "0.3.9"
1549source = "registry+https://github.com/rust-lang/crates.io-index"
1550checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1551dependencies = [
1552 "winapi-i686-pc-windows-gnu",
1553 "winapi-x86_64-pc-windows-gnu",
1554]
1555
1556[[package]]
1557name = "winapi-i686-pc-windows-gnu"
1558version = "0.4.0"
1559source = "registry+https://github.com/rust-lang/crates.io-index"
1560checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1561
1562[[package]]
1563name = "winapi-util"
1564version = "0.1.5"
1565source = "registry+https://github.com/rust-lang/crates.io-index"
1566checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1567dependencies = [
1568 "winapi",
1569]
1570
1571[[package]]
1572name = "winapi-x86_64-pc-windows-gnu"
1573version = "0.4.0"
1574source = "registry+https://github.com/rust-lang/crates.io-index"
1575checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1576
1577[[package]]
1578name = "windows-sys"
1579version = "0.45.0"
1580source = "registry+https://github.com/rust-lang/crates.io-index"
1581checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
1582dependencies = [
1583 "windows-targets 0.42.2",
1584]
1585
1586[[package]]
1587name = "windows-sys"
1588version = "0.48.0"
1589source = "registry+https://github.com/rust-lang/crates.io-index"
1590checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
1591dependencies = [
1592 "windows-targets 0.48.0",
1593]
1594
1595[[package]]
1596name = "windows-targets"
1597version = "0.42.2"
1598source = "registry+https://github.com/rust-lang/crates.io-index"
1599checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
1600dependencies = [
1601 "windows_aarch64_gnullvm 0.42.2",
1602 "windows_aarch64_msvc 0.42.2",
1603 "windows_i686_gnu 0.42.2",
1604 "windows_i686_msvc 0.42.2",
1605 "windows_x86_64_gnu 0.42.2",
1606 "windows_x86_64_gnullvm 0.42.2",
1607 "windows_x86_64_msvc 0.42.2",
1608]
1609
1610[[package]]
1611name = "windows-targets"
1612version = "0.48.0"
1613source = "registry+https://github.com/rust-lang/crates.io-index"
1614checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
1615dependencies = [
1616 "windows_aarch64_gnullvm 0.48.0",
1617 "windows_aarch64_msvc 0.48.0",
1618 "windows_i686_gnu 0.48.0",
1619 "windows_i686_msvc 0.48.0",
1620 "windows_x86_64_gnu 0.48.0",
1621 "windows_x86_64_gnullvm 0.48.0",
1622 "windows_x86_64_msvc 0.48.0",
1623]
1624
1625[[package]]
1626name = "windows_aarch64_gnullvm"
1627version = "0.42.2"
1628source = "registry+https://github.com/rust-lang/crates.io-index"
1629checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
1630
1631[[package]]
1632name = "windows_aarch64_gnullvm"
1633version = "0.48.0"
1634source = "registry+https://github.com/rust-lang/crates.io-index"
1635checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
1636
1637[[package]]
1638name = "windows_aarch64_msvc"
1639version = "0.42.2"
1640source = "registry+https://github.com/rust-lang/crates.io-index"
1641checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
1642
1643[[package]]
1644name = "windows_aarch64_msvc"
1645version = "0.48.0"
1646source = "registry+https://github.com/rust-lang/crates.io-index"
1647checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
1648
1649[[package]]
1650name = "windows_i686_gnu"
1651version = "0.42.2"
1652source = "registry+https://github.com/rust-lang/crates.io-index"
1653checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
1654
1655[[package]]
1656name = "windows_i686_gnu"
1657version = "0.48.0"
1658source = "registry+https://github.com/rust-lang/crates.io-index"
1659checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
1660
1661[[package]]
1662name = "windows_i686_msvc"
1663version = "0.42.2"
1664source = "registry+https://github.com/rust-lang/crates.io-index"
1665checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
1666
1667[[package]]
1668name = "windows_i686_msvc"
1669version = "0.48.0"
1670source = "registry+https://github.com/rust-lang/crates.io-index"
1671checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
1672
1673[[package]]
1674name = "windows_x86_64_gnu"
1675version = "0.42.2"
1676source = "registry+https://github.com/rust-lang/crates.io-index"
1677checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
1678
1679[[package]]
1680name = "windows_x86_64_gnu"
1681version = "0.48.0"
1682source = "registry+https://github.com/rust-lang/crates.io-index"
1683checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
1684
1685[[package]]
1686name = "windows_x86_64_gnullvm"
1687version = "0.42.2"
1688source = "registry+https://github.com/rust-lang/crates.io-index"
1689checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
1690
1691[[package]]
1692name = "windows_x86_64_gnullvm"
1693version = "0.48.0"
1694source = "registry+https://github.com/rust-lang/crates.io-index"
1695checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
1696
1697[[package]]
1698name = "windows_x86_64_msvc"
1699version = "0.42.2"
1700source = "registry+https://github.com/rust-lang/crates.io-index"
1701checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
1702
1703[[package]]
1704name = "windows_x86_64_msvc"
1705version = "0.48.0"
1706source = "registry+https://github.com/rust-lang/crates.io-index"
1707checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
diff --git a/examples/rpi-pico-w/Cargo.toml b/examples/rpi-pico-w/Cargo.toml
new file mode 100644
index 000000000..d3ce3085e
--- /dev/null
+++ b/examples/rpi-pico-w/Cargo.toml
@@ -0,0 +1,67 @@
1[package]
2name = "cyw43-example-rpi-pico-w"
3version = "0.1.0"
4edition = "2021"
5
6
7[dependencies]
8cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
9cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
10embassy-executor = { version = "0.2.0", features = ["defmt", "integrated-timers", "executor-thread", "arch-cortex-m"] }
11embassy-time = { version = "0.1.0", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] }
13embassy-net = { version = "0.1.0", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "nightly"] }
14atomic-polyfill = "0.1.5"
15static_cell = "1.0"
16
17defmt = "0.3.4"
18defmt-rtt = "0.3"
19panic-probe = { version = "0.3", features = ["print-defmt"] }
20
21cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
24
25embedded-io = { version = "0.4.0", features = ["async", "defmt"] }
26heapless = "0.7.15"
27
28
29[patch.crates-io]
30embassy-executor = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
31embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
32embassy-futures = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
33embassy-sync = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
34embassy-rp = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
35embassy-net = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
36embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
37embassy-net-driver-channel = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" }
38
39[profile.dev]
40debug = 2
41debug-assertions = true
42opt-level = 1
43overflow-checks = true
44
45[profile.release]
46codegen-units = 1
47debug = 1
48debug-assertions = false
49incremental = false
50lto = 'fat'
51opt-level = 's'
52overflow-checks = false
53
54# do not optimize proc-macro crates = faster builds from scratch
55[profile.dev.build-override]
56codegen-units = 8
57debug = false
58debug-assertions = false
59opt-level = 0
60overflow-checks = false
61
62[profile.release.build-override]
63codegen-units = 8
64debug = false
65debug-assertions = false
66opt-level = 0
67overflow-checks = false
diff --git a/examples/rpi-pico-w/build.rs b/examples/rpi-pico-w/build.rs
new file mode 100644
index 000000000..3f915f931
--- /dev/null
+++ b/examples/rpi-pico-w/build.rs
@@ -0,0 +1,36 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
35 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
36}
diff --git a/examples/rpi-pico-w/memory.x b/examples/rpi-pico-w/memory.x
new file mode 100644
index 000000000..eb8c1731d
--- /dev/null
+++ b/examples/rpi-pico-w/memory.x
@@ -0,0 +1,5 @@
1MEMORY {
2 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
3 FLASH : ORIGIN = 0x10000100, LENGTH = 1024K - 0x100
4 RAM : ORIGIN = 0x20000000, LENGTH = 256K
5} \ No newline at end of file
diff --git a/examples/rpi-pico-w/src/bin/tcp_server.rs b/examples/rpi-pico-w/src/bin/tcp_server.rs
new file mode 100644
index 000000000..6a87e7c53
--- /dev/null
+++ b/examples/rpi-pico-w/src/bin/tcp_server.rs
@@ -0,0 +1,160 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#![feature(async_fn_in_trait)]
5#![allow(incomplete_features)]
6
7use core::str::from_utf8;
8
9use cyw43_pio::PioSpi;
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_net::tcp::TcpSocket;
13use embassy_net::{Config, Stack, StackResources};
14use embassy_rp::gpio::{Level, Output};
15use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
16use embassy_rp::pio::Pio;
17use embedded_io::asynch::Write;
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21macro_rules! singleton {
22 ($val:expr) => {{
23 type T = impl Sized;
24 static STATIC_CELL: StaticCell<T> = StaticCell::new();
25 STATIC_CELL.init_with(move || $val)
26 }};
27}
28
29#[embassy_executor::task]
30async fn wifi_task(
31 runner: cyw43::Runner<
32 'static,
33 Output<'static, PIN_23>,
34 PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>,
35 >,
36) -> ! {
37 runner.run().await
38}
39
40#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
42 stack.run().await
43}
44
45#[embassy_executor::main]
46async fn main(spawner: Spawner) {
47 info!("Hello World!");
48
49 let p = embassy_rp::init(Default::default());
50
51 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
52 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
53
54 // To make flashing faster for development, you may want to flash the firmwares independently
55 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
56 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
57 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
58 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
59 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
60
61 let pwr = Output::new(p.PIN_23, Level::Low);
62 let cs = Output::new(p.PIN_25, Level::High);
63 let mut pio = Pio::new(p.PIO0);
64 let spi = PioSpi::new(
65 &mut pio.common,
66 pio.sm0,
67 pio.irq0,
68 cs,
69 p.PIN_24,
70 p.PIN_29,
71 p.DMA_CH0,
72 );
73
74 let state = singleton!(cyw43::State::new());
75 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
76 unwrap!(spawner.spawn(wifi_task(runner)));
77
78 control.init(clm).await;
79 control
80 .set_power_management(cyw43::PowerManagementMode::PowerSave)
81 .await;
82
83 let config = Config::Dhcp(Default::default());
84 //let config = embassy_net::Config::Static(embassy_net::Config {
85 // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
86 // dns_servers: Vec::new(),
87 // gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
88 //});
89
90 // Generate random seed
91 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
92
93 // Init network stack
94 let stack = &*singleton!(Stack::new(
95 net_device,
96 config,
97 singleton!(StackResources::<2>::new()),
98 seed
99 ));
100
101 unwrap!(spawner.spawn(net_task(stack)));
102
103 loop {
104 //control.join_open(env!("WIFI_NETWORK")).await;
105 match control
106 .join_wpa2(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD"))
107 .await
108 {
109 Ok(_) => break,
110 Err(err) => {
111 info!("join failed with status={}", err.status);
112 }
113 }
114 }
115
116 // And now we can use it!
117
118 let mut rx_buffer = [0; 4096];
119 let mut tx_buffer = [0; 4096];
120 let mut buf = [0; 4096];
121
122 loop {
123 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
124 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
125
126 control.gpio_set(0, false).await;
127 info!("Listening on TCP:1234...");
128 if let Err(e) = socket.accept(1234).await {
129 warn!("accept error: {:?}", e);
130 continue;
131 }
132
133 info!("Received connection from {:?}", socket.remote_endpoint());
134 control.gpio_set(0, true).await;
135
136 loop {
137 let n = match socket.read(&mut buf).await {
138 Ok(0) => {
139 warn!("read EOF");
140 break;
141 }
142 Ok(n) => n,
143 Err(e) => {
144 warn!("read error: {:?}", e);
145 break;
146 }
147 };
148
149 info!("rxd {}", from_utf8(&buf[..n]).unwrap());
150
151 match socket.write_all(&buf[..n]).await {
152 Ok(()) => {}
153 Err(e) => {
154 warn!("write error: {:?}", e);
155 break;
156 }
157 };
158 }
159 }
160}
diff --git a/examples/rpi-pico-w/src/bin/tcp_server_ap.rs b/examples/rpi-pico-w/src/bin/tcp_server_ap.rs
new file mode 100644
index 000000000..24ff7767f
--- /dev/null
+++ b/examples/rpi-pico-w/src/bin/tcp_server_ap.rs
@@ -0,0 +1,150 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#![feature(async_fn_in_trait)]
5#![allow(incomplete_features)]
6
7use core::str::from_utf8;
8
9use cyw43_pio::PioSpi;
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_net::tcp::TcpSocket;
13use embassy_net::{Config, Stack, StackResources};
14use embassy_rp::gpio::{Level, Output};
15use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
16use embassy_rp::pio::Pio;
17use embedded_io::asynch::Write;
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21macro_rules! singleton {
22 ($val:expr) => {{
23 type T = impl Sized;
24 static STATIC_CELL: StaticCell<T> = StaticCell::new();
25 STATIC_CELL.init_with(move || $val)
26 }};
27}
28
29#[embassy_executor::task]
30async fn wifi_task(
31 runner: cyw43::Runner<
32 'static,
33 Output<'static, PIN_23>,
34 PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>,
35 >,
36) -> ! {
37 runner.run().await
38}
39
40#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
42 stack.run().await
43}
44
45#[embassy_executor::main]
46async fn main(spawner: Spawner) {
47 info!("Hello World!");
48
49 let p = embassy_rp::init(Default::default());
50
51 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
52 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
53
54 // To make flashing faster for development, you may want to flash the firmwares independently
55 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
56 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
57 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
58 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
59 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
60
61 let pwr = Output::new(p.PIN_23, Level::Low);
62 let cs = Output::new(p.PIN_25, Level::High);
63 let mut pio = Pio::new(p.PIO0);
64 let spi = PioSpi::new(
65 &mut pio.common,
66 pio.sm0,
67 pio.irq0,
68 cs,
69 p.PIN_24,
70 p.PIN_29,
71 p.DMA_CH0,
72 );
73
74 let state = singleton!(cyw43::State::new());
75 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
76 unwrap!(spawner.spawn(wifi_task(runner)));
77
78 control.init(clm).await;
79 control
80 .set_power_management(cyw43::PowerManagementMode::PowerSave)
81 .await;
82
83 // Use a link-local address for communication without DHCP server
84 let config = Config::Static(embassy_net::StaticConfig {
85 address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16),
86 dns_servers: heapless::Vec::new(),
87 gateway: None,
88 });
89
90 // Generate random seed
91 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
92
93 // Init network stack
94 let stack = &*singleton!(Stack::new(
95 net_device,
96 config,
97 singleton!(StackResources::<2>::new()),
98 seed
99 ));
100
101 unwrap!(spawner.spawn(net_task(stack)));
102
103 //control.start_ap_open("cyw43", 5).await;
104 control.start_ap_wpa2("cyw43", "password", 5).await;
105
106 // And now we can use it!
107
108 let mut rx_buffer = [0; 4096];
109 let mut tx_buffer = [0; 4096];
110 let mut buf = [0; 4096];
111
112 loop {
113 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
114 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
115
116 control.gpio_set(0, false).await;
117 info!("Listening on TCP:1234...");
118 if let Err(e) = socket.accept(1234).await {
119 warn!("accept error: {:?}", e);
120 continue;
121 }
122
123 info!("Received connection from {:?}", socket.remote_endpoint());
124 control.gpio_set(0, true).await;
125
126 loop {
127 let n = match socket.read(&mut buf).await {
128 Ok(0) => {
129 warn!("read EOF");
130 break;
131 }
132 Ok(n) => n,
133 Err(e) => {
134 warn!("read error: {:?}", e);
135 break;
136 }
137 };
138
139 info!("rxd {}", from_utf8(&buf[..n]).unwrap());
140
141 match socket.write_all(&buf[..n]).await {
142 Ok(()) => {}
143 Err(e) => {
144 warn!("write error: {:?}", e);
145 break;
146 }
147 };
148 }
149 }
150}
diff --git a/examples/rpi-pico-w/src/bin/wifi_scan.rs b/examples/rpi-pico-w/src/bin/wifi_scan.rs
new file mode 100644
index 000000000..8fb6c65aa
--- /dev/null
+++ b/examples/rpi-pico-w/src/bin/wifi_scan.rs
@@ -0,0 +1,87 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#![feature(async_fn_in_trait)]
5#![allow(incomplete_features)]
6
7use core::str;
8
9use cyw43_pio::PioSpi;
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_net::Stack;
13use embassy_rp::gpio::{Level, Output};
14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
15use embassy_rp::pio::Pio;
16use static_cell::StaticCell;
17use {defmt_rtt as _, panic_probe as _};
18
19macro_rules! singleton {
20 ($val:expr) => {{
21 type T = impl Sized;
22 static STATIC_CELL: StaticCell<T> = StaticCell::new();
23 STATIC_CELL.init_with(move || $val)
24 }};
25}
26
27#[embassy_executor::task]
28async fn wifi_task(
29 runner: cyw43::Runner<
30 'static,
31 Output<'static, PIN_23>,
32 PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>,
33 >,
34) -> ! {
35 runner.run().await
36}
37
38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
40 stack.run().await
41}
42
43#[embassy_executor::main]
44async fn main(spawner: Spawner) {
45 info!("Hello World!");
46
47 let p = embassy_rp::init(Default::default());
48
49 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
50 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
51
52 // To make flashing faster for development, you may want to flash the firmwares independently
53 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
54 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
55 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
56 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
57 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
58
59 let pwr = Output::new(p.PIN_23, Level::Low);
60 let cs = Output::new(p.PIN_25, Level::High);
61 let mut pio = Pio::new(p.PIO0);
62 let spi = PioSpi::new(
63 &mut pio.common,
64 pio.sm0,
65 pio.irq0,
66 cs,
67 p.PIN_24,
68 p.PIN_29,
69 p.DMA_CH0,
70 );
71
72 let state = singleton!(cyw43::State::new());
73 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
74 unwrap!(spawner.spawn(wifi_task(runner)));
75
76 control.init(clm).await;
77 control
78 .set_power_management(cyw43::PowerManagementMode::PowerSave)
79 .await;
80
81 let mut scanner = control.scan().await;
82 while let Some(bss) = scanner.next().await {
83 if let Ok(ssid_str) = str::from_utf8(&bss.ssid) {
84 info!("scanned {} == {:x}", ssid_str, bss.bssid);
85 }
86 }
87}