diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 1c1b57b3..f9023ed7 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -27,6 +27,9 @@ bit_field = "0.10.2" [features] defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] +ble = [] +mac = [] + stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ] diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs index f0bd6f48..60e0cbdf 100644 --- a/embassy-stm32-wpan/src/ble.rs +++ b/embassy-stm32-wpan/src/ble.rs @@ -2,12 +2,12 @@ use core::marker::PhantomData; use embassy_stm32::ipcc::Ipcc; +use crate::channels; use crate::cmd::CmdPacket; use crate::consts::TlPacketType; use crate::evt::EvtBox; -use crate::tables::BleTable; +use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; use crate::unsafe_linked_list::LinkedListNode; -use crate::{channels, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; pub struct Ble { phantom: PhantomData, diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs index edca8239..c8056aaa 100644 --- a/embassy-stm32-wpan/src/cmd.rs +++ b/embassy-stm32-wpan/src/cmd.rs @@ -37,7 +37,7 @@ pub struct CmdSerialStub { } #[derive(Copy, Clone, Default)] -#[repr(C, packed)] +#[repr(C, packed(4))] pub struct CmdPacket { pub header: PacketHeader, pub cmdserial: CmdSerial, diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs index caf26c06..9a107306 100644 --- a/embassy-stm32-wpan/src/consts.rs +++ b/embassy-stm32-wpan/src/consts.rs @@ -1,5 +1,8 @@ use core::convert::TryFrom; +use crate::evt::CsEvt; +use crate::PacketHeader; + #[derive(Debug)] #[repr(C)] pub enum TlPacketType { @@ -53,3 +56,34 @@ impl TryFrom for TlPacketType { } } } + +pub const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::(); +pub const TL_EVT_HEADER_SIZE: usize = 3; +pub const TL_CS_EVT_SIZE: usize = core::mem::size_of::(); + +/** + * Queue length of BLE Event + * This parameter defines the number of asynchronous events that can be stored in the HCI layer before + * being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer + * is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large + * enough to store all asynchronous events received in between. + * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events + * between the HCI command and its event. + * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small, + * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting + * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate + * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout). + */ +pub const CFG_TL_BLE_EVT_QUEUE_LENGTH: usize = 5; +pub const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255; +pub const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE; + +pub const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4); + +pub const fn divc(x: usize, y: usize) -> usize { + (x + y - 1) / y +} + +pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE; +#[allow(dead_code)] +pub const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE; diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs index 3a9d0357..47bdc49b 100644 --- a/embassy-stm32-wpan/src/evt.rs +++ b/embassy-stm32-wpan/src/evt.rs @@ -1,7 +1,6 @@ use core::{ptr, slice}; use super::PacketHeader; -use crate::mm; /** * The payload of `Evt` for a command status event @@ -46,15 +45,15 @@ pub struct AsynchEvt { payload: [u8; 1], } -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone)] #[repr(C, packed)] pub struct Evt { pub evt_code: u8, pub payload_len: u8, - pub payload: [u8; 1], + pub payload: [u8; 255], } -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone)] #[repr(C, packed)] pub struct EvtSerial { pub kind: u8, @@ -62,6 +61,7 @@ pub struct EvtSerial { } #[derive(Copy, Clone, Default)] +#[repr(C, packed)] pub struct EvtStub { pub kind: u8, pub evt_code: u8, @@ -75,7 +75,7 @@ pub struct EvtStub { /// 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(Copy, Clone, Default)] +#[derive(Copy, Clone)] #[repr(C, packed)] pub struct EvtPacket { pub header: PacketHeader, @@ -114,7 +114,7 @@ impl EvtBox { } } - pub fn payload<'a>(&self) -> &'a [u8] { + pub fn payload<'a>(&'a self) -> &'a [u8] { unsafe { let p_payload_len = &(*self.ptr).evt_serial.evt.payload_len as *const u8; let p_payload = &(*self.ptr).evt_serial.evt.payload as *const u8; @@ -124,72 +124,22 @@ impl EvtBox { slice::from_raw_parts(p_payload, payload_len as usize) } } - - // TODO: bring back acl - - // /// writes an underlying [`EvtPacket`] into the provided buffer. - // /// Returns the number of bytes that were written. - // /// Returns an error if event kind is unknown or if provided buffer size is not enough. - // #[allow(clippy::result_unit_err)] - // pub fn write(&self, buf: &mut [u8]) -> Result { - // 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) - // } - // } - // } - // - // /// returns the size of a buffer required to hold this event - // #[allow(clippy::result_unit_err)] - // pub fn size(&self) -> Result { - // 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 acl_data: *const AclDataPacket = self.ptr.cast(); - // let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial; - // - // if let TlPacketType::AclData = evt_kind { - // Ok((*acl_serial).length as usize + 5) - // } else { - // Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE) - // } - // } - // } } impl Drop for EvtBox { fn drop(&mut self) { - trace!("evt box drop packet"); + #[cfg(feature = "ble")] + unsafe { + use crate::mm; - unsafe { mm::MemoryManager::drop_event_packet(self.ptr) }; + mm::MemoryManager::drop_event_packet(self.ptr) + }; + + #[cfg(feature = "mac")] + unsafe { + use crate::mac; + + mac::Mac::drop_event_packet(self.ptr) + } } } diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 833db0df..5aec9933 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -6,148 +6,40 @@ pub mod fmt; use core::mem::MaybeUninit; use core::sync::atomic::{compiler_fence, Ordering}; -use ble::Ble; -use cmd::CmdPacket; use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; use embassy_stm32::interrupt; -use embassy_stm32::interrupt::typelevel::Interrupt; use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::peripherals::IPCC; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::channel::Channel; -use embassy_sync::signal::Signal; -use evt::{CcEvt, EvtBox}; use mm::MemoryManager; use sys::Sys; -use tables::{ - BleTable, DeviceInfoTable, Mac802_15_4Table, MemManagerTable, RefTable, SysTable, ThreadTable, TracesTable, -}; +use tables::*; use unsafe_linked_list::LinkedListNode; +#[cfg(feature = "ble")] pub mod ble; pub mod channels; pub mod cmd; pub mod consts; pub mod evt; +#[cfg(feature = "mac")] +pub mod mac; pub mod mm; pub mod shci; pub mod sys; pub mod tables; pub mod unsafe_linked_list; -#[link_section = "TL_REF_TABLE"] -pub static mut TL_REF_TABLE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM1"] -static mut TL_DEVICE_INFO_TABLE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM1"] -static mut TL_BLE_TABLE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM1"] -static mut TL_THREAD_TABLE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM1"] -static mut TL_SYS_TABLE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM1"] -static mut TL_MEM_MANAGER_TABLE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM1"] -static mut TL_TRACES_TABLE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM1"] -static mut TL_MAC_802_15_4_TABLE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM2"] -static mut FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit(); - -// Not in shared RAM -static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit(); - -#[allow(dead_code)] // Not used currently but reserved -#[link_section = "MB_MEM2"] -static mut TRACES_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); - type PacketHeader = LinkedListNode; -const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::(); -const TL_EVT_HEADER_SIZE: usize = 3; -const TL_CS_EVT_SIZE: usize = core::mem::size_of::(); - -#[link_section = "MB_MEM2"] -static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = - MaybeUninit::uninit(); - -#[link_section = "MB_MEM2"] -static mut EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM2"] -static mut SYSTEM_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM2"] -pub static mut SYS_CMD_BUF: MaybeUninit = MaybeUninit::uninit(); - -/** - * Queue length of BLE Event - * This parameter defines the number of asynchronous events that can be stored in the HCI layer before - * being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer - * is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large - * enough to store all asynchronous events received in between. - * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events - * between the HCI command and its event. - * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small, - * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting - * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate - * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout). - */ -const CFG_TLBLE_EVT_QUEUE_LENGTH: usize = 5; -const CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255; -const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE; - -const fn divc(x: usize, y: usize) -> usize { - ((x) + (y) - 1) / (y) -} - -const POOL_SIZE: usize = CFG_TLBLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4); - -#[link_section = "MB_MEM2"] -static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); - -#[link_section = "MB_MEM2"] -static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = - MaybeUninit::uninit(); - -#[link_section = "MB_MEM2"] -static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = - MaybeUninit::uninit(); - -#[link_section = "MB_MEM2"] -static mut BLE_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); - -#[link_section = "MB_MEM2"] -// fuck these "magic" numbers from ST ---v---v -static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit(); - -// TODO: remove these items - -#[allow(dead_code)] -/// current event that is produced during IPCC IRQ handler execution -/// on SYS channel -static EVT_CHANNEL: Channel = Channel::new(); - -#[allow(dead_code)] -/// last received Command Complete event -static LAST_CC_EVT: Signal = Signal::new(); - -static STATE: Signal = Signal::new(); - pub struct TlMbox<'d> { _ipcc: PeripheralRef<'d, IPCC>, pub sys_subsystem: Sys, pub mm_subsystem: MemoryManager, - pub ble_subsystem: Ble, + #[cfg(feature = "ble")] + pub ble_subsystem: ble::Ble, + #[cfg(feature = "mac")] + pub mac_subsystem: mac::Mac, } impl<'d> TlMbox<'d> { @@ -232,24 +124,14 @@ impl<'d> TlMbox<'d> { Ipcc::enable(config); - let sys = sys::Sys::new(); - let ble = ble::Ble::new(); - let mm = mm::MemoryManager::new(); - - // enable interrupts - interrupt::typelevel::IPCC_C1_RX::unpend(); - interrupt::typelevel::IPCC_C1_TX::unpend(); - - unsafe { interrupt::typelevel::IPCC_C1_RX::enable() }; - unsafe { interrupt::typelevel::IPCC_C1_TX::enable() }; - - STATE.reset(); - Self { _ipcc: ipcc, - sys_subsystem: sys, - ble_subsystem: ble, - mm_subsystem: mm, + sys_subsystem: sys::Sys::new(), + #[cfg(feature = "ble")] + ble_subsystem: ble::Ble::new(), + #[cfg(feature = "mac")] + mac_subsystem: mac::Mac::new(), + mm_subsystem: mm::MemoryManager::new(), } } } diff --git a/embassy-stm32-wpan/src/mac.rs b/embassy-stm32-wpan/src/mac.rs new file mode 100644 index 00000000..d2be1b85 --- /dev/null +++ b/embassy-stm32-wpan/src/mac.rs @@ -0,0 +1,111 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::ptr; +use core::sync::atomic::{AtomicBool, Ordering}; +use core::task::Poll; + +use embassy_futures::poll_once; +use embassy_stm32::ipcc::Ipcc; +use embassy_sync::waitqueue::AtomicWaker; + +use crate::channels; +use crate::cmd::CmdPacket; +use crate::consts::TlPacketType; +use crate::evt::{EvtBox, EvtPacket}; +use crate::tables::{ + Mac802_15_4Table, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, TL_MAC_802_15_4_TABLE, +}; + +static MAC_WAKER: AtomicWaker = AtomicWaker::new(); +static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); + +pub struct Mac { + phantom: PhantomData, +} + +impl Mac { + pub(crate) fn new() -> Self { + unsafe { + TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table { + p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(), + p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(), + evt_queue: ptr::null_mut(), + }); + } + + Self { phantom: PhantomData } + } + + /// SAFETY: passing a pointer to something other than a managed event packet is UB + pub(crate) unsafe fn drop_event_packet(_: *mut EvtPacket) { + // Write the ack + CmdPacket::write_into( + MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, + TlPacketType::OtAck, + 0, + &[], + ); + + // Clear the rx flag + let _ = poll_once(Ipcc::receive::( + channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, + || None, + )); + + // Allow a new read call + MAC_EVT_OUT.store(false, Ordering::SeqCst); + MAC_WAKER.wake(); + } + + /// `HW_IPCC_MAC_802_15_4_EvtNot` + /// + /// This function will stall if the previous `EvtBox` has not been dropped + pub async fn read(&self) -> EvtBox { + // Wait for the last event box to be dropped + poll_fn(|cx| { + MAC_WAKER.register(cx.waker()); + if MAC_EVT_OUT.load(Ordering::SeqCst) { + Poll::Pending + } else { + Poll::Ready(()) + } + }) + .await; + + // Return a new event box + Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe { + // The closure is not async, therefore the closure must execute to completion (cannot be dropped) + // Therefore, the event box is guaranteed to be cleaned up if it's not leaked + MAC_EVT_OUT.store(true, Ordering::SeqCst); + + Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _)) + }) + .await + } + + /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` + pub async fn write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { + self.write(opcode, payload).await; + Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await; + + unsafe { + let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket; + let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8; + + ptr::read_volatile(p_mac_rsp_evt) + } + } + + /// `TL_MAC_802_15_4_SendCmd` + pub async fn write(&self, opcode: u16, payload: &[u8]) { + Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe { + CmdPacket::write_into( + MAC_802_15_4_CMD_BUFFER.as_mut_ptr(), + TlPacketType::OtCmd, + opcode, + payload, + ); + }) + .await; + } +} diff --git a/embassy-stm32-wpan/src/mm.rs b/embassy-stm32-wpan/src/mm.rs index 21f42409..047fddcd 100644 --- a/embassy-stm32-wpan/src/mm.rs +++ b/embassy-stm32-wpan/src/mm.rs @@ -1,22 +1,23 @@ //! Memory manager routines - use core::future::poll_fn; use core::marker::PhantomData; +use core::mem::MaybeUninit; use core::task::Poll; use cortex_m::interrupt; use embassy_stm32::ipcc::Ipcc; use embassy_sync::waitqueue::AtomicWaker; +use crate::channels; +use crate::consts::POOL_SIZE; use crate::evt::EvtPacket; -use crate::tables::MemManagerTable; -use crate::unsafe_linked_list::LinkedListNode; -use crate::{ - channels, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF, - TL_MEM_MANAGER_TABLE, +use crate::tables::{ + MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, }; +use crate::unsafe_linked_list::LinkedListNode; static MM_WAKER: AtomicWaker = AtomicWaker::new(); +static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit(); pub struct MemoryManager { phantom: PhantomData, @@ -42,7 +43,8 @@ impl MemoryManager { Self { phantom: PhantomData } } - /// SAFETY: passing a pointer to something other than an event packet is UB + #[allow(dead_code)] + /// SAFETY: passing a pointer to something other than a managed event packet is UB pub(crate) unsafe fn drop_event_packet(evt: *mut EvtPacket) { interrupt::free(|_| unsafe { LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _); diff --git a/embassy-stm32-wpan/src/shci.rs b/embassy-stm32-wpan/src/shci.rs index cdf027d5..30d68971 100644 --- a/embassy-stm32-wpan/src/shci.rs +++ b/embassy-stm32-wpan/src/shci.rs @@ -1,39 +1,346 @@ use core::{mem, slice}; -use super::{TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE}; +use crate::consts::{TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE}; -pub const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66; +const SHCI_OGF: u16 = 0x3F; -#[derive(Debug, Clone, Copy)] +const fn opcode(ogf: u16, ocf: u16) -> isize { + ((ogf << 10) + ocf) as isize +} + +#[allow(dead_code)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum SchiCommandStatus { + ShciSuccess = 0x00, + ShciUnknownCmd = 0x01, + ShciMemoryCapacityExceededErrCode = 0x07, + ShciErrUnsupportedFeature = 0x11, + ShciErrInvalidHciCmdParams = 0x12, + ShciErrInvalidParams = 0x42, /* only used for release < v1.13.0 */ + ShciErrInvalidParamsV2 = 0x92, /* available for release >= v1.13.0 */ + ShciFusCmdNotSupported = 0xFF, +} + +impl TryFrom for SchiCommandStatus { + type Error = (); + + fn try_from(v: u8) -> Result { + match v { + x if x == SchiCommandStatus::ShciSuccess as u8 => Ok(SchiCommandStatus::ShciSuccess), + x if x == SchiCommandStatus::ShciUnknownCmd as u8 => Ok(SchiCommandStatus::ShciUnknownCmd), + x if x == SchiCommandStatus::ShciMemoryCapacityExceededErrCode as u8 => { + Ok(SchiCommandStatus::ShciMemoryCapacityExceededErrCode) + } + x if x == SchiCommandStatus::ShciErrUnsupportedFeature as u8 => { + Ok(SchiCommandStatus::ShciErrUnsupportedFeature) + } + x if x == SchiCommandStatus::ShciErrInvalidHciCmdParams as u8 => { + Ok(SchiCommandStatus::ShciErrInvalidHciCmdParams) + } + x if x == SchiCommandStatus::ShciErrInvalidParams as u8 => Ok(SchiCommandStatus::ShciErrInvalidParams), /* only used for release < v1.13.0 */ + x if x == SchiCommandStatus::ShciErrInvalidParamsV2 as u8 => Ok(SchiCommandStatus::ShciErrInvalidParamsV2), /* available for release >= v1.13.0 */ + x if x == SchiCommandStatus::ShciFusCmdNotSupported as u8 => Ok(SchiCommandStatus::ShciFusCmdNotSupported), + _ => Err(()), + } + } +} + +#[allow(dead_code)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ShciOpcode { + // 0x50 reserved + // 0x51 reserved + FusGetState = opcode(SHCI_OGF, 0x52), + // 0x53 reserved + FusFirmwareUpgrade = opcode(SHCI_OGF, 0x54), + FusFirmwareDelete = opcode(SHCI_OGF, 0x55), + FusUpdateAuthKey = opcode(SHCI_OGF, 0x56), + FusLockAuthKey = opcode(SHCI_OGF, 0x57), + FusStoreUserKey = opcode(SHCI_OGF, 0x58), + FusLoadUserKey = opcode(SHCI_OGF, 0x59), + FusStartWirelessStack = opcode(SHCI_OGF, 0x5a), + // 0x5b reserved + // 0x5c reserved + FusLockUserKey = opcode(SHCI_OGF, 0x5d), + FusUnloadUserKey = opcode(SHCI_OGF, 0x5e), + FusActivateAntirollback = opcode(SHCI_OGF, 0x5f), + // 0x60 reserved + // 0x61 reserved + // 0x62 reserved + // 0x63 reserved + // 0x64 reserved + // 0x65 reserved + BleInit = opcode(SHCI_OGF, 0x66), + ThreadInit = opcode(SHCI_OGF, 0x67), + DebugInit = opcode(SHCI_OGF, 0x68), + FlashEraseActivity = opcode(SHCI_OGF, 0x69), + ConcurrentSetMode = opcode(SHCI_OGF, 0x6a), + FlashStoreData = opcode(SHCI_OGF, 0x6b), + FlashEraseData = opcode(SHCI_OGF, 0x6c), + RadioAllowLowPower = opcode(SHCI_OGF, 0x6d), + Mac802_15_4Init = opcode(SHCI_OGF, 0x6e), + ReInit = opcode(SHCI_OGF, 0x6f), + ZigbeeInit = opcode(SHCI_OGF, 0x70), + LldTestsInit = opcode(SHCI_OGF, 0x71), + ExtraConfig = opcode(SHCI_OGF, 0x72), + SetFlashActivityControl = opcode(SHCI_OGF, 0x73), + BleLldInit = opcode(SHCI_OGF, 0x74), + Config = opcode(SHCI_OGF, 0x75), + ConcurrentGetNextBleEvtTime = opcode(SHCI_OGF, 0x76), + ConcurrentEnableNext802_15_4EvtNotification = opcode(SHCI_OGF, 0x77), + Mac802_15_4DeInit = opcode(SHCI_OGF, 0x78), +} + +pub const SHCI_C2_CONFIG_EVTMASK1_BIT0_ERROR_NOTIF_ENABLE: u8 = 1 << 0; +pub const SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE: u8 = 1 << 1; +pub const SHCI_C2_CONFIG_EVTMASK1_BIT2_THREAD_NVM_RAM_UPDATE_ENABLE: u8 = 1 << 2; +pub const SHCI_C2_CONFIG_EVTMASK1_BIT3_NVM_START_WRITE_ENABLE: u8 = 1 << 3; +pub const SHCI_C2_CONFIG_EVTMASK1_BIT4_NVM_END_WRITE_ENABLE: u8 = 1 << 4; +pub const SHCI_C2_CONFIG_EVTMASK1_BIT5_NVM_START_ERASE_ENABLE: u8 = 1 << 5; +pub const SHCI_C2_CONFIG_EVTMASK1_BIT6_NVM_END_ERASE_ENABLE: u8 = 1 << 6; + +#[derive(Clone, Copy)] +#[repr(C, packed)] +pub struct ShciConfigParam { + pub payload_cmd_size: u8, + pub config: u8, + pub event_mask: u8, + pub spare: u8, + pub ble_nvm_ram_address: u32, + pub thread_nvm_ram_address: u32, + pub revision_id: u16, + pub device_id: u16, +} + +impl ShciConfigParam { + pub fn payload<'a>(&'a self) -> &'a [u8] { + unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::()) } + } +} + +impl Default for ShciConfigParam { + fn default() -> Self { + Self { + payload_cmd_size: (mem::size_of::() - 1) as u8, + config: 0, + event_mask: SHCI_C2_CONFIG_EVTMASK1_BIT0_ERROR_NOTIF_ENABLE + + SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE + + SHCI_C2_CONFIG_EVTMASK1_BIT2_THREAD_NVM_RAM_UPDATE_ENABLE + + SHCI_C2_CONFIG_EVTMASK1_BIT3_NVM_START_WRITE_ENABLE + + SHCI_C2_CONFIG_EVTMASK1_BIT4_NVM_END_WRITE_ENABLE + + SHCI_C2_CONFIG_EVTMASK1_BIT5_NVM_START_ERASE_ENABLE + + SHCI_C2_CONFIG_EVTMASK1_BIT6_NVM_END_ERASE_ENABLE, + spare: 0, + ble_nvm_ram_address: 0, + thread_nvm_ram_address: 0, + revision_id: 0, + device_id: 0, + } + } +} + +#[derive(Clone, Copy)] #[repr(C, packed)] pub struct ShciBleInitCmdParam { - /// NOT USED CURRENTLY + /// NOT USED - shall be set to 0 pub p_ble_buffer_address: u32, - - /// Size of the Buffer allocated in pBleBufferAddress + /// NOT USED - shall be set to 0 pub ble_buffer_size: u32, - + /// Maximum number of attribute records related to all the required characteristics (excluding the services) + /// that can be stored in the GATT database, for the specific BLE user application. + /// For each characteristic, the number of attribute records goes from two to five depending on the characteristic properties: + /// - minimum of two (one for declaration and one for the value) + /// - add one more record for each additional property: notify or indicate, broadcast, extended property. + /// The total calculated value must be increased by 9, due to the records related to the standard attribute profile and + /// GAP service characteristics, and automatically added when initializing GATT and GAP layers + /// - Min value: + 9 + /// - Max value: depending on the GATT database defined by user application pub num_attr_record: u16, + /// Defines the maximum number of services that can be stored in the GATT database. Note that the GAP and GATT services + /// are automatically added at initialization so this parameter must be the number of user services increased by two. + /// - Min value: + 2 + /// - Max value: depending GATT database defined by user application pub num_attr_serv: u16, + /// NOTE: This parameter is ignored by the CPU2 when the parameter "Options" is set to "LL_only" ( see Options description in that structure ) + /// + /// Size of the storage area for the attribute values. + /// Each characteristic contributes to the attrValueArrSize value as follows: + /// - Characteristic value length plus: + /// + 5 bytes if characteristic UUID is 16 bits + /// + 19 bytes if characteristic UUID is 128 bits + /// + 2 bytes if characteristic has a server configuration descriptor + /// + 2 bytes * NumOfLinks if the characteristic has a client configuration descriptor + /// + 2 bytes if the characteristic has extended properties + /// Each descriptor contributes to the attrValueArrSize value as follows: + /// - Descriptor length pub attr_value_arr_size: u16, + /// Maximum number of BLE links supported + /// - Min value: 1 + /// - Max value: 8 pub num_of_links: u8, + /// Disable/enable the extended packet length BLE 5.0 feature + /// - Disable: 0 + /// - Enable: 1 pub extended_packet_length_enable: u8, - pub pr_write_list_size: u8, - pub mb_lock_count: u8, - + /// NOTE: This parameter is ignored by the CPU2 when the parameter "Options" is set to "LL_only" ( see Options description in that structure ) + /// + /// Maximum number of supported "prepare write request" + /// - Min value: given by the macro DEFAULT_PREP_WRITE_LIST_SIZE + /// - Max value: a value higher than the minimum required can be specified, but it is not recommended + pub prepare_write_list_size: u8, + /// NOTE: This parameter is overwritten by the CPU2 with an hardcoded optimal value when the parameter "Options" is set to "LL_only" + /// ( see Options description in that structure ) + /// + /// Number of allocated memory blocks for the BLE stack + /// - Min value: given by the macro MBLOCKS_CALC + /// - Max value: a higher value can improve data throughput performance, but uses more memory + pub block_count: u8, + /// NOTE: This parameter is ignored by the CPU2 when the parameter "Options" is set to "LL_only" ( see Options description in that structure ) + /// + /// Maximum ATT MTU size supported + /// - Min value: 23 + /// - Max value: 512 pub att_mtu: u16, + /// The sleep clock accuracy (ppm value) that used in BLE connected slave mode to calculate the window widening + /// (in combination with the sleep clock accuracy sent by master in CONNECT_REQ PDU), + /// refer to BLE 5.0 specifications - Vol 6 - Part B - chap 4.5.7 and 4.2.2 + /// - Min value: 0 + /// - Max value: 500 (worst possible admitted by specification) pub slave_sca: u16, + /// The sleep clock accuracy handled in master mode. It is used to determine the connection and advertising events timing. + /// It is transmitted to the slave in CONNEC_REQ PDU used by the slave to calculate the window widening, + /// see SlaveSca and Bluetooth Core Specification v5.0 Vol 6 - Part B - chap 4.5.7 and 4.2.2 + /// Possible values: + /// - 251 ppm to 500 ppm: 0 + /// - 151 ppm to 250 ppm: 1 + /// - 101 ppm to 150 ppm: 2 + /// - 76 ppm to 100 ppm: 3 + /// - 51 ppm to 75 ppm: 4 + /// - 31 ppm to 50 ppm: 5 + /// - 21 ppm to 30 ppm: 6 + /// - 0 ppm to 20 ppm: 7 pub master_sca: u8, + /// Some information for Low speed clock mapped in bits field + /// - bit 0: + /// - 1: Calibration for the RF system wakeup clock source + /// - 0: No calibration for the RF system wakeup clock source + /// - bit 1: + /// - 1: STM32W5M Module device + /// - 0: Other devices as STM32WBxx SOC, STM32WB1M module + /// - bit 2: + /// - 1: HSE/1024 Clock config + /// - 0: LSE Clock config pub ls_source: u8, + /// This parameter determines the maximum duration of a slave connection event. When this duration is reached the slave closes + /// the current connections event (whatever is the CE_length parameter specified by the master in HCI_CREATE_CONNECTION HCI command), + /// expressed in units of 625/256 µs (~2.44 µs) + /// - Min value: 0 (if 0 is specified, the master and slave perform only a single TX-RX exchange per connection event) + /// - Max value: 1638400 (4000 ms). A higher value can be specified (max 0xFFFFFFFF) but results in a maximum connection time + /// of 4000 ms as specified. In this case the parameter is not applied, and the predicted CE length calculated on slave is not shortened pub max_conn_event_length: u32, + /// Startup time of the high speed (16 or 32 MHz) crystal oscillator in units of 625/256 µs (~2.44 µs). + /// - Min value: 0 + /// - Max value: 820 (~2 ms). A higher value can be specified, but the value that implemented in stack is forced to ~2 ms pub hs_startup_time: u16, + /// Viterbi implementation in BLE LL reception. + /// - 0: Enable + /// - 1: Disable pub viterbi_enable: u8, - pub ll_only: u8, + /// - bit 0: + /// - 1: LL only + /// - 0: LL + host + /// - bit 1: + /// - 1: no service change desc. + /// - 0: with service change desc. + /// - bit 2: + /// - 1: device name Read-Only + /// - 0: device name R/W + /// - bit 3: + /// - 1: extended advertizing supported + /// - 0: extended advertizing not supported + /// - bit 4: + /// - 1: CS Algo #2 supported + /// - 0: CS Algo #2 not supported + /// - bit 5: + /// - 1: Reduced GATT database in NVM + /// - 0: Full GATT database in NVM + /// - bit 6: + /// - 1: GATT caching is used + /// - 0: GATT caching is not used + /// - bit 7: + /// - 1: LE Power Class 1 + /// - 0: LE Power Classe 2-3 + /// - other bits: complete with Options_extension flag + pub options: u8, + /// Reserved for future use - shall be set to 0 pub hw_version: u8, + // /** + // * Maximum number of connection-oriented channels in initiator mode. + // * Range: 0 .. 64 + // */ + // pub max_coc_initiator_nbr: u8, + // + // /** + // * Minimum transmit power in dBm supported by the Controller. + // * Range: -127 .. 20 + // */ + // pub min_tx_power: i8, + // + // /** + // * Maximum transmit power in dBm supported by the Controller. + // * Range: -127 .. 20 + // */ + // pub max_tx_power: i8, + // + // /** + // * RX model configuration + // * - bit 0: 1: agc_rssi model improved vs RF blockers 0: Legacy agc_rssi model + // * - other bits: reserved ( shall be set to 0) + // */ + // pub rx_model_config: u8, + // + // /* Maximum number of advertising sets. + // * Range: 1 .. 8 with limitation: + // * This parameter is linked to max_adv_data_len such as both compliant with allocated Total memory computed with BLE_EXT_ADV_BUFFER_SIZE based + // * on Max Extended advertising configuration supported. + // * This parameter is considered by the CPU2 when Options has SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV flag set + // */ + // pub max_adv_set_nbr: u8, + // + // /* Maximum advertising data length (in bytes) + // * Range: 31 .. 1650 with limitation: + // * This parameter is linked to max_adv_set_nbr such as both compliant with allocated Total memory computed with BLE_EXT_ADV_BUFFER_SIZE based + // * on Max Extended advertising configuration supported. + // * This parameter is considered by the CPU2 when Options has SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV flag set + // */ + // pub max_adv_data_len: u16, + // + // /* RF TX Path Compensation Value (16-bit signed integer). Units: 0.1 dB. + // * Range: -1280 .. 1280 + // */ + // pub tx_path_compens: i16, + // + // /* RF RX Path Compensation Value (16-bit signed integer). Units: 0.1 dB. + // * Range: -1280 .. 1280 + // */ + // pub rx_path_compens: i16, + // + // /* BLE core specification version (8-bit unsigned integer). + // * values as: 11(5.2), 12(5.3) + // */ + // pub ble_core_version: u8, + // + // /** + // * Options flags extension + // * - bit 0: 1: appearance Writable 0: appearance Read-Only + // * - bit 1: 1: Enhanced ATT supported 0: Enhanced ATT not supported + // * - other bits: reserved ( shall be set to 0) + // */ + // pub options_extension: u8, } impl ShciBleInitCmdParam { - pub fn payload<'a>(&self) -> &'a [u8] { + pub fn payload<'a>(&'a self) -> &'a [u8] { unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::()) } } } @@ -48,8 +355,8 @@ impl Default for ShciBleInitCmdParam { attr_value_arr_size: 1344, num_of_links: 2, extended_packet_length_enable: 1, - pr_write_list_size: 0x3A, - mb_lock_count: 0x79, + prepare_write_list_size: 0x3A, + block_count: 0x79, att_mtu: 156, slave_sca: 500, master_sca: 0, @@ -57,25 +364,12 @@ impl Default for ShciBleInitCmdParam { max_conn_event_length: 0xFFFFFFFF, hs_startup_time: 0x148, viterbi_enable: 1, - ll_only: 0, + options: 0, hw_version: 0, } } } -#[derive(Debug, Clone, Copy, Default)] -#[repr(C, packed)] -pub struct ShciHeader { - metadata: [u32; 3], -} - -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct ShciBleInitCmdPacket { - pub header: ShciHeader, - pub param: ShciBleInitCmdParam, -} - pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE; #[allow(dead_code)] // Not used currently but reserved const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE; diff --git a/embassy-stm32-wpan/src/sys.rs b/embassy-stm32-wpan/src/sys.rs index a185cd4f..2b699b72 100644 --- a/embassy-stm32-wpan/src/sys.rs +++ b/embassy-stm32-wpan/src/sys.rs @@ -1,9 +1,11 @@ use core::marker::PhantomData; +use core::ptr; use crate::cmd::CmdPacket; use crate::consts::TlPacketType; -use crate::evt::EvtBox; -use crate::shci::{ShciBleInitCmdParam, SCHI_OPCODE_BLE_INIT}; +use crate::evt::{CcEvt, EvtBox, EvtPacket}; +#[allow(unused_imports)] +use crate::shci::{SchiCommandStatus, ShciBleInitCmdParam, ShciOpcode}; use crate::tables::{SysTable, WirelessFwInfoTable}; use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; @@ -39,21 +41,35 @@ impl Sys { } } - pub fn write(&self, opcode: u16, payload: &[u8]) { + pub async fn write(&self, opcode: ShciOpcode, payload: &[u8]) { + Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || unsafe { + CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode as u16, payload); + }) + .await; + } + + /// `HW_IPCC_SYS_CmdEvtNot` + pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> SchiCommandStatus { + self.write(opcode, payload).await; + Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await; + unsafe { - CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode, payload); + let p_event_packet = SYS_CMD_BUF.as_ptr() as *const EvtPacket; + let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt; + let p_payload = &((*p_command_event).payload) as *const u8; + + ptr::read_volatile(p_payload).try_into().unwrap() } } - pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) { - debug!("sending SHCI"); + #[cfg(feature = "mac")] + pub async fn shci_c2_mac_802_15_4_init(&self) -> SchiCommandStatus { + self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await + } - Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || { - self.write(SCHI_OPCODE_BLE_INIT, param.payload()); - }) - .await; - - Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await; + #[cfg(feature = "ble")] + pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> SchiCommandStatus { + self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await } /// `HW_IPCC_SYS_EvtNot` diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index 15121695..3f26282c 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -1,6 +1,9 @@ +use core::mem::MaybeUninit; + use bit_field::BitField; use crate::cmd::{AclDataPacket, CmdPacket}; +use crate::consts::{POOL_SIZE, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE}; use crate::unsafe_linked_list::LinkedListNode; #[derive(Debug, Copy, Clone)] @@ -161,6 +164,9 @@ pub struct Mac802_15_4Table { pub evt_queue: *const u8, } +#[repr(C, align(4))] +pub struct AlignedData([u8; L]); + /// Reference table. Contains pointers to all other tables. #[derive(Debug, Copy, Clone)] #[repr(C)] @@ -173,3 +179,94 @@ pub struct RefTable { pub traces_table: *const TracesTable, pub mac_802_15_4_table: *const Mac802_15_4Table, } + +// --------------------- ref table --------------------- +#[link_section = "TL_REF_TABLE"] +pub static mut TL_REF_TABLE: MaybeUninit = MaybeUninit::uninit(); + +#[link_section = "MB_MEM1"] +pub static mut TL_DEVICE_INFO_TABLE: MaybeUninit = MaybeUninit::uninit(); + +#[link_section = "MB_MEM1"] +pub static mut TL_BLE_TABLE: MaybeUninit = MaybeUninit::uninit(); + +#[link_section = "MB_MEM1"] +pub static mut TL_THREAD_TABLE: MaybeUninit = MaybeUninit::uninit(); + +// #[link_section = "MB_MEM1"] +// pub static mut TL_LLD_TESTS_TABLE: MaybeUninit = MaybeUninit::uninit(); + +// #[link_section = "MB_MEM1"] +// pub static mut TL_BLE_LLD_TABLE: MaybeUninit = MaybeUninit::uninit(); + +#[link_section = "MB_MEM1"] +pub static mut TL_SYS_TABLE: MaybeUninit = MaybeUninit::uninit(); + +#[link_section = "MB_MEM1"] +pub static mut TL_MEM_MANAGER_TABLE: MaybeUninit = MaybeUninit::uninit(); + +#[link_section = "MB_MEM1"] +pub static mut TL_TRACES_TABLE: MaybeUninit = MaybeUninit::uninit(); + +#[link_section = "MB_MEM1"] +pub static mut TL_MAC_802_15_4_TABLE: MaybeUninit = MaybeUninit::uninit(); + +// #[link_section = "MB_MEM1"] +// pub static mut TL_ZIGBEE_TABLE: MaybeUninit = MaybeUninit::uninit(); + +// --------------------- tables --------------------- +#[link_section = "MB_MEM1"] +pub static mut FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit(); + +#[allow(dead_code)] +#[link_section = "MB_MEM1"] +pub static mut TRACES_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); + +const CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE; + +#[link_section = "MB_MEM2"] +pub static mut CS_BUFFER: MaybeUninit> = MaybeUninit::uninit(); + +#[link_section = "MB_MEM2"] +pub static mut EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); + +#[link_section = "MB_MEM2"] +pub static mut SYSTEM_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); + +// --------------------- app tables --------------------- +#[cfg(feature = "mac")] +#[link_section = "MB_MEM2"] +pub static mut MAC_802_15_4_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "mac")] +const MAC_802_15_4_NOTIF_RSP_EVT_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255; + +#[cfg(feature = "mac")] +#[link_section = "MB_MEM2"] +pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit> = + MaybeUninit::uninit(); + +#[link_section = "MB_MEM2"] +pub static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); + +#[link_section = "MB_MEM2"] +pub static mut SYS_CMD_BUF: MaybeUninit = MaybeUninit::uninit(); + +const SYS_SPARE_EVT_BUF_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255; + +#[link_section = "MB_MEM2"] +pub static mut SYS_SPARE_EVT_BUF: MaybeUninit> = MaybeUninit::uninit(); + +#[link_section = "MB_MEM1"] +pub static mut BLE_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); + +const BLE_SPARE_EVT_BUF_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255; + +#[link_section = "MB_MEM2"] +pub static mut BLE_SPARE_EVT_BUF: MaybeUninit> = MaybeUninit::uninit(); + +const HCI_ACL_DATA_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + 5 + 251; + +#[link_section = "MB_MEM2"] +// fuck these "magic" numbers from ST ---v---v +pub static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; HCI_ACL_DATA_BUFFER_SIZE]> = MaybeUninit::uninit(); diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 3062226c..37f840c7 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -120,7 +120,6 @@ impl Ipcc { let regs = IPCC::regs(); Self::flush(channel).await; - compiler_fence(Ordering::SeqCst); f(); @@ -136,7 +135,7 @@ impl Ipcc { // This is a race, but is nice for debugging if regs.cpu(0).sr().read().chf(channel as usize) { - trace!("ipcc: ch {}: wait for tx free", channel as u8); + trace!("ipcc: ch {}: wait for tx free", channel as u8); } poll_fn(|cx| { @@ -165,7 +164,7 @@ impl Ipcc { loop { // This is a race, but is nice for debugging if !regs.cpu(1).sr().read().chf(channel as usize) { - trace!("ipcc: ch {}: wait for rx occupied", channel as u8); + trace!("ipcc: ch {}: wait for rx occupied", channel as u8); } poll_fn(|cx| { @@ -186,8 +185,7 @@ impl Ipcc { }) .await; - trace!("ipcc: ch {}: read data", channel as u8); - compiler_fence(Ordering::SeqCst); + trace!("ipcc: ch {}: read data", channel as u8); match f() { Some(ret) => return ret, @@ -237,7 +235,7 @@ pub(crate) mod sealed { } } - pub fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { + pub const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { match channel { IpccChannel::Channel1 => &self.rx_wakers[0], IpccChannel::Channel2 => &self.rx_wakers[1], @@ -248,7 +246,7 @@ pub(crate) mod sealed { } } - pub fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { + pub const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { match channel { IpccChannel::Channel1 => &self.tx_wakers[0], IpccChannel::Channel2 => &self.tx_wakers[1], diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 83a44375..e41424aa 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -20,3 +20,17 @@ embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } + + +[features] +default = ["ble"] +mac = ["embassy-stm32-wpan/mac"] +ble = ["embassy-stm32-wpan/ble"] + +[[bin]] +name = "tl_mbox_ble" +required-features = ["ble"] + +[[bin]] +name = "tl_mbox_mac" +required-features = ["mac"] \ No newline at end of file diff --git a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs similarity index 100% rename from examples/stm32wb/src/bin/tl_mbox_tx_rx.rs rename to examples/stm32wb/src/bin/tl_mbox_ble.rs diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs new file mode 100644 index 00000000..a42939bb --- /dev/null +++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs @@ -0,0 +1,64 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::bind_interrupts; +use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; +use embassy_stm32_wpan::TlMbox; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs{ + IPCC_C1_RX => ReceiveInterruptHandler; + IPCC_C1_TX => TransmitInterruptHandler; +}); + +#[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". + - Select "Start Wireless Stack". + - 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 mbox = TlMbox::init(p.IPCC, Irqs, config); + + let sys_event = mbox.sys_subsystem.read().await; + info!("sys event: {}", sys_event.payload()); + + mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await; + // + // info!("starting ble..."); + // mbox.ble_subsystem.write(0x0c, &[]).await; + // + // info!("waiting for ble..."); + // let ble_event = mbox.ble_subsystem.read().await; + // + // info!("ble event: {}", ble_event.payload()); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 365f631b..fe646927 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -30,7 +30,7 @@ embassy-executor = { version = "0.2.0", path = "../../embassy-executor", feature embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg"] } +embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } defmt = "0.3.0" defmt-rtt = "0.4" diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs index f6641ae3..f47a89b6 100644 --- a/tests/stm32/src/bin/tl_mbox.rs +++ b/tests/stm32/src/bin/tl_mbox.rs @@ -39,7 +39,7 @@ async fn main(spawner: Spawner) { let ready_event = mbox.sys_subsystem.read().await; let _ = poll_once(mbox.sys_subsystem.read()); // clear rx not - info!("coprocessor ready {}", ready_event.payload()); + info!("sys event {:x} : {:x}", ready_event.stub().kind, ready_event.payload()); // test memory manager mem::drop(ready_event); @@ -59,7 +59,8 @@ async fn main(spawner: Spawner) { Timer::after(Duration::from_millis(50)).await; - mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; + let result = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; + info!("subsystem initialization: {}", result); info!("starting ble..."); mbox.ble_subsystem.write(0x0c, &[]).await; @@ -67,9 +68,8 @@ async fn main(spawner: Spawner) { info!("waiting for ble..."); let ble_event = mbox.ble_subsystem.read().await; - info!("ble event: {}", ble_event.payload()); + info!("ble event {:x} : {:x}", ble_event.stub().kind, ble_event.payload()); - Timer::after(Duration::from_millis(150)).await; info!("Test OK"); cortex_m::asm::bkpt(); }