aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32-wpan/src/wba/linklayer_plat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32-wpan/src/wba/linklayer_plat.rs')
-rw-r--r--embassy-stm32-wpan/src/wba/linklayer_plat.rs913
1 files changed, 913 insertions, 0 deletions
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}