aboutsummaryrefslogtreecommitdiff
path: root/cyw43/src/bluetooth.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cyw43/src/bluetooth.rs')
-rw-r--r--cyw43/src/bluetooth.rs508
1 files changed, 508 insertions, 0 deletions
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}