tl_mbox read and write

This commit is contained in:
goueslati 2023-05-15 10:25:02 +01:00
parent 3810fe6a20
commit d97724cca3
11 changed files with 661 additions and 22 deletions

View File

@ -158,6 +158,10 @@ impl<'d> Ipcc<'d> {
pub fn is_rx_pending(&self, channel: IpccChannel) -> bool { pub fn is_rx_pending(&self, channel: IpccChannel) -> bool {
self.c2_is_active_flag(channel) && self.c1_get_rx_channel(channel) self.c2_is_active_flag(channel) && self.c1_get_rx_channel(channel)
} }
pub fn as_mut_ptr(&self) -> *mut Self {
unsafe { &mut core::ptr::read(self) as *mut _ }
}
} }
impl sealed::Instance for crate::peripherals::IPCC { impl sealed::Instance for crate::peripherals::IPCC {
@ -176,3 +180,14 @@ unsafe fn _configure_pwr() {
// set RF wake-up clock = LSE // set RF wake-up clock = LSE
rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
} }
// TODO: if anyone has a better idea, please let me know
/// extension trait that constrains the [`Ipcc`] peripheral
pub trait IpccExt<'d> {
fn constrain(self) -> Ipcc<'d>;
}
impl<'d> IpccExt<'d> for IPCC {
fn constrain(self) -> Ipcc<'d> {
Ipcc { _peri: self.into_ref() }
}
}

View File

@ -1,13 +1,22 @@
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use super::unsafe_linked_list::LST_init_head; use embassy_futures::block_on;
use super::{channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
use super::cmd::CmdSerial;
use super::consts::TlPacketType;
use super::evt::EvtBox;
use super::unsafe_linked_list::{LST_init_head, LST_is_empty, LST_remove_head};
use super::{
channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_CHANNEL,
TL_REF_TABLE,
};
use crate::ipcc::Ipcc; use crate::ipcc::Ipcc;
use crate::tl_mbox::cmd::CmdPacket;
pub struct Ble; pub struct Ble;
impl Ble { impl Ble {
pub fn new(ipcc: &mut Ipcc) -> Self { pub(crate) fn new(ipcc: &mut Ipcc) -> Self {
unsafe { unsafe {
LST_init_head(EVT_QUEUE.as_mut_ptr()); LST_init_head(EVT_QUEUE.as_mut_ptr());
@ -23,4 +32,37 @@ impl Ble {
Ble Ble
} }
pub(crate) fn evt_handler(ipcc: &mut Ipcc) {
unsafe {
let mut node_ptr = core::ptr::null_mut();
let node_ptr_ptr: *mut _ = &mut node_ptr;
while !LST_is_empty(EVT_QUEUE.as_mut_ptr()) {
LST_remove_head(EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
let event = node_ptr.cast();
let event = EvtBox::new(event);
block_on(TL_CHANNEL.send(event));
}
}
ipcc.c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL);
}
pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) {
unsafe {
let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmd_serial;
let pcmd_serial_buf: *mut u8 = pcmd_serial.cast();
core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len());
let mut cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8;
}
ipcc.c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL);
}
} }

View File

@ -52,9 +52,9 @@
pub mod cpu1 { pub mod cpu1 {
use crate::ipcc::IpccChannel; use crate::ipcc::IpccChannel;
#[allow(dead_code)] // Not used currently but reserved // Not used currently but reserved
pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1;
#[allow(dead_code)] // Not used currently but reserved // Not used currently but reserved
pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2;
#[allow(dead_code)] // Not used currently but reserved #[allow(dead_code)] // Not used currently but reserved
pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
@ -62,7 +62,7 @@ pub mod cpu1 {
pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved #[allow(dead_code)] // Not used currently but reserved
pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved // Not used currently but reserved
pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4; pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
#[allow(dead_code)] // Not used currently but reserved #[allow(dead_code)] // Not used currently but reserved
pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
@ -88,7 +88,7 @@ pub mod cpu2 {
#[allow(dead_code)] // Not used currently but reserved #[allow(dead_code)] // Not used currently but reserved
pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved #[allow(dead_code)] // Not used currently but reserved
pub const IPCC_BLE_LLDÇM0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved #[allow(dead_code)] // Not used currently but reserved
pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
#[allow(dead_code)] // Not used currently but reserved #[allow(dead_code)] // Not used currently but reserved

View File

@ -0,0 +1,53 @@
#[derive(PartialEq)]
#[repr(C)]
pub enum TlPacketType {
BleCmd = 0x01,
AclData = 0x02,
BleEvt = 0x04,
OtCmd = 0x08,
OtRsp = 0x09,
CliCmd = 0x0A,
OtNot = 0x0C,
OtAck = 0x0D,
CliNot = 0x0E,
CliAck = 0x0F,
SysCmd = 0x10,
SysRsp = 0x11,
SysEvt = 0x12,
LocCmd = 0x20,
LocRsp = 0x21,
TracesApp = 0x40,
TracesWl = 0x41,
}
impl TryFrom<u8> for TlPacketType {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x01 => Ok(TlPacketType::BleCmd),
0x02 => Ok(TlPacketType::AclData),
0x04 => Ok(TlPacketType::BleEvt),
0x08 => Ok(TlPacketType::OtCmd),
0x09 => Ok(TlPacketType::OtRsp),
0x0A => Ok(TlPacketType::CliCmd),
0x0C => Ok(TlPacketType::OtNot),
0x0D => Ok(TlPacketType::OtAck),
0x0E => Ok(TlPacketType::CliNot),
0x0F => Ok(TlPacketType::CliAck),
0x10 => Ok(TlPacketType::SysCmd),
0x11 => Ok(TlPacketType::SysRsp),
0x12 => Ok(TlPacketType::SysEvt),
0x20 => Ok(TlPacketType::LocCmd),
0x21 => Ok(TlPacketType::LocRsp),
0x40 => Ok(TlPacketType::TracesApp),
0x41 => Ok(TlPacketType::TracesWl),
_ => Err(()),
}
}
}

View File

@ -1,3 +1,10 @@
use core::mem::MaybeUninit;
use super::cmd::{AclDataPacket, AclDataSerial};
use super::consts::TlPacketType;
use super::{PacketHeader, TL_EVT_HEADER_SIZE};
use crate::tl_mbox::mm;
/// the payload of [`Evt`] for a command status event /// the payload of [`Evt`] for a command status event
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
#[repr(C, packed)] #[repr(C, packed)]
@ -6,3 +13,159 @@ pub struct CsEvt {
pub num_cmd: u8, pub num_cmd: u8,
pub cmd_code: u16, pub cmd_code: u16,
} }
/// the payload of [`Evt`] for a command complete event
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct CcEvt {
pub num_cmd: u8,
pub cmd_code: u8,
pub payload: [u8; 1],
}
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct Evt {
pub evt_code: u8,
pub payload_len: u8,
pub payload: [u8; 1],
}
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct EvtSerial {
pub kind: u8,
pub evt: Evt,
}
/// This format shall be used for all events (asynchronous and command response) reported
/// by the CPU2 except for the command response of a system command where the header is not there
/// and the format to be used shall be `EvtSerial`.
///
/// ### Note:
/// Be careful that the asynchronous events reported by the CPU2 on the system channel do
/// include the header and shall use `EvtPacket` format. Only the command response format on the
/// system channel is different.
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct EvtPacket {
pub header: PacketHeader,
pub evt_serial: EvtSerial,
}
/// Smart pointer to the [`EvtPacket`] that will dispose of it automatically on drop
pub struct EvtBox {
ptr: *mut EvtPacket,
}
unsafe impl Send for EvtBox {}
impl EvtBox {
pub(super) fn new(ptr: *mut EvtPacket) -> Self {
Self { ptr }
}
/// Copies the event data from inner pointer and returns and event structure
pub fn evt(&self) -> EvtPacket {
let mut evt = MaybeUninit::uninit();
unsafe {
self.ptr.copy_to(evt.as_mut_ptr(), 1);
evt.assume_init()
}
}
/// Returns the size of a buffer required to hold this event
pub fn size(&self) -> Result<usize, ()> {
unsafe {
let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
if evt_kind == TlPacketType::AclData {
let acl_data: *const AclDataPacket = self.ptr.cast();
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
Ok((*acl_serial).length as usize + 5)
} else {
let evt_data: *const EvtPacket = self.ptr.cast();
let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
}
}
}
/// writes an underlying [`EvtPacket`] into the provided buffer. Returns the number of bytes that were
/// written. Returns an error if event kind is unkown or if provided buffer size is not enough
pub fn copy_into_slice(&self, buf: &mut [u8]) -> Result<usize, ()> {
// TODO: double check this
// unsafe {
// let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
// if let TlPacketType::AclData = evt_kind {
// let acl_data: *const AclDataPacket = self.ptr.cast();
// let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
// let acl_serial_buf: *const u8 = acl_serial.cast();
// let len = (*acl_serial).length as usize + 5;
// if len > buf.len() {
// return Err(());
// }
// core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
// Ok(len)
// } else {
// let evt_data: *const EvtPacket = self.ptr.cast();
// let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
// let evt_serial_buf: *const u8 = evt_serial.cast();
// let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
// if len > buf.len() {
// return Err(());
// }
// core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
// Ok(len)
// }
// }
unsafe {
let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
let evt_data: *const EvtPacket = self.ptr.cast();
let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
let evt_serial_buf: *const u8 = evt_serial.cast();
let acl_data: *const AclDataPacket = self.ptr.cast();
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
let acl_serial_buf: *const u8 = acl_serial.cast();
if let TlPacketType::AclData = evt_kind {
let len = (*acl_serial).length as usize + 5;
if len > buf.len() {
return Err(());
}
core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
Ok(len)
} else {
let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
if len > buf.len() {
return Err(());
}
core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
Ok(len)
}
}
}
}
impl Drop for EvtBox {
fn drop(&mut self) {
use crate::ipcc::IpccExt;
let mut ipcc = unsafe { crate::Peripherals::steal() }.IPCC.constrain();
mm::MemoryManager::evt_drop(self.ptr, &mut ipcc);
}
}

View File

@ -1,10 +1,12 @@
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use super::unsafe_linked_list::LST_init_head; use super::evt::EvtPacket;
use super::unsafe_linked_list::{LST_init_head, LST_insert_tail, LST_is_empty, LST_remove_head};
use super::{ use super::{
MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF, channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE,
TL_MEM_MANAGER_TABLE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
}; };
use crate::ipcc::Ipcc;
pub struct MemoryManager; pub struct MemoryManager;
@ -27,4 +29,43 @@ impl MemoryManager {
MemoryManager MemoryManager
} }
pub fn evt_handler(ipcc: &mut Ipcc) {
ipcc.c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false);
Self::send_free_buf();
ipcc.c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
}
pub fn evt_drop(evt: *mut EvtPacket, ipcc: &mut Ipcc) {
unsafe {
let list_node = evt.cast();
LST_insert_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node);
}
let channel_is_busy = ipcc.c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
// postpone event buffer freeing to IPCC interrupt handler
if channel_is_busy {
ipcc.c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true);
} else {
Self::send_free_buf();
ipcc.c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
}
}
fn send_free_buf() {
unsafe {
let mut node_ptr = core::ptr::null_mut();
let node_ptr_ptr: *mut _ = &mut node_ptr;
while !LST_is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
LST_remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr);
LST_insert_tail(
(*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
node_ptr,
);
}
}
}
} }

View File

@ -1,20 +1,27 @@
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use bit_field::BitField; use bit_field::BitField;
use embassy_cortex_m::interrupt::InterruptExt;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use self::ble::Ble; use self::ble::Ble;
use self::cmd::{AclDataPacket, CmdPacket}; use self::cmd::{AclDataPacket, CmdPacket};
use self::evt::CsEvt; use self::evt::{CsEvt, EvtBox};
use self::mm::MemoryManager; use self::mm::MemoryManager;
use self::shci::{shci_ble_init, ShciBleInitCmdParam};
use self::sys::Sys; use self::sys::Sys;
use self::unsafe_linked_list::LinkedListNode; use self::unsafe_linked_list::LinkedListNode;
use crate::_generated::interrupt::{IPCC_C1_RX, IPCC_C1_TX};
use crate::ipcc::Ipcc; use crate::ipcc::Ipcc;
mod ble; mod ble;
mod channels; mod channels;
mod cmd; mod cmd;
mod consts;
mod evt; mod evt;
mod mm; mod mm;
mod shci;
mod sys; mod sys;
mod unsafe_linked_list; mod unsafe_linked_list;
@ -236,18 +243,14 @@ static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
// not in shared RAM // not in shared RAM
static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
#[allow(dead_code)] // Not used currently but reserved
#[link_section = "MB_MEM1"]
static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"] #[link_section = "MB_MEM2"]
static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
MaybeUninit::uninit(); MaybeUninit::uninit();
#[link_section = "MB_MEM1"] #[link_section = "MB_MEM2"]
static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"] #[link_section = "MB_MEM2"]
static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"] #[link_section = "MB_MEM2"]
@ -271,6 +274,9 @@ static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
// "magic" numbers from ST ---v---v // "magic" numbers from ST ---v---v
static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit(); static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
// TODO: get a better size, this is a placeholder
pub(crate) static TL_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 5> = Channel::new();
pub struct TlMbox { pub struct TlMbox {
_sys: Sys, _sys: Sys,
_ble: Ble, _ble: Ble,
@ -279,7 +285,7 @@ pub struct TlMbox {
impl TlMbox { impl TlMbox {
/// initializes low-level transport between CPU1 and BLE stack on CPU2 /// initializes low-level transport between CPU1 and BLE stack on CPU2
pub fn init(ipcc: &mut Ipcc) -> TlMbox { pub fn init(ipcc: &mut Ipcc, rx_irq: IPCC_C1_RX, tx_irq: IPCC_C1_TX) -> TlMbox {
unsafe { unsafe {
TL_REF_TABLE = MaybeUninit::new(RefTable { TL_REF_TABLE = MaybeUninit::new(RefTable {
device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
@ -320,6 +326,24 @@ impl TlMbox {
let _ble = Ble::new(ipcc); let _ble = Ble::new(ipcc);
let _mm = MemoryManager::new(); let _mm = MemoryManager::new();
rx_irq.disable();
tx_irq.disable();
rx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ());
tx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ());
rx_irq.set_handler(|ipcc| {
let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() };
Self::interrupt_ipcc_rx_handler(ipcc);
});
tx_irq.set_handler(|ipcc| {
let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() };
Self::interrupt_ipcc_tx_handler(ipcc);
});
rx_irq.enable();
tx_irq.enable();
TlMbox { _sys, _ble, _mm } TlMbox { _sys, _ble, _mm }
} }
@ -333,4 +357,41 @@ impl TlMbox {
None None
} }
} }
pub fn shci_ble_init(&self, ipcc: &mut Ipcc, param: ShciBleInitCmdParam) {
shci_ble_init(ipcc, param);
}
pub fn send_ble_cmd(&self, ipcc: &mut Ipcc, buf: &[u8]) {
ble::Ble::send_cmd(ipcc, buf);
}
// pub fn send_sys_cmd(&self, ipcc: &mut Ipcc, buf: &[u8]) {
// sys::Sys::send_cmd(ipcc, buf);
// }
pub async fn read(&self) -> EvtBox {
TL_CHANNEL.recv().await
}
fn interrupt_ipcc_rx_handler(ipcc: &mut Ipcc) {
if ipcc.is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) {
sys::Sys::evt_handler(ipcc);
} else if ipcc.is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) {
ble::Ble::evt_handler(ipcc);
} else {
todo!()
}
}
fn interrupt_ipcc_tx_handler(ipcc: &mut Ipcc) {
if ipcc.is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) {
// TODO: handle this case
let _ = sys::Sys::cmd_evt_handler(ipcc);
} else if ipcc.is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) {
mm::MemoryManager::evt_handler(ipcc);
} else {
todo!()
}
}
} }

View File

@ -0,0 +1,101 @@
//! HCI commands for system channel
use super::cmd::CmdPacket;
use super::consts::TlPacketType;
use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
use crate::ipcc::Ipcc;
const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
#[allow(dead_code)]
const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct ShciBleInitCmdParam {
/// NOT USED CURRENTLY
pub p_ble_buffer_address: u32,
/// Size of the Buffer allocated in pBleBufferAddress
pub ble_buffer_size: u32,
pub num_attr_record: u16,
pub num_attr_serv: u16,
pub attr_value_arr_size: u16,
pub num_of_links: u8,
pub extended_packet_length_enable: u8,
pub pr_write_list_size: u8,
pub mb_lock_count: u8,
pub att_mtu: u16,
pub slave_sca: u16,
pub master_sca: u8,
pub ls_source: u8,
pub max_conn_event_length: u32,
pub hs_startup_time: u16,
pub viterbi_enable: u8,
pub ll_only: u8,
pub hw_version: u8,
}
impl Default for ShciBleInitCmdParam {
fn default() -> Self {
Self {
p_ble_buffer_address: 0,
ble_buffer_size: 0,
num_attr_record: 68,
num_attr_serv: 8,
attr_value_arr_size: 1344,
num_of_links: 2,
extended_packet_length_enable: 1,
pr_write_list_size: 0x3A,
mb_lock_count: 0x79,
att_mtu: 156,
slave_sca: 500,
master_sca: 0,
ls_source: 1,
max_conn_event_length: 0xFFFFFFFF,
hs_startup_time: 0x148,
viterbi_enable: 1,
ll_only: 0,
hw_version: 0,
}
}
}
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct ShciHeader {
metadata: [u32; 3],
}
#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct ShciBleInitCmdPacket {
header: ShciHeader,
param: ShciBleInitCmdParam,
}
pub fn shci_ble_init(ipcc: &mut Ipcc, param: ShciBleInitCmdParam) {
let mut packet = ShciBleInitCmdPacket {
header: ShciHeader::default(),
param,
};
let packet_ptr: *mut ShciBleInitCmdPacket = &mut packet;
unsafe {
let cmd_ptr: *mut CmdPacket = packet_ptr.cast();
(*cmd_ptr).cmd_serial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT;
(*cmd_ptr).cmd_serial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8;
let mut cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
core::ptr::write(cmd_buf, *cmd_ptr);
cmd_buf.cmd_serial.ty = TlPacketType::SysCmd as u8;
ipcc.c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
ipcc.c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
}
}

View File

@ -1,13 +1,18 @@
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use super::unsafe_linked_list::LST_init_head; use embassy_futures::block_on;
use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_SYS_TABLE};
use super::cmd::{CmdPacket, CmdSerial};
use super::consts::TlPacketType;
use super::evt::{CcEvt, EvtBox, EvtSerial};
use super::unsafe_linked_list::{LST_init_head, LST_is_empty, LST_remove_head};
use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE};
use crate::ipcc::Ipcc; use crate::ipcc::Ipcc;
pub struct Sys; pub struct Sys;
impl Sys { impl Sys {
pub fn new(ipcc: &mut Ipcc) -> Self { pub(crate) fn new(ipcc: &mut Ipcc) -> Self {
unsafe { unsafe {
LST_init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); LST_init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
@ -21,4 +26,62 @@ impl Sys {
Sys Sys
} }
pub(crate) fn evt_handler(ipcc: &mut Ipcc) {
unsafe {
let mut node_ptr = core::ptr::null_mut();
let node_ptr_ptr: *mut _ = &mut node_ptr;
while !LST_is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
LST_remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
let event = node_ptr.cast();
let event = EvtBox::new(event);
// TODO: not really happy about this
block_on(TL_CHANNEL.send(event));
}
}
ipcc.c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL);
}
pub(crate) fn cmd_evt_handler(ipcc: &mut Ipcc) -> CcEvt {
ipcc.c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false);
// ST's command response data structure is really convoluted.
//
// for command response events on SYS channel, the header is missing
// and one should:
// 1. interpret the content of CMD_BUFFER as CmdPacket
// 2. Access CmdPacket's cmdserial field and interpret its content as EvtSerial
// 3. Access EvtSerial's evt field (as Evt) and interpret its payload as CcEvt
// 4. CcEvt type is the actual SHCI response
// 5. profit
unsafe {
let cmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer;
let cmd_serial: *const CmdSerial = &(*cmd).cmd_serial;
let evt_serial: *const EvtSerial = cmd_serial.cast();
let cc = (*evt_serial).evt.payload.as_ptr().cast();
*cc
}
}
#[allow(dead_code)]
pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) {
unsafe {
// TODO: check this
let cmd_buffer = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
let cmd_serial: *mut CmdSerial = &mut (*cmd_buffer).cmd_serial;
let cmd_serial_buf = cmd_serial.cast();
core::ptr::copy(buf.as_ptr(), cmd_serial_buf, buf.len());
let mut cmd_packet = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
cmd_packet.cmd_serial.ty = TlPacketType::SysCmd as u8;
ipcc.c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
ipcc.c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
}
}
} }

View File

@ -4,6 +4,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::interrupt;
use embassy_stm32::ipcc::{Config, Ipcc}; use embassy_stm32::ipcc::{Config, Ipcc};
use embassy_stm32::tl_mbox::TlMbox; use embassy_stm32::tl_mbox::TlMbox;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
@ -40,7 +41,10 @@ async fn main(_spawner: Spawner) {
let config = Config::default(); let config = Config::default();
let mut ipcc = Ipcc::new(p.IPCC, config); let mut ipcc = Ipcc::new(p.IPCC, config);
let mbox = TlMbox::init(&mut ipcc); let rx_irq = interrupt::take!(IPCC_C1_RX);
let tx_irq = interrupt::take!(IPCC_C1_TX);
let mbox = TlMbox::init(&mut ipcc, rx_irq, tx_irq);
loop { loop {
let wireless_fw_info = mbox.wireless_fw_info(); let wireless_fw_info = mbox.wireless_fw_info();

View File

@ -0,0 +1,96 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::interrupt;
use embassy_stm32::ipcc::{Config, Ipcc};
use embassy_stm32::tl_mbox::TlMbox;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
/*
How to make this work:
- Obtain a NUCLEO-STM32WB55 from your preferred supplier.
- Download and Install STM32CubeProgrammer.
- Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
- Open STM32CubeProgrammer
- On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
- Once complete, click connect to connect to the device.
- On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
- In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
- Select that file, the memory address, "verify download", and then "Firmware Upgrade".
- Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
- Select that file, the memory address, "verify download", and then "Firmware Upgrade".
- Disconnect from the device.
- In the examples folder for stm32wb, modify the memory.x file to match your target device.
- Run this example.
Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
*/
let p = embassy_stm32::init(Default::default());
info!("Hello World!");
let config = Config::default();
let mut ipcc = Ipcc::new(p.IPCC, config);
let rx_irq = interrupt::take!(IPCC_C1_RX);
let tx_irq = interrupt::take!(IPCC_C1_TX);
let mbox = TlMbox::init(&mut ipcc, rx_irq, tx_irq);
// initialize ble stack, does not return a response
// mbox.shci_ble_init(&mut ipcc, Default::default());
info!("waiting for coprocessor to boot");
let event_box = mbox.read().await;
let mut payload = [0u8; 6];
event_box.copy_into_slice(&mut payload).unwrap();
let event_packet = event_box.evt();
let kind = event_packet.evt_serial.kind;
// means recieved SYS event, which indicates in this case that the coprocessor is ready
if kind == 0x12 {
let code = event_packet.evt_serial.evt.evt_code;
let payload_len = event_packet.evt_serial.evt.payload_len;
info!(
"==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
kind,
code,
payload_len,
payload[3..]
);
}
mbox.shci_ble_init(&mut ipcc, Default::default());
info!("resetting BLE");
mbox.send_ble_cmd(&mut ipcc, &[0x01, 0x03, 0x0c]);
let event_box = mbox.read().await;
let mut payload = [0u8; 7];
event_box.copy_into_slice(&mut payload).unwrap();
let event_packet = event_box.evt();
let kind = event_packet.evt_serial.kind;
let code = event_packet.evt_serial.evt.evt_code;
let payload_len = event_packet.evt_serial.evt.payload_len;
info!(
"==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
kind, code, payload_len, payload
);
loop {}
}