diff options
Diffstat (limited to 'embassy-stm32-wpan/src')
47 files changed, 4155 insertions, 1212 deletions
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 40ff14795..3fabe112a 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs | |||
| @@ -13,187 +13,19 @@ | |||
| 13 | 13 | ||
| 14 | #![no_std] | 14 | #![no_std] |
| 15 | #![allow(async_fn_in_trait)] | 15 | #![allow(async_fn_in_trait)] |
| 16 | #![allow(unsafe_op_in_unsafe_fn)] | ||
| 16 | #![doc = include_str!("../README.md")] | 17 | #![doc = include_str!("../README.md")] |
| 17 | // #![warn(missing_docs)] | 18 | // #![warn(missing_docs)] |
| 18 | #![allow(static_mut_refs)] // TODO: Fix | 19 | #![allow(static_mut_refs)] // TODO: Fix |
| 19 | 20 | ||
| 20 | // This must go FIRST so that all the other modules see its macros. | 21 | #[cfg(feature = "wb55")] |
| 21 | mod fmt; | 22 | mod wb55; |
| 22 | 23 | ||
| 23 | use core::mem::MaybeUninit; | 24 | #[cfg(feature = "wb55")] |
| 24 | use core::sync::atomic::{compiler_fence, Ordering}; | 25 | pub use wb55::*; |
| 25 | 26 | ||
| 26 | use embassy_hal_internal::Peri; | 27 | #[cfg(feature = "wba")] |
| 27 | use embassy_stm32::interrupt; | 28 | mod wba; |
| 28 | use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler}; | ||
| 29 | use embassy_stm32::peripherals::IPCC; | ||
| 30 | use sub::mm::MemoryManager; | ||
| 31 | use sub::sys::Sys; | ||
| 32 | use tables::*; | ||
| 33 | use unsafe_linked_list::LinkedListNode; | ||
| 34 | 29 | ||
| 35 | pub mod channels; | 30 | #[cfg(feature = "wba")] |
| 36 | pub mod cmd; | 31 | pub use wba::*; |
| 37 | pub mod consts; | ||
| 38 | pub mod evt; | ||
| 39 | pub mod lhci; | ||
| 40 | pub mod shci; | ||
| 41 | pub mod sub; | ||
| 42 | pub mod tables; | ||
| 43 | pub mod unsafe_linked_list; | ||
| 44 | |||
| 45 | #[cfg(feature = "mac")] | ||
| 46 | pub mod mac; | ||
| 47 | |||
| 48 | #[cfg(feature = "ble")] | ||
| 49 | pub use crate::sub::ble::hci; | ||
| 50 | |||
| 51 | type PacketHeader = LinkedListNode; | ||
| 52 | |||
| 53 | /// Transport Layer for the Mailbox interface | ||
| 54 | pub struct TlMbox<'d> { | ||
| 55 | _ipcc: Peri<'d, IPCC>, | ||
| 56 | |||
| 57 | pub sys_subsystem: Sys, | ||
| 58 | pub mm_subsystem: MemoryManager, | ||
| 59 | #[cfg(feature = "ble")] | ||
| 60 | pub ble_subsystem: sub::ble::Ble, | ||
| 61 | #[cfg(feature = "mac")] | ||
| 62 | pub mac_subsystem: sub::mac::Mac, | ||
| 63 | } | ||
| 64 | |||
| 65 | impl<'d> TlMbox<'d> { | ||
| 66 | /// Initialise the Transport Layer, and creates and returns a wrapper around it. | ||
| 67 | /// | ||
| 68 | /// This method performs the initialisation laid out in AN5289 annex 14.1. However, it differs | ||
| 69 | /// from the implementation documented in Figure 64, to avoid needing to reference any C | ||
| 70 | /// function pointers. | ||
| 71 | /// | ||
| 72 | /// Annex 14.1 lays out the following methods that should be called: | ||
| 73 | /// 1. tl_mbox.c/TL_Init, which initialises the reference table that is shared between CPU1 | ||
| 74 | /// and CPU2. | ||
| 75 | /// 2. shci_tl.c/shci_init(), which initialises the system transport layer, and in turn | ||
| 76 | /// calls tl_mbox.c/TL_SYS_Init, which initialises SYSTEM_EVT_QUEUE channel. | ||
| 77 | /// 3. tl_mbox.c/TL_MM_Init(), which initialises the channel used for sending memory | ||
| 78 | /// manager commands. | ||
| 79 | /// 4. tl_mbox.c/TL_Enable(), which enables the IPCC, and starts CPU2. | ||
| 80 | /// This implementation initialises all of the shared refernce tables and all IPCC channel that | ||
| 81 | /// would be initialised by this process. The developer should therefore treat this method as | ||
| 82 | /// completing all steps in Figure 64. | ||
| 83 | /// | ||
| 84 | /// Once this method has been called, no system commands may be sent until the CPU2 ready | ||
| 85 | /// signal is received, via [sys_subsystem.read]; this completes the procedure laid out in | ||
| 86 | /// Figure 65. | ||
| 87 | /// | ||
| 88 | /// If the `ble` feature is enabled, at this point, the user should call | ||
| 89 | /// [sys_subsystem.shci_c2_ble_init], before any commands are written to the | ||
| 90 | /// [TlMbox.ble_subsystem] ([sub::ble::Ble::new()] completes the process that would otherwise | ||
| 91 | /// be handled by `TL_BLE_Init`; see Figure 66). This completes the procedure laid out in | ||
| 92 | /// Figure 66. | ||
| 93 | // TODO: document what the user should do after calling init to use the mac_802_15_4 subsystem | ||
| 94 | pub fn init( | ||
| 95 | ipcc: Peri<'d, IPCC>, | ||
| 96 | _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler> | ||
| 97 | + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>, | ||
| 98 | config: Config, | ||
| 99 | ) -> Self { | ||
| 100 | // this is an inlined version of TL_Init from the STM32WB firmware as requested by AN5289. | ||
| 101 | // HW_IPCC_Init is not called, and its purpose is (presumably?) covered by this | ||
| 102 | // implementation | ||
| 103 | unsafe { | ||
| 104 | TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable { | ||
| 105 | device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), | ||
| 106 | ble_table: TL_BLE_TABLE.as_ptr(), | ||
| 107 | thread_table: TL_THREAD_TABLE.as_ptr(), | ||
| 108 | sys_table: TL_SYS_TABLE.as_ptr(), | ||
| 109 | mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(), | ||
| 110 | traces_table: TL_TRACES_TABLE.as_ptr(), | ||
| 111 | mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(), | ||
| 112 | zigbee_table: TL_ZIGBEE_TABLE.as_ptr(), | ||
| 113 | lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(), | ||
| 114 | ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(), | ||
| 115 | }); | ||
| 116 | |||
| 117 | TL_SYS_TABLE | ||
| 118 | .as_mut_ptr() | ||
| 119 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 120 | TL_DEVICE_INFO_TABLE | ||
| 121 | .as_mut_ptr() | ||
| 122 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 123 | TL_BLE_TABLE | ||
| 124 | .as_mut_ptr() | ||
| 125 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 126 | TL_THREAD_TABLE | ||
| 127 | .as_mut_ptr() | ||
| 128 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 129 | TL_MEM_MANAGER_TABLE | ||
| 130 | .as_mut_ptr() | ||
| 131 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 132 | |||
| 133 | TL_TRACES_TABLE | ||
| 134 | .as_mut_ptr() | ||
| 135 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 136 | TL_MAC_802_15_4_TABLE | ||
| 137 | .as_mut_ptr() | ||
| 138 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 139 | TL_ZIGBEE_TABLE | ||
| 140 | .as_mut_ptr() | ||
| 141 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 142 | TL_LLD_TESTS_TABLE | ||
| 143 | .as_mut_ptr() | ||
| 144 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 145 | TL_BLE_LLD_TABLE | ||
| 146 | .as_mut_ptr() | ||
| 147 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 148 | |||
| 149 | EVT_POOL | ||
| 150 | .as_mut_ptr() | ||
| 151 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 152 | SYS_SPARE_EVT_BUF | ||
| 153 | .as_mut_ptr() | ||
| 154 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 155 | CS_BUFFER | ||
| 156 | .as_mut_ptr() | ||
| 157 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 158 | |||
| 159 | #[cfg(feature = "ble")] | ||
| 160 | { | ||
| 161 | BLE_SPARE_EVT_BUF | ||
| 162 | .as_mut_ptr() | ||
| 163 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 164 | |||
| 165 | BLE_CMD_BUFFER | ||
| 166 | .as_mut_ptr() | ||
| 167 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 168 | HCI_ACL_DATA_BUFFER | ||
| 169 | .as_mut_ptr() | ||
| 170 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 171 | } | ||
| 172 | |||
| 173 | #[cfg(feature = "mac")] | ||
| 174 | { | ||
| 175 | MAC_802_15_4_CMD_BUFFER | ||
| 176 | .as_mut_ptr() | ||
| 177 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 178 | MAC_802_15_4_NOTIF_RSP_EVT_BUFFER | ||
| 179 | .as_mut_ptr() | ||
| 180 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | compiler_fence(Ordering::SeqCst); | ||
| 185 | |||
| 186 | // this is equivalent to `HW_IPCC_Enable`, which is called by `TL_Enable` | ||
| 187 | Ipcc::enable(config); | ||
| 188 | |||
| 189 | Self { | ||
| 190 | _ipcc: ipcc, | ||
| 191 | sys_subsystem: sub::sys::Sys::new(), | ||
| 192 | #[cfg(feature = "ble")] | ||
| 193 | ble_subsystem: sub::ble::Ble::new(), | ||
| 194 | #[cfg(feature = "mac")] | ||
| 195 | mac_subsystem: sub::mac::Mac::new(), | ||
| 196 | mm_subsystem: sub::mm::MemoryManager::new(), | ||
| 197 | } | ||
| 198 | } | ||
| 199 | } | ||
diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs deleted file mode 100644 index e8d2f9f7b..000000000 --- a/embassy-stm32-wpan/src/mac/control.rs +++ /dev/null | |||
| @@ -1,95 +0,0 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::task; | ||
| 3 | use core::task::Poll; | ||
| 4 | |||
| 5 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 6 | use embassy_sync::mutex::MutexGuard; | ||
| 7 | use embassy_sync::signal::Signal; | ||
| 8 | use futures_util::FutureExt; | ||
| 9 | |||
| 10 | use super::commands::MacCommand; | ||
| 11 | use super::event::MacEvent; | ||
| 12 | use super::typedefs::MacError; | ||
| 13 | use crate::mac::runner::Runner; | ||
| 14 | |||
| 15 | pub struct Control<'a> { | ||
| 16 | runner: &'a Runner<'a>, | ||
| 17 | } | ||
| 18 | |||
| 19 | impl<'a> Control<'a> { | ||
| 20 | pub(crate) fn new(runner: &'a Runner<'a>) -> Self { | ||
| 21 | Self { runner: runner } | ||
| 22 | } | ||
| 23 | |||
| 24 | pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError> | ||
| 25 | where | ||
| 26 | T: MacCommand, | ||
| 27 | { | ||
| 28 | let _wm = self.runner.write_mutex.lock().await; | ||
| 29 | |||
| 30 | self.runner.mac_subsystem.send_command(cmd).await | ||
| 31 | } | ||
| 32 | |||
| 33 | pub async fn send_command_and_get_response<T>(&self, cmd: &T) -> Result<EventToken<'a>, MacError> | ||
| 34 | where | ||
| 35 | T: MacCommand, | ||
| 36 | { | ||
| 37 | let rm = self.runner.read_mutex.lock().await; | ||
| 38 | let _wm = self.runner.write_mutex.lock().await; | ||
| 39 | let token = EventToken::new(self.runner, rm); | ||
| 40 | |||
| 41 | self.runner.mac_subsystem.send_command(cmd).await?; | ||
| 42 | |||
| 43 | Ok(token) | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | pub struct EventToken<'a> { | ||
| 48 | runner: &'a Runner<'a>, | ||
| 49 | _mutex_guard: MutexGuard<'a, CriticalSectionRawMutex, ()>, | ||
| 50 | } | ||
| 51 | |||
| 52 | impl<'a> EventToken<'a> { | ||
| 53 | pub(crate) fn new(runner: &'a Runner<'a>, mutex_guard: MutexGuard<'a, CriticalSectionRawMutex, ()>) -> Self { | ||
| 54 | // Enable event receiving | ||
| 55 | runner.rx_event_channel.lock(|s| { | ||
| 56 | *s.borrow_mut() = Some(Signal::new()); | ||
| 57 | }); | ||
| 58 | |||
| 59 | Self { | ||
| 60 | runner: runner, | ||
| 61 | _mutex_guard: mutex_guard, | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | impl<'a> Future for EventToken<'a> { | ||
| 67 | type Output = MacEvent<'a>; | ||
| 68 | |||
| 69 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||
| 70 | self.get_mut().runner.rx_event_channel.lock(|s| { | ||
| 71 | let signal = s.borrow_mut(); | ||
| 72 | let signal = match &*signal { | ||
| 73 | Some(s) => s, | ||
| 74 | _ => unreachable!(), | ||
| 75 | }; | ||
| 76 | |||
| 77 | let result = match signal.wait().poll_unpin(cx) { | ||
| 78 | Poll::Ready(mac_event) => Poll::Ready(mac_event), | ||
| 79 | Poll::Pending => Poll::Pending, | ||
| 80 | }; | ||
| 81 | |||
| 82 | result | ||
| 83 | }) | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | impl<'a> Drop for EventToken<'a> { | ||
| 88 | fn drop(&mut self) { | ||
| 89 | // Disable event receiving | ||
| 90 | // This will also drop the contained event, if it exists, and will free up receiving the next event | ||
| 91 | self.runner.rx_event_channel.lock(|s| { | ||
| 92 | *s.borrow_mut() = None; | ||
| 93 | }); | ||
| 94 | } | ||
| 95 | } | ||
diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs deleted file mode 100644 index 41cca09e3..000000000 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ /dev/null | |||
| @@ -1,120 +0,0 @@ | |||
| 1 | #![deny(unused_must_use)] | ||
| 2 | |||
| 3 | use core::task::Context; | ||
| 4 | |||
| 5 | use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; | ||
| 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 7 | use embassy_sync::channel::Channel; | ||
| 8 | |||
| 9 | use crate::mac::event::MacEvent; | ||
| 10 | use crate::mac::runner::Runner; | ||
| 11 | use crate::mac::MTU; | ||
| 12 | |||
| 13 | pub struct Driver<'d> { | ||
| 14 | runner: &'d Runner<'d>, | ||
| 15 | } | ||
| 16 | |||
| 17 | impl<'d> Driver<'d> { | ||
| 18 | pub(crate) fn new(runner: &'d Runner<'d>) -> Self { | ||
| 19 | Self { runner: runner } | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | impl<'d> embassy_net_driver::Driver for Driver<'d> { | ||
| 24 | // type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; | ||
| 25 | // type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; | ||
| 26 | type RxToken<'a> | ||
| 27 | = RxToken<'d> | ||
| 28 | where | ||
| 29 | Self: 'a; | ||
| 30 | type TxToken<'a> | ||
| 31 | = TxToken<'d> | ||
| 32 | where | ||
| 33 | Self: 'a; | ||
| 34 | |||
| 35 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { | ||
| 36 | if self.runner.rx_channel.poll_ready_to_receive(cx).is_ready() | ||
| 37 | && self.runner.tx_buf_channel.poll_ready_to_receive(cx).is_ready() | ||
| 38 | { | ||
| 39 | Some(( | ||
| 40 | RxToken { | ||
| 41 | rx: &self.runner.rx_channel, | ||
| 42 | }, | ||
| 43 | TxToken { | ||
| 44 | tx: &self.runner.tx_channel, | ||
| 45 | tx_buf: &self.runner.tx_buf_channel, | ||
| 46 | }, | ||
| 47 | )) | ||
| 48 | } else { | ||
| 49 | None | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> { | ||
| 54 | if self.runner.tx_buf_channel.poll_ready_to_receive(cx).is_ready() { | ||
| 55 | Some(TxToken { | ||
| 56 | tx: &self.runner.tx_channel, | ||
| 57 | tx_buf: &self.runner.tx_buf_channel, | ||
| 58 | }) | ||
| 59 | } else { | ||
| 60 | None | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | fn capabilities(&self) -> Capabilities { | ||
| 65 | let mut caps = Capabilities::default(); | ||
| 66 | caps.max_transmission_unit = MTU; | ||
| 67 | // caps.max_burst_size = Some(self.tx.len()); | ||
| 68 | caps | ||
| 69 | } | ||
| 70 | |||
| 71 | fn link_state(&mut self, _cx: &mut Context) -> LinkState { | ||
| 72 | LinkState::Down | ||
| 73 | } | ||
| 74 | |||
| 75 | fn hardware_address(&self) -> HardwareAddress { | ||
| 76 | // self.mac_addr | ||
| 77 | HardwareAddress::Ieee802154([0; 8]) | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | pub struct RxToken<'d> { | ||
| 82 | rx: &'d Channel<CriticalSectionRawMutex, MacEvent<'d>, 1>, | ||
| 83 | } | ||
| 84 | |||
| 85 | impl<'d> embassy_net_driver::RxToken for RxToken<'d> { | ||
| 86 | fn consume<R, F>(self, f: F) -> R | ||
| 87 | where | ||
| 88 | F: FnOnce(&mut [u8]) -> R, | ||
| 89 | { | ||
| 90 | // Only valid data events should be put into the queue | ||
| 91 | |||
| 92 | let data_event = match self.rx.try_receive().unwrap() { | ||
| 93 | MacEvent::McpsDataInd(data_event) => data_event, | ||
| 94 | _ => unreachable!(), | ||
| 95 | }; | ||
| 96 | |||
| 97 | f(&mut data_event.payload()) | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | pub struct TxToken<'d> { | ||
| 102 | tx: &'d Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), 5>, | ||
| 103 | tx_buf: &'d Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], 5>, | ||
| 104 | } | ||
| 105 | |||
| 106 | impl<'d> embassy_net_driver::TxToken for TxToken<'d> { | ||
| 107 | fn consume<R, F>(self, len: usize, f: F) -> R | ||
| 108 | where | ||
| 109 | F: FnOnce(&mut [u8]) -> R, | ||
| 110 | { | ||
| 111 | // Only valid tx buffers should be put into the queue | ||
| 112 | let buf = self.tx_buf.try_receive().unwrap(); | ||
| 113 | let r = f(&mut buf[..len]); | ||
| 114 | |||
| 115 | // The tx channel should always be of equal capacity to the tx_buf channel | ||
| 116 | self.tx.try_send((buf, len)).unwrap(); | ||
| 117 | |||
| 118 | r | ||
| 119 | } | ||
| 120 | } | ||
diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs deleted file mode 100644 index d3099b6b7..000000000 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ /dev/null | |||
| @@ -1,109 +0,0 @@ | |||
| 1 | use core::cell::RefCell; | ||
| 2 | |||
| 3 | use embassy_futures::join; | ||
| 4 | use embassy_sync::blocking_mutex; | ||
| 5 | use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; | ||
| 6 | use embassy_sync::channel::Channel; | ||
| 7 | use embassy_sync::mutex::Mutex; | ||
| 8 | use embassy_sync::signal::Signal; | ||
| 9 | |||
| 10 | use crate::mac::commands::DataRequest; | ||
| 11 | use crate::mac::event::MacEvent; | ||
| 12 | use crate::mac::typedefs::{AddressMode, MacAddress, PanId, SecurityLevel}; | ||
| 13 | use crate::mac::MTU; | ||
| 14 | use crate::sub::mac::Mac; | ||
| 15 | |||
| 16 | type ZeroCopyPubSub<M, T> = blocking_mutex::Mutex<M, RefCell<Option<Signal<NoopRawMutex, T>>>>; | ||
| 17 | |||
| 18 | pub struct Runner<'a> { | ||
| 19 | pub(crate) mac_subsystem: Mac, | ||
| 20 | // rx event backpressure is already provided through the MacEvent drop mechanism | ||
| 21 | // therefore, we don't need to worry about overwriting events | ||
| 22 | pub(crate) rx_event_channel: ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, | ||
| 23 | pub(crate) read_mutex: Mutex<CriticalSectionRawMutex, ()>, | ||
| 24 | pub(crate) write_mutex: Mutex<CriticalSectionRawMutex, ()>, | ||
| 25 | pub(crate) rx_channel: Channel<CriticalSectionRawMutex, MacEvent<'a>, 1>, | ||
| 26 | pub(crate) tx_channel: Channel<CriticalSectionRawMutex, (&'a mut [u8; MTU], usize), 5>, | ||
| 27 | pub(crate) tx_buf_channel: Channel<CriticalSectionRawMutex, &'a mut [u8; MTU], 5>, | ||
| 28 | } | ||
| 29 | |||
| 30 | impl<'a> Runner<'a> { | ||
| 31 | pub fn new(mac: Mac, tx_buf_queue: [&'a mut [u8; MTU]; 5]) -> Self { | ||
| 32 | let this = Self { | ||
| 33 | mac_subsystem: mac, | ||
| 34 | rx_event_channel: blocking_mutex::Mutex::new(RefCell::new(None)), | ||
| 35 | read_mutex: Mutex::new(()), | ||
| 36 | write_mutex: Mutex::new(()), | ||
| 37 | rx_channel: Channel::new(), | ||
| 38 | tx_channel: Channel::new(), | ||
| 39 | tx_buf_channel: Channel::new(), | ||
| 40 | }; | ||
| 41 | |||
| 42 | for buf in tx_buf_queue { | ||
| 43 | this.tx_buf_channel.try_send(buf).unwrap(); | ||
| 44 | } | ||
| 45 | |||
| 46 | this | ||
| 47 | } | ||
| 48 | |||
| 49 | pub async fn run(&'a self) -> ! { | ||
| 50 | join::join( | ||
| 51 | async { | ||
| 52 | loop { | ||
| 53 | if let Ok(mac_event) = self.mac_subsystem.read().await { | ||
| 54 | match mac_event { | ||
| 55 | MacEvent::McpsDataInd(_) => { | ||
| 56 | self.rx_channel.send(mac_event).await; | ||
| 57 | } | ||
| 58 | _ => { | ||
| 59 | self.rx_event_channel.lock(|s| { | ||
| 60 | match &*s.borrow() { | ||
| 61 | Some(signal) => { | ||
| 62 | signal.signal(mac_event); | ||
| 63 | } | ||
| 64 | None => {} | ||
| 65 | }; | ||
| 66 | }); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | }, | ||
| 72 | async { | ||
| 73 | let mut msdu_handle = 0x02; | ||
| 74 | |||
| 75 | loop { | ||
| 76 | let (buf, len) = self.tx_channel.receive().await; | ||
| 77 | let _wm = self.write_mutex.lock().await; | ||
| 78 | |||
| 79 | // The mutex should be dropped on the next loop iteration | ||
| 80 | self.mac_subsystem | ||
| 81 | .send_command( | ||
| 82 | DataRequest { | ||
| 83 | src_addr_mode: AddressMode::Short, | ||
| 84 | dst_addr_mode: AddressMode::Short, | ||
| 85 | dst_pan_id: PanId([0x1A, 0xAA]), | ||
| 86 | dst_address: MacAddress::BROADCAST, | ||
| 87 | msdu_handle: msdu_handle, | ||
| 88 | ack_tx: 0x00, | ||
| 89 | gts_tx: false, | ||
| 90 | security_level: SecurityLevel::Unsecure, | ||
| 91 | ..Default::default() | ||
| 92 | } | ||
| 93 | .set_buffer(&buf[..len]), | ||
| 94 | ) | ||
| 95 | .await | ||
| 96 | .unwrap(); | ||
| 97 | |||
| 98 | msdu_handle = msdu_handle.wrapping_add(1); | ||
| 99 | |||
| 100 | // The tx channel should always be of equal capacity to the tx_buf channel | ||
| 101 | self.tx_buf_channel.try_send(buf).unwrap(); | ||
| 102 | } | ||
| 103 | }, | ||
| 104 | ) | ||
| 105 | .await; | ||
| 106 | |||
| 107 | loop {} | ||
| 108 | } | ||
| 109 | } | ||
diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs deleted file mode 100644 index baf4da979..000000000 --- a/embassy-stm32-wpan/src/sub/mac.rs +++ /dev/null | |||
| @@ -1,124 +0,0 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::ptr; | ||
| 3 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use embassy_futures::poll_once; | ||
| 7 | use embassy_stm32::ipcc::Ipcc; | ||
| 8 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 9 | |||
| 10 | use crate::cmd::CmdPacket; | ||
| 11 | use crate::consts::TlPacketType; | ||
| 12 | use crate::evt::{EvtBox, EvtPacket}; | ||
| 13 | use crate::mac::commands::MacCommand; | ||
| 14 | use crate::mac::event::MacEvent; | ||
| 15 | use crate::mac::typedefs::MacError; | ||
| 16 | use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER}; | ||
| 17 | use crate::{channels, evt}; | ||
| 18 | |||
| 19 | static MAC_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 20 | static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); | ||
| 21 | |||
| 22 | pub struct Mac { | ||
| 23 | _private: (), | ||
| 24 | } | ||
| 25 | |||
| 26 | impl Mac { | ||
| 27 | pub(crate) fn new() -> Self { | ||
| 28 | Self { _private: () } | ||
| 29 | } | ||
| 30 | |||
| 31 | /// `HW_IPCC_MAC_802_15_4_EvtNot` | ||
| 32 | /// | ||
| 33 | /// This function will stall if the previous `EvtBox` has not been dropped | ||
| 34 | pub async fn tl_read(&self) -> EvtBox<Self> { | ||
| 35 | // Wait for the last event box to be dropped | ||
| 36 | poll_fn(|cx| { | ||
| 37 | MAC_WAKER.register(cx.waker()); | ||
| 38 | if MAC_EVT_OUT.load(Ordering::SeqCst) { | ||
| 39 | Poll::Pending | ||
| 40 | } else { | ||
| 41 | Poll::Ready(()) | ||
| 42 | } | ||
| 43 | }) | ||
| 44 | .await; | ||
| 45 | |||
| 46 | // Return a new event box | ||
| 47 | Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe { | ||
| 48 | // The closure is not async, therefore the closure must execute to completion (cannot be dropped) | ||
| 49 | // Therefore, the event box is guaranteed to be cleaned up if it's not leaked | ||
| 50 | MAC_EVT_OUT.store(true, Ordering::SeqCst); | ||
| 51 | |||
| 52 | Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _)) | ||
| 53 | }) | ||
| 54 | .await | ||
| 55 | } | ||
| 56 | |||
| 57 | /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` | ||
| 58 | pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { | ||
| 59 | self.tl_write(opcode, payload).await; | ||
| 60 | Ipcc::flush(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL).await; | ||
| 61 | |||
| 62 | unsafe { | ||
| 63 | let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket; | ||
| 64 | let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8; | ||
| 65 | |||
| 66 | ptr::read_volatile(p_mac_rsp_evt) | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | /// `TL_MAC_802_15_4_SendCmd` | ||
| 71 | pub async fn tl_write(&self, opcode: u16, payload: &[u8]) { | ||
| 72 | Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe { | ||
| 73 | CmdPacket::write_into( | ||
| 74 | MAC_802_15_4_CMD_BUFFER.as_mut_ptr(), | ||
| 75 | TlPacketType::MacCmd, | ||
| 76 | opcode, | ||
| 77 | payload, | ||
| 78 | ); | ||
| 79 | }) | ||
| 80 | .await; | ||
| 81 | } | ||
| 82 | |||
| 83 | pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError> | ||
| 84 | where | ||
| 85 | T: MacCommand, | ||
| 86 | { | ||
| 87 | let response = self.tl_write_and_get_response(T::OPCODE as u16, cmd.payload()).await; | ||
| 88 | |||
| 89 | if response == 0x00 { | ||
| 90 | Ok(()) | ||
| 91 | } else { | ||
| 92 | Err(MacError::from(response)) | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | pub async fn read(&self) -> Result<MacEvent<'_>, ()> { | ||
| 97 | MacEvent::new(self.tl_read().await) | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | impl evt::MemoryManager for Mac { | ||
| 102 | /// SAFETY: passing a pointer to something other than a managed event packet is UB | ||
| 103 | unsafe fn drop_event_packet(_: *mut EvtPacket) { | ||
| 104 | trace!("mac drop event"); | ||
| 105 | |||
| 106 | // Write the ack | ||
| 107 | CmdPacket::write_into( | ||
| 108 | MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, | ||
| 109 | TlPacketType::OtAck, | ||
| 110 | 0, | ||
| 111 | &[], | ||
| 112 | ); | ||
| 113 | |||
| 114 | // Clear the rx flag | ||
| 115 | let _ = poll_once(Ipcc::receive::<()>( | ||
| 116 | channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, | ||
| 117 | || None, | ||
| 118 | )); | ||
| 119 | |||
| 120 | // Allow a new read call | ||
| 121 | MAC_EVT_OUT.store(false, Ordering::SeqCst); | ||
| 122 | MAC_WAKER.wake(); | ||
| 123 | } | ||
| 124 | } | ||
diff --git a/embassy-stm32-wpan/src/sub/mod.rs b/embassy-stm32-wpan/src/sub/mod.rs deleted file mode 100644 index bee3dbdf1..000000000 --- a/embassy-stm32-wpan/src/sub/mod.rs +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | #[cfg(feature = "ble")] | ||
| 2 | pub mod ble; | ||
| 3 | #[cfg(feature = "mac")] | ||
| 4 | pub mod mac; | ||
| 5 | pub mod mm; | ||
| 6 | pub mod sys; | ||
diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs deleted file mode 100644 index cf6df58bf..000000000 --- a/embassy-stm32-wpan/src/sub/sys.rs +++ /dev/null | |||
| @@ -1,116 +0,0 @@ | |||
| 1 | use core::ptr; | ||
| 2 | |||
| 3 | use crate::cmd::CmdPacket; | ||
| 4 | use crate::consts::TlPacketType; | ||
| 5 | use crate::evt::{CcEvt, EvtBox, EvtPacket}; | ||
| 6 | #[allow(unused_imports)] | ||
| 7 | use crate::shci::{SchiCommandStatus, ShciBleInitCmdParam, ShciOpcode}; | ||
| 8 | use crate::sub::mm; | ||
| 9 | use crate::tables::{SysTable, WirelessFwInfoTable}; | ||
| 10 | use crate::unsafe_linked_list::LinkedListNode; | ||
| 11 | use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; | ||
| 12 | |||
| 13 | /// A guard that, once constructed, allows for sys commands to be sent to CPU2. | ||
| 14 | pub struct Sys { | ||
| 15 | _private: (), | ||
| 16 | } | ||
| 17 | |||
| 18 | impl Sys { | ||
| 19 | /// TL_Sys_Init | ||
| 20 | pub(crate) fn new() -> Self { | ||
| 21 | unsafe { | ||
| 22 | LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); | ||
| 23 | |||
| 24 | TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable { | ||
| 25 | pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(), | ||
| 26 | sys_queue: SYSTEM_EVT_QUEUE.as_ptr(), | ||
| 27 | }); | ||
| 28 | } | ||
| 29 | |||
| 30 | Self { _private: () } | ||
| 31 | } | ||
| 32 | |||
| 33 | /// Returns CPU2 wireless firmware information (if present). | ||
| 34 | pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> { | ||
| 35 | let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table }; | ||
| 36 | |||
| 37 | // Zero version indicates that CPU2 wasn't active and didn't fill the information table | ||
| 38 | if info.version != 0 { | ||
| 39 | Some(info) | ||
| 40 | } else { | ||
| 41 | None | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | pub async fn write(&self, opcode: ShciOpcode, payload: &[u8]) { | ||
| 46 | Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || unsafe { | ||
| 47 | CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode as u16, payload); | ||
| 48 | }) | ||
| 49 | .await; | ||
| 50 | } | ||
| 51 | |||
| 52 | /// `HW_IPCC_SYS_CmdEvtNot` | ||
| 53 | pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> Result<SchiCommandStatus, ()> { | ||
| 54 | self.write(opcode, payload).await; | ||
| 55 | Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await; | ||
| 56 | |||
| 57 | unsafe { | ||
| 58 | let p_event_packet = SYS_CMD_BUF.as_ptr() as *const EvtPacket; | ||
| 59 | let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt; | ||
| 60 | let p_payload = &((*p_command_event).payload) as *const u8; | ||
| 61 | |||
| 62 | ptr::read_volatile(p_payload).try_into() | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | #[cfg(feature = "mac")] | ||
| 67 | pub async fn shci_c2_mac_802_15_4_init(&self) -> Result<SchiCommandStatus, ()> { | ||
| 68 | use crate::tables::{ | ||
| 69 | Mac802_15_4Table, TracesTable, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, | ||
| 70 | TL_MAC_802_15_4_TABLE, TL_TRACES_TABLE, TRACES_EVT_QUEUE, | ||
| 71 | }; | ||
| 72 | |||
| 73 | unsafe { | ||
| 74 | LinkedListNode::init_head(TRACES_EVT_QUEUE.as_mut_ptr() as *mut _); | ||
| 75 | |||
| 76 | TL_TRACES_TABLE.as_mut_ptr().write_volatile(TracesTable { | ||
| 77 | traces_queue: TRACES_EVT_QUEUE.as_ptr() as *const _, | ||
| 78 | }); | ||
| 79 | |||
| 80 | TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table { | ||
| 81 | p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(), | ||
| 82 | p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(), | ||
| 83 | evt_queue: core::ptr::null_mut(), | ||
| 84 | }); | ||
| 85 | }; | ||
| 86 | |||
| 87 | self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Send a request to CPU2 to initialise the BLE stack. | ||
| 91 | /// | ||
| 92 | /// This must be called before any BLE commands are sent via the BLE channel (according to | ||
| 93 | /// AN5289, Figures 65 and 66). It should only be called after CPU2 sends a system event, via | ||
| 94 | /// `HW_IPCC_SYS_EvtNot`, aka `IoBusCallBackUserEvt` (as detailed in Figure 65), aka | ||
| 95 | /// [crate::sub::ble::hci::host::uart::UartHci::read]. | ||
| 96 | #[cfg(feature = "ble")] | ||
| 97 | pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result<SchiCommandStatus, ()> { | ||
| 98 | self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await | ||
| 99 | } | ||
| 100 | |||
| 101 | /// `HW_IPCC_SYS_EvtNot` | ||
| 102 | /// | ||
| 103 | /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`, | ||
| 104 | /// as the embassy implementation avoids the need to call C public bindings, and instead | ||
| 105 | /// handles the event channels directly. | ||
| 106 | pub async fn read(&self) -> EvtBox<mm::MemoryManager> { | ||
| 107 | Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe { | ||
| 108 | if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) { | ||
| 109 | Some(EvtBox::new(node_ptr.cast())) | ||
| 110 | } else { | ||
| 111 | None | ||
| 112 | } | ||
| 113 | }) | ||
| 114 | .await | ||
| 115 | } | ||
| 116 | } | ||
diff --git a/embassy-stm32-wpan/src/unsafe_linked_list.rs b/embassy-stm32-wpan/src/unsafe_linked_list.rs deleted file mode 100644 index d8bc29763..000000000 --- a/embassy-stm32-wpan/src/unsafe_linked_list.rs +++ /dev/null | |||
| @@ -1,257 +0,0 @@ | |||
| 1 | //! Unsafe linked list. | ||
| 2 | //! Translated from ST's C by `c2rust` tool. | ||
| 3 | |||
| 4 | #![allow( | ||
| 5 | dead_code, | ||
| 6 | mutable_transmutes, | ||
| 7 | non_camel_case_types, | ||
| 8 | non_snake_case, | ||
| 9 | non_upper_case_globals, | ||
| 10 | unused_assignments, | ||
| 11 | unused_mut | ||
| 12 | )] | ||
| 13 | |||
| 14 | use core::ptr; | ||
| 15 | |||
| 16 | use cortex_m::interrupt; | ||
| 17 | |||
| 18 | #[derive(Copy, Clone)] | ||
| 19 | #[repr(C, packed(4))] | ||
| 20 | pub struct LinkedListNode { | ||
| 21 | pub next: *mut LinkedListNode, | ||
| 22 | pub prev: *mut LinkedListNode, | ||
| 23 | } | ||
| 24 | |||
| 25 | impl Default for LinkedListNode { | ||
| 26 | fn default() -> Self { | ||
| 27 | LinkedListNode { | ||
| 28 | next: core::ptr::null_mut(), | ||
| 29 | prev: core::ptr::null_mut(), | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | impl LinkedListNode { | ||
| 35 | pub unsafe fn init_head(mut p_list_head: *mut LinkedListNode) { | ||
| 36 | ptr::write_volatile( | ||
| 37 | p_list_head, | ||
| 38 | LinkedListNode { | ||
| 39 | next: p_list_head, | ||
| 40 | prev: p_list_head, | ||
| 41 | }, | ||
| 42 | ); | ||
| 43 | } | ||
| 44 | |||
| 45 | pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool { | ||
| 46 | interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head) | ||
| 47 | } | ||
| 48 | |||
| 49 | /// Insert `node` after `list_head` and before the next node | ||
| 50 | pub unsafe fn insert_head(mut p_list_head: *mut LinkedListNode, mut p_node: *mut LinkedListNode) { | ||
| 51 | interrupt::free(|_| { | ||
| 52 | let mut list_head = ptr::read_volatile(p_list_head); | ||
| 53 | if p_list_head != list_head.next { | ||
| 54 | let mut node_next = ptr::read_volatile(list_head.next); | ||
| 55 | let node = LinkedListNode { | ||
| 56 | next: list_head.next, | ||
| 57 | prev: p_list_head, | ||
| 58 | }; | ||
| 59 | |||
| 60 | list_head.next = p_node; | ||
| 61 | node_next.prev = p_node; | ||
| 62 | |||
| 63 | // All nodes must be written because they will all be seen by another core | ||
| 64 | ptr::write_volatile(p_node, node); | ||
| 65 | ptr::write_volatile(node.next, node_next); | ||
| 66 | ptr::write_volatile(p_list_head, list_head); | ||
| 67 | } else { | ||
| 68 | let node = LinkedListNode { | ||
| 69 | next: list_head.next, | ||
| 70 | prev: p_list_head, | ||
| 71 | }; | ||
| 72 | |||
| 73 | list_head.next = p_node; | ||
| 74 | list_head.prev = p_node; | ||
| 75 | |||
| 76 | // All nodes must be written because they will all be seen by another core | ||
| 77 | ptr::write_volatile(p_node, node); | ||
| 78 | ptr::write_volatile(p_list_head, list_head); | ||
| 79 | } | ||
| 80 | }); | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Insert `node` before `list_tail` and after the second-to-last node | ||
| 84 | pub unsafe fn insert_tail(mut p_list_tail: *mut LinkedListNode, mut p_node: *mut LinkedListNode) { | ||
| 85 | interrupt::free(|_| { | ||
| 86 | let mut list_tail = ptr::read_volatile(p_list_tail); | ||
| 87 | if p_list_tail != list_tail.prev { | ||
| 88 | let mut node_prev = ptr::read_volatile(list_tail.prev); | ||
| 89 | let node = LinkedListNode { | ||
| 90 | next: p_list_tail, | ||
| 91 | prev: list_tail.prev, | ||
| 92 | }; | ||
| 93 | |||
| 94 | list_tail.prev = p_node; | ||
| 95 | node_prev.next = p_node; | ||
| 96 | |||
| 97 | // All nodes must be written because they will all be seen by another core | ||
| 98 | ptr::write_volatile(p_node, node); | ||
| 99 | ptr::write_volatile(node.prev, node_prev); | ||
| 100 | ptr::write_volatile(p_list_tail, list_tail); | ||
| 101 | } else { | ||
| 102 | let node = LinkedListNode { | ||
| 103 | next: p_list_tail, | ||
| 104 | prev: list_tail.prev, | ||
| 105 | }; | ||
| 106 | |||
| 107 | list_tail.prev = p_node; | ||
| 108 | list_tail.next = p_node; | ||
| 109 | |||
| 110 | // All nodes must be written because they will all be seen by another core | ||
| 111 | ptr::write_volatile(p_node, node); | ||
| 112 | ptr::write_volatile(p_list_tail, list_tail); | ||
| 113 | } | ||
| 114 | }); | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Remove `node` from the linked list | ||
| 118 | pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) { | ||
| 119 | interrupt::free(|_| { | ||
| 120 | // trace!("remove node: {:x}", p_node); | ||
| 121 | // apparently linked list nodes are not always aligned. | ||
| 122 | // if more hardfaults occur, more of these may need to be converted to unaligned. | ||
| 123 | let node = ptr::read_unaligned(p_node); | ||
| 124 | // trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next); | ||
| 125 | |||
| 126 | if node.next != node.prev { | ||
| 127 | let mut node_next = ptr::read_volatile(node.next); | ||
| 128 | let mut node_prev = ptr::read_volatile(node.prev); | ||
| 129 | |||
| 130 | node_prev.next = node.next; | ||
| 131 | node_next.prev = node.prev; | ||
| 132 | |||
| 133 | ptr::write_volatile(node.next, node_next); | ||
| 134 | ptr::write_volatile(node.prev, node_prev); | ||
| 135 | } else { | ||
| 136 | let mut node_next = ptr::read_volatile(node.next); | ||
| 137 | |||
| 138 | node_next.next = node.next; | ||
| 139 | node_next.prev = node.prev; | ||
| 140 | |||
| 141 | ptr::write_volatile(node.next, node_next); | ||
| 142 | } | ||
| 143 | }); | ||
| 144 | } | ||
| 145 | |||
| 146 | /// Remove `list_head` and return a pointer to the `node`. | ||
| 147 | pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> { | ||
| 148 | interrupt::free(|_| { | ||
| 149 | let list_head = ptr::read_volatile(p_list_head); | ||
| 150 | |||
| 151 | if list_head.next == p_list_head { | ||
| 152 | None | ||
| 153 | } else { | ||
| 154 | // Allowed because a removed node is not seen by another core | ||
| 155 | let p_node = list_head.next; | ||
| 156 | Self::remove_node(p_node); | ||
| 157 | |||
| 158 | Some(p_node) | ||
| 159 | } | ||
| 160 | }) | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Remove `list_tail` and return a pointer to the `node`. | ||
| 164 | pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> { | ||
| 165 | interrupt::free(|_| { | ||
| 166 | let list_tail = ptr::read_volatile(p_list_tail); | ||
| 167 | |||
| 168 | if list_tail.prev == p_list_tail { | ||
| 169 | None | ||
| 170 | } else { | ||
| 171 | // Allowed because a removed node is not seen by another core | ||
| 172 | let p_node = list_tail.prev; | ||
| 173 | Self::remove_node(p_node); | ||
| 174 | |||
| 175 | Some(p_node) | ||
| 176 | } | ||
| 177 | }) | ||
| 178 | } | ||
| 179 | |||
| 180 | pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { | ||
| 181 | interrupt::free(|_| { | ||
| 182 | (*node).next = (*ref_node).next; | ||
| 183 | (*node).prev = ref_node; | ||
| 184 | (*ref_node).next = node; | ||
| 185 | (*(*node).next).prev = node; | ||
| 186 | }); | ||
| 187 | |||
| 188 | todo!("this function has not been converted to volatile semantics"); | ||
| 189 | } | ||
| 190 | |||
| 191 | pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { | ||
| 192 | interrupt::free(|_| { | ||
| 193 | (*node).next = ref_node; | ||
| 194 | (*node).prev = (*ref_node).prev; | ||
| 195 | (*ref_node).prev = node; | ||
| 196 | (*(*node).prev).next = node; | ||
| 197 | }); | ||
| 198 | |||
| 199 | todo!("this function has not been converted to volatile semantics"); | ||
| 200 | } | ||
| 201 | |||
| 202 | pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize { | ||
| 203 | interrupt::free(|_| { | ||
| 204 | let mut size = 0; | ||
| 205 | let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>(); | ||
| 206 | |||
| 207 | temp = (*list_head).next; | ||
| 208 | while temp != list_head { | ||
| 209 | size += 1; | ||
| 210 | temp = (*temp).next | ||
| 211 | } | ||
| 212 | |||
| 213 | size | ||
| 214 | }); | ||
| 215 | |||
| 216 | todo!("this function has not been converted to volatile semantics"); | ||
| 217 | } | ||
| 218 | |||
| 219 | pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { | ||
| 220 | interrupt::free(|_| { | ||
| 221 | let ref_node = ptr::read_volatile(p_ref_node); | ||
| 222 | |||
| 223 | // Allowed because a removed node is not seen by another core | ||
| 224 | ref_node.next | ||
| 225 | }) | ||
| 226 | } | ||
| 227 | |||
| 228 | pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { | ||
| 229 | interrupt::free(|_| { | ||
| 230 | let ref_node = ptr::read_volatile(p_ref_node); | ||
| 231 | |||
| 232 | // Allowed because a removed node is not seen by another core | ||
| 233 | ref_node.prev | ||
| 234 | }) | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | #[allow(dead_code)] | ||
| 239 | unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) { | ||
| 240 | info!("iterating list from node: {:x}", p_node); | ||
| 241 | let mut p_current_node = p_node; | ||
| 242 | let mut i = 0; | ||
| 243 | loop { | ||
| 244 | let current_node = ptr::read_volatile(p_current_node); | ||
| 245 | info!( | ||
| 246 | "node (prev, current, next): {:x}, {:x}, {:x}", | ||
| 247 | current_node.prev, p_current_node, current_node.next | ||
| 248 | ); | ||
| 249 | |||
| 250 | i += 1; | ||
| 251 | if i > 10 || current_node.next == p_node { | ||
| 252 | break; | ||
| 253 | } | ||
| 254 | |||
| 255 | p_current_node = current_node.next; | ||
| 256 | } | ||
| 257 | } | ||
diff --git a/embassy-stm32-wpan/src/channels.rs b/embassy-stm32-wpan/src/wb55/channels.rs index 9a2be1cfa..58f857136 100644 --- a/embassy-stm32-wpan/src/channels.rs +++ b/embassy-stm32-wpan/src/wb55/channels.rs | |||
| @@ -48,9 +48,20 @@ | |||
| 48 | //! |<----HW_IPCC_TRACES_CHANNEL----------------------| | 48 | //! |<----HW_IPCC_TRACES_CHANNEL----------------------| |
| 49 | //! | | | 49 | //! | | |
| 50 | //! | 50 | //! |
| 51 | //! | ||
| 52 | |||
| 53 | #[repr(u8)] | ||
| 54 | pub enum IpccChannel { | ||
| 55 | Channel1 = 1, | ||
| 56 | Channel2 = 2, | ||
| 57 | Channel3 = 3, | ||
| 58 | Channel4 = 4, | ||
| 59 | Channel5 = 5, | ||
| 60 | Channel6 = 6, | ||
| 61 | } | ||
| 51 | 62 | ||
| 52 | pub mod cpu1 { | 63 | pub mod cpu1 { |
| 53 | use embassy_stm32::ipcc::IpccChannel; | 64 | use super::IpccChannel; |
| 54 | 65 | ||
| 55 | pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; | 66 | pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; |
| 56 | pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; | 67 | pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; |
| @@ -70,7 +81,7 @@ pub mod cpu1 { | |||
| 70 | } | 81 | } |
| 71 | 82 | ||
| 72 | pub mod cpu2 { | 83 | pub mod cpu2 { |
| 73 | use embassy_stm32::ipcc::IpccChannel; | 84 | use super::IpccChannel; |
| 74 | 85 | ||
| 75 | pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; | 86 | pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; |
| 76 | pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; | 87 | pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; |
diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/wb55/cmd.rs index 928357384..34f02d6e7 100644 --- a/embassy-stm32-wpan/src/cmd.rs +++ b/embassy-stm32-wpan/src/wb55/cmd.rs | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | use core::ptr; | 1 | use core::ptr; |
| 2 | use core::sync::atomic::{Ordering, compiler_fence}; | ||
| 2 | 3 | ||
| 3 | use crate::consts::TlPacketType; | 4 | use crate::consts::TlPacketType; |
| 4 | use crate::PacketHeader; | 5 | use crate::wb55::PacketHeader; |
| 5 | 6 | ||
| 6 | #[derive(Copy, Clone)] | 7 | #[derive(Copy, Clone)] |
| 7 | #[repr(C, packed)] | 8 | #[repr(C, packed)] |
| @@ -45,11 +46,11 @@ pub struct CmdPacket { | |||
| 45 | 46 | ||
| 46 | impl CmdPacket { | 47 | impl CmdPacket { |
| 47 | pub unsafe fn write_into(cmd_buf: *mut CmdPacket, packet_type: TlPacketType, cmd_code: u16, payload: &[u8]) { | 48 | pub unsafe fn write_into(cmd_buf: *mut CmdPacket, packet_type: TlPacketType, cmd_code: u16, payload: &[u8]) { |
| 48 | let p_cmd_serial = &mut (*cmd_buf).cmdserial as *mut _ as *mut CmdSerialStub; | 49 | let p_cmd_serial = (cmd_buf as *mut u8).add(size_of::<PacketHeader>()); |
| 49 | let p_payload = &mut (*cmd_buf).cmdserial.cmd.payload as *mut _; | 50 | let p_payload = p_cmd_serial.add(size_of::<CmdSerialStub>()); |
| 50 | 51 | ||
| 51 | ptr::write_volatile( | 52 | ptr::write_unaligned( |
| 52 | p_cmd_serial, | 53 | p_cmd_serial as *mut _, |
| 53 | CmdSerialStub { | 54 | CmdSerialStub { |
| 54 | ty: packet_type as u8, | 55 | ty: packet_type as u8, |
| 55 | cmd_code, | 56 | cmd_code, |
| @@ -58,6 +59,8 @@ impl CmdPacket { | |||
| 58 | ); | 59 | ); |
| 59 | 60 | ||
| 60 | ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len()); | 61 | ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len()); |
| 62 | |||
| 63 | compiler_fence(Ordering::Release); | ||
| 61 | } | 64 | } |
| 62 | } | 65 | } |
| 63 | 66 | ||
| @@ -87,11 +90,11 @@ pub struct AclDataPacket { | |||
| 87 | 90 | ||
| 88 | impl AclDataPacket { | 91 | impl AclDataPacket { |
| 89 | pub unsafe fn write_into(cmd_buf: *mut AclDataPacket, packet_type: TlPacketType, handle: u16, payload: &[u8]) { | 92 | pub unsafe fn write_into(cmd_buf: *mut AclDataPacket, packet_type: TlPacketType, handle: u16, payload: &[u8]) { |
| 90 | let p_cmd_serial = &mut (*cmd_buf).acl_data_serial as *mut _ as *mut AclDataSerialStub; | 93 | let p_cmd_serial = (cmd_buf as *mut u8).add(size_of::<PacketHeader>()); |
| 91 | let p_payload = &mut (*cmd_buf).acl_data_serial.acl_data as *mut _; | 94 | let p_payload = p_cmd_serial.add(size_of::<AclDataSerialStub>()); |
| 92 | 95 | ||
| 93 | ptr::write_volatile( | 96 | ptr::write_unaligned( |
| 94 | p_cmd_serial, | 97 | p_cmd_serial as *mut _, |
| 95 | AclDataSerialStub { | 98 | AclDataSerialStub { |
| 96 | ty: packet_type as u8, | 99 | ty: packet_type as u8, |
| 97 | handle: handle, | 100 | handle: handle, |
| @@ -100,5 +103,7 @@ impl AclDataPacket { | |||
| 100 | ); | 103 | ); |
| 101 | 104 | ||
| 102 | ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len()); | 105 | ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len()); |
| 106 | |||
| 107 | compiler_fence(Ordering::Release); | ||
| 103 | } | 108 | } |
| 104 | } | 109 | } |
diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/wb55/consts.rs index e2ae6ca86..659e74e69 100644 --- a/embassy-stm32-wpan/src/consts.rs +++ b/embassy-stm32-wpan/src/wb55/consts.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | use crate::evt::CsEvt; | 1 | use crate::evt::CsEvt; |
| 2 | use crate::PacketHeader; | 2 | use crate::wb55::PacketHeader; |
| 3 | 3 | ||
| 4 | #[derive(Debug)] | 4 | #[derive(Debug)] |
| 5 | #[repr(C)] | 5 | #[repr(C)] |
diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/wb55/evt.rs index c6528413d..f32821269 100644 --- a/embassy-stm32-wpan/src/evt.rs +++ b/embassy-stm32-wpan/src/wb55/evt.rs | |||
| @@ -67,6 +67,7 @@ pub struct EvtSerial { | |||
| 67 | pub struct EvtStub { | 67 | pub struct EvtStub { |
| 68 | pub kind: u8, | 68 | pub kind: u8, |
| 69 | pub evt_code: u8, | 69 | pub evt_code: u8, |
| 70 | pub payload_len: u8, | ||
| 70 | } | 71 | } |
| 71 | 72 | ||
| 72 | /// This format shall be used for all events (asynchronous and command response) reported | 73 | /// This format shall be used for all events (asynchronous and command response) reported |
diff --git a/embassy-stm32-wpan/src/fmt.rs b/embassy-stm32-wpan/src/wb55/fmt.rs index 8ca61bc39..8ca61bc39 100644 --- a/embassy-stm32-wpan/src/fmt.rs +++ b/embassy-stm32-wpan/src/wb55/fmt.rs | |||
diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/wb55/lhci.rs index 89f204f99..59c8bfb5d 100644 --- a/embassy-stm32-wpan/src/lhci.rs +++ b/embassy-stm32-wpan/src/wb55/lhci.rs | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | use core::ptr; | 1 | use core::ptr; |
| 2 | 2 | ||
| 3 | use crate::cmd::CmdPacket; | 3 | use crate::cmd::CmdPacket; |
| 4 | use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE}; | 4 | use crate::consts::{TL_EVT_HEADER_SIZE, TlPacketType}; |
| 5 | use crate::evt::{CcEvt, EvtPacket, EvtSerial}; | 5 | use crate::evt::{CcEvt, EvtPacket, EvtSerial}; |
| 6 | use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable, TL_DEVICE_INFO_TABLE}; | 6 | use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, TL_DEVICE_INFO_TABLE, WirelessFwInfoTable}; |
| 7 | 7 | ||
| 8 | const TL_BLEEVT_CC_OPCODE: u8 = 0x0e; | 8 | const TL_BLEEVT_CC_OPCODE: u8 = 0x0e; |
| 9 | const LHCI_OPCODE_C1_DEVICE_INF: u16 = 0xfd62; | 9 | const LHCI_OPCODE_C1_DEVICE_INF: u16 = 0xfd62; |
diff --git a/embassy-stm32-wpan/src/mac/commands.rs b/embassy-stm32-wpan/src/wb55/mac/commands.rs index 82b9d2772..d96f0094a 100644 --- a/embassy-stm32-wpan/src/mac/commands.rs +++ b/embassy-stm32-wpan/src/wb55/mac/commands.rs | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | use core::{mem, slice}; | 3 | use core::{mem, slice}; |
| 4 | 4 | ||
| 5 | use smoltcp::wire::ieee802154::Frame; | ||
| 6 | |||
| 5 | use super::opcodes::OpcodeM4ToM0; | 7 | use super::opcodes::OpcodeM4ToM0; |
| 6 | use super::typedefs::{ | 8 | use super::typedefs::{ |
| 7 | AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus, | 9 | AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus, |
| @@ -379,6 +381,35 @@ impl DataRequest { | |||
| 379 | } | 381 | } |
| 380 | } | 382 | } |
| 381 | 383 | ||
| 384 | impl<'a, T: AsRef<[u8]>> TryFrom<Frame<&'a T>> for DataRequest { | ||
| 385 | type Error = (); | ||
| 386 | |||
| 387 | fn try_from(frame: Frame<&'a T>) -> Result<Self, Self::Error> { | ||
| 388 | // TODO: map the rest of these | ||
| 389 | |||
| 390 | let mut request = DataRequest { | ||
| 391 | src_addr_mode: frame.src_addressing_mode().try_into()?, | ||
| 392 | dst_addr_mode: frame.dst_addressing_mode().try_into()?, | ||
| 393 | dst_pan_id: frame.dst_pan_id().ok_or(())?.into(), | ||
| 394 | dst_address: frame.dst_addr().ok_or(())?.into(), | ||
| 395 | msdu_handle: frame.sequence_number().ok_or(())?, | ||
| 396 | key_source: frame.key_source().unwrap_or_default().try_into().unwrap_or_default(), | ||
| 397 | ack_tx: frame.ack_request() as u8, | ||
| 398 | gts_tx: false, | ||
| 399 | security_level: if frame.security_enabled() { | ||
| 400 | SecurityLevel::Secured | ||
| 401 | } else { | ||
| 402 | SecurityLevel::Unsecure | ||
| 403 | }, | ||
| 404 | ..Default::default() | ||
| 405 | }; | ||
| 406 | |||
| 407 | request.set_buffer(frame.payload().ok_or(())?); | ||
| 408 | |||
| 409 | Ok(request) | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 382 | impl Default for DataRequest { | 413 | impl Default for DataRequest { |
| 383 | fn default() -> Self { | 414 | fn default() -> Self { |
| 384 | Self { | 415 | Self { |
diff --git a/embassy-stm32-wpan/src/mac/consts.rs b/embassy-stm32-wpan/src/wb55/mac/consts.rs index 56903d980..56903d980 100644 --- a/embassy-stm32-wpan/src/mac/consts.rs +++ b/embassy-stm32-wpan/src/wb55/mac/consts.rs | |||
diff --git a/embassy-stm32-wpan/src/wb55/mac/control.rs b/embassy-stm32-wpan/src/wb55/mac/control.rs new file mode 100644 index 000000000..14c6fdd2b --- /dev/null +++ b/embassy-stm32-wpan/src/wb55/mac/control.rs | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | use core::cell::RefCell; | ||
| 2 | use core::future::Future; | ||
| 3 | use core::sync::atomic::{Ordering, compiler_fence}; | ||
| 4 | use core::task; | ||
| 5 | use core::task::Poll; | ||
| 6 | |||
| 7 | use embassy_net_driver::LinkState; | ||
| 8 | use embassy_sync::blocking_mutex; | ||
| 9 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 10 | use embassy_sync::mutex::Mutex; | ||
| 11 | use embassy_sync::signal::Signal; | ||
| 12 | use futures_util::FutureExt; | ||
| 13 | |||
| 14 | use crate::mac::commands::*; | ||
| 15 | use crate::mac::driver::NetworkState; | ||
| 16 | use crate::mac::event::MacEvent; | ||
| 17 | use crate::mac::runner::ZeroCopyPubSub; | ||
| 18 | use crate::mac::typedefs::*; | ||
| 19 | use crate::sub::mac::MacTx; | ||
| 20 | |||
| 21 | pub struct Control<'a> { | ||
| 22 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, | ||
| 23 | mac_tx: &'a Mutex<CriticalSectionRawMutex, MacTx<'a>>, | ||
| 24 | #[allow(unused)] | ||
| 25 | network_state: &'a blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl<'a> Control<'a> { | ||
| 29 | pub(crate) fn new( | ||
| 30 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, | ||
| 31 | mac_tx: &'a Mutex<CriticalSectionRawMutex, MacTx<'a>>, | ||
| 32 | network_state: &'a blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 33 | ) -> Self { | ||
| 34 | Self { | ||
| 35 | rx_event_channel, | ||
| 36 | mac_tx, | ||
| 37 | network_state, | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | pub async fn init_link(&mut self, pan_id: [u8; 2]) { | ||
| 42 | debug!("resetting"); | ||
| 43 | |||
| 44 | debug!( | ||
| 45 | "{:#x}", | ||
| 46 | self.send_command_and_get_response(&ResetRequest { | ||
| 47 | set_default_pib: true, | ||
| 48 | ..Default::default() | ||
| 49 | }) | ||
| 50 | .await | ||
| 51 | .unwrap() | ||
| 52 | .await | ||
| 53 | ); | ||
| 54 | |||
| 55 | let (short_address, mac_address) = critical_section::with(|cs| { | ||
| 56 | let mut network_state = self.network_state.borrow(cs).borrow_mut(); | ||
| 57 | |||
| 58 | network_state.pan_id = pan_id; | ||
| 59 | |||
| 60 | (network_state.short_addr, network_state.mac_addr) | ||
| 61 | }); | ||
| 62 | |||
| 63 | debug!("setting extended address"); | ||
| 64 | debug!( | ||
| 65 | "{:#x}", | ||
| 66 | self.send_command_and_get_response(&SetRequest { | ||
| 67 | pib_attribute_ptr: &u64::from_be_bytes(mac_address) as *const _ as *const u8, | ||
| 68 | pib_attribute: PibId::ExtendedAddress, | ||
| 69 | }) | ||
| 70 | .await | ||
| 71 | .unwrap() | ||
| 72 | .await | ||
| 73 | ); | ||
| 74 | |||
| 75 | debug!("setting short address"); | ||
| 76 | debug!( | ||
| 77 | "{:#x}", | ||
| 78 | self.send_command_and_get_response(&SetRequest { | ||
| 79 | pib_attribute_ptr: &u16::from_be_bytes(short_address) as *const _ as *const u8, | ||
| 80 | pib_attribute: PibId::ShortAddress, | ||
| 81 | }) | ||
| 82 | .await | ||
| 83 | .unwrap() | ||
| 84 | .await | ||
| 85 | ); | ||
| 86 | |||
| 87 | debug!("setting association permit"); | ||
| 88 | let association_permit: bool = true; | ||
| 89 | debug!( | ||
| 90 | "{:#x}", | ||
| 91 | self.send_command_and_get_response(&SetRequest { | ||
| 92 | pib_attribute_ptr: &association_permit as *const _ as *const u8, | ||
| 93 | pib_attribute: PibId::AssociationPermit, | ||
| 94 | }) | ||
| 95 | .await | ||
| 96 | .unwrap() | ||
| 97 | .await | ||
| 98 | ); | ||
| 99 | |||
| 100 | debug!("setting TX power"); | ||
| 101 | let transmit_power: i8 = 2; | ||
| 102 | debug!( | ||
| 103 | "{:#x}", | ||
| 104 | self.send_command_and_get_response(&SetRequest { | ||
| 105 | pib_attribute_ptr: &transmit_power as *const _ as *const u8, | ||
| 106 | pib_attribute: PibId::TransmitPower, | ||
| 107 | }) | ||
| 108 | .await | ||
| 109 | .unwrap() | ||
| 110 | .await | ||
| 111 | ); | ||
| 112 | |||
| 113 | debug!("starting FFD device"); | ||
| 114 | debug!( | ||
| 115 | "{:#x}", | ||
| 116 | self.send_command_and_get_response(&StartRequest { | ||
| 117 | pan_id: PanId(pan_id), | ||
| 118 | channel_number: MacChannel::Channel16, | ||
| 119 | beacon_order: 0x0F, | ||
| 120 | superframe_order: 0x0F, | ||
| 121 | pan_coordinator: true, | ||
| 122 | battery_life_extension: false, | ||
| 123 | ..Default::default() | ||
| 124 | }) | ||
| 125 | .await | ||
| 126 | .unwrap() | ||
| 127 | .await | ||
| 128 | ); | ||
| 129 | |||
| 130 | debug!("setting RX on when idle"); | ||
| 131 | let rx_on_while_idle: bool = true; | ||
| 132 | debug!( | ||
| 133 | "{:#x}", | ||
| 134 | self.send_command_and_get_response(&SetRequest { | ||
| 135 | pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8, | ||
| 136 | pib_attribute: PibId::RxOnWhenIdle, | ||
| 137 | }) | ||
| 138 | .await | ||
| 139 | .unwrap() | ||
| 140 | .await | ||
| 141 | ); | ||
| 142 | |||
| 143 | critical_section::with(|cs| { | ||
| 144 | let mut network_state = self.network_state.borrow(cs).borrow_mut(); | ||
| 145 | |||
| 146 | network_state.link_state = LinkState::Up; | ||
| 147 | network_state.link_waker.wake(); | ||
| 148 | }); | ||
| 149 | } | ||
| 150 | |||
| 151 | pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError> | ||
| 152 | where | ||
| 153 | T: MacCommand, | ||
| 154 | { | ||
| 155 | self.mac_tx.lock().await.send_command(cmd).await | ||
| 156 | } | ||
| 157 | |||
| 158 | pub async fn send_command_and_get_response<T>(&self, cmd: &T) -> Result<EventToken<'a>, MacError> | ||
| 159 | where | ||
| 160 | T: MacCommand, | ||
| 161 | { | ||
| 162 | let token = EventToken::new(self.rx_event_channel); | ||
| 163 | |||
| 164 | compiler_fence(Ordering::Release); | ||
| 165 | |||
| 166 | self.mac_tx.lock().await.send_command(cmd).await?; | ||
| 167 | |||
| 168 | Ok(token) | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | pub struct EventToken<'a> { | ||
| 173 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, | ||
| 174 | } | ||
| 175 | |||
| 176 | impl<'a> EventToken<'a> { | ||
| 177 | pub(crate) fn new(rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>) -> Self { | ||
| 178 | // Enable event receiving | ||
| 179 | rx_event_channel.lock(|s| { | ||
| 180 | *s.borrow_mut() = Some(Signal::new()); | ||
| 181 | }); | ||
| 182 | |||
| 183 | Self { rx_event_channel } | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | impl<'a> Future for EventToken<'a> { | ||
| 188 | type Output = MacEvent<'a>; | ||
| 189 | |||
| 190 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||
| 191 | self.rx_event_channel | ||
| 192 | .lock(|s| s.borrow_mut().as_mut().unwrap().wait().poll_unpin(cx)) | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | impl<'a> Drop for EventToken<'a> { | ||
| 197 | fn drop(&mut self) { | ||
| 198 | // Disable event receiving | ||
| 199 | // This will also drop the contained event, if it exists, and will free up receiving the next event | ||
| 200 | self.rx_event_channel.lock(|s| { | ||
| 201 | *s.borrow_mut() = None; | ||
| 202 | }); | ||
| 203 | } | ||
| 204 | } | ||
diff --git a/embassy-stm32-wpan/src/wb55/mac/driver.rs b/embassy-stm32-wpan/src/wb55/mac/driver.rs new file mode 100644 index 000000000..41171ce3d --- /dev/null +++ b/embassy-stm32-wpan/src/wb55/mac/driver.rs | |||
| @@ -0,0 +1,213 @@ | |||
| 1 | #![deny(unused_must_use)] | ||
| 2 | |||
| 3 | use core::cell::RefCell; | ||
| 4 | use core::task::Context; | ||
| 5 | |||
| 6 | use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; | ||
| 7 | use embassy_sync::blocking_mutex; | ||
| 8 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 9 | use embassy_sync::channel::Channel; | ||
| 10 | use embassy_sync::mutex::Mutex; | ||
| 11 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 12 | |||
| 13 | use crate::mac::event::MacEvent; | ||
| 14 | use crate::mac::indications::{write_frame_from_beacon_indication, write_frame_from_data_indication}; | ||
| 15 | use crate::mac::runner::{BUF_SIZE, ZeroCopyPubSub}; | ||
| 16 | use crate::mac::{Control, MTU, Runner}; | ||
| 17 | use crate::sub::mac::{Mac, MacRx, MacTx}; | ||
| 18 | |||
| 19 | pub struct NetworkState { | ||
| 20 | pub mac_addr: [u8; 8], | ||
| 21 | pub short_addr: [u8; 2], | ||
| 22 | pub pan_id: [u8; 2], | ||
| 23 | pub link_state: LinkState, | ||
| 24 | pub link_waker: AtomicWaker, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl NetworkState { | ||
| 28 | pub const fn new() -> Self { | ||
| 29 | Self { | ||
| 30 | mac_addr: [0u8; 8], | ||
| 31 | short_addr: [0u8; 2], | ||
| 32 | pan_id: [0u8; 2], | ||
| 33 | link_state: LinkState::Down, | ||
| 34 | link_waker: AtomicWaker::new(), | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | pub struct DriverState<'d> { | ||
| 40 | pub mac_tx: Mutex<CriticalSectionRawMutex, MacTx<'d>>, | ||
| 41 | pub mac_rx: MacRx<'d>, | ||
| 42 | pub rx_event_channel: ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'d>>, | ||
| 43 | pub rx_data_channel: Channel<CriticalSectionRawMutex, MacEvent<'d>, 1>, | ||
| 44 | pub tx_data_channel: Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), BUF_SIZE>, | ||
| 45 | pub tx_buf_channel: Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], BUF_SIZE>, | ||
| 46 | pub tx_buf_queue: [[u8; MTU]; BUF_SIZE], | ||
| 47 | pub network_state: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 48 | } | ||
| 49 | |||
| 50 | impl<'d> DriverState<'d> { | ||
| 51 | pub const fn new(mac: Mac<'d>) -> Self { | ||
| 52 | let (mac_rx, mac_tx) = mac.split(); | ||
| 53 | let mac_tx = Mutex::new(mac_tx); | ||
| 54 | |||
| 55 | Self { | ||
| 56 | mac_tx, | ||
| 57 | mac_rx, | ||
| 58 | rx_event_channel: ZeroCopyPubSub::new(RefCell::new(None)), | ||
| 59 | rx_data_channel: Channel::new(), | ||
| 60 | tx_data_channel: Channel::new(), | ||
| 61 | tx_buf_channel: Channel::new(), | ||
| 62 | tx_buf_queue: [[0u8; MTU]; BUF_SIZE], | ||
| 63 | network_state: blocking_mutex::Mutex::new(RefCell::new(NetworkState::new())), | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | pub struct Driver<'d> { | ||
| 69 | tx_data_channel: &'d Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), BUF_SIZE>, | ||
| 70 | tx_buf_channel: &'d Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], BUF_SIZE>, | ||
| 71 | rx_data_channel: &'d Channel<CriticalSectionRawMutex, MacEvent<'d>, 1>, | ||
| 72 | network_state: &'d blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 73 | } | ||
| 74 | |||
| 75 | impl<'d> Driver<'d> { | ||
| 76 | pub fn new( | ||
| 77 | driver_state: &'d mut DriverState<'d>, | ||
| 78 | short_address: [u8; 2], | ||
| 79 | mac_address: [u8; 8], | ||
| 80 | ) -> (Self, Runner<'d>, Control<'d>) { | ||
| 81 | ( | ||
| 82 | Self { | ||
| 83 | tx_data_channel: &driver_state.tx_data_channel, | ||
| 84 | tx_buf_channel: &driver_state.tx_buf_channel, | ||
| 85 | rx_data_channel: &driver_state.rx_data_channel, | ||
| 86 | network_state: &driver_state.network_state, | ||
| 87 | }, | ||
| 88 | Runner::new( | ||
| 89 | &driver_state.rx_event_channel, | ||
| 90 | &driver_state.rx_data_channel, | ||
| 91 | &mut driver_state.mac_rx, | ||
| 92 | &driver_state.tx_data_channel, | ||
| 93 | &driver_state.tx_buf_channel, | ||
| 94 | &driver_state.mac_tx, | ||
| 95 | &mut driver_state.tx_buf_queue, | ||
| 96 | &driver_state.network_state, | ||
| 97 | short_address, | ||
| 98 | mac_address, | ||
| 99 | ), | ||
| 100 | Control::new( | ||
| 101 | &driver_state.rx_event_channel, | ||
| 102 | &driver_state.mac_tx, | ||
| 103 | &driver_state.network_state, | ||
| 104 | ), | ||
| 105 | ) | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | impl<'d> embassy_net_driver::Driver for Driver<'d> { | ||
| 110 | // type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; | ||
| 111 | // type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; | ||
| 112 | type RxToken<'a> | ||
| 113 | = RxToken<'d> | ||
| 114 | where | ||
| 115 | Self: 'a; | ||
| 116 | type TxToken<'a> | ||
| 117 | = TxToken<'d> | ||
| 118 | where | ||
| 119 | Self: 'a; | ||
| 120 | |||
| 121 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { | ||
| 122 | if self.rx_data_channel.poll_ready_to_receive(cx).is_ready() | ||
| 123 | && self.tx_buf_channel.poll_ready_to_receive(cx).is_ready() | ||
| 124 | { | ||
| 125 | Some(( | ||
| 126 | RxToken { | ||
| 127 | rx: self.rx_data_channel, | ||
| 128 | }, | ||
| 129 | TxToken { | ||
| 130 | tx: self.tx_data_channel, | ||
| 131 | tx_buf: self.tx_buf_channel, | ||
| 132 | }, | ||
| 133 | )) | ||
| 134 | } else { | ||
| 135 | None | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> { | ||
| 140 | if self.tx_buf_channel.poll_ready_to_receive(cx).is_ready() { | ||
| 141 | Some(TxToken { | ||
| 142 | tx: self.tx_data_channel, | ||
| 143 | tx_buf: self.tx_buf_channel, | ||
| 144 | }) | ||
| 145 | } else { | ||
| 146 | None | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | fn capabilities(&self) -> Capabilities { | ||
| 151 | let mut caps = Capabilities::default(); | ||
| 152 | caps.max_transmission_unit = MTU; | ||
| 153 | // caps.max_burst_size = Some(self.tx.len()); | ||
| 154 | caps | ||
| 155 | } | ||
| 156 | |||
| 157 | fn link_state(&mut self, cx: &mut Context) -> LinkState { | ||
| 158 | critical_section::with(|cs| { | ||
| 159 | let network_state = self.network_state.borrow(cs).borrow_mut(); | ||
| 160 | |||
| 161 | // Unconditionally register the waker to avoid a race | ||
| 162 | network_state.link_waker.register(cx.waker()); | ||
| 163 | network_state.link_state | ||
| 164 | }) | ||
| 165 | } | ||
| 166 | |||
| 167 | fn hardware_address(&self) -> HardwareAddress { | ||
| 168 | HardwareAddress::Ieee802154(critical_section::with(|cs| { | ||
| 169 | self.network_state.borrow(cs).borrow().mac_addr | ||
| 170 | })) | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | pub struct RxToken<'d> { | ||
| 175 | rx: &'d Channel<CriticalSectionRawMutex, MacEvent<'d>, 1>, | ||
| 176 | } | ||
| 177 | |||
| 178 | impl<'d> embassy_net_driver::RxToken for RxToken<'d> { | ||
| 179 | fn consume<R, F>(self, f: F) -> R | ||
| 180 | where | ||
| 181 | F: FnOnce(&mut [u8]) -> R, | ||
| 182 | { | ||
| 183 | let mut buffer = [0u8; MTU]; | ||
| 184 | match self.rx.try_receive().unwrap() { | ||
| 185 | MacEvent::McpsDataInd(data_event) => write_frame_from_data_indication(data_event, &mut buffer), | ||
| 186 | MacEvent::MlmeBeaconNotifyInd(data_event) => write_frame_from_beacon_indication(data_event, &mut buffer), | ||
| 187 | _ => {} | ||
| 188 | }; | ||
| 189 | |||
| 190 | f(&mut buffer[..]) | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | pub struct TxToken<'d> { | ||
| 195 | tx: &'d Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), BUF_SIZE>, | ||
| 196 | tx_buf: &'d Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], BUF_SIZE>, | ||
| 197 | } | ||
| 198 | |||
| 199 | impl<'d> embassy_net_driver::TxToken for TxToken<'d> { | ||
| 200 | fn consume<R, F>(self, len: usize, f: F) -> R | ||
| 201 | where | ||
| 202 | F: FnOnce(&mut [u8]) -> R, | ||
| 203 | { | ||
| 204 | // Only valid tx buffers should be put into the queue | ||
| 205 | let buf = self.tx_buf.try_receive().unwrap(); | ||
| 206 | let r = f(&mut buf[..len]); | ||
| 207 | |||
| 208 | // The tx channel should always be of equal capacity to the tx_buf channel | ||
| 209 | self.tx.try_send((buf, len)).unwrap(); | ||
| 210 | |||
| 211 | r | ||
| 212 | } | ||
| 213 | } | ||
diff --git a/embassy-stm32-wpan/src/mac/event.rs b/embassy-stm32-wpan/src/wb55/mac/event.rs index 9ca4f5a2a..39856e185 100644 --- a/embassy-stm32-wpan/src/mac/event.rs +++ b/embassy-stm32-wpan/src/wb55/mac/event.rs | |||
| @@ -10,7 +10,7 @@ use super::responses::{ | |||
| 10 | }; | 10 | }; |
| 11 | use crate::evt::{EvtBox, MemoryManager}; | 11 | use crate::evt::{EvtBox, MemoryManager}; |
| 12 | use crate::mac::opcodes::OpcodeM0ToM4; | 12 | use crate::mac::opcodes::OpcodeM0ToM4; |
| 13 | use crate::sub::mac::{self, Mac}; | 13 | use crate::sub::mac::{self, MacRx}; |
| 14 | 14 | ||
| 15 | pub(crate) trait ParseableMacEvent: Sized { | 15 | pub(crate) trait ParseableMacEvent: Sized { |
| 16 | fn from_buffer<'a>(buf: &'a [u8]) -> Result<&'a Self, ()> { | 16 | fn from_buffer<'a>(buf: &'a [u8]) -> Result<&'a Self, ()> { |
| @@ -53,7 +53,7 @@ pub enum MacEvent<'a> { | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | impl<'a> MacEvent<'a> { | 55 | impl<'a> MacEvent<'a> { |
| 56 | pub(crate) fn new(event_box: EvtBox<Mac>) -> Result<Self, ()> { | 56 | pub(crate) fn new(event_box: EvtBox<MacRx>) -> Result<Self, ()> { |
| 57 | let payload = event_box.payload(); | 57 | let payload = event_box.payload(); |
| 58 | let opcode = u16::from_le_bytes(payload[0..2].try_into().unwrap()); | 58 | let opcode = u16::from_le_bytes(payload[0..2].try_into().unwrap()); |
| 59 | 59 | ||
| @@ -148,6 +148,6 @@ unsafe impl<'a> Send for MacEvent<'a> {} | |||
| 148 | 148 | ||
| 149 | impl<'a> Drop for MacEvent<'a> { | 149 | impl<'a> Drop for MacEvent<'a> { |
| 150 | fn drop(&mut self) { | 150 | fn drop(&mut self) { |
| 151 | unsafe { mac::Mac::drop_event_packet(ptr::null_mut()) }; | 151 | unsafe { mac::MacRx::drop_event_packet(ptr::null_mut()) }; |
| 152 | } | 152 | } |
| 153 | } | 153 | } |
diff --git a/embassy-stm32-wpan/src/mac/indications.rs b/embassy-stm32-wpan/src/wb55/mac/indications.rs index c0b86d745..5673514c9 100644 --- a/embassy-stm32-wpan/src/mac/indications.rs +++ b/embassy-stm32-wpan/src/wb55/mac/indications.rs | |||
| @@ -1,11 +1,15 @@ | |||
| 1 | use core::slice; | 1 | use core::slice; |
| 2 | 2 | ||
| 3 | use smoltcp::wire::Ieee802154FrameType; | ||
| 4 | use smoltcp::wire::ieee802154::Frame; | ||
| 5 | |||
| 3 | use super::consts::MAX_PENDING_ADDRESS; | 6 | use super::consts::MAX_PENDING_ADDRESS; |
| 4 | use super::event::ParseableMacEvent; | 7 | use super::event::ParseableMacEvent; |
| 5 | use super::typedefs::{ | 8 | use super::typedefs::{ |
| 6 | AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor, | 9 | AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor, |
| 7 | PanId, SecurityLevel, | 10 | PanId, SecurityLevel, |
| 8 | }; | 11 | }; |
| 12 | use crate::mac::typedefs::MacAddressAndMode; | ||
| 9 | 13 | ||
| 10 | /// MLME ASSOCIATE Indication which will be used by the MAC | 14 | /// MLME ASSOCIATE Indication which will be used by the MAC |
| 11 | /// to indicate the reception of an association request command | 15 | /// to indicate the reception of an association request command |
| @@ -74,6 +78,22 @@ pub struct BeaconNotifyIndication { | |||
| 74 | 78 | ||
| 75 | impl ParseableMacEvent for BeaconNotifyIndication {} | 79 | impl ParseableMacEvent for BeaconNotifyIndication {} |
| 76 | 80 | ||
| 81 | impl BeaconNotifyIndication { | ||
| 82 | pub fn payload<'a>(&'a self) -> &'a mut [u8] { | ||
| 83 | unsafe { slice::from_raw_parts_mut(self.sdu_ptr as *mut _, self.sdu_length as usize) } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | pub fn write_frame_from_beacon_indication<'a, T: AsRef<[u8]> + AsMut<[u8]>>( | ||
| 88 | data: &'a BeaconNotifyIndication, | ||
| 89 | buffer: &'a mut T, | ||
| 90 | ) { | ||
| 91 | let mut frame = Frame::new_unchecked(buffer); | ||
| 92 | |||
| 93 | frame.set_frame_type(Ieee802154FrameType::Beacon); | ||
| 94 | frame.set_sequence_number(data.bsn); | ||
| 95 | } | ||
| 96 | |||
| 77 | /// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status | 97 | /// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status |
| 78 | #[repr(C)] | 98 | #[repr(C)] |
| 79 | #[derive(Debug)] | 99 | #[derive(Debug)] |
| @@ -250,6 +270,21 @@ impl DataIndication { | |||
| 250 | } | 270 | } |
| 251 | } | 271 | } |
| 252 | 272 | ||
| 273 | pub fn write_frame_from_data_indication<'a, T: AsRef<[u8]> + AsMut<[u8]>>(data: &'a DataIndication, buffer: &'a mut T) { | ||
| 274 | let mut frame = Frame::new_unchecked(buffer); | ||
| 275 | |||
| 276 | frame.set_frame_type(Ieee802154FrameType::Data); | ||
| 277 | frame.set_src_addr(MacAddressAndMode(data.src_address, data.src_addr_mode).into()); | ||
| 278 | frame.set_dst_addr(MacAddressAndMode(data.dst_address, data.dst_addr_mode).into()); | ||
| 279 | frame.set_dst_pan_id(data.dst_pan_id.into()); | ||
| 280 | frame.set_src_pan_id(data.src_pan_id.into()); | ||
| 281 | frame.set_sequence_number(data.dsn); | ||
| 282 | frame.set_security_enabled(data.security_level == SecurityLevel::Secured); | ||
| 283 | |||
| 284 | // No way around the copy with the current API | ||
| 285 | frame.payload_mut().unwrap().copy_from_slice(data.payload()); | ||
| 286 | } | ||
| 287 | |||
| 253 | /// MLME POLL Indication which will be used for indicating the Data Request | 288 | /// MLME POLL Indication which will be used for indicating the Data Request |
| 254 | /// reception to upper layer as defined in Zigbee r22 - D.8.2 | 289 | /// reception to upper layer as defined in Zigbee r22 - D.8.2 |
| 255 | #[repr(C)] | 290 | #[repr(C)] |
diff --git a/embassy-stm32-wpan/src/mac/macros.rs b/embassy-stm32-wpan/src/wb55/mac/macros.rs index 1a988a779..1a988a779 100644 --- a/embassy-stm32-wpan/src/mac/macros.rs +++ b/embassy-stm32-wpan/src/wb55/mac/macros.rs | |||
diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/wb55/mac/mod.rs index c847a5cca..ac50a6b29 100644 --- a/embassy-stm32-wpan/src/mac/mod.rs +++ b/embassy-stm32-wpan/src/wb55/mac/mod.rs | |||
| @@ -11,11 +11,7 @@ pub mod runner; | |||
| 11 | pub mod typedefs; | 11 | pub mod typedefs; |
| 12 | 12 | ||
| 13 | pub use crate::mac::control::Control; | 13 | pub use crate::mac::control::Control; |
| 14 | use crate::mac::driver::Driver; | 14 | pub use crate::mac::driver::{Driver, DriverState}; |
| 15 | pub use crate::mac::runner::Runner; | 15 | pub use crate::mac::runner::Runner; |
| 16 | 16 | ||
| 17 | const MTU: usize = 127; | 17 | const MTU: usize = 127; |
| 18 | |||
| 19 | pub async fn new<'a>(runner: &'a Runner<'a>) -> (Control<'a>, Driver<'a>) { | ||
| 20 | (Control::new(runner), Driver::new(runner)) | ||
| 21 | } | ||
diff --git a/embassy-stm32-wpan/src/mac/opcodes.rs b/embassy-stm32-wpan/src/wb55/mac/opcodes.rs index fd7011873..fd7011873 100644 --- a/embassy-stm32-wpan/src/mac/opcodes.rs +++ b/embassy-stm32-wpan/src/wb55/mac/opcodes.rs | |||
diff --git a/embassy-stm32-wpan/src/mac/responses.rs b/embassy-stm32-wpan/src/wb55/mac/responses.rs index 544fdaae8..544fdaae8 100644 --- a/embassy-stm32-wpan/src/mac/responses.rs +++ b/embassy-stm32-wpan/src/wb55/mac/responses.rs | |||
diff --git a/embassy-stm32-wpan/src/wb55/mac/runner.rs b/embassy-stm32-wpan/src/wb55/mac/runner.rs new file mode 100644 index 000000000..3b7d895df --- /dev/null +++ b/embassy-stm32-wpan/src/wb55/mac/runner.rs | |||
| @@ -0,0 +1,151 @@ | |||
| 1 | use core::cell::RefCell; | ||
| 2 | |||
| 3 | use embassy_futures::join; | ||
| 4 | use embassy_sync::blocking_mutex; | ||
| 5 | use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; | ||
| 6 | use embassy_sync::channel::Channel; | ||
| 7 | use embassy_sync::mutex::Mutex; | ||
| 8 | use embassy_sync::signal::Signal; | ||
| 9 | use smoltcp::wire::Ieee802154FrameType; | ||
| 10 | use smoltcp::wire::ieee802154::Frame; | ||
| 11 | |||
| 12 | use crate::mac::MTU; | ||
| 13 | use crate::mac::commands::*; | ||
| 14 | use crate::mac::driver::NetworkState; | ||
| 15 | use crate::mac::event::MacEvent; | ||
| 16 | use crate::sub::mac::{MacRx, MacTx}; | ||
| 17 | |||
| 18 | pub type ZeroCopyPubSub<M, T> = blocking_mutex::Mutex<M, RefCell<Option<Signal<NoopRawMutex, T>>>>; | ||
| 19 | |||
| 20 | pub const BUF_SIZE: usize = 3; | ||
| 21 | |||
| 22 | pub struct Runner<'a> { | ||
| 23 | // rx event backpressure is already provided through the MacEvent drop mechanism | ||
| 24 | // therefore, we don't need to worry about overwriting events | ||
| 25 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, | ||
| 26 | rx_data_channel: &'a Channel<CriticalSectionRawMutex, MacEvent<'a>, 1>, | ||
| 27 | mac_rx: Mutex<NoopRawMutex, &'a mut MacRx<'a>>, | ||
| 28 | |||
| 29 | tx_data_channel: &'a Channel<CriticalSectionRawMutex, (&'a mut [u8; MTU], usize), BUF_SIZE>, | ||
| 30 | tx_buf_channel: &'a Channel<CriticalSectionRawMutex, &'a mut [u8; MTU], BUF_SIZE>, | ||
| 31 | mac_tx: &'a Mutex<CriticalSectionRawMutex, MacTx<'a>>, | ||
| 32 | |||
| 33 | #[allow(unused)] | ||
| 34 | network_state: &'a blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 35 | } | ||
| 36 | |||
| 37 | impl<'a> Runner<'a> { | ||
| 38 | pub(crate) fn new( | ||
| 39 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, | ||
| 40 | rx_data_channel: &'a Channel<CriticalSectionRawMutex, MacEvent<'a>, 1>, | ||
| 41 | mac_rx: &'a mut MacRx<'a>, | ||
| 42 | tx_data_channel: &'a Channel<CriticalSectionRawMutex, (&'a mut [u8; MTU], usize), BUF_SIZE>, | ||
| 43 | tx_buf_channel: &'a Channel<CriticalSectionRawMutex, &'a mut [u8; MTU], BUF_SIZE>, | ||
| 44 | mac_tx: &'a Mutex<CriticalSectionRawMutex, MacTx<'a>>, | ||
| 45 | tx_buf_queue: &'a mut [[u8; MTU]; BUF_SIZE], | ||
| 46 | network_state: &'a blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 47 | short_address: [u8; 2], | ||
| 48 | mac_address: [u8; 8], | ||
| 49 | ) -> Self { | ||
| 50 | for buf in tx_buf_queue { | ||
| 51 | tx_buf_channel.try_send(buf).unwrap(); | ||
| 52 | } | ||
| 53 | |||
| 54 | critical_section::with(|cs| { | ||
| 55 | let mut network_state = network_state.borrow(cs).borrow_mut(); | ||
| 56 | |||
| 57 | network_state.mac_addr = mac_address; | ||
| 58 | network_state.short_addr = short_address; | ||
| 59 | }); | ||
| 60 | |||
| 61 | Self { | ||
| 62 | rx_event_channel, | ||
| 63 | rx_data_channel, | ||
| 64 | mac_rx: Mutex::new(mac_rx), | ||
| 65 | tx_data_channel, | ||
| 66 | tx_buf_channel, | ||
| 67 | mac_tx, | ||
| 68 | network_state, | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | async fn send_request<T: MacCommand, U: TryInto<T>>(&self, frame: U) -> Result<(), ()> | ||
| 73 | where | ||
| 74 | (): From<<U as TryInto<T>>::Error>, | ||
| 75 | { | ||
| 76 | let request: T = frame.try_into()?; | ||
| 77 | self.mac_tx.lock().await.send_command(&request).await.map_err(|_| ())?; | ||
| 78 | |||
| 79 | Ok(()) | ||
| 80 | } | ||
| 81 | |||
| 82 | pub async fn run(&'a self) -> ! { | ||
| 83 | join::join( | ||
| 84 | async { | ||
| 85 | loop { | ||
| 86 | if let Ok(mac_event) = self.mac_rx.try_lock().unwrap().read().await { | ||
| 87 | match mac_event { | ||
| 88 | MacEvent::MlmeAssociateCnf(_) | ||
| 89 | | MacEvent::MlmeDisassociateCnf(_) | ||
| 90 | | MacEvent::MlmeGetCnf(_) | ||
| 91 | | MacEvent::MlmeGtsCnf(_) | ||
| 92 | | MacEvent::MlmeResetCnf(_) | ||
| 93 | | MacEvent::MlmeRxEnableCnf(_) | ||
| 94 | | MacEvent::MlmeScanCnf(_) | ||
| 95 | | MacEvent::MlmeSetCnf(_) | ||
| 96 | | MacEvent::MlmeStartCnf(_) | ||
| 97 | | MacEvent::MlmePollCnf(_) | ||
| 98 | | MacEvent::MlmeDpsCnf(_) | ||
| 99 | | MacEvent::MlmeSoundingCnf(_) | ||
| 100 | | MacEvent::MlmeCalibrateCnf(_) | ||
| 101 | | MacEvent::McpsDataCnf(_) | ||
| 102 | | MacEvent::McpsPurgeCnf(_) => { | ||
| 103 | self.rx_event_channel.lock(|s| { | ||
| 104 | s.borrow().as_ref().map(|signal| signal.signal(mac_event)); | ||
| 105 | }); | ||
| 106 | } | ||
| 107 | MacEvent::McpsDataInd(_) => { | ||
| 108 | // Pattern should match driver | ||
| 109 | self.rx_data_channel.send(mac_event).await; | ||
| 110 | } | ||
| 111 | _ => { | ||
| 112 | debug!("unhandled mac event: {:#x}", mac_event); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | }, | ||
| 118 | async { | ||
| 119 | loop { | ||
| 120 | let (buf, _) = self.tx_data_channel.receive().await; | ||
| 121 | |||
| 122 | // Smoltcp has created this frame, so there's no need to reparse it. | ||
| 123 | let frame = Frame::new_unchecked(&buf); | ||
| 124 | |||
| 125 | let result: Result<(), ()> = match frame.frame_type() { | ||
| 126 | Ieee802154FrameType::Beacon => Err(()), | ||
| 127 | Ieee802154FrameType::Data => self.send_request::<DataRequest, _>(frame).await, | ||
| 128 | Ieee802154FrameType::Acknowledgement => Err(()), | ||
| 129 | Ieee802154FrameType::MacCommand => Err(()), | ||
| 130 | Ieee802154FrameType::Multipurpose => Err(()), | ||
| 131 | Ieee802154FrameType::FragmentOrFrak => Err(()), | ||
| 132 | Ieee802154FrameType::Extended => Err(()), | ||
| 133 | _ => Err(()), | ||
| 134 | }; | ||
| 135 | |||
| 136 | if result.is_err() { | ||
| 137 | debug!("failed to parse mac frame"); | ||
| 138 | } else { | ||
| 139 | trace!("data frame sent!"); | ||
| 140 | } | ||
| 141 | |||
| 142 | // The tx channel should always be of equal capacity to the tx_buf channel | ||
| 143 | self.tx_buf_channel.try_send(buf).unwrap(); | ||
| 144 | } | ||
| 145 | }, | ||
| 146 | ) | ||
| 147 | .await; | ||
| 148 | |||
| 149 | loop {} | ||
| 150 | } | ||
| 151 | } | ||
diff --git a/embassy-stm32-wpan/src/mac/typedefs.rs b/embassy-stm32-wpan/src/wb55/mac/typedefs.rs index 0552b8ea1..175d4a37d 100644 --- a/embassy-stm32-wpan/src/mac/typedefs.rs +++ b/embassy-stm32-wpan/src/wb55/mac/typedefs.rs | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | use core::fmt::Debug; | 1 | use core::fmt::Debug; |
| 2 | 2 | ||
| 3 | use smoltcp::wire::ieee802154::{Address, AddressingMode, Pan}; | ||
| 4 | |||
| 3 | use crate::numeric_enum; | 5 | use crate::numeric_enum; |
| 4 | 6 | ||
| 5 | #[derive(Debug)] | 7 | #[derive(Debug)] |
| @@ -109,12 +111,51 @@ numeric_enum! { | |||
| 109 | } | 111 | } |
| 110 | } | 112 | } |
| 111 | 113 | ||
| 114 | impl TryFrom<AddressingMode> for AddressMode { | ||
| 115 | type Error = (); | ||
| 116 | |||
| 117 | fn try_from(value: AddressingMode) -> Result<Self, Self::Error> { | ||
| 118 | match value { | ||
| 119 | AddressingMode::Absent => Ok(Self::NoAddress), | ||
| 120 | AddressingMode::Extended => Ok(Self::Extended), | ||
| 121 | AddressingMode::Short => Ok(Self::Short), | ||
| 122 | AddressingMode::Unknown(_) => Err(()), | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 112 | #[derive(Clone, Copy)] | 127 | #[derive(Clone, Copy)] |
| 113 | pub union MacAddress { | 128 | pub union MacAddress { |
| 114 | pub short: [u8; 2], | 129 | pub short: [u8; 2], |
| 115 | pub extended: [u8; 8], | 130 | pub extended: [u8; 8], |
| 116 | } | 131 | } |
| 117 | 132 | ||
| 133 | impl From<Address> for MacAddress { | ||
| 134 | fn from(value: Address) -> Self { | ||
| 135 | match value { | ||
| 136 | Address::Short(addr) => Self { short: addr }, | ||
| 137 | Address::Extended(addr) => Self { extended: addr }, | ||
| 138 | Address::Absent => Self { short: [0u8; 2] }, | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | pub struct MacAddressAndMode(pub MacAddress, pub AddressMode); | ||
| 144 | |||
| 145 | impl From<MacAddressAndMode> for Address { | ||
| 146 | fn from(mac_address_and_mode: MacAddressAndMode) -> Self { | ||
| 147 | let address = mac_address_and_mode.0; | ||
| 148 | let mode = mac_address_and_mode.1; | ||
| 149 | |||
| 150 | match mode { | ||
| 151 | AddressMode::Short => Address::Short(unsafe { address.short }), | ||
| 152 | AddressMode::Extended => Address::Extended(unsafe { address.extended }), | ||
| 153 | AddressMode::NoAddress => Address::Absent, | ||
| 154 | AddressMode::Reserved => Address::Absent, | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 118 | impl Debug for MacAddress { | 159 | impl Debug for MacAddress { |
| 119 | fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | 160 | fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
| 120 | unsafe { | 161 | unsafe { |
| @@ -346,7 +387,7 @@ numeric_enum! { | |||
| 346 | 387 | ||
| 347 | numeric_enum! { | 388 | numeric_enum! { |
| 348 | #[repr(u8)] | 389 | #[repr(u8)] |
| 349 | #[derive(Default, Clone, Copy, Debug)] | 390 | #[derive(Default, Clone, Copy, Debug, PartialEq)] |
| 350 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 391 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 351 | pub enum SecurityLevel { | 392 | pub enum SecurityLevel { |
| 352 | /// MAC Unsecured Mode Security | 393 | /// MAC Unsecured Mode Security |
| @@ -379,3 +420,15 @@ pub struct PanId(pub [u8; 2]); | |||
| 379 | impl PanId { | 420 | impl PanId { |
| 380 | pub const BROADCAST: Self = Self([0xFF, 0xFF]); | 421 | pub const BROADCAST: Self = Self([0xFF, 0xFF]); |
| 381 | } | 422 | } |
| 423 | |||
| 424 | impl From<Pan> for PanId { | ||
| 425 | fn from(value: Pan) -> Self { | ||
| 426 | Self(value.0.to_be_bytes()) | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | impl From<PanId> for Pan { | ||
| 431 | fn from(value: PanId) -> Self { | ||
| 432 | Self(u16::from_be_bytes(value.0)) | ||
| 433 | } | ||
| 434 | } | ||
diff --git a/embassy-stm32-wpan/src/wb55/mod.rs b/embassy-stm32-wpan/src/wb55/mod.rs new file mode 100644 index 000000000..95cfe09f1 --- /dev/null +++ b/embassy-stm32-wpan/src/wb55/mod.rs | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | // This must go FIRST so that all the other modules see its macros. | ||
| 2 | mod fmt; | ||
| 3 | |||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | use core::sync::atomic::{Ordering, compiler_fence}; | ||
| 6 | |||
| 7 | use embassy_hal_internal::Peri; | ||
| 8 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::ipcc::{Config, Ipcc, IpccRxChannel, ReceiveInterruptHandler, TransmitInterruptHandler}; | ||
| 10 | use embassy_stm32::peripherals::IPCC; | ||
| 11 | use sub::mm::MemoryManager; | ||
| 12 | use sub::sys::Sys; | ||
| 13 | use tables::*; | ||
| 14 | use unsafe_linked_list::LinkedListNode; | ||
| 15 | |||
| 16 | pub mod channels; | ||
| 17 | pub mod cmd; | ||
| 18 | pub mod consts; | ||
| 19 | pub mod evt; | ||
| 20 | pub mod lhci; | ||
| 21 | pub mod shci; | ||
| 22 | pub mod sub; | ||
| 23 | pub mod tables; | ||
| 24 | pub mod unsafe_linked_list; | ||
| 25 | |||
| 26 | #[cfg(feature = "wb55_mac")] | ||
| 27 | pub mod mac; | ||
| 28 | |||
| 29 | #[cfg(feature = "wb55_ble")] | ||
| 30 | pub use crate::sub::ble::hci; | ||
| 31 | |||
| 32 | type PacketHeader = LinkedListNode; | ||
| 33 | |||
| 34 | /// Transport Layer for the Mailbox interface | ||
| 35 | pub struct TlMbox<'d> { | ||
| 36 | pub sys_subsystem: Sys<'d>, | ||
| 37 | pub mm_subsystem: MemoryManager<'d>, | ||
| 38 | #[cfg(feature = "wb55_ble")] | ||
| 39 | pub ble_subsystem: sub::ble::Ble<'d>, | ||
| 40 | #[cfg(feature = "wb55_mac")] | ||
| 41 | pub mac_subsystem: sub::mac::Mac<'d>, | ||
| 42 | pub traces: IpccRxChannel<'d>, | ||
| 43 | } | ||
| 44 | |||
| 45 | impl<'d> TlMbox<'d> { | ||
| 46 | /// Initialise the Transport Layer, and creates and returns a wrapper around it. | ||
| 47 | /// | ||
| 48 | /// This method performs the initialisation laid out in AN5289 annex 14.1. However, it differs | ||
| 49 | /// from the implementation documented in Figure 64, to avoid needing to reference any C | ||
| 50 | /// function pointers. | ||
| 51 | /// | ||
| 52 | /// Annex 14.1 lays out the following methods that should be called: | ||
| 53 | /// 1. tl_mbox.c/TL_Init, which initialises the reference table that is shared between CPU1 | ||
| 54 | /// and CPU2. | ||
| 55 | /// 2. shci_tl.c/shci_init(), which initialises the system transport layer, and in turn | ||
| 56 | /// calls tl_mbox.c/TL_SYS_Init, which initialises SYSTEM_EVT_QUEUE channel. | ||
| 57 | /// 3. tl_mbox.c/TL_MM_Init(), which initialises the channel used for sending memory | ||
| 58 | /// manager commands. | ||
| 59 | /// 4. tl_mbox.c/TL_Enable(), which enables the IPCC, and starts CPU2. | ||
| 60 | /// This implementation initialises all of the shared refernce tables and all IPCC channel that | ||
| 61 | /// would be initialised by this process. The developer should therefore treat this method as | ||
| 62 | /// completing all steps in Figure 64. | ||
| 63 | /// | ||
| 64 | /// Once this method has been called, no system commands may be sent until the CPU2 ready | ||
| 65 | /// signal is received, via [sys_subsystem.read]; this completes the procedure laid out in | ||
| 66 | /// Figure 65. | ||
| 67 | /// | ||
| 68 | /// If the `ble` feature is enabled, at this point, the user should call | ||
| 69 | /// [sys_subsystem.shci_c2_ble_init], before any commands are written to the | ||
| 70 | /// [TlMbox.ble_subsystem] ([sub::ble::Ble::new()] completes the process that would otherwise | ||
| 71 | /// be handled by `TL_BLE_Init`; see Figure 66). This completes the procedure laid out in | ||
| 72 | /// Figure 66. | ||
| 73 | // TODO: document what the user should do after calling init to use the mac_802_15_4 subsystem | ||
| 74 | pub async fn init( | ||
| 75 | ipcc: Peri<'d, IPCC>, | ||
| 76 | _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler> | ||
| 77 | + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>, | ||
| 78 | config: Config, | ||
| 79 | ) -> Self { | ||
| 80 | // this is an inlined version of TL_Init from the STM32WB firmware as requested by AN5289. | ||
| 81 | // HW_IPCC_Init is not called, and its purpose is (presumably?) covered by this | ||
| 82 | // implementation | ||
| 83 | unsafe { | ||
| 84 | TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable { | ||
| 85 | device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), | ||
| 86 | ble_table: TL_BLE_TABLE.as_ptr(), | ||
| 87 | thread_table: TL_THREAD_TABLE.as_ptr(), | ||
| 88 | sys_table: TL_SYS_TABLE.as_ptr(), | ||
| 89 | mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(), | ||
| 90 | traces_table: TL_TRACES_TABLE.as_ptr(), | ||
| 91 | mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(), | ||
| 92 | zigbee_table: TL_ZIGBEE_TABLE.as_ptr(), | ||
| 93 | lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(), | ||
| 94 | ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(), | ||
| 95 | }); | ||
| 96 | |||
| 97 | TL_SYS_TABLE | ||
| 98 | .as_mut_ptr() | ||
| 99 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 100 | TL_DEVICE_INFO_TABLE | ||
| 101 | .as_mut_ptr() | ||
| 102 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 103 | TL_BLE_TABLE | ||
| 104 | .as_mut_ptr() | ||
| 105 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 106 | TL_THREAD_TABLE | ||
| 107 | .as_mut_ptr() | ||
| 108 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 109 | TL_MEM_MANAGER_TABLE | ||
| 110 | .as_mut_ptr() | ||
| 111 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 112 | |||
| 113 | TL_TRACES_TABLE | ||
| 114 | .as_mut_ptr() | ||
| 115 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 116 | TL_MAC_802_15_4_TABLE | ||
| 117 | .as_mut_ptr() | ||
| 118 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 119 | TL_ZIGBEE_TABLE | ||
| 120 | .as_mut_ptr() | ||
| 121 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 122 | TL_LLD_TESTS_TABLE | ||
| 123 | .as_mut_ptr() | ||
| 124 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 125 | TL_BLE_LLD_TABLE | ||
| 126 | .as_mut_ptr() | ||
| 127 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 128 | |||
| 129 | EVT_POOL | ||
| 130 | .as_mut_ptr() | ||
| 131 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 132 | SYS_SPARE_EVT_BUF | ||
| 133 | .as_mut_ptr() | ||
| 134 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 135 | CS_BUFFER | ||
| 136 | .as_mut_ptr() | ||
| 137 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 138 | |||
| 139 | #[cfg(feature = "wb55_ble")] | ||
| 140 | { | ||
| 141 | BLE_SPARE_EVT_BUF | ||
| 142 | .as_mut_ptr() | ||
| 143 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 144 | |||
| 145 | BLE_CMD_BUFFER | ||
| 146 | .as_mut_ptr() | ||
| 147 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 148 | HCI_ACL_DATA_BUFFER | ||
| 149 | .as_mut_ptr() | ||
| 150 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 151 | } | ||
| 152 | |||
| 153 | #[cfg(feature = "wb55_mac")] | ||
| 154 | { | ||
| 155 | MAC_802_15_4_CMD_BUFFER | ||
| 156 | .as_mut_ptr() | ||
| 157 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 158 | MAC_802_15_4_NOTIF_RSP_EVT_BUFFER | ||
| 159 | .as_mut_ptr() | ||
| 160 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | compiler_fence(Ordering::SeqCst); | ||
| 165 | |||
| 166 | // this is equivalent to `HW_IPCC_Enable`, which is called by `TL_Enable` | ||
| 167 | let [ | ||
| 168 | (_hw_ipcc_ble_cmd_channel, _ipcc_ble_event_channel), | ||
| 169 | (ipcc_system_cmd_rsp_channel, ipcc_system_event_channel), | ||
| 170 | (_ipcc_mac_802_15_4_cmd_rsp_channel, _ipcc_mac_802_15_4_notification_ack_channel), | ||
| 171 | (ipcc_mm_release_buffer_channel, _ipcc_traces_channel), | ||
| 172 | (_ipcc_ble_lld_cmd_channel, _ipcc_ble_lld_rsp_channel), | ||
| 173 | (_ipcc_hci_acl_data_channel, _), | ||
| 174 | ] = Ipcc::new(ipcc, _irqs, config).split(); | ||
| 175 | |||
| 176 | let mm = sub::mm::MemoryManager::new(ipcc_mm_release_buffer_channel); | ||
| 177 | let mut sys = sub::sys::Sys::new(ipcc_system_cmd_rsp_channel, ipcc_system_event_channel); | ||
| 178 | |||
| 179 | debug!("sys event: {}", sys.read().await.payload()); | ||
| 180 | |||
| 181 | Self { | ||
| 182 | sys_subsystem: sys, | ||
| 183 | #[cfg(feature = "wb55_ble")] | ||
| 184 | ble_subsystem: sub::ble::Ble::new( | ||
| 185 | _hw_ipcc_ble_cmd_channel, | ||
| 186 | _ipcc_ble_event_channel, | ||
| 187 | _ipcc_hci_acl_data_channel, | ||
| 188 | ), | ||
| 189 | #[cfg(feature = "wb55_mac")] | ||
| 190 | mac_subsystem: sub::mac::Mac::new( | ||
| 191 | _ipcc_mac_802_15_4_cmd_rsp_channel, | ||
| 192 | _ipcc_mac_802_15_4_notification_ack_channel, | ||
| 193 | ), | ||
| 194 | mm_subsystem: mm, | ||
| 195 | traces: _ipcc_traces_channel, | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } | ||
diff --git a/embassy-stm32-wpan/src/shci.rs b/embassy-stm32-wpan/src/wb55/shci.rs index 30d689716..3faa79209 100644 --- a/embassy-stm32-wpan/src/shci.rs +++ b/embassy-stm32-wpan/src/wb55/shci.rs | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | use core::{mem, slice}; | 1 | use core::sync::atomic::{Ordering, compiler_fence}; |
| 2 | use core::{mem, ptr, slice}; | ||
| 2 | 3 | ||
| 4 | use crate::cmd::CmdPacket; | ||
| 3 | use crate::consts::{TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE}; | 5 | use crate::consts::{TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE}; |
| 6 | use crate::evt::{CcEvt, EvtStub}; | ||
| 7 | use crate::wb55::PacketHeader; | ||
| 4 | 8 | ||
| 5 | const SHCI_OGF: u16 = 0x3F; | 9 | const SHCI_OGF: u16 = 0x3F; |
| 6 | 10 | ||
| @@ -21,6 +25,18 @@ pub enum SchiCommandStatus { | |||
| 21 | ShciFusCmdNotSupported = 0xFF, | 25 | ShciFusCmdNotSupported = 0xFF, |
| 22 | } | 26 | } |
| 23 | 27 | ||
| 28 | impl SchiCommandStatus { | ||
| 29 | pub unsafe fn from_packet(cmd_buf: *const CmdPacket) -> Result<Self, ()> { | ||
| 30 | let p_cmd_serial = (cmd_buf as *mut u8).add(size_of::<PacketHeader>()); | ||
| 31 | let p_evt_payload = p_cmd_serial.add(size_of::<EvtStub>()); | ||
| 32 | |||
| 33 | compiler_fence(Ordering::Acquire); | ||
| 34 | let cc_evt = ptr::read_unaligned(p_evt_payload as *const CcEvt); | ||
| 35 | |||
| 36 | cc_evt.payload[0].try_into() | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 24 | impl TryFrom<u8> for SchiCommandStatus { | 40 | impl TryFrom<u8> for SchiCommandStatus { |
| 25 | type Error = (); | 41 | type Error = (); |
| 26 | 42 | ||
| @@ -274,69 +290,64 @@ pub struct ShciBleInitCmdParam { | |||
| 274 | pub options: u8, | 290 | pub options: u8, |
| 275 | /// Reserved for future use - shall be set to 0 | 291 | /// Reserved for future use - shall be set to 0 |
| 276 | pub hw_version: u8, | 292 | pub hw_version: u8, |
| 277 | // /** | 293 | /// |
| 278 | // * Maximum number of connection-oriented channels in initiator mode. | 294 | /// Maximum number of connection-oriented channels in initiator mode. |
| 279 | // * Range: 0 .. 64 | 295 | /// Range: 0 .. 64 |
| 280 | // */ | 296 | pub max_coc_initiator_nbr: u8, |
| 281 | // pub max_coc_initiator_nbr: u8, | 297 | |
| 282 | // | 298 | /// |
| 283 | // /** | 299 | /// Minimum transmit power in dBm supported by the Controller. |
| 284 | // * Minimum transmit power in dBm supported by the Controller. | 300 | /// Range: -127 .. 20 |
| 285 | // * Range: -127 .. 20 | 301 | pub min_tx_power: i8, |
| 286 | // */ | 302 | |
| 287 | // pub min_tx_power: i8, | 303 | /// |
| 288 | // | 304 | /// Maximum transmit power in dBm supported by the Controller. |
| 289 | // /** | 305 | /// Range: -127 .. 20 |
| 290 | // * Maximum transmit power in dBm supported by the Controller. | 306 | pub max_tx_power: i8, |
| 291 | // * Range: -127 .. 20 | 307 | |
| 292 | // */ | 308 | /// |
| 293 | // pub max_tx_power: i8, | 309 | /// RX model configuration |
| 294 | // | 310 | /// - bit 0: 1: agc_rssi model improved vs RF blockers 0: Legacy agc_rssi model |
| 295 | // /** | 311 | /// - other bits: reserved ( shall be set to 0) |
| 296 | // * RX model configuration | 312 | pub rx_model_config: u8, |
| 297 | // * - bit 0: 1: agc_rssi model improved vs RF blockers 0: Legacy agc_rssi model | 313 | |
| 298 | // * - other bits: reserved ( shall be set to 0) | 314 | /// Maximum number of advertising sets. |
| 299 | // */ | 315 | /// Range: 1 .. 8 with limitation: |
| 300 | // pub rx_model_config: u8, | 316 | /// 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 |
| 301 | // | 317 | /// on Max Extended advertising configuration supported. |
| 302 | // /* Maximum number of advertising sets. | 318 | /// This parameter is considered by the CPU2 when Options has SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV flag set |
| 303 | // * Range: 1 .. 8 with limitation: | 319 | pub max_adv_set_nbr: u8, |
| 304 | // * 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 | 320 | |
| 305 | // * on Max Extended advertising configuration supported. | 321 | /// Maximum advertising data length (in bytes) |
| 306 | // * This parameter is considered by the CPU2 when Options has SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV flag set | 322 | /// Range: 31 .. 1650 with limitation: |
| 307 | // */ | 323 | /// 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 |
| 308 | // pub max_adv_set_nbr: u8, | 324 | /// on Max Extended advertising configuration supported. |
| 309 | // | 325 | /// This parameter is considered by the CPU2 when Options has SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV flag set |
| 310 | // /* Maximum advertising data length (in bytes) | 326 | pub max_adv_data_len: u16, |
| 311 | // * Range: 31 .. 1650 with limitation: | 327 | |
| 312 | // * 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 | 328 | /// RF TX Path Compensation Value (16-bit signed integer). Units: 0.1 dB. |
| 313 | // * on Max Extended advertising configuration supported. | 329 | /// Range: -1280 .. 1280 |
| 314 | // * This parameter is considered by the CPU2 when Options has SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV flag set | 330 | pub tx_path_compens: i16, |
| 315 | // */ | 331 | |
| 316 | // pub max_adv_data_len: u16, | 332 | //// RF RX Path Compensation Value (16-bit signed integer). Units: 0.1 dB. |
| 317 | // | 333 | /// Range: -1280 .. 1280 |
| 318 | // /* RF TX Path Compensation Value (16-bit signed integer). Units: 0.1 dB. | 334 | pub rx_path_compens: i16, |
| 319 | // * Range: -1280 .. 1280 | 335 | |
| 320 | // */ | 336 | /// BLE core specification version (8-bit unsigned integer). |
| 321 | // pub tx_path_compens: i16, | 337 | /// values as: 11(5.2), 12(5.3) |
| 322 | // | 338 | pub ble_core_version: u8, |
| 323 | // /* RF RX Path Compensation Value (16-bit signed integer). Units: 0.1 dB. | 339 | |
| 324 | // * Range: -1280 .. 1280 | 340 | /// Options flags extension |
| 325 | // */ | 341 | /// - bit 0: 1: appearance Writable 0: appearance Read-Only |
| 326 | // pub rx_path_compens: i16, | 342 | /// - bit 1: 1: Enhanced ATT supported 0: Enhanced ATT not supported |
| 327 | // | 343 | /// - other bits: reserved ( shall be set to 0) |
| 328 | // /* BLE core specification version (8-bit unsigned integer). | 344 | pub options_extension: u8, |
| 329 | // * values as: 11(5.2), 12(5.3) | 345 | |
| 330 | // */ | 346 | /// MaxAddEattBearers |
| 331 | // pub ble_core_version: u8, | 347 | /// Maximum number of bearers that can be created for Enhanced ATT |
| 332 | // | 348 | /// in addition to the number of links |
| 333 | // /** | 349 | /// - Range: 0 .. 4 |
| 334 | // * Options flags extension | 350 | pub max_add_eatt_bearers: u8, |
| 335 | // * - bit 0: 1: appearance Writable 0: appearance Read-Only | ||
| 336 | // * - bit 1: 1: Enhanced ATT supported 0: Enhanced ATT not supported | ||
| 337 | // * - other bits: reserved ( shall be set to 0) | ||
| 338 | // */ | ||
| 339 | // pub options_extension: u8, | ||
| 340 | } | 351 | } |
| 341 | 352 | ||
| 342 | impl ShciBleInitCmdParam { | 353 | impl ShciBleInitCmdParam { |
| @@ -351,7 +362,7 @@ impl Default for ShciBleInitCmdParam { | |||
| 351 | p_ble_buffer_address: 0, | 362 | p_ble_buffer_address: 0, |
| 352 | ble_buffer_size: 0, | 363 | ble_buffer_size: 0, |
| 353 | num_attr_record: 68, | 364 | num_attr_record: 68, |
| 354 | num_attr_serv: 8, | 365 | num_attr_serv: 4, |
| 355 | attr_value_arr_size: 1344, | 366 | attr_value_arr_size: 1344, |
| 356 | num_of_links: 2, | 367 | num_of_links: 2, |
| 357 | extended_packet_length_enable: 1, | 368 | extended_packet_length_enable: 1, |
| @@ -366,6 +377,17 @@ impl Default for ShciBleInitCmdParam { | |||
| 366 | viterbi_enable: 1, | 377 | viterbi_enable: 1, |
| 367 | options: 0, | 378 | options: 0, |
| 368 | hw_version: 0, | 379 | hw_version: 0, |
| 380 | max_coc_initiator_nbr: 32, | ||
| 381 | min_tx_power: -40, | ||
| 382 | max_tx_power: 6, | ||
| 383 | rx_model_config: 0, | ||
| 384 | max_adv_set_nbr: 2, | ||
| 385 | max_adv_data_len: 1650, | ||
| 386 | tx_path_compens: 0, | ||
| 387 | rx_path_compens: 0, | ||
| 388 | ble_core_version: 11, | ||
| 389 | options_extension: 0, | ||
| 390 | max_add_eatt_bearers: 4, | ||
| 369 | } | 391 | } |
| 370 | } | 392 | } |
| 371 | } | 393 | } |
diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/wb55/sub/ble.rs index 0f770d92c..a822d6530 100644 --- a/embassy-stm32-wpan/src/sub/ble.rs +++ b/embassy-stm32-wpan/src/wb55/sub/ble.rs | |||
| @@ -1,15 +1,15 @@ | |||
| 1 | use core::ptr; | 1 | use core::ptr; |
| 2 | 2 | ||
| 3 | use embassy_stm32::ipcc::Ipcc; | 3 | use embassy_stm32::ipcc::{IpccRxChannel, IpccTxChannel}; |
| 4 | use hci::Opcode; | 4 | use hci::Opcode; |
| 5 | 5 | ||
| 6 | use crate::cmd::CmdPacket; | 6 | use crate::cmd::CmdPacket; |
| 7 | use crate::consts::{TlPacketType, TL_BLEEVT_CC_OPCODE, TL_BLEEVT_CS_OPCODE}; | 7 | use crate::consts::{TL_BLEEVT_CC_OPCODE, TL_BLEEVT_CS_OPCODE, TlPacketType}; |
| 8 | use crate::evt; | ||
| 8 | use crate::evt::{EvtBox, EvtPacket, EvtStub}; | 9 | use crate::evt::{EvtBox, EvtPacket, EvtStub}; |
| 9 | use crate::sub::mm; | 10 | use crate::sub::mm; |
| 10 | use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; | 11 | use crate::tables::{BLE_CMD_BUFFER, BleTable, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; |
| 11 | use crate::unsafe_linked_list::LinkedListNode; | 12 | use crate::unsafe_linked_list::LinkedListNode; |
| 12 | use crate::{channels, evt}; | ||
| 13 | 13 | ||
| 14 | /// A guard that, once constructed, may be used to send BLE commands to CPU2. | 14 | /// A guard that, once constructed, may be used to send BLE commands to CPU2. |
| 15 | /// | 15 | /// |
| @@ -36,15 +36,21 @@ use crate::{channels, evt}; | |||
| 36 | /// # mbox.ble_subsystem.reset().await; | 36 | /// # mbox.ble_subsystem.reset().await; |
| 37 | /// # let _reset_response = mbox.ble_subsystem.read().await; | 37 | /// # let _reset_response = mbox.ble_subsystem.read().await; |
| 38 | /// ``` | 38 | /// ``` |
| 39 | pub struct Ble { | 39 | pub struct Ble<'a> { |
| 40 | _private: (), | 40 | hw_ipcc_ble_cmd_channel: IpccTxChannel<'a>, |
| 41 | ipcc_ble_event_channel: IpccRxChannel<'a>, | ||
| 42 | ipcc_hci_acl_data_channel: IpccTxChannel<'a>, | ||
| 41 | } | 43 | } |
| 42 | 44 | ||
| 43 | impl Ble { | 45 | impl<'a> Ble<'a> { |
| 44 | /// Constructs a guard that allows for BLE commands to be sent to CPU2. | 46 | /// Constructs a guard that allows for BLE commands to be sent to CPU2. |
| 45 | /// | 47 | /// |
| 46 | /// This takes the place of `TL_BLE_Init`, completing that step as laid out in AN5289, Fig 66. | 48 | /// This takes the place of `TL_BLE_Init`, completing that step as laid out in AN5289, Fig 66. |
| 47 | pub(crate) fn new() -> Self { | 49 | pub(crate) fn new( |
| 50 | hw_ipcc_ble_cmd_channel: IpccTxChannel<'a>, | ||
| 51 | ipcc_ble_event_channel: IpccRxChannel<'a>, | ||
| 52 | ipcc_hci_acl_data_channel: IpccTxChannel<'a>, | ||
| 53 | ) -> Self { | ||
| 48 | unsafe { | 54 | unsafe { |
| 49 | LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); | 55 | LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); |
| 50 | 56 | ||
| @@ -56,44 +62,53 @@ impl Ble { | |||
| 56 | }); | 62 | }); |
| 57 | } | 63 | } |
| 58 | 64 | ||
| 59 | Self { _private: () } | 65 | Self { |
| 66 | hw_ipcc_ble_cmd_channel, | ||
| 67 | ipcc_ble_event_channel, | ||
| 68 | ipcc_hci_acl_data_channel, | ||
| 69 | } | ||
| 60 | } | 70 | } |
| 61 | 71 | ||
| 62 | /// `HW_IPCC_BLE_EvtNot` | 72 | /// `HW_IPCC_BLE_EvtNot` |
| 63 | pub async fn tl_read(&self) -> EvtBox<Self> { | 73 | pub async fn tl_read(&mut self) -> EvtBox<Self> { |
| 64 | Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe { | 74 | self.ipcc_ble_event_channel |
| 65 | if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) { | 75 | .receive(|| unsafe { |
| 66 | Some(EvtBox::new(node_ptr.cast())) | 76 | if let Some(node_ptr) = |
| 67 | } else { | 77 | critical_section::with(|cs| LinkedListNode::remove_head(cs, EVT_QUEUE.as_mut_ptr())) |
| 68 | None | 78 | { |
| 69 | } | 79 | Some(EvtBox::new(node_ptr.cast())) |
| 70 | }) | 80 | } else { |
| 71 | .await | 81 | None |
| 82 | } | ||
| 83 | }) | ||
| 84 | .await | ||
| 72 | } | 85 | } |
| 73 | 86 | ||
| 74 | /// `TL_BLE_SendCmd` | 87 | /// `TL_BLE_SendCmd` |
| 75 | pub async fn tl_write(&self, opcode: u16, payload: &[u8]) { | 88 | pub async fn tl_write(&mut self, opcode: u16, payload: &[u8]) { |
| 76 | Ipcc::send(channels::cpu1::IPCC_BLE_CMD_CHANNEL, || unsafe { | 89 | self.hw_ipcc_ble_cmd_channel |
| 77 | CmdPacket::write_into(BLE_CMD_BUFFER.as_mut_ptr(), TlPacketType::BleCmd, opcode, payload); | 90 | .send(|| unsafe { |
| 78 | }) | 91 | CmdPacket::write_into(BLE_CMD_BUFFER.as_mut_ptr(), TlPacketType::BleCmd, opcode, payload); |
| 79 | .await; | 92 | }) |
| 93 | .await; | ||
| 80 | } | 94 | } |
| 81 | 95 | ||
| 82 | /// `TL_BLE_SendAclData` | 96 | /// `TL_BLE_SendAclData` |
| 83 | pub async fn acl_write(&self, handle: u16, payload: &[u8]) { | 97 | pub async fn acl_write(&mut self, handle: u16, payload: &[u8]) { |
| 84 | Ipcc::send(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, || unsafe { | 98 | self.ipcc_hci_acl_data_channel |
| 85 | CmdPacket::write_into( | 99 | .send(|| unsafe { |
| 86 | HCI_ACL_DATA_BUFFER.as_mut_ptr() as *mut _, | 100 | CmdPacket::write_into( |
| 87 | TlPacketType::AclData, | 101 | HCI_ACL_DATA_BUFFER.as_mut_ptr() as *mut _, |
| 88 | handle, | 102 | TlPacketType::AclData, |
| 89 | payload, | 103 | handle, |
| 90 | ); | 104 | payload, |
| 91 | }) | 105 | ); |
| 92 | .await; | 106 | }) |
| 107 | .await; | ||
| 93 | } | 108 | } |
| 94 | } | 109 | } |
| 95 | 110 | ||
| 96 | impl evt::MemoryManager for Ble { | 111 | impl<'a> evt::MemoryManager for Ble<'a> { |
| 97 | /// SAFETY: passing a pointer to something other than a managed event packet is UB | 112 | /// SAFETY: passing a pointer to something other than a managed event packet is UB |
| 98 | unsafe fn drop_event_packet(evt: *mut EvtPacket) { | 113 | unsafe fn drop_event_packet(evt: *mut EvtPacket) { |
| 99 | let stub = unsafe { | 114 | let stub = unsafe { |
| @@ -110,12 +125,12 @@ impl evt::MemoryManager for Ble { | |||
| 110 | 125 | ||
| 111 | pub extern crate stm32wb_hci as hci; | 126 | pub extern crate stm32wb_hci as hci; |
| 112 | 127 | ||
| 113 | impl hci::Controller for Ble { | 128 | impl<'a> hci::Controller for Ble<'a> { |
| 114 | async fn controller_write(&mut self, opcode: Opcode, payload: &[u8]) { | 129 | async fn controller_write(&mut self, opcode: Opcode, payload: &[u8]) { |
| 115 | self.tl_write(opcode.0, payload).await; | 130 | self.tl_write(opcode.0, payload).await; |
| 116 | } | 131 | } |
| 117 | 132 | ||
| 118 | async fn controller_read_into(&self, buf: &mut [u8]) { | 133 | async fn controller_read_into(&mut self, buf: &mut [u8]) { |
| 119 | let evt_box = self.tl_read().await; | 134 | let evt_box = self.tl_read().await; |
| 120 | let evt_serial = evt_box.serial(); | 135 | let evt_serial = evt_box.serial(); |
| 121 | 136 | ||
diff --git a/embassy-stm32-wpan/src/wb55/sub/mac.rs b/embassy-stm32-wpan/src/wb55/sub/mac.rs new file mode 100644 index 000000000..ce2903e61 --- /dev/null +++ b/embassy-stm32-wpan/src/wb55/sub/mac.rs | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::ptr; | ||
| 3 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use embassy_futures::poll_once; | ||
| 7 | use embassy_stm32::ipcc::{Ipcc, IpccRxChannel, IpccTxChannel}; | ||
| 8 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 9 | |||
| 10 | use crate::cmd::CmdPacket; | ||
| 11 | use crate::consts::TlPacketType; | ||
| 12 | use crate::evt; | ||
| 13 | use crate::evt::{EvtBox, EvtPacket}; | ||
| 14 | use crate::mac::commands::MacCommand; | ||
| 15 | use crate::mac::event::MacEvent; | ||
| 16 | use crate::mac::typedefs::MacError; | ||
| 17 | use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER}; | ||
| 18 | use crate::unsafe_linked_list::LinkedListNode; | ||
| 19 | |||
| 20 | static MAC_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 21 | static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); | ||
| 22 | |||
| 23 | pub struct Mac<'a> { | ||
| 24 | ipcc_mac_802_15_4_cmd_rsp_channel: IpccTxChannel<'a>, | ||
| 25 | ipcc_mac_802_15_4_notification_ack_channel: IpccRxChannel<'a>, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl<'a> Mac<'a> { | ||
| 29 | pub(crate) fn new( | ||
| 30 | ipcc_mac_802_15_4_cmd_rsp_channel: IpccTxChannel<'a>, | ||
| 31 | ipcc_mac_802_15_4_notification_ack_channel: IpccRxChannel<'a>, | ||
| 32 | ) -> Self { | ||
| 33 | use crate::tables::{ | ||
| 34 | MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, Mac802_15_4Table, TL_MAC_802_15_4_TABLE, | ||
| 35 | TL_TRACES_TABLE, TRACES_EVT_QUEUE, TracesTable, | ||
| 36 | }; | ||
| 37 | |||
| 38 | unsafe { | ||
| 39 | LinkedListNode::init_head(TRACES_EVT_QUEUE.as_mut_ptr() as *mut _); | ||
| 40 | |||
| 41 | TL_TRACES_TABLE.as_mut_ptr().write_volatile(TracesTable { | ||
| 42 | traces_queue: TRACES_EVT_QUEUE.as_ptr() as *const _, | ||
| 43 | }); | ||
| 44 | |||
| 45 | TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table { | ||
| 46 | p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(), | ||
| 47 | p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(), | ||
| 48 | evt_queue: core::ptr::null_mut(), | ||
| 49 | }); | ||
| 50 | }; | ||
| 51 | |||
| 52 | Self { | ||
| 53 | ipcc_mac_802_15_4_cmd_rsp_channel, | ||
| 54 | ipcc_mac_802_15_4_notification_ack_channel, | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | pub const fn split(self) -> (MacRx<'a>, MacTx<'a>) { | ||
| 59 | ( | ||
| 60 | MacRx { | ||
| 61 | ipcc_mac_802_15_4_notification_ack_channel: self.ipcc_mac_802_15_4_notification_ack_channel, | ||
| 62 | }, | ||
| 63 | MacTx { | ||
| 64 | ipcc_mac_802_15_4_cmd_rsp_channel: self.ipcc_mac_802_15_4_cmd_rsp_channel, | ||
| 65 | }, | ||
| 66 | ) | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | pub struct MacTx<'a> { | ||
| 71 | ipcc_mac_802_15_4_cmd_rsp_channel: IpccTxChannel<'a>, | ||
| 72 | } | ||
| 73 | |||
| 74 | impl<'a> MacTx<'a> { | ||
| 75 | /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` | ||
| 76 | pub async fn tl_write_and_get_response(&mut self, opcode: u16, payload: &[u8]) -> u8 { | ||
| 77 | self.tl_write(opcode, payload).await; | ||
| 78 | self.ipcc_mac_802_15_4_cmd_rsp_channel.flush().await; | ||
| 79 | |||
| 80 | unsafe { | ||
| 81 | let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket; | ||
| 82 | let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8; | ||
| 83 | |||
| 84 | ptr::read_volatile(p_mac_rsp_evt) | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | /// `TL_MAC_802_15_4_SendCmd` | ||
| 89 | pub async fn tl_write(&mut self, opcode: u16, payload: &[u8]) { | ||
| 90 | self.ipcc_mac_802_15_4_cmd_rsp_channel | ||
| 91 | .send(|| unsafe { | ||
| 92 | CmdPacket::write_into( | ||
| 93 | MAC_802_15_4_CMD_BUFFER.as_mut_ptr(), | ||
| 94 | TlPacketType::MacCmd, | ||
| 95 | opcode, | ||
| 96 | payload, | ||
| 97 | ); | ||
| 98 | }) | ||
| 99 | .await; | ||
| 100 | } | ||
| 101 | |||
| 102 | pub async fn send_command<T>(&mut self, cmd: &T) -> Result<(), MacError> | ||
| 103 | where | ||
| 104 | T: MacCommand, | ||
| 105 | { | ||
| 106 | let response = self.tl_write_and_get_response(T::OPCODE as u16, cmd.payload()).await; | ||
| 107 | |||
| 108 | if response == 0x00 { | ||
| 109 | Ok(()) | ||
| 110 | } else { | ||
| 111 | Err(MacError::from(response)) | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | pub struct MacRx<'a> { | ||
| 117 | ipcc_mac_802_15_4_notification_ack_channel: IpccRxChannel<'a>, | ||
| 118 | } | ||
| 119 | |||
| 120 | impl<'a> MacRx<'a> { | ||
| 121 | /// `HW_IPCC_MAC_802_15_4_EvtNot` | ||
| 122 | /// | ||
| 123 | /// This function will stall if the previous `EvtBox` has not been dropped | ||
| 124 | pub async fn tl_read(&mut self) -> EvtBox<MacRx<'a>> { | ||
| 125 | // Wait for the last event box to be dropped | ||
| 126 | poll_fn(|cx| { | ||
| 127 | MAC_WAKER.register(cx.waker()); | ||
| 128 | if MAC_EVT_OUT.load(Ordering::Acquire) { | ||
| 129 | Poll::Pending | ||
| 130 | } else { | ||
| 131 | Poll::Ready(()) | ||
| 132 | } | ||
| 133 | }) | ||
| 134 | .await; | ||
| 135 | |||
| 136 | // Return a new event box | ||
| 137 | self.ipcc_mac_802_15_4_notification_ack_channel | ||
| 138 | .receive(|| unsafe { | ||
| 139 | // The closure is not async, therefore the closure must execute to completion (cannot be dropped) | ||
| 140 | // Therefore, the event box is guaranteed to be cleaned up if it's not leaked | ||
| 141 | MAC_EVT_OUT.store(true, Ordering::SeqCst); | ||
| 142 | |||
| 143 | Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _)) | ||
| 144 | }) | ||
| 145 | .await | ||
| 146 | } | ||
| 147 | |||
| 148 | pub async fn read<'b>(&mut self) -> Result<MacEvent<'b>, ()> { | ||
| 149 | MacEvent::new(self.tl_read().await) | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | impl<'a> evt::MemoryManager for MacRx<'a> { | ||
| 154 | /// SAFETY: passing a pointer to something other than a managed event packet is UB | ||
| 155 | unsafe fn drop_event_packet(_: *mut EvtPacket) { | ||
| 156 | trace!("mac drop event"); | ||
| 157 | |||
| 158 | // Write the ack | ||
| 159 | CmdPacket::write_into( | ||
| 160 | MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, | ||
| 161 | TlPacketType::OtAck, | ||
| 162 | 0, | ||
| 163 | &[], | ||
| 164 | ); | ||
| 165 | |||
| 166 | // Clear the rx flag | ||
| 167 | let _ = poll_once(Ipcc::receive::<()>(3, || None)); | ||
| 168 | |||
| 169 | // Allow a new read call | ||
| 170 | MAC_EVT_OUT.store(false, Ordering::Release); | ||
| 171 | MAC_WAKER.wake(); | ||
| 172 | } | ||
| 173 | } | ||
diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/wb55/sub/mm.rs index 4e4d2f854..0ca7d1835 100644 --- a/embassy-stm32-wpan/src/sub/mm.rs +++ b/embassy-stm32-wpan/src/wb55/sub/mm.rs | |||
| @@ -3,36 +3,35 @@ use core::future::poll_fn; | |||
| 3 | use core::mem::MaybeUninit; | 3 | use core::mem::MaybeUninit; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use aligned::{Aligned, A4}; | 6 | use aligned::{A4, Aligned}; |
| 7 | use cortex_m::interrupt; | 7 | use embassy_stm32::ipcc::IpccTxChannel; |
| 8 | use embassy_stm32::ipcc::Ipcc; | ||
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | 9 | ||
| 11 | use crate::consts::POOL_SIZE; | 10 | use crate::consts::POOL_SIZE; |
| 11 | use crate::evt; | ||
| 12 | use crate::evt::EvtPacket; | 12 | use crate::evt::EvtPacket; |
| 13 | #[cfg(feature = "ble")] | 13 | #[cfg(feature = "wb55_ble")] |
| 14 | use crate::tables::BLE_SPARE_EVT_BUF; | 14 | use crate::tables::BLE_SPARE_EVT_BUF; |
| 15 | use crate::tables::{MemManagerTable, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE}; | 15 | use crate::tables::{EVT_POOL, FREE_BUF_QUEUE, MemManagerTable, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE}; |
| 16 | use crate::unsafe_linked_list::LinkedListNode; | 16 | use crate::unsafe_linked_list::LinkedListNode; |
| 17 | use crate::{channels, evt}; | ||
| 18 | 17 | ||
| 19 | static MM_WAKER: AtomicWaker = AtomicWaker::new(); | 18 | static MM_WAKER: AtomicWaker = AtomicWaker::new(); |
| 20 | static mut LOCAL_FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit()); | 19 | static mut LOCAL_FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit()); |
| 21 | 20 | ||
| 22 | pub struct MemoryManager { | 21 | pub struct MemoryManager<'a> { |
| 23 | _private: (), | 22 | ipcc_mm_release_buffer_channel: IpccTxChannel<'a>, |
| 24 | } | 23 | } |
| 25 | 24 | ||
| 26 | impl MemoryManager { | 25 | impl<'a> MemoryManager<'a> { |
| 27 | pub(crate) fn new() -> Self { | 26 | pub(crate) fn new(ipcc_mm_release_buffer_channel: IpccTxChannel<'a>) -> Self { |
| 28 | unsafe { | 27 | unsafe { |
| 29 | LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr()); | 28 | LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr()); |
| 30 | LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()); | 29 | LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()); |
| 31 | 30 | ||
| 32 | TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable { | 31 | TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable { |
| 33 | #[cfg(feature = "ble")] | 32 | #[cfg(feature = "wb55_ble")] |
| 34 | spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(), | 33 | spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(), |
| 35 | #[cfg(not(feature = "ble"))] | 34 | #[cfg(not(feature = "wb55_ble"))] |
| 36 | spare_ble_buffer: core::ptr::null(), | 35 | spare_ble_buffer: core::ptr::null(), |
| 37 | spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(), | 36 | spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(), |
| 38 | blepool: EVT_POOL.as_ptr().cast(), | 37 | blepool: EVT_POOL.as_ptr().cast(), |
| @@ -43,14 +42,16 @@ impl MemoryManager { | |||
| 43 | }); | 42 | }); |
| 44 | } | 43 | } |
| 45 | 44 | ||
| 46 | Self { _private: () } | 45 | Self { |
| 46 | ipcc_mm_release_buffer_channel, | ||
| 47 | } | ||
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | pub async fn run_queue(&self) { | 50 | pub async fn run_queue(&mut self) -> ! { |
| 50 | loop { | 51 | loop { |
| 51 | poll_fn(|cx| unsafe { | 52 | poll_fn(|cx| unsafe { |
| 52 | MM_WAKER.register(cx.waker()); | 53 | MM_WAKER.register(cx.waker()); |
| 53 | if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { | 54 | if critical_section::with(|cs| LinkedListNode::is_empty(cs, LOCAL_FREE_BUF_QUEUE.as_mut_ptr())) { |
| 54 | Poll::Pending | 55 | Poll::Pending |
| 55 | } else { | 56 | } else { |
| 56 | Poll::Ready(()) | 57 | Poll::Ready(()) |
| @@ -58,24 +59,24 @@ impl MemoryManager { | |||
| 58 | }) | 59 | }) |
| 59 | .await; | 60 | .await; |
| 60 | 61 | ||
| 61 | Ipcc::send(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, || { | 62 | self.ipcc_mm_release_buffer_channel |
| 62 | interrupt::free(|_| unsafe { | 63 | .send(|| { |
| 63 | // CS required while moving nodes | 64 | critical_section::with(|cs| unsafe { |
| 64 | while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { | 65 | while let Some(node_ptr) = LinkedListNode::remove_head(cs, LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { |
| 65 | LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr); | 66 | LinkedListNode::insert_head(cs, FREE_BUF_QUEUE.as_mut_ptr(), node_ptr); |
| 66 | } | 67 | } |
| 68 | }) | ||
| 67 | }) | 69 | }) |
| 68 | }) | 70 | .await; |
| 69 | .await; | ||
| 70 | } | 71 | } |
| 71 | } | 72 | } |
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | impl evt::MemoryManager for MemoryManager { | 75 | impl<'a> evt::MemoryManager for MemoryManager<'a> { |
| 75 | /// SAFETY: passing a pointer to something other than a managed event packet is UB | 76 | /// SAFETY: passing a pointer to something other than a managed event packet is UB |
| 76 | unsafe fn drop_event_packet(evt: *mut EvtPacket) { | 77 | unsafe fn drop_event_packet(evt: *mut EvtPacket) { |
| 77 | interrupt::free(|_| unsafe { | 78 | critical_section::with(|cs| unsafe { |
| 78 | LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _); | 79 | LinkedListNode::insert_head(cs, LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _); |
| 79 | }); | 80 | }); |
| 80 | 81 | ||
| 81 | MM_WAKER.wake(); | 82 | MM_WAKER.wake(); |
diff --git a/embassy-stm32-wpan/src/wb55/sub/mod.rs b/embassy-stm32-wpan/src/wb55/sub/mod.rs new file mode 100644 index 000000000..d3ebd822a --- /dev/null +++ b/embassy-stm32-wpan/src/wb55/sub/mod.rs | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #[cfg(feature = "wb55_ble")] | ||
| 2 | pub mod ble; | ||
| 3 | #[cfg(feature = "wb55_mac")] | ||
| 4 | pub mod mac; | ||
| 5 | pub mod mm; | ||
| 6 | pub mod sys; | ||
diff --git a/embassy-stm32-wpan/src/wb55/sub/sys.rs b/embassy-stm32-wpan/src/wb55/sub/sys.rs new file mode 100644 index 000000000..2e625a677 --- /dev/null +++ b/embassy-stm32-wpan/src/wb55/sub/sys.rs | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | use embassy_stm32::ipcc::{IpccRxChannel, IpccTxChannel}; | ||
| 2 | |||
| 3 | use crate::cmd::CmdPacket; | ||
| 4 | use crate::consts::TlPacketType; | ||
| 5 | use crate::evt::EvtBox; | ||
| 6 | #[cfg(feature = "wb55_ble")] | ||
| 7 | use crate::shci::ShciBleInitCmdParam; | ||
| 8 | use crate::shci::{SchiCommandStatus, ShciOpcode}; | ||
| 9 | use crate::sub::mm; | ||
| 10 | use crate::tables::{SysTable, WirelessFwInfoTable}; | ||
| 11 | use crate::unsafe_linked_list::LinkedListNode; | ||
| 12 | use crate::wb55::{SYS_CMD_BUF, SYSTEM_EVT_QUEUE, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; | ||
| 13 | |||
| 14 | /// A guard that, once constructed, allows for sys commands to be sent to CPU2. | ||
| 15 | pub struct Sys<'a> { | ||
| 16 | ipcc_system_cmd_rsp_channel: IpccTxChannel<'a>, | ||
| 17 | ipcc_system_event_channel: IpccRxChannel<'a>, | ||
| 18 | } | ||
| 19 | |||
| 20 | impl<'a> Sys<'a> { | ||
| 21 | /// TL_Sys_Init | ||
| 22 | pub(crate) fn new( | ||
| 23 | ipcc_system_cmd_rsp_channel: IpccTxChannel<'a>, | ||
| 24 | ipcc_system_event_channel: IpccRxChannel<'a>, | ||
| 25 | ) -> Self { | ||
| 26 | unsafe { | ||
| 27 | LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); | ||
| 28 | |||
| 29 | TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable { | ||
| 30 | pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(), | ||
| 31 | sys_queue: SYSTEM_EVT_QUEUE.as_ptr(), | ||
| 32 | }); | ||
| 33 | } | ||
| 34 | |||
| 35 | Self { | ||
| 36 | ipcc_system_cmd_rsp_channel, | ||
| 37 | ipcc_system_event_channel, | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | /// Returns CPU2 wireless firmware information (if present). | ||
| 42 | pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> { | ||
| 43 | let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table }; | ||
| 44 | |||
| 45 | // Zero version indicates that CPU2 wasn't active and didn't fill the information table | ||
| 46 | if info.version != 0 { Some(info) } else { None } | ||
| 47 | } | ||
| 48 | |||
| 49 | pub async fn write(&mut self, opcode: ShciOpcode, payload: &[u8]) { | ||
| 50 | self.ipcc_system_cmd_rsp_channel | ||
| 51 | .send(|| unsafe { | ||
| 52 | CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode as u16, payload); | ||
| 53 | }) | ||
| 54 | .await; | ||
| 55 | } | ||
| 56 | |||
| 57 | /// `HW_IPCC_SYS_CmdEvtNot` | ||
| 58 | pub async fn write_and_get_response( | ||
| 59 | &mut self, | ||
| 60 | opcode: ShciOpcode, | ||
| 61 | payload: &[u8], | ||
| 62 | ) -> Result<SchiCommandStatus, ()> { | ||
| 63 | self.write(opcode, payload).await; | ||
| 64 | self.ipcc_system_cmd_rsp_channel.flush().await; | ||
| 65 | |||
| 66 | unsafe { SchiCommandStatus::from_packet(SYS_CMD_BUF.as_ptr()) } | ||
| 67 | } | ||
| 68 | |||
| 69 | #[cfg(feature = "wb55_mac")] | ||
| 70 | pub async fn shci_c2_mac_802_15_4_init(&mut self) -> Result<SchiCommandStatus, ()> { | ||
| 71 | self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await | ||
| 72 | } | ||
| 73 | |||
| 74 | /// Send a request to CPU2 to initialise the BLE stack. | ||
| 75 | /// | ||
| 76 | /// This must be called before any BLE commands are sent via the BLE channel (according to | ||
| 77 | /// AN5289, Figures 65 and 66). It should only be called after CPU2 sends a system event, via | ||
| 78 | /// `HW_IPCC_SYS_EvtNot`, aka `IoBusCallBackUserEvt` (as detailed in Figure 65), aka | ||
| 79 | /// [crate::sub::ble::hci::host::uart::UartHci::read]. | ||
| 80 | #[cfg(feature = "wb55_ble")] | ||
| 81 | pub async fn shci_c2_ble_init(&mut self, param: ShciBleInitCmdParam) -> Result<SchiCommandStatus, ()> { | ||
| 82 | self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await | ||
| 83 | } | ||
| 84 | |||
| 85 | /// `HW_IPCC_SYS_EvtNot` | ||
| 86 | /// | ||
| 87 | /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`, | ||
| 88 | /// as the embassy implementation avoids the need to call C public bindings, and instead | ||
| 89 | /// handles the event channels directly. | ||
| 90 | pub async fn read(&mut self) -> EvtBox<mm::MemoryManager<'_>> { | ||
| 91 | self.ipcc_system_event_channel | ||
| 92 | .receive(|| unsafe { | ||
| 93 | if let Some(node_ptr) = | ||
| 94 | critical_section::with(|cs| LinkedListNode::remove_head(cs, SYSTEM_EVT_QUEUE.as_mut_ptr())) | ||
| 95 | { | ||
| 96 | Some(EvtBox::new(node_ptr.cast())) | ||
| 97 | } else { | ||
| 98 | None | ||
| 99 | } | ||
| 100 | }) | ||
| 101 | .await | ||
| 102 | } | ||
| 103 | } | ||
diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/wb55/tables.rs index fe6fc47a3..2e6a9199b 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/wb55/tables.rs | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | use core::mem::MaybeUninit; | 1 | use core::mem::MaybeUninit; |
| 2 | 2 | ||
| 3 | use aligned::{Aligned, A4}; | 3 | use aligned::{A4, Aligned}; |
| 4 | use bit_field::BitField; | 4 | use bit_field::BitField; |
| 5 | 5 | ||
| 6 | use crate::cmd::{AclDataPacket, CmdPacket}; | 6 | use crate::cmd::{AclDataPacket, CmdPacket}; |
| 7 | #[cfg(feature = "mac")] | 7 | #[cfg(feature = "wb55_mac")] |
| 8 | use crate::consts::C_SIZE_CMD_STRING; | 8 | use crate::consts::C_SIZE_CMD_STRING; |
| 9 | use crate::consts::{POOL_SIZE, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE}; | 9 | use crate::consts::{POOL_SIZE, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE}; |
| 10 | use crate::unsafe_linked_list::LinkedListNode; | 10 | use crate::unsafe_linked_list::LinkedListNode; |
| @@ -190,94 +190,94 @@ pub struct RefTable { | |||
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | // --------------------- ref table --------------------- | 192 | // --------------------- ref table --------------------- |
| 193 | #[link_section = "TL_REF_TABLE"] | 193 | #[unsafe(link_section = "TL_REF_TABLE")] |
| 194 | pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit(); | 194 | pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::zeroed(); |
| 195 | 195 | ||
| 196 | #[link_section = "MB_MEM1"] | 196 | #[unsafe(link_section = "MB_MEM1")] |
| 197 | pub static mut TL_DEVICE_INFO_TABLE: Aligned<A4, MaybeUninit<DeviceInfoTable>> = Aligned(MaybeUninit::uninit()); | 197 | pub static mut TL_DEVICE_INFO_TABLE: Aligned<A4, MaybeUninit<DeviceInfoTable>> = Aligned(MaybeUninit::zeroed()); |
| 198 | 198 | ||
| 199 | #[link_section = "MB_MEM1"] | 199 | #[unsafe(link_section = "MB_MEM1")] |
| 200 | pub static mut TL_BLE_TABLE: Aligned<A4, MaybeUninit<BleTable>> = Aligned(MaybeUninit::uninit()); | 200 | pub static mut TL_BLE_TABLE: Aligned<A4, MaybeUninit<BleTable>> = Aligned(MaybeUninit::zeroed()); |
| 201 | 201 | ||
| 202 | #[link_section = "MB_MEM1"] | 202 | #[unsafe(link_section = "MB_MEM1")] |
| 203 | pub static mut TL_THREAD_TABLE: Aligned<A4, MaybeUninit<ThreadTable>> = Aligned(MaybeUninit::uninit()); | 203 | pub static mut TL_THREAD_TABLE: Aligned<A4, MaybeUninit<ThreadTable>> = Aligned(MaybeUninit::zeroed()); |
| 204 | 204 | ||
| 205 | #[link_section = "MB_MEM1"] | 205 | #[unsafe(link_section = "MB_MEM1")] |
| 206 | pub static mut TL_LLD_TESTS_TABLE: Aligned<A4, MaybeUninit<LldTestsTable>> = Aligned(MaybeUninit::uninit()); | 206 | pub static mut TL_LLD_TESTS_TABLE: Aligned<A4, MaybeUninit<LldTestsTable>> = Aligned(MaybeUninit::zeroed()); |
| 207 | 207 | ||
| 208 | #[link_section = "MB_MEM1"] | 208 | #[unsafe(link_section = "MB_MEM1")] |
| 209 | pub static mut TL_BLE_LLD_TABLE: Aligned<A4, MaybeUninit<BleLldTable>> = Aligned(MaybeUninit::uninit()); | 209 | pub static mut TL_BLE_LLD_TABLE: Aligned<A4, MaybeUninit<BleLldTable>> = Aligned(MaybeUninit::zeroed()); |
| 210 | 210 | ||
| 211 | #[link_section = "MB_MEM1"] | 211 | #[unsafe(link_section = "MB_MEM1")] |
| 212 | pub static mut TL_SYS_TABLE: Aligned<A4, MaybeUninit<SysTable>> = Aligned(MaybeUninit::uninit()); | 212 | pub static mut TL_SYS_TABLE: Aligned<A4, MaybeUninit<SysTable>> = Aligned(MaybeUninit::zeroed()); |
| 213 | 213 | ||
| 214 | #[link_section = "MB_MEM1"] | 214 | #[unsafe(link_section = "MB_MEM1")] |
| 215 | pub static mut TL_MEM_MANAGER_TABLE: Aligned<A4, MaybeUninit<MemManagerTable>> = Aligned(MaybeUninit::uninit()); | 215 | pub static mut TL_MEM_MANAGER_TABLE: Aligned<A4, MaybeUninit<MemManagerTable>> = Aligned(MaybeUninit::zeroed()); |
| 216 | 216 | ||
| 217 | #[link_section = "MB_MEM1"] | 217 | #[unsafe(link_section = "MB_MEM1")] |
| 218 | pub static mut TL_TRACES_TABLE: Aligned<A4, MaybeUninit<TracesTable>> = Aligned(MaybeUninit::uninit()); | 218 | pub static mut TL_TRACES_TABLE: Aligned<A4, MaybeUninit<TracesTable>> = Aligned(MaybeUninit::zeroed()); |
| 219 | 219 | ||
| 220 | #[link_section = "MB_MEM1"] | 220 | #[unsafe(link_section = "MB_MEM1")] |
| 221 | pub static mut TL_MAC_802_15_4_TABLE: Aligned<A4, MaybeUninit<Mac802_15_4Table>> = Aligned(MaybeUninit::uninit()); | 221 | pub static mut TL_MAC_802_15_4_TABLE: Aligned<A4, MaybeUninit<Mac802_15_4Table>> = Aligned(MaybeUninit::zeroed()); |
| 222 | 222 | ||
| 223 | #[link_section = "MB_MEM1"] | 223 | #[unsafe(link_section = "MB_MEM1")] |
| 224 | pub static mut TL_ZIGBEE_TABLE: Aligned<A4, MaybeUninit<ZigbeeTable>> = Aligned(MaybeUninit::uninit()); | 224 | pub static mut TL_ZIGBEE_TABLE: Aligned<A4, MaybeUninit<ZigbeeTable>> = Aligned(MaybeUninit::zeroed()); |
| 225 | 225 | ||
| 226 | // --------------------- tables --------------------- | 226 | // --------------------- tables --------------------- |
| 227 | #[link_section = "MB_MEM1"] | 227 | #[unsafe(link_section = "MB_MEM1")] |
| 228 | pub static mut FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit()); | 228 | pub static mut FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::zeroed()); |
| 229 | 229 | ||
| 230 | #[allow(dead_code)] | 230 | #[allow(dead_code)] |
| 231 | #[link_section = "MB_MEM1"] | 231 | #[unsafe(link_section = "MB_MEM1")] |
| 232 | pub static mut TRACES_EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit()); | 232 | pub static mut TRACES_EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::zeroed()); |
| 233 | 233 | ||
| 234 | #[link_section = "MB_MEM2"] | 234 | #[unsafe(link_section = "MB_MEM2")] |
| 235 | pub static mut CS_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]>> = | 235 | pub static mut CS_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]>> = |
| 236 | Aligned(MaybeUninit::uninit()); | 236 | Aligned(MaybeUninit::zeroed()); |
| 237 | 237 | ||
| 238 | #[link_section = "MB_MEM2"] | 238 | #[unsafe(link_section = "MB_MEM2")] |
| 239 | pub static mut EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit()); | 239 | pub static mut EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::zeroed()); |
| 240 | 240 | ||
| 241 | #[link_section = "MB_MEM2"] | 241 | #[unsafe(link_section = "MB_MEM2")] |
| 242 | pub static mut SYSTEM_EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit()); | 242 | pub static mut SYSTEM_EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::zeroed()); |
| 243 | 243 | ||
| 244 | // --------------------- app tables --------------------- | 244 | // --------------------- app tables --------------------- |
| 245 | #[cfg(feature = "mac")] | 245 | #[cfg(feature = "wb55_mac")] |
| 246 | #[link_section = "MB_MEM2"] | 246 | #[unsafe(link_section = "MB_MEM2")] |
| 247 | pub static mut MAC_802_15_4_CMD_BUFFER: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::uninit()); | 247 | pub static mut MAC_802_15_4_CMD_BUFFER: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::zeroed()); |
| 248 | 248 | ||
| 249 | #[cfg(feature = "mac")] | 249 | #[cfg(feature = "wb55_mac")] |
| 250 | #[link_section = "MB_MEM2"] | 250 | #[unsafe(link_section = "MB_MEM2")] |
| 251 | pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit< | 251 | pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit< |
| 252 | Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>, | 252 | Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>, |
| 253 | > = MaybeUninit::uninit(); | 253 | > = MaybeUninit::zeroed(); |
| 254 | 254 | ||
| 255 | #[link_section = "MB_MEM2"] | 255 | #[unsafe(link_section = "MB_MEM2")] |
| 256 | pub static mut EVT_POOL: Aligned<A4, MaybeUninit<[u8; POOL_SIZE]>> = Aligned(MaybeUninit::uninit()); | 256 | pub static mut EVT_POOL: Aligned<A4, MaybeUninit<[u8; POOL_SIZE]>> = Aligned(MaybeUninit::zeroed()); |
| 257 | 257 | ||
| 258 | #[link_section = "MB_MEM2"] | 258 | #[unsafe(link_section = "MB_MEM2")] |
| 259 | pub static mut SYS_CMD_BUF: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::uninit()); | 259 | pub static mut SYS_CMD_BUF: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::zeroed()); |
| 260 | 260 | ||
| 261 | #[link_section = "MB_MEM2"] | 261 | #[unsafe(link_section = "MB_MEM2")] |
| 262 | pub static mut SYS_SPARE_EVT_BUF: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> = | 262 | pub static mut SYS_SPARE_EVT_BUF: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> = |
| 263 | Aligned(MaybeUninit::uninit()); | 263 | Aligned(MaybeUninit::zeroed()); |
| 264 | 264 | ||
| 265 | #[cfg(feature = "mac")] | 265 | #[cfg(feature = "wb55_mac")] |
| 266 | #[link_section = "MB_MEM2"] | 266 | #[unsafe(link_section = "MB_MEM2")] |
| 267 | pub static mut MAC_802_15_4_CNFINDNOT: Aligned<A4, MaybeUninit<[u8; C_SIZE_CMD_STRING]>> = | 267 | pub static mut MAC_802_15_4_CNFINDNOT: Aligned<A4, MaybeUninit<[u8; C_SIZE_CMD_STRING]>> = |
| 268 | Aligned(MaybeUninit::uninit()); | 268 | Aligned(MaybeUninit::zeroed()); |
| 269 | 269 | ||
| 270 | #[cfg(feature = "ble")] | 270 | #[cfg(feature = "wb55_ble")] |
| 271 | #[link_section = "MB_MEM1"] | 271 | #[unsafe(link_section = "MB_MEM1")] |
| 272 | pub static mut BLE_CMD_BUFFER: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::uninit()); | 272 | pub static mut BLE_CMD_BUFFER: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::zeroed()); |
| 273 | 273 | ||
| 274 | #[cfg(feature = "ble")] | 274 | #[cfg(feature = "wb55_ble")] |
| 275 | #[link_section = "MB_MEM2"] | 275 | #[unsafe(link_section = "MB_MEM2")] |
| 276 | pub static mut BLE_SPARE_EVT_BUF: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> = | 276 | pub static mut BLE_SPARE_EVT_BUF: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> = |
| 277 | Aligned(MaybeUninit::uninit()); | 277 | Aligned(MaybeUninit::zeroed()); |
| 278 | 278 | ||
| 279 | #[cfg(feature = "ble")] | 279 | #[cfg(feature = "wb55_ble")] |
| 280 | #[link_section = "MB_MEM2"] | 280 | #[unsafe(link_section = "MB_MEM2")] |
| 281 | // fuck these "magic" numbers from ST ---v---v | 281 | // fuck these "magic" numbers from ST ---v---v |
| 282 | pub static mut HCI_ACL_DATA_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]>> = | 282 | pub static mut HCI_ACL_DATA_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]>> = |
| 283 | Aligned(MaybeUninit::uninit()); | 283 | Aligned(MaybeUninit::zeroed()); |
diff --git a/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs b/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs new file mode 100644 index 000000000..c84ee1bb6 --- /dev/null +++ b/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs | |||
| @@ -0,0 +1,269 @@ | |||
| 1 | //! Unsafe linked list. | ||
| 2 | //! Translated from ST's C by `c2rust` tool. | ||
| 3 | |||
| 4 | #![allow( | ||
| 5 | dead_code, | ||
| 6 | mutable_transmutes, | ||
| 7 | non_camel_case_types, | ||
| 8 | non_snake_case, | ||
| 9 | non_upper_case_globals, | ||
| 10 | unused_assignments, | ||
| 11 | unused_mut | ||
| 12 | )] | ||
| 13 | |||
| 14 | use core::fmt::Debug; | ||
| 15 | use core::ptr; | ||
| 16 | |||
| 17 | use critical_section::CriticalSection; | ||
| 18 | |||
| 19 | #[derive(Copy, Clone)] | ||
| 20 | #[repr(C, packed(4))] | ||
| 21 | pub struct LinkedListNode { | ||
| 22 | pub next: *mut LinkedListNode, | ||
| 23 | pub prev: *mut LinkedListNode, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl Default for LinkedListNode { | ||
| 27 | fn default() -> Self { | ||
| 28 | LinkedListNode { | ||
| 29 | next: core::ptr::null_mut(), | ||
| 30 | prev: core::ptr::null_mut(), | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | impl LinkedListNode { | ||
| 36 | pub unsafe fn init_head(mut p_list_head: *mut LinkedListNode) { | ||
| 37 | ptr::write_volatile( | ||
| 38 | p_list_head, | ||
| 39 | LinkedListNode { | ||
| 40 | next: p_list_head, | ||
| 41 | prev: p_list_head, | ||
| 42 | }, | ||
| 43 | ); | ||
| 44 | } | ||
| 45 | |||
| 46 | pub unsafe fn is_empty(_cs: CriticalSection, mut p_list_head: *mut LinkedListNode) -> bool { | ||
| 47 | ptr::read_volatile(p_list_head).next == p_list_head | ||
| 48 | } | ||
| 49 | |||
| 50 | /// Insert `node` after `list_head` and before the next node | ||
| 51 | pub unsafe fn insert_head( | ||
| 52 | _cs: CriticalSection, | ||
| 53 | mut p_list_head: *mut LinkedListNode, | ||
| 54 | mut p_node: *mut LinkedListNode, | ||
| 55 | ) { | ||
| 56 | let mut list_head = ptr::read_volatile(p_list_head); | ||
| 57 | if p_list_head != list_head.next { | ||
| 58 | let mut node_next = ptr::read_volatile(list_head.next); | ||
| 59 | let node = LinkedListNode { | ||
| 60 | next: list_head.next, | ||
| 61 | prev: p_list_head, | ||
| 62 | }; | ||
| 63 | |||
| 64 | list_head.next = p_node; | ||
| 65 | node_next.prev = p_node; | ||
| 66 | |||
| 67 | // All nodes must be written because they will all be seen by another core | ||
| 68 | ptr::write_volatile(p_node, node); | ||
| 69 | ptr::write_volatile(node.next, node_next); | ||
| 70 | ptr::write_volatile(p_list_head, list_head); | ||
| 71 | } else { | ||
| 72 | let node = LinkedListNode { | ||
| 73 | next: list_head.next, | ||
| 74 | prev: p_list_head, | ||
| 75 | }; | ||
| 76 | |||
| 77 | list_head.next = p_node; | ||
| 78 | list_head.prev = p_node; | ||
| 79 | |||
| 80 | // All nodes must be written because they will all be seen by another core | ||
| 81 | ptr::write_volatile(p_node, node); | ||
| 82 | ptr::write_volatile(p_list_head, list_head); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | /// Insert `node` before `list_tail` and after the second-to-last node | ||
| 87 | pub unsafe fn insert_tail( | ||
| 88 | _cs: CriticalSection, | ||
| 89 | mut p_list_tail: *mut LinkedListNode, | ||
| 90 | mut p_node: *mut LinkedListNode, | ||
| 91 | ) { | ||
| 92 | let mut list_tail = ptr::read_volatile(p_list_tail); | ||
| 93 | if p_list_tail != list_tail.prev { | ||
| 94 | let mut node_prev = ptr::read_volatile(list_tail.prev); | ||
| 95 | let node = LinkedListNode { | ||
| 96 | next: p_list_tail, | ||
| 97 | prev: list_tail.prev, | ||
| 98 | }; | ||
| 99 | |||
| 100 | list_tail.prev = p_node; | ||
| 101 | node_prev.next = p_node; | ||
| 102 | |||
| 103 | // All nodes must be written because they will all be seen by another core | ||
| 104 | ptr::write_volatile(p_node, node); | ||
| 105 | ptr::write_volatile(node.prev, node_prev); | ||
| 106 | ptr::write_volatile(p_list_tail, list_tail); | ||
| 107 | } else { | ||
| 108 | let node = LinkedListNode { | ||
| 109 | next: p_list_tail, | ||
| 110 | prev: list_tail.prev, | ||
| 111 | }; | ||
| 112 | |||
| 113 | list_tail.prev = p_node; | ||
| 114 | list_tail.next = p_node; | ||
| 115 | |||
| 116 | // All nodes must be written because they will all be seen by another core | ||
| 117 | ptr::write_volatile(p_node, node); | ||
| 118 | ptr::write_volatile(p_list_tail, list_tail); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | /// Remove `node` from the linked list | ||
| 123 | pub unsafe fn remove_node(_cs: CriticalSection, mut p_node: *mut LinkedListNode) { | ||
| 124 | let node = ptr::read_unaligned(p_node); | ||
| 125 | |||
| 126 | if node.next != node.prev { | ||
| 127 | let mut node_next = ptr::read_volatile(node.next); | ||
| 128 | let mut node_prev = ptr::read_volatile(node.prev); | ||
| 129 | |||
| 130 | node_prev.next = node.next; | ||
| 131 | node_next.prev = node.prev; | ||
| 132 | |||
| 133 | ptr::write_volatile(node.next, node_next); | ||
| 134 | ptr::write_volatile(node.prev, node_prev); | ||
| 135 | } else { | ||
| 136 | let mut node_next = ptr::read_volatile(node.next); | ||
| 137 | |||
| 138 | node_next.next = node.next; | ||
| 139 | node_next.prev = node.prev; | ||
| 140 | |||
| 141 | ptr::write_volatile(node.next, node_next); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | /// Remove `list_head` and return a pointer to the `node`. | ||
| 146 | pub unsafe fn remove_head( | ||
| 147 | _cs: CriticalSection, | ||
| 148 | mut p_list_head: *mut LinkedListNode, | ||
| 149 | ) -> Option<*mut LinkedListNode> { | ||
| 150 | let list_head = ptr::read_volatile(p_list_head); | ||
| 151 | |||
| 152 | if list_head.next == p_list_head { | ||
| 153 | None | ||
| 154 | } else { | ||
| 155 | // Allowed because a removed node is not seen by another core | ||
| 156 | let p_node = list_head.next; | ||
| 157 | Self::remove_node(_cs, p_node); | ||
| 158 | |||
| 159 | Some(p_node) | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Remove `list_tail` and return a pointer to the `node`. | ||
| 164 | pub unsafe fn remove_tail( | ||
| 165 | _cs: CriticalSection, | ||
| 166 | mut p_list_tail: *mut LinkedListNode, | ||
| 167 | ) -> Option<*mut LinkedListNode> { | ||
| 168 | let list_tail = ptr::read_volatile(p_list_tail); | ||
| 169 | |||
| 170 | if list_tail.prev == p_list_tail { | ||
| 171 | None | ||
| 172 | } else { | ||
| 173 | // Allowed because a removed node is not seen by another core | ||
| 174 | let p_node = list_tail.prev; | ||
| 175 | Self::remove_node(_cs, p_node); | ||
| 176 | |||
| 177 | Some(p_node) | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | pub unsafe fn insert_node_after( | ||
| 182 | _cs: CriticalSection, | ||
| 183 | mut p_node: *mut LinkedListNode, | ||
| 184 | mut p_ref_node: *mut LinkedListNode, | ||
| 185 | ) { | ||
| 186 | let mut node = ptr::read_volatile(p_node); | ||
| 187 | let mut ref_node = ptr::read_volatile(p_ref_node); | ||
| 188 | let mut prev_node = ptr::read_volatile(ref_node.next); | ||
| 189 | |||
| 190 | node.next = ref_node.next; | ||
| 191 | node.prev = p_ref_node; | ||
| 192 | ref_node.next = p_node; | ||
| 193 | prev_node.prev = p_node; | ||
| 194 | |||
| 195 | ptr::write_volatile(p_node, node); | ||
| 196 | ptr::write_volatile(p_ref_node, ref_node); | ||
| 197 | ptr::write_volatile(node.next, prev_node); | ||
| 198 | } | ||
| 199 | |||
| 200 | pub unsafe fn insert_node_before( | ||
| 201 | _cs: CriticalSection, | ||
| 202 | mut node: *mut LinkedListNode, | ||
| 203 | mut ref_node: *mut LinkedListNode, | ||
| 204 | ) { | ||
| 205 | (*node).next = ref_node; | ||
| 206 | (*node).prev = (*ref_node).prev; | ||
| 207 | (*ref_node).prev = node; | ||
| 208 | (*(*node).prev).next = node; | ||
| 209 | |||
| 210 | todo!("this function has not been converted to volatile semantics"); | ||
| 211 | } | ||
| 212 | |||
| 213 | pub unsafe fn get_size(_cs: CriticalSection, mut list_head: *mut LinkedListNode) -> usize { | ||
| 214 | let mut size = 0; | ||
| 215 | let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>(); | ||
| 216 | |||
| 217 | temp = (*list_head).next; | ||
| 218 | while temp != list_head { | ||
| 219 | size += 1; | ||
| 220 | temp = (*temp).next | ||
| 221 | } | ||
| 222 | |||
| 223 | let _ = size; | ||
| 224 | |||
| 225 | todo!("this function has not been converted to volatile semantics"); | ||
| 226 | } | ||
| 227 | |||
| 228 | pub unsafe fn get_next_node(_cs: CriticalSection, mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { | ||
| 229 | let ref_node = ptr::read_volatile(p_ref_node); | ||
| 230 | |||
| 231 | // Allowed because a removed node is not seen by another core | ||
| 232 | ref_node.next | ||
| 233 | } | ||
| 234 | |||
| 235 | pub unsafe fn get_prev_node(_cs: CriticalSection, mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { | ||
| 236 | let ref_node = ptr::read_volatile(p_ref_node); | ||
| 237 | |||
| 238 | // Allowed because a removed node is not seen by another core | ||
| 239 | ref_node.prev | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | pub struct DebuggableLinkedListNode(*const LinkedListNode); | ||
| 244 | |||
| 245 | impl Debug for DebuggableLinkedListNode { | ||
| 246 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 247 | // Safe because this is just reading memory, and using unaligned to do it | ||
| 248 | let p_node = self.0; | ||
| 249 | |||
| 250 | f.write_fmt(format_args!("iterating list from node: {:x}", p_node as usize))?; | ||
| 251 | |||
| 252 | let mut p_current_node = p_node; | ||
| 253 | for _ in 0..30 { | ||
| 254 | let current_node = unsafe { ptr::read_unaligned(p_current_node) }; | ||
| 255 | f.write_fmt(format_args!( | ||
| 256 | "node (prev, current, next): {:x}, {:x}, {:x}", | ||
| 257 | current_node.prev as usize, p_current_node as usize, current_node.next as usize | ||
| 258 | ))?; | ||
| 259 | |||
| 260 | if current_node.next == p_node as *mut _ { | ||
| 261 | break; | ||
| 262 | } | ||
| 263 | |||
| 264 | p_current_node = current_node.next; | ||
| 265 | } | ||
| 266 | |||
| 267 | Ok(()) | ||
| 268 | } | ||
| 269 | } | ||
diff --git a/embassy-stm32-wpan/src/wba/bindings.rs b/embassy-stm32-wpan/src/wba/bindings.rs new file mode 100644 index 000000000..d2030cfb8 --- /dev/null +++ b/embassy-stm32-wpan/src/wba/bindings.rs | |||
| @@ -0,0 +1 @@ | |||
| pub use stm32_bindings::bindings::{mac, wba_ble_stack as ble, wba_link_layer as link_layer}; | |||
diff --git a/embassy-stm32-wpan/src/wba/linklayer_plat.rs b/embassy-stm32-wpan/src/wba/linklayer_plat.rs new file mode 100644 index 000000000..108e84efe --- /dev/null +++ b/embassy-stm32-wpan/src/wba/linklayer_plat.rs | |||
| @@ -0,0 +1,913 @@ | |||
| 1 | // /* USER CODE BEGIN Header */ | ||
| 2 | // /** | ||
| 3 | // ****************************************************************************** | ||
| 4 | // * @file linklayer_plat.c | ||
| 5 | // * @author MCD Application Team | ||
| 6 | // * @brief Source file for the linklayer plateform adaptation layer | ||
| 7 | // ****************************************************************************** | ||
| 8 | // * @attention | ||
| 9 | // * | ||
| 10 | // * Copyright (c) 2024 STMicroelectronics. | ||
| 11 | // * All rights reserved. | ||
| 12 | // * | ||
| 13 | // * This software is licensed under terms that can be found in the LICENSE file | ||
| 14 | // * in the root directory of this software component. | ||
| 15 | // * If no LICENSE file comes with this software, it is provided AS-IS. | ||
| 16 | // * | ||
| 17 | // ****************************************************************************** | ||
| 18 | // */ | ||
| 19 | // /* USER CODE END Header */ | ||
| 20 | // | ||
| 21 | // #include "stm32wbaxx_hal.h" | ||
| 22 | // #include "stm32wbaxx_hal_conf.h" | ||
| 23 | // #include "stm32wbaxx_ll_rcc.h" | ||
| 24 | // | ||
| 25 | // #include "app_common.h" | ||
| 26 | // #include "app_conf.h" | ||
| 27 | // #include "linklayer_plat.h" | ||
| 28 | // #include "scm.h" | ||
| 29 | // #include "log_module.h" | ||
| 30 | // #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) | ||
| 31 | // #include "adc_ctrl.h" | ||
| 32 | // #endif /* (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) */ | ||
| 33 | // | ||
| 34 | // #if (CFG_LPM_LEVEL != 0) | ||
| 35 | // #include "stm32_lpm.h" | ||
| 36 | // #include "stm32_lpm_if.h" | ||
| 37 | // #endif /* (CFG_LPM_LEVEL != 0) */ | ||
| 38 | // | ||
| 39 | // /* USER CODE BEGIN Includes */ | ||
| 40 | // | ||
| 41 | // /* USER CODE END Includes */ | ||
| 42 | // | ||
| 43 | // #define max(a,b) ((a) > (b) ? a : b) | ||
| 44 | // | ||
| 45 | // /* 2.4GHz RADIO ISR callbacks */ | ||
| 46 | // void (*radio_callback)(void) = NULL; | ||
| 47 | // void (*low_isr_callback)(void) = NULL; | ||
| 48 | // | ||
| 49 | // /* RNG handle */ | ||
| 50 | // extern RNG_HandleTypeDef hrng; | ||
| 51 | // | ||
| 52 | // #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) | ||
| 53 | // /* Link Layer temperature request from background */ | ||
| 54 | // extern void ll_sys_bg_temperature_measurement(void); | ||
| 55 | // #endif /* (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) */ | ||
| 56 | // | ||
| 57 | // /* Radio critical sections */ | ||
| 58 | // static uint32_t primask_bit = 0; | ||
| 59 | // volatile int32_t prio_high_isr_counter = 0; | ||
| 60 | // volatile int32_t prio_low_isr_counter = 0; | ||
| 61 | // volatile int32_t prio_sys_isr_counter = 0; | ||
| 62 | // volatile int32_t irq_counter = 0; | ||
| 63 | // volatile uint32_t local_basepri_value = 0; | ||
| 64 | // | ||
| 65 | // /* Radio SW low ISR global variable */ | ||
| 66 | // volatile uint8_t radio_sw_low_isr_is_running_high_prio = 0; | ||
| 67 | // | ||
| 68 | // /* Radio bus clock control variables */ | ||
| 69 | // uint8_t AHB5_SwitchedOff = 0; | ||
| 70 | // uint32_t radio_sleep_timer_val = 0; | ||
| 71 | // | ||
| 72 | // /* USER CODE BEGIN LINKLAYER_PLAT 0 */ | ||
| 73 | // | ||
| 74 | // /* USER CODE END LINKLAYER_PLAT 0 */ | ||
| 75 | #![cfg(feature = "wba")] | ||
| 76 | #![allow(clippy::missing_safety_doc)] | ||
| 77 | |||
| 78 | use core::hint::spin_loop; | ||
| 79 | use core::ptr; | ||
| 80 | use core::sync::atomic::{AtomicBool, AtomicI32, AtomicPtr, AtomicU32, Ordering}; | ||
| 81 | |||
| 82 | use cortex_m::asm::{dsb, isb}; | ||
| 83 | use cortex_m::interrupt::InterruptNumber; | ||
| 84 | use cortex_m::peripheral::NVIC; | ||
| 85 | use cortex_m::register::basepri; | ||
| 86 | use critical_section; | ||
| 87 | #[cfg(feature = "defmt")] | ||
| 88 | use defmt::trace; | ||
| 89 | use embassy_stm32::NVIC_PRIO_BITS; | ||
| 90 | use embassy_time::{Duration, block_for}; | ||
| 91 | |||
| 92 | use super::bindings::{link_layer, mac}; | ||
| 93 | |||
| 94 | // Missing constant from stm32-bindings - RADIO_SW_LOW interrupt number | ||
| 95 | // For STM32WBA, this is typically RADIO_IRQ_BUSY (interrupt 43) | ||
| 96 | const RADIO_SW_LOW_INTR_NUM: u32 = 43; | ||
| 97 | |||
| 98 | type Callback = unsafe extern "C" fn(); | ||
| 99 | |||
| 100 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | ||
| 101 | #[repr(transparent)] | ||
| 102 | struct RawInterrupt(u16); | ||
| 103 | |||
| 104 | impl RawInterrupt { | ||
| 105 | #[inline(always)] | ||
| 106 | fn new(irq: u32) -> Self { | ||
| 107 | debug_assert!(irq <= u16::MAX as u32); | ||
| 108 | Self(irq as u16) | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | impl From<u32> for RawInterrupt { | ||
| 113 | #[inline(always)] | ||
| 114 | fn from(value: u32) -> Self { | ||
| 115 | Self::new(value) | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | unsafe impl InterruptNumber for RawInterrupt { | ||
| 120 | fn number(self) -> u16 { | ||
| 121 | self.0 | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | static RADIO_CALLBACK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); | ||
| 126 | static LOW_ISR_CALLBACK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); | ||
| 127 | |||
| 128 | static IRQ_COUNTER: AtomicI32 = AtomicI32::new(0); | ||
| 129 | |||
| 130 | static PRIO_HIGH_ISR_COUNTER: AtomicI32 = AtomicI32::new(0); | ||
| 131 | static PRIO_LOW_ISR_COUNTER: AtomicI32 = AtomicI32::new(0); | ||
| 132 | static PRIO_SYS_ISR_COUNTER: AtomicI32 = AtomicI32::new(0); | ||
| 133 | static LOCAL_BASEPRI_VALUE: AtomicU32 = AtomicU32::new(0); | ||
| 134 | |||
| 135 | static RADIO_SW_LOW_ISR_RUNNING_HIGH_PRIO: AtomicBool = AtomicBool::new(false); | ||
| 136 | static AHB5_SWITCHED_OFF: AtomicBool = AtomicBool::new(false); | ||
| 137 | static RADIO_SLEEP_TIMER_VAL: AtomicU32 = AtomicU32::new(0); | ||
| 138 | |||
| 139 | static PRNG_STATE: AtomicU32 = AtomicU32::new(0); | ||
| 140 | static PRNG_INIT: AtomicBool = AtomicBool::new(false); | ||
| 141 | |||
| 142 | // Critical-section restore token for IRQ enable/disable pairing. | ||
| 143 | // Only written when the IRQ disable counter transitions 0->1, and consumed when it transitions 1->0. | ||
| 144 | static mut CS_RESTORE_STATE: Option<critical_section::RestoreState> = None; | ||
| 145 | |||
| 146 | unsafe extern "C" { | ||
| 147 | static SystemCoreClock: u32; | ||
| 148 | } | ||
| 149 | |||
| 150 | #[inline(always)] | ||
| 151 | fn read_system_core_clock() -> u32 { | ||
| 152 | unsafe { ptr::read_volatile(&SystemCoreClock) } | ||
| 153 | } | ||
| 154 | |||
| 155 | #[inline(always)] | ||
| 156 | fn store_callback(slot: &AtomicPtr<()>, cb: Option<Callback>) { | ||
| 157 | let ptr = cb.map_or(ptr::null_mut(), |f| f as *mut ()); | ||
| 158 | slot.store(ptr, Ordering::Release); | ||
| 159 | } | ||
| 160 | |||
| 161 | #[inline(always)] | ||
| 162 | fn load_callback(slot: &AtomicPtr<()>) -> Option<Callback> { | ||
| 163 | let ptr = slot.load(Ordering::Acquire); | ||
| 164 | if ptr.is_null() { | ||
| 165 | None | ||
| 166 | } else { | ||
| 167 | Some(unsafe { core::mem::transmute::<*mut (), Callback>(ptr) }) | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | #[inline(always)] | ||
| 172 | fn priority_shift() -> u8 { | ||
| 173 | 8 - NVIC_PRIO_BITS as u8 | ||
| 174 | } | ||
| 175 | |||
| 176 | fn pack_priority(raw: u32) -> u8 { | ||
| 177 | let shift = priority_shift(); | ||
| 178 | let priority_bits = NVIC_PRIO_BITS as u32; | ||
| 179 | let mask = if priority_bits >= 32 { | ||
| 180 | u32::MAX | ||
| 181 | } else { | ||
| 182 | (1u32 << priority_bits) - 1 | ||
| 183 | }; | ||
| 184 | let clamped = raw & mask; | ||
| 185 | (clamped << u32::from(shift)) as u8 | ||
| 186 | } | ||
| 187 | |||
| 188 | #[inline(always)] | ||
| 189 | fn counter_release(counter: &AtomicI32) -> bool { | ||
| 190 | counter.fetch_sub(1, Ordering::SeqCst) <= 1 | ||
| 191 | } | ||
| 192 | |||
| 193 | #[inline(always)] | ||
| 194 | fn counter_acquire(counter: &AtomicI32) -> bool { | ||
| 195 | counter.fetch_add(1, Ordering::SeqCst) == 0 | ||
| 196 | } | ||
| 197 | |||
| 198 | unsafe fn nvic_enable(irq: u32) { | ||
| 199 | NVIC::unmask(RawInterrupt::new(irq)); | ||
| 200 | dsb(); | ||
| 201 | isb(); | ||
| 202 | } | ||
| 203 | |||
| 204 | unsafe fn nvic_disable(irq: u32) { | ||
| 205 | NVIC::mask(RawInterrupt::new(irq)); | ||
| 206 | dsb(); | ||
| 207 | isb(); | ||
| 208 | } | ||
| 209 | |||
| 210 | unsafe fn nvic_set_pending(irq: u32) { | ||
| 211 | NVIC::pend(RawInterrupt::new(irq)); | ||
| 212 | dsb(); | ||
| 213 | isb(); | ||
| 214 | } | ||
| 215 | |||
| 216 | unsafe fn nvic_get_active(irq: u32) -> bool { | ||
| 217 | NVIC::is_active(RawInterrupt::new(irq)) | ||
| 218 | } | ||
| 219 | |||
| 220 | unsafe fn nvic_set_priority(irq: u32, priority: u8) { | ||
| 221 | // STM32WBA is ARMv8-M, which uses byte-accessible IPR registers | ||
| 222 | let nvic = &*NVIC::PTR; | ||
| 223 | nvic.ipr[irq as usize].write(priority); | ||
| 224 | |||
| 225 | dsb(); | ||
| 226 | isb(); | ||
| 227 | } | ||
| 228 | |||
| 229 | #[inline(always)] | ||
| 230 | fn set_basepri_max(value: u8) { | ||
| 231 | unsafe { | ||
| 232 | if basepri::read() < value { | ||
| 233 | basepri::write(value); | ||
| 234 | } | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | fn prng_next() -> u32 { | ||
| 239 | #[inline] | ||
| 240 | fn xorshift(mut x: u32) -> u32 { | ||
| 241 | x ^= x << 13; | ||
| 242 | x ^= x >> 17; | ||
| 243 | x ^= x << 5; | ||
| 244 | x | ||
| 245 | } | ||
| 246 | |||
| 247 | if !PRNG_INIT.load(Ordering::Acquire) { | ||
| 248 | let seed = unsafe { | ||
| 249 | let timer = link_layer::ll_intf_cmn_get_slptmr_value(); | ||
| 250 | let core_clock = read_system_core_clock(); | ||
| 251 | timer ^ core_clock ^ 0x6C8E_9CF5 | ||
| 252 | }; | ||
| 253 | PRNG_STATE.store(seed, Ordering::Relaxed); | ||
| 254 | PRNG_INIT.store(true, Ordering::Release); | ||
| 255 | } | ||
| 256 | |||
| 257 | let mut current = PRNG_STATE.load(Ordering::Relaxed); | ||
| 258 | loop { | ||
| 259 | let next = xorshift(current); | ||
| 260 | match PRNG_STATE.compare_exchange_weak(current, next, Ordering::AcqRel, Ordering::Relaxed) { | ||
| 261 | Ok(_) => return next, | ||
| 262 | Err(v) => current = v, | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | pub unsafe fn run_radio_high_isr() { | ||
| 268 | if let Some(cb) = load_callback(&RADIO_CALLBACK) { | ||
| 269 | cb(); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | pub unsafe fn run_radio_sw_low_isr() { | ||
| 274 | if let Some(cb) = load_callback(&LOW_ISR_CALLBACK) { | ||
| 275 | cb(); | ||
| 276 | } | ||
| 277 | |||
| 278 | if RADIO_SW_LOW_ISR_RUNNING_HIGH_PRIO.swap(false, Ordering::AcqRel) { | ||
| 279 | nvic_set_priority(RADIO_SW_LOW_INTR_NUM, pack_priority(mac::RADIO_SW_LOW_INTR_PRIO)); | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | // /** | ||
| 284 | // * @brief Configure the necessary clock sources for the radio. | ||
| 285 | // * @param None | ||
| 286 | // * @retval None | ||
| 287 | // */ | ||
| 288 | #[unsafe(no_mangle)] | ||
| 289 | pub unsafe extern "C" fn LINKLAYER_PLAT_ClockInit() { | ||
| 290 | // uint32_t linklayer_slp_clk_src = LL_RCC_RADIOSLEEPSOURCE_NONE; | ||
| 291 | // | ||
| 292 | // /* Get the Link Layer sleep timer clock source */ | ||
| 293 | // linklayer_slp_clk_src = LL_RCC_RADIO_GetSleepTimerClockSource(); | ||
| 294 | // if(linklayer_slp_clk_src == LL_RCC_RADIOSLEEPSOURCE_NONE) | ||
| 295 | // { | ||
| 296 | // /* If there is no clock source defined, should be selected before */ | ||
| 297 | // assert_param(0); | ||
| 298 | // } | ||
| 299 | // | ||
| 300 | // /* Enable AHB5ENR peripheral clock (bus CLK) */ | ||
| 301 | // __HAL_RCC_RADIO_CLK_ENABLE(); | ||
| 302 | trace!("LINKLAYER_PLAT_ClockInit: get_slptmr_value"); | ||
| 303 | let _ = link_layer::ll_intf_cmn_get_slptmr_value(); | ||
| 304 | } | ||
| 305 | |||
| 306 | // /** | ||
| 307 | // * @brief Link Layer active waiting loop. | ||
| 308 | // * @param delay: delay in us | ||
| 309 | // * @retval None | ||
| 310 | // */ | ||
| 311 | #[unsafe(no_mangle)] | ||
| 312 | pub unsafe extern "C" fn LINKLAYER_PLAT_DelayUs(delay: u32) { | ||
| 313 | // static uint8_t lock = 0; | ||
| 314 | // uint32_t t0; | ||
| 315 | // uint32_t primask_bit; | ||
| 316 | // | ||
| 317 | // /* Enter critical section */ | ||
| 318 | // primask_bit= __get_PRIMASK(); | ||
| 319 | // __disable_irq(); | ||
| 320 | // | ||
| 321 | // if (lock == 0U) | ||
| 322 | // { | ||
| 323 | // /* Initialize counter */ | ||
| 324 | // /* Reset cycle counter to prevent overflow | ||
| 325 | // As a us counter, it is assumed than even with re-entrancy, | ||
| 326 | // overflow will never happen before re-initializing this counter */ | ||
| 327 | // DWT->CYCCNT = 0U; | ||
| 328 | // /* Enable DWT by safety but should be useless (as already set) */ | ||
| 329 | // SET_BIT(DCB->DEMCR, DCB_DEMCR_TRCENA_Msk); | ||
| 330 | // /* Enable counter */ | ||
| 331 | // SET_BIT(DWT->CTRL, DWT_CTRL_CYCCNTENA_Msk); | ||
| 332 | // } | ||
| 333 | // /* Increment 're-entrance' counter */ | ||
| 334 | // lock++; | ||
| 335 | // /* Get starting time stamp */ | ||
| 336 | // t0 = DWT->CYCCNT; | ||
| 337 | // /* Exit critical section */ | ||
| 338 | // __set_PRIMASK(primask_bit); | ||
| 339 | // | ||
| 340 | // /* Turn us into cycles */ | ||
| 341 | // delay = delay * (SystemCoreClock / 1000000U); | ||
| 342 | // delay += t0; | ||
| 343 | // | ||
| 344 | // /* Busy waiting loop */ | ||
| 345 | // while (DWT->CYCCNT < delay) | ||
| 346 | // { | ||
| 347 | // }; | ||
| 348 | // | ||
| 349 | // /* Enter critical section */ | ||
| 350 | // primask_bit= __get_PRIMASK(); | ||
| 351 | // __disable_irq(); | ||
| 352 | // if (lock == 1U) | ||
| 353 | // { | ||
| 354 | // /* Disable counter */ | ||
| 355 | // CLEAR_BIT(DWT->CTRL, DWT_CTRL_CYCCNTENA_Msk); | ||
| 356 | // } | ||
| 357 | // /* Decrement 're-entrance' counter */ | ||
| 358 | // lock--; | ||
| 359 | // /* Exit critical section */ | ||
| 360 | // __set_PRIMASK(primask_bit); | ||
| 361 | // | ||
| 362 | trace!("LINKLAYER_PLAT_DelayUs: delay={}", delay); | ||
| 363 | block_for(Duration::from_micros(u64::from(delay))); | ||
| 364 | } | ||
| 365 | |||
| 366 | // /** | ||
| 367 | // * @brief Link Layer assertion API | ||
| 368 | // * @param condition: conditional statement to be checked. | ||
| 369 | // * @retval None | ||
| 370 | // */ | ||
| 371 | #[unsafe(no_mangle)] | ||
| 372 | pub unsafe extern "C" fn LINKLAYER_PLAT_Assert(condition: u8) { | ||
| 373 | if condition == 0 { | ||
| 374 | panic!("LINKLAYER_PLAT assertion failed"); | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | // /** | ||
| 379 | // * @brief Enable/disable the Link Layer active clock (baseband clock). | ||
| 380 | // * @param enable: boolean value to enable (1) or disable (0) the clock. | ||
| 381 | // * @retval None | ||
| 382 | // */ | ||
| 383 | #[unsafe(no_mangle)] | ||
| 384 | pub unsafe extern "C" fn LINKLAYER_PLAT_WaitHclkRdy() { | ||
| 385 | trace!("LINKLAYER_PLAT_WaitHclkRdy"); | ||
| 386 | if AHB5_SWITCHED_OFF.swap(false, Ordering::AcqRel) { | ||
| 387 | let reference = RADIO_SLEEP_TIMER_VAL.load(Ordering::Acquire); | ||
| 388 | trace!("LINKLAYER_PLAT_WaitHclkRdy: reference={}", reference); | ||
| 389 | while reference == link_layer::ll_intf_cmn_get_slptmr_value() { | ||
| 390 | spin_loop(); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | // /** | ||
| 396 | // * @brief Notify the Link Layer platform layer the system will enter in WFI | ||
| 397 | // * and AHB5 clock may be turned of regarding the 2.4Ghz radio state. | ||
| 398 | // * @param None | ||
| 399 | // * @retval None | ||
| 400 | // */ | ||
| 401 | #[unsafe(no_mangle)] | ||
| 402 | pub unsafe extern "C" fn LINKLAYER_PLAT_NotifyWFIEnter() { | ||
| 403 | // /* Check if Radio state will allow the AHB5 clock to be cut */ | ||
| 404 | // | ||
| 405 | // /* AHB5 clock will be cut in the following cases: | ||
| 406 | // * - 2.4GHz radio is not in ACTIVE mode (in SLEEP or DEEPSLEEP mode). | ||
| 407 | // * - RADIOSMEN and STRADIOCLKON bits are at 0. | ||
| 408 | // */ | ||
| 409 | // if((LL_PWR_GetRadioMode() != LL_PWR_RADIO_ACTIVE_MODE) || | ||
| 410 | // ((__HAL_RCC_RADIO_IS_CLK_SLEEP_ENABLED() == 0) && (LL_RCC_RADIO_IsEnabledSleepTimerClock() == 0))) | ||
| 411 | // { | ||
| 412 | // AHB5_SwitchedOff = 1; | ||
| 413 | // } | ||
| 414 | trace!("LINKLAYER_PLAT_NotifyWFIEnter"); | ||
| 415 | AHB5_SWITCHED_OFF.store(true, Ordering::Release); | ||
| 416 | } | ||
| 417 | |||
| 418 | // /** | ||
| 419 | // * @brief Notify the Link Layer platform layer the system exited WFI and AHB5 | ||
| 420 | // * clock may be resynchronized as is may have been turned of during | ||
| 421 | // * low power mode entry. | ||
| 422 | // * @param None | ||
| 423 | // * @retval None | ||
| 424 | // */ | ||
| 425 | #[unsafe(no_mangle)] | ||
| 426 | pub unsafe extern "C" fn LINKLAYER_PLAT_NotifyWFIExit() { | ||
| 427 | trace!("LINKLAYER_PLAT_NotifyWFIExit"); | ||
| 428 | // /* Check if AHB5 clock has been turned of and needs resynchronisation */ | ||
| 429 | if AHB5_SWITCHED_OFF.load(Ordering::Acquire) { | ||
| 430 | // /* Read sleep register as earlier as possible */ | ||
| 431 | let value = link_layer::ll_intf_cmn_get_slptmr_value(); | ||
| 432 | RADIO_SLEEP_TIMER_VAL.store(value, Ordering::Release); | ||
| 433 | } | ||
| 434 | } | ||
| 435 | |||
| 436 | // /** | ||
| 437 | // * @brief Active wait on bus clock readiness. | ||
| 438 | // * @param None | ||
| 439 | // * @retval None | ||
| 440 | // */ | ||
| 441 | #[unsafe(no_mangle)] | ||
| 442 | pub unsafe extern "C" fn LINKLAYER_PLAT_AclkCtrl(_enable: u8) { | ||
| 443 | trace!("LINKLAYER_PLAT_AclkCtrl: enable={}", _enable); | ||
| 444 | if _enable != 0 { | ||
| 445 | // #if (CFG_SCM_SUPPORTED == 1) | ||
| 446 | // /* SCM HSE BEGIN */ | ||
| 447 | // /* Polling on HSE32 activation */ | ||
| 448 | // SCM_HSE_WaitUntilReady(); | ||
| 449 | // /* Enable RADIO baseband clock (active CLK) */ | ||
| 450 | // HAL_RCCEx_EnableRadioBBClock(); | ||
| 451 | // /* SCM HSE END */ | ||
| 452 | // #else | ||
| 453 | // /* Enable RADIO baseband clock (active CLK) */ | ||
| 454 | // HAL_RCCEx_EnableRadioBBClock(); | ||
| 455 | // /* Polling on HSE32 activation */ | ||
| 456 | // while ( LL_RCC_HSE_IsReady() == 0); | ||
| 457 | // #endif /* CFG_SCM_SUPPORTED */ | ||
| 458 | // NOTE: Add a proper assertion once a typed `Radio` peripheral exists in embassy-stm32 | ||
| 459 | // that exposes the baseband clock enable status via RCC. | ||
| 460 | } else { | ||
| 461 | // /* Disable RADIO baseband clock (active CLK) */ | ||
| 462 | // HAL_RCCEx_DisableRadioBBClock(); | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 466 | // /** | ||
| 467 | // * @brief Link Layer RNG request. | ||
| 468 | // * @param ptr_rnd: pointer to the variable that hosts the number. | ||
| 469 | // * @param len: number of byte of anthropy to get. | ||
| 470 | // * @retval None | ||
| 471 | // */ | ||
| 472 | #[unsafe(no_mangle)] | ||
| 473 | pub unsafe extern "C" fn LINKLAYER_PLAT_GetRNG(ptr_rnd: *mut u8, len: u32) { | ||
| 474 | // uint32_t nb_remaining_rng = len; | ||
| 475 | // uint32_t generated_rng; | ||
| 476 | // | ||
| 477 | // /* Get the requested RNGs (4 bytes by 4bytes) */ | ||
| 478 | // while(nb_remaining_rng >= 4) | ||
| 479 | // { | ||
| 480 | // generated_rng = 0; | ||
| 481 | // HW_RNG_Get(1, &generated_rng); | ||
| 482 | // memcpy((ptr_rnd+(len-nb_remaining_rng)), &generated_rng, 4); | ||
| 483 | // nb_remaining_rng -=4; | ||
| 484 | // } | ||
| 485 | // | ||
| 486 | // /* Get the remaining number of RNGs */ | ||
| 487 | // if(nb_remaining_rng>0){ | ||
| 488 | // generated_rng = 0; | ||
| 489 | // HW_RNG_Get(1, &generated_rng); | ||
| 490 | // memcpy((ptr_rnd+(len-nb_remaining_rng)), &generated_rng, nb_remaining_rng); | ||
| 491 | // } | ||
| 492 | trace!("LINKLAYER_PLAT_GetRNG: ptr_rnd={:?}, len={}", ptr_rnd, len); | ||
| 493 | if ptr_rnd.is_null() || len == 0 { | ||
| 494 | return; | ||
| 495 | } | ||
| 496 | |||
| 497 | for i in 0..len { | ||
| 498 | let byte = (prng_next() >> ((i & 3) * 8)) as u8; | ||
| 499 | ptr::write_volatile(ptr_rnd.add(i as usize), byte); | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | // /** | ||
| 504 | // * @brief Initialize Link Layer radio high priority interrupt. | ||
| 505 | // * @param intr_cb: function pointer to assign for the radio high priority ISR routine. | ||
| 506 | // * @retval None | ||
| 507 | // */ | ||
| 508 | #[unsafe(no_mangle)] | ||
| 509 | pub unsafe extern "C" fn LINKLAYER_PLAT_SetupRadioIT(intr_cb: Option<Callback>) { | ||
| 510 | trace!("LINKLAYER_PLAT_SetupRadioIT: intr_cb={:?}", intr_cb); | ||
| 511 | store_callback(&RADIO_CALLBACK, intr_cb); | ||
| 512 | |||
| 513 | if intr_cb.is_some() { | ||
| 514 | nvic_set_priority(mac::RADIO_INTR_NUM, pack_priority(mac::RADIO_INTR_PRIO_HIGH)); | ||
| 515 | nvic_enable(mac::RADIO_INTR_NUM); | ||
| 516 | } else { | ||
| 517 | nvic_disable(mac::RADIO_INTR_NUM); | ||
| 518 | } | ||
| 519 | } | ||
| 520 | |||
| 521 | // /** | ||
| 522 | // * @brief Initialize Link Layer SW low priority interrupt. | ||
| 523 | // * @param intr_cb: function pointer to assign for the SW low priority ISR routine. | ||
| 524 | // * @retval None | ||
| 525 | // */ | ||
| 526 | #[unsafe(no_mangle)] | ||
| 527 | pub unsafe extern "C" fn LINKLAYER_PLAT_SetupSwLowIT(intr_cb: Option<Callback>) { | ||
| 528 | trace!("LINKLAYER_PLAT_SetupSwLowIT: intr_cb={:?}", intr_cb); | ||
| 529 | store_callback(&LOW_ISR_CALLBACK, intr_cb); | ||
| 530 | |||
| 531 | if intr_cb.is_some() { | ||
| 532 | nvic_set_priority(RADIO_SW_LOW_INTR_NUM, pack_priority(mac::RADIO_SW_LOW_INTR_PRIO)); | ||
| 533 | nvic_enable(RADIO_SW_LOW_INTR_NUM); | ||
| 534 | } else { | ||
| 535 | nvic_disable(RADIO_SW_LOW_INTR_NUM); | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | // /** | ||
| 540 | // * @brief Trigger the link layer SW low interrupt. | ||
| 541 | // * @param None | ||
| 542 | // * @retval None | ||
| 543 | // */ | ||
| 544 | #[unsafe(no_mangle)] | ||
| 545 | pub unsafe extern "C" fn LINKLAYER_PLAT_TriggerSwLowIT(priority: u8) { | ||
| 546 | trace!("LINKLAYER_PLAT_TriggerSwLowIT: priority={}", priority); | ||
| 547 | let active = nvic_get_active(RADIO_SW_LOW_INTR_NUM); | ||
| 548 | |||
| 549 | // /* Check if a SW low interrupt as already been raised. | ||
| 550 | // * Nested call far radio low isr are not supported | ||
| 551 | // **/ | ||
| 552 | if !active { | ||
| 553 | let prio = if priority == 0 { | ||
| 554 | // /* No nested SW low ISR, default behavior */ | ||
| 555 | pack_priority(mac::RADIO_SW_LOW_INTR_PRIO) | ||
| 556 | } else { | ||
| 557 | pack_priority(mac::RADIO_INTR_PRIO_LOW) | ||
| 558 | }; | ||
| 559 | nvic_set_priority(RADIO_SW_LOW_INTR_NUM, prio); | ||
| 560 | } else if priority != 0 { | ||
| 561 | // /* Nested call detected */ | ||
| 562 | // /* No change for SW radio low interrupt priority for the moment */ | ||
| 563 | // | ||
| 564 | // if(priority != 0) | ||
| 565 | // { | ||
| 566 | // /* At the end of current SW radio low ISR, this pending SW low interrupt | ||
| 567 | // * will run with RADIO_INTR_PRIO_LOW priority | ||
| 568 | // **/ | ||
| 569 | // radio_sw_low_isr_is_running_high_prio = 1; | ||
| 570 | // } | ||
| 571 | RADIO_SW_LOW_ISR_RUNNING_HIGH_PRIO.store(true, Ordering::Release); | ||
| 572 | } | ||
| 573 | |||
| 574 | nvic_set_pending(RADIO_SW_LOW_INTR_NUM); | ||
| 575 | } | ||
| 576 | |||
| 577 | // /** | ||
| 578 | // * @brief Enable interrupts. | ||
| 579 | // * @param None | ||
| 580 | // * @retval None | ||
| 581 | // */ | ||
| 582 | #[unsafe(no_mangle)] | ||
| 583 | pub unsafe extern "C" fn LINKLAYER_PLAT_EnableIRQ() { | ||
| 584 | trace!("LINKLAYER_PLAT_EnableIRQ"); | ||
| 585 | // irq_counter = max(0,irq_counter-1); | ||
| 586 | // | ||
| 587 | // if(irq_counter == 0) | ||
| 588 | // { | ||
| 589 | // /* When irq_counter reaches 0, restore primask bit */ | ||
| 590 | // __set_PRIMASK(primask_bit); | ||
| 591 | // } | ||
| 592 | if counter_release(&IRQ_COUNTER) { | ||
| 593 | // When the counter reaches zero, restore prior interrupt state using the captured token. | ||
| 594 | if let Some(token) = CS_RESTORE_STATE.take() { | ||
| 595 | critical_section::release(token); | ||
| 596 | } | ||
| 597 | } | ||
| 598 | } | ||
| 599 | |||
| 600 | // /** | ||
| 601 | // * @brief Disable interrupts. | ||
| 602 | // * @param None | ||
| 603 | // * @retval None | ||
| 604 | // */ | ||
| 605 | #[unsafe(no_mangle)] | ||
| 606 | pub unsafe extern "C" fn LINKLAYER_PLAT_DisableIRQ() { | ||
| 607 | trace!("LINKLAYER_PLAT_DisableIRQ"); | ||
| 608 | // if(irq_counter == 0) | ||
| 609 | // { | ||
| 610 | // /* Save primask bit at first interrupt disablement */ | ||
| 611 | // primask_bit= __get_PRIMASK(); | ||
| 612 | // } | ||
| 613 | // __disable_irq(); | ||
| 614 | // irq_counter ++; | ||
| 615 | if counter_acquire(&IRQ_COUNTER) { | ||
| 616 | // Capture and disable using critical-section API on first disable. | ||
| 617 | CS_RESTORE_STATE = Some(critical_section::acquire()); | ||
| 618 | } | ||
| 619 | } | ||
| 620 | |||
| 621 | // /** | ||
| 622 | // * @brief Enable specific interrupt group. | ||
| 623 | // * @param isr_type: mask for interrupt group to enable. | ||
| 624 | // * This parameter can be one of the following: | ||
| 625 | // * @arg LL_HIGH_ISR_ONLY: enable link layer high priority ISR. | ||
| 626 | // * @arg LL_LOW_ISR_ONLY: enable link layer SW low priority ISR. | ||
| 627 | // * @arg SYS_LOW_ISR: mask interrupts for all the other system ISR with | ||
| 628 | // * lower priority that link layer SW low interrupt. | ||
| 629 | // * @retval None | ||
| 630 | // */ | ||
| 631 | #[unsafe(no_mangle)] | ||
| 632 | pub unsafe extern "C" fn LINKLAYER_PLAT_EnableSpecificIRQ(isr_type: u8) { | ||
| 633 | trace!("LINKLAYER_PLAT_EnableSpecificIRQ: isr_type={}", isr_type); | ||
| 634 | // if( (isr_type & LL_HIGH_ISR_ONLY) != 0 ) | ||
| 635 | // { | ||
| 636 | // prio_high_isr_counter--; | ||
| 637 | // if(prio_high_isr_counter == 0) | ||
| 638 | // { | ||
| 639 | // /* When specific counter for link layer high ISR reaches 0, interrupt is enabled */ | ||
| 640 | // HAL_NVIC_EnableIRQ(RADIO_INTR_NUM); | ||
| 641 | // /* USER CODE BEGIN LINKLAYER_PLAT_EnableSpecificIRQ_1 */ | ||
| 642 | // | ||
| 643 | // /* USER CODE END LINKLAYER_PLAT_EnableSpecificIRQ_1 */ | ||
| 644 | // } | ||
| 645 | // } | ||
| 646 | // | ||
| 647 | // if( (isr_type & LL_LOW_ISR_ONLY) != 0 ) | ||
| 648 | // { | ||
| 649 | // prio_low_isr_counter--; | ||
| 650 | // if(prio_low_isr_counter == 0) | ||
| 651 | // { | ||
| 652 | // /* When specific counter for link layer SW low ISR reaches 0, interrupt is enabled */ | ||
| 653 | // HAL_NVIC_EnableIRQ(RADIO_SW_LOW_INTR_NUM); | ||
| 654 | // } | ||
| 655 | // | ||
| 656 | // } | ||
| 657 | // | ||
| 658 | // if( (isr_type & SYS_LOW_ISR) != 0 ) | ||
| 659 | // { | ||
| 660 | // prio_sys_isr_counter--; | ||
| 661 | // if(prio_sys_isr_counter == 0) | ||
| 662 | // { | ||
| 663 | // /* Restore basepri value */ | ||
| 664 | // __set_BASEPRI(local_basepri_value); | ||
| 665 | // } | ||
| 666 | // } | ||
| 667 | if (isr_type & link_layer::LL_HIGH_ISR_ONLY as u8) != 0 { | ||
| 668 | if counter_release(&PRIO_HIGH_ISR_COUNTER) { | ||
| 669 | nvic_enable(mac::RADIO_INTR_NUM); | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 673 | if (isr_type & link_layer::LL_LOW_ISR_ONLY as u8) != 0 { | ||
| 674 | if counter_release(&PRIO_LOW_ISR_COUNTER) { | ||
| 675 | nvic_enable(RADIO_SW_LOW_INTR_NUM); | ||
| 676 | } | ||
| 677 | } | ||
| 678 | |||
| 679 | if (isr_type & link_layer::SYS_LOW_ISR as u8) != 0 { | ||
| 680 | if counter_release(&PRIO_SYS_ISR_COUNTER) { | ||
| 681 | let stored = LOCAL_BASEPRI_VALUE.load(Ordering::Relaxed) as u8; | ||
| 682 | basepri::write(stored); | ||
| 683 | } | ||
| 684 | } | ||
| 685 | } | ||
| 686 | |||
| 687 | // /** | ||
| 688 | // * @brief Disable specific interrupt group. | ||
| 689 | // * @param isr_type: mask for interrupt group to disable. | ||
| 690 | // * This parameter can be one of the following: | ||
| 691 | // * @arg LL_HIGH_ISR_ONLY: disable link layer high priority ISR. | ||
| 692 | // * @arg LL_LOW_ISR_ONLY: disable link layer SW low priority ISR. | ||
| 693 | // * @arg SYS_LOW_ISR: unmask interrupts for all the other system ISR with | ||
| 694 | // * lower priority that link layer SW low interrupt. | ||
| 695 | // * @retval None | ||
| 696 | // */ | ||
| 697 | #[unsafe(no_mangle)] | ||
| 698 | pub unsafe extern "C" fn LINKLAYER_PLAT_DisableSpecificIRQ(isr_type: u8) { | ||
| 699 | // if( (isr_type & LL_HIGH_ISR_ONLY) != 0 ) | ||
| 700 | // { | ||
| 701 | // prio_high_isr_counter++; | ||
| 702 | // if(prio_high_isr_counter == 1) | ||
| 703 | // { | ||
| 704 | // /* USER CODE BEGIN LINKLAYER_PLAT_DisableSpecificIRQ_1 */ | ||
| 705 | // | ||
| 706 | // /* USER CODE END LINKLAYER_PLAT_DisableSpecificIRQ_1 */ | ||
| 707 | // /* When specific counter for link layer high ISR value is 1, interrupt is disabled */ | ||
| 708 | // HAL_NVIC_DisableIRQ(RADIO_INTR_NUM); | ||
| 709 | // } | ||
| 710 | // } | ||
| 711 | // | ||
| 712 | // if( (isr_type & LL_LOW_ISR_ONLY) != 0 ) | ||
| 713 | // { | ||
| 714 | // prio_low_isr_counter++; | ||
| 715 | // if(prio_low_isr_counter == 1) | ||
| 716 | // { | ||
| 717 | // /* When specific counter for link layer SW low ISR value is 1, interrupt is disabled */ | ||
| 718 | // HAL_NVIC_DisableIRQ(RADIO_SW_LOW_INTR_NUM); | ||
| 719 | // } | ||
| 720 | // } | ||
| 721 | // | ||
| 722 | // if( (isr_type & SYS_LOW_ISR) != 0 ) | ||
| 723 | // { | ||
| 724 | // prio_sys_isr_counter++; | ||
| 725 | // if(prio_sys_isr_counter == 1) | ||
| 726 | // { | ||
| 727 | // /* Save basepri register value */ | ||
| 728 | // local_basepri_value = __get_BASEPRI(); | ||
| 729 | // | ||
| 730 | // /* Mask all other interrupts with lower priority that link layer SW low ISR */ | ||
| 731 | // __set_BASEPRI_MAX(RADIO_INTR_PRIO_LOW<<4); | ||
| 732 | // } | ||
| 733 | // } | ||
| 734 | trace!("LINKLAYER_PLAT_DisableSpecificIRQ: isr_type={}", isr_type); | ||
| 735 | if (isr_type & link_layer::LL_HIGH_ISR_ONLY as u8) != 0 { | ||
| 736 | if counter_acquire(&PRIO_HIGH_ISR_COUNTER) { | ||
| 737 | nvic_disable(mac::RADIO_INTR_NUM); | ||
| 738 | } | ||
| 739 | } | ||
| 740 | |||
| 741 | if (isr_type & link_layer::LL_LOW_ISR_ONLY as u8) != 0 { | ||
| 742 | if counter_acquire(&PRIO_LOW_ISR_COUNTER) { | ||
| 743 | nvic_disable(RADIO_SW_LOW_INTR_NUM); | ||
| 744 | } | ||
| 745 | } | ||
| 746 | |||
| 747 | if (isr_type & link_layer::SYS_LOW_ISR as u8) != 0 { | ||
| 748 | if counter_acquire(&PRIO_SYS_ISR_COUNTER) { | ||
| 749 | let current = basepri::read(); | ||
| 750 | LOCAL_BASEPRI_VALUE.store(current.into(), Ordering::Relaxed); | ||
| 751 | set_basepri_max(pack_priority(mac::RADIO_INTR_PRIO_LOW)); | ||
| 752 | } | ||
| 753 | } | ||
| 754 | } | ||
| 755 | |||
| 756 | // /** | ||
| 757 | // * @brief Enable link layer high priority ISR only. | ||
| 758 | // * @param None | ||
| 759 | // * @retval None | ||
| 760 | // */ | ||
| 761 | #[unsafe(no_mangle)] | ||
| 762 | pub unsafe extern "C" fn LINKLAYER_PLAT_EnableRadioIT() { | ||
| 763 | trace!("LINKLAYER_PLAT_EnableRadioIT"); | ||
| 764 | nvic_enable(mac::RADIO_INTR_NUM); | ||
| 765 | } | ||
| 766 | |||
| 767 | // /** | ||
| 768 | // * @brief Disable link layer high priority ISR only. | ||
| 769 | // * @param None | ||
| 770 | // * @retval None | ||
| 771 | // */ | ||
| 772 | #[unsafe(no_mangle)] | ||
| 773 | pub unsafe extern "C" fn LINKLAYER_PLAT_DisableRadioIT() { | ||
| 774 | trace!("LINKLAYER_PLAT_DisableRadioIT"); | ||
| 775 | nvic_disable(mac::RADIO_INTR_NUM); | ||
| 776 | } | ||
| 777 | |||
| 778 | // /** | ||
| 779 | // * @brief Link Layer notification for radio activity start. | ||
| 780 | // * @param None | ||
| 781 | // * @retval None | ||
| 782 | // */ | ||
| 783 | #[unsafe(no_mangle)] | ||
| 784 | pub unsafe extern "C" fn LINKLAYER_PLAT_StartRadioEvt() { | ||
| 785 | trace!("LINKLAYER_PLAT_StartRadioEvt"); | ||
| 786 | // __HAL_RCC_RADIO_CLK_SLEEP_ENABLE(); | ||
| 787 | // NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH); | ||
| 788 | // #if (CFG_SCM_SUPPORTED == 1) | ||
| 789 | // scm_notifyradiostate(SCM_RADIO_ACTIVE); | ||
| 790 | // #endif /* CFG_SCM_SUPPORTED */ | ||
| 791 | nvic_set_priority(mac::RADIO_INTR_NUM, pack_priority(mac::RADIO_INTR_PRIO_HIGH)); | ||
| 792 | nvic_enable(mac::RADIO_INTR_NUM); | ||
| 793 | } | ||
| 794 | |||
| 795 | // /** | ||
| 796 | // * @brief Link Layer notification for radio activity end. | ||
| 797 | // * @param None | ||
| 798 | // * @retval None | ||
| 799 | // */ | ||
| 800 | #[unsafe(no_mangle)] | ||
| 801 | pub unsafe extern "C" fn LINKLAYER_PLAT_StopRadioEvt() { | ||
| 802 | trace!("LINKLAYER_PLAT_StopRadioEvt"); | ||
| 803 | // { | ||
| 804 | // __HAL_RCC_RADIO_CLK_SLEEP_DISABLE(); | ||
| 805 | // NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_LOW); | ||
| 806 | // #if (CFG_SCM_SUPPORTED == 1) | ||
| 807 | // scm_notifyradiostate(SCM_RADIO_NOT_ACTIVE); | ||
| 808 | // #endif /* CFG_SCM_SUPPORTED */ | ||
| 809 | nvic_set_priority(mac::RADIO_INTR_NUM, pack_priority(mac::RADIO_INTR_PRIO_LOW)); | ||
| 810 | } | ||
| 811 | |||
| 812 | // /** | ||
| 813 | // * @brief Link Layer notification for RCO calibration start. | ||
| 814 | // * @param None | ||
| 815 | // * @retval None | ||
| 816 | // */ | ||
| 817 | #[unsafe(no_mangle)] | ||
| 818 | pub unsafe extern "C" fn LINKLAYER_PLAT_RCOStartClbr() { | ||
| 819 | trace!("LINKLAYER_PLAT_RCOStartClbr"); | ||
| 820 | // #if (CFG_LPM_LEVEL != 0) | ||
| 821 | // PWR_DisableSleepMode(); | ||
| 822 | // /* Disabling stop mode prevents also from entering in standby */ | ||
| 823 | // UTIL_LPM_SetStopMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_DISABLE); | ||
| 824 | // #endif /* (CFG_LPM_LEVEL != 0) */ | ||
| 825 | // #if (CFG_SCM_SUPPORTED == 1) | ||
| 826 | // scm_setsystemclock(SCM_USER_LL_HW_RCO_CLBR, HSE_32MHZ); | ||
| 827 | // while (LL_PWR_IsActiveFlag_VOS() == 0); | ||
| 828 | // #endif /* (CFG_SCM_SUPPORTED == 1) */ | ||
| 829 | } | ||
| 830 | |||
| 831 | // /** | ||
| 832 | // * @brief Link Layer notification for RCO calibration end. | ||
| 833 | // * @param None | ||
| 834 | // * @retval None | ||
| 835 | // */ | ||
| 836 | #[unsafe(no_mangle)] | ||
| 837 | pub unsafe extern "C" fn LINKLAYER_PLAT_RCOStopClbr() { | ||
| 838 | trace!("LINKLAYER_PLAT_RCOStopClbr"); | ||
| 839 | // #if (CFG_LPM_LEVEL != 0) | ||
| 840 | // PWR_EnableSleepMode(); | ||
| 841 | // UTIL_LPM_SetStopMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_ENABLE); | ||
| 842 | // #endif /* (CFG_LPM_LEVEL != 0) */ | ||
| 843 | // #if (CFG_SCM_SUPPORTED == 1) | ||
| 844 | // scm_setsystemclock(SCM_USER_LL_HW_RCO_CLBR, HSE_16MHZ); | ||
| 845 | // #endif /* (CFG_SCM_SUPPORTED == 1) */ | ||
| 846 | } | ||
| 847 | |||
| 848 | // /** | ||
| 849 | // * @brief Link Layer requests temperature. | ||
| 850 | // * @param None | ||
| 851 | // * @retval None | ||
| 852 | // */ | ||
| 853 | #[unsafe(no_mangle)] | ||
| 854 | pub unsafe extern "C" fn LINKLAYER_PLAT_RequestTemperature() { | ||
| 855 | trace!("LINKLAYER_PLAT_RequestTemperature"); | ||
| 856 | // #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) | ||
| 857 | // ll_sys_bg_temperature_measurement(); | ||
| 858 | // #endif /* USE_TEMPERATURE_BASED_RADIO_CALIBRATION */ | ||
| 859 | } | ||
| 860 | |||
| 861 | // /** | ||
| 862 | // * @brief PHY Start calibration. | ||
| 863 | // * @param None | ||
| 864 | // * @retval None | ||
| 865 | // */ | ||
| 866 | #[unsafe(no_mangle)] | ||
| 867 | pub unsafe extern "C" fn LINKLAYER_PLAT_PhyStartClbr() { | ||
| 868 | trace!("LINKLAYER_PLAT_PhyStartClbr"); | ||
| 869 | } | ||
| 870 | |||
| 871 | // /** | ||
| 872 | // * @brief PHY Stop calibration. | ||
| 873 | // * @param None | ||
| 874 | // * @retval None | ||
| 875 | // */ | ||
| 876 | #[unsafe(no_mangle)] | ||
| 877 | pub unsafe extern "C" fn LINKLAYER_PLAT_PhyStopClbr() { | ||
| 878 | trace!("LINKLAYER_PLAT_PhyStopClbr"); | ||
| 879 | } | ||
| 880 | |||
| 881 | // /** | ||
| 882 | // * @brief Notify the upper layer that new Link Layer timings have been applied. | ||
| 883 | // * @param evnt_timing[in]: Evnt_timing_t pointer to structure contains drift time , execution time and scheduling time | ||
| 884 | // * @retval None. | ||
| 885 | // */ | ||
| 886 | #[unsafe(no_mangle)] | ||
| 887 | pub unsafe extern "C" fn LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(_timings: *const link_layer::Evnt_timing_t) { | ||
| 888 | trace!("LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT: timings={:?}", _timings); | ||
| 889 | } | ||
| 890 | |||
| 891 | // /** | ||
| 892 | // * @brief Get the ST company ID. | ||
| 893 | // * @param None | ||
| 894 | // * @retval Company ID | ||
| 895 | // */ | ||
| 896 | #[unsafe(no_mangle)] | ||
| 897 | pub unsafe extern "C" fn LINKLAYER_PLAT_GetSTCompanyID() -> u32 { | ||
| 898 | // STMicroelectronics Bluetooth SIG Company Identifier | ||
| 899 | // TODO: Pull in update from latest stm32-generated-data | ||
| 900 | 0x0030 | ||
| 901 | } | ||
| 902 | |||
| 903 | // /** | ||
| 904 | // * @brief Get the Unique Device Number (UDN). | ||
| 905 | // * @param None | ||
| 906 | // * @retval UDN | ||
| 907 | // */ | ||
| 908 | #[unsafe(no_mangle)] | ||
| 909 | pub unsafe extern "C" fn LINKLAYER_PLAT_GetUDN() -> u32 { | ||
| 910 | // Read the first 32 bits of the STM32 unique 96-bit ID | ||
| 911 | let uid = embassy_stm32::uid::uid(); | ||
| 912 | u32::from_le_bytes([uid[0], uid[1], uid[2], uid[3]]) | ||
| 913 | } | ||
diff --git a/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_cs.rs b/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_cs.rs new file mode 100644 index 000000000..30103ba27 --- /dev/null +++ b/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_cs.rs | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | use crate::bindings::link_layer::{ | ||
| 2 | LINKLAYER_PLAT_DisableIRQ, LINKLAYER_PLAT_DisableSpecificIRQ, LINKLAYER_PLAT_EnableIRQ, | ||
| 3 | LINKLAYER_PLAT_EnableSpecificIRQ, LINKLAYER_PLAT_PhyStartClbr, LINKLAYER_PLAT_PhyStopClbr, | ||
| 4 | }; | ||
| 5 | |||
| 6 | // /** | ||
| 7 | // ****************************************************************************** | ||
| 8 | // * @file ll_sys_cs.c | ||
| 9 | // * @author MCD Application Team | ||
| 10 | // * @brief Link Layer IP system interface critical sections management | ||
| 11 | // ****************************************************************************** | ||
| 12 | // * @attention | ||
| 13 | // * | ||
| 14 | // * Copyright (c) 2022 STMicroelectronics. | ||
| 15 | // * All rights reserved. | ||
| 16 | // * | ||
| 17 | // * This software is licensed under terms that can be found in the LICENSE file | ||
| 18 | // * in the root directory of this software component. | ||
| 19 | // * If no LICENSE file comes with this software, it is provided AS-IS. | ||
| 20 | // * | ||
| 21 | // ****************************************************************************** | ||
| 22 | // */ | ||
| 23 | // | ||
| 24 | // #include "linklayer_plat.h" | ||
| 25 | // #include "ll_sys.h" | ||
| 26 | // #include <stdint.h> | ||
| 27 | // | ||
| 28 | /** | ||
| 29 | * @brief Enable interrupts | ||
| 30 | * @param None | ||
| 31 | * @retval None | ||
| 32 | */ | ||
| 33 | #[unsafe(no_mangle)] | ||
| 34 | unsafe extern "C" fn ll_sys_enable_irq() { | ||
| 35 | LINKLAYER_PLAT_EnableIRQ(); | ||
| 36 | } | ||
| 37 | // | ||
| 38 | // /** | ||
| 39 | // * @brief Disable interrupts | ||
| 40 | // * @param None | ||
| 41 | // * @retval None | ||
| 42 | // */ | ||
| 43 | #[unsafe(no_mangle)] | ||
| 44 | unsafe extern "C" fn ll_sys_disable_irq() { | ||
| 45 | LINKLAYER_PLAT_DisableIRQ(); | ||
| 46 | } | ||
| 47 | // | ||
| 48 | // /** | ||
| 49 | // * @brief Set the Current Interrupt Priority Mask. | ||
| 50 | // * All interrupts with low priority level will be masked. | ||
| 51 | // * @param None | ||
| 52 | // * @retval None | ||
| 53 | // */ | ||
| 54 | #[unsafe(no_mangle)] | ||
| 55 | unsafe extern "C" fn ll_sys_enable_specific_irq(isr_type: u8) { | ||
| 56 | LINKLAYER_PLAT_EnableSpecificIRQ(isr_type); | ||
| 57 | } | ||
| 58 | // | ||
| 59 | // /** | ||
| 60 | // * @brief Restore the previous interrupt priority level | ||
| 61 | // * @param None | ||
| 62 | // * @retval None | ||
| 63 | // */ | ||
| 64 | #[unsafe(no_mangle)] | ||
| 65 | unsafe extern "C" fn ll_sys_disable_specific_irq(isr_type: u8) { | ||
| 66 | LINKLAYER_PLAT_DisableSpecificIRQ(isr_type); | ||
| 67 | } | ||
| 68 | // | ||
| 69 | #[unsafe(no_mangle)] | ||
| 70 | unsafe extern "C" fn ll_sys_phy_start_clbr() { | ||
| 71 | LINKLAYER_PLAT_PhyStartClbr(); | ||
| 72 | } | ||
| 73 | // | ||
| 74 | #[unsafe(no_mangle)] | ||
| 75 | unsafe extern "C" fn ll_sys_phy_stop_clbr() { | ||
| 76 | LINKLAYER_PLAT_PhyStopClbr(); | ||
| 77 | } | ||
diff --git a/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_dp_slp.rs b/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_dp_slp.rs new file mode 100644 index 000000000..ae8223a5a --- /dev/null +++ b/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_dp_slp.rs | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | use crate::bindings::link_layer::{ | ||
| 2 | _NULL as NULL, DPSLP_STATE_DEEP_SLEEP_DISABLE, DPSLP_STATE_DEEP_SLEEP_ENABLE, LINKLAYER_PLAT_DisableRadioIT, | ||
| 3 | LINKLAYER_PLAT_EnableRadioIT, LL_SYS_DP_SLP_STATE_T_LL_SYS_DP_SLP_DISABLED, | ||
| 4 | LL_SYS_DP_SLP_STATE_T_LL_SYS_DP_SLP_ENABLED, LL_SYS_STATUS_T_LL_SYS_ERROR, LL_SYS_STATUS_T_LL_SYS_OK, | ||
| 5 | OS_TIMER_PRIO_HG_PRIO_TMR, OS_TIMER_STATE_OSTIMERSTOPPED, OS_TIMER_TYPE_OS_TIMER_ONCE, SUCCESS, ble_stat_t, | ||
| 6 | ll_intf_cmn_le_set_dp_slp_mode, ll_sys_dp_slp_state_t, ll_sys_status_t, os_get_tmr_state, os_timer_create, | ||
| 7 | os_timer_id, os_timer_set_prio, os_timer_start, os_timer_stop, | ||
| 8 | }; | ||
| 9 | |||
| 10 | macro_rules! LL_DP_SLP_NO_WAKEUP { | ||
| 11 | () => { | ||
| 12 | !0u32 | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | |||
| 16 | macro_rules! LL_INTERNAL_TMR_US_TO_STEPS { | ||
| 17 | ($us:expr) => { | ||
| 18 | ((($us) * 4) / 125) | ||
| 19 | }; | ||
| 20 | } | ||
| 21 | |||
| 22 | // /** | ||
| 23 | // ****************************************************************************** | ||
| 24 | // * @file ll_sys_dp_slp.c | ||
| 25 | // * @author MCD Application Team | ||
| 26 | // * @brief Link Layer IP system interface deep sleep management | ||
| 27 | // ****************************************************************************** | ||
| 28 | // * @attention | ||
| 29 | // * | ||
| 30 | // * Copyright (c) 2022 STMicroelectronics. | ||
| 31 | // * All rights reserved. | ||
| 32 | // * | ||
| 33 | // * This software is licensed under terms that can be found in the LICENSE file | ||
| 34 | // * in the root directory of this software component. | ||
| 35 | // * If no LICENSE file comes with this software, it is provided AS-IS. | ||
| 36 | // * | ||
| 37 | // ****************************************************************************** | ||
| 38 | // */ | ||
| 39 | // | ||
| 40 | // #include "linklayer_plat.h" | ||
| 41 | // #include "ll_sys.h" | ||
| 42 | // #include "ll_intf_cmn.h" | ||
| 43 | // | ||
| 44 | // /* Link Layer deep sleep timer */ | ||
| 45 | static mut RADIO_DP_SLP_TMR_ID: os_timer_id = NULL as *mut _; | ||
| 46 | // | ||
| 47 | // /* Link Layer deep sleep state */ | ||
| 48 | static mut LINKLAYER_DP_SLP_STATE: ll_sys_dp_slp_state_t = LL_SYS_DP_SLP_STATE_T_LL_SYS_DP_SLP_DISABLED; | ||
| 49 | // | ||
| 50 | // /** | ||
| 51 | // * @brief Initialize resources to handle deep sleep entry/exit | ||
| 52 | // * @param None | ||
| 53 | // * @retval LL_SYS status | ||
| 54 | // */ | ||
| 55 | #[unsafe(no_mangle)] | ||
| 56 | unsafe extern "C" fn ll_sys_dp_slp_init() -> ll_sys_status_t { | ||
| 57 | let mut return_status: ll_sys_status_t = LL_SYS_STATUS_T_LL_SYS_ERROR; | ||
| 58 | |||
| 59 | /* Create link layer timer for handling IP DEEP SLEEP mode */ | ||
| 60 | RADIO_DP_SLP_TMR_ID = os_timer_create( | ||
| 61 | Some(ll_sys_dp_slp_wakeup_evt_clbk), | ||
| 62 | OS_TIMER_TYPE_OS_TIMER_ONCE, | ||
| 63 | NULL as *mut _, | ||
| 64 | ); | ||
| 65 | |||
| 66 | /* Set priority of deep sleep timer */ | ||
| 67 | os_timer_set_prio(RADIO_DP_SLP_TMR_ID, OS_TIMER_PRIO_HG_PRIO_TMR); | ||
| 68 | |||
| 69 | if RADIO_DP_SLP_TMR_ID != NULL as *mut _ { | ||
| 70 | return_status = LL_SYS_STATUS_T_LL_SYS_OK; | ||
| 71 | } | ||
| 72 | |||
| 73 | return return_status; | ||
| 74 | } | ||
| 75 | // | ||
| 76 | // /** | ||
| 77 | // * @brief Link Layer deep sleep status getter | ||
| 78 | // * @param None | ||
| 79 | // * @retval Link Layer deep sleep state | ||
| 80 | // */ | ||
| 81 | #[unsafe(no_mangle)] | ||
| 82 | unsafe extern "C" fn ll_sys_dp_slp_get_state() -> ll_sys_dp_slp_state_t { | ||
| 83 | return LINKLAYER_DP_SLP_STATE; | ||
| 84 | } | ||
| 85 | // | ||
| 86 | // /** | ||
| 87 | // * @brief The Link Layer IP enters deep sleep mode | ||
| 88 | // * @param dp_slp_duration deep sleep duration in us | ||
| 89 | // * @retval LL_SYS status | ||
| 90 | // */ | ||
| 91 | #[unsafe(no_mangle)] | ||
| 92 | unsafe extern "C" fn ll_sys_dp_slp_enter(dp_slp_duration: u32) -> ll_sys_status_t { | ||
| 93 | let cmd_status: ble_stat_t; | ||
| 94 | let os_status: i32; | ||
| 95 | let mut return_status: ll_sys_status_t = LL_SYS_STATUS_T_LL_SYS_ERROR; | ||
| 96 | |||
| 97 | /* Check if deep sleep timer has to be started */ | ||
| 98 | if dp_slp_duration < LL_DP_SLP_NO_WAKEUP!() { | ||
| 99 | /* Start deep sleep timer */ | ||
| 100 | os_status = os_timer_start(RADIO_DP_SLP_TMR_ID, LL_INTERNAL_TMR_US_TO_STEPS!(dp_slp_duration)); | ||
| 101 | } else { | ||
| 102 | /* No timer started */ | ||
| 103 | os_status = SUCCESS as i32; | ||
| 104 | } | ||
| 105 | |||
| 106 | if os_status == SUCCESS as i32 { | ||
| 107 | /* Switch Link Layer IP to DEEP SLEEP mode */ | ||
| 108 | cmd_status = ll_intf_cmn_le_set_dp_slp_mode(DPSLP_STATE_DEEP_SLEEP_ENABLE as u8); | ||
| 109 | if cmd_status == SUCCESS { | ||
| 110 | LINKLAYER_DP_SLP_STATE = LL_SYS_DP_SLP_STATE_T_LL_SYS_DP_SLP_ENABLED; | ||
| 111 | return_status = LL_SYS_STATUS_T_LL_SYS_OK; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | return return_status; | ||
| 116 | } | ||
| 117 | // | ||
| 118 | // /** | ||
| 119 | // * @brief The Link Layer IP exits deep sleep mode | ||
| 120 | // * @param None | ||
| 121 | // * @retval LL_SYS status | ||
| 122 | // */ | ||
| 123 | #[unsafe(no_mangle)] | ||
| 124 | unsafe extern "C" fn ll_sys_dp_slp_exit() -> ll_sys_status_t { | ||
| 125 | let cmd_status: ble_stat_t; | ||
| 126 | let mut return_status: ll_sys_status_t = LL_SYS_STATUS_T_LL_SYS_ERROR; | ||
| 127 | |||
| 128 | /* Disable radio interrupt */ | ||
| 129 | LINKLAYER_PLAT_DisableRadioIT(); | ||
| 130 | |||
| 131 | if LINKLAYER_DP_SLP_STATE == LL_SYS_DP_SLP_STATE_T_LL_SYS_DP_SLP_DISABLED { | ||
| 132 | /* Radio not in sleep mode */ | ||
| 133 | return_status = LL_SYS_STATUS_T_LL_SYS_OK; | ||
| 134 | } else { | ||
| 135 | /* Switch Link Layer IP to SLEEP mode (by deactivate DEEP SLEEP mode) */ | ||
| 136 | cmd_status = ll_intf_cmn_le_set_dp_slp_mode(DPSLP_STATE_DEEP_SLEEP_DISABLE as u8); | ||
| 137 | if cmd_status == SUCCESS { | ||
| 138 | LINKLAYER_DP_SLP_STATE = LL_SYS_DP_SLP_STATE_T_LL_SYS_DP_SLP_DISABLED; | ||
| 139 | return_status = LL_SYS_STATUS_T_LL_SYS_OK; | ||
| 140 | } | ||
| 141 | |||
| 142 | /* Stop the deep sleep wake-up timer if running */ | ||
| 143 | if os_get_tmr_state(RADIO_DP_SLP_TMR_ID) != OS_TIMER_STATE_OSTIMERSTOPPED { | ||
| 144 | os_timer_stop(RADIO_DP_SLP_TMR_ID); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | /* Re-enable radio interrupt */ | ||
| 149 | LINKLAYER_PLAT_EnableRadioIT(); | ||
| 150 | |||
| 151 | return return_status; | ||
| 152 | } | ||
| 153 | |||
| 154 | /** | ||
| 155 | * @brief Link Layer deep sleep wake-up timer callback | ||
| 156 | * @param ptr_arg pointer passed through the callback | ||
| 157 | * @retval LL_SYS status | ||
| 158 | */ | ||
| 159 | #[unsafe(no_mangle)] | ||
| 160 | unsafe extern "C" fn ll_sys_dp_slp_wakeup_evt_clbk(_ptr_arg: *const ::core::ffi::c_void) { | ||
| 161 | /* Link Layer IP exits from DEEP SLEEP mode */ | ||
| 162 | ll_sys_dp_slp_exit(); | ||
| 163 | } | ||
diff --git a/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_intf.rs b/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_intf.rs new file mode 100644 index 000000000..0b4b0b37f --- /dev/null +++ b/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_intf.rs | |||
| @@ -0,0 +1,199 @@ | |||
| 1 | use crate::bindings::link_layer::{ | ||
| 2 | Evnt_timing_t, HostStack_Process, LINKLAYER_PLAT_AclkCtrl, LINKLAYER_PLAT_Assert, LINKLAYER_PLAT_ClockInit, | ||
| 3 | LINKLAYER_PLAT_DelayUs, LINKLAYER_PLAT_GetRNG, LINKLAYER_PLAT_RCOStartClbr, LINKLAYER_PLAT_RCOStopClbr, | ||
| 4 | LINKLAYER_PLAT_RequestTemperature, LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT, LINKLAYER_PLAT_SetupRadioIT, | ||
| 5 | LINKLAYER_PLAT_SetupSwLowIT, LINKLAYER_PLAT_StartRadioEvt, LINKLAYER_PLAT_StopRadioEvt, | ||
| 6 | LINKLAYER_PLAT_TriggerSwLowIT, LINKLAYER_PLAT_WaitHclkRdy, MAX_NUM_CNCRT_STAT_MCHNS, emngr_can_mcu_sleep, | ||
| 7 | emngr_handle_all_events, ll_sys_schedule_bg_process, | ||
| 8 | }; | ||
| 9 | |||
| 10 | // /** | ||
| 11 | // ****************************************************************************** | ||
| 12 | // * @file ll_sys_intf.c | ||
| 13 | // * @author MCD Application Team | ||
| 14 | // * @brief Link Layer IP general system interface | ||
| 15 | // ****************************************************************************** | ||
| 16 | // * @attention | ||
| 17 | // * | ||
| 18 | // * Copyright (c) 2022 STMicroelectronics. | ||
| 19 | // * All rights reserved. | ||
| 20 | // * | ||
| 21 | // * This software is licensed under terms that can be found in the LICENSE file | ||
| 22 | // * in the root directory of this software component. | ||
| 23 | // * If no LICENSE file comes with this software, it is provided AS-IS. | ||
| 24 | // * | ||
| 25 | // ****************************************************************************** | ||
| 26 | // */ | ||
| 27 | // #include <stdint.h> | ||
| 28 | // | ||
| 29 | // #include "ll_sys.h" | ||
| 30 | // #include "linklayer_plat.h" | ||
| 31 | // #include "event_manager.h" | ||
| 32 | // #include "ll_intf.h" | ||
| 33 | // | ||
| 34 | /** | ||
| 35 | * @brief Initialize the Link Layer SoC dependencies | ||
| 36 | * @param None | ||
| 37 | * @retval None | ||
| 38 | */ | ||
| 39 | #[unsafe(no_mangle)] | ||
| 40 | unsafe extern "C" fn ll_sys_init() { | ||
| 41 | LINKLAYER_PLAT_ClockInit(); | ||
| 42 | } | ||
| 43 | // | ||
| 44 | /** | ||
| 45 | * @brief Blocking delay in us | ||
| 46 | * @param None | ||
| 47 | * @retval None | ||
| 48 | */ | ||
| 49 | #[unsafe(no_mangle)] | ||
| 50 | unsafe extern "C" fn ll_sys_delay_us(delay: u32) { | ||
| 51 | LINKLAYER_PLAT_DelayUs(delay); | ||
| 52 | } | ||
| 53 | |||
| 54 | /** | ||
| 55 | * @brief Assert checking | ||
| 56 | * @param None | ||
| 57 | * @retval None | ||
| 58 | */ | ||
| 59 | #[unsafe(no_mangle)] | ||
| 60 | unsafe extern "C" fn ll_sys_assert(condition: u8) { | ||
| 61 | LINKLAYER_PLAT_Assert(condition); | ||
| 62 | } | ||
| 63 | |||
| 64 | /** | ||
| 65 | * @brief Radio active clock management | ||
| 66 | * @param None | ||
| 67 | * @retval None | ||
| 68 | */ | ||
| 69 | #[unsafe(no_mangle)] | ||
| 70 | unsafe extern "C" fn ll_sys_radio_ack_ctrl(enable: u8) { | ||
| 71 | LINKLAYER_PLAT_AclkCtrl(enable); | ||
| 72 | } | ||
| 73 | |||
| 74 | /** | ||
| 75 | * @brief Link Layer waits for radio bus clock ready | ||
| 76 | * @param None | ||
| 77 | * @retval None | ||
| 78 | */ | ||
| 79 | #[unsafe(no_mangle)] | ||
| 80 | unsafe extern "C" fn ll_sys_radio_wait_for_busclkrdy() { | ||
| 81 | LINKLAYER_PLAT_WaitHclkRdy(); | ||
| 82 | } | ||
| 83 | |||
| 84 | /** | ||
| 85 | * @brief Get RNG number for the Link Layer IP | ||
| 86 | * @param None | ||
| 87 | * @retval None | ||
| 88 | */ | ||
| 89 | #[unsafe(no_mangle)] | ||
| 90 | unsafe extern "C" fn ll_sys_get_rng(ptr_rnd: *mut u8, len: u32) { | ||
| 91 | LINKLAYER_PLAT_GetRNG(ptr_rnd, len); | ||
| 92 | } | ||
| 93 | |||
| 94 | /** | ||
| 95 | * @brief Initialize the main radio interrupt | ||
| 96 | * @param intr_cb radio interrupt callback to link with the radio IRQ | ||
| 97 | * @retval None | ||
| 98 | */ | ||
| 99 | #[unsafe(no_mangle)] | ||
| 100 | unsafe extern "C" fn ll_sys_setup_radio_intr(intr_cb: ::core::option::Option<unsafe extern "C" fn()>) { | ||
| 101 | LINKLAYER_PLAT_SetupRadioIT(intr_cb); | ||
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * @brief Initialize the radio SW low interrupt | ||
| 106 | * @param intr_cb radio SW low interrupt interrupt callback to link | ||
| 107 | * with the defined interrupt vector | ||
| 108 | * @retval None | ||
| 109 | */ | ||
| 110 | #[unsafe(no_mangle)] | ||
| 111 | unsafe extern "C" fn ll_sys_setup_radio_sw_low_intr(intr_cb: ::core::option::Option<unsafe extern "C" fn()>) { | ||
| 112 | LINKLAYER_PLAT_SetupSwLowIT(intr_cb); | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * @brief Trigger the radio SW low interrupt | ||
| 117 | * @param None | ||
| 118 | * @retval None | ||
| 119 | */ | ||
| 120 | #[unsafe(no_mangle)] | ||
| 121 | unsafe extern "C" fn ll_sys_radio_sw_low_intr_trigger(priority: u8) { | ||
| 122 | LINKLAYER_PLAT_TriggerSwLowIT(priority); | ||
| 123 | } | ||
| 124 | |||
| 125 | /** | ||
| 126 | * @brief Link Layer radio activity event notification | ||
| 127 | * @param start start/end of radio event | ||
| 128 | * @retval None | ||
| 129 | */ | ||
| 130 | #[unsafe(no_mangle)] | ||
| 131 | unsafe extern "C" fn ll_sys_radio_evt_not(start: u8) { | ||
| 132 | if start != 0 { | ||
| 133 | LINKLAYER_PLAT_StartRadioEvt(); | ||
| 134 | } else { | ||
| 135 | LINKLAYER_PLAT_StopRadioEvt(); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /** | ||
| 140 | * @brief Link Layer RCO calibration notification | ||
| 141 | * @param start start/end of RCO calibration | ||
| 142 | * @retval None | ||
| 143 | */ | ||
| 144 | #[unsafe(no_mangle)] | ||
| 145 | unsafe extern "C" fn ll_sys_rco_clbr_not(start: u8) { | ||
| 146 | if start != 0 { | ||
| 147 | LINKLAYER_PLAT_RCOStartClbr(); | ||
| 148 | } else { | ||
| 149 | LINKLAYER_PLAT_RCOStopClbr(); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * @brief Link Layer temperature request | ||
| 155 | * @param None | ||
| 156 | * @retval None | ||
| 157 | */ | ||
| 158 | #[unsafe(no_mangle)] | ||
| 159 | unsafe extern "C" fn ll_sys_request_temperature() { | ||
| 160 | LINKLAYER_PLAT_RequestTemperature(); | ||
| 161 | } | ||
| 162 | |||
| 163 | /** | ||
| 164 | * @brief Link Layer background task pcoessing procedure | ||
| 165 | * @param None | ||
| 166 | * @retval None | ||
| 167 | */ | ||
| 168 | #[unsafe(no_mangle)] | ||
| 169 | unsafe extern "C" fn ll_sys_bg_process() { | ||
| 170 | if emngr_can_mcu_sleep() == 0 { | ||
| 171 | emngr_handle_all_events(); | ||
| 172 | |||
| 173 | HostStack_Process(); | ||
| 174 | } | ||
| 175 | |||
| 176 | if emngr_can_mcu_sleep() == 0 { | ||
| 177 | ll_sys_schedule_bg_process(); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | #[unsafe(no_mangle)] | ||
| 182 | unsafe extern "C" fn ll_sys_schldr_timing_update_not(p_evnt_timing: *mut Evnt_timing_t) { | ||
| 183 | LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(p_evnt_timing); | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * @brief Get the number of concurrent state machines for the Link Layer | ||
| 188 | * @param None | ||
| 189 | * @retval Supported number of concurrent state machines | ||
| 190 | */ | ||
| 191 | #[unsafe(no_mangle)] | ||
| 192 | unsafe extern "C" fn ll_sys_get_concurrent_state_machines_num() -> u8 { | ||
| 193 | return MAX_NUM_CNCRT_STAT_MCHNS as u8; | ||
| 194 | } | ||
| 195 | // | ||
| 196 | // __WEAK void HostStack_Process(void) | ||
| 197 | // { | ||
| 198 | // | ||
| 199 | // } | ||
diff --git a/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_startup.rs b/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_startup.rs new file mode 100644 index 000000000..074aaeafe --- /dev/null +++ b/embassy-stm32-wpan/src/wba/ll_sys/ll_sys_startup.rs | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | use crate::bindings::link_layer::{ | ||
| 2 | _NULL as NULL, LL_SYS_STATUS_T_LL_SYS_OK, ble_buff_hdr_p, hci_dispatch_tbl, hci_get_dis_tbl, hst_cbk, ll_intf_init, | ||
| 3 | ll_intf_rgstr_hst_cbk, ll_intf_rgstr_hst_cbk_ll_queue_full, ll_sys_assert, ll_sys_bg_process_init, | ||
| 4 | ll_sys_config_params, ll_sys_dp_slp_init, ll_sys_status_t, | ||
| 5 | }; | ||
| 6 | use crate::bindings::mac::ST_MAC_preInit; | ||
| 7 | // /** | ||
| 8 | // ****************************************************************************** | ||
| 9 | // * @file ll_sys_startup.c | ||
| 10 | // * @author MCD Application Team | ||
| 11 | // * @brief Link Layer IP system interface startup module | ||
| 12 | // ****************************************************************************** | ||
| 13 | // * @attention | ||
| 14 | // * | ||
| 15 | // * Copyright (c) 2022 STMicroelectronics. | ||
| 16 | // * All rights reserved. | ||
| 17 | // * | ||
| 18 | // * This software is licensed under terms that can be found in the LICENSE file | ||
| 19 | // * in the root directory of this software component. | ||
| 20 | // * If no LICENSE file comes with this software, it is provided AS-IS. | ||
| 21 | // * | ||
| 22 | // ****************************************************************************** | ||
| 23 | // */ | ||
| 24 | // | ||
| 25 | // #include "ll_fw_config.h" | ||
| 26 | // #include "ll_sys.h" | ||
| 27 | // #include "ll_intf.h" | ||
| 28 | // #include "ll_sys_startup.h" | ||
| 29 | // #include "common_types.h" | ||
| 30 | // #if defined(MAC) | ||
| 31 | // #ifndef OPENTHREAD_CONFIG_FILE | ||
| 32 | // /* Projects with MAC Layer (i.e. 15.4 except Thread) */ | ||
| 33 | // #include "st_mac_802_15_4_sap.h" | ||
| 34 | // #endif /* OPENTHREAD_CONFIG_FILE */ | ||
| 35 | // #endif /* MAC */ | ||
| 36 | // | ||
| 37 | |||
| 38 | #[allow(dead_code)] | ||
| 39 | /** | ||
| 40 | * @brief Missed HCI event flag | ||
| 41 | */ | ||
| 42 | static mut MISSED_HCI_EVENT_FLAG: u8 = 0; | ||
| 43 | |||
| 44 | // static void ll_sys_dependencies_init(void); | ||
| 45 | // #if SUPPORT_BLE | ||
| 46 | |||
| 47 | #[cfg(feature = "wba_ble")] | ||
| 48 | #[allow(dead_code)] | ||
| 49 | unsafe extern "C" fn ll_sys_event_missed_cb(_ptr_evnt_hdr: ble_buff_hdr_p) { | ||
| 50 | MISSED_HCI_EVENT_FLAG = 1; | ||
| 51 | } | ||
| 52 | |||
| 53 | #[cfg(feature = "wba_ble")] | ||
| 54 | /** | ||
| 55 | * @brief Initialize the Link Layer IP BLE controller | ||
| 56 | * @param None | ||
| 57 | * @retval None | ||
| 58 | */ | ||
| 59 | #[unsafe(no_mangle)] | ||
| 60 | unsafe extern "C" fn ll_sys_ble_cntrl_init(host_callback: hst_cbk) { | ||
| 61 | let p_hci_dis_tbl: *const hci_dispatch_tbl = NULL as *const _; | ||
| 62 | |||
| 63 | hci_get_dis_tbl(&p_hci_dis_tbl as *const *const _ as *mut *const _); | ||
| 64 | |||
| 65 | ll_intf_init(p_hci_dis_tbl); | ||
| 66 | |||
| 67 | ll_intf_rgstr_hst_cbk(host_callback); | ||
| 68 | |||
| 69 | ll_intf_rgstr_hst_cbk_ll_queue_full(Some(ll_sys_event_missed_cb)); | ||
| 70 | |||
| 71 | ll_sys_dependencies_init(); | ||
| 72 | } | ||
| 73 | // #endif /* SUPPORT_BLE */ | ||
| 74 | // #if defined(MAC) | ||
| 75 | // #ifndef OPENTHREAD_CONFIG_FILE | ||
| 76 | #[cfg(feature = "wba_mac")] | ||
| 77 | /** | ||
| 78 | * @brief Initialize the Link Layer IP 802.15.4 MAC controller | ||
| 79 | * @param None | ||
| 80 | * @retval None | ||
| 81 | */ | ||
| 82 | #[unsafe(no_mangle)] | ||
| 83 | unsafe extern "C" fn ll_sys_mac_cntrl_init() { | ||
| 84 | ST_MAC_preInit(); | ||
| 85 | ll_sys_dependencies_init(); | ||
| 86 | } | ||
| 87 | // #endif /* OPENTHREAD_CONFIG_FILE */ | ||
| 88 | // #endif /* MAC */ | ||
| 89 | /** | ||
| 90 | * @brief Start the Link Layer IP in OpenThread configuration | ||
| 91 | * @param None | ||
| 92 | * @retval None | ||
| 93 | */ | ||
| 94 | #[unsafe(no_mangle)] | ||
| 95 | unsafe extern "C" fn ll_sys_thread_init() { | ||
| 96 | ll_sys_dependencies_init(); | ||
| 97 | } | ||
| 98 | |||
| 99 | /** | ||
| 100 | * @brief Initialize the Link Layer resources for startup. | ||
| 101 | * This includes: - Deep Sleep feature resources | ||
| 102 | * - Link Layer background task | ||
| 103 | * @param None | ||
| 104 | * @retval None | ||
| 105 | */ | ||
| 106 | unsafe fn ll_sys_dependencies_init() { | ||
| 107 | static mut IS_LL_INITIALIZED: u8 = 0; | ||
| 108 | let dp_slp_status: ll_sys_status_t; | ||
| 109 | |||
| 110 | /* Ensure Link Layer resources are created only once */ | ||
| 111 | if IS_LL_INITIALIZED == 1 { | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | IS_LL_INITIALIZED = 1; | ||
| 115 | |||
| 116 | /* Deep sleep feature initialization */ | ||
| 117 | dp_slp_status = ll_sys_dp_slp_init(); | ||
| 118 | ll_sys_assert((dp_slp_status == LL_SYS_STATUS_T_LL_SYS_OK) as u8); | ||
| 119 | |||
| 120 | /* Background task initialization */ | ||
| 121 | ll_sys_bg_process_init(); | ||
| 122 | |||
| 123 | /* Link Layer user parameters application */ | ||
| 124 | ll_sys_config_params(); | ||
| 125 | } | ||
diff --git a/embassy-stm32-wpan/src/wba/ll_sys/ll_version.rs b/embassy-stm32-wpan/src/wba/ll_sys/ll_version.rs new file mode 100644 index 000000000..a42e8cc67 --- /dev/null +++ b/embassy-stm32-wpan/src/wba/ll_sys/ll_version.rs | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | use crate::bindings::link_layer::{ | ||
| 2 | LL_SYS_BRIEF_VERSION_MAJOR, LL_SYS_BRIEF_VERSION_MAJOR_MASK, LL_SYS_BRIEF_VERSION_MAJOR_POS, | ||
| 3 | LL_SYS_BRIEF_VERSION_MINOR, LL_SYS_BRIEF_VERSION_MINOR_MASK, LL_SYS_BRIEF_VERSION_MINOR_POS, | ||
| 4 | LL_SYS_BRIEF_VERSION_PATCH, LL_SYS_BRIEF_VERSION_PATCH_MASK, LL_SYS_BRIEF_VERSION_PATCH_POS, | ||
| 5 | }; | ||
| 6 | |||
| 7 | // /** | ||
| 8 | // ****************************************************************************** | ||
| 9 | // * @file ll_version.c | ||
| 10 | // * @author MCD Application Team | ||
| 11 | // * @brief Link Layer version interface | ||
| 12 | // ****************************************************************************** | ||
| 13 | // * @attention | ||
| 14 | // * | ||
| 15 | // * Copyright (c) 2025 STMicroelectronics. | ||
| 16 | // * All rights reserved. | ||
| 17 | // * | ||
| 18 | // * This software is licensed under terms that can be found in the LICENSE file | ||
| 19 | // * in the root directory of this software component. | ||
| 20 | // * If no LICENSE file comes with this software, it is provided AS-IS. | ||
| 21 | // * | ||
| 22 | // ****************************************************************************** | ||
| 23 | // */ | ||
| 24 | // | ||
| 25 | // /* Includes ------------------------------------------------------------------*/ | ||
| 26 | // /* Integer types */ | ||
| 27 | // #include <stdint.h> | ||
| 28 | // | ||
| 29 | // /* Own header file */ | ||
| 30 | // #include "ll_version.h" | ||
| 31 | // | ||
| 32 | // /* Temporary header file for version tracking */ | ||
| 33 | // #include "ll_tmp_version.h" | ||
| 34 | // | ||
| 35 | // /* Private defines -----------------------------------------------------------*/ | ||
| 36 | // /** | ||
| 37 | // * @brief Magic keyword to identify the system version when debugging | ||
| 38 | // */ | ||
| 39 | // #define LL_SYS_MAGIC_KEYWORD 0xDEADBEEF | ||
| 40 | |||
| 41 | const LL_SYS_MAGIC_KEYWORD: u32 = 0xDEADBEEF; | ||
| 42 | |||
| 43 | // | ||
| 44 | // /* Private macros ------------------------------------------------------------*/ | ||
| 45 | // /* Macro to set a specific field value */ | ||
| 46 | // #define LL_SYS_SET_FIELD_VALUE(value, mask, pos) \ | ||
| 47 | // (((value) << (pos)) & (mask)) | ||
| 48 | |||
| 49 | macro_rules! LL_SYS_SET_FIELD_VALUE { | ||
| 50 | ($value:expr, $mask:expr, $pos:expr) => { | ||
| 51 | ((($value) << ($pos)) & ($mask)) | ||
| 52 | }; | ||
| 53 | } | ||
| 54 | |||
| 55 | // | ||
| 56 | // /* Private typedef -----------------------------------------------------------*/ | ||
| 57 | // /** | ||
| 58 | // * @brief Link Layer system version structure definition | ||
| 59 | // */ | ||
| 60 | #[allow(non_camel_case_types)] | ||
| 61 | struct ll_sys_version_t { | ||
| 62 | #[allow(unused)] | ||
| 63 | magic_key_word: u32, /* Magic key word to identify the system version */ | ||
| 64 | version: u32, /* System version - i.e.: short hash of latest commit */ | ||
| 65 | } | ||
| 66 | // | ||
| 67 | // /* Private variables ---------------------------------------------------------*/ | ||
| 68 | // /** | ||
| 69 | // * @brief Link Layer brief version definition | ||
| 70 | // */ | ||
| 71 | const LL_SYS_BRIEF_VERSION: u8 = LL_SYS_SET_FIELD_VALUE!( | ||
| 72 | LL_SYS_BRIEF_VERSION_MAJOR as u8, | ||
| 73 | LL_SYS_BRIEF_VERSION_MAJOR_MASK as u8, | ||
| 74 | LL_SYS_BRIEF_VERSION_MAJOR_POS as u8 | ||
| 75 | ) | LL_SYS_SET_FIELD_VALUE!( | ||
| 76 | LL_SYS_BRIEF_VERSION_MINOR as u8, | ||
| 77 | LL_SYS_BRIEF_VERSION_MINOR_MASK as u8, | ||
| 78 | LL_SYS_BRIEF_VERSION_MINOR_POS as u8 | ||
| 79 | ) | LL_SYS_SET_FIELD_VALUE!( | ||
| 80 | LL_SYS_BRIEF_VERSION_PATCH as u8, | ||
| 81 | LL_SYS_BRIEF_VERSION_PATCH_MASK as u8, | ||
| 82 | LL_SYS_BRIEF_VERSION_PATCH_POS as u8 | ||
| 83 | ); | ||
| 84 | // | ||
| 85 | // /** | ||
| 86 | // * @brief Link Layer system version structure definition | ||
| 87 | // */ | ||
| 88 | const LL_SYS_SYSTEM_VERSION: ll_sys_version_t = ll_sys_version_t { | ||
| 89 | magic_key_word: LL_SYS_MAGIC_KEYWORD, | ||
| 90 | version: 0, // LL_SYS_SYSTEM_VERSION, | ||
| 91 | }; | ||
| 92 | // | ||
| 93 | // /** | ||
| 94 | // * @brief Link Layer source version structure definition | ||
| 95 | // */ | ||
| 96 | const LL_SYS_SOURCE_VERSION: ll_sys_version_t = ll_sys_version_t { | ||
| 97 | magic_key_word: LL_SYS_MAGIC_KEYWORD, | ||
| 98 | version: 0, // LL_SYS_SOURCE_VERSION | ||
| 99 | }; | ||
| 100 | // | ||
| 101 | // /* Functions Definition ------------------------------------------------------*/ | ||
| 102 | #[unsafe(no_mangle)] | ||
| 103 | unsafe extern "C" fn ll_sys_get_brief_fw_version() -> u8 { | ||
| 104 | return LL_SYS_BRIEF_VERSION; | ||
| 105 | } | ||
| 106 | |||
| 107 | #[unsafe(no_mangle)] | ||
| 108 | unsafe extern "C" fn ll_sys_get_system_fw_version() -> u32 { | ||
| 109 | return LL_SYS_SYSTEM_VERSION.version; | ||
| 110 | } | ||
| 111 | |||
| 112 | #[unsafe(no_mangle)] | ||
| 113 | unsafe extern "C" fn ll_sys_get_source_fw_version() -> u32 { | ||
| 114 | return LL_SYS_SOURCE_VERSION.version; | ||
| 115 | } | ||
diff --git a/embassy-stm32-wpan/src/wba/ll_sys/mod.rs b/embassy-stm32-wpan/src/wba/ll_sys/mod.rs new file mode 100644 index 000000000..45e196c96 --- /dev/null +++ b/embassy-stm32-wpan/src/wba/ll_sys/mod.rs | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | mod ll_sys_cs; | ||
| 2 | mod ll_sys_dp_slp; | ||
| 3 | mod ll_sys_intf; | ||
| 4 | mod ll_sys_startup; | ||
| 5 | mod ll_version; | ||
diff --git a/embassy-stm32-wpan/src/wba/ll_sys_if.rs b/embassy-stm32-wpan/src/wba/ll_sys_if.rs new file mode 100644 index 000000000..7218b69c4 --- /dev/null +++ b/embassy-stm32-wpan/src/wba/ll_sys_if.rs | |||
| @@ -0,0 +1,416 @@ | |||
| 1 | #![cfg(feature = "wba")] | ||
| 2 | // /* USER CODE BEGIN Header */ | ||
| 3 | // /** | ||
| 4 | // ****************************************************************************** | ||
| 5 | // * @file ll_sys_if.c | ||
| 6 | // * @author MCD Application Team | ||
| 7 | // * @brief Source file for initiating system | ||
| 8 | // ****************************************************************************** | ||
| 9 | // * @attention | ||
| 10 | // * | ||
| 11 | // * Copyright (c) 2022 STMicroelectronics. | ||
| 12 | // * All rights reserved. | ||
| 13 | // * | ||
| 14 | // * This software is licensed under terms that can be found in the LICENSE file | ||
| 15 | // * in the root directory of this software component. | ||
| 16 | // * If no LICENSE file comes with this software, it is provided AS-IS. | ||
| 17 | // * | ||
| 18 | // ****************************************************************************** | ||
| 19 | // */ | ||
| 20 | // /* USER CODE END Header */ | ||
| 21 | // | ||
| 22 | // #include "main.h" | ||
| 23 | // #include "app_common.h" | ||
| 24 | // #include "app_conf.h" | ||
| 25 | // #include "log_module.h" | ||
| 26 | // #include "ll_intf_cmn.h" | ||
| 27 | // #include "ll_sys.h" | ||
| 28 | // #include "ll_sys_if.h" | ||
| 29 | // #include "stm32_rtos.h" | ||
| 30 | // #include "utilities_common.h" | ||
| 31 | // #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) | ||
| 32 | // #include "temp_measurement.h" | ||
| 33 | // #endif /* (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) */ | ||
| 34 | // #if (CFG_LPM_STANDBY_SUPPORTED == 0) | ||
| 35 | // extern void profile_reset(void); | ||
| 36 | // #endif | ||
| 37 | // /* Private defines -----------------------------------------------------------*/ | ||
| 38 | // /* Radio event scheduling method - must be set at 1 */ | ||
| 39 | // #define USE_RADIO_LOW_ISR (1) | ||
| 40 | // #define NEXT_EVENT_SCHEDULING_FROM_ISR (1) | ||
| 41 | // | ||
| 42 | // /* USER CODE BEGIN PD */ | ||
| 43 | // | ||
| 44 | // /* USER CODE END PD */ | ||
| 45 | // | ||
| 46 | // /* Private macros ------------------------------------------------------------*/ | ||
| 47 | // /* USER CODE BEGIN PM */ | ||
| 48 | // | ||
| 49 | // /* USER CODE END PM */ | ||
| 50 | // | ||
| 51 | // /* Private constants ---------------------------------------------------------*/ | ||
| 52 | // /* USER CODE BEGIN PC */ | ||
| 53 | // | ||
| 54 | // /* USER CODE END PC */ | ||
| 55 | // | ||
| 56 | // /* Private variables ---------------------------------------------------------*/ | ||
| 57 | // /* USER CODE BEGIN PV */ | ||
| 58 | // | ||
| 59 | // /* USER CODE END PV */ | ||
| 60 | // | ||
| 61 | // /* Global variables ----------------------------------------------------------*/ | ||
| 62 | // | ||
| 63 | // /* USER CODE BEGIN GV */ | ||
| 64 | // | ||
| 65 | // /* USER CODE END GV */ | ||
| 66 | // | ||
| 67 | // /* Private functions prototypes-----------------------------------------------*/ | ||
| 68 | // #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) | ||
| 69 | // static void ll_sys_bg_temperature_measurement_init(void); | ||
| 70 | // #endif /* USE_TEMPERATURE_BASED_RADIO_CALIBRATION */ | ||
| 71 | // static void ll_sys_sleep_clock_source_selection(void); | ||
| 72 | // static uint8_t ll_sys_BLE_sleep_clock_accuracy_selection(void); | ||
| 73 | // void ll_sys_reset(void); | ||
| 74 | // | ||
| 75 | // /* USER CODE BEGIN PFP */ | ||
| 76 | // | ||
| 77 | // /* USER CODE END PFP */ | ||
| 78 | // | ||
| 79 | // /* External variables --------------------------------------------------------*/ | ||
| 80 | // | ||
| 81 | // /* USER CODE BEGIN EV */ | ||
| 82 | // | ||
| 83 | // /* USER CODE END EV */ | ||
| 84 | // | ||
| 85 | // /* Functions Definition ------------------------------------------------------*/ | ||
| 86 | // | ||
| 87 | // /** | ||
| 88 | // * @brief Link Layer background process initialization | ||
| 89 | // * @param None | ||
| 90 | // * @retval None | ||
| 91 | // */ | ||
| 92 | // void ll_sys_bg_process_init(void) | ||
| 93 | // { | ||
| 94 | // /* Register Link Layer task */ | ||
| 95 | // UTIL_SEQ_RegTask(1U << CFG_TASK_LINK_LAYER, UTIL_SEQ_RFU, ll_sys_bg_process); | ||
| 96 | // } | ||
| 97 | // | ||
| 98 | // /** | ||
| 99 | // * @brief Link Layer background process next iteration scheduling | ||
| 100 | // * @param None | ||
| 101 | // * @retval None | ||
| 102 | // */ | ||
| 103 | // void ll_sys_schedule_bg_process(void) | ||
| 104 | // { | ||
| 105 | // UTIL_SEQ_SetTask(1U << CFG_TASK_LINK_LAYER, TASK_PRIO_LINK_LAYER); | ||
| 106 | // } | ||
| 107 | // | ||
| 108 | // /** | ||
| 109 | // * @brief Link Layer background process next iteration scheduling from ISR | ||
| 110 | // * @param None | ||
| 111 | // * @retval None | ||
| 112 | // */ | ||
| 113 | // void ll_sys_schedule_bg_process_isr(void) | ||
| 114 | // { | ||
| 115 | // UTIL_SEQ_SetTask(1U << CFG_TASK_LINK_LAYER, TASK_PRIO_LINK_LAYER); | ||
| 116 | // } | ||
| 117 | // | ||
| 118 | // /** | ||
| 119 | // * @brief Link Layer configuration phase before application startup. | ||
| 120 | // * @param None | ||
| 121 | // * @retval None | ||
| 122 | // */ | ||
| 123 | // void ll_sys_config_params(void) | ||
| 124 | // { | ||
| 125 | // /* USER CODE BEGIN ll_sys_config_params_0 */ | ||
| 126 | // | ||
| 127 | // /* USER CODE END ll_sys_config_params_0 */ | ||
| 128 | // | ||
| 129 | // /* Configure link layer behavior for low ISR use and next event scheduling method: | ||
| 130 | // * - SW low ISR is used. | ||
| 131 | // * - Next event is scheduled from ISR. | ||
| 132 | // */ | ||
| 133 | // ll_intf_cmn_config_ll_ctx_params(USE_RADIO_LOW_ISR, NEXT_EVENT_SCHEDULING_FROM_ISR); | ||
| 134 | // /* Apply the selected link layer sleep timer source */ | ||
| 135 | // ll_sys_sleep_clock_source_selection(); | ||
| 136 | // | ||
| 137 | // /* USER CODE BEGIN ll_sys_config_params_1 */ | ||
| 138 | // | ||
| 139 | // /* USER CODE END ll_sys_config_params_1 */ | ||
| 140 | // | ||
| 141 | // #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) | ||
| 142 | // /* Initialize link layer temperature measurement background task */ | ||
| 143 | // ll_sys_bg_temperature_measurement_init(); | ||
| 144 | // | ||
| 145 | // /* Link layer IP uses temperature based calibration instead of periodic one */ | ||
| 146 | // ll_intf_cmn_set_temperature_sensor_state(); | ||
| 147 | // #endif /* USE_TEMPERATURE_BASED_RADIO_CALIBRATION */ | ||
| 148 | // | ||
| 149 | // /* Link Layer power table */ | ||
| 150 | // ll_intf_cmn_select_tx_power_table(CFG_RF_TX_POWER_TABLE_ID); | ||
| 151 | // | ||
| 152 | // #if (USE_CTE_DEGRADATION == 1u) | ||
| 153 | // /* Apply CTE degradation */ | ||
| 154 | // ll_sys_apply_cte_settings (); | ||
| 155 | // #endif /* (USE_CTE_DEGRADATION == 1u) */ | ||
| 156 | // | ||
| 157 | // /* USER CODE BEGIN ll_sys_config_params_2 */ | ||
| 158 | // | ||
| 159 | // /* USER CODE END ll_sys_config_params_2 */ | ||
| 160 | // } | ||
| 161 | // | ||
| 162 | // #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) | ||
| 163 | // | ||
| 164 | // /** | ||
| 165 | // * @brief Link Layer temperature request background process initialization | ||
| 166 | // * @param None | ||
| 167 | // * @retval None | ||
| 168 | // */ | ||
| 169 | // void ll_sys_bg_temperature_measurement_init(void) | ||
| 170 | // { | ||
| 171 | // /* Register Temperature Measurement task */ | ||
| 172 | // UTIL_SEQ_RegTask(1U << CFG_TASK_TEMP_MEAS, UTIL_SEQ_RFU, TEMPMEAS_RequestTemperatureMeasurement); | ||
| 173 | // } | ||
| 174 | // | ||
| 175 | // /** | ||
| 176 | // * @brief Request backroud task processing for temperature measurement | ||
| 177 | // * @param None | ||
| 178 | // * @retval None | ||
| 179 | // */ | ||
| 180 | // void ll_sys_bg_temperature_measurement(void) | ||
| 181 | // { | ||
| 182 | // static uint8_t initial_temperature_acquisition = 0; | ||
| 183 | // | ||
| 184 | // if(initial_temperature_acquisition == 0) | ||
| 185 | // { | ||
| 186 | // TEMPMEAS_RequestTemperatureMeasurement(); | ||
| 187 | // initial_temperature_acquisition = 1; | ||
| 188 | // } | ||
| 189 | // else | ||
| 190 | // { | ||
| 191 | // UTIL_SEQ_SetTask(1U << CFG_TASK_TEMP_MEAS, CFG_SEQ_PRIO_0); | ||
| 192 | // } | ||
| 193 | // } | ||
| 194 | // | ||
| 195 | // #endif /* USE_TEMPERATURE_BASED_RADIO_CALIBRATION */ | ||
| 196 | // | ||
| 197 | // uint8_t ll_sys_BLE_sleep_clock_accuracy_selection(void) | ||
| 198 | // { | ||
| 199 | // uint8_t BLE_sleep_clock_accuracy = 0; | ||
| 200 | // #if (CFG_RADIO_LSE_SLEEP_TIMER_CUSTOM_SCA_RANGE == 0) | ||
| 201 | // uint32_t RevID = LL_DBGMCU_GetRevisionID(); | ||
| 202 | // #endif | ||
| 203 | // uint32_t linklayer_slp_clk_src = LL_RCC_RADIO_GetSleepTimerClockSource(); | ||
| 204 | // | ||
| 205 | // if(linklayer_slp_clk_src == LL_RCC_RADIOSLEEPSOURCE_LSE) | ||
| 206 | // { | ||
| 207 | // /* LSE selected as Link Layer sleep clock source. | ||
| 208 | // Sleep clock accuracy is different regarding the WBA device ID and revision | ||
| 209 | // */ | ||
| 210 | // #if (CFG_RADIO_LSE_SLEEP_TIMER_CUSTOM_SCA_RANGE == 0) | ||
| 211 | // #if defined(STM32WBA52xx) || defined(STM32WBA54xx) || defined(STM32WBA55xx) | ||
| 212 | // if(RevID == REV_ID_A) | ||
| 213 | // { | ||
| 214 | // BLE_sleep_clock_accuracy = STM32WBA5x_REV_ID_A_SCA_RANGE; | ||
| 215 | // } | ||
| 216 | // else if(RevID == REV_ID_B) | ||
| 217 | // { | ||
| 218 | // BLE_sleep_clock_accuracy = STM32WBA5x_REV_ID_B_SCA_RANGE; | ||
| 219 | // } | ||
| 220 | // else | ||
| 221 | // { | ||
| 222 | // /* Revision ID not supported, default value of 500ppm applied */ | ||
| 223 | // BLE_sleep_clock_accuracy = STM32WBA5x_DEFAULT_SCA_RANGE; | ||
| 224 | // } | ||
| 225 | // #elif defined(STM32WBA65xx) | ||
| 226 | // BLE_sleep_clock_accuracy = STM32WBA6x_SCA_RANGE; | ||
| 227 | // UNUSED(RevID); | ||
| 228 | // #else | ||
| 229 | // UNUSED(RevID); | ||
| 230 | // #endif /* defined(STM32WBA52xx) || defined(STM32WBA54xx) || defined(STM32WBA55xx) */ | ||
| 231 | // #else /* CFG_RADIO_LSE_SLEEP_TIMER_CUSTOM_SCA_RANGE */ | ||
| 232 | // BLE_sleep_clock_accuracy = CFG_RADIO_LSE_SLEEP_TIMER_CUSTOM_SCA_RANGE; | ||
| 233 | // #endif /* CFG_RADIO_LSE_SLEEP_TIMER_CUSTOM_SCA_RANGE */ | ||
| 234 | // } | ||
| 235 | // else | ||
| 236 | // { | ||
| 237 | // /* LSE is not the Link Layer sleep clock source, sleep clock accurcay default value is 500 ppm */ | ||
| 238 | // BLE_sleep_clock_accuracy = STM32WBA5x_DEFAULT_SCA_RANGE; | ||
| 239 | // } | ||
| 240 | // | ||
| 241 | // return BLE_sleep_clock_accuracy; | ||
| 242 | // } | ||
| 243 | // | ||
| 244 | // void ll_sys_sleep_clock_source_selection(void) | ||
| 245 | // { | ||
| 246 | // uint16_t freq_value = 0; | ||
| 247 | // uint32_t linklayer_slp_clk_src = LL_RCC_RADIOSLEEPSOURCE_NONE; | ||
| 248 | // | ||
| 249 | // linklayer_slp_clk_src = LL_RCC_RADIO_GetSleepTimerClockSource(); | ||
| 250 | // switch(linklayer_slp_clk_src) | ||
| 251 | // { | ||
| 252 | // case LL_RCC_RADIOSLEEPSOURCE_LSE: | ||
| 253 | // linklayer_slp_clk_src = RTC_SLPTMR; | ||
| 254 | // break; | ||
| 255 | // | ||
| 256 | // case LL_RCC_RADIOSLEEPSOURCE_LSI: | ||
| 257 | // linklayer_slp_clk_src = RCO_SLPTMR; | ||
| 258 | // break; | ||
| 259 | // | ||
| 260 | // case LL_RCC_RADIOSLEEPSOURCE_HSE_DIV1000: | ||
| 261 | // linklayer_slp_clk_src = CRYSTAL_OSCILLATOR_SLPTMR; | ||
| 262 | // break; | ||
| 263 | // | ||
| 264 | // case LL_RCC_RADIOSLEEPSOURCE_NONE: | ||
| 265 | // /* No Link Layer sleep clock source selected */ | ||
| 266 | // assert_param(0); | ||
| 267 | // break; | ||
| 268 | // } | ||
| 269 | // ll_intf_cmn_le_select_slp_clk_src((uint8_t)linklayer_slp_clk_src, &freq_value); | ||
| 270 | // } | ||
| 271 | // | ||
| 272 | // void ll_sys_reset(void) | ||
| 273 | // { | ||
| 274 | // uint8_t bsca = 0; | ||
| 275 | // /* Link layer timings */ | ||
| 276 | // uint8_t drift_time = DRIFT_TIME_DEFAULT; | ||
| 277 | // uint8_t exec_time = EXEC_TIME_DEFAULT; | ||
| 278 | // | ||
| 279 | // /* USER CODE BEGIN ll_sys_reset_0 */ | ||
| 280 | // | ||
| 281 | // /* USER CODE END ll_sys_reset_0 */ | ||
| 282 | // | ||
| 283 | // /* Apply the selected link layer sleep timer source */ | ||
| 284 | // ll_sys_sleep_clock_source_selection(); | ||
| 285 | // | ||
| 286 | // /* Configure the link layer sleep clock accuracy */ | ||
| 287 | // bsca = ll_sys_BLE_sleep_clock_accuracy_selection(); | ||
| 288 | // ll_intf_le_set_sleep_clock_accuracy(bsca); | ||
| 289 | // | ||
| 290 | // /* Update link layer timings depending on selected configuration */ | ||
| 291 | // if(LL_RCC_RADIO_GetSleepTimerClockSource() == LL_RCC_RADIOSLEEPSOURCE_LSI) | ||
| 292 | // { | ||
| 293 | // drift_time += DRIFT_TIME_EXTRA_LSI2; | ||
| 294 | // exec_time += EXEC_TIME_EXTRA_LSI2; | ||
| 295 | // } | ||
| 296 | // else | ||
| 297 | // { | ||
| 298 | // #if defined(__GNUC__) && defined(DEBUG) | ||
| 299 | // drift_time += DRIFT_TIME_EXTRA_GCC_DEBUG; | ||
| 300 | // exec_time += EXEC_TIME_EXTRA_GCC_DEBUG; | ||
| 301 | // #endif | ||
| 302 | // } | ||
| 303 | // | ||
| 304 | // /* USER CODE BEGIN ll_sys_reset_1 */ | ||
| 305 | // | ||
| 306 | // /* USER CODE END ll_sys_reset_1 */ | ||
| 307 | // | ||
| 308 | // if((drift_time != DRIFT_TIME_DEFAULT) || (exec_time != EXEC_TIME_DEFAULT)) | ||
| 309 | // { | ||
| 310 | // ll_sys_config_BLE_schldr_timings(drift_time, exec_time); | ||
| 311 | // } | ||
| 312 | // /* USER CODE BEGIN ll_sys_reset_2 */ | ||
| 313 | // | ||
| 314 | // /* USER CODE END ll_sys_reset_2 */ | ||
| 315 | // } | ||
| 316 | // #if defined(STM32WBA52xx) || defined(STM32WBA54xx) || defined(STM32WBA55xx) || defined(STM32WBA65xx) | ||
| 317 | // void ll_sys_apply_cte_settings(void) | ||
| 318 | // { | ||
| 319 | // ll_intf_apply_cte_degrad_change(); | ||
| 320 | // } | ||
| 321 | // #endif /* defined(STM32WBA52xx) || defined(STM32WBA54xx) || defined(STM32WBA55xx) || defined(STM32WBA65xx) */ | ||
| 322 | // | ||
| 323 | // #if (CFG_LPM_STANDBY_SUPPORTED == 0) | ||
| 324 | // void ll_sys_get_ble_profile_statistics(uint32_t* exec_time, uint32_t* drift_time, uint32_t* average_drift_time, uint8_t reset) | ||
| 325 | // { | ||
| 326 | // if (reset != 0U) | ||
| 327 | // { | ||
| 328 | // profile_reset(); | ||
| 329 | // } | ||
| 330 | // ll_intf_get_profile_statistics(exec_time, drift_time, average_drift_time); | ||
| 331 | // } | ||
| 332 | // #endif | ||
| 333 | // | ||
| 334 | use super::bindings::{link_layer, mac}; | ||
| 335 | use super::util_seq; | ||
| 336 | |||
| 337 | const UTIL_SEQ_RFU: u32 = 0; | ||
| 338 | const TASK_LINK_LAYER_MASK: u32 = 1 << mac::CFG_TASK_ID_T_CFG_TASK_LINK_LAYER; | ||
| 339 | const TASK_PRIO_LINK_LAYER: u32 = mac::CFG_SEQ_PRIO_ID_T_CFG_SEQ_PRIO_0 as u32; | ||
| 340 | |||
| 341 | /** | ||
| 342 | * @brief Link Layer background process initialization | ||
| 343 | * @param None | ||
| 344 | * @retval None | ||
| 345 | */ | ||
| 346 | #[unsafe(no_mangle)] | ||
| 347 | pub unsafe extern "C" fn ll_sys_bg_process_init() { | ||
| 348 | util_seq::UTIL_SEQ_RegTask(TASK_LINK_LAYER_MASK, UTIL_SEQ_RFU, Some(link_layer::ll_sys_bg_process)); | ||
| 349 | } | ||
| 350 | |||
| 351 | /** | ||
| 352 | * @brief Link Layer background process next iteration scheduling | ||
| 353 | * @param None | ||
| 354 | * @retval None | ||
| 355 | */ | ||
| 356 | #[unsafe(no_mangle)] | ||
| 357 | pub unsafe extern "C" fn ll_sys_schedule_bg_process() { | ||
| 358 | util_seq::UTIL_SEQ_SetTask(TASK_LINK_LAYER_MASK, TASK_PRIO_LINK_LAYER); | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * @brief Link Layer background process next iteration scheduling from ISR | ||
| 363 | * @param None | ||
| 364 | * @retval None | ||
| 365 | */ | ||
| 366 | #[unsafe(no_mangle)] | ||
| 367 | pub unsafe extern "C" fn ll_sys_schedule_bg_process_isr() { | ||
| 368 | util_seq::UTIL_SEQ_SetTask(TASK_LINK_LAYER_MASK, TASK_PRIO_LINK_LAYER); | ||
| 369 | } | ||
| 370 | |||
| 371 | /** | ||
| 372 | * @brief Link Layer configuration phase before application startup. | ||
| 373 | * @param None | ||
| 374 | * @retval None | ||
| 375 | */ | ||
| 376 | #[unsafe(no_mangle)] | ||
| 377 | pub unsafe extern "C" fn ll_sys_config_params() { | ||
| 378 | let allow_low_isr = mac::USE_RADIO_LOW_ISR as u8; | ||
| 379 | let run_from_isr = mac::NEXT_EVENT_SCHEDULING_FROM_ISR as u8; | ||
| 380 | let _ = link_layer::ll_intf_cmn_config_ll_ctx_params(allow_low_isr, run_from_isr); | ||
| 381 | |||
| 382 | ll_sys_sleep_clock_source_selection(); | ||
| 383 | let _ = link_layer::ll_intf_cmn_select_tx_power_table(mac::CFG_RF_TX_POWER_TABLE_ID as u8); | ||
| 384 | } | ||
| 385 | |||
| 386 | /** | ||
| 387 | * @brief Reset Link Layer timing parameters to their default configuration. | ||
| 388 | * @param None | ||
| 389 | * @retval None | ||
| 390 | */ | ||
| 391 | #[unsafe(no_mangle)] | ||
| 392 | pub unsafe extern "C" fn ll_sys_reset() { | ||
| 393 | ll_sys_sleep_clock_source_selection(); | ||
| 394 | |||
| 395 | let sleep_accuracy = ll_sys_BLE_sleep_clock_accuracy_selection(); | ||
| 396 | let _ = link_layer::ll_intf_le_set_sleep_clock_accuracy(sleep_accuracy); | ||
| 397 | } | ||
| 398 | |||
| 399 | /// Select the sleep-clock source used by the Link Layer. | ||
| 400 | /// Defaults to the crystal oscillator when no explicit configuration is available. | ||
| 401 | #[unsafe(no_mangle)] | ||
| 402 | pub unsafe extern "C" fn ll_sys_sleep_clock_source_selection() { | ||
| 403 | let mut frequency: u16 = 0; | ||
| 404 | let _ = link_layer::ll_intf_cmn_le_select_slp_clk_src( | ||
| 405 | link_layer::_SLPTMR_SRC_TYPE_E_CRYSTAL_OSCILLATOR_SLPTMR as u8, | ||
| 406 | &mut frequency as *mut u16, | ||
| 407 | ); | ||
| 408 | } | ||
| 409 | |||
| 410 | /// Determine the BLE sleep-clock accuracy used by the stack. | ||
| 411 | /// Returns zero when board-specific calibration data is unavailable. | ||
| 412 | #[unsafe(no_mangle)] | ||
| 413 | pub unsafe extern "C" fn ll_sys_BLE_sleep_clock_accuracy_selection() -> u8 { | ||
| 414 | // TODO: derive the board-specific sleep clock accuracy once calibration data is available. | ||
| 415 | 0 | ||
| 416 | } | ||
diff --git a/embassy-stm32-wpan/src/wba/mac_sys_if.rs b/embassy-stm32-wpan/src/wba/mac_sys_if.rs new file mode 100644 index 000000000..273399a19 --- /dev/null +++ b/embassy-stm32-wpan/src/wba/mac_sys_if.rs | |||
| @@ -0,0 +1,188 @@ | |||
| 1 | #![cfg(feature = "wba")] | ||
| 2 | #![allow(non_snake_case)] | ||
| 3 | |||
| 4 | // | ||
| 5 | // /* USER CODE BEGIN Header */ | ||
| 6 | // /** | ||
| 7 | // ****************************************************************************** | ||
| 8 | // * @file mac_sys_if.c | ||
| 9 | // * @author MCD Application Team | ||
| 10 | // * @brief Source file for using MAC Layer with a RTOS | ||
| 11 | // ****************************************************************************** | ||
| 12 | // * @attention | ||
| 13 | // * | ||
| 14 | // * Copyright (c) 2025 STMicroelectronics. | ||
| 15 | // * All rights reserved. | ||
| 16 | // * | ||
| 17 | // * This software is licensed under terms that can be found in the LICENSE file | ||
| 18 | // * in the root directory of this software component. | ||
| 19 | // * If no LICENSE file comes with this software, it is provided AS-IS. | ||
| 20 | // * | ||
| 21 | // ****************************************************************************** | ||
| 22 | // */ | ||
| 23 | // /* USER CODE END Header */ | ||
| 24 | // | ||
| 25 | // #include "main.h" | ||
| 26 | // #include "app_common.h" | ||
| 27 | // #include "app_conf.h" | ||
| 28 | // #include "log_module.h" | ||
| 29 | // #include "stm32_rtos.h" | ||
| 30 | // #include "st_mac_802_15_4_sys.h" | ||
| 31 | // | ||
| 32 | // extern void mac_baremetal_run(void); | ||
| 33 | // | ||
| 34 | // /* Private defines -----------------------------------------------------------*/ | ||
| 35 | // /* USER CODE BEGIN PD */ | ||
| 36 | // | ||
| 37 | // /* USER CODE END PD */ | ||
| 38 | // | ||
| 39 | // /* Private macros ------------------------------------------------------------*/ | ||
| 40 | // /* USER CODE BEGIN PM */ | ||
| 41 | // | ||
| 42 | // /* USER CODE END PM */ | ||
| 43 | // | ||
| 44 | // /* Private variables ---------------------------------------------------------*/ | ||
| 45 | // /* USER CODE BEGIN PV */ | ||
| 46 | // | ||
| 47 | // /* USER CODE END PV */ | ||
| 48 | // | ||
| 49 | // /* Global variables ----------------------------------------------------------*/ | ||
| 50 | // /* USER CODE BEGIN GV */ | ||
| 51 | // | ||
| 52 | // /* USER CODE END GV */ | ||
| 53 | // | ||
| 54 | // /* Functions Definition ------------------------------------------------------*/ | ||
| 55 | // | ||
| 56 | // /** | ||
| 57 | // * @brief Mac Layer Initialisation | ||
| 58 | // * @param None | ||
| 59 | // * @retval None | ||
| 60 | // */ | ||
| 61 | // void MacSys_Init(void) | ||
| 62 | // { | ||
| 63 | // /* Register tasks */ | ||
| 64 | // UTIL_SEQ_RegTask( TASK_MAC_LAYER, UTIL_SEQ_RFU, mac_baremetal_run); | ||
| 65 | // } | ||
| 66 | // | ||
| 67 | // /** | ||
| 68 | // * @brief Mac Layer Resume | ||
| 69 | // * @param None | ||
| 70 | // * @retval None | ||
| 71 | // */ | ||
| 72 | // void MacSys_Resume(void) | ||
| 73 | // { | ||
| 74 | // UTIL_SEQ_ResumeTask( TASK_MAC_LAYER ); | ||
| 75 | // } | ||
| 76 | // | ||
| 77 | // /** | ||
| 78 | // * @brief MAC Layer set Task. | ||
| 79 | // * @param None | ||
| 80 | // * @retval None | ||
| 81 | // */ | ||
| 82 | // void MacSys_SemaphoreSet(void) | ||
| 83 | // { | ||
| 84 | // UTIL_SEQ_SetTask( TASK_MAC_LAYER, TASK_PRIO_MAC_LAYER ); | ||
| 85 | // } | ||
| 86 | // | ||
| 87 | // /** | ||
| 88 | // * @brief MAC Layer Task wait. | ||
| 89 | // * @param None | ||
| 90 | // * @retval None | ||
| 91 | // */ | ||
| 92 | // void MacSys_SemaphoreWait( void ) | ||
| 93 | // { | ||
| 94 | // /* Not used */ | ||
| 95 | // } | ||
| 96 | // | ||
| 97 | // /** | ||
| 98 | // * @brief MAC Layer set Event. | ||
| 99 | // * @param None | ||
| 100 | // * @retval None | ||
| 101 | // */ | ||
| 102 | // void MacSys_EventSet( void ) | ||
| 103 | // { | ||
| 104 | // UTIL_SEQ_SetEvt( EVENT_MAC_LAYER ); | ||
| 105 | // } | ||
| 106 | // | ||
| 107 | // /** | ||
| 108 | // * @brief MAC Layer wait Event. | ||
| 109 | // * @param None | ||
| 110 | // * @retval None | ||
| 111 | // */ | ||
| 112 | // void MacSys_EventWait( void ) | ||
| 113 | // { | ||
| 114 | // UTIL_SEQ_WaitEvt( EVENT_MAC_LAYER ); | ||
| 115 | // } | ||
| 116 | // | ||
| 117 | |||
| 118 | use super::util_seq; | ||
| 119 | use crate::bindings::mac; | ||
| 120 | |||
| 121 | /// Placeholder value used by the original ST middleware when registering tasks. | ||
| 122 | const UTIL_SEQ_RFU: u32 = 0; | ||
| 123 | |||
| 124 | /// Bit mask identifying the MAC layer task within the sequencer. | ||
| 125 | const TASK_MAC_LAYER_MASK: u32 = 1 << mac::CFG_TASK_ID_T_CFG_TASK_MAC_LAYER; | ||
| 126 | |||
| 127 | /// Sequencer priority assigned to the MAC layer task. | ||
| 128 | const TASK_PRIO_MAC_LAYER: u32 = mac::CFG_SEQ_PRIO_ID_T_CFG_SEQ_PRIO_0 as u32; | ||
| 129 | |||
| 130 | /// Event flag consumed by the MAC task while waiting on notifications. | ||
| 131 | const EVENT_MAC_LAYER_MASK: u32 = 1 << 0; | ||
| 132 | |||
| 133 | /// Registers the MAC bare-metal runner with the lightweight sequencer. | ||
| 134 | /// | ||
| 135 | /// Mirrors the behaviour of the reference implementation: | ||
| 136 | /// `UTIL_SEQ_RegTask(TASK_MAC_LAYER, UTIL_SEQ_RFU, mac_baremetal_run);` | ||
| 137 | #[unsafe(no_mangle)] | ||
| 138 | pub unsafe extern "C" fn MacSys_Init() { | ||
| 139 | util_seq::UTIL_SEQ_RegTask(TASK_MAC_LAYER_MASK, UTIL_SEQ_RFU, Some(mac::mac_baremetal_run)); | ||
| 140 | } | ||
| 141 | |||
| 142 | /** | ||
| 143 | * @brief Mac Layer Resume | ||
| 144 | * @param None | ||
| 145 | * @retval None | ||
| 146 | */ | ||
| 147 | #[unsafe(no_mangle)] | ||
| 148 | pub unsafe extern "C" fn MacSys_Resume() { | ||
| 149 | util_seq::UTIL_SEQ_ResumeTask(TASK_MAC_LAYER_MASK); | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * @brief MAC Layer set Task. | ||
| 154 | * @param None | ||
| 155 | * @retval None | ||
| 156 | */ | ||
| 157 | #[unsafe(no_mangle)] | ||
| 158 | pub unsafe extern "C" fn MacSys_SemaphoreSet() { | ||
| 159 | util_seq::UTIL_SEQ_SetTask(TASK_MAC_LAYER_MASK, TASK_PRIO_MAC_LAYER); | ||
| 160 | } | ||
| 161 | |||
| 162 | /** | ||
| 163 | * @brief MAC Layer Task wait. | ||
| 164 | * @param None | ||
| 165 | * @retval None | ||
| 166 | */ | ||
| 167 | #[unsafe(no_mangle)] | ||
| 168 | pub unsafe extern "C" fn MacSys_SemaphoreWait() {} | ||
| 169 | |||
| 170 | /** | ||
| 171 | * @brief MAC Layer set Event. | ||
| 172 | * @param None | ||
| 173 | * @retval None | ||
| 174 | */ | ||
| 175 | #[unsafe(no_mangle)] | ||
| 176 | pub unsafe extern "C" fn MacSys_EventSet() { | ||
| 177 | util_seq::UTIL_SEQ_SetEvt(EVENT_MAC_LAYER_MASK); | ||
| 178 | } | ||
| 179 | |||
| 180 | /** | ||
| 181 | * @brief MAC Layer wait Event. | ||
| 182 | * @param None | ||
| 183 | * @retval None | ||
| 184 | */ | ||
| 185 | #[unsafe(no_mangle)] | ||
| 186 | pub unsafe extern "C" fn MacSys_EventWait() { | ||
| 187 | util_seq::UTIL_SEQ_WaitEvt(EVENT_MAC_LAYER_MASK); | ||
| 188 | } | ||
diff --git a/embassy-stm32-wpan/src/wba/mod.rs b/embassy-stm32-wpan/src/wba/mod.rs new file mode 100644 index 000000000..3161b578e --- /dev/null +++ b/embassy-stm32-wpan/src/wba/mod.rs | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | pub mod bindings; | ||
| 2 | pub mod linklayer_plat; | ||
| 3 | pub mod ll_sys; | ||
| 4 | pub mod ll_sys_if; | ||
| 5 | pub mod mac_sys_if; | ||
| 6 | pub mod util_seq; | ||
diff --git a/embassy-stm32-wpan/src/wba/util_seq.rs b/embassy-stm32-wpan/src/wba/util_seq.rs new file mode 100644 index 000000000..b596df908 --- /dev/null +++ b/embassy-stm32-wpan/src/wba/util_seq.rs | |||
| @@ -0,0 +1,243 @@ | |||
| 1 | #![cfg(feature = "wba")] | ||
| 2 | |||
| 3 | use core::cell::UnsafeCell; | ||
| 4 | use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; | ||
| 5 | |||
| 6 | use critical_section::with as critical; | ||
| 7 | |||
| 8 | type TaskFn = unsafe extern "C" fn(); | ||
| 9 | |||
| 10 | const MAX_TASKS: usize = 32; | ||
| 11 | const DEFAULT_PRIORITY: u8 = u8::MAX; | ||
| 12 | |||
| 13 | struct TaskTable { | ||
| 14 | funcs: UnsafeCell<[Option<TaskFn>; MAX_TASKS]>, | ||
| 15 | priorities: UnsafeCell<[u8; MAX_TASKS]>, | ||
| 16 | } | ||
| 17 | |||
| 18 | impl TaskTable { | ||
| 19 | const fn new() -> Self { | ||
| 20 | Self { | ||
| 21 | funcs: UnsafeCell::new([None; MAX_TASKS]), | ||
| 22 | priorities: UnsafeCell::new([DEFAULT_PRIORITY; MAX_TASKS]), | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | unsafe fn set_task(&self, idx: usize, func: Option<TaskFn>, priority: u8) { | ||
| 27 | (*self.funcs.get())[idx] = func; | ||
| 28 | (*self.priorities.get())[idx] = priority; | ||
| 29 | } | ||
| 30 | |||
| 31 | unsafe fn update_priority(&self, idx: usize, priority: u8) { | ||
| 32 | (*self.priorities.get())[idx] = priority; | ||
| 33 | } | ||
| 34 | |||
| 35 | unsafe fn task(&self, idx: usize) -> Option<TaskFn> { | ||
| 36 | (*self.funcs.get())[idx] | ||
| 37 | } | ||
| 38 | |||
| 39 | unsafe fn priority(&self, idx: usize) -> u8 { | ||
| 40 | (*self.priorities.get())[idx] | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | unsafe impl Sync for TaskTable {} | ||
| 45 | |||
| 46 | #[inline(always)] | ||
| 47 | fn wake_event() { | ||
| 48 | #[cfg(target_arch = "arm")] | ||
| 49 | { | ||
| 50 | cortex_m::asm::sev(); | ||
| 51 | } | ||
| 52 | |||
| 53 | #[cfg(not(target_arch = "arm"))] | ||
| 54 | { | ||
| 55 | // No-op on architectures without SEV support. | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | #[inline(always)] | ||
| 60 | fn wait_event() { | ||
| 61 | #[cfg(target_arch = "arm")] | ||
| 62 | { | ||
| 63 | cortex_m::asm::wfe(); | ||
| 64 | } | ||
| 65 | |||
| 66 | #[cfg(not(target_arch = "arm"))] | ||
| 67 | { | ||
| 68 | core::hint::spin_loop(); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | static TASKS: TaskTable = TaskTable::new(); | ||
| 73 | static PENDING_TASKS: AtomicU32 = AtomicU32::new(0); | ||
| 74 | static EVENTS: AtomicU32 = AtomicU32::new(0); | ||
| 75 | static SCHEDULING: AtomicBool = AtomicBool::new(false); | ||
| 76 | |||
| 77 | fn mask_to_index(mask: u32) -> Option<usize> { | ||
| 78 | if mask == 0 { | ||
| 79 | return None; | ||
| 80 | } | ||
| 81 | let idx = mask.trailing_zeros() as usize; | ||
| 82 | if idx < MAX_TASKS { Some(idx) } else { None } | ||
| 83 | } | ||
| 84 | |||
| 85 | fn drain_pending_tasks() { | ||
| 86 | loop { | ||
| 87 | if SCHEDULING | ||
| 88 | .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) | ||
| 89 | .is_err() | ||
| 90 | { | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | |||
| 94 | loop { | ||
| 95 | let next = critical(|_| select_next_task()); | ||
| 96 | match next { | ||
| 97 | Some((idx, task)) => unsafe { | ||
| 98 | task(); | ||
| 99 | // Force a fresh read of the pending bitmask after each task completion. | ||
| 100 | let _ = idx; | ||
| 101 | }, | ||
| 102 | None => break, | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | SCHEDULING.store(false, Ordering::Release); | ||
| 107 | |||
| 108 | if PENDING_TASKS.load(Ordering::Acquire) == 0 { | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Poll and execute any tasks that have been scheduled via the UTIL sequencer API. | ||
| 115 | pub fn poll_pending_tasks() { | ||
| 116 | drain_pending_tasks(); | ||
| 117 | } | ||
| 118 | |||
| 119 | fn select_next_task() -> Option<(usize, TaskFn)> { | ||
| 120 | let pending = PENDING_TASKS.load(Ordering::Acquire); | ||
| 121 | if pending == 0 { | ||
| 122 | return None; | ||
| 123 | } | ||
| 124 | |||
| 125 | let mut remaining = pending; | ||
| 126 | let mut best_idx: Option<usize> = None; | ||
| 127 | let mut best_priority = DEFAULT_PRIORITY; | ||
| 128 | let mut best_fn: Option<TaskFn> = None; | ||
| 129 | |||
| 130 | while remaining != 0 { | ||
| 131 | let idx = remaining.trailing_zeros() as usize; | ||
| 132 | remaining &= remaining - 1; | ||
| 133 | |||
| 134 | if idx >= MAX_TASKS { | ||
| 135 | continue; | ||
| 136 | } | ||
| 137 | |||
| 138 | unsafe { | ||
| 139 | if let Some(func) = TASKS.task(idx) { | ||
| 140 | let prio = TASKS.priority(idx); | ||
| 141 | if prio <= best_priority { | ||
| 142 | if prio < best_priority || best_idx.map_or(true, |current| idx < current) { | ||
| 143 | best_priority = prio; | ||
| 144 | best_idx = Some(idx); | ||
| 145 | best_fn = Some(func); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | } else { | ||
| 149 | PENDING_TASKS.fetch_and(!(1u32 << idx), Ordering::AcqRel); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | if let (Some(idx), Some(func)) = (best_idx, best_fn) { | ||
| 155 | PENDING_TASKS.fetch_and(!(1u32 << idx), Ordering::AcqRel); | ||
| 156 | Some((idx, func)) | ||
| 157 | } else { | ||
| 158 | None | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | #[unsafe(no_mangle)] | ||
| 163 | pub extern "C" fn UTIL_SEQ_RegTask(task_mask: u32, _flags: u32, task: Option<TaskFn>) { | ||
| 164 | if let Some(idx) = mask_to_index(task_mask) { | ||
| 165 | critical(|_| unsafe { | ||
| 166 | TASKS.set_task(idx, task, DEFAULT_PRIORITY); | ||
| 167 | }); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | #[unsafe(no_mangle)] | ||
| 172 | pub extern "C" fn UTIL_SEQ_UnregTask(task_mask: u32) { | ||
| 173 | if let Some(idx) = mask_to_index(task_mask) { | ||
| 174 | critical(|_| unsafe { | ||
| 175 | TASKS.set_task(idx, None, DEFAULT_PRIORITY); | ||
| 176 | }); | ||
| 177 | PENDING_TASKS.fetch_and(!(task_mask), Ordering::AcqRel); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | #[unsafe(no_mangle)] | ||
| 182 | pub extern "C" fn UTIL_SEQ_SetTask(task_mask: u32, priority: u32) { | ||
| 183 | let prio = (priority & 0xFF) as u8; | ||
| 184 | |||
| 185 | if let Some(idx) = mask_to_index(task_mask) { | ||
| 186 | let registered = critical(|_| unsafe { | ||
| 187 | if TASKS.task(idx).is_some() { | ||
| 188 | TASKS.update_priority(idx, prio); | ||
| 189 | true | ||
| 190 | } else { | ||
| 191 | false | ||
| 192 | } | ||
| 193 | }); | ||
| 194 | |||
| 195 | if registered { | ||
| 196 | PENDING_TASKS.fetch_or(task_mask, Ordering::Release); | ||
| 197 | wake_event(); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | #[unsafe(no_mangle)] | ||
| 203 | pub extern "C" fn UTIL_SEQ_ResumeTask(task_mask: u32) { | ||
| 204 | PENDING_TASKS.fetch_or(task_mask, Ordering::Release); | ||
| 205 | wake_event(); | ||
| 206 | } | ||
| 207 | |||
| 208 | #[unsafe(no_mangle)] | ||
| 209 | pub extern "C" fn UTIL_SEQ_PauseTask(task_mask: u32) { | ||
| 210 | PENDING_TASKS.fetch_and(!task_mask, Ordering::AcqRel); | ||
| 211 | } | ||
| 212 | |||
| 213 | #[unsafe(no_mangle)] | ||
| 214 | pub extern "C" fn UTIL_SEQ_SetEvt(event_mask: u32) { | ||
| 215 | EVENTS.fetch_or(event_mask, Ordering::Release); | ||
| 216 | wake_event(); | ||
| 217 | } | ||
| 218 | |||
| 219 | #[unsafe(no_mangle)] | ||
| 220 | pub extern "C" fn UTIL_SEQ_ClrEvt(event_mask: u32) { | ||
| 221 | EVENTS.fetch_and(!event_mask, Ordering::AcqRel); | ||
| 222 | } | ||
| 223 | |||
| 224 | #[unsafe(no_mangle)] | ||
| 225 | pub extern "C" fn UTIL_SEQ_IsEvtSet(event_mask: u32) -> u32 { | ||
| 226 | let state = EVENTS.load(Ordering::Acquire); | ||
| 227 | if (state & event_mask) == event_mask { 1 } else { 0 } | ||
| 228 | } | ||
| 229 | |||
| 230 | #[unsafe(no_mangle)] | ||
| 231 | pub extern "C" fn UTIL_SEQ_WaitEvt(event_mask: u32) { | ||
| 232 | loop { | ||
| 233 | poll_pending_tasks(); | ||
| 234 | |||
| 235 | let current = EVENTS.load(Ordering::Acquire); | ||
| 236 | if (current & event_mask) == event_mask { | ||
| 237 | EVENTS.fetch_and(!event_mask, Ordering::AcqRel); | ||
| 238 | break; | ||
| 239 | } | ||
| 240 | |||
| 241 | wait_event(); | ||
| 242 | } | ||
| 243 | } | ||
