diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-08-05 20:58:04 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2024-08-05 21:07:42 +0200 |
| commit | 4f7ac1946a43379306aa432961fb97bba1139a6e (patch) | |
| tree | 2589e67baa770acf244dfdea355e16585d683d16 | |
| parent | afc8e684dd16c3bc947b365ca293f0f37d95b342 (diff) | |
cyw43: add Bluetooth support.
Co-Authored-By: Brandon Ros <[email protected]>
| -rwxr-xr-x | ci.sh | 2 | ||||
| -rw-r--r--[-rwxr-xr-x] | cyw43-firmware/43439A0.bin | bin | 230321 -> 231077 bytes | |||
| -rw-r--r-- | cyw43-firmware/43439A0_btfw.bin | bin | 0 -> 6164 bytes | |||
| -rw-r--r--[-rwxr-xr-x] | cyw43-firmware/43439A0_clm.bin | bin | 4752 -> 984 bytes | |||
| -rw-r--r-- | cyw43-firmware/README.md | 11 | ||||
| -rw-r--r-- | cyw43-pio/src/lib.rs | 9 | ||||
| -rw-r--r-- | cyw43/Cargo.toml | 8 | ||||
| -rw-r--r-- | cyw43/src/bluetooth.rs | 508 | ||||
| -rw-r--r-- | cyw43/src/bus.rs | 90 | ||||
| -rw-r--r-- | cyw43/src/consts.rs | 67 | ||||
| -rw-r--r-- | cyw43/src/control.rs | 10 | ||||
| -rw-r--r-- | cyw43/src/lib.rs | 87 | ||||
| -rw-r--r-- | cyw43/src/runner.rs | 120 | ||||
| -rw-r--r-- | cyw43/src/util.rs | 20 | ||||
| -rw-r--r-- | examples/rp/Cargo.toml | 17 | ||||
| -rw-r--r-- | examples/rp/src/bin/bluetooth.rs | 148 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_ap_tcp_server.rs | 4 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_blinky.rs | 4 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_scan.rs | 4 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_tcp_server.rs | 8 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_webrequest.rs | 4 |
21 files changed, 1037 insertions, 84 deletions
| @@ -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 | ||
| 3 | Firmware obtained from https://github.com/Infineon/wifi-host-driver/tree/master/WiFi_Host_Driver/resources/firmware/COMPONENT_43439 | 3 | Firmware obtained from https://github.com/georgerobotics/cyw43-driver/tree/main/firmware |
| 4 | 4 | ||
| 5 | Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt) | 5 | Licensed 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 | |||
| 14 | If 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" | |||
| 10 | documentation = "https://docs.embassy.dev/cyw43" | 10 | documentation = "https://docs.embassy.dev/cyw43" |
| 11 | 11 | ||
| 12 | [features] | 12 | [features] |
| 13 | defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt"] | 13 | defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt", "bt-hci?/defmt", "embedded-io-async?/defmt-03"] |
| 14 | log = ["dep:log"] | 14 | log = ["dep:log"] |
| 15 | bluetooth = ["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`. |
| 17 | firmware-logs = [] | 18 | firmware-logs = [] |
| @@ -31,9 +32,12 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa | |||
| 31 | 32 | ||
| 32 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | 33 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } |
| 33 | num_enum = { version = "0.5.7", default-features = false } | 34 | num_enum = { version = "0.5.7", default-features = false } |
| 34 | |||
| 35 | heapless = "0.8.0" | 35 | heapless = "0.8.0" |
| 36 | 36 | ||
| 37 | # Bluetooth deps | ||
| 38 | embedded-io-async = { version = "0.6.0", optional = true } | ||
| 39 | bt-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] |
| 38 | src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" | 42 | src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" |
| 39 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" | 43 | src_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 @@ | |||
| 1 | use core::cell::RefCell; | ||
| 2 | use core::future::Future; | ||
| 3 | use core::mem::MaybeUninit; | ||
| 4 | |||
| 5 | use bt_hci::transport::WithIndicator; | ||
| 6 | use bt_hci::{ControllerToHostPacket, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci}; | ||
| 7 | use embassy_futures::yield_now; | ||
| 8 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 9 | use embassy_sync::zerocopy_channel; | ||
| 10 | use embassy_time::{Duration, Timer}; | ||
| 11 | use embedded_hal_1::digital::OutputPin; | ||
| 12 | |||
| 13 | use crate::bus::Bus; | ||
| 14 | pub use crate::bus::SpiBusCyw43; | ||
| 15 | use crate::consts::*; | ||
| 16 | use crate::util::round_up; | ||
| 17 | use crate::{util, CHIP}; | ||
| 18 | |||
| 19 | pub(crate) struct BtState { | ||
| 20 | rx: [BtPacketBuf; 4], | ||
| 21 | tx: [BtPacketBuf; 4], | ||
| 22 | inner: MaybeUninit<BtStateInnre<'static>>, | ||
| 23 | } | ||
| 24 | |||
| 25 | impl 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 | |||
| 35 | struct BtStateInnre<'d> { | ||
| 36 | rx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>, | ||
| 37 | tx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>, | ||
| 38 | } | ||
| 39 | |||
| 40 | /// Bluetooth driver. | ||
| 41 | pub struct BtDriver<'d> { | ||
| 42 | rx: RefCell<zerocopy_channel::Receiver<'d, NoopRawMutex, BtPacketBuf>>, | ||
| 43 | tx: RefCell<zerocopy_channel::Sender<'d, NoopRawMutex, BtPacketBuf>>, | ||
| 44 | } | ||
| 45 | |||
| 46 | pub(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 | |||
| 56 | const BT_HCI_MTU: usize = 1024; | ||
| 57 | |||
| 58 | /// Represents a packet of size MTU. | ||
| 59 | pub(crate) struct BtPacketBuf { | ||
| 60 | pub(crate) len: usize, | ||
| 61 | pub(crate) buf: [u8; BT_HCI_MTU], | ||
| 62 | } | ||
| 63 | |||
| 64 | impl 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 | |||
| 74 | pub(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 | |||
| 104 | pub(crate) struct CybtFwCb<'a> { | ||
| 105 | pub p_next_line_start: &'a [u8], | ||
| 106 | } | ||
| 107 | |||
| 108 | pub(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 | |||
| 115 | pub(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 | |||
| 167 | impl<'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 | |||
| 475 | impl<'d> embedded_io_async::ErrorType for BtDriver<'d> { | ||
| 476 | type Error = core::convert::Infallible; | ||
| 477 | } | ||
| 478 | |||
| 479 | impl<'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; | |||
| 4 | use futures::FutureExt; | 4 | use futures::FutureExt; |
| 5 | 5 | ||
| 6 | use crate::consts::*; | 6 | use crate::consts::*; |
| 7 | use crate::slice8_mut; | 7 | use 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; | |||
| 5 | pub(crate) const FUNC_WLAN: u32 = 2; | 5 | pub(crate) const FUNC_WLAN: u32 = 2; |
| 6 | pub(crate) const FUNC_BT: u32 = 3; | 6 | pub(crate) const FUNC_BT: u32 = 3; |
| 7 | 7 | ||
| 8 | // Register addresses | ||
| 8 | pub(crate) const REG_BUS_CTRL: u32 = 0x0; | 9 | pub(crate) const REG_BUS_CTRL: u32 = 0x0; |
| 10 | pub(crate) const REG_BUS_RESPONSE_DELAY: u32 = 0x1; | ||
| 11 | pub(crate) const REG_BUS_STATUS_ENABLE: u32 = 0x2; | ||
| 9 | pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status | 12 | pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status |
| 10 | pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask | 13 | pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask |
| 11 | pub(crate) const REG_BUS_STATUS: u32 = 0x8; | 14 | pub(crate) const REG_BUS_STATUS: u32 = 0x8; |
| 12 | pub(crate) const REG_BUS_TEST_RO: u32 = 0x14; | 15 | pub(crate) const REG_BUS_TEST_RO: u32 = 0x14; |
| 13 | pub(crate) const REG_BUS_TEST_RW: u32 = 0x18; | 16 | pub(crate) const REG_BUS_TEST_RW: u32 = 0x18; |
| 14 | pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c; | 17 | pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c; |
| 18 | |||
| 19 | // SPI_BUS_CONTROL Bits | ||
| 15 | pub(crate) const WORD_LENGTH_32: u32 = 0x1; | 20 | pub(crate) const WORD_LENGTH_32: u32 = 0x1; |
| 21 | pub(crate) const ENDIAN_BIG: u32 = 0x2; | ||
| 22 | pub(crate) const CLOCK_PHASE: u32 = 0x4; | ||
| 23 | pub(crate) const CLOCK_POLARITY: u32 = 0x8; | ||
| 16 | pub(crate) const HIGH_SPEED: u32 = 0x10; | 24 | pub(crate) const HIGH_SPEED: u32 = 0x10; |
| 17 | pub(crate) const INTERRUPT_HIGH: u32 = 1 << 5; | 25 | pub(crate) const INTERRUPT_POLARITY_HIGH: u32 = 0x20; |
| 18 | pub(crate) const WAKE_UP: u32 = 1 << 7; | 26 | pub(crate) const WAKE_UP: u32 = 0x80; |
| 19 | pub(crate) const STATUS_ENABLE: u32 = 1 << 16; | 27 | |
| 20 | pub(crate) const INTERRUPT_WITH_STATUS: u32 = 1 << 17; | 28 | // SPI_STATUS_ENABLE bits |
| 29 | pub(crate) const STATUS_ENABLE: u32 = 0x01; | ||
| 30 | pub(crate) const INTR_WITH_STATUS: u32 = 0x02; | ||
| 31 | pub(crate) const RESP_DELAY_ALL: u32 = 0x04; | ||
| 32 | pub(crate) const DWORD_PKT_LEN_EN: u32 = 0x08; | ||
| 33 | pub(crate) const CMD_ERR_CHK_EN: u32 = 0x20; | ||
| 34 | pub(crate) const DATA_ERR_CHK_EN: u32 = 0x40; | ||
| 21 | 35 | ||
| 22 | // SPI_STATUS_REGISTER bits | 36 | // SPI_STATUS_REGISTER bits |
| 23 | pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001; | 37 | pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001; |
| @@ -51,6 +65,13 @@ pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C; | |||
| 51 | pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E; | 65 | pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E; |
| 52 | pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F; | 66 | pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F; |
| 53 | 67 | ||
| 68 | pub(crate) const I_HMB_SW_MASK: u32 = 0x000000f0; | ||
| 69 | pub(crate) const I_HMB_FC_CHANGE: u32 = 1 << 5; | ||
| 70 | pub(crate) const SDIO_INT_STATUS: u32 = 0x20; | ||
| 71 | pub(crate) const SDIO_INT_HOST_MASK: u32 = 0x24; | ||
| 72 | |||
| 73 | pub(crate) const SPI_F2_WATERMARK: u8 = 0x20; | ||
| 74 | |||
| 54 | pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000; | 75 | pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000; |
| 55 | pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF; | 76 | pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF; |
| 56 | pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000; | 77 | pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000; |
| @@ -119,6 +140,44 @@ pub(crate) const WPA2_SECURITY: u32 = 0x00400000; | |||
| 119 | pub(crate) const MIN_PSK_LEN: usize = 8; | 140 | pub(crate) const MIN_PSK_LEN: usize = 8; |
| 120 | pub(crate) const MAX_PSK_LEN: usize = 64; | 141 | pub(crate) const MAX_PSK_LEN: usize = 64; |
| 121 | 142 | ||
| 143 | // Bluetooth firmware extraction constants. | ||
| 144 | pub(crate) const BTFW_ADDR_MODE_UNKNOWN: i32 = 0; | ||
| 145 | pub(crate) const BTFW_ADDR_MODE_EXTENDED: i32 = 1; | ||
| 146 | pub(crate) const BTFW_ADDR_MODE_SEGMENT: i32 = 2; | ||
| 147 | pub(crate) const BTFW_ADDR_MODE_LINEAR32: i32 = 3; | ||
| 148 | |||
| 149 | pub(crate) const BTFW_HEX_LINE_TYPE_DATA: u8 = 0; | ||
| 150 | pub(crate) const BTFW_HEX_LINE_TYPE_END_OF_DATA: u8 = 1; | ||
| 151 | pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS: u8 = 2; | ||
| 152 | pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS: u8 = 4; | ||
| 153 | pub(crate) const BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS: u8 = 5; | ||
| 154 | |||
| 155 | // Bluetooth constants. | ||
| 156 | pub(crate) const SPI_RESP_DELAY_F1: u32 = 0x001d; | ||
| 157 | pub(crate) const WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE: u8 = 4; | ||
| 158 | |||
| 159 | pub(crate) const BT2WLAN_PWRUP_WAKE: u32 = 3; | ||
| 160 | pub(crate) const BT2WLAN_PWRUP_ADDR: u32 = 0x640894; | ||
| 161 | |||
| 162 | pub(crate) const BT_CTRL_REG_ADDR: u32 = 0x18000c7c; | ||
| 163 | pub(crate) const HOST_CTRL_REG_ADDR: u32 = 0x18000d6c; | ||
| 164 | pub(crate) const WLAN_RAM_BASE_REG_ADDR: u32 = 0x18000d68; | ||
| 165 | |||
| 166 | pub(crate) const BTSDIO_REG_DATA_VALID_BITMASK: u32 = 1 << 1; | ||
| 167 | pub(crate) const BTSDIO_REG_BT_AWAKE_BITMASK: u32 = 1 << 8; | ||
| 168 | pub(crate) const BTSDIO_REG_WAKE_BT_BITMASK: u32 = 1 << 17; | ||
| 169 | pub(crate) const BTSDIO_REG_SW_RDY_BITMASK: u32 = 1 << 24; | ||
| 170 | pub(crate) const BTSDIO_REG_FW_RDY_BITMASK: u32 = 1 << 24; | ||
| 171 | |||
| 172 | pub(crate) const BTSDIO_FWBUF_SIZE: u32 = 0x1000; | ||
| 173 | pub(crate) const BTSDIO_OFFSET_HOST_WRITE_BUF: u32 = 0; | ||
| 174 | pub(crate) const BTSDIO_OFFSET_HOST_READ_BUF: u32 = BTSDIO_FWBUF_SIZE; | ||
| 175 | |||
| 176 | pub(crate) const BTSDIO_OFFSET_HOST2BT_IN: u32 = 0x00002000; | ||
| 177 | pub(crate) const BTSDIO_OFFSET_HOST2BT_OUT: u32 = 0x00002004; | ||
| 178 | pub(crate) const BTSDIO_OFFSET_BT2HOST_IN: u32 = 0x00002008; | ||
| 179 | pub(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. |
| 9 | pub(crate) mod fmt; | 9 | pub(crate) mod fmt; |
| 10 | 10 | ||
| 11 | #[cfg(feature = "bluetooth")] | ||
| 12 | mod bluetooth; | ||
| 11 | mod bus; | 13 | mod bus; |
| 12 | mod consts; | 14 | mod consts; |
| 15 | mod control; | ||
| 13 | mod countries; | 16 | mod countries; |
| 14 | mod events; | 17 | mod events; |
| 15 | mod ioctl; | 18 | mod ioctl; |
| 16 | mod structs; | ||
| 17 | |||
| 18 | mod control; | ||
| 19 | mod nvram; | 19 | mod nvram; |
| 20 | mod runner; | 20 | mod runner; |
| 21 | 21 | mod structs; | |
| 22 | use core::slice; | 22 | mod util; |
| 23 | 23 | ||
| 24 | use embassy_net_driver_channel as ch; | 24 | use embassy_net_driver_channel as ch; |
| 25 | use embedded_hal_1::digital::OutputPin; | 25 | use embedded_hal_1::digital::OutputPin; |
| @@ -56,6 +56,7 @@ impl Core { | |||
| 56 | struct Chip { | 56 | struct 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; | |||
| 83 | const CHIP: Chip = Chip { | 84 | const 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. |
| 108 | pub struct State { | 110 | pub struct State { |
| 109 | ioctl_state: IoctlState, | 111 | ioctl_state: IoctlState, |
| 112 | net: NetState, | ||
| 113 | #[cfg(feature = "bluetooth")] | ||
| 114 | bt: bluetooth::BtState, | ||
| 115 | } | ||
| 116 | |||
| 117 | struct 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 | ||
| 242 | fn 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")] | ||
| 263 | pub 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 | ) | ||
| 275 | where | ||
| 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 @@ | |||
| 1 | use embassy_futures::select::{select3, Either3}; | 1 | use embassy_futures::select::{select4, Either4}; |
| 2 | use embassy_net_driver_channel as ch; | 2 | use embassy_net_driver_channel as ch; |
| 3 | use embassy_time::{block_for, Duration, Timer}; | 3 | use embassy_time::{block_for, Duration, Timer}; |
| 4 | use embedded_hal_1::digital::OutputPin; | 4 | use embedded_hal_1::digital::OutputPin; |
| @@ -11,7 +11,8 @@ use crate::fmt::Bytes; | |||
| 11 | use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; | 11 | use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; |
| 12 | use crate::nvram::NVRAM; | 12 | use crate::nvram::NVRAM; |
| 13 | use crate::structs::*; | 13 | use crate::structs::*; |
| 14 | use crate::{events, slice8_mut, Core, CHIP, MTU}; | 14 | use crate::util::slice8_mut; |
| 15 | use crate::{events, Core, CHIP, MTU}; | ||
| 15 | 16 | ||
| 16 | #[cfg(feature = "firmware-logs")] | 17 | #[cfg(feature = "firmware-logs")] |
| 17 | struct LogState { | 18 | struct LogState { |
| @@ -36,7 +37,7 @@ impl Default for LogState { | |||
| 36 | /// Driver communicating with the WiFi chip. | 37 | /// Driver communicating with the WiFi chip. |
| 37 | pub struct Runner<'a, PWR, SPI> { | 38 | pub 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 | ||
| 52 | impl<'a, PWR, SPI> Runner<'a, PWR, SPI> | 56 | impl<'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 | |||
| 3 | use core::slice; | ||
| 4 | |||
| 5 | pub(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 | |||
| 10 | pub(crate) fn is_aligned(a: u32, x: u32) -> bool { | ||
| 11 | (a & (x - 1)) == 0 | ||
| 12 | } | ||
| 13 | |||
| 14 | pub(crate) fn round_down(x: u32, a: u32) -> u32 { | ||
| 15 | x & !(a - 1) | ||
| 16 | } | ||
| 17 | |||
| 18 | pub(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 | |||
| 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } | 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } |
| 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 18 | embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } | 18 | embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } |
| 19 | cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } | 19 | cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] } |
| 20 | cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } | 20 | cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } |
| 21 | 21 | ||
| 22 | defmt = "0.3" | 22 | defmt = "0.3" |
| 23 | defmt-rtt = "0.4" | 23 | defmt-rtt = "0.4" |
| @@ -59,9 +59,22 @@ pio = "0.2.1" | |||
| 59 | rand = { version = "0.8.5", default-features = false } | 59 | rand = { version = "0.8.5", default-features = false } |
| 60 | embedded-sdmmc = "0.7.0" | 60 | embedded-sdmmc = "0.7.0" |
| 61 | 61 | ||
| 62 | bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } | ||
| 63 | trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } | ||
| 64 | |||
| 62 | [profile.release] | 65 | [profile.release] |
| 63 | debug = 2 | 66 | debug = 2 |
| 64 | 67 | ||
| 65 | [profile.dev] | 68 | [profile.dev] |
| 66 | lto = true | 69 | lto = true |
| 67 | opt-level = "z" | 70 | opt-level = "z" |
| 71 | |||
| 72 | [patch.crates-io] | ||
| 73 | trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } | ||
| 74 | bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" } | ||
| 75 | embassy-executor = { path = "../../embassy-executor" } | ||
| 76 | embassy-sync = { path = "../../embassy-sync" } | ||
| 77 | embassy-futures = { path = "../../embassy-futures" } | ||
| 78 | embassy-time = { path = "../../embassy-time" } | ||
| 79 | embassy-time-driver = { path = "../../embassy-time-driver" } | ||
| 80 | embassy-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 | |||
| 8 | use bt_hci::controller::ExternalController; | ||
| 9 | use cyw43_pio::PioSpi; | ||
| 10 | use defmt::*; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_futures::join::join3; | ||
| 13 | use embassy_rp::bind_interrupts; | ||
| 14 | use embassy_rp::gpio::{Level, Output}; | ||
| 15 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | ||
| 16 | use embassy_rp::pio::{InterruptHandler, Pio}; | ||
| 17 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 18 | use embassy_time::{Duration, Timer}; | ||
| 19 | use static_cell::StaticCell; | ||
| 20 | use trouble_host::advertise::{AdStructure, Advertisement, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE}; | ||
| 21 | use trouble_host::attribute::{AttributeTable, CharacteristicProp, Service, Uuid}; | ||
| 22 | use trouble_host::gatt::GattEvent; | ||
| 23 | use trouble_host::{Address, BleHost, BleHostResources, PacketQos}; | ||
| 24 | use {defmt_rtt as _, embassy_time as _, panic_probe as _}; | ||
| 25 | |||
| 26 | bind_interrupts!(struct Irqs { | ||
| 27 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 28 | }); | ||
| 29 | |||
| 30 | #[embassy_executor::task] | ||
| 31 | async 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] | ||
| 36 | async 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] |
| 31 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 31 | async 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] |
| 24 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 24 | async 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] |
| 26 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 26 | async 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 | ||
| 30 | const WIFI_NETWORK: &str = "EmbassyTest"; | 30 | const WIFI_NETWORK: &str = "LadronDeWifi"; |
| 31 | const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; | 31 | const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8"; |
| 32 | 32 | ||
| 33 | #[embassy_executor::task] | 33 | #[embassy_executor::task] |
| 34 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 34 | async 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 | |||
| 34 | const WIFI_PASSWORD: &str = "pwd"; // change to your network password | 34 | const WIFI_PASSWORD: &str = "pwd"; // change to your network password |
| 35 | 35 | ||
| 36 | #[embassy_executor::task] | 36 | #[embassy_executor::task] |
| 37 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 37 | async 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 |
