aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32-wpan/src/wba
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32-wpan/src/wba')
-rw-r--r--embassy-stm32-wpan/src/wba/bindings.rs1
-rw-r--r--embassy-stm32-wpan/src/wba/linklayer_plat.rs913
-rw-r--r--embassy-stm32-wpan/src/wba/ll_sys/ll_sys_cs.rs77
-rw-r--r--embassy-stm32-wpan/src/wba/ll_sys/ll_sys_dp_slp.rs163
-rw-r--r--embassy-stm32-wpan/src/wba/ll_sys/ll_sys_intf.rs199
-rw-r--r--embassy-stm32-wpan/src/wba/ll_sys/ll_sys_startup.rs125
-rw-r--r--embassy-stm32-wpan/src/wba/ll_sys/ll_version.rs115
-rw-r--r--embassy-stm32-wpan/src/wba/ll_sys/mod.rs5
-rw-r--r--embassy-stm32-wpan/src/wba/ll_sys_if.rs416
-rw-r--r--embassy-stm32-wpan/src/wba/mac_sys_if.rs188
-rw-r--r--embassy-stm32-wpan/src/wba/mod.rs6
-rw-r--r--embassy-stm32-wpan/src/wba/util_seq.rs243
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
78use core::hint::spin_loop;
79use core::ptr;
80use core::sync::atomic::{AtomicBool, AtomicI32, AtomicPtr, AtomicU32, Ordering};
81
82use cortex_m::asm::{dsb, isb};
83use cortex_m::interrupt::InterruptNumber;
84use cortex_m::peripheral::NVIC;
85use cortex_m::register::basepri;
86use critical_section;
87#[cfg(feature = "defmt")]
88use defmt::trace;
89use embassy_stm32::NVIC_PRIO_BITS;
90use embassy_time::{Duration, block_for};
91
92use 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)
96const RADIO_SW_LOW_INTR_NUM: u32 = 43;
97
98type Callback = unsafe extern "C" fn();
99
100#[derive(Clone, Copy, Debug, Eq, PartialEq)]
101#[repr(transparent)]
102struct RawInterrupt(u16);
103
104impl 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
112impl From<u32> for RawInterrupt {
113 #[inline(always)]
114 fn from(value: u32) -> Self {
115 Self::new(value)
116 }
117}
118
119unsafe impl InterruptNumber for RawInterrupt {
120 fn number(self) -> u16 {
121 self.0
122 }
123}
124
125static RADIO_CALLBACK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
126static LOW_ISR_CALLBACK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
127
128static IRQ_COUNTER: AtomicI32 = AtomicI32::new(0);
129
130static PRIO_HIGH_ISR_COUNTER: AtomicI32 = AtomicI32::new(0);
131static PRIO_LOW_ISR_COUNTER: AtomicI32 = AtomicI32::new(0);
132static PRIO_SYS_ISR_COUNTER: AtomicI32 = AtomicI32::new(0);
133static LOCAL_BASEPRI_VALUE: AtomicU32 = AtomicU32::new(0);
134
135static RADIO_SW_LOW_ISR_RUNNING_HIGH_PRIO: AtomicBool = AtomicBool::new(false);
136static AHB5_SWITCHED_OFF: AtomicBool = AtomicBool::new(false);
137static RADIO_SLEEP_TIMER_VAL: AtomicU32 = AtomicU32::new(0);
138
139static PRNG_STATE: AtomicU32 = AtomicU32::new(0);
140static 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.
144static mut CS_RESTORE_STATE: Option<critical_section::RestoreState> = None;
145
146unsafe extern "C" {
147 static SystemCoreClock: u32;
148}
149
150#[inline(always)]
151fn read_system_core_clock() -> u32 {
152 unsafe { ptr::read_volatile(&SystemCoreClock) }
153}
154
155#[inline(always)]
156fn 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)]
162fn 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)]
172fn priority_shift() -> u8 {
173 8 - NVIC_PRIO_BITS as u8
174}
175
176fn 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)]
189fn counter_release(counter: &AtomicI32) -> bool {
190 counter.fetch_sub(1, Ordering::SeqCst) <= 1
191}
192
193#[inline(always)]
194fn counter_acquire(counter: &AtomicI32) -> bool {
195 counter.fetch_add(1, Ordering::SeqCst) == 0
196}
197
198unsafe fn nvic_enable(irq: u32) {
199 NVIC::unmask(RawInterrupt::new(irq));
200 dsb();
201 isb();
202}
203
204unsafe fn nvic_disable(irq: u32) {
205 NVIC::mask(RawInterrupt::new(irq));
206 dsb();
207 isb();
208}
209
210unsafe fn nvic_set_pending(irq: u32) {
211 NVIC::pend(RawInterrupt::new(irq));
212 dsb();
213 isb();
214}
215
216unsafe fn nvic_get_active(irq: u32) -> bool {
217 NVIC::is_active(RawInterrupt::new(irq))
218}
219
220unsafe 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)]
230fn set_basepri_max(value: u8) {
231 unsafe {
232 if basepri::read() < value {
233 basepri::write(value);
234 }
235 }
236}
237
238fn 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
267pub unsafe fn run_radio_high_isr() {
268 if let Some(cb) = load_callback(&RADIO_CALLBACK) {
269 cb();
270 }
271}
272
273pub 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)]
289pub 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)]
312pub 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)]
372pub 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)]
384pub 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)]
402pub 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)]
426pub 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)]
442pub 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)]
473pub 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)]
509pub 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)]
527pub 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)]
545pub 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)]
583pub 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)]
606pub 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)]
632pub 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)]
698pub 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)]
762pub 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)]
773pub 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)]
784pub 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)]
801pub 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)]
818pub 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)]
837pub 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)]
854pub 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)]
867pub 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)]
877pub 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)]
887pub 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)]
897pub 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)]
909pub 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 @@
1use 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)]
34unsafe 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)]
44unsafe 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)]
55unsafe 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)]
65unsafe extern "C" fn ll_sys_disable_specific_irq(isr_type: u8) {
66 LINKLAYER_PLAT_DisableSpecificIRQ(isr_type);
67}
68//
69#[unsafe(no_mangle)]
70unsafe extern "C" fn ll_sys_phy_start_clbr() {
71 LINKLAYER_PLAT_PhyStartClbr();
72}
73//
74#[unsafe(no_mangle)]
75unsafe 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 @@
1use 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
10macro_rules! LL_DP_SLP_NO_WAKEUP {
11 () => {
12 !0u32
13 };
14}
15
16macro_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 */
45static mut RADIO_DP_SLP_TMR_ID: os_timer_id = NULL as *mut _;
46//
47// /* Link Layer deep sleep state */
48static 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)]
56unsafe 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)]
82unsafe 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)]
92unsafe 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)]
124unsafe 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)]
160unsafe 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 @@
1use 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)]
40unsafe 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)]
50unsafe 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)]
60unsafe 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)]
70unsafe 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)]
80unsafe 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)]
90unsafe 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)]
100unsafe 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)]
111unsafe 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)]
121unsafe 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)]
131unsafe 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)]
145unsafe 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)]
159unsafe 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)]
169unsafe 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)]
182unsafe 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)]
192unsafe 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 @@
1use 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};
6use 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 */
42static 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)]
49unsafe 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)]
60unsafe 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)]
83unsafe 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)]
95unsafe 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 */
106unsafe 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 @@
1use 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
41const 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
49macro_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)]
61struct 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// */
71const 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// */
88const 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// */
96const 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)]
103unsafe extern "C" fn ll_sys_get_brief_fw_version() -> u8 {
104 return LL_SYS_BRIEF_VERSION;
105}
106
107#[unsafe(no_mangle)]
108unsafe extern "C" fn ll_sys_get_system_fw_version() -> u32 {
109 return LL_SYS_SYSTEM_VERSION.version;
110}
111
112#[unsafe(no_mangle)]
113unsafe 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 @@
1mod ll_sys_cs;
2mod ll_sys_dp_slp;
3mod ll_sys_intf;
4mod ll_sys_startup;
5mod 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//
334use super::bindings::{link_layer, mac};
335use super::util_seq;
336
337const UTIL_SEQ_RFU: u32 = 0;
338const TASK_LINK_LAYER_MASK: u32 = 1 << mac::CFG_TASK_ID_T_CFG_TASK_LINK_LAYER;
339const 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)]
347pub 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)]
357pub 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)]
367pub 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)]
377pub 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)]
392pub 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)]
402pub 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)]
413pub 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
118use super::util_seq;
119use crate::bindings::mac;
120
121/// Placeholder value used by the original ST middleware when registering tasks.
122const UTIL_SEQ_RFU: u32 = 0;
123
124/// Bit mask identifying the MAC layer task within the sequencer.
125const 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.
128const 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.
131const 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)]
138pub 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)]
148pub 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)]
158pub 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)]
168pub 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)]
176pub 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)]
186pub 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 @@
1pub mod bindings;
2pub mod linklayer_plat;
3pub mod ll_sys;
4pub mod ll_sys_if;
5pub mod mac_sys_if;
6pub 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
3use core::cell::UnsafeCell;
4use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
5
6use critical_section::with as critical;
7
8type TaskFn = unsafe extern "C" fn();
9
10const MAX_TASKS: usize = 32;
11const DEFAULT_PRIORITY: u8 = u8::MAX;
12
13struct TaskTable {
14 funcs: UnsafeCell<[Option<TaskFn>; MAX_TASKS]>,
15 priorities: UnsafeCell<[u8; MAX_TASKS]>,
16}
17
18impl 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
44unsafe impl Sync for TaskTable {}
45
46#[inline(always)]
47fn 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)]
60fn 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
72static TASKS: TaskTable = TaskTable::new();
73static PENDING_TASKS: AtomicU32 = AtomicU32::new(0);
74static EVENTS: AtomicU32 = AtomicU32::new(0);
75static SCHEDULING: AtomicBool = AtomicBool::new(false);
76
77fn 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
85fn 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.
115pub fn poll_pending_tasks() {
116 drain_pending_tasks();
117}
118
119fn 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)]
163pub 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)]
172pub 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)]
182pub 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)]
203pub 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)]
209pub extern "C" fn UTIL_SEQ_PauseTask(task_mask: u32) {
210 PENDING_TASKS.fetch_and(!task_mask, Ordering::AcqRel);
211}
212
213#[unsafe(no_mangle)]
214pub 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)]
220pub extern "C" fn UTIL_SEQ_ClrEvt(event_mask: u32) {
221 EVENTS.fetch_and(!event_mask, Ordering::AcqRel);
222}
223
224#[unsafe(no_mangle)]
225pub 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)]
231pub 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}