aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-08-05 20:58:04 +0200
committerDario Nieuwenhuis <[email protected]>2024-08-05 21:07:42 +0200
commit4f7ac1946a43379306aa432961fb97bba1139a6e (patch)
tree2589e67baa770acf244dfdea355e16585d683d16
parentafc8e684dd16c3bc947b365ca293f0f37d95b342 (diff)
cyw43: add Bluetooth support.
Co-Authored-By: Brandon Ros <[email protected]>
-rwxr-xr-xci.sh2
-rw-r--r--[-rwxr-xr-x]cyw43-firmware/43439A0.binbin230321 -> 231077 bytes
-rw-r--r--cyw43-firmware/43439A0_btfw.binbin0 -> 6164 bytes
-rw-r--r--[-rwxr-xr-x]cyw43-firmware/43439A0_clm.binbin4752 -> 984 bytes
-rw-r--r--cyw43-firmware/README.md11
-rw-r--r--cyw43-pio/src/lib.rs9
-rw-r--r--cyw43/Cargo.toml8
-rw-r--r--cyw43/src/bluetooth.rs508
-rw-r--r--cyw43/src/bus.rs90
-rw-r--r--cyw43/src/consts.rs67
-rw-r--r--cyw43/src/control.rs10
-rw-r--r--cyw43/src/lib.rs87
-rw-r--r--cyw43/src/runner.rs120
-rw-r--r--cyw43/src/util.rs20
-rw-r--r--examples/rp/Cargo.toml17
-rw-r--r--examples/rp/src/bin/bluetooth.rs148
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs4
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs4
-rw-r--r--examples/rp/src/bin/wifi_scan.rs4
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs8
-rw-r--r--examples/rp/src/bin/wifi_webrequest.rs4
21 files changed, 1037 insertions, 84 deletions
diff --git a/ci.sh b/ci.sh
index ce165cf39..0cd0c54bc 100755
--- a/ci.sh
+++ b/ci.sh
@@ -173,6 +173,8 @@ cargo batch \
173 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ 173 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
174 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \ 174 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
175 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \ 175 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
176 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs,bluetooth' \
177 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs,bluetooth' \
176 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \ 178 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \
177 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \ 179 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \
178 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ 180 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
diff --git a/cyw43-firmware/43439A0.bin b/cyw43-firmware/43439A0.bin
index 017375277..a05482fe9 100755..100644
--- a/cyw43-firmware/43439A0.bin
+++ b/cyw43-firmware/43439A0.bin
Binary files differ
diff --git a/cyw43-firmware/43439A0_btfw.bin b/cyw43-firmware/43439A0_btfw.bin
new file mode 100644
index 000000000..290ce8ef0
--- /dev/null
+++ b/cyw43-firmware/43439A0_btfw.bin
Binary files differ
diff --git a/cyw43-firmware/43439A0_clm.bin b/cyw43-firmware/43439A0_clm.bin
index 1fedd753a..dc4ee0252 100755..100644
--- a/cyw43-firmware/43439A0_clm.bin
+++ b/cyw43-firmware/43439A0_clm.bin
Binary files differ
diff --git a/cyw43-firmware/README.md b/cyw43-firmware/README.md
index db3d9c9cf..10a6b5d02 100644
--- a/cyw43-firmware/README.md
+++ b/cyw43-firmware/README.md
@@ -1,9 +1,14 @@
1# WiFi firmware 1# WiFi + Bluetooth firmware blobs
2 2
3Firmware obtained from https://github.com/Infineon/wifi-host-driver/tree/master/WiFi_Host_Driver/resources/firmware/COMPONENT_43439 3Firmware obtained from https://github.com/georgerobotics/cyw43-driver/tree/main/firmware
4 4
5Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt) 5Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt)
6 6
7## Changelog 7## Changelog
8 8
9* 2023-07-28: synced with `ad3bad0` - Update 43439 fw from 7.95.55 ot 7.95.62 9* 2023-08-21: synced with `a1dc885` - Update 43439 fw + clm to come from `wb43439A0_7_95_49_00_combined.h` + add Bluetooth firmware
10* 2023-07-28: synced with `ad3bad0` - Update 43439 fw from 7.95.55 to 7.95.62
11
12## Notes
13
14If you update these files, please update the lengths in the `tests/rp/src/bin/cyw43_perf.rs` test (which relies on these files running from RAM).
diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs
index 8c217b995..40cf63a17 100644
--- a/cyw43-pio/src/lib.rs
+++ b/cyw43-pio/src/lib.rs
@@ -181,7 +181,10 @@ where
181 let read_bits = read.len() * 32 + 32 - 1; 181 let read_bits = read.len() * 32 + 32 - 1;
182 182
183 #[cfg(feature = "defmt")] 183 #[cfg(feature = "defmt")]
184 defmt::trace!("write={} read={}", write_bits, read_bits); 184 defmt::trace!("cmd_read write={} read={}", write_bits, read_bits);
185
186 #[cfg(feature = "defmt")]
187 defmt::trace!("cmd_read cmd = {:02x} len = {}", cmd, read.len());
185 188
186 unsafe { 189 unsafe {
187 instr::set_y(&mut self.sm, read_bits as u32); 190 instr::set_y(&mut self.sm, read_bits as u32);
@@ -201,6 +204,10 @@ where
201 .rx() 204 .rx()
202 .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status)) 205 .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status))
203 .await; 206 .await;
207
208 #[cfg(feature = "defmt")]
209 defmt::trace!("cmd_read cmd = {:02x} len = {} read = {:08x}", cmd, read.len(), read);
210
204 status 211 status
205 } 212 }
206} 213}
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index 654afe356..9b469c338 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -10,8 +10,9 @@ repository = "https://github.com/embassy-rs/embassy"
10documentation = "https://docs.embassy.dev/cyw43" 10documentation = "https://docs.embassy.dev/cyw43"
11 11
12[features] 12[features]
13defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt"] 13defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt", "bt-hci?/defmt", "embedded-io-async?/defmt-03"]
14log = ["dep:log"] 14log = ["dep:log"]
15bluetooth = ["dep:bt-hci", "dep:embedded-io-async"]
15 16
16# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`. 17# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`.
17firmware-logs = [] 18firmware-logs = []
@@ -31,9 +32,12 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
31 32
32embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 33embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
33num_enum = { version = "0.5.7", default-features = false } 34num_enum = { version = "0.5.7", default-features = false }
34
35heapless = "0.8.0" 35heapless = "0.8.0"
36 36
37# Bluetooth deps
38embedded-io-async = { version = "0.6.0", optional = true }
39bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3", optional = true, default-features = false }
40
37[package.metadata.embassy_docs] 41[package.metadata.embassy_docs]
38src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" 42src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/"
39src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" 43src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/"
diff --git a/cyw43/src/bluetooth.rs b/cyw43/src/bluetooth.rs
new file mode 100644
index 000000000..f617a8c7e
--- /dev/null
+++ b/cyw43/src/bluetooth.rs
@@ -0,0 +1,508 @@
1use core::cell::RefCell;
2use core::future::Future;
3use core::mem::MaybeUninit;
4
5use bt_hci::transport::WithIndicator;
6use bt_hci::{ControllerToHostPacket, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci};
7use embassy_futures::yield_now;
8use embassy_sync::blocking_mutex::raw::NoopRawMutex;
9use embassy_sync::zerocopy_channel;
10use embassy_time::{Duration, Timer};
11use embedded_hal_1::digital::OutputPin;
12
13use crate::bus::Bus;
14pub use crate::bus::SpiBusCyw43;
15use crate::consts::*;
16use crate::util::round_up;
17use crate::{util, CHIP};
18
19pub(crate) struct BtState {
20 rx: [BtPacketBuf; 4],
21 tx: [BtPacketBuf; 4],
22 inner: MaybeUninit<BtStateInnre<'static>>,
23}
24
25impl BtState {
26 pub const fn new() -> Self {
27 Self {
28 rx: [const { BtPacketBuf::new() }; 4],
29 tx: [const { BtPacketBuf::new() }; 4],
30 inner: MaybeUninit::uninit(),
31 }
32 }
33}
34
35struct BtStateInnre<'d> {
36 rx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>,
37 tx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>,
38}
39
40/// Bluetooth driver.
41pub struct BtDriver<'d> {
42 rx: RefCell<zerocopy_channel::Receiver<'d, NoopRawMutex, BtPacketBuf>>,
43 tx: RefCell<zerocopy_channel::Sender<'d, NoopRawMutex, BtPacketBuf>>,
44}
45
46pub(crate) struct BtRunner<'d> {
47 pub(crate) tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, BtPacketBuf>,
48 rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, BtPacketBuf>,
49
50 // Bluetooth circular buffers
51 addr: u32,
52 h2b_write_pointer: u32,
53 b2h_read_pointer: u32,
54}
55
56const BT_HCI_MTU: usize = 1024;
57
58/// Represents a packet of size MTU.
59pub(crate) struct BtPacketBuf {
60 pub(crate) len: usize,
61 pub(crate) buf: [u8; BT_HCI_MTU],
62}
63
64impl BtPacketBuf {
65 /// Create a new packet buffer.
66 pub const fn new() -> Self {
67 Self {
68 len: 0,
69 buf: [0; BT_HCI_MTU],
70 }
71 }
72}
73
74pub(crate) fn new<'d>(state: &'d mut BtState) -> (BtRunner<'d>, BtDriver<'d>) {
75 // safety: this is a self-referential struct, however:
76 // - it can't move while the `'d` borrow is active.
77 // - when the borrow ends, the dangling references inside the MaybeUninit will never be used again.
78 let state_uninit: *mut MaybeUninit<BtStateInnre<'d>> =
79 (&mut state.inner as *mut MaybeUninit<BtStateInnre<'static>>).cast();
80 let state = unsafe { &mut *state_uninit }.write(BtStateInnre {
81 rx: zerocopy_channel::Channel::new(&mut state.rx[..]),
82 tx: zerocopy_channel::Channel::new(&mut state.tx[..]),
83 });
84
85 let (rx_sender, rx_receiver) = state.rx.split();
86 let (tx_sender, tx_receiver) = state.tx.split();
87
88 (
89 BtRunner {
90 tx_chan: tx_receiver,
91 rx_chan: rx_sender,
92
93 addr: 0,
94 h2b_write_pointer: 0,
95 b2h_read_pointer: 0,
96 },
97 BtDriver {
98 rx: RefCell::new(rx_receiver),
99 tx: RefCell::new(tx_sender),
100 },
101 )
102}
103
104pub(crate) struct CybtFwCb<'a> {
105 pub p_next_line_start: &'a [u8],
106}
107
108pub(crate) struct HexFileData<'a> {
109 pub addr_mode: i32,
110 pub hi_addr: u16,
111 pub dest_addr: u32,
112 pub p_ds: &'a mut [u8],
113}
114
115pub(crate) fn read_firmware_patch_line(p_btfw_cb: &mut CybtFwCb, hfd: &mut HexFileData) -> u32 {
116 let mut abs_base_addr32 = 0;
117
118 loop {
119 let num_bytes = p_btfw_cb.p_next_line_start[0];
120 p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[1..];
121
122 let addr = (p_btfw_cb.p_next_line_start[0] as u16) << 8 | p_btfw_cb.p_next_line_start[1] as u16;
123 p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[2..];
124
125 let line_type = p_btfw_cb.p_next_line_start[0];
126 p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[1..];
127
128 if num_bytes == 0 {
129 break;
130 }
131
132 hfd.p_ds[..num_bytes as usize].copy_from_slice(&p_btfw_cb.p_next_line_start[..num_bytes as usize]);
133 p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[num_bytes as usize..];
134
135 match line_type {
136 BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS => {
137 hfd.hi_addr = (hfd.p_ds[0] as u16) << 8 | hfd.p_ds[1] as u16;
138 hfd.addr_mode = BTFW_ADDR_MODE_EXTENDED;
139 }
140 BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS => {
141 hfd.hi_addr = (hfd.p_ds[0] as u16) << 8 | hfd.p_ds[1] as u16;
142 hfd.addr_mode = BTFW_ADDR_MODE_SEGMENT;
143 }
144 BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS => {
145 abs_base_addr32 = (hfd.p_ds[0] as u32) << 24
146 | (hfd.p_ds[1] as u32) << 16
147 | (hfd.p_ds[2] as u32) << 8
148 | hfd.p_ds[3] as u32;
149 hfd.addr_mode = BTFW_ADDR_MODE_LINEAR32;
150 }
151 BTFW_HEX_LINE_TYPE_DATA => {
152 hfd.dest_addr = addr as u32;
153 match hfd.addr_mode {
154 BTFW_ADDR_MODE_EXTENDED => hfd.dest_addr += (hfd.hi_addr as u32) << 16,
155 BTFW_ADDR_MODE_SEGMENT => hfd.dest_addr += (hfd.hi_addr as u32) << 4,
156 BTFW_ADDR_MODE_LINEAR32 => hfd.dest_addr += abs_base_addr32,
157 _ => {}
158 }
159 return num_bytes as u32;
160 }
161 _ => {}
162 }
163 }
164 0
165}
166
167impl<'a> BtRunner<'a> {
168 pub(crate) async fn init_bluetooth(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>, firmware: &[u8]) {
169 trace!("init_bluetooth");
170 bus.bp_write32(CHIP.bluetooth_base_address + BT2WLAN_PWRUP_ADDR, BT2WLAN_PWRUP_WAKE)
171 .await;
172 Timer::after(Duration::from_millis(2)).await;
173 self.upload_bluetooth_firmware(bus, firmware).await;
174 self.wait_bt_ready(bus).await;
175 self.init_bt_buffers(bus).await;
176 self.wait_bt_awake(bus).await;
177 self.bt_set_host_ready(bus).await;
178 self.bt_toggle_intr(bus).await;
179 }
180
181 pub(crate) async fn upload_bluetooth_firmware(
182 &mut self,
183 bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>,
184 firmware: &[u8],
185 ) {
186 // read version
187 let version_length = firmware[0];
188 let _version = &firmware[1..=version_length as usize];
189 // skip version + 1 extra byte as per cybt_shared_bus_driver.c
190 let firmware = &firmware[version_length as usize + 2..];
191 // buffers
192 let mut data_buffer: [u8; 0x100] = [0; 0x100];
193 let mut aligned_data_buffer: [u8; 0x100] = [0; 0x100];
194 // structs
195 let mut btfw_cb = CybtFwCb {
196 p_next_line_start: firmware,
197 };
198 let mut hfd = HexFileData {
199 addr_mode: BTFW_ADDR_MODE_EXTENDED,
200 hi_addr: 0,
201 dest_addr: 0,
202 p_ds: &mut data_buffer,
203 };
204 loop {
205 let num_fw_bytes = read_firmware_patch_line(&mut btfw_cb, &mut hfd);
206 if num_fw_bytes == 0 {
207 break;
208 }
209 let fw_bytes = &hfd.p_ds[0..num_fw_bytes as usize];
210 let mut dest_start_addr = hfd.dest_addr + CHIP.bluetooth_base_address;
211 let mut aligned_data_buffer_index: usize = 0;
212 // pad start
213 if !util::is_aligned(dest_start_addr, 4) {
214 let num_pad_bytes = dest_start_addr % 4;
215 let padded_dest_start_addr = util::round_down(dest_start_addr, 4);
216 let memory_value = bus.bp_read32(padded_dest_start_addr).await;
217 let memory_value_bytes = memory_value.to_le_bytes();
218 // Copy the previous memory value's bytes to the start
219 for i in 0..num_pad_bytes as usize {
220 aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i];
221 aligned_data_buffer_index += 1;
222 }
223 // Copy the firmware bytes after the padding bytes
224 for i in 0..num_fw_bytes as usize {
225 aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
226 aligned_data_buffer_index += 1;
227 }
228 dest_start_addr = padded_dest_start_addr;
229 } else {
230 // Directly copy fw_bytes into aligned_data_buffer if no start padding is required
231 for i in 0..num_fw_bytes as usize {
232 aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
233 aligned_data_buffer_index += 1;
234 }
235 }
236 // pad end
237 let mut dest_end_addr = dest_start_addr + aligned_data_buffer_index as u32;
238 if !util::is_aligned(dest_end_addr, 4) {
239 let offset = dest_end_addr % 4;
240 let num_pad_bytes_end = 4 - offset;
241 let padded_dest_end_addr = util::round_down(dest_end_addr, 4);
242 let memory_value = bus.bp_read32(padded_dest_end_addr).await;
243 let memory_value_bytes = memory_value.to_le_bytes();
244 // Append the necessary memory bytes to pad the end of aligned_data_buffer
245 for i in offset..4 {
246 aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i as usize];
247 aligned_data_buffer_index += 1;
248 }
249 dest_end_addr += num_pad_bytes_end;
250 } else {
251 // pad end alignment not needed
252 }
253 let buffer_to_write = &aligned_data_buffer[0..aligned_data_buffer_index as usize];
254 assert!(dest_start_addr % 4 == 0);
255 assert!(dest_end_addr % 4 == 0);
256 assert!(aligned_data_buffer_index % 4 == 0);
257 bus.bp_write(dest_start_addr, buffer_to_write).await;
258 }
259 }
260
261 pub(crate) async fn wait_bt_ready(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
262 trace!("wait_bt_ready");
263 let mut success = false;
264 for _ in 0..300 {
265 let val = bus.bp_read32(BT_CTRL_REG_ADDR).await;
266 trace!("BT_CTRL_REG_ADDR = {:08x}", val);
267 if val & BTSDIO_REG_FW_RDY_BITMASK != 0 {
268 success = true;
269 break;
270 }
271 Timer::after(Duration::from_millis(1)).await;
272 }
273 assert!(success == true);
274 }
275
276 pub(crate) async fn wait_bt_awake(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
277 trace!("wait_bt_awake");
278 let mut success = false;
279 for _ in 0..300 {
280 let val = bus.bp_read32(BT_CTRL_REG_ADDR).await;
281 trace!("BT_CTRL_REG_ADDR = {:08x}", val);
282 if val & BTSDIO_REG_BT_AWAKE_BITMASK != 0 {
283 success = true;
284 break;
285 }
286 Timer::after(Duration::from_millis(1)).await;
287 }
288 assert!(success == true);
289 }
290
291 pub(crate) async fn bt_set_host_ready(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
292 trace!("bt_set_host_ready");
293 let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
294 // TODO: do we need to swap endianness on this read?
295 let new_val = old_val | BTSDIO_REG_SW_RDY_BITMASK;
296 bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
297 }
298
299 // TODO: use this
300 #[allow(dead_code)]
301 pub(crate) async fn bt_set_awake(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>, awake: bool) {
302 trace!("bt_set_awake");
303 let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
304 // TODO: do we need to swap endianness on this read?
305 let new_val = if awake {
306 old_val | BTSDIO_REG_WAKE_BT_BITMASK
307 } else {
308 old_val & !BTSDIO_REG_WAKE_BT_BITMASK
309 };
310 bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
311 }
312
313 pub(crate) async fn bt_toggle_intr(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
314 trace!("bt_toggle_intr");
315 let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
316 // TODO: do we need to swap endianness on this read?
317 let new_val = old_val ^ BTSDIO_REG_DATA_VALID_BITMASK;
318 bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
319 }
320
321 // TODO: use this
322 #[allow(dead_code)]
323 pub(crate) async fn bt_set_intr(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
324 trace!("bt_set_intr");
325 let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
326 let new_val = old_val | BTSDIO_REG_DATA_VALID_BITMASK;
327 bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
328 }
329
330 pub(crate) async fn init_bt_buffers(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
331 trace!("init_bt_buffers");
332 self.addr = bus.bp_read32(WLAN_RAM_BASE_REG_ADDR).await;
333 assert!(self.addr != 0);
334 trace!("wlan_ram_base_addr = {:08x}", self.addr);
335 bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_IN, 0).await;
336 bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_OUT, 0).await;
337 bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_IN, 0).await;
338 bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_OUT, 0).await;
339 }
340
341 async fn bt_bus_request(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
342 // TODO: CYW43_THREAD_ENTER mutex?
343 self.bt_set_awake(bus, true).await;
344 self.wait_bt_awake(bus).await;
345 }
346
347 pub(crate) async fn hci_write(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
348 self.bt_bus_request(bus).await;
349
350 // NOTE(unwrap): we only call this when we do have a packet in the queue.
351 let buf = self.tx_chan.try_receive().unwrap();
352 debug!("HCI tx: {:02x}", crate::fmt::Bytes(&buf.buf[..buf.len]));
353
354 let len = buf.len as u32 - 1; // len doesn't include hci type byte
355 let rounded_len = round_up(len, 4);
356 let total_len = 4 + rounded_len;
357
358 let read_pointer = bus.bp_read32(self.addr + BTSDIO_OFFSET_HOST2BT_OUT).await;
359 let available = read_pointer.wrapping_sub(self.h2b_write_pointer + 4) % BTSDIO_FWBUF_SIZE;
360 if available < total_len {
361 warn!(
362 "bluetooth tx queue full, retrying. len {} available {}",
363 total_len, available
364 );
365 yield_now().await;
366 return;
367 }
368
369 // Build header
370 let mut header = [0u8; 4];
371 header[0] = len as u8;
372 header[1] = (len >> 8) as u8;
373 header[2] = (len >> 16) as u8;
374 header[3] = buf.buf[0]; // HCI type byte
375
376 // Write header
377 let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer;
378 bus.bp_write(addr, &header).await;
379 self.h2b_write_pointer = (self.h2b_write_pointer + 4) % BTSDIO_FWBUF_SIZE;
380
381 // Write payload.
382 let payload = &buf.buf[1..][..rounded_len as usize];
383 if self.h2b_write_pointer as usize + payload.len() > BTSDIO_FWBUF_SIZE as usize {
384 // wraparound
385 let n = BTSDIO_FWBUF_SIZE - self.h2b_write_pointer;
386 let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer;
387 bus.bp_write(addr, &payload[..n as usize]).await;
388 let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF;
389 bus.bp_write(addr, &payload[n as usize..]).await;
390 } else {
391 // no wraparound
392 let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer;
393 bus.bp_write(addr, payload).await;
394 }
395 self.h2b_write_pointer = (self.h2b_write_pointer + payload.len() as u32) % BTSDIO_FWBUF_SIZE;
396
397 // Update pointer.
398 bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_IN, self.h2b_write_pointer)
399 .await;
400
401 self.bt_toggle_intr(bus).await;
402
403 self.tx_chan.receive_done();
404 }
405
406 async fn bt_has_work(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) -> bool {
407 let int_status = bus.bp_read32(CHIP.sdiod_core_base_address + SDIO_INT_STATUS).await;
408 if int_status & I_HMB_FC_CHANGE != 0 {
409 bus.bp_write32(
410 CHIP.sdiod_core_base_address + SDIO_INT_STATUS,
411 int_status & I_HMB_FC_CHANGE,
412 )
413 .await;
414 return true;
415 }
416 return false;
417 }
418
419 pub(crate) async fn handle_irq(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
420 if self.bt_has_work(bus).await {
421 loop {
422 // Check if we have data.
423 let write_pointer = bus.bp_read32(self.addr + BTSDIO_OFFSET_BT2HOST_IN).await;
424 let available = write_pointer.wrapping_sub(self.b2h_read_pointer) % BTSDIO_FWBUF_SIZE;
425 if available == 0 {
426 break;
427 }
428
429 // read header
430 let mut header = [0u8; 4];
431 let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer;
432 bus.bp_read(addr, &mut header).await;
433
434 // calc length
435 let len = header[0] as u32 | ((header[1]) as u32) << 8 | ((header[2]) as u32) << 16;
436 let rounded_len = round_up(len, 4);
437 if available < 4 + rounded_len {
438 warn!("ringbuf data not enough for a full packet?");
439 break;
440 }
441 self.b2h_read_pointer = (self.b2h_read_pointer + 4) % BTSDIO_FWBUF_SIZE;
442
443 // Obtain a buf from the channel.
444 let buf = self.rx_chan.send().await;
445
446 buf.buf[0] = header[3]; // hci packet type
447 let payload = &mut buf.buf[1..][..rounded_len as usize];
448 if self.b2h_read_pointer as usize + payload.len() > BTSDIO_FWBUF_SIZE as usize {
449 // wraparound
450 let n = BTSDIO_FWBUF_SIZE - self.b2h_read_pointer;
451 let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer;
452 bus.bp_read(addr, &mut payload[..n as usize]).await;
453 let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF;
454 bus.bp_read(addr, &mut payload[n as usize..]).await;
455 } else {
456 // no wraparound
457 let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer;
458 bus.bp_read(addr, payload).await;
459 }
460 self.b2h_read_pointer = (self.b2h_read_pointer + payload.len() as u32) % BTSDIO_FWBUF_SIZE;
461 bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_OUT, self.b2h_read_pointer)
462 .await;
463
464 buf.len = 1 + len as usize;
465 debug!("HCI rx: {:02x}", crate::fmt::Bytes(&buf.buf[..buf.len]));
466
467 self.rx_chan.send_done();
468
469 self.bt_toggle_intr(bus).await;
470 }
471 }
472 }
473}
474
475impl<'d> embedded_io_async::ErrorType for BtDriver<'d> {
476 type Error = core::convert::Infallible;
477}
478
479impl<'d> bt_hci::transport::Transport for BtDriver<'d> {
480 fn read<'a>(&self, rx: &'a mut [u8]) -> impl Future<Output = Result<ControllerToHostPacket<'a>, Self::Error>> {
481 async {
482 let ch = &mut *self.rx.borrow_mut();
483 let buf = ch.receive().await;
484 let n = buf.len;
485 assert!(n < rx.len());
486 rx[..n].copy_from_slice(&buf.buf[..n]);
487 ch.receive_done();
488
489 let kind = PacketKind::from_hci_bytes_complete(&rx[..1]).unwrap();
490 let (res, _) = ControllerToHostPacket::from_hci_bytes_with_kind(kind, &rx[1..n]).unwrap();
491 Ok(res)
492 }
493 }
494
495 /// Write a complete HCI packet from the tx buffer
496 fn write<T: HostToControllerPacket>(&self, val: &T) -> impl Future<Output = Result<(), Self::Error>> {
497 async {
498 let ch = &mut *self.tx.borrow_mut();
499 let buf = ch.send().await;
500 let buf_len = buf.buf.len();
501 let mut slice = &mut buf.buf[..];
502 WithIndicator::new(val).write_hci(&mut slice).unwrap();
503 buf.len = buf_len - slice.len();
504 ch.send_done();
505 Ok(())
506 }
507 }
508}
diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs
index 014109038..8a53484d5 100644
--- a/cyw43/src/bus.rs
+++ b/cyw43/src/bus.rs
@@ -4,7 +4,7 @@ use embedded_hal_1::digital::OutputPin;
4use futures::FutureExt; 4use futures::FutureExt;
5 5
6use crate::consts::*; 6use crate::consts::*;
7use crate::slice8_mut; 7use crate::util::slice8_mut;
8 8
9/// Custom Spi Trait that _only_ supports the bus operation of the cyw43 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. 10/// Implementors are expected to hold the CS pin low during an operation.
@@ -48,44 +48,91 @@ where
48 } 48 }
49 } 49 }
50 50
51 pub async fn init(&mut self) { 51 pub async fn init(&mut self, bluetooth_enabled: bool) {
52 // Reset 52 // Reset
53 trace!("WL_REG off/on");
53 self.pwr.set_low().unwrap(); 54 self.pwr.set_low().unwrap();
54 Timer::after_millis(20).await; 55 Timer::after_millis(20).await;
55 self.pwr.set_high().unwrap(); 56 self.pwr.set_high().unwrap();
56 Timer::after_millis(250).await; 57 Timer::after_millis(250).await;
57 58
59 trace!("read REG_BUS_TEST_RO");
58 while self 60 while self
59 .read32_swapped(REG_BUS_TEST_RO) 61 .read32_swapped(FUNC_BUS, REG_BUS_TEST_RO)
60 .inspect(|v| trace!("{:#x}", v)) 62 .inspect(|v| trace!("{:#x}", v))
61 .await 63 .await
62 != FEEDBEAD 64 != FEEDBEAD
63 {} 65 {}
64 66
65 self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; 67 trace!("write REG_BUS_TEST_RW");
66 let val = self.read32_swapped(REG_BUS_TEST_RW).await; 68 self.write32_swapped(FUNC_BUS, REG_BUS_TEST_RW, TEST_PATTERN).await;
69 let val = self.read32_swapped(FUNC_BUS, REG_BUS_TEST_RW).await;
67 trace!("{:#x}", val); 70 trace!("{:#x}", val);
68 assert_eq!(val, TEST_PATTERN); 71 assert_eq!(val, TEST_PATTERN);
69 72
70 let val = self.read32_swapped(REG_BUS_CTRL).await; 73 trace!("read REG_BUS_CTRL");
74 let val = self.read32_swapped(FUNC_BUS, REG_BUS_CTRL).await;
71 trace!("{:#010b}", (val & 0xff)); 75 trace!("{:#010b}", (val & 0xff));
72 76
73 // 32-bit word length, little endian (which is the default endianess). 77 // 32-bit word length, little endian (which is the default endianess).
78 // TODO: C library is uint32_t val = WORD_LENGTH_32 | HIGH_SPEED_MODE| ENDIAN_BIG | INTERRUPT_POLARITY_HIGH | WAKE_UP | 0x4 << (8 * SPI_RESPONSE_DELAY) | INTR_WITH_STATUS << (8 * SPI_STATUS_ENABLE);
79 trace!("write REG_BUS_CTRL");
74 self.write32_swapped( 80 self.write32_swapped(
81 FUNC_BUS,
75 REG_BUS_CTRL, 82 REG_BUS_CTRL,
76 WORD_LENGTH_32 | HIGH_SPEED | INTERRUPT_HIGH | WAKE_UP | STATUS_ENABLE | INTERRUPT_WITH_STATUS, 83 WORD_LENGTH_32
84 | HIGH_SPEED
85 | INTERRUPT_POLARITY_HIGH
86 | WAKE_UP
87 | 0x4 << (8 * REG_BUS_RESPONSE_DELAY)
88 | STATUS_ENABLE << (8 * REG_BUS_STATUS_ENABLE)
89 | INTR_WITH_STATUS << (8 * REG_BUS_STATUS_ENABLE),
77 ) 90 )
78 .await; 91 .await;
79 92
93 trace!("read REG_BUS_CTRL");
80 let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await; 94 let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await;
81 trace!("{:#b}", val); 95 trace!("{:#b}", val);
82 96
97 // TODO: C doesn't do this? i doubt it messes anything up
98 trace!("read REG_BUS_TEST_RO");
83 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; 99 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await;
84 trace!("{:#x}", val); 100 trace!("{:#x}", val);
85 assert_eq!(val, FEEDBEAD); 101 assert_eq!(val, FEEDBEAD);
102
103 // TODO: C doesn't do this? i doubt it messes anything up
104 trace!("read REG_BUS_TEST_RW");
86 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; 105 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await;
87 trace!("{:#x}", val); 106 trace!("{:#x}", val);
88 assert_eq!(val, TEST_PATTERN); 107 assert_eq!(val, TEST_PATTERN);
108
109 trace!("write SPI_RESP_DELAY_F1 CYW43_BACKPLANE_READ_PAD_LEN_BYTES");
110 self.write8(FUNC_BUS, SPI_RESP_DELAY_F1, WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE)
111 .await;
112
113 // TODO: Make sure error interrupt bits are clear?
114 // cyw43_write_reg_u8(self, BUS_FUNCTION, SPI_INTERRUPT_REGISTER, DATA_UNAVAILABLE | COMMAND_ERROR | DATA_ERROR | F1_OVERFLOW) != 0)
115 trace!("Make sure error interrupt bits are clear");
116 self.write8(
117 FUNC_BUS,
118 REG_BUS_INTERRUPT,
119 (IRQ_DATA_UNAVAILABLE | IRQ_COMMAND_ERROR | IRQ_DATA_ERROR | IRQ_F1_OVERFLOW) as u8,
120 )
121 .await;
122
123 // Enable a selection of interrupts
124 // TODO: why not all of these F2_F3_FIFO_RD_UNDERFLOW | F2_F3_FIFO_WR_OVERFLOW | COMMAND_ERROR | DATA_ERROR | F2_PACKET_AVAILABLE | F1_OVERFLOW | F1_INTR
125 trace!("enable a selection of interrupts");
126 let mut val = IRQ_F2_F3_FIFO_RD_UNDERFLOW
127 | IRQ_F2_F3_FIFO_WR_OVERFLOW
128 | IRQ_COMMAND_ERROR
129 | IRQ_DATA_ERROR
130 | IRQ_F2_PACKET_AVAILABLE
131 | IRQ_F1_OVERFLOW;
132 if bluetooth_enabled {
133 val = val | IRQ_F1_INTR;
134 }
135 self.write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, val).await;
89 } 136 }
90 137
91 pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) { 138 pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) {
@@ -107,6 +154,8 @@ where
107 154
108 #[allow(unused)] 155 #[allow(unused)]
109 pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) { 156 pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) {
157 trace!("bp_read addr = {:08x}", addr);
158
110 // It seems the HW force-aligns the addr 159 // It seems the HW force-aligns the addr
111 // to 2 if data.len() >= 2 160 // to 2 if data.len() >= 2
112 // to 4 if data.len() >= 4 161 // to 4 if data.len() >= 4
@@ -140,6 +189,8 @@ where
140 } 189 }
141 190
142 pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) { 191 pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) {
192 trace!("bp_write addr = {:08x}", addr);
193
143 // It seems the HW force-aligns the addr 194 // It seems the HW force-aligns the addr
144 // to 2 if data.len() >= 2 195 // to 2 if data.len() >= 2
145 // to 4 if data.len() >= 4 196 // to 4 if data.len() >= 4
@@ -196,23 +247,32 @@ where
196 } 247 }
197 248
198 async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 { 249 async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 {
250 trace!("backplane_readn addr = {:08x} len = {}", addr, len);
251
199 self.backplane_set_window(addr).await; 252 self.backplane_set_window(addr).await;
200 253
201 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; 254 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
202 if len == 4 { 255 if len == 4 {
203 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG 256 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG;
204 } 257 }
205 self.readn(FUNC_BACKPLANE, bus_addr, len).await 258
259 let val = self.readn(FUNC_BACKPLANE, bus_addr, len).await;
260
261 trace!("backplane_readn addr = {:08x} len = {} val = {:08x}", addr, len, val);
262
263 return val;
206 } 264 }
207 265
208 async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) { 266 async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) {
267 trace!("backplane_writen addr = {:08x} len = {} val = {:08x}", addr, len, val);
268
209 self.backplane_set_window(addr).await; 269 self.backplane_set_window(addr).await;
210 270
211 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; 271 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
212 if len == 4 { 272 if len == 4 {
213 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG 273 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG;
214 } 274 }
215 self.writen(FUNC_BACKPLANE, bus_addr, val, len).await 275 self.writen(FUNC_BACKPLANE, bus_addr, val, len).await;
216 } 276 }
217 277
218 async fn backplane_set_window(&mut self, addr: u32) { 278 async fn backplane_set_window(&mut self, addr: u32) {
@@ -293,8 +353,8 @@ where
293 self.status = self.spi.cmd_write(&[cmd, val]).await; 353 self.status = self.spi.cmd_write(&[cmd, val]).await;
294 } 354 }
295 355
296 async fn read32_swapped(&mut self, addr: u32) -> u32 { 356 async fn read32_swapped(&mut self, func: u32, addr: u32) -> u32 {
297 let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); 357 let cmd = cmd_word(READ, INC_ADDR, func, addr, 4);
298 let cmd = swap16(cmd); 358 let cmd = swap16(cmd);
299 let mut buf = [0; 1]; 359 let mut buf = [0; 1];
300 360
@@ -303,8 +363,8 @@ where
303 swap16(buf[0]) 363 swap16(buf[0])
304 } 364 }
305 365
306 async fn write32_swapped(&mut self, addr: u32, val: u32) { 366 async fn write32_swapped(&mut self, func: u32, addr: u32, val: u32) {
307 let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); 367 let cmd = cmd_word(WRITE, INC_ADDR, func, addr, 4);
308 let buf = [swap16(cmd), swap16(val)]; 368 let buf = [swap16(cmd), swap16(val)];
309 369
310 self.status = self.spi.cmd_write(&buf).await; 370 self.status = self.spi.cmd_write(&buf).await;
diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs
index 4e2836f3b..b6e22e61d 100644
--- a/cyw43/src/consts.rs
+++ b/cyw43/src/consts.rs
@@ -5,19 +5,33 @@ pub(crate) const FUNC_BACKPLANE: u32 = 1;
5pub(crate) const FUNC_WLAN: u32 = 2; 5pub(crate) const FUNC_WLAN: u32 = 2;
6pub(crate) const FUNC_BT: u32 = 3; 6pub(crate) const FUNC_BT: u32 = 3;
7 7
8// Register addresses
8pub(crate) const REG_BUS_CTRL: u32 = 0x0; 9pub(crate) const REG_BUS_CTRL: u32 = 0x0;
10pub(crate) const REG_BUS_RESPONSE_DELAY: u32 = 0x1;
11pub(crate) const REG_BUS_STATUS_ENABLE: u32 = 0x2;
9pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status 12pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status
10pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask 13pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask
11pub(crate) const REG_BUS_STATUS: u32 = 0x8; 14pub(crate) const REG_BUS_STATUS: u32 = 0x8;
12pub(crate) const REG_BUS_TEST_RO: u32 = 0x14; 15pub(crate) const REG_BUS_TEST_RO: u32 = 0x14;
13pub(crate) const REG_BUS_TEST_RW: u32 = 0x18; 16pub(crate) const REG_BUS_TEST_RW: u32 = 0x18;
14pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c; 17pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c;
18
19// SPI_BUS_CONTROL Bits
15pub(crate) const WORD_LENGTH_32: u32 = 0x1; 20pub(crate) const WORD_LENGTH_32: u32 = 0x1;
21pub(crate) const ENDIAN_BIG: u32 = 0x2;
22pub(crate) const CLOCK_PHASE: u32 = 0x4;
23pub(crate) const CLOCK_POLARITY: u32 = 0x8;
16pub(crate) const HIGH_SPEED: u32 = 0x10; 24pub(crate) const HIGH_SPEED: u32 = 0x10;
17pub(crate) const INTERRUPT_HIGH: u32 = 1 << 5; 25pub(crate) const INTERRUPT_POLARITY_HIGH: u32 = 0x20;
18pub(crate) const WAKE_UP: u32 = 1 << 7; 26pub(crate) const WAKE_UP: u32 = 0x80;
19pub(crate) const STATUS_ENABLE: u32 = 1 << 16; 27
20pub(crate) const INTERRUPT_WITH_STATUS: u32 = 1 << 17; 28// SPI_STATUS_ENABLE bits
29pub(crate) const STATUS_ENABLE: u32 = 0x01;
30pub(crate) const INTR_WITH_STATUS: u32 = 0x02;
31pub(crate) const RESP_DELAY_ALL: u32 = 0x04;
32pub(crate) const DWORD_PKT_LEN_EN: u32 = 0x08;
33pub(crate) const CMD_ERR_CHK_EN: u32 = 0x20;
34pub(crate) const DATA_ERR_CHK_EN: u32 = 0x40;
21 35
22// SPI_STATUS_REGISTER bits 36// SPI_STATUS_REGISTER bits
23pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001; 37pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001;
@@ -51,6 +65,13 @@ pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C;
51pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E; 65pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E;
52pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F; 66pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F;
53 67
68pub(crate) const I_HMB_SW_MASK: u32 = 0x000000f0;
69pub(crate) const I_HMB_FC_CHANGE: u32 = 1 << 5;
70pub(crate) const SDIO_INT_STATUS: u32 = 0x20;
71pub(crate) const SDIO_INT_HOST_MASK: u32 = 0x24;
72
73pub(crate) const SPI_F2_WATERMARK: u8 = 0x20;
74
54pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000; 75pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000;
55pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF; 76pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF;
56pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000; 77pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000;
@@ -119,6 +140,44 @@ pub(crate) const WPA2_SECURITY: u32 = 0x00400000;
119pub(crate) const MIN_PSK_LEN: usize = 8; 140pub(crate) const MIN_PSK_LEN: usize = 8;
120pub(crate) const MAX_PSK_LEN: usize = 64; 141pub(crate) const MAX_PSK_LEN: usize = 64;
121 142
143// Bluetooth firmware extraction constants.
144pub(crate) const BTFW_ADDR_MODE_UNKNOWN: i32 = 0;
145pub(crate) const BTFW_ADDR_MODE_EXTENDED: i32 = 1;
146pub(crate) const BTFW_ADDR_MODE_SEGMENT: i32 = 2;
147pub(crate) const BTFW_ADDR_MODE_LINEAR32: i32 = 3;
148
149pub(crate) const BTFW_HEX_LINE_TYPE_DATA: u8 = 0;
150pub(crate) const BTFW_HEX_LINE_TYPE_END_OF_DATA: u8 = 1;
151pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS: u8 = 2;
152pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS: u8 = 4;
153pub(crate) const BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS: u8 = 5;
154
155// Bluetooth constants.
156pub(crate) const SPI_RESP_DELAY_F1: u32 = 0x001d;
157pub(crate) const WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE: u8 = 4;
158
159pub(crate) const BT2WLAN_PWRUP_WAKE: u32 = 3;
160pub(crate) const BT2WLAN_PWRUP_ADDR: u32 = 0x640894;
161
162pub(crate) const BT_CTRL_REG_ADDR: u32 = 0x18000c7c;
163pub(crate) const HOST_CTRL_REG_ADDR: u32 = 0x18000d6c;
164pub(crate) const WLAN_RAM_BASE_REG_ADDR: u32 = 0x18000d68;
165
166pub(crate) const BTSDIO_REG_DATA_VALID_BITMASK: u32 = 1 << 1;
167pub(crate) const BTSDIO_REG_BT_AWAKE_BITMASK: u32 = 1 << 8;
168pub(crate) const BTSDIO_REG_WAKE_BT_BITMASK: u32 = 1 << 17;
169pub(crate) const BTSDIO_REG_SW_RDY_BITMASK: u32 = 1 << 24;
170pub(crate) const BTSDIO_REG_FW_RDY_BITMASK: u32 = 1 << 24;
171
172pub(crate) const BTSDIO_FWBUF_SIZE: u32 = 0x1000;
173pub(crate) const BTSDIO_OFFSET_HOST_WRITE_BUF: u32 = 0;
174pub(crate) const BTSDIO_OFFSET_HOST_READ_BUF: u32 = BTSDIO_FWBUF_SIZE;
175
176pub(crate) const BTSDIO_OFFSET_HOST2BT_IN: u32 = 0x00002000;
177pub(crate) const BTSDIO_OFFSET_HOST2BT_OUT: u32 = 0x00002004;
178pub(crate) const BTSDIO_OFFSET_BT2HOST_IN: u32 = 0x00002008;
179pub(crate) const BTSDIO_OFFSET_BT2HOST_OUT: u32 = 0x0000200C;
180
122// Security type (authentication and encryption types are combined using bit mask) 181// Security type (authentication and encryption types are combined using bit mask)
123#[allow(non_camel_case_types)] 182#[allow(non_camel_case_types)]
124#[derive(Copy, Clone, PartialEq)] 183#[derive(Copy, Clone, PartialEq)]
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index f0f179e2e..22c52bd96 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -83,8 +83,7 @@ impl<'a> Control<'a> {
83 } 83 }
84 } 84 }
85 85
86 /// Initialize WiFi controller. 86 async fn load_clm(&mut self, clm: &[u8]) {
87 pub async fn init(&mut self, clm: &[u8]) {
88 const CHUNK_SIZE: usize = 1024; 87 const CHUNK_SIZE: usize = 1024;
89 88
90 debug!("Downloading CLM..."); 89 debug!("Downloading CLM...");
@@ -116,6 +115,11 @@ impl<'a> Control<'a> {
116 115
117 // check clmload ok 116 // check clmload ok
118 assert_eq!(self.get_iovar_u32("clmload_status").await, 0); 117 assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
118 }
119
120 /// Initialize WiFi controller.
121 pub async fn init(&mut self, clm: &[u8]) {
122 self.load_clm(&clm).await;
119 123
120 debug!("Configuring misc stuff..."); 124 debug!("Configuring misc stuff...");
121 125
@@ -186,7 +190,7 @@ impl<'a> Control<'a> {
186 190
187 self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr)); 191 self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr));
188 192
189 debug!("INIT DONE"); 193 debug!("cyw43 control init done");
190 } 194 }
191 195
192 /// Set the WiFi interface up. 196 /// Set the WiFi interface up.
diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs
index 7c8f35da7..efeb3f313 100644
--- a/cyw43/src/lib.rs
+++ b/cyw43/src/lib.rs
@@ -8,18 +8,18 @@
8// This mod MUST go first, so that the others see its macros. 8// This mod MUST go first, so that the others see its macros.
9pub(crate) mod fmt; 9pub(crate) mod fmt;
10 10
11#[cfg(feature = "bluetooth")]
12mod bluetooth;
11mod bus; 13mod bus;
12mod consts; 14mod consts;
15mod control;
13mod countries; 16mod countries;
14mod events; 17mod events;
15mod ioctl; 18mod ioctl;
16mod structs;
17
18mod control;
19mod nvram; 19mod nvram;
20mod runner; 20mod runner;
21 21mod structs;
22use core::slice; 22mod util;
23 23
24use embassy_net_driver_channel as ch; 24use embassy_net_driver_channel as ch;
25use embedded_hal_1::digital::OutputPin; 25use embedded_hal_1::digital::OutputPin;
@@ -56,6 +56,7 @@ impl Core {
56struct Chip { 56struct Chip {
57 arm_core_base_address: u32, 57 arm_core_base_address: u32,
58 socsram_base_address: u32, 58 socsram_base_address: u32,
59 bluetooth_base_address: u32,
59 socsram_wrapper_base_address: u32, 60 socsram_wrapper_base_address: u32,
60 sdiod_core_base_address: u32, 61 sdiod_core_base_address: u32,
61 pmu_base_address: u32, 62 pmu_base_address: u32,
@@ -83,6 +84,7 @@ const WRAPPER_REGISTER_OFFSET: u32 = 0x100000;
83const CHIP: Chip = Chip { 84const CHIP: Chip = Chip {
84 arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET, 85 arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET,
85 socsram_base_address: 0x18004000, 86 socsram_base_address: 0x18004000,
87 bluetooth_base_address: 0x19000000,
86 socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET, 88 socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET,
87 sdiod_core_base_address: 0x18002000, 89 sdiod_core_base_address: 0x18002000,
88 pmu_base_address: 0x18000000, 90 pmu_base_address: 0x18000000,
@@ -107,6 +109,12 @@ const CHIP: Chip = Chip {
107/// Driver state. 109/// Driver state.
108pub struct State { 110pub struct State {
109 ioctl_state: IoctlState, 111 ioctl_state: IoctlState,
112 net: NetState,
113 #[cfg(feature = "bluetooth")]
114 bt: bluetooth::BtState,
115}
116
117struct NetState {
110 ch: ch::State<MTU, 4, 4>, 118 ch: ch::State<MTU, 4, 4>,
111 events: Events, 119 events: Events,
112} 120}
@@ -116,8 +124,12 @@ impl State {
116 pub fn new() -> Self { 124 pub fn new() -> Self {
117 Self { 125 Self {
118 ioctl_state: IoctlState::new(), 126 ioctl_state: IoctlState::new(),
119 ch: ch::State::new(), 127 net: NetState {
120 events: Events::new(), 128 ch: ch::State::new(),
129 events: Events::new(),
130 },
131 #[cfg(feature = "bluetooth")]
132 bt: bluetooth::BtState::new(),
121 } 133 }
122 } 134 }
123} 135}
@@ -225,21 +237,60 @@ where
225 PWR: OutputPin, 237 PWR: OutputPin,
226 SPI: SpiBusCyw43, 238 SPI: SpiBusCyw43,
227{ 239{
228 let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6])); 240 let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
229 let state_ch = ch_runner.state_runner(); 241 let state_ch = ch_runner.state_runner();
230 242
231 let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events); 243 let mut runner = Runner::new(
244 ch_runner,
245 Bus::new(pwr, spi),
246 &state.ioctl_state,
247 &state.net.events,
248 #[cfg(feature = "bluetooth")]
249 None,
250 );
232 251
233 runner.init(firmware).await; 252 runner.init(firmware, None).await;
253 let control = Control::new(state_ch, &state.net.events, &state.ioctl_state);
234 254
235 ( 255 (device, control, runner)
236 device,
237 Control::new(state_ch, &state.events, &state.ioctl_state),
238 runner,
239 )
240} 256}
241 257
242fn slice8_mut(x: &mut [u32]) -> &mut [u8] { 258/// Create a new instance of the CYW43 driver.
243 let len = x.len() * 4; 259///
244 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } 260/// Returns a handle to the network device, control handle and a runner for driving the low level
261/// stack.
262#[cfg(feature = "bluetooth")]
263pub async fn new_with_bluetooth<'a, PWR, SPI>(
264 state: &'a mut State,
265 pwr: PWR,
266 spi: SPI,
267 wifi_firmware: &[u8],
268 bluetooth_firmware: &[u8],
269) -> (
270 NetDriver<'a>,
271 bluetooth::BtDriver<'a>,
272 Control<'a>,
273 Runner<'a, PWR, SPI>,
274)
275where
276 PWR: OutputPin,
277 SPI: SpiBusCyw43,
278{
279 let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
280 let state_ch = ch_runner.state_runner();
281
282 let (bt_runner, bt_driver) = bluetooth::new(&mut state.bt);
283 let mut runner = Runner::new(
284 ch_runner,
285 Bus::new(pwr, spi),
286 &state.ioctl_state,
287 &state.net.events,
288 #[cfg(feature = "bluetooth")]
289 Some(bt_runner),
290 );
291
292 runner.init(wifi_firmware, Some(bluetooth_firmware)).await;
293 let control = Control::new(state_ch, &state.net.events, &state.ioctl_state);
294
295 (device, bt_driver, control, runner)
245} 296}
diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs
index e90316302..6522d40fa 100644
--- a/cyw43/src/runner.rs
+++ b/cyw43/src/runner.rs
@@ -1,4 +1,4 @@
1use embassy_futures::select::{select3, Either3}; 1use embassy_futures::select::{select4, Either4};
2use embassy_net_driver_channel as ch; 2use embassy_net_driver_channel as ch;
3use embassy_time::{block_for, Duration, Timer}; 3use embassy_time::{block_for, Duration, Timer};
4use embedded_hal_1::digital::OutputPin; 4use embedded_hal_1::digital::OutputPin;
@@ -11,7 +11,8 @@ use crate::fmt::Bytes;
11use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; 11use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
12use crate::nvram::NVRAM; 12use crate::nvram::NVRAM;
13use crate::structs::*; 13use crate::structs::*;
14use crate::{events, slice8_mut, Core, CHIP, MTU}; 14use crate::util::slice8_mut;
15use crate::{events, Core, CHIP, MTU};
15 16
16#[cfg(feature = "firmware-logs")] 17#[cfg(feature = "firmware-logs")]
17struct LogState { 18struct LogState {
@@ -36,7 +37,7 @@ impl Default for LogState {
36/// Driver communicating with the WiFi chip. 37/// Driver communicating with the WiFi chip.
37pub struct Runner<'a, PWR, SPI> { 38pub struct Runner<'a, PWR, SPI> {
38 ch: ch::Runner<'a, MTU>, 39 ch: ch::Runner<'a, MTU>,
39 bus: Bus<PWR, SPI>, 40 pub(crate) bus: Bus<PWR, SPI>,
40 41
41 ioctl_state: &'a IoctlState, 42 ioctl_state: &'a IoctlState,
42 ioctl_id: u16, 43 ioctl_id: u16,
@@ -47,6 +48,9 @@ pub struct Runner<'a, PWR, SPI> {
47 48
48 #[cfg(feature = "firmware-logs")] 49 #[cfg(feature = "firmware-logs")]
49 log: LogState, 50 log: LogState,
51
52 #[cfg(feature = "bluetooth")]
53 pub(crate) bt: Option<crate::bluetooth::BtRunner<'a>>,
50} 54}
51 55
52impl<'a, PWR, SPI> Runner<'a, PWR, SPI> 56impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
@@ -59,6 +63,7 @@ where
59 bus: Bus<PWR, SPI>, 63 bus: Bus<PWR, SPI>,
60 ioctl_state: &'a IoctlState, 64 ioctl_state: &'a IoctlState,
61 events: &'a Events, 65 events: &'a Events,
66 #[cfg(feature = "bluetooth")] bt: Option<crate::bluetooth::BtRunner<'a>>,
62 ) -> Self { 67 ) -> Self {
63 Self { 68 Self {
64 ch, 69 ch,
@@ -70,33 +75,52 @@ where
70 events, 75 events,
71 #[cfg(feature = "firmware-logs")] 76 #[cfg(feature = "firmware-logs")]
72 log: LogState::default(), 77 log: LogState::default(),
78 #[cfg(feature = "bluetooth")]
79 bt,
73 } 80 }
74 } 81 }
75 82
76 pub(crate) async fn init(&mut self, firmware: &[u8]) { 83 pub(crate) async fn init(&mut self, wifi_fw: &[u8], bt_fw: Option<&[u8]>) {
77 self.bus.init().await; 84 self.bus.init(bt_fw.is_some()).await;
78 85
79 // Init ALP (Active Low Power) clock 86 // Init ALP (Active Low Power) clock
87 debug!("init alp");
80 self.bus 88 self.bus
81 .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ) 89 .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ)
82 .await; 90 .await;
91
92 debug!("set f2 watermark");
93 self.bus
94 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 0x10)
95 .await;
96 let watermark = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK).await;
97 debug!("watermark = {:02x}", watermark);
98 assert!(watermark == 0x10);
99
83 debug!("waiting for clock..."); 100 debug!("waiting for clock...");
84 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {} 101 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
85 debug!("clock ok"); 102 debug!("clock ok");
86 103
104 // clear request for ALP
105 debug!("clear request for ALP");
106 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0).await;
107
87 let chip_id = self.bus.bp_read16(0x1800_0000).await; 108 let chip_id = self.bus.bp_read16(0x1800_0000).await;
88 debug!("chip ID: {}", chip_id); 109 debug!("chip ID: {}", chip_id);
89 110
90 // Upload firmware. 111 // Upload firmware.
91 self.core_disable(Core::WLAN).await; 112 self.core_disable(Core::WLAN).await;
113 self.core_disable(Core::SOCSRAM).await; // TODO: is this needed if we reset right after?
92 self.core_reset(Core::SOCSRAM).await; 114 self.core_reset(Core::SOCSRAM).await;
115
116 // this is 4343x specific stuff: Disable remap for SRAM_3
93 self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await; 117 self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await;
94 self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await; 118 self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await;
95 119
96 let ram_addr = CHIP.atcm_ram_base_address; 120 let ram_addr = CHIP.atcm_ram_base_address;
97 121
98 debug!("loading fw"); 122 debug!("loading fw");
99 self.bus.bp_write(ram_addr, firmware).await; 123 self.bus.bp_write(ram_addr, wifi_fw).await;
100 124
101 debug!("loading nvram"); 125 debug!("loading nvram");
102 // Round up to 4 bytes. 126 // Round up to 4 bytes.
@@ -116,10 +140,23 @@ where
116 self.core_reset(Core::WLAN).await; 140 self.core_reset(Core::WLAN).await;
117 assert!(self.core_is_up(Core::WLAN).await); 141 assert!(self.core_is_up(Core::WLAN).await);
118 142
143 // wait until HT clock is available; takes about 29ms
144 debug!("wait for HT clock");
119 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} 145 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
120 146
121 // "Set up the interrupt mask and enable interrupts" 147 // "Set up the interrupt mask and enable interrupts"
122 // self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await; 148 debug!("setup interrupt mask");
149 self.bus
150 .bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_SW_MASK)
151 .await;
152
153 // Set up the interrupt mask and enable interrupts
154 if bt_fw.is_some() {
155 debug!("bluetooth setup interrupt mask");
156 self.bus
157 .bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_FC_CHANGE)
158 .await;
159 }
123 160
124 self.bus 161 self.bus
125 .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE) 162 .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE)
@@ -128,11 +165,11 @@ where
128 // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped." 165 // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
129 // Sounds scary... 166 // Sounds scary...
130 self.bus 167 self.bus
131 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32) 168 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, SPI_F2_WATERMARK)
132 .await; 169 .await;
133 170
134 // wait for wifi startup 171 // wait for F2 to be ready
135 debug!("waiting for wifi init..."); 172 debug!("waiting for F2 to be ready...");
136 while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {} 173 while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
137 174
138 // Some random configs related to sleep. 175 // Some random configs related to sleep.
@@ -153,19 +190,27 @@ where
153 */ 190 */
154 191
155 // clear pulls 192 // clear pulls
193 debug!("clear pad pulls");
156 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await; 194 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
157 let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await; 195 let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
158 196
159 // start HT clock 197 // start HT clock
160 //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await; 198 self.bus
161 //debug!("waiting for HT clock..."); 199 .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10)
162 //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} 200 .await; // SBSDIO_HT_AVAIL_REQ
163 //debug!("clock ok"); 201 debug!("waiting for HT clock...");
202 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
203 debug!("clock ok");
164 204
165 #[cfg(feature = "firmware-logs")] 205 #[cfg(feature = "firmware-logs")]
166 self.log_init().await; 206 self.log_init().await;
167 207
168 debug!("wifi init done"); 208 #[cfg(feature = "bluetooth")]
209 if let Some(bt_fw) = bt_fw {
210 self.bt.as_mut().unwrap().init_bluetooth(&mut self.bus, bt_fw).await;
211 }
212
213 debug!("cyw43 runner init done");
169 } 214 }
170 215
171 #[cfg(feature = "firmware-logs")] 216 #[cfg(feature = "firmware-logs")]
@@ -222,7 +267,7 @@ where
222 } 267 }
223 } 268 }
224 269
225 /// Run the 270 /// Run the CYW43 event handling loop.
226 pub async fn run(mut self) -> ! { 271 pub async fn run(mut self) -> ! {
227 let mut buf = [0; 512]; 272 let mut buf = [0; 512];
228 loop { 273 loop {
@@ -231,11 +276,27 @@ where
231 276
232 if self.has_credit() { 277 if self.has_credit() {
233 let ioctl = self.ioctl_state.wait_pending(); 278 let ioctl = self.ioctl_state.wait_pending();
234 let tx = self.ch.tx_buf(); 279 let wifi_tx = self.ch.tx_buf();
280 #[cfg(feature = "bluetooth")]
281 let bt_tx = async {
282 match &mut self.bt {
283 Some(bt) => bt.tx_chan.receive().await,
284 None => core::future::pending().await,
285 }
286 };
287 #[cfg(not(feature = "bluetooth"))]
288 let bt_tx = core::future::pending::<()>();
289
290 // interrupts aren't working yet for bluetooth. Do busy-polling instead.
291 // Note for this to work `ev` has to go last in the `select()`. It prefers
292 // first futures if they're ready, so other select branches don't get starved.`
293 #[cfg(feature = "bluetooth")]
294 let ev = core::future::ready(());
295 #[cfg(not(feature = "bluetooth"))]
235 let ev = self.bus.wait_for_event(); 296 let ev = self.bus.wait_for_event();
236 297
237 match select3(ioctl, tx, ev).await { 298 match select4(ioctl, wifi_tx, bt_tx, ev).await {
238 Either3::First(PendingIoctl { 299 Either4::First(PendingIoctl {
239 buf: iobuf, 300 buf: iobuf,
240 kind, 301 kind,
241 cmd, 302 cmd,
@@ -244,7 +305,7 @@ where
244 self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await; 305 self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await;
245 self.check_status(&mut buf).await; 306 self.check_status(&mut buf).await;
246 } 307 }
247 Either3::Second(packet) => { 308 Either4::Second(packet) => {
248 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); 309 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
249 310
250 let buf8 = slice8_mut(&mut buf); 311 let buf8 = slice8_mut(&mut buf);
@@ -298,7 +359,11 @@ where
298 self.ch.tx_done(); 359 self.ch.tx_done();
299 self.check_status(&mut buf).await; 360 self.check_status(&mut buf).await;
300 } 361 }
301 Either3::Third(()) => { 362 Either4::Third(_) => {
363 #[cfg(feature = "bluetooth")]
364 self.bt.as_mut().unwrap().hci_write(&mut self.bus).await;
365 }
366 Either4::Fourth(()) => {
302 self.handle_irq(&mut buf).await; 367 self.handle_irq(&mut buf).await;
303 } 368 }
304 } 369 }
@@ -314,17 +379,24 @@ where
314 async fn handle_irq(&mut self, buf: &mut [u32; 512]) { 379 async fn handle_irq(&mut self, buf: &mut [u32; 512]) {
315 // Receive stuff 380 // Receive stuff
316 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; 381 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
317 trace!("irq{}", FormatInterrupt(irq)); 382 if irq != 0 {
383 trace!("irq{}", FormatInterrupt(irq));
384 }
318 385
319 if irq & IRQ_F2_PACKET_AVAILABLE != 0 { 386 if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
320 self.check_status(buf).await; 387 self.check_status(buf).await;
321 } 388 }
322 389
323 if irq & IRQ_DATA_UNAVAILABLE != 0 { 390 if irq & IRQ_DATA_UNAVAILABLE != 0 {
324 // TODO what should we do here? 391 // this seems to be ignorable with no ill effects.
325 warn!("IRQ DATA_UNAVAILABLE, clearing..."); 392 trace!("IRQ DATA_UNAVAILABLE, clearing...");
326 self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await; 393 self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await;
327 } 394 }
395
396 #[cfg(feature = "bluetooth")]
397 if let Some(bt) = &mut self.bt {
398 bt.handle_irq(&mut self.bus).await;
399 }
328 } 400 }
329 401
330 /// Handle F2 events while status register is set 402 /// Handle F2 events while status register is set
diff --git a/cyw43/src/util.rs b/cyw43/src/util.rs
new file mode 100644
index 000000000..a4adbd4ed
--- /dev/null
+++ b/cyw43/src/util.rs
@@ -0,0 +1,20 @@
1#![allow(unused)]
2
3use core::slice;
4
5pub(crate) fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
6 let len = x.len() * 4;
7 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
8}
9
10pub(crate) fn is_aligned(a: u32, x: u32) -> bool {
11 (a & (x - 1)) == 0
12}
13
14pub(crate) fn round_down(x: u32, a: u32) -> u32 {
15 x & !(a - 1)
16}
17
18pub(crate) fn round_up(x: u32, a: u32) -> u32 {
19 ((x + a - 1) / a) * a
20}
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 4945f4bd2..2884ca85a 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -16,8 +16,8 @@ embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defm
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } 18embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } 19cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] }
20cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } 20cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] }
21 21
22defmt = "0.3" 22defmt = "0.3"
23defmt-rtt = "0.4" 23defmt-rtt = "0.4"
@@ -59,9 +59,22 @@ pio = "0.2.1"
59rand = { version = "0.8.5", default-features = false } 59rand = { version = "0.8.5", default-features = false }
60embedded-sdmmc = "0.7.0" 60embedded-sdmmc = "0.7.0"
61 61
62bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] }
63trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] }
64
62[profile.release] 65[profile.release]
63debug = 2 66debug = 2
64 67
65[profile.dev] 68[profile.dev]
66lto = true 69lto = true
67opt-level = "z" 70opt-level = "z"
71
72[patch.crates-io]
73trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" }
74bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" }
75embassy-executor = { path = "../../embassy-executor" }
76embassy-sync = { path = "../../embassy-sync" }
77embassy-futures = { path = "../../embassy-futures" }
78embassy-time = { path = "../../embassy-time" }
79embassy-time-driver = { path = "../../embassy-time-driver" }
80embassy-embedded-hal = { path = "../../embassy-embedded-hal" }
diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs
new file mode 100644
index 000000000..901521b60
--- /dev/null
+++ b/examples/rp/src/bin/bluetooth.rs
@@ -0,0 +1,148 @@
1//! This example test the RP Pico W on board LED.
2//!
3//! It does not work with the RP Pico board. See blinky.rs.
4
5#![no_std]
6#![no_main]
7
8use bt_hci::controller::ExternalController;
9use cyw43_pio::PioSpi;
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_futures::join::join3;
13use embassy_rp::bind_interrupts;
14use embassy_rp::gpio::{Level, Output};
15use embassy_rp::peripherals::{DMA_CH0, PIO0};
16use embassy_rp::pio::{InterruptHandler, Pio};
17use embassy_sync::blocking_mutex::raw::NoopRawMutex;
18use embassy_time::{Duration, Timer};
19use static_cell::StaticCell;
20use trouble_host::advertise::{AdStructure, Advertisement, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE};
21use trouble_host::attribute::{AttributeTable, CharacteristicProp, Service, Uuid};
22use trouble_host::gatt::GattEvent;
23use trouble_host::{Address, BleHost, BleHostResources, PacketQos};
24use {defmt_rtt as _, embassy_time as _, panic_probe as _};
25
26bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28});
29
30#[embassy_executor::task]
31async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
32 runner.run().await
33}
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 let p = embassy_rp::init(Default::default());
38 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
39 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
40 let btfw = include_bytes!("../../../../cyw43-firmware/43439A0_btfw.bin");
41
42 // To make flashing faster for development, you may want to flash the firmwares independently
43 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
44 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
45 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
46 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
47 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
48
49 let pwr = Output::new(p.PIN_23, Level::Low);
50 let cs = Output::new(p.PIN_25, Level::High);
51 let mut pio = Pio::new(p.PIO0, Irqs);
52 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
53
54 static STATE: StaticCell<cyw43::State> = StaticCell::new();
55 let state = STATE.init(cyw43::State::new());
56 let (_net_device, bt_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await;
57 unwrap!(spawner.spawn(cyw43_task(runner)));
58 control.init(clm).await;
59
60 let controller: ExternalController<_, 10> = ExternalController::new(bt_device);
61 static HOST_RESOURCES: StaticCell<BleHostResources<4, 32, 27>> = StaticCell::new();
62 let host_resources = HOST_RESOURCES.init(BleHostResources::new(PacketQos::None));
63
64 let mut ble: BleHost<'_, _> = BleHost::new(controller, host_resources);
65
66 ble.set_random_address(Address::random([0xff, 0x9f, 0x1a, 0x05, 0xe4, 0xff]));
67 let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new();
68
69 // Generic Access Service (mandatory)
70 let id = b"Pico W Bluetooth";
71 let appearance = [0x80, 0x07];
72 let mut bat_level = [0; 1];
73 let handle = {
74 let mut svc = table.add_service(Service::new(0x1800));
75 let _ = svc.add_characteristic_ro(0x2a00, id);
76 let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]);
77 svc.build();
78
79 // Generic attribute service (mandatory)
80 table.add_service(Service::new(0x1801));
81
82 // Battery service
83 let mut svc = table.add_service(Service::new(0x180f));
84
85 svc.add_characteristic(
86 0x2a19,
87 &[CharacteristicProp::Read, CharacteristicProp::Notify],
88 &mut bat_level,
89 )
90 .build()
91 };
92
93 let mut adv_data = [0; 31];
94 AdStructure::encode_slice(
95 &[
96 AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED),
97 AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]),
98 AdStructure::CompleteLocalName(b"Pico W Bluetooth"),
99 ],
100 &mut adv_data[..],
101 )
102 .unwrap();
103
104 let server = ble.gatt_server(&table);
105
106 info!("Starting advertising and GATT service");
107 let _ = join3(
108 ble.run(),
109 async {
110 loop {
111 match server.next().await {
112 Ok(GattEvent::Write { handle, connection: _ }) => {
113 let _ = table.get(handle, |value| {
114 info!("Write event. Value written: {:?}", value);
115 });
116 }
117 Ok(GattEvent::Read { .. }) => {
118 info!("Read event");
119 }
120 Err(e) => {
121 error!("Error processing GATT events: {:?}", e);
122 }
123 }
124 }
125 },
126 async {
127 let mut advertiser = ble
128 .advertise(
129 &Default::default(),
130 Advertisement::ConnectableScannableUndirected {
131 adv_data: &adv_data[..],
132 scan_data: &[],
133 },
134 )
135 .await
136 .unwrap();
137 let conn = advertiser.accept().await.unwrap();
138 // Keep connection alive
139 let mut tick: u8 = 0;
140 loop {
141 Timer::after(Duration::from_secs(10)).await;
142 tick += 1;
143 server.notify(handle, &conn, &[tick]).await.unwrap();
144 }
145 },
146 )
147 .await;
148}
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index 4fc2690e3..b5fbd8e36 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -28,7 +28,7 @@ bind_interrupts!(struct Irqs {
28}); 28});
29 29
30#[embassy_executor::task] 30#[embassy_executor::task]
31async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 31async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
32 runner.run().await 32 runner.run().await
33} 33}
34 34
@@ -62,7 +62,7 @@ async fn main(spawner: Spawner) {
62 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 62 static STATE: StaticCell<cyw43::State> = StaticCell::new();
63 let state = STATE.init(cyw43::State::new()); 63 let state = STATE.init(cyw43::State::new());
64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
65 unwrap!(spawner.spawn(wifi_task(runner))); 65 unwrap!(spawner.spawn(cyw43_task(runner)));
66 66
67 control.init(clm).await; 67 control.init(clm).await;
68 control 68 control
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
index 471349639..04a61bbd5 100644
--- a/examples/rp/src/bin/wifi_blinky.rs
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs {
21}); 21});
22 22
23#[embassy_executor::task] 23#[embassy_executor::task]
24async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 24async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
25 runner.run().await 25 runner.run().await
26} 26}
27 27
@@ -46,7 +46,7 @@ async fn main(spawner: Spawner) {
46 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 46 static STATE: StaticCell<cyw43::State> = StaticCell::new();
47 let state = STATE.init(cyw43::State::new()); 47 let state = STATE.init(cyw43::State::new());
48 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 48 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
49 unwrap!(spawner.spawn(wifi_task(runner))); 49 unwrap!(spawner.spawn(cyw43_task(runner)));
50 50
51 control.init(clm).await; 51 control.init(clm).await;
52 control 52 control
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index 5f4c848a2..ab3529112 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -23,7 +23,7 @@ bind_interrupts!(struct Irqs {
23}); 23});
24 24
25#[embassy_executor::task] 25#[embassy_executor::task]
26async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 26async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
27 runner.run().await 27 runner.run().await
28} 28}
29 29
@@ -56,7 +56,7 @@ async fn main(spawner: Spawner) {
56 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 56 static STATE: StaticCell<cyw43::State> = StaticCell::new();
57 let state = STATE.init(cyw43::State::new()); 57 let state = STATE.init(cyw43::State::new());
58 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 58 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
59 unwrap!(spawner.spawn(wifi_task(runner))); 59 unwrap!(spawner.spawn(cyw43_task(runner)));
60 60
61 control.init(clm).await; 61 control.init(clm).await;
62 control 62 control
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index 5575df677..87487cbe8 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -27,11 +27,11 @@ bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>; 27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28}); 28});
29 29
30const WIFI_NETWORK: &str = "EmbassyTest"; 30const WIFI_NETWORK: &str = "LadronDeWifi";
31const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; 31const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8";
32 32
33#[embassy_executor::task] 33#[embassy_executor::task]
34async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 34async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
35 runner.run().await 35 runner.run().await
36} 36}
37 37
@@ -65,7 +65,7 @@ async fn main(spawner: Spawner) {
65 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 65 static STATE: StaticCell<cyw43::State> = StaticCell::new();
66 let state = STATE.init(cyw43::State::new()); 66 let state = STATE.init(cyw43::State::new());
67 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 67 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
68 unwrap!(spawner.spawn(wifi_task(runner))); 68 unwrap!(spawner.spawn(cyw43_task(runner)));
69 69
70 control.init(clm).await; 70 control.init(clm).await;
71 control 71 control
diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs
index 70b6f0949..e32be6e45 100644
--- a/examples/rp/src/bin/wifi_webrequest.rs
+++ b/examples/rp/src/bin/wifi_webrequest.rs
@@ -34,7 +34,7 @@ const WIFI_NETWORK: &str = "ssid"; // change to your network SSID
34const WIFI_PASSWORD: &str = "pwd"; // change to your network password 34const WIFI_PASSWORD: &str = "pwd"; // change to your network password
35 35
36#[embassy_executor::task] 36#[embassy_executor::task]
37async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 37async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
38 runner.run().await 38 runner.run().await
39} 39}
40 40
@@ -67,7 +67,7 @@ async fn main(spawner: Spawner) {
67 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 67 static STATE: StaticCell<cyw43::State> = StaticCell::new();
68 let state = STATE.init(cyw43::State::new()); 68 let state = STATE.init(cyw43::State::new());
69 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 69 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
70 unwrap!(spawner.spawn(wifi_task(runner))); 70 unwrap!(spawner.spawn(cyw43_task(runner)));
71 71
72 control.init(clm).await; 72 control.init(clm).await;
73 control 73 control