diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs index f0bd6f48c..60e0cbdf8 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/evt.rs b/embassy-stm32-wpan/src/evt.rs index a7b99e540..ee108ec88 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 @@ -129,6 +128,18 @@ impl EvtBox { impl Drop for EvtBox { fn drop(&mut self) { - unsafe { mm::MemoryManager::drop_event_packet(self.ptr) }; + #[cfg(feature = "ble")] + unsafe { + use crate::mm; + + 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 1ddb3f2e0..5aec9933c 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -6,7 +6,6 @@ pub mod fmt; use core::mem::MaybeUninit; use core::sync::atomic::{compiler_fence, Ordering}; -use ble::Ble; use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; use embassy_stm32::interrupt; use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler}; @@ -16,11 +15,14 @@ use sys::Sys; 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; @@ -34,7 +36,10 @@ pub struct TlMbox<'d> { 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> { @@ -122,7 +127,10 @@ impl<'d> TlMbox<'d> { Self { _ipcc: ipcc, 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 000000000..9fbf37473 --- /dev/null +++ b/embassy-stm32-wpan/src/mac.rs @@ -0,0 +1,109 @@ +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::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, +}; +use crate::unsafe_linked_list::LinkedListNode; +use crate::{channels, EVT_QUEUE}; + +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 { + LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); + + 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_CMD_BUFFER.as_mut_ptr(), 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 dc499c1e7..047fddcd4 100644 --- a/embassy-stm32-wpan/src/mm.rs +++ b/embassy-stm32-wpan/src/mm.rs @@ -43,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/tables.rs b/embassy-stm32-wpan/src/tables.rs index 81873b147..2064910f0 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -230,6 +230,15 @@ pub static mut EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); 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")] +#[link_section = "MB_MEM2"] +pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = + MaybeUninit::uninit(); + #[link_section = "MB_MEM2"] pub static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 83a443754..e41424aad 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 000000000..f13f260b5 --- /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_ble_init(Default::default()).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(); +}