diff options
Diffstat (limited to 'embassy-stm32-wpan/src/wba')
| -rw-r--r-- | embassy-stm32-wpan/src/wba/bindings.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/linklayer_plat.rs | 913 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/ll_sys/ll_sys_cs.rs | 77 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/ll_sys/ll_sys_dp_slp.rs | 163 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/ll_sys/ll_sys_intf.rs | 199 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/ll_sys/ll_sys_startup.rs | 125 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/ll_sys/ll_version.rs | 115 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/ll_sys/mod.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/ll_sys_if.rs | 416 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/mac_sys_if.rs | 188 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/mod.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/wba/util_seq.rs | 243 |
12 files changed, 2451 insertions, 0 deletions
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 | } | ||
