blend firmware + HCI PRs together to call out design problem
This commit is contained in:
parent
4d1de8766d
commit
a9ba5145e2
@ -25,6 +25,7 @@ cortex-m-rt = "0.7.0"
|
|||||||
futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
|
futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
|
||||||
|
|
||||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-rc.1" }
|
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-rc.1" }
|
||||||
|
embedded-io-async = { version = "0.5.0", features = ["defmt-03"] }
|
||||||
num_enum = { version = "0.5.7", default-features = false }
|
num_enum = { version = "0.5.7", default-features = false }
|
||||||
|
|
||||||
[package.metadata.embassy_docs]
|
[package.metadata.embassy_docs]
|
||||||
|
@ -1,30 +1,17 @@
|
|||||||
use embassy_time::{Duration, Timer};
|
|
||||||
use embedded_hal_1::digital::OutputPin;
|
|
||||||
|
|
||||||
use crate::bus::Bus;
|
|
||||||
use crate::consts::*;
|
use crate::consts::*;
|
||||||
use crate::{SpiBusCyw43, CHIP};
|
|
||||||
|
|
||||||
struct CybtFwCb<'a> {
|
pub(crate) struct CybtFwCb<'a> {
|
||||||
p_next_line_start: &'a [u8],
|
pub p_next_line_start: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HexFileData<'a> {
|
pub(crate) struct HexFileData<'a> {
|
||||||
addr_mode: i32,
|
pub addr_mode: i32,
|
||||||
hi_addr: u16,
|
pub hi_addr: u16,
|
||||||
dest_addr: u32,
|
pub dest_addr: u32,
|
||||||
p_ds: &'a mut [u8],
|
pub p_ds: &'a mut [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_aligned(a: u32, x: u32) -> bool {
|
pub(crate) fn read_firmware_patch_line(p_btfw_cb: &mut CybtFwCb, hfd: &mut HexFileData) -> u32 {
|
||||||
(a & (x - 1)) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn round_down(x: u32, a: u32) -> u32 {
|
|
||||||
x & !(a - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_firmware_patch_line(p_btfw_cb: &mut CybtFwCb, hfd: &mut HexFileData) -> u32 {
|
|
||||||
let mut abs_base_addr32 = 0;
|
let mut abs_base_addr32 = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -75,171 +62,3 @@ fn read_firmware_patch_line(p_btfw_cb: &mut CybtFwCb, hfd: &mut HexFileData) ->
|
|||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn upload_bluetooth_firmware<PWR: OutputPin, SPI: SpiBusCyw43>(
|
|
||||||
bus: &mut Bus<PWR, SPI>,
|
|
||||||
firmware: &[u8],
|
|
||||||
) {
|
|
||||||
// read version
|
|
||||||
let version_length = firmware[0];
|
|
||||||
let _version = &firmware[1..=version_length as usize];
|
|
||||||
// skip version + 1 extra byte as per cybt_shared_bus_driver.c
|
|
||||||
let firmware = &firmware[version_length as usize + 2..];
|
|
||||||
// buffers
|
|
||||||
let mut data_buffer: [u8; 0x100] = [0; 0x100];
|
|
||||||
let mut aligned_data_buffer: [u8; 0x100] = [0; 0x100];
|
|
||||||
// structs
|
|
||||||
let mut btfw_cb = CybtFwCb {
|
|
||||||
p_next_line_start: firmware,
|
|
||||||
};
|
|
||||||
let mut hfd = HexFileData {
|
|
||||||
addr_mode: BTFW_ADDR_MODE_EXTENDED,
|
|
||||||
hi_addr: 0,
|
|
||||||
dest_addr: 0,
|
|
||||||
p_ds: &mut data_buffer,
|
|
||||||
};
|
|
||||||
loop {
|
|
||||||
let num_fw_bytes = read_firmware_patch_line(&mut btfw_cb, &mut hfd);
|
|
||||||
if num_fw_bytes == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let fw_bytes = &hfd.p_ds[0..num_fw_bytes as usize];
|
|
||||||
let mut dest_start_addr = hfd.dest_addr + CHIP.bluetooth_base_address;
|
|
||||||
let mut aligned_data_buffer_index: usize = 0;
|
|
||||||
// pad start
|
|
||||||
if !is_aligned(dest_start_addr, 4) {
|
|
||||||
let num_pad_bytes = dest_start_addr % 4;
|
|
||||||
let padded_dest_start_addr = round_down(dest_start_addr, 4);
|
|
||||||
let memory_value = bus.bp_read32(padded_dest_start_addr).await;
|
|
||||||
let memory_value_bytes = memory_value.to_le_bytes(); // TODO: le or be
|
|
||||||
// Copy the previous memory value's bytes to the start
|
|
||||||
for i in 0..num_pad_bytes as usize {
|
|
||||||
aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i];
|
|
||||||
aligned_data_buffer_index += 1;
|
|
||||||
}
|
|
||||||
// Copy the firmware bytes after the padding bytes
|
|
||||||
for i in 0..num_fw_bytes as usize {
|
|
||||||
aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
|
|
||||||
aligned_data_buffer_index += 1;
|
|
||||||
}
|
|
||||||
dest_start_addr = padded_dest_start_addr;
|
|
||||||
} else {
|
|
||||||
// Directly copy fw_bytes into aligned_data_buffer if no start padding is required
|
|
||||||
for i in 0..num_fw_bytes as usize {
|
|
||||||
aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
|
|
||||||
aligned_data_buffer_index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// pad end
|
|
||||||
let mut dest_end_addr = dest_start_addr + aligned_data_buffer_index as u32;
|
|
||||||
if !is_aligned(dest_end_addr, 4) {
|
|
||||||
let offset = dest_end_addr % 4;
|
|
||||||
let num_pad_bytes_end = 4 - offset;
|
|
||||||
let padded_dest_end_addr = round_down(dest_end_addr, 4);
|
|
||||||
let memory_value = bus.bp_read32(padded_dest_end_addr).await;
|
|
||||||
let memory_value_bytes = memory_value.to_le_bytes(); // TODO: le or be
|
|
||||||
// Append the necessary memory bytes to pad the end of aligned_data_buffer
|
|
||||||
for i in offset..4 {
|
|
||||||
aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i as usize];
|
|
||||||
aligned_data_buffer_index += 1;
|
|
||||||
}
|
|
||||||
dest_end_addr += num_pad_bytes_end;
|
|
||||||
} else {
|
|
||||||
// pad end alignment not needed
|
|
||||||
}
|
|
||||||
let buffer_to_write = &aligned_data_buffer[0..aligned_data_buffer_index as usize];
|
|
||||||
assert!(dest_start_addr % 4 == 0);
|
|
||||||
assert!(dest_end_addr % 4 == 0);
|
|
||||||
assert!(aligned_data_buffer_index % 4 == 0);
|
|
||||||
// write in 0x40 chunks TODO: is this needed or can we write straight away
|
|
||||||
let chunk_size = 0x40;
|
|
||||||
for (i, chunk) in buffer_to_write.chunks(chunk_size).enumerate() {
|
|
||||||
let offset = i * chunk_size;
|
|
||||||
bus.bp_write(dest_start_addr + (offset as u32), chunk).await;
|
|
||||||
}
|
|
||||||
// sleep TODO: is this needed
|
|
||||||
Timer::after(Duration::from_millis(1)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn wait_bt_ready<PWR: OutputPin, SPI: SpiBusCyw43>(bus: &mut Bus<PWR, SPI>) {
|
|
||||||
debug!("wait_bt_ready");
|
|
||||||
let mut success = false;
|
|
||||||
for _ in 0..300 {
|
|
||||||
let val = bus.bp_read32(BT_CTRL_REG_ADDR).await;
|
|
||||||
// TODO: do we need to swap endianness on this read?
|
|
||||||
debug!("BT_CTRL_REG_ADDR = {:08x}", val);
|
|
||||||
if val & BTSDIO_REG_FW_RDY_BITMASK != 0 {
|
|
||||||
success = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Timer::after(Duration::from_millis(1)).await;
|
|
||||||
}
|
|
||||||
assert!(success == true);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn wait_bt_awake<PWR: OutputPin, SPI: SpiBusCyw43>(bus: &mut Bus<PWR, SPI>) {
|
|
||||||
debug!("wait_bt_awake");
|
|
||||||
let mut success = false;
|
|
||||||
for _ in 0..300 {
|
|
||||||
let val = bus.bp_read32(BT_CTRL_REG_ADDR).await;
|
|
||||||
// TODO: do we need to swap endianness on this read?
|
|
||||||
debug!("BT_CTRL_REG_ADDR = {:08x}", val);
|
|
||||||
if val & BTSDIO_REG_BT_AWAKE_BITMASK != 0 {
|
|
||||||
success = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Timer::after(Duration::from_millis(1)).await;
|
|
||||||
}
|
|
||||||
assert!(success == true);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn bt_set_host_ready<PWR: OutputPin, SPI: SpiBusCyw43>(bus: &mut Bus<PWR, SPI>) {
|
|
||||||
debug!("bt_set_host_ready");
|
|
||||||
let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
|
||||||
// TODO: do we need to swap endianness on this read?
|
|
||||||
let new_val = old_val | BTSDIO_REG_SW_RDY_BITMASK;
|
|
||||||
bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use this
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) async fn bt_set_awake<PWR: OutputPin, SPI: SpiBusCyw43>(bus: &mut Bus<PWR, SPI>) {
|
|
||||||
debug!("bt_set_awake");
|
|
||||||
let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
|
||||||
// TODO: do we need to swap endianness on this read?
|
|
||||||
let new_val = old_val | BTSDIO_REG_WAKE_BT_BITMASK;
|
|
||||||
bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn bt_toggle_intr<PWR: OutputPin, SPI: SpiBusCyw43>(bus: &mut Bus<PWR, SPI>) {
|
|
||||||
debug!("bt_toggle_intr");
|
|
||||||
let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
|
||||||
// TODO: do we need to swap endianness on this read?
|
|
||||||
let new_val = old_val ^ BTSDIO_REG_DATA_VALID_BITMASK;
|
|
||||||
bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use this
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) async fn bt_set_intr<PWR: OutputPin, SPI: SpiBusCyw43>(bus: &mut Bus<PWR, SPI>) {
|
|
||||||
debug!("bt_set_intr");
|
|
||||||
let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
|
||||||
let new_val = old_val | BTSDIO_REG_DATA_VALID_BITMASK;
|
|
||||||
bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn init_bluetooth<PWR: OutputPin, SPI: SpiBusCyw43>(bus: &mut Bus<PWR, SPI>, firmware: &[u8]) {
|
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
|
||||||
debug!("init_bluetooth");
|
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
|
||||||
bus.bp_write32(CHIP.bluetooth_base_address + BT2WLAN_PWRUP_ADDR, BT2WLAN_PWRUP_WAKE)
|
|
||||||
.await;
|
|
||||||
Timer::after(Duration::from_millis(2)).await;
|
|
||||||
upload_bluetooth_firmware(bus, firmware).await;
|
|
||||||
wait_bt_ready(bus).await;
|
|
||||||
// TODO: cybt_init_buffer();
|
|
||||||
wait_bt_awake(bus).await;
|
|
||||||
bt_set_host_ready(bus).await;
|
|
||||||
bt_toggle_intr(bus).await;
|
|
||||||
}
|
|
||||||
|
@ -4,7 +4,7 @@ use embedded_hal_1::digital::OutputPin;
|
|||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
|
||||||
use crate::consts::*;
|
use crate::consts::*;
|
||||||
use crate::slice8_mut;
|
use crate::utilities;
|
||||||
|
|
||||||
/// Custom Spi Trait that _only_ supports the bus operation of the cyw43
|
/// Custom Spi Trait that _only_ supports the bus operation of the cyw43
|
||||||
/// Implementors are expected to hold the CS pin low during an operation.
|
/// Implementors are expected to hold the CS pin low during an operation.
|
||||||
@ -48,7 +48,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn init(&mut self) {
|
pub async fn init(&mut self, bluetooth_enabled: bool) {
|
||||||
// Reset
|
// Reset
|
||||||
debug!("WL_REG off/on");
|
debug!("WL_REG off/on");
|
||||||
self.pwr.set_low().unwrap();
|
self.pwr.set_low().unwrap();
|
||||||
@ -122,18 +122,16 @@ where
|
|||||||
// Enable a selection of interrupts
|
// Enable a selection of interrupts
|
||||||
// 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
|
// 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
|
||||||
debug!("enable a selection of interrupts");
|
debug!("enable a selection of interrupts");
|
||||||
self.write16(
|
let mut val = IRQ_F2_F3_FIFO_RD_UNDERFLOW
|
||||||
FUNC_BUS,
|
| IRQ_F2_F3_FIFO_WR_OVERFLOW
|
||||||
REG_BUS_INTERRUPT_ENABLE,
|
| IRQ_COMMAND_ERROR
|
||||||
IRQ_F2_F3_FIFO_RD_UNDERFLOW
|
| IRQ_DATA_ERROR
|
||||||
| IRQ_F2_F3_FIFO_WR_OVERFLOW
|
| IRQ_F2_PACKET_AVAILABLE
|
||||||
| IRQ_COMMAND_ERROR
|
| IRQ_F1_OVERFLOW;
|
||||||
| IRQ_DATA_ERROR
|
if bluetooth_enabled {
|
||||||
| IRQ_F2_PACKET_AVAILABLE
|
val = val | IRQ_F1_INTR;
|
||||||
| IRQ_F1_OVERFLOW
|
}
|
||||||
| IRQ_F1_INTR,
|
self.write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, val).await;
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) {
|
pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) {
|
||||||
@ -155,6 +153,8 @@ where
|
|||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) {
|
pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) {
|
||||||
|
debug!("bp_read addr = {:08x}", addr);
|
||||||
|
|
||||||
// It seems the HW force-aligns the addr
|
// It seems the HW force-aligns the addr
|
||||||
// to 2 if data.len() >= 2
|
// to 2 if data.len() >= 2
|
||||||
// to 4 if data.len() >= 4
|
// to 4 if data.len() >= 4
|
||||||
@ -179,7 +179,7 @@ where
|
|||||||
self.status = self.spi.cmd_read(cmd, &mut buf[..(len + 3) / 4 + 1]).await;
|
self.status = self.spi.cmd_read(cmd, &mut buf[..(len + 3) / 4 + 1]).await;
|
||||||
|
|
||||||
// when writing out the data, we skip the response-delay byte
|
// when writing out the data, we skip the response-delay byte
|
||||||
data[..len].copy_from_slice(&slice8_mut(&mut buf[1..])[..len]);
|
data[..len].copy_from_slice(&utilities::slice8_mut(&mut buf[1..])[..len]);
|
||||||
|
|
||||||
// Advance ptr.
|
// Advance ptr.
|
||||||
addr += len as u32;
|
addr += len as u32;
|
||||||
@ -188,6 +188,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) {
|
pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) {
|
||||||
|
debug!("bp_write addr = {:08x}", addr);
|
||||||
|
|
||||||
// It seems the HW force-aligns the addr
|
// It seems the HW force-aligns the addr
|
||||||
// to 2 if data.len() >= 2
|
// to 2 if data.len() >= 2
|
||||||
// to 4 if data.len() >= 4
|
// to 4 if data.len() >= 4
|
||||||
@ -202,7 +204,7 @@ where
|
|||||||
let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize;
|
let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize;
|
||||||
|
|
||||||
let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining);
|
let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining);
|
||||||
slice8_mut(&mut buf[1..])[..len].copy_from_slice(&data[..len]);
|
utilities::slice8_mut(&mut buf[1..])[..len].copy_from_slice(&data[..len]);
|
||||||
|
|
||||||
self.backplane_set_window(addr).await;
|
self.backplane_set_window(addr).await;
|
||||||
|
|
||||||
|
@ -168,6 +168,15 @@ pub(crate) const BTSDIO_REG_WAKE_BT_BITMASK: u32 = 1 << 17;
|
|||||||
pub(crate) const BTSDIO_REG_SW_RDY_BITMASK: u32 = 1 << 24;
|
pub(crate) const BTSDIO_REG_SW_RDY_BITMASK: u32 = 1 << 24;
|
||||||
pub(crate) const BTSDIO_REG_FW_RDY_BITMASK: u32 = 1 << 24;
|
pub(crate) const BTSDIO_REG_FW_RDY_BITMASK: u32 = 1 << 24;
|
||||||
|
|
||||||
|
pub(crate) const BTSDIO_FWBUF_SIZE: u32 = 0x1000;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_HOST_WRITE_BUF: u32 = 0;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_HOST_READ_BUF: u32 = BTSDIO_FWBUF_SIZE;
|
||||||
|
|
||||||
|
pub(crate) const BTSDIO_OFFSET_HOST2BT_IN: u32 = 0x00002000;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_HOST2BT_OUT: u32 = 0x00002004;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_BT2HOST_IN: u32 = 0x00002008;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_BT2HOST_OUT: u32 = 0x0000200C;
|
||||||
|
|
||||||
// Security type (authentication and encryption types are combined using bit mask)
|
// Security type (authentication and encryption types are combined using bit mask)
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
@ -32,13 +32,11 @@ impl<'a> Control<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn init(&mut self, clm: &[u8]) {
|
async fn load_clm(&mut self, clm: &[u8]) {
|
||||||
const CHUNK_SIZE: usize = 1024;
|
debug!("load_clm");
|
||||||
|
const CLM_CHUNK_SIZE: usize = 1024;
|
||||||
debug!("Downloading CLM...");
|
|
||||||
|
|
||||||
let mut offs = 0;
|
let mut offs = 0;
|
||||||
for chunk in clm.chunks(CHUNK_SIZE) {
|
for chunk in clm.chunks(CLM_CHUNK_SIZE) {
|
||||||
let mut flag = DOWNLOAD_FLAG_HANDLER_VER;
|
let mut flag = DOWNLOAD_FLAG_HANDLER_VER;
|
||||||
if offs == 0 {
|
if offs == 0 {
|
||||||
flag |= DOWNLOAD_FLAG_BEGIN;
|
flag |= DOWNLOAD_FLAG_BEGIN;
|
||||||
@ -54,16 +52,19 @@ impl<'a> Control<'a> {
|
|||||||
len: chunk.len() as _,
|
len: chunk.len() as _,
|
||||||
crc: 0,
|
crc: 0,
|
||||||
};
|
};
|
||||||
let mut buf = [0; 8 + 12 + CHUNK_SIZE];
|
let mut buf = [0; 8 + 12 + CLM_CHUNK_SIZE];
|
||||||
buf[0..8].copy_from_slice(b"clmload\x00");
|
buf[0..8].copy_from_slice(b"clmload\x00");
|
||||||
buf[8..20].copy_from_slice(&header.to_bytes());
|
buf[8..20].copy_from_slice(&header.to_bytes());
|
||||||
buf[20..][..chunk.len()].copy_from_slice(&chunk);
|
buf[20..][..chunk.len()].copy_from_slice(&chunk);
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()])
|
self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()])
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check clmload ok
|
// check clmload ok
|
||||||
assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
|
assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn init(&mut self, clm: &[u8], wifi_enabled: bool, bluetooth_enabled: bool) {
|
||||||
|
self.load_clm(&clm).await;
|
||||||
|
|
||||||
debug!("Configuring misc stuff...");
|
debug!("Configuring misc stuff...");
|
||||||
|
|
||||||
@ -78,64 +79,70 @@ impl<'a> Control<'a> {
|
|||||||
assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
|
assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
|
||||||
debug!("mac addr: {:02x}", Bytes(&mac_addr));
|
debug!("mac addr: {:02x}", Bytes(&mac_addr));
|
||||||
|
|
||||||
let country = countries::WORLD_WIDE_XX;
|
if wifi_enabled {
|
||||||
let country_info = CountryInfo {
|
let country = countries::WORLD_WIDE_XX;
|
||||||
country_abbrev: [country.code[0], country.code[1], 0, 0],
|
let country_info = CountryInfo {
|
||||||
country_code: [country.code[0], country.code[1], 0, 0],
|
country_abbrev: [country.code[0], country.code[1], 0, 0],
|
||||||
rev: if country.rev == 0 { -1 } else { country.rev as _ },
|
country_code: [country.code[0], country.code[1], 0, 0],
|
||||||
};
|
rev: if country.rev == 0 { -1 } else { country.rev as _ },
|
||||||
self.set_iovar("country", &country_info.to_bytes()).await;
|
};
|
||||||
|
self.set_iovar("country", &country_info.to_bytes()).await;
|
||||||
|
|
||||||
// set country takes some time, next ioctls fail if we don't wait.
|
// set country takes some time, next ioctls fail if we don't wait.
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
|
|
||||||
// Set antenna to chip antenna
|
// Set antenna to chip antenna
|
||||||
self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
|
self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
|
||||||
|
|
||||||
self.set_iovar_u32("bus:txglom", 0).await;
|
self.set_iovar_u32("bus:txglom", 0).await;
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
//self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
|
//self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
|
||||||
//Timer::after(Duration::from_millis(100)).await;
|
//Timer::after(Duration::from_millis(100)).await;
|
||||||
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
|
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
self.set_iovar_u32("ampdu_mpdu", 4).await;
|
self.set_iovar_u32("ampdu_mpdu", 4).await;
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
//self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
|
//self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
|
||||||
|
|
||||||
//Timer::after(Duration::from_millis(100)).await;
|
//Timer::after(Duration::from_millis(100)).await;
|
||||||
|
|
||||||
// evts
|
// evts
|
||||||
let mut evts = EventMask {
|
let mut evts = EventMask {
|
||||||
iface: 0,
|
iface: 0,
|
||||||
events: [0xFF; 24],
|
events: [0xFF; 24],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Disable spammy uninteresting events.
|
// Disable spammy uninteresting events.
|
||||||
evts.unset(Event::RADIO);
|
evts.unset(Event::RADIO);
|
||||||
evts.unset(Event::IF);
|
evts.unset(Event::IF);
|
||||||
evts.unset(Event::PROBREQ_MSG);
|
evts.unset(Event::PROBREQ_MSG);
|
||||||
evts.unset(Event::PROBREQ_MSG_RX);
|
evts.unset(Event::PROBREQ_MSG_RX);
|
||||||
evts.unset(Event::PROBRESP_MSG);
|
evts.unset(Event::PROBRESP_MSG);
|
||||||
evts.unset(Event::PROBRESP_MSG);
|
evts.unset(Event::PROBRESP_MSG);
|
||||||
evts.unset(Event::ROAM);
|
evts.unset(Event::ROAM);
|
||||||
|
|
||||||
self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
|
self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
|
|
||||||
// set wifi up
|
// set wifi up
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
|
self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
|
|
||||||
self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
|
self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
|
||||||
self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
|
self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
|
|
||||||
self.state_ch.set_ethernet_address(mac_addr);
|
self.state_ch.set_ethernet_address(mac_addr);
|
||||||
|
}
|
||||||
|
|
||||||
debug!("INIT DONE");
|
if bluetooth_enabled {
|
||||||
|
// TODO: call runner.init_bluetooth somehow and pass it bluetooth_firmware?
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("cyw43 control init done");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
|
pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
|
||||||
|
36
cyw43/src/hci_connector.rs
Normal file
36
cyw43/src/hci_connector.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
pub struct HciConnector {}
|
||||||
|
|
||||||
|
impl HciConnector {
|
||||||
|
pub fn new() -> HciConnector {
|
||||||
|
return HciConnector {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum HciConnectorError {
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_io_async::Error for HciConnectorError {
|
||||||
|
fn kind(&self) -> embedded_io_async::ErrorKind {
|
||||||
|
embedded_io_async::ErrorKind::Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_io_async::ErrorType for HciConnector {
|
||||||
|
type Error = HciConnectorError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_io_async::Read for HciConnector {
|
||||||
|
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, HciConnectorError> {
|
||||||
|
// TODO: how to get all the way to runner.hci_read()?
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_io_async::Write for HciConnector {
|
||||||
|
async fn write(&mut self, buf: &[u8]) -> Result<usize, HciConnectorError> {
|
||||||
|
// TODO: how to get all the way to runner.hci_write()?
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
@ -10,16 +10,15 @@ pub(crate) mod fmt;
|
|||||||
mod bluetooth;
|
mod bluetooth;
|
||||||
mod bus;
|
mod bus;
|
||||||
mod consts;
|
mod consts;
|
||||||
|
mod control;
|
||||||
mod countries;
|
mod countries;
|
||||||
mod events;
|
mod events;
|
||||||
|
mod hci_connector;
|
||||||
mod ioctl;
|
mod ioctl;
|
||||||
mod structs;
|
|
||||||
|
|
||||||
mod control;
|
|
||||||
mod nvram;
|
mod nvram;
|
||||||
mod runner;
|
mod runner;
|
||||||
|
mod structs;
|
||||||
use core::slice;
|
mod utilities;
|
||||||
|
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
use embedded_hal_1::digital::OutputPin;
|
use embedded_hal_1::digital::OutputPin;
|
||||||
@ -226,6 +225,8 @@ where
|
|||||||
|
|
||||||
runner.init(firmware, None).await;
|
runner.init(firmware, None).await;
|
||||||
|
|
||||||
|
// TODO: build and return something like MPSC channels that can interact as hci_connector with runner/bus?
|
||||||
|
|
||||||
(
|
(
|
||||||
device,
|
device,
|
||||||
Control::new(state_ch, &state.events, &state.ioctl_state),
|
Control::new(state_ch, &state.events, &state.ioctl_state),
|
||||||
@ -257,8 +258,3 @@ where
|
|||||||
runner,
|
runner,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
|
|
||||||
let len = x.len() * 4;
|
|
||||||
unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
|
|
||||||
}
|
|
||||||
|
@ -4,6 +4,7 @@ use embassy_sync::pubsub::PubSubBehavior;
|
|||||||
use embassy_time::{block_for, Duration, Timer};
|
use embassy_time::{block_for, Duration, Timer};
|
||||||
use embedded_hal_1::digital::OutputPin;
|
use embedded_hal_1::digital::OutputPin;
|
||||||
|
|
||||||
|
use crate::bluetooth::{CybtFwCb, HexFileData};
|
||||||
use crate::bus::Bus;
|
use crate::bus::Bus;
|
||||||
pub use crate::bus::SpiBusCyw43;
|
pub use crate::bus::SpiBusCyw43;
|
||||||
use crate::consts::*;
|
use crate::consts::*;
|
||||||
@ -12,7 +13,7 @@ use crate::fmt::Bytes;
|
|||||||
use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
|
use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
|
||||||
use crate::nvram::NVRAM;
|
use crate::nvram::NVRAM;
|
||||||
use crate::structs::*;
|
use crate::structs::*;
|
||||||
use crate::{bluetooth, events, slice8_mut, Core, CHIP, MTU};
|
use crate::{bluetooth, events, utilities, Core, CHIP, MTU};
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
struct LogState {
|
struct LogState {
|
||||||
@ -47,6 +48,12 @@ pub struct Runner<'a, PWR, SPI> {
|
|||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
log: LogState,
|
log: LogState,
|
||||||
|
|
||||||
|
// Bluetooth circular buffers
|
||||||
|
h2b_buf_addr: u32,
|
||||||
|
h2b_buf_addr_pointer: u32,
|
||||||
|
b2h_buf_addr: u32,
|
||||||
|
b2h_buf_addr_pointer: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
|
impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
|
||||||
@ -63,18 +70,26 @@ where
|
|||||||
Self {
|
Self {
|
||||||
ch,
|
ch,
|
||||||
bus,
|
bus,
|
||||||
|
|
||||||
ioctl_state,
|
ioctl_state,
|
||||||
ioctl_id: 0,
|
ioctl_id: 0,
|
||||||
sdpcm_seq: 0,
|
sdpcm_seq: 0,
|
||||||
sdpcm_seq_max: 1,
|
sdpcm_seq_max: 1,
|
||||||
|
|
||||||
events,
|
events,
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
log: LogState::default(),
|
log: LogState::default(),
|
||||||
|
|
||||||
|
h2b_buf_addr: 0,
|
||||||
|
h2b_buf_addr_pointer: 0,
|
||||||
|
b2h_buf_addr: 0,
|
||||||
|
b2h_buf_addr_pointer: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn init(&mut self, firmware: &[u8], bluetooth_firmware: Option<&[u8]>) {
|
pub(crate) async fn init(&mut self, firmware: &[u8], bluetooth_firmware: Option<&[u8]>) {
|
||||||
self.bus.init().await;
|
self.bus.init(bluetooth_firmware.is_some()).await;
|
||||||
|
|
||||||
// Init ALP (Active Low Power) clock
|
// Init ALP (Active Low Power) clock
|
||||||
debug!("init alp");
|
debug!("init alp");
|
||||||
@ -83,13 +98,15 @@ where
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
// check we can set the bluetooth watermark
|
// check we can set the bluetooth watermark
|
||||||
debug!("set bluetooth watermark");
|
if bluetooth_firmware.is_some() {
|
||||||
self.bus
|
debug!("set bluetooth watermark");
|
||||||
.write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 0x10)
|
self.bus
|
||||||
.await;
|
.write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 0x10)
|
||||||
let watermark = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK).await;
|
.await;
|
||||||
debug!("watermark = {:02x}", watermark);
|
let watermark = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK).await;
|
||||||
assert!(watermark == 0x10);
|
debug!("watermark = {:02x}", watermark);
|
||||||
|
assert!(watermark == 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
debug!("waiting for clock...");
|
debug!("waiting for clock...");
|
||||||
while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
|
while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
|
||||||
@ -116,12 +133,6 @@ where
|
|||||||
debug!("loading fw");
|
debug!("loading fw");
|
||||||
self.bus.bp_write(ram_addr, firmware).await;
|
self.bus.bp_write(ram_addr, firmware).await;
|
||||||
|
|
||||||
// Optionally load Bluetooth fimrware into RAM.
|
|
||||||
if bluetooth_firmware.is_some() {
|
|
||||||
debug!("loading bluetooth fw");
|
|
||||||
bluetooth::init_bluetooth(&mut self.bus, bluetooth_firmware.unwrap()).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("loading nvram");
|
debug!("loading nvram");
|
||||||
// Round up to 4 bytes.
|
// Round up to 4 bytes.
|
||||||
let nvram_len = (NVRAM.len() + 3) / 4 * 4;
|
let nvram_len = (NVRAM.len() + 3) / 4 * 4;
|
||||||
@ -151,10 +162,12 @@ where
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Set up the interrupt mask and enable interrupts
|
// Set up the interrupt mask and enable interrupts
|
||||||
debug!("bluetooth setup interrupt mask");
|
if bluetooth_firmware.is_some() {
|
||||||
self.bus
|
debug!("bluetooth setup interrupt mask");
|
||||||
.bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_FC_CHANGE)
|
self.bus
|
||||||
.await;
|
.bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_FC_CHANGE)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: turn interrupts on here or in bus.init()?
|
// TODO: turn interrupts on here or in bus.init()?
|
||||||
/*self.bus
|
/*self.bus
|
||||||
@ -204,7 +217,7 @@ where
|
|||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
self.log_init().await;
|
self.log_init().await;
|
||||||
|
|
||||||
debug!("wifi init done");
|
debug!("cyw43 runner init done");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
@ -261,6 +274,261 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn init_bluetooth(&mut self, firmware: &[u8]) {
|
||||||
|
debug!("init_bluetooth");
|
||||||
|
self.bus
|
||||||
|
.bp_write32(CHIP.bluetooth_base_address + BT2WLAN_PWRUP_ADDR, BT2WLAN_PWRUP_WAKE)
|
||||||
|
.await;
|
||||||
|
Timer::after(Duration::from_millis(2)).await;
|
||||||
|
self.upload_bluetooth_firmware(firmware).await;
|
||||||
|
self.wait_bt_ready().await;
|
||||||
|
self.init_bt_buffers().await;
|
||||||
|
self.wait_bt_awake().await;
|
||||||
|
self.bt_set_host_ready().await;
|
||||||
|
self.bt_toggle_intr().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn upload_bluetooth_firmware(&mut self, firmware: &[u8]) {
|
||||||
|
// read version
|
||||||
|
let version_length = firmware[0];
|
||||||
|
let _version = &firmware[1..=version_length as usize];
|
||||||
|
// skip version + 1 extra byte as per cybt_shared_bus_driver.c
|
||||||
|
let firmware = &firmware[version_length as usize + 2..];
|
||||||
|
// buffers
|
||||||
|
let mut data_buffer: [u8; 0x100] = [0; 0x100];
|
||||||
|
let mut aligned_data_buffer: [u8; 0x100] = [0; 0x100];
|
||||||
|
// structs
|
||||||
|
let mut btfw_cb = CybtFwCb {
|
||||||
|
p_next_line_start: firmware,
|
||||||
|
};
|
||||||
|
let mut hfd = HexFileData {
|
||||||
|
addr_mode: BTFW_ADDR_MODE_EXTENDED,
|
||||||
|
hi_addr: 0,
|
||||||
|
dest_addr: 0,
|
||||||
|
p_ds: &mut data_buffer,
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
let num_fw_bytes = bluetooth::read_firmware_patch_line(&mut btfw_cb, &mut hfd);
|
||||||
|
if num_fw_bytes == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let fw_bytes = &hfd.p_ds[0..num_fw_bytes as usize];
|
||||||
|
let mut dest_start_addr = hfd.dest_addr + CHIP.bluetooth_base_address;
|
||||||
|
let mut aligned_data_buffer_index: usize = 0;
|
||||||
|
// pad start
|
||||||
|
if utilities::is_aligned(dest_start_addr, 4) {
|
||||||
|
let num_pad_bytes = dest_start_addr % 4;
|
||||||
|
let padded_dest_start_addr = utilities::round_down(dest_start_addr, 4);
|
||||||
|
let memory_value = self.bus.bp_read32(padded_dest_start_addr).await;
|
||||||
|
let memory_value_bytes = memory_value.to_le_bytes(); // TODO: le or be
|
||||||
|
// Copy the previous memory value's bytes to the start
|
||||||
|
for i in 0..num_pad_bytes as usize {
|
||||||
|
aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i];
|
||||||
|
aligned_data_buffer_index += 1;
|
||||||
|
}
|
||||||
|
// Copy the firmware bytes after the padding bytes
|
||||||
|
for i in 0..num_fw_bytes as usize {
|
||||||
|
aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
|
||||||
|
aligned_data_buffer_index += 1;
|
||||||
|
}
|
||||||
|
dest_start_addr = padded_dest_start_addr;
|
||||||
|
} else {
|
||||||
|
// Directly copy fw_bytes into aligned_data_buffer if no start padding is required
|
||||||
|
for i in 0..num_fw_bytes as usize {
|
||||||
|
aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
|
||||||
|
aligned_data_buffer_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// pad end
|
||||||
|
let mut dest_end_addr = dest_start_addr + aligned_data_buffer_index as u32;
|
||||||
|
if !utilities::is_aligned(dest_end_addr, 4) {
|
||||||
|
let offset = dest_end_addr % 4;
|
||||||
|
let num_pad_bytes_end = 4 - offset;
|
||||||
|
let padded_dest_end_addr = utilities::round_down(dest_end_addr, 4);
|
||||||
|
let memory_value = self.bus.bp_read32(padded_dest_end_addr).await;
|
||||||
|
let memory_value_bytes = memory_value.to_le_bytes(); // TODO: le or be
|
||||||
|
// Append the necessary memory bytes to pad the end of aligned_data_buffer
|
||||||
|
for i in offset..4 {
|
||||||
|
aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i as usize];
|
||||||
|
aligned_data_buffer_index += 1;
|
||||||
|
}
|
||||||
|
dest_end_addr += num_pad_bytes_end;
|
||||||
|
} else {
|
||||||
|
// pad end alignment not needed
|
||||||
|
}
|
||||||
|
let buffer_to_write = &aligned_data_buffer[0..aligned_data_buffer_index as usize];
|
||||||
|
assert!(dest_start_addr % 4 == 0);
|
||||||
|
assert!(dest_end_addr % 4 == 0);
|
||||||
|
assert!(aligned_data_buffer_index % 4 == 0);
|
||||||
|
// write in 0x40 chunks TODO: is this needed or can we write straight away
|
||||||
|
let chunk_size = 0x40;
|
||||||
|
for (i, chunk) in buffer_to_write.chunks(chunk_size).enumerate() {
|
||||||
|
let offset = i * chunk_size;
|
||||||
|
self.bus.bp_write(dest_start_addr + (offset as u32), chunk).await;
|
||||||
|
}
|
||||||
|
// sleep TODO: is this needed
|
||||||
|
Timer::after(Duration::from_millis(1)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn wait_bt_ready(&mut self) {
|
||||||
|
debug!("wait_bt_ready");
|
||||||
|
let mut success = false;
|
||||||
|
for _ in 0..300 {
|
||||||
|
let val = self.bus.bp_read32(BT_CTRL_REG_ADDR).await;
|
||||||
|
// TODO: do we need to swap endianness on this read?
|
||||||
|
debug!("BT_CTRL_REG_ADDR = {:08x}", val);
|
||||||
|
if val & BTSDIO_REG_FW_RDY_BITMASK != 0 {
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Timer::after(Duration::from_millis(1)).await;
|
||||||
|
}
|
||||||
|
assert!(success == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn wait_bt_awake(&mut self) {
|
||||||
|
debug!("wait_bt_awake");
|
||||||
|
let mut success = false;
|
||||||
|
for _ in 0..300 {
|
||||||
|
let val = self.bus.bp_read32(BT_CTRL_REG_ADDR).await;
|
||||||
|
// TODO: do we need to swap endianness on this read?
|
||||||
|
debug!("BT_CTRL_REG_ADDR = {:08x}", val);
|
||||||
|
if val & BTSDIO_REG_BT_AWAKE_BITMASK != 0 {
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Timer::after(Duration::from_millis(1)).await;
|
||||||
|
}
|
||||||
|
assert!(success == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn bt_set_host_ready(&mut self) {
|
||||||
|
debug!("bt_set_host_ready");
|
||||||
|
let old_val = self.bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
||||||
|
// TODO: do we need to swap endianness on this read?
|
||||||
|
let new_val = old_val | BTSDIO_REG_SW_RDY_BITMASK;
|
||||||
|
self.bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use this
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn bt_set_awake(&mut self, awake: bool) {
|
||||||
|
debug!("bt_set_awake");
|
||||||
|
let old_val = self.bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
||||||
|
// TODO: do we need to swap endianness on this read?
|
||||||
|
let new_val = if awake {
|
||||||
|
old_val | BTSDIO_REG_WAKE_BT_BITMASK
|
||||||
|
} else {
|
||||||
|
old_val & !BTSDIO_REG_WAKE_BT_BITMASK
|
||||||
|
};
|
||||||
|
self.bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn bt_toggle_intr(&mut self) {
|
||||||
|
debug!("bt_toggle_intr");
|
||||||
|
let old_val = self.bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
||||||
|
// TODO: do we need to swap endianness on this read?
|
||||||
|
let new_val = old_val ^ BTSDIO_REG_DATA_VALID_BITMASK;
|
||||||
|
self.bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use this
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn bt_set_intr(&mut self) {
|
||||||
|
debug!("bt_set_intr");
|
||||||
|
let old_val = self.bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
||||||
|
let new_val = old_val | BTSDIO_REG_DATA_VALID_BITMASK;
|
||||||
|
self.bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn init_bt_buffers(&mut self) {
|
||||||
|
debug!("init_bt_buffers");
|
||||||
|
let wlan_ram_base_addr = self.bus.bp_read32(WLAN_RAM_BASE_REG_ADDR).await;
|
||||||
|
assert!(wlan_ram_base_addr != 0);
|
||||||
|
debug!("wlan_ram_base_addr = {:08x}", wlan_ram_base_addr);
|
||||||
|
self.h2b_buf_addr = wlan_ram_base_addr + BTSDIO_OFFSET_HOST_WRITE_BUF;
|
||||||
|
self.b2h_buf_addr = wlan_ram_base_addr + BTSDIO_OFFSET_HOST_READ_BUF;
|
||||||
|
let h2b_buf_in_addr = wlan_ram_base_addr + BTSDIO_OFFSET_HOST2BT_IN;
|
||||||
|
let h2b_buf_out_addr = wlan_ram_base_addr + BTSDIO_OFFSET_HOST2BT_OUT;
|
||||||
|
let b2h_buf_in_addr = wlan_ram_base_addr + BTSDIO_OFFSET_BT2HOST_IN;
|
||||||
|
let b2h_buf_out_addr = wlan_ram_base_addr + BTSDIO_OFFSET_BT2HOST_OUT;
|
||||||
|
self.bus.bp_write32(h2b_buf_in_addr, 0).await;
|
||||||
|
self.bus.bp_write32(h2b_buf_out_addr, 0).await;
|
||||||
|
self.bus.bp_write32(b2h_buf_in_addr, 0).await;
|
||||||
|
self.bus.bp_write32(b2h_buf_out_addr, 0).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bt_bus_request(&mut self) {
|
||||||
|
// TODO: CYW43_THREAD_ENTER mutex?
|
||||||
|
self.bt_set_awake(true).await;
|
||||||
|
self.wait_bt_awake().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bt_bus_release(&mut self) {
|
||||||
|
// TODO: CYW43_THREAD_EXIT mutex?
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn hci_read(&mut self, buf: &mut [u8]) -> u32 {
|
||||||
|
debug!("hci_read buf = {:02x}", buf);
|
||||||
|
self.bt_bus_request().await;
|
||||||
|
let mut header = [0 as u8; 4];
|
||||||
|
self.bus
|
||||||
|
.bp_read(self.b2h_buf_addr + self.b2h_buf_addr_pointer, &mut header)
|
||||||
|
.await;
|
||||||
|
self.b2h_buf_addr_pointer += header.len() as u32;
|
||||||
|
debug!("hci_read heaer = {:02x}", header);
|
||||||
|
// cybt_get_bt_buf_index(&fw_membuf_info);
|
||||||
|
// fw_b2h_buf_count = CIRC_BUF_CNT(fw_membuf_info.bt2host_in_val, fw_membuf_info.bt2host_out_val);
|
||||||
|
// cybt_mem_read_idx(B2H_BUF_ADDR_IDX, fw_membuf_info.bt2host_out_val, p_data, read_len);
|
||||||
|
// cybt_mem_read_idx(B2H_BUF_ADDR_IDX, 0, p_data + first_read_len, second_read_len);
|
||||||
|
// cybt_reg_write_idx(B2H_BUF_OUT_ADDR_IDX, new_b2h_out_val);
|
||||||
|
self.bt_toggle_intr().await;
|
||||||
|
let bytes_read = 0;
|
||||||
|
self.bt_bus_release().await;
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn hci_write(&mut self, buf: &[u8]) {
|
||||||
|
let buf_len = buf.len();
|
||||||
|
let algined_buf_len = utilities::round_up((buf_len + 3) as u32, 4);
|
||||||
|
assert!(buf_len <= algined_buf_len as usize);
|
||||||
|
let cmd_len = buf_len + 3 - 4; // add 3 bytes for SDIO header thingie?
|
||||||
|
let mut buf_with_cmd = [0 as u8; 0x100];
|
||||||
|
buf_with_cmd[0] = (cmd_len & 0xFF) as u8;
|
||||||
|
buf_with_cmd[1] = ((cmd_len & 0xFF00) >> 8) as u8;
|
||||||
|
buf_with_cmd[2] = 0x00;
|
||||||
|
for i in 0..buf_len {
|
||||||
|
buf_with_cmd[3 + i] = buf[i];
|
||||||
|
}
|
||||||
|
let padded_buf_with_cmd = &buf_with_cmd[0..algined_buf_len as usize];
|
||||||
|
debug!("hci_write padded_buf_with_cmd = {:02x}", padded_buf_with_cmd);
|
||||||
|
self.bt_bus_request().await;
|
||||||
|
self.bus
|
||||||
|
.bp_write(self.h2b_buf_addr + self.h2b_buf_addr_pointer, &padded_buf_with_cmd)
|
||||||
|
.await;
|
||||||
|
self.h2b_buf_addr_pointer += padded_buf_with_cmd.len() as u32;
|
||||||
|
// TODO: handle wrapping based on BTSDIO_FWBUF_SIZE
|
||||||
|
self.bt_toggle_intr().await;
|
||||||
|
self.bt_bus_release().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn bt_has_work(&mut self) -> bool {
|
||||||
|
let int_status = self.bus.bp_read32(CHIP.sdiod_core_base_address + SDIO_INT_STATUS).await;
|
||||||
|
if int_status & I_HMB_FC_CHANGE != 0 {
|
||||||
|
self.bus
|
||||||
|
.bp_write32(
|
||||||
|
CHIP.sdiod_core_base_address + SDIO_INT_STATUS,
|
||||||
|
int_status & I_HMB_FC_CHANGE,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn run(mut self) -> ! {
|
pub async fn run(mut self) -> ! {
|
||||||
let mut buf = [0; 512];
|
let mut buf = [0; 512];
|
||||||
loop {
|
loop {
|
||||||
@ -286,7 +554,7 @@ where
|
|||||||
trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
|
trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
|
||||||
|
|
||||||
let mut buf = [0; 512];
|
let mut buf = [0; 512];
|
||||||
let buf8 = slice8_mut(&mut buf);
|
let buf8 = utilities::slice8_mut(&mut buf);
|
||||||
|
|
||||||
// There MUST be 2 bytes of padding between the SDPCM and BDC headers.
|
// There MUST be 2 bytes of padding between the SDPCM and BDC headers.
|
||||||
// And ONLY for data packets!
|
// And ONLY for data packets!
|
||||||
@ -375,8 +643,11 @@ where
|
|||||||
if status & STATUS_F2_PKT_AVAILABLE != 0 {
|
if status & STATUS_F2_PKT_AVAILABLE != 0 {
|
||||||
let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
|
let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
|
||||||
self.bus.wlan_read(buf, len).await;
|
self.bus.wlan_read(buf, len).await;
|
||||||
trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)]));
|
trace!(
|
||||||
self.rx(&mut slice8_mut(buf)[..len as usize]);
|
"rx {:02x}",
|
||||||
|
Bytes(&utilities::slice8_mut(buf)[..(len as usize).min(48)])
|
||||||
|
);
|
||||||
|
self.rx(&mut utilities::slice8_mut(buf)[..len as usize]);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -519,7 +790,7 @@ where
|
|||||||
|
|
||||||
async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) {
|
async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) {
|
||||||
let mut buf = [0; 512];
|
let mut buf = [0; 512];
|
||||||
let buf8 = slice8_mut(&mut buf);
|
let buf8 = utilities::slice8_mut(&mut buf);
|
||||||
|
|
||||||
let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
|
let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
|
||||||
|
|
||||||
|
18
cyw43/src/utilities.rs
Normal file
18
cyw43/src/utilities.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use core::slice;
|
||||||
|
|
||||||
|
pub(crate) fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
|
||||||
|
let len = x.len() * 4;
|
||||||
|
unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_aligned(a: u32, x: u32) -> bool {
|
||||||
|
(a & (x - 1)) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn round_down(x: u32, a: u32) -> u32 {
|
||||||
|
x & !(a - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn round_up(x: u32, a: u32) -> u32 {
|
||||||
|
((x + a - 1) / a) * a
|
||||||
|
}
|
@ -51,7 +51,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let (_net_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await;
|
let (_net_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await;
|
||||||
unwrap!(spawner.spawn(cyw43_runner_task(runner)));
|
unwrap!(spawner.spawn(cyw43_runner_task(runner)));
|
||||||
|
|
||||||
control.init(clm).await;
|
control.init(clm, false, true).await;
|
||||||
control
|
control
|
||||||
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
||||||
.await;
|
.await;
|
||||||
|
@ -64,7 +64,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
|
let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
|
||||||
unwrap!(spawner.spawn(wifi_task(runner)));
|
unwrap!(spawner.spawn(wifi_task(runner)));
|
||||||
|
|
||||||
control.init(clm).await;
|
control.init(clm, true, false).await;
|
||||||
control
|
control
|
||||||
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
||||||
.await;
|
.await;
|
||||||
|
@ -50,7 +50,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
|
let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
|
||||||
unwrap!(spawner.spawn(wifi_task(runner)));
|
unwrap!(spawner.spawn(wifi_task(runner)));
|
||||||
|
|
||||||
control.init(clm).await;
|
control.init(clm, true, false).await;
|
||||||
control
|
control
|
||||||
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
||||||
.await;
|
.await;
|
||||||
|
@ -61,7 +61,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
|
let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
|
||||||
unwrap!(spawner.spawn(wifi_task(runner)));
|
unwrap!(spawner.spawn(wifi_task(runner)));
|
||||||
|
|
||||||
control.init(clm).await;
|
control.init(clm, true, false).await;
|
||||||
control
|
control
|
||||||
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
||||||
.await;
|
.await;
|
||||||
|
@ -67,7 +67,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
|
let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
|
||||||
unwrap!(spawner.spawn(wifi_task(runner)));
|
unwrap!(spawner.spawn(wifi_task(runner)));
|
||||||
|
|
||||||
control.init(clm).await;
|
control.init(clm, true, false).await;
|
||||||
control
|
control
|
||||||
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
||||||
.await;
|
.await;
|
||||||
|
Loading…
Reference in New Issue
Block a user