1 /**
2   ******************************************************************************
3   * @file    stm32wb0x_hal_radio_timer.c
4   * @author  GPM WBL Application Team
5   * @brief   Virtual timer and Radio timer high level APIs
6   * @details This file implements the software layer that provides the virtualization of the
7   * resources of a single hardware timer in order to allocate many user virtual timers.
8   * The only constraint to the number of virtual timers is the memory.
9   * Each instance of a virtual timer is placed in an queue ordered by the expiration time
10   * and it can be linked to a callback.
11   * The timer tick is in charge to execute the callback linked to each virtual timer
12   * and to update the hardware timeout to guarantee the expiration of the next virtual
13   * timer in the queue.
14   * A special virtual timer called calibration/anti-wrapping timer is automatically armed
15   * by the software. This timer can address two tasks:
16   * - it is in charge to maintain the never wrapping virtual time base.
17   * - if the slow clock calibration is enabled, it starts the calibration procedure at each
18   * calibration interval specified during the initialization.
19   *
20   * A timer is intended as an event programmed in the future at a certain absolute expiration time
21   * on a time base. In this implementation the time base grows on 64 bits. Then, it never wraps.
22   * However, due to hardware timer finite length and in order to maintain the timing coherency, the time base
23   * must be maintained at least one time before the hardware timer wraps.
24   * Then even if the slow clock calibration is disabled, the calibration/anti-wrapping timer
25   * is always active with the only role to maintain the time base and it will expire
26   * at a rate that depends on the hardware timer capability.
27   * The time base unit is a STU that is the unit exposed to the user and it is equal to 625/256 us.
28   * The calibration/anti-wrapping mechanism is not managed by the user.
29   *
30   * This software layer also exposes the possibility to program a radio timer.
31   * A radio timer allows the user to trigger an already configured radio transaction.
32   * The duties of this library does not include the configuration of a radio transaction.
33   * This layer tries to exploit the last calibration values to program the radio activity
34   * in order to improve the accuracy. In this case, the radio event is not immediately programmed
35   * when it is requested, but only when the next calibration values are available.
36   * Since the calibration values are available inside the timer tick when the calibration is over,
37   * the application must ensure that the timer tick is called after the calibration timer
38   * expiration within a certain margin in order to avoid that the radio event is shifted in the
39   * past and cannot be anymore programmed.
40   *
41   ******************************************************************************
42   * @attention
43   *
44   * Copyright (c) 2024 STMicroelectronics.
45   * All rights reserved.
46   *
47   * This software is licensed under terms that can be found in the LICENSE file
48   * in the root directory of this software component.
49   * If no LICENSE file comes with this software, it is provided AS-IS.
50   *
51   ******************************************************************************
52   */
53 
54 /* Includes ------------------------------------------------------------------*/
55 #include "stm32wb0x_hal.h"
56 
57 /** @addtogroup STM32WB0x_HAL_Driver
58   * @{
59   */
60 
61 /** @addtogroup RADIO_TIMER
62   * @brief HAL RADIO TIMER  module driver
63   * @{
64   */
65 
66 /* Private typedef -----------------------------------------------------------*/
67 
68 /** @defgroup RADIO_TIMER_Private_Types RADIO TIMER Private Types
69   * @{
70   */
71 typedef struct
72 {
73   uint8_t periodicCalibration; /*!< Periodic calibration enable status */
74   uint32_t periodicCalibrationInterval;  /*!< Periodic calibration interval in ms, to disable set to 0 */
75   bool calibration_in_progress;  /*!< Flag to indicate that a periodic calibration has been started */
76 } CalibrationSettingsTypeDef;
77 
78 typedef struct
79 {
80   uint32_t period;        /** Number of 16 MHz clock cycles in (2*(SLOW_COUNT+1)) low speed oscillator periods */
81   uint32_t freq;          /** 2^39/period */
82   int32_t freq1;          /** Round(((freq/64)*0x753)/256) */
83   int32_t period1;        /** Round (( ((period /256) * 0x8BCF6) + (((period % 256)* 0x8BCF6)/256)) / 32) */
84   int32_t last_period1;   /** Period global in last calibration */
85   uint64_t last_calibration_time; /** Absolute system time when last calibration was performed */
86   uint32_t calibration_machine_interval; /** Calibration Interval MTU */
87   uint8_t calibration_data_available; /** Flag to signal if a new calibration data is available or not */
88 } CalibrationDataTypeDef;
89 
90 typedef struct
91 {
92   uint8_t tx_cal_delay; /**time in MTU to be compensated if transmission and pll calibration are requested. The value in RAM must be initialized before the TIMER is initialized*/
93   uint8_t tx_no_cal_delay; /**time in MTU to be compensated if transmission is requested. The value in RAM must be initialized before the TIMER is initialized*/
94   uint8_t rx_cal_delay; /**time in MTU to be compensated if reception and pll calibration are requested. The value in RAM must be initialized before the TIMER is initialized*/
95   uint8_t rx_no_cal_delay; /**time in MTU to be compensated if reception is requested. The value in RAM must be initialized before the TIMER is initialized*/
96   uint8_t tx_cal_delay_st; /**time in STU to be compensated if transmission and pll calibration are requested. The value in RAM must be initialized before the TIMER is initialized*/
97   uint8_t tim12_delay_mt;
98 } TxRxDelayTypeDef;
99 
100 typedef struct
101 {
102   uint64_t expiryTime;
103   bool cal_req;
104   bool active;
105   bool pending;
106   bool intTxRx_to_be_served;
107   bool event_type;
108 } RADIO_TIMER_RadioHandleTypeDef;
109 
110 typedef struct
111 {
112   CalibrationSettingsTypeDef calibrationSettings;
113   CalibrationDataTypeDef calibrationData;
114   TxRxDelayTypeDef TxRxDelay;
115   VTIMER_HandleType calibrationTimer;
116   RADIO_TIMER_RadioHandleTypeDef radioTimer;
117   uint32_t hs_startup_time; /*!< HS startup time */
118   uint64_t cumulative_time; /** Absolute system time since power up */
119   uint64_t last_system_time; /** Last System Time */
120   uint32_t last_machine_time; /** Last machine time used to update cumulative time */
121   uint8_t last_setup_time; /**setup time of last timer programmed*/
122   uint32_t last_anchor_mt;
123   VTIMER_HandleType *rootNode; /*!< First timer of the host timer queue */
124   bool enableTimeBase;      /*!< Internal flag. User can ignore it*/
125   uint8_t expired_count; /*!< Progressive number to indicate expired timers */
126   uint8_t served_count; /*!< Progressive number to indicate served expired timers */
127   uint8_t stop_notimer_action; /*!< Flag to indicate DEEPSTOP no timer action */
128   uint8_t wakeup_calibration; /*!< Flag to indicate if start a calibration after  wakeup */
129 #if defined (STM32WB06) || defined (STM32WB07)
130   uint8_t hostIsRadioPending; /*!< If hostIsRadioPending is true, the virtual timer callback will be triggered when the wakeup timer triggers */
131   uint32_t hostMargin; /*!< It depends on the hs startup time. See HOST_MARGIN */
132   uint8_t waitCal; /*!< Wait the next calibration to get the latest values */
133 #endif
134 } RADIO_TIMER_ContextTypeDef;
135 
136 /**
137   * @}
138   */
139 
140 /* Private define ------------------------------------------------------------*/
141 /** @defgroup RADIO_TIMER_Private_Defines RADIO TIMER Private Defines
142   * @{
143   */
144 #define MULT64_THR_FREQ (806)
145 #define MULT64_THR_PERIOD (1589)
146 
147 /* Margin to add to the calibration interval in order to guarantee
148  * enough time to program the radio timer after the calibration.
149  * It is expressed in STU. */
150 #define RADIO_ACTIVITY_MARGIN (204800)
151 
152 /* Threshold to take into account the calibration duration. */
153 #define CALIB_SAFE_THR (370)
154 
155 /* Minimum threshold to safely program the radio timer (expressed in STU) */
156 #define TIMER1_MARGIN (10)
157 
158 /*  Delay to program a radio timer in the worst case (in STU).
159    This is the sum of: 1st init dalay, 2 init delay and tx delay (118 + 65 + 2)  */
160 #define TIMER1_INIT_DELAY (76)
161 
162 /* Radio event types */
163 #define RX (0)
164 #define TX (1)
165 
166 #define MARGIN_EXT (200)
167 
168 /* Minimum threshold in STU to safely clear radio timers.
169 The wakeup timer in the worst case triggers about 30us in advance.
170 This must be considered when the radio timer is cleared.
171 Then a window of about 30 us is considered as critical, that is
172 it is not sure the timer can be cleared properly */
173 #define CLEAR_MIN_THR (15)
174 
175 /* Extra margin to consider before going in low power mode.
176    This is the time (STU) needed for the system to go to sleep from the time the
177    HAL_RADIO_TIMER_PowerSaveLevelCheck() is called. */
178 #define LOW_POWER_THR (82)  // Around 200 us.
179 
180 #if defined (STM32WB06) || defined (STM32WB07)
181 /* HOST_MARGIN is the margin in STU needed to program a pending radio operation after the host timer is triggered */
182 #define HOST_MARGIN (200)
183 
184 #define RADIO_TX_RX_EXCEPTION_NUMBER 18
185 #endif
186 
187 /**
188   * @}
189   */
190 
191 /* Private macros ------------------------------------------------------------*/
192 
193 /** @defgroup RADIO_TIMER_Private_Macros RADIO TIMER Private Macros
194   * @{
195   */
196 
197 #define ATOMIC_SECTION_BEGIN() uint32_t uwPRIMASK_Bit = __get_PRIMASK(); \
198   __disable_irq(); \
199   /* Must be called in the same scope of ATOMIC_SECTION_BEGIN */
200 #define ATOMIC_SECTION_END() __set_PRIMASK(uwPRIMASK_Bit)
201 
202 #define MAX(a,b) ((a) < (b) )? (b) : (a)
203 #define MIN(a,b) ((a) < (b) )? (a) : (b)
204 #define DIFF8(a,b) ((a)>=(b) ? ((a)-(b)) : (256+((a)-(b))))
205 #define TIME_DIFF(a, b)       (((int32_t)((a - b) << (32-TIMER_BITS))) >> (32-TIMER_BITS))
206 /* This define assumes that a is always greater than b */
207 #define TIME_ABSDIFF(a, b)       ((a - b) & TIMER_MAX_VALUE)
208 #define INCREMENT_EXPIRE_COUNT_ISR (RADIO_TIMER_Context.expired_count\
209                                     = ((RADIO_TIMER_Context.expired_count + 1) == RADIO_TIMER_Context.served_count) ? RADIO_TIMER_Context.expired_count : (RADIO_TIMER_Context.expired_count + 1))
210 #define INCREMENT_EXPIRE_COUNT ATOMIC_SECTION_BEGIN(); INCREMENT_EXPIRE_COUNT_ISR ; ATOMIC_SECTION_END();
211 
212 /**
213   * @}
214   */
215 
216 /* Private variables ---------------------------------------------------------*/
217 /** @defgroup RADIO_TIMER_Private_Variables RADIO TIMER Private Variables
218   * @{
219   */
220 static RADIO_TIMER_ContextTypeDef RADIO_TIMER_Context;
221 /**
222   * @}
223   */
224 
225 /* Private constants ---------------------------------------------------------*/
226 /** @defgroup RADIO_TIMER_Private_Constants  RADIO TIMER Private Constants
227   * @{
228   */
229 #define TIMER_SYSTICK_PER_FIVE_SECONDS (2048000)
230 #define TIMER_SYSTICK_PER_SECOND       (409600)
231 #define TIMER_SYSTICK_PER_10MS         (4096)
232 
233 /** Margin arging to take for long sleep to allow the
234   * system to avoid to have the counter wrapping. It is expressed in machine
235   * time, so it is variable when using internal RO
236   */
237 #define TIMER_WRAPPING_MARGIN (4096)
238 /** Number of significant bits in the radio timer */
239 #define TIMER_BITS (32)
240 #define TIMER_MAX_VALUE (0xFFFFFFFFU >> (32-TIMER_BITS))
241 
242 #define WAKEUP_INIT_DELAY (27) /* about 65us in STU */
243 /**
244   * @}
245   */
246 
247 /* Private function prototypes -----------------------------------------------*/
248 /** @addtogroup RADIO_TIMER_Private_Functions
249   * @{
250   */
251 /* Privati Calibration APIs */
252 static void _calibrationProcedure(void);
253 static void _timer_start_calibration(void);
254 static void _timer_calibrate(CalibrationDataTypeDef *calibrationData);
255 static void _get_calibration_data(CalibrationDataTypeDef *calibrationData);
256 static void _calibration_callback(void *handle);
257 static void _updateCalibrationData(void);
258 
259 static uint32_t _us_to_systime(uint32_t time);
260 static uint32_t _us_to_machinetime(uint32_t time);
261 static void _configureTxRxDelay(RADIO_TIMER_ContextTypeDef *context, uint8_t calculate_st);
262 static void _update_xtal_startup_time(uint16_t hs_startup_time, int32_t freq1);
263 uint32_t blue_unit_conversion(uint32_t time, uint32_t period_freq,
264                               uint32_t thr); /* Translate MTU to STU and vice-versa. It is implemented using integer operation. */
265 static uint64_t _get_system_time_and_machine(RADIO_TIMER_ContextTypeDef *context, uint32_t *current_machine_time);
266 static int32_t _start_timer(VTIMER_HandleType *timerHandle, uint64_t time);
267 static VTIMER_HandleType *_update_user_timeout(VTIMER_HandleType *rootNode, uint8_t *expired);
268 static VTIMER_HandleType *_insert_timer_in_queue(VTIMER_HandleType *rootNode, VTIMER_HandleType *handle);
269 static void _virtualTimeBaseEnable(FunctionalState state);
270 static VTIMER_HandleType *_remove_timer_in_queue(VTIMER_HandleType *rootNode, VTIMER_HandleType *handle);
271 static VTIMER_HandleType *_check_callbacks(VTIMER_HandleType *rootNode, VTIMER_HandleType **expiredList);
272 static void _update_system_time(RADIO_TIMER_ContextTypeDef *context);
273 static void _check_radio_activity(RADIO_TIMER_RadioHandleTypeDef *timerHandle, uint8_t *expired);
274 #if defined (STM32WB06) || defined (STM32WB07)
275 static uint32_t TIMER_SetRadioHostWakeupTime(uint32_t delay, bool *share);
276 static void _set_controller_as_host(void);
277 static void _check_host_activity(void);
278 #else
279 static uint32_t VTIMER_SetWakeupTime(uint32_t delay, bool allow_sleep);
280 #endif
281 static uint8_t TIMER_SetRadioTimerValue(uint32_t timeout, bool event_type, bool cal_req);
282 static uint64_t TIMER_GetPastSysTime(uint32_t time, uint64_t *current_system_time);
283 static bool TIMER_SleepCheck(void);
284 static uint8_t TIMER_GetRadioTimerValue(uint32_t *time);
285 /**
286   * @}
287   */
288 
289 /* Exported functions --------------------------------------------------------*/
290 
291 /** @defgroup RADIO_TIMER_Exported_Functions Radio Timer Exported Functions
292   * @{
293   */
294 
295 /* ------------------------ RADIO Init APIs ----------------------------------*/
296 /**
297   * @brief  Initialize the radio timer module. It must be placed in the initialization
298   *         section of the application.
299   * @param RADIO_TIMER_InitStruct Radio Timer Initialization parameters
300   * @retval None
301   */
HAL_RADIO_TIMER_Init(RADIO_TIMER_InitTypeDef * RADIO_TIMER_InitStruct)302 void HAL_RADIO_TIMER_Init(RADIO_TIMER_InitTypeDef *RADIO_TIMER_InitStruct)
303 {
304   /* Interrupt Configuration */
305   LL_RADIO_TIMER_ClearFlag_CPUWakeup(WAKEUP);
306   LL_RADIO_TIMER_EnableCPUWakeupIT(WAKEUP);
307   NVIC_EnableIRQ(RADIO_TIMER_CPU_WKUP_IRQn);
308   NVIC_EnableIRQ(RADIO_TIMER_ERROR_IRQn);
309 
310 #if defined (STM32WB06) || defined (STM32WB07)
311   LL_RADIO_TIMER_ClearFlag_BLEWakeup(WAKEUP);
312   LL_RADIO_TIMER_EnableBLEWakeupIT(WAKEUP);
313   NVIC_EnableIRQ(RADIO_TIMER_TXRX_WKUP_IRQn);
314   RADIO_TIMER_Context.hostMargin = MAX(HOST_MARGIN, RADIO_TIMER_InitStruct->XTAL_StartupTime);
315 #endif
316 
317   /* Calibration Setting */
318   RADIO_TIMER_Context.calibrationSettings.periodicCalibration = (RADIO_TIMER_InitStruct->periodicCalibrationInterval != 0);
319   if (RADIO_TIMER_Context.calibrationSettings.periodicCalibration || RADIO_TIMER_InitStruct->enableInitialCalibration)
320   {
321     _calibrationProcedure();
322   }
323   else
324   {
325     /* Assume fix frequency at 32.768 kHz */
326     RADIO_TIMER_Context.calibrationData.last_period1 = 0x00190000;
327     RADIO_TIMER_Context.calibrationData.period1 = 0x00190000 ;
328     RADIO_TIMER_Context.calibrationData.freq1 = 0x0028F5C2 ;
329     RADIO_TIMER_Context.calibrationData.period = 23437;
330     RADIO_TIMER_Context.calibrationData.freq = 23456748;
331   }
332   if (RADIO_TIMER_InitStruct->periodicCalibrationInterval == 0)
333   {
334     RADIO_TIMER_Context.calibrationSettings.periodicCalibrationInterval = HAL_RADIO_TIMER_MachineTimeToSysTime(0x50000000);
335   }
336   else
337   {
338     RADIO_TIMER_Context.calibrationSettings.periodicCalibrationInterval = (TIMER_SYSTICK_PER_10MS * RADIO_TIMER_InitStruct->periodicCalibrationInterval) / 10;
339     RADIO_TIMER_Context.calibrationSettings.periodicCalibrationInterval = MIN(RADIO_TIMER_Context.calibrationSettings.periodicCalibrationInterval,
340                                                                               HAL_RADIO_TIMER_MachineTimeToSysTime(TIMER_MAX_VALUE - TIMER_WRAPPING_MARGIN));
341   }
342   RADIO_TIMER_Context.calibrationSettings.calibration_in_progress = FALSE;
343 
344   /* XTAL startup time configuration */
345   RADIO_TIMER_Context.hs_startup_time = RADIO_TIMER_InitStruct->XTAL_StartupTime;
346   _update_xtal_startup_time(RADIO_TIMER_Context.hs_startup_time, RADIO_TIMER_Context.calibrationData.freq1);
347 
348   /* Init Radio Timer Context */
349   RADIO_TIMER_Context.last_setup_time = 0;
350   RADIO_TIMER_Context.cumulative_time = 0;
351   RADIO_TIMER_Context.last_machine_time = LL_RADIO_TIMER_GetAbsoluteTime(WAKEUP);
352   RADIO_TIMER_Context.last_system_time = 0;
353   RADIO_TIMER_Context.calibrationData.last_calibration_time = 0;
354   RADIO_TIMER_Context.calibrationData.calibration_data_available = 0;
355   RADIO_TIMER_Context.calibrationData.calibration_machine_interval = blue_unit_conversion(RADIO_TIMER_Context.calibrationSettings.periodicCalibrationInterval,
356                                                                      RADIO_TIMER_Context.calibrationData.freq1, MULT64_THR_FREQ);
357   RADIO_TIMER_Context.wakeup_calibration = RADIO_TIMER_Context.calibrationSettings.periodicCalibration;
358 
359   /* Init the Virtual Timer queue */
360   RADIO_TIMER_Context.rootNode = NULL;
361   RADIO_TIMER_Context.enableTimeBase = TRUE;
362   RADIO_TIMER_Context.stop_notimer_action = FALSE;
363   RADIO_TIMER_Context.expired_count = 0;
364   RADIO_TIMER_Context.served_count = 0;
365 
366   /* Init Radio Timer queue */
367   RADIO_TIMER_Context.radioTimer.active = FALSE;
368   RADIO_TIMER_Context.radioTimer.pending = FALSE;
369   RADIO_TIMER_Context.radioTimer.intTxRx_to_be_served = FALSE;
370   RADIO_TIMER_Context.radioTimer.expiryTime = 0;
371 
372   /* Configure the Calibration callback and schedule the next calibration */
373   RADIO_TIMER_Context.calibrationTimer.callback = _calibration_callback;
374   RADIO_TIMER_Context.calibrationTimer.userData = NULL;
375   _start_timer(&RADIO_TIMER_Context.calibrationTimer,
376                HAL_RADIO_TIMER_GetCurrentSysTime() + RADIO_TIMER_Context.calibrationSettings.periodicCalibrationInterval);
377 
378   /* Tx & Rx delay configuration */
379   _configureTxRxDelay(&RADIO_TIMER_Context, TRUE);
380 }
381 
382 /**
383   * @brief Timer module state machine. Check and schedule the calibration.
384   * Check expired timers and execute user callback.
385   * It must be placed inside the infinite loop.
386   * @retval None
387   */
HAL_RADIO_TIMER_Tick(void)388 void HAL_RADIO_TIMER_Tick(void)
389 {
390   uint8_t expired = 0;
391 
392   ATOMIC_SECTION_BEGIN();
393   if (RADIO_TIMER_Context.radioTimer.active)
394   {
395     if (RADIO_TIMER_Context.radioTimer.expiryTime < HAL_RADIO_TIMER_GetCurrentSysTime())
396     {
397       RADIO_TIMER_Context.radioTimer.active = FALSE;
398     }
399   }
400   ATOMIC_SECTION_END();
401 
402   /* Check for expired timers */
403   while (DIFF8(RADIO_TIMER_Context.expired_count, RADIO_TIMER_Context.served_count))
404   {
405     VTIMER_HandleType *expiredList, *curr;
406     uint8_t to_be_served = DIFF8(RADIO_TIMER_Context.expired_count, RADIO_TIMER_Context.served_count);
407 
408     RADIO_TIMER_Context.rootNode = _check_callbacks(RADIO_TIMER_Context.rootNode, &expiredList);
409 
410     /* Call all the user callbacks */
411     curr = expiredList;
412     while (curr != NULL)
413     {
414       /* Save next pointer, in case callback start the timer again */
415       VTIMER_HandleType *next = curr->next;
416       curr->active = FALSE;
417       if (curr->callback)
418       {
419         curr->callback(curr); /* we are sure a callback is set?*/
420       }
421       curr = next;
422     }
423 
424     RADIO_TIMER_Context.rootNode = _update_user_timeout(RADIO_TIMER_Context.rootNode, &expired);
425     if (expired == 1)
426     {
427       /* A new root timer is already expired, mimic timer expire */
428       INCREMENT_EXPIRE_COUNT;
429     }
430     RADIO_TIMER_Context.served_count += to_be_served;
431   }
432 
433   /* Check for periodic calibration */
434   if (RADIO_TIMER_Context.calibrationSettings.calibration_in_progress)
435   {
436     if (LL_RADIO_TIMER_IsActiveFlag_LSICalibrationEnded(RADIO_CTRL))
437     {
438       /* Calibration is completed */
439       RADIO_TIMER_Context.calibrationSettings.calibration_in_progress = FALSE;
440       if ((RADIO_TIMER_Context.wakeup_calibration == FALSE) && RADIO_TIMER_Context.stop_notimer_action)
441       {
442         RADIO_TIMER_Context.stop_notimer_action = FALSE;
443       }
444       else
445       {
446         /* Collect calibration data */
447         _updateCalibrationData();
448       }
449 
450 #if defined (STM32WB06) || defined (STM32WB07)
451       if (RADIO_TIMER_Context.waitCal)
452       {
453         RADIO_TIMER_Context.waitCal = 0;
454         RADIO_TIMER_Context.radioTimer.pending = TRUE;
455         _check_radio_activity(&RADIO_TIMER_Context.radioTimer, &expired);
456         RADIO_TIMER_Context.rootNode = _update_user_timeout(RADIO_TIMER_Context.rootNode, &expired);
457       }
458 #else
459       _check_radio_activity(&RADIO_TIMER_Context.radioTimer, &expired);
460 #endif
461 
462       HAL_RADIO_TIMER_StopVirtualTimer(&RADIO_TIMER_Context.calibrationTimer);
463       /* Schedule next calibration event */
464       _start_timer(&RADIO_TIMER_Context.calibrationTimer,
465                    HAL_RADIO_TIMER_GetCurrentSysTime() + RADIO_TIMER_Context.calibrationSettings.periodicCalibrationInterval);
466     }
467   }
468   /* if there is a periodic calibration, start it in advance during the active phase */
469   else
470   {
471     if (RADIO_TIMER_Context.calibrationSettings.periodicCalibration)
472     {
473       if (HAL_RADIO_TIMER_GetCurrentSysTime() > (RADIO_TIMER_Context.calibrationData.last_calibration_time +
474                                                  TIMER_SYSTICK_PER_FIVE_SECONDS))
475       {
476         _calibration_callback(&RADIO_TIMER_Context.calibrationTimer);
477       }
478     }
479   }
480 }
481 
482 /**
483   * @brief  Return the status of the radio timer.
484   *         The timeout of the last radio timer activity taken into account by the Timer Module
485   *         is saved in the variable passed as parameter.
486   * @param  time: Pointer of the variable where the time of the last radio activity scheduled is stored
487   *               The time is expressed in STU.
488   * @retval 0 if no radio timer is pending.
489   * @retval 1 if a radio timer is pending.
490   */
HAL_RADIO_TIMER_GetRadioTimerStatus(uint64_t * time)491 RADIO_TIMER_Status HAL_RADIO_TIMER_GetRadioTimerStatus(uint64_t *time)
492 {
493   RADIO_TIMER_Status status;
494 
495   *time = RADIO_TIMER_Context.radioTimer.expiryTime;
496   if ((RADIO_TIMER_Context.radioTimer.pending) || (LL_RADIO_TIMER_IsEnabledBLEWakeupTimer(WAKEUP))
497       || (LL_RADIO_TIMER_IsEnabledTimer1(BLUE)))
498   {
499     status =  RADIO_TIMER_PENDING;
500   }
501   else
502   {
503     status = RADIO_TIMER_OFF;
504   }
505   return status;
506 }
507 
508 /**
509   * @brief Get the last anchorPoint in system time unit.
510   * @param current_system_time: Current System Time
511   * @return TimerCapture register in system time unit.
512   */
HAL_RADIO_TIMER_GetAnchorPoint(uint64_t * current_system_time)513 uint64_t HAL_RADIO_TIMER_GetAnchorPoint(uint64_t *current_system_time)
514 {
515   return TIMER_GetPastSysTime(BLUE->TIMERCAPTUREREG, current_system_time);
516 }
517 
518 /**
519   * @brief  Returns the admitted low power mode according to the next timer activity.
520   * @return Low Power mode
521   */
HAL_RADIO_TIMER_PowerSaveLevelCheck(void)522 PowerSaveLevels HAL_RADIO_TIMER_PowerSaveLevelCheck(void)
523 {
524   uint32_t nextRadioActivity;
525   uint8_t timerState;
526   uint64_t current_time;
527   PowerSaveLevels level;
528 
529   if (TIMER_SleepCheck() == FALSE)
530   {
531     return POWER_SAVE_LEVEL_RUNNING;
532   }
533 
534   level = POWER_SAVE_LEVEL_STOP;
535 
536   current_time = HAL_RADIO_TIMER_GetCurrentSysTime();
537   timerState = TIMER_GetRadioTimerValue(&nextRadioActivity);
538 
539   /*Timer1 and wakeup timer are programmed only through the timer module*/
540   if (((RADIO_TIMER_Context.radioTimer.active || RADIO_TIMER_Context.radioTimer.pending)
541        && !(timerState == RADIO_TIMER1_BUSY)) || RADIO_TIMER_Context.radioTimer.intTxRx_to_be_served)
542   {
543     if (RADIO_TIMER_Context.radioTimer.expiryTime < (current_time + \
544                                                      RADIO_TIMER_Context.last_setup_time + \
545                                                      RADIO_TIMER_Context.hs_startup_time + \
546                                                      LOW_POWER_THR))
547     {
548       return POWER_SAVE_LEVEL_CPU_HALT;
549     }
550 
551     level = POWER_SAVE_LEVEL_STOP_LS_CLOCK_ON;
552   }
553   else
554   {
555     if ((timerState == RADIO_TIMER2_BUSY) || (timerState == RADIO_TIMER1_BUSY))
556     {
557       return POWER_SAVE_LEVEL_CPU_HALT;
558     }
559   }
560 
561   if (RADIO_TIMER_Context.rootNode != NULL && RADIO_TIMER_Context.rootNode->active)
562   {
563     if (RADIO_TIMER_Context.rootNode->expiryTime < (current_time + LOW_POWER_THR + RADIO_TIMER_Context.hs_startup_time))
564     {
565       return POWER_SAVE_LEVEL_CPU_HALT;
566     }
567 
568     if (level == POWER_SAVE_LEVEL_STOP)
569     {
570       if ((RADIO_TIMER_Context.rootNode->next == NULL)
571           && (RADIO_TIMER_Context.rootNode == &RADIO_TIMER_Context.calibrationTimer))
572       {
573         RADIO_TIMER_Context.stop_notimer_action = TRUE;
574         _virtualTimeBaseEnable(DISABLE);
575         LL_RADIO_TIMER_DisableCPUWakeupTimer(WAKEUP);
576         return POWER_SAVE_LEVEL_STOP;
577       }
578     }
579     level = POWER_SAVE_LEVEL_STOP_LS_CLOCK_ON;
580   }
581 
582   return level;
583 }
584 
585 /* ---------------------- RADIO Activity APIs --------------------------------*/
586 /**
587   * @brief  Schedules a radio activity for the given absolute timeout value expressed in STU.
588   *         If the calibration of the low speed oscillator is needed, if it is possible,
589   *         the radio timer will be programmed with the latest calibration data.
590   * @param  time: Absolute time expressed in STU.
591   * @param  event_type: Specify if it is a TX (1) or RX (0) event.
592   * @param  cal_req: Specify if PLL calibration is requested (1) or not (0).
593   * @retval 0 if radio activity has been scheduled successfully.
594   * @retval 1 if radio activity has been rejected (it is too close or in the past).
595   */
HAL_RADIO_TIMER_SetRadioTimerValue(uint32_t time,uint8_t event_type,uint8_t cal_req)596 uint32_t HAL_RADIO_TIMER_SetRadioTimerValue(uint32_t time, uint8_t event_type, uint8_t cal_req)
597 {
598   uint8_t retVal = 0;
599 #if defined (STM32WB06) || defined (STM32WB07)
600   uint64_t current_time;
601 #endif
602 
603   RADIO_TIMER_Context.radioTimer.event_type = event_type;
604   RADIO_TIMER_Context.radioTimer.cal_req = cal_req;
605   RADIO_TIMER_Context.radioTimer.expiryTime = RADIO_TIMER_Context.calibrationData.last_calibration_time + (uint32_t)(time - (uint32_t)RADIO_TIMER_Context.calibrationData.last_calibration_time);
606   RADIO_TIMER_Context.radioTimer.active = FALSE;
607   RADIO_TIMER_Context.radioTimer.intTxRx_to_be_served = FALSE;
608   RADIO_TIMER_Context.radioTimer.pending = TRUE;
609 
610 #if defined (STM32WB06) || defined (STM32WB07)
611   current_time = HAL_RADIO_TIMER_GetCurrentSysTime();
612 
613   if (RADIO_TIMER_Context.rootNode == NULL)
614   {
615     _check_radio_activity(&RADIO_TIMER_Context.radioTimer, &retVal);
616   }
617   else
618   {
619     if (RADIO_TIMER_Context.rootNode->expiryTime < current_time ||
620         ((RADIO_TIMER_Context.radioTimer.expiryTime < (RADIO_TIMER_Context.rootNode->expiryTime +
621                                                        RADIO_TIMER_Context.hostMargin)) && RADIO_TIMER_Context.rootNode->active) || !RADIO_TIMER_Context.rootNode->active)
622     {
623       /* Program the radio timer */
624       _check_radio_activity(&RADIO_TIMER_Context.radioTimer, &retVal);
625       if ((RADIO_TIMER_Context.radioTimer.expiryTime >= RADIO_TIMER_Context.rootNode->expiryTime)
626           && RADIO_TIMER_Context.rootNode->active)
627       {
628         /*The radio operation is before or too close the host timeout*/
629         RADIO_TIMER_Context.hostIsRadioPending = 1;
630       }
631     }
632     else
633     {
634       /* If radio timer is not programmed, an emulated host timer is already programmed.
635       Make sure radio errors are disabled.
636       This call is not needed if radio errors are not enabled by the BLE stack. */
637       _set_controller_as_host();
638     }
639   }
640 #else
641   _check_radio_activity(&RADIO_TIMER_Context.radioTimer, &retVal);
642 #endif
643 
644   _virtualTimeBaseEnable(ENABLE);
645 
646   return retVal;
647 }
648 
649 /**
650   * @brief   Programs Timer1 with a relative timeout - expressed in us - wrt the previous radio event.
651   * @param   rel_timeout_us: relative delay, in us, wrt the previous radio event.
652   * @param   event_type: 1 Tx event.
653                          0 Rx event
654   * @param   cal_req: 1 PLL calibartion is requested.
655                       0 PLL calibartion is not requested.
656   * @warning The API must be called with interrupts disabled to avoid programming the timer with a value in the past
657   * @retval  0 if a correct timeout has been programmed in the timeout register
658   * @retval  1 if a correct timeout cannot be programmed
659   */
HAL_RADIO_TIMER_SetRadioTimerRelativeUsValue(uint32_t rel_timeout_us,bool event_type,bool cal_req)660 uint32_t HAL_RADIO_TIMER_SetRadioTimerRelativeUsValue(uint32_t rel_timeout_us, bool event_type, bool cal_req)
661 {
662   uint32_t event_time;
663   uint32_t radio_init_delay;
664   uint32_t abs_timeout_mt;
665   uint32_t current_machine_time;
666 
667   /*choose the 2nd init duration. Check the event_type and cal. request*/
668   if (event_type == TX)
669   {
670     if (cal_req)
671     {
672       radio_init_delay = RADIO_TIMER_Context.TxRxDelay.tx_cal_delay;
673     }
674     else
675     {
676       radio_init_delay = RADIO_TIMER_Context.TxRxDelay.tx_no_cal_delay;
677     }
678   }
679   else
680   {
681     if (cal_req)
682     {
683       radio_init_delay = RADIO_TIMER_Context.TxRxDelay.rx_cal_delay;
684     }
685     else
686     {
687       radio_init_delay = RADIO_TIMER_Context.TxRxDelay.rx_no_cal_delay;
688     }
689   }
690 
691   abs_timeout_mt =  RADIO_TIMER_Context.last_anchor_mt + _us_to_machinetime(rel_timeout_us);
692 
693   event_time = (abs_timeout_mt - RADIO_TIMER_Context.TxRxDelay.tim12_delay_mt - radio_init_delay) & TIMER_MAX_VALUE;
694 
695   current_machine_time = WAKEUP->ABSOLUTE_TIME;
696 
697   if ((event_time - current_machine_time) > 0x80000000)
698   {
699     /* Requested time is in the past, return error */
700     return 1;
701   }
702 
703   LL_RADIO_TIMER_SetTimeout(BLUE, event_time);
704   LL_RADIO_TIMER_EnableTimer1(BLUE);
705   LL_RADIO_TIMER_DisableBLEWakeupTimer(WAKEUP);
706 
707 #if defined (STM32WB06) || defined (STM32WB07)
708   BLUEGLOB->BYTE4 |= 1 << 7;
709   BLUEGLOB->BYTE22 = 0xF0;
710   BLUEGLOB->BYTE23 = 0xFF;
711 #endif
712 
713   RADIO_TIMER_Context.last_anchor_mt = abs_timeout_mt & TIMER_MAX_VALUE;
714 
715   radio_init_delay += RADIO_TIMER_Context.TxRxDelay.tim12_delay_mt;
716   RADIO_TIMER_Context.last_setup_time = blue_unit_conversion(radio_init_delay, RADIO_TIMER_Context.calibrationData.period1, MULT64_THR_PERIOD);
717 
718   return 0;
719 }
720 
721 /**
722   * @brief  Return the status of the Radio timers and the last value programmed in the register.
723   * @note   When Timer2 is on schedule, the time is expressed in microseconds, otherwise in absolute machine time units.
724   * @param  time: pointer to value which is going to have time value.
725   * @retval 0 if no timer has been programmed.
726   * @retval 1 if Timer1 has been programmed.
727   * @retval 2 if Timer2 has been programmed.
728   * @retval 3 if Wakeup Timer has been programmed.
729   */
HAL_RADIO_TIMER_GetRadioTimerValue(uint32_t * time)730 uint8_t HAL_RADIO_TIMER_GetRadioTimerValue(uint32_t *time)
731 {
732   return TIMER_GetRadioTimerValue(time);
733 }
734 
735 /**
736   * @brief  Clear the last radio activity scheduled disabling the radio timers too.
737   *         Furthermore, it returns if the timeout is too close with respect the current time and
738   *         the radio activity might not be cleared in time.
739   * @retval 0 if the radio activity has been cleared successfully.
740   * @retval 1 if it is too late to clear the last radio activity.
741   * @retval 2 if it might not be possible to clear the last radio activity.
742   */
HAL_RADIO_TIMER_ClearRadioTimerValue(void)743 uint32_t HAL_RADIO_TIMER_ClearRadioTimerValue(void)
744 {
745   int64_t time_diff;
746   uint8_t retVal;
747 
748   /* Disable Radio Timer1/2 and BLE Wakeup Timer */
749   LL_RADIO_TIMER_DisableTimer1(BLUE);
750   LL_RADIO_TIMER_DisableTimer2(BLUE);
751   LL_RADIO_TIMER_DisableBLEWakeupTimer(WAKEUP);
752   RADIO_TIMER_Context.radioTimer.active = FALSE;
753   RADIO_TIMER_Context.radioTimer.pending = FALSE;
754   RADIO_TIMER_Context.radioTimer.intTxRx_to_be_served = FALSE;
755 
756   /*The rfSetup is different if Timer1 or Wakeup timer is programmed*/
757   ATOMIC_SECTION_BEGIN();
758   time_diff = RADIO_TIMER_Context.radioTimer.expiryTime \
759               - HAL_RADIO_TIMER_GetCurrentSysTime() \
760               - RADIO_TIMER_Context.last_setup_time;
761   ATOMIC_SECTION_END();
762 
763 #if defined (STM32WB06) || defined (STM32WB07)
764   /* Check if the routine is executed in the Tx/Rx interrupt handler or not */
765   if (((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) - 16) != RADIO_TX_RX_EXCEPTION_NUMBER)
766   {
767     _check_host_activity();
768   }
769 #endif
770 
771   if (time_diff <= 0)
772   {
773     retVal = HAL_RADIO_TIMER_LATE;
774   }
775   else if (time_diff < CLEAR_MIN_THR)
776   {
777     retVal = HAL_RADIO_TIMER_CRITICAL;
778   }
779   else
780   {
781     retVal = HAL_RADIO_TIMER_SUCCESS;
782   }
783 
784   return retVal;
785 }
786 
787 /**
788   * @brief Program the radio timer (a.k.a Timer1) as close as possible.
789   *        The current time is sampled and increased by two.
790   *        It means that the timer is going to trigger in a timer interval that goes
791   *        from one to two machine time units.
792   */
HAL_RADIO_TIMER_SetRadioCloseTimeout(void)793 void HAL_RADIO_TIMER_SetRadioCloseTimeout(void)
794 {
795   uint32_t current_time;
796 
797   ATOMIC_SECTION_BEGIN();
798   current_time = LL_RADIO_TIMER_GetAbsoluteTime(WAKEUP);
799   LL_RADIO_TIMER_SetTimeout(BLUE, ((current_time + 2) & TIMER_MAX_VALUE));
800   LL_RADIO_TIMER_EnableTimer1(BLUE);
801   ATOMIC_SECTION_END();
802 }
803 
804 /**
805   * @brief  Radio activity finished.
806   * @retval None
807   */
HAL_RADIO_TIMER_RadioTimerIsr(void)808 void HAL_RADIO_TIMER_RadioTimerIsr(void)
809 {
810 #if defined (STM32WB06) || defined (STM32WB07)
811   if (!(LL_RADIO_TIMER_IsEnabledTimer1(BLUE) || LL_RADIO_TIMER_IsEnabledTimer2(BLUE)))
812   {
813     _check_host_activity();
814   }
815 #endif
816 }
817 
818 /**
819   * @brief  Timer State machine semaphore to signal the radio activity finished.
820   * @retval None
821   */
HAL_RADIO_TIMER_EndOfRadioActivityIsr(void)822 void HAL_RADIO_TIMER_EndOfRadioActivityIsr(void)
823 {
824   RADIO_TIMER_Context.radioTimer.intTxRx_to_be_served = FALSE;
825 }
826 
827 /* ----------------------- Radio Timer time unit APIs ------------------------*/
828 
829 /**
830   * @brief  Translate time in microseconds into sys time units.
831   * @param  time: Microseconds to be converted in STU
832   * @return STU value
833   */
HAL_RADIO_TIMER_UsToSystime(uint32_t time)834 uint32_t HAL_RADIO_TIMER_UsToSystime(uint32_t time)
835 {
836   return _us_to_systime(time);
837 }
838 
839 /**
840   * @brief   Returns the STU corresponding to the MTU passed as parameter.
841   * @param   time: MTU amount to be converted in STU
842   * @warning This function is not re-entrant since it updates the context variable
843   *          storing the system time. It should be called only in
844   *          user context and not in interrupt context.
845   * @return  STU value
846   */
HAL_RADIO_TIMER_MachineTimeToSysTime(uint32_t time)847 uint32_t HAL_RADIO_TIMER_MachineTimeToSysTime(uint32_t time)
848 {
849   return blue_unit_conversion(time, RADIO_TIMER_Context.calibrationData.period1, MULT64_THR_PERIOD);
850 }
851 
852 /**
853   * @brief  This function returns the current reference time expressed in system time units.
854   *         The returned value can be used as absolute time parameter where needed in the other
855   *         HAL_RADIO_TIMER* APIs
856   * @return absolute current time expressed in system time units.
857   */
HAL_RADIO_TIMER_GetCurrentSysTime(void)858 uint64_t HAL_RADIO_TIMER_GetCurrentSysTime(void)
859 {
860   uint32_t current_machine_time;
861   return _get_system_time_and_machine(&RADIO_TIMER_Context, &current_machine_time);
862 }
863 
864 /**
865   * @brief  This function returns the sum of an absolute time and a signed relative time.
866   * @param  sysTime: Absolute time expressed in internal time units.
867   * @param  msTime: Signed relative time expressed in ms.
868   * @return 64bit resulting absolute time expressed in internal time units.
869   */
HAL_RADIO_TIMER_AddSysTimeMs(uint64_t sysTime,int32_t msTime)870 uint64_t HAL_RADIO_TIMER_AddSysTimeMs(uint64_t sysTime, int32_t msTime)
871 {
872   int32_t sysTick = (msTime * TIMER_SYSTICK_PER_10MS) / 10;
873   return (sysTime + sysTick);
874 }
875 
876 /**
877   * @brief  Returns the difference between two absolute times: sysTime1-sysTime2.
878   *         The resulting value is expressed in ms.
879   * @param  sysTime2: Absolute time expressed in internal time units.
880   * @param  sysTime1: Absolute time expressed in internal time units.
881   * @return resulting signed relative time expressed in ms.
882   */
HAL_RADIO_TIMER_DiffSysTimeMs(uint64_t sysTime1,uint64_t sysTime2)883 int64_t HAL_RADIO_TIMER_DiffSysTimeMs(uint64_t sysTime1, uint64_t sysTime2)
884 {
885   return ((sysTime1 - sysTime2) * 10) >> 12;
886 }
887 
888 /* -------------------------- Virtual timer APIs ---------------------------- */
889 
890 /**
891   * @brief  Starts a one-shot virtual timer for the given relative timeout value expressed in ms
892   * @param  timerHandle: The virtual timer
893   * @param  msRelTimeout: The relative time, from current time, expressed in ms
894   * @retval 0 if the timerHandle is valid.
895   * @retval 1 if the timerHandle is not valid. It is already started.
896   */
HAL_RADIO_TIMER_StartVirtualTimer(VTIMER_HandleType * timerHandle,uint32_t msRelTimeout)897 uint32_t HAL_RADIO_TIMER_StartVirtualTimer(VTIMER_HandleType *timerHandle, uint32_t msRelTimeout)
898 {
899   uint64_t temp = msRelTimeout;
900   uint8_t retVal;
901   retVal = _start_timer(timerHandle, HAL_RADIO_TIMER_GetCurrentSysTime() + (temp * TIMER_SYSTICK_PER_10MS) / 10);
902   _virtualTimeBaseEnable(ENABLE);
903 
904   return retVal;
905 }
906 
907 /**
908   * @brief Starts a one-shot virtual timer for the given absolute timeout value
909   *        expressed in internal system time units.
910   * @param timerHandle: The virtual timer
911   * @param time: Absolute time expressed in STU.
912   * @retval 0 if the timerHandle is valid.
913   * @retval 1 if the timerHandle is not valid. It is already started.
914   */
HAL_RADIO_TIMER_StartVirtualTimerSysTime(VTIMER_HandleType * timerHandle,uint64_t time)915 uint32_t HAL_RADIO_TIMER_StartVirtualTimerSysTime(VTIMER_HandleType *timerHandle, uint64_t time)
916 {
917   uint8_t retVal;
918   retVal = _start_timer(timerHandle, time);
919   _virtualTimeBaseEnable(ENABLE);
920 
921   return retVal;
922 }
923 
924 /**
925   * @brief  Stops the one-shot virtual timer specified if found
926   * @param  timerHandle: The virtual timer
927   * @retval None
928   */
HAL_RADIO_TIMER_StopVirtualTimer(VTIMER_HandleType * timerHandle)929 void HAL_RADIO_TIMER_StopVirtualTimer(VTIMER_HandleType *timerHandle)
930 {
931   VTIMER_HandleType *rootNode = _remove_timer_in_queue(RADIO_TIMER_Context.rootNode, timerHandle);
932   uint8_t expired = 0;
933   timerHandle->active = FALSE;
934   if (RADIO_TIMER_Context.rootNode != rootNode)
935   {
936     RADIO_TIMER_Context.rootNode = _update_user_timeout(rootNode, &expired);
937     if (expired)
938     {
939       /* A new root timer is already expired, mimic timer expire */
940       INCREMENT_EXPIRE_COUNT;
941     }
942   }
943   else
944   {
945     RADIO_TIMER_Context.rootNode = rootNode;
946   }
947 }
948 
949 /**
950   * @brief Returns the absolute expiry time of a running virtual timer expressed in internal system time units.
951   * @param timerHandle: The virtual timer
952   * @retval sysTime: Absolute time expressed in internal system time units.
953   */
HAL_RADIO_TIMER_ExpiryTime(VTIMER_HandleType * timerHandle)954 uint64_t HAL_RADIO_TIMER_ExpiryTime(VTIMER_HandleType *timerHandle)
955 {
956   return timerHandle->expiryTime;
957 }
958 
959 #if defined (STM32WB06) || defined (STM32WB07)
960 /**
961   * @brief   If the wakeup timer triggers for a host wakeup, a pending radio activity is programmed.
962   *          If the wakeup timer triggers for a radio activity, a pending virtual timer callback is executed.
963   * @retval  None
964   */
HAL_RADIO_TIMER_WakeUpCallback(void)965 void HAL_RADIO_TIMER_WakeUpCallback(void)
966 {
967   volatile uint32_t status = 0;
968   uint8_t expired;
969   UNUSED(status);
970   _check_radio_activity(&RADIO_TIMER_Context.radioTimer, &expired);
971   if (RADIO_TIMER_Context.hostIsRadioPending)
972   {
973     RADIO_TIMER_Context.hostIsRadioPending = 0;
974     HAL_RADIO_TIMER_TimeoutCallback();
975   }
976 
977   LL_RADIO_TIMER_ClearFlag_BLEWakeup(WAKEUP);
978   status = LL_RADIO_TIMER_IsActiveFlag_BLEWakeup(WAKEUP);
979 }
980 #endif
981 
982 /**
983   * @brief  Virtual timer Timeout Callback. It signals that a host timeout occurred.
984   * @retval None
985   */
HAL_RADIO_TIMER_TimeoutCallback(void)986 void HAL_RADIO_TIMER_TimeoutCallback(void)
987 {
988   volatile uint32_t status = 0;
989   UNUSED(status);
990 #if defined (STM32WB06) || defined (STM32WB07)
991   RADIO_TIMER_Context.hostIsRadioPending = 0;
992 #endif
993 
994   /* Disable host timer */
995   LL_RADIO_TIMER_DisableCPUWakeupTimer(WAKEUP);
996   INCREMENT_EXPIRE_COUNT_ISR;
997   /* Clear the interrupt */
998   LL_RADIO_TIMER_ClearFlag_CPUWakeup(WAKEUP);
999   status = LL_RADIO_TIMER_IsActiveFlag_CPUWakeup(WAKEUP);
1000 }
1001 
1002 /**
1003   * @brief  Returns the number of timers in the queue.
1004   * @return number of timers in the queue.
1005   */
HAL_RADIO_TIMER_GetPendingTimers(void)1006 uint32_t HAL_RADIO_TIMER_GetPendingTimers(void)
1007 {
1008   VTIMER_HandleType *curr = RADIO_TIMER_Context.rootNode;
1009   uint32_t counter = 0;
1010   while (curr != NULL)
1011   {
1012     counter++;
1013     curr = curr->next;
1014   }
1015   return counter;
1016 }
1017 
1018 /**
1019   * @brief   Returns the 64-bit system time, referred to the 32-bit system time parameter.
1020   *          The returned system time refers to a time between last calibration and last
1021   *          calibration + 10485 seconds.
1022   * @param   sys_time: system time
1023   * @warning The system time cannot be more then 10485 seconds (174 min) after the last calibration time.
1024   * @return  STU value
1025   */
HAL_RADIO_TIMER_GetSysTime64(uint32_t sys_time)1026 uint64_t HAL_RADIO_TIMER_GetSysTime64(uint32_t sys_time)
1027 {
1028   uint64_t time;
1029 
1030   time = RADIO_TIMER_Context.calibrationData.last_calibration_time + (uint32_t)(sys_time - (uint32_t)RADIO_TIMER_Context.calibrationData.last_calibration_time);
1031 
1032   return time;
1033 }
1034 
1035 /**
1036   * @brief   Returns the next 64-bit system time in the future, referred to the 32-bit system time parameter.
1037   *          Compared to HAL_RADIO_TIMER_GetSysTime64() this function makes sure that the returned
1038   *          time is always in the future, but execution time of the function is longer.
1039   * @param   sys_time: system time in the future (no more than 10485 s = 174 min in the future)
1040   * @return  STU value
1041   */
HAL_RADIO_TIMER_GetFutureSysTime64(uint32_t sys_time)1042 uint64_t HAL_RADIO_TIMER_GetFutureSysTime64(uint32_t sys_time)
1043 {
1044   uint64_t current_time;
1045   uint32_t sysTime_ms32b;
1046 
1047   current_time = HAL_RADIO_TIMER_GetCurrentSysTime();
1048   sysTime_ms32b = current_time >> 32; /* Most significant 32 bits of sysTime64 */
1049 
1050   if (sys_time < (uint32_t)current_time)
1051   {
1052     /* Need to get most signicant 32 bits of current time increased by one */
1053     sysTime_ms32b++;
1054   }
1055 
1056   return sys_time | (((uint64_t)sysTime_ms32b) << 32);
1057 }
1058 
1059 /**
1060   * @}
1061   */
1062 
1063 /* Private functions ---------------------------------------------------------*/
1064 /** @defgroup RADIO_TIMER_Private_Functions  RADIO TIMER Private Functions
1065   * @{
1066   */
1067 
_calibrationProcedure(void)1068 static void _calibrationProcedure(void)
1069 {
1070   /* Make sure any pending calibration is over */
1071   while (LL_RADIO_TIMER_IsActiveFlag_LSICalibrationEnded(RADIO_CTRL) == 0);
1072 
1073   /* Set SLOW_COUNT to 23, that is calibrate over 24 clock periods, this number
1074   cannot be changed without changing all the integer maths function in the
1075   file  */
1076   LL_RADIO_TIMER_SetLSIWindowCalibrationLength(RADIO_CTRL, 23);
1077 
1078   /* Start a calibration and take the correct freq */
1079   _timer_calibrate(&RADIO_TIMER_Context.calibrationData);
1080   /* For first time set last to current */
1081   RADIO_TIMER_Context.calibrationData.last_period1 = RADIO_TIMER_Context.calibrationData.period1;
1082 
1083 }
1084 
_timer_start_calibration(void)1085 static void _timer_start_calibration(void)
1086 {
1087   /* Clear any pending interrupt */
1088   LL_RADIO_TIMER_ClearFlag_LSICalibrationEnded(RADIO_CTRL);
1089   /* Start calibration */
1090   LL_RADIO_TIMER_StartLSICalibration(RADIO_CTRL);
1091 }
1092 
_timer_calibrate(CalibrationDataTypeDef * calibrationData)1093 static void _timer_calibrate(CalibrationDataTypeDef *calibrationData)
1094 {
1095   _timer_start_calibration();
1096   while (LL_RADIO_TIMER_IsActiveFlag_LSICalibrationEnded(RADIO_CTRL) == 0);
1097   _get_calibration_data(calibrationData);
1098 }
1099 
_get_calibration_data(CalibrationDataTypeDef * calibrationData)1100 static void _get_calibration_data(CalibrationDataTypeDef *calibrationData)
1101 {
1102   int32_t period;
1103   int32_t freq;
1104   int32_t mul1;
1105   int32_t b1;
1106   int32_t b2;
1107   int32_t mult;
1108   int32_t a1;
1109   int32_t a2;
1110 
1111   period =  LL_RADIO_TIMER_GetLSIPeriod(RADIO_CTRL);
1112   while (period != LL_RADIO_TIMER_GetLSIPeriod(RADIO_CTRL) || period == 0)
1113   {
1114     period = LL_RADIO_TIMER_GetLSIPeriod(RADIO_CTRL);
1115   }
1116 
1117   mul1 = 0x8BCF6 ;
1118   b1 = period >> 8 ;
1119   b2 = period & 0xff ;
1120   calibrationData->period1 = ((mul1 * b1) + ((b2 * mul1) >> 8) + 16) >> 5;
1121   calibrationData->period = period;
1122 
1123   mult = 0x753 ;
1124   freq = LL_RADIO_TIMER_GetLSIFrequency(RADIO_CTRL);
1125 
1126   while (freq != LL_RADIO_TIMER_GetLSIFrequency(RADIO_CTRL) || freq == 0)
1127   {
1128     freq = LL_RADIO_TIMER_GetLSIFrequency(RADIO_CTRL);
1129   }
1130   a1 = freq >> 6 ;
1131   a2 = a1 * mult ;
1132   calibrationData->freq1 = (a2 + 128) >> 8 ;
1133   calibrationData->freq = freq;
1134 }
1135 
_configureTxRxDelay(RADIO_TIMER_ContextTypeDef * context,uint8_t calculate_st)1136 static void _configureTxRxDelay(RADIO_TIMER_ContextTypeDef *context, uint8_t calculate_st)
1137 {
1138   uint8_t tx_delay_start;
1139 
1140   tx_delay_start = (BLUEGLOB->TXDELAYSTART * 125 / 1000) + 1;
1141 
1142   BLUEGLOB->WAKEUPINITDELAY =  blue_unit_conversion(WAKEUP_INIT_DELAY, context->calibrationData.freq1, MULT64_THR_FREQ);
1143   context->TxRxDelay.tim12_delay_mt = _us_to_machinetime(BLUEGLOB->TIMER12INITDELAYCAL);
1144   context->TxRxDelay.tx_cal_delay = _us_to_machinetime(BLUEGLOB->TRANSMITCALDELAYCHK + tx_delay_start);
1145   context->TxRxDelay.tx_no_cal_delay = _us_to_machinetime(BLUEGLOB->TRANSMITNOCALDELAYCHK + tx_delay_start);
1146   context->TxRxDelay.rx_cal_delay = _us_to_machinetime(BLUEGLOB->RECEIVECALDELAYCHK);
1147   context->TxRxDelay.rx_no_cal_delay = _us_to_machinetime(BLUEGLOB->RECEIVENOCALDELAYCHK);
1148 
1149   if (calculate_st)
1150   {
1151     context->TxRxDelay.tx_cal_delay_st    = _us_to_systime(BLUEGLOB->TRANSMITCALDELAYCHK + tx_delay_start) + WAKEUP_INIT_DELAY;
1152   }
1153 
1154 }
1155 
_us_to_systime(uint32_t time)1156 static uint32_t _us_to_systime(uint32_t time)
1157 {
1158   uint32_t t1, t2;
1159   t1 = time * 0x68;
1160   t2 = time * 0xDB;
1161   return (t1 >> 8) + (t2 >> 16);
1162 }
1163 
_us_to_machinetime(uint32_t time)1164 static uint32_t _us_to_machinetime(uint32_t time)
1165 {
1166   uint64_t tmp = (uint64_t)RADIO_TIMER_Context.calibrationData.freq * (uint64_t)time * (uint64_t)3U;
1167   uint32_t time_mt = ((tmp + (1 << 26)) >> 27) & TIMER_MAX_VALUE;
1168 
1169   return time_mt;
1170 }
1171 
_update_xtal_startup_time(uint16_t hs_startup_time,int32_t freq1)1172 static void _update_xtal_startup_time(uint16_t hs_startup_time, int32_t freq1)
1173 {
1174   int32_t time1;
1175 
1176   time1 = blue_unit_conversion(hs_startup_time, freq1, MULT64_THR_FREQ);
1177   if (time1 >= 4096)
1178   {
1179     time1 = 4095;
1180   }
1181   if (time1 < 16)
1182   {
1183     time1 = 16;
1184   }
1185   LL_RADIO_TIMER_SetWakeupOffset(WAKEUP, (time1 >> 4));
1186 }
1187 
_calibration_callback(void * handle)1188 static void _calibration_callback(void *handle)
1189 {
1190   if (RADIO_TIMER_Context.calibrationSettings.periodicCalibration)
1191   {
1192     _timer_start_calibration();
1193   }
1194   RADIO_TIMER_Context.calibrationSettings.calibration_in_progress = TRUE;
1195 }
1196 
_start_timer(VTIMER_HandleType * timerHandle,uint64_t time)1197 static int32_t _start_timer(VTIMER_HandleType *timerHandle, uint64_t time)
1198 {
1199   uint8_t expired = 0;
1200 
1201   /* The timer is already started*/
1202   if (timerHandle->active)
1203   {
1204     return 1;
1205   }
1206   timerHandle->expiryTime = time;
1207   timerHandle->active = TRUE;
1208   if (_insert_timer_in_queue(RADIO_TIMER_Context.rootNode, timerHandle) == timerHandle)
1209   {
1210     RADIO_TIMER_Context.rootNode = _update_user_timeout(timerHandle, &expired);
1211     if (expired)
1212     {
1213       /* A new root timer is already expired, mimic timer expire that is normally signaled
1214        through the interrupt handler that increase the number of expired timers*/
1215       INCREMENT_EXPIRE_COUNT;
1216     }
1217   }
1218   return expired;
1219 }
1220 
_get_system_time_and_machine(RADIO_TIMER_ContextTypeDef * context,uint32_t * current_machine_time)1221 static uint64_t _get_system_time_and_machine(RADIO_TIMER_ContextTypeDef *context, uint32_t *current_machine_time)
1222 {
1223   uint32_t difftime;
1224   uint64_t new_time;
1225 
1226   ATOMIC_SECTION_BEGIN();
1227   new_time = context->cumulative_time;
1228   *current_machine_time =  LL_RADIO_TIMER_GetAbsoluteTime(WAKEUP);
1229   difftime = TIME_ABSDIFF(*current_machine_time, context->last_machine_time);
1230   new_time += blue_unit_conversion(difftime, context->calibrationData.period1, MULT64_THR_PERIOD);
1231   if (new_time < context->last_system_time)
1232   {
1233     new_time += blue_unit_conversion(TIMER_MAX_VALUE, context->calibrationData.period1, MULT64_THR_PERIOD);
1234   }
1235   context->last_system_time = new_time;
1236   ATOMIC_SECTION_END();
1237 
1238   return new_time;
1239 }
1240 
1241 /* Set timeout and skip non active timers */
_update_user_timeout(VTIMER_HandleType * rootNode,uint8_t * expired)1242 static VTIMER_HandleType *_update_user_timeout(VTIMER_HandleType *rootNode, uint8_t *expired)
1243 {
1244   VTIMER_HandleType *curr = rootNode;
1245   VTIMER_HandleType *rootOrig = rootNode;
1246   int64_t delay;
1247   *expired = 0;
1248   while (curr != NULL)
1249   {
1250     if (curr->active)
1251     {
1252       ATOMIC_SECTION_BEGIN();
1253 #if defined (STM32WB06) || defined (STM32WB07)
1254       uint8_t dummy;
1255       bool share = FALSE;
1256       _check_radio_activity(&RADIO_TIMER_Context.radioTimer, &dummy);
1257 #endif
1258       delay = curr->expiryTime - HAL_RADIO_TIMER_GetCurrentSysTime();
1259       if (delay > 0)
1260       {
1261         /* Protection against interrupt must be used to avoid that the called function will be interrupted
1262           and so the timer programming will happen after the target time is already passed
1263           leading to a timer expiring after timer wraps, instead of the expected delay */
1264 #if defined (STM32WB06) || defined (STM32WB07)
1265         /* Is the active radio operation before or too close the host timeout? */
1266         if (((RADIO_TIMER_Context.radioTimer.expiryTime) < (curr->expiryTime + RADIO_TIMER_Context.hostMargin))
1267             && RADIO_TIMER_Context.radioTimer.active)
1268         {
1269           if ((RADIO_TIMER_Context.radioTimer.expiryTime >= curr->expiryTime) && RADIO_TIMER_Context.radioTimer.active)
1270           {
1271             RADIO_TIMER_Context.hostIsRadioPending = 1;
1272           }
1273         }
1274         else
1275         {
1276           /* It's fine to program the wakeup timer for an host wakeup */
1277           share = TRUE;
1278         }
1279         TIMER_SetRadioHostWakeupTime(delay, &share);
1280         if (share == TRUE)
1281         {
1282           RADIO_TIMER_Context.radioTimer.pending |= RADIO_TIMER_Context.radioTimer.active;
1283           RADIO_TIMER_Context.radioTimer.active = FALSE;
1284         }
1285 #else
1286         VTIMER_SetWakeupTime(delay, TRUE);
1287 #endif
1288       }
1289       else
1290       {
1291         *expired = 1;
1292       }
1293       ATOMIC_SECTION_END();
1294       break;
1295     }
1296     curr = curr->next;
1297   }
1298   if (*expired)
1299   {
1300     return rootOrig;
1301   }
1302 
1303   return curr;
1304 }
1305 
1306 #if defined (STM32WB05) || defined (STM32WB09)
VTIMER_SetWakeupTime(uint32_t delay,bool allow_sleep)1307 static uint32_t VTIMER_SetWakeupTime(uint32_t delay, bool allow_sleep)
1308 {
1309   uint32_t current_time;
1310   delay = blue_unit_conversion(delay, RADIO_TIMER_Context.calibrationData.freq1, MULT64_THR_FREQ) ;
1311   /* If the delay is too small round to minimum 2 tick */
1312   delay = MAX(32, delay);
1313   current_time = LL_RADIO_TIMER_GetAbsoluteTime(WAKEUP);
1314   /* 4 least significant bits are not taken into account. Then let's round the value */
1315   LL_RADIO_TIMER_SetCPUWakeupTime(WAKEUP, ((current_time + (delay + 8)) & TIMER_MAX_VALUE));
1316   LL_RADIO_TIMER_EnableWakeupTimerLowPowerMode(WAKEUP);
1317   LL_RADIO_TIMER_EnableCPUWakeupTimer(WAKEUP);
1318 
1319   return current_time;
1320 }
1321 #endif
1322 
_insert_timer_in_queue(VTIMER_HandleType * rootNode,VTIMER_HandleType * handle)1323 static VTIMER_HandleType *_insert_timer_in_queue(VTIMER_HandleType *rootNode, VTIMER_HandleType *handle)
1324 {
1325   VTIMER_HandleType *current = rootNode;
1326   VTIMER_HandleType *prev = NULL;
1327   VTIMER_HandleType *returnValue = rootNode;
1328 
1329   while ((current != NULL) && (current->expiryTime < handle->expiryTime))
1330   {
1331     prev = current;
1332     current = current->next;
1333   }
1334 
1335   handle->next = current;
1336 
1337   if (prev == NULL)
1338   {
1339     /* We are the new root */
1340     returnValue = handle;
1341   }
1342   else
1343   {
1344     prev->next = handle;
1345   }
1346 
1347   return returnValue;
1348 }
1349 
_virtualTimeBaseEnable(FunctionalState state)1350 static void _virtualTimeBaseEnable(FunctionalState state)
1351 {
1352   if (state != DISABLE)
1353   {
1354     if (RADIO_TIMER_Context.enableTimeBase == FALSE)
1355     {
1356       _calibration_callback(&RADIO_TIMER_Context.calibrationTimer);
1357       RADIO_TIMER_Context.enableTimeBase = TRUE;
1358     }
1359   }
1360   else
1361   {
1362     HAL_RADIO_TIMER_StopVirtualTimer(&RADIO_TIMER_Context.calibrationTimer);
1363     RADIO_TIMER_Context.enableTimeBase = FALSE;
1364   }
1365 }
1366 
_remove_timer_in_queue(VTIMER_HandleType * rootNode,VTIMER_HandleType * handle)1367 static VTIMER_HandleType *_remove_timer_in_queue(VTIMER_HandleType *rootNode, VTIMER_HandleType *handle)
1368 {
1369   VTIMER_HandleType *current = rootNode;
1370   VTIMER_HandleType *prev = NULL;
1371   VTIMER_HandleType *returnValue = rootNode;
1372 
1373   while ((current != NULL) && (current != handle))
1374   {
1375     prev = current;
1376     current = current->next;
1377   }
1378 
1379   if (current == NULL)
1380   {
1381     /* Not found */
1382   }
1383   else if (current == rootNode)
1384   {
1385     /* New root node */
1386     returnValue = current->next;
1387   }
1388   else
1389   {
1390     prev->next = current->next;
1391   }
1392 
1393   return returnValue;
1394 }
1395 
1396 /* Check the number of expired timer from rootNode (ordered list of timers) and return the list of expired timers */
_check_callbacks(VTIMER_HandleType * rootNode,VTIMER_HandleType ** expiredList)1397 static VTIMER_HandleType *_check_callbacks(VTIMER_HandleType *rootNode, VTIMER_HandleType **expiredList)
1398 {
1399 
1400   VTIMER_HandleType *curr = rootNode;
1401   VTIMER_HandleType *prev = NULL;
1402   VTIMER_HandleType *returnValue = rootNode;
1403   *expiredList = rootNode;
1404 
1405   int64_t delay;
1406   uint32_t expiredCount = 0;
1407 
1408   while (curr != NULL)
1409   {
1410 
1411     if (curr->active)
1412     {
1413       delay = curr->expiryTime - HAL_RADIO_TIMER_GetCurrentSysTime();
1414 
1415       if (delay > 5)   /*TBR*/
1416       {
1417         /* End of expired timers list*/
1418         break;
1419       }
1420     }
1421 
1422     prev = curr;
1423     curr = curr->next;
1424     expiredCount++;
1425   }
1426 
1427   if (expiredCount)
1428   {
1429     /* Some timers expired */
1430     prev->next = NULL;
1431     returnValue = curr;
1432   }
1433   else
1434   {
1435     /* No timer expired */
1436     *expiredList = NULL;
1437   }
1438 
1439   return returnValue;
1440 }
1441 
_updateCalibrationData(void)1442 static void _updateCalibrationData(void)
1443 {
1444   if (RADIO_TIMER_Context.calibrationSettings.periodicCalibration)
1445   {
1446     _get_calibration_data(&RADIO_TIMER_Context.calibrationData);
1447     _update_xtal_startup_time(RADIO_TIMER_Context.hs_startup_time, RADIO_TIMER_Context.calibrationData.freq1);
1448     _configureTxRxDelay(&RADIO_TIMER_Context, FALSE);
1449     RADIO_TIMER_Context.calibrationData.calibration_data_available = 1;
1450   }
1451   ATOMIC_SECTION_BEGIN();
1452   _update_system_time(&RADIO_TIMER_Context);
1453   ATOMIC_SECTION_END();
1454 }
1455 
1456 /* This function update the system time after a calibration.
1457  * If the user calls too often this function, you could have rounding issues in the integer maths.
1458  */
_update_system_time(RADIO_TIMER_ContextTypeDef * context)1459 static void _update_system_time(RADIO_TIMER_ContextTypeDef *context)
1460 {
1461   uint32_t current_machine_time;
1462   uint32_t period;
1463 
1464   current_machine_time = LL_RADIO_TIMER_GetAbsoluteTime(WAKEUP);
1465   period = context->calibrationData.last_period1;
1466   context->cumulative_time = context->calibrationData.last_calibration_time + \
1467                              blue_unit_conversion(TIME_ABSDIFF(current_machine_time,
1468                                                                context->last_machine_time),
1469                                                   period, MULT64_THR_PERIOD);
1470 
1471   if ((context->calibrationSettings.periodicCalibration == 0)
1472       && (TIME_ABSDIFF(current_machine_time,
1473                        context->last_machine_time) < context->calibrationData.calibration_machine_interval))
1474   {
1475     context->cumulative_time += blue_unit_conversion(TIMER_MAX_VALUE, period, MULT64_THR_PERIOD);
1476   }
1477   context->last_machine_time = current_machine_time;
1478   context->calibrationData.last_calibration_time = context->cumulative_time;
1479   context->calibrationData.last_period1 = context->calibrationData.period1;
1480 }
1481 
1482 /* Check if it is time to program the pending radio timer (large timeouts).
1483    1) The radio event is before the next calibration event. Then the timer must be programmed.
1484    2) The calibration timer expired but the calibration didn't start and the values not updated as expected.
1485       Then the next calibration event is misleading. The radio timer must be programmed.
1486    3) The radio event is after the next calibration event. Then the timer will be programmed with the latest values.
1487    The check on the next calibration event is made even though the calibration is disabled (max cal. interval)
1488    in order to avoid counter wrapping with timeouts far in the future.
1489 */
_check_radio_activity(RADIO_TIMER_RadioHandleTypeDef * timerHandle,uint8_t * expired)1490 static void _check_radio_activity(RADIO_TIMER_RadioHandleTypeDef *timerHandle, uint8_t *expired)
1491 {
1492   uint64_t nextCalibrationEvent, currentTime;
1493 
1494   *expired = 0;
1495 
1496   if (timerHandle->pending)
1497   {
1498     nextCalibrationEvent = RADIO_TIMER_Context.calibrationData.last_calibration_time + \
1499                            RADIO_TIMER_Context.calibrationSettings.periodicCalibrationInterval;
1500 
1501     ATOMIC_SECTION_BEGIN();
1502     currentTime = HAL_RADIO_TIMER_GetCurrentSysTime();
1503     if ((timerHandle->expiryTime < (nextCalibrationEvent + RADIO_ACTIVITY_MARGIN)) || \
1504         (currentTime > (nextCalibrationEvent + CALIB_SAFE_THR)))
1505     {
1506       if (timerHandle->expiryTime - TIMER1_INIT_DELAY > (currentTime + TIMER1_MARGIN))
1507       {
1508         *expired = TIMER_SetRadioTimerValue(timerHandle->expiryTime, timerHandle->event_type, timerHandle->cal_req);
1509         timerHandle->pending = FALSE; /* timer has been served. No more pending */
1510         timerHandle->active = TRUE; /* timer has been programmed and it becomes ACTIVE */
1511         timerHandle->intTxRx_to_be_served = TRUE;
1512       }
1513       else
1514       {
1515         RADIO_TIMER_Context.radioTimer.pending = FALSE;
1516         *expired = 1;
1517       }
1518     }
1519     else
1520     {
1521 #if defined (STM32WB06) || defined (STM32WB07)
1522       RADIO_TIMER_Context.waitCal = 1;
1523 #endif
1524     }
1525     ATOMIC_SECTION_END();
1526   }
1527 }
1528 
1529 #if defined (STM32WB06) || defined (STM32WB07)
1530 /**
1531   * @brief   Set the wakeup time to the specified delay. The delay is converted in machine time and only 28 most significant bits
1532   *          are taken into account. The XTAL startup time is not taken into account for the wakeup, i.e. the system does not wait for
1533   *          the XTAL startup time parameter to trigger the interrupt. If is it possible the wakeup timer is programmed too.
1534   *          The delay is translated into machine time unit (MTU) and it is assigned to the wakeup register.
1535   * @param   delay: Delay from the current time expressed in system time unit (STU). Range is 0 to maximum value of STU.
1536   *          The maximum value STU is dependent on the speed of the low speed oscillator.
1537   *          A value too small will force the timer to wrap, so it is recommended to use at least 5-10 STU.
1538   * @param   share: flag that indicates if the wakeup timer has to be programmed too.
1539   *          if other code commands the system to go to deep sleep.
1540   * @warning The API must be called with interrupts disabled to avoid programming the timer with a value in the past.
1541   * @return  Current time in MTU.
1542   */
TIMER_SetRadioHostWakeupTime(uint32_t delay,bool * share)1543 static uint32_t TIMER_SetRadioHostWakeupTime(uint32_t delay, bool *share)
1544 {
1545   uint32_t current_time;
1546 
1547   delay = blue_unit_conversion(delay, RADIO_TIMER_Context.calibrationData.freq1, MULT64_THR_FREQ) ;
1548   /* If the delay is too small round to minimum 2 tick */
1549   delay = MAX(32, delay);
1550   current_time = LL_RADIO_TIMER_GetAbsoluteTime(WAKEUP);
1551   /* 4 least significant bits are not taken into account. Then let's round the value */
1552   LL_RADIO_TIMER_SetCPUWakeupTime(WAKEUP, ((current_time + (delay + 8)) & TIMER_MAX_VALUE));
1553   LL_RADIO_TIMER_EnableWakeupTimerLowPowerMode(WAKEUP);
1554   LL_RADIO_TIMER_EnableCPUWakeupTimer(WAKEUP);
1555   if ((LL_RADIO_TIMER_IsEnabledTimer1(BLUE) || LL_RADIO_TIMER_IsEnabledTimer2(BLUE) || (*share != TRUE)))
1556   {
1557     *share = FALSE;
1558     return current_time;
1559   }
1560   _set_controller_as_host();
1561   /* 4 least significant bits are not taken into account. Then let's round the value */
1562   LL_RADIO_TIMER_SetBLEWakeupTime(WAKEUP, ((current_time + delay + 8) & 0xFFFFFFF0));
1563   LL_RADIO_TIMER_SetSleepRequestMode(WAKEUP, 0);
1564   LL_RADIO_TIMER_EnableBLEWakeupTimer(WAKEUP);
1565   LL_RADIO_TIMER_EnableWakeupTimerLowPowerMode(WAKEUP);
1566   return current_time;
1567 }
1568 
_set_controller_as_host(void)1569 static void _set_controller_as_host(void)
1570 {
1571   BLUEGLOB->BYTE4 &= ~(1 << 7);
1572   BLUEGLOB->BYTE22 = 0x0;
1573   BLUEGLOB->BYTE23 = 0x0;
1574 }
1575 
_check_host_activity(void)1576 static void _check_host_activity(void)
1577 {
1578   uint8_t expired;
1579   RADIO_TIMER_Context.rootNode = _update_user_timeout(RADIO_TIMER_Context.rootNode, &expired);
1580   if (expired == 1)
1581   {
1582     /* A new root timer is already expired, mimic timer expire */
1583     INCREMENT_EXPIRE_COUNT_ISR;
1584   }
1585 }
1586 #endif
1587 
1588 /**
1589   * @brief   Programs either the Wakeup timer or Timer1. Both timers are able to trigger the radio sequencer.
1590   *          Then, they are able to start a transmission or a reception according to the configured radio ram tables.
1591   *          Only the wakeup timer is able to let the device out from sleep.
1592   *          The wakeup timer is programmed if the anolag part has enough time to settle after the wakeup or not.
1593   *          The timeout passed as parameter represents the moment where the first bit must be transmitted or the
1594   *          receive window must be opened.
1595   *          Since the radio needs some time to setup, the final timeout programmed is compensated by certain
1596   *          time intervals according to the kind of operation (Tx or Rx), calibration request and programmed timer.
1597   *          The wakeup offset is compensated automatically by the hardware.
1598   *          The CPU wakes up at timeout minus wakeup_offset. if the wakeup timer is programmed, the BLE event triggers
1599   *          when the absolute time mathches the 28 MSB of the timeout. Otherwise the trigger event occurs considering all 32 bits.
1600   * @param   timeout: absolute starting time of the desired operation expressed in STU.
1601   *                   If this absolute time is less then the current time, the timer will wrap.
1602   *                   The maximum value STU is dependent on the speed of the low speed oscillator.
1603   * @param   event_type: 1 Tx event.
1604                          0 Rx event
1605   * @param   cal_req: 1 pll calibration is requested.
1606                      0 pll calibration is not requested.
1607   * @warning The API must be called with interrupts disabled to avoid programming the timer with a value in the past
1608   * @retval  0 if a correct timeout has been programmed in the timeout register
1609   * @retval  1 if a correct timeout cannot be programmed
1610   */
TIMER_SetRadioTimerValue(uint32_t timeout,bool event_type,bool cal_req)1611 static uint8_t TIMER_SetRadioTimerValue(uint32_t timeout, bool event_type, bool cal_req)
1612 {
1613   uint32_t current_time, delay, radio_init_delay, device_delay, rel_timeout, rel_timeout_mt;
1614   uint8_t ret_val;
1615 
1616   /*choose the 2nd init duration. Check the event_type and cal. request*/
1617   if (event_type == TX)
1618   {
1619     if (cal_req)
1620     {
1621       radio_init_delay = RADIO_TIMER_Context.TxRxDelay.tx_cal_delay;
1622       device_delay = RADIO_TIMER_Context.TxRxDelay.tx_cal_delay_st;
1623     }
1624     else
1625     {
1626       radio_init_delay = RADIO_TIMER_Context.TxRxDelay.tx_no_cal_delay;
1627       device_delay = RADIO_TIMER_Context.TxRxDelay.tx_cal_delay_st;
1628     }
1629   }
1630   else
1631   {
1632     if (cal_req)
1633     {
1634       radio_init_delay = RADIO_TIMER_Context.TxRxDelay.rx_cal_delay;
1635       device_delay = RADIO_TIMER_Context.TxRxDelay.tx_cal_delay_st;
1636     }
1637     else
1638     {
1639       radio_init_delay = RADIO_TIMER_Context.TxRxDelay.rx_no_cal_delay;
1640       device_delay = RADIO_TIMER_Context.TxRxDelay.tx_cal_delay_st;
1641     }
1642   }
1643 
1644   /* At this point, it is care of the upper layers to guarantee that the timeout represents an absolute time in the future */
1645   rel_timeout = timeout - (uint32_t)_get_system_time_and_machine(&RADIO_TIMER_Context, &current_time);
1646 
1647   rel_timeout_mt =  blue_unit_conversion(rel_timeout, RADIO_TIMER_Context.calibrationData.freq1, MULT64_THR_FREQ);
1648 
1649   /*Check if the timeout is beyond the wakeup time offset. Then program either the WakeUp timer or the Timer1*/
1650   if (rel_timeout > (device_delay + RADIO_TIMER_Context.hs_startup_time + MARGIN_EXT))
1651   {
1652     /*The timeout is after the wakeup_time_offset, So it is ok to program the wakeup timer*/
1653     delay = rel_timeout_mt - BLUEGLOB->WAKEUPINITDELAY - radio_init_delay;
1654     LL_RADIO_TIMER_SetBLEWakeupTime(WAKEUP, ((current_time + delay) & TIMER_MAX_VALUE));
1655     LL_RADIO_TIMER_SetSleepRequestMode(WAKEUP, 0);
1656     LL_RADIO_TIMER_DisableTimer1(BLUE);
1657     LL_RADIO_TIMER_DisableTimer2(BLUE);
1658     LL_RADIO_TIMER_EnableBLEWakeupTimer(WAKEUP);
1659     LL_RADIO_TIMER_EnableWakeupTimerLowPowerMode(WAKEUP);
1660     radio_init_delay += BLUEGLOB->WAKEUPINITDELAY;
1661   }
1662   else
1663   {
1664     delay = rel_timeout_mt - RADIO_TIMER_Context.TxRxDelay.tim12_delay_mt - radio_init_delay;
1665     LL_RADIO_TIMER_SetTimeout(BLUE, ((current_time + delay) & TIMER_MAX_VALUE));
1666     LL_RADIO_TIMER_DisableBLEWakeupTimer(WAKEUP);
1667     LL_RADIO_TIMER_EnableTimer1(BLUE);
1668     radio_init_delay += RADIO_TIMER_Context.TxRxDelay.tim12_delay_mt;
1669   }
1670 
1671   RADIO_TIMER_Context.last_anchor_mt = (current_time + rel_timeout_mt) & TIMER_MAX_VALUE;
1672 
1673 #if defined (STM32WB06) || defined (STM32WB07)
1674   BLUEGLOB->BYTE4 |= 1 << 7;
1675   BLUEGLOB->BYTE22 = 0xF0;
1676   BLUEGLOB->BYTE23 = 0xFF;
1677 #endif
1678 
1679   /* Basic low level check with an extra margin of machine units */
1680   if ((delay + radio_init_delay) < (radio_init_delay + 5))
1681   {
1682     LL_RADIO_TIMER_DisableTimer1(BLUE);
1683     LL_RADIO_TIMER_DisableTimer2(BLUE);
1684     LL_RADIO_TIMER_DisableBLEWakeupTimer(WAKEUP);
1685     ret_val =  1;
1686   }
1687   else
1688   {
1689     RADIO_TIMER_Context.last_setup_time = blue_unit_conversion(radio_init_delay, RADIO_TIMER_Context.calibrationData.period1, MULT64_THR_PERIOD);
1690     ret_val = 0;
1691   }
1692 
1693   return ret_val;
1694 }
1695 
1696 /**
1697   * @brief   Return the system time referred to the absolute machine time passed as parameter and the current system time.
1698   * @param   time: Absolute machine time in the past
1699   * @param   current_system_time: Current System time
1700   * @warning User should guarantee that call to this function are performed in a non-interruptible context.
1701   * @return  STU value
1702   */
TIMER_GetPastSysTime(uint32_t time,uint64_t * current_system_time)1703 static uint64_t TIMER_GetPastSysTime(uint32_t time, uint64_t *current_system_time)
1704 {
1705   uint32_t delta_systime, current_machine_time;
1706 
1707   *current_system_time = _get_system_time_and_machine(&RADIO_TIMER_Context, &current_machine_time);
1708   delta_systime = blue_unit_conversion(TIME_DIFF(current_machine_time, time), RADIO_TIMER_Context.calibrationData.period1, MULT64_THR_PERIOD);
1709 
1710   return (*current_system_time - delta_systime);
1711 }
1712 
1713 /**
1714   * @brief  Return the consensus of the Virtual timer management to go in sleep.
1715   * @retval TRUE if all vtimers have been served and the calibration procedure has already finished.
1716   * @retval FALSE if the vtimer Tick is still busy.
1717   */
TIMER_SleepCheck(void)1718 static bool TIMER_SleepCheck(void)
1719 {
1720   return ((RADIO_TIMER_Context.expired_count == RADIO_TIMER_Context.served_count) && (RADIO_TIMER_Context.calibrationSettings.calibration_in_progress == FALSE));
1721 }
1722 
1723 /**
1724   * @brief  Return the status of the Radio timers and the last value programmed in the register.
1725   * @note   When Timer2 is on schedule, the time is expressed in microseconds, otherwise in absolute machine time units.
1726   * @param  time: pointer to value which is going to have time value.
1727   * @retval 0 if no timer has been programmed.
1728   * @retval 1 if Timer1 has been programmed.
1729   * @retval 2 if Timer2 has been programmed.
1730   * @retval 3 if Wakeup Timer has been programmed.
1731   */
TIMER_GetRadioTimerValue(uint32_t * time)1732 static uint8_t TIMER_GetRadioTimerValue(uint32_t *time)
1733 {
1734   if (LL_RADIO_TIMER_IsEnabledBLEWakeupTimer(WAKEUP))
1735   {
1736     *time = LL_RADIO_TIMER_GetBLEWakeupTime(WAKEUP);
1737     return WAKEUP_RADIO_TIMER_BUSY;
1738   }
1739   else if (LL_RADIO_TIMER_IsEnabledTimer1(BLUE))
1740   {
1741     *time = LL_RADIO_TIMER_GetTimeout(BLUE);
1742     return RADIO_TIMER1_BUSY;
1743   }
1744   else if (LL_RADIO_TIMER_IsEnabledTimer2(BLUE))
1745   {
1746     *time = LL_RADIO_TIMER_GetTimeout(BLUE);
1747     return RADIO_TIMER2_BUSY;
1748   }
1749   else
1750   {
1751     return 0;
1752   }
1753 }
1754 
HAL_RADIO_TIMER_CpuWakeUpCallback(void)1755 __weak void HAL_RADIO_TIMER_CpuWakeUpCallback(void)
1756 {
1757 }
1758 
1759 
HAL_RADIO_TIMER_TxRxWakeUpCallback(void)1760 __weak void HAL_RADIO_TIMER_TxRxWakeUpCallback(void)
1761 {
1762 }
1763 
HAL_RADIO_TIMER_CPU_WKUP_IRQHandler(void)1764 void HAL_RADIO_TIMER_CPU_WKUP_IRQHandler(void)
1765 {
1766   HAL_RADIO_TIMER_TimeoutCallback();
1767 
1768   HAL_RADIO_TIMER_CpuWakeUpCallback();
1769 }
1770 
HAL_RADIO_TIMER_TXRX_WKUP_IRQHandler(void)1771 void HAL_RADIO_TIMER_TXRX_WKUP_IRQHandler(void)
1772 {
1773   HAL_RADIO_TIMER_TxRxWakeUpCallback();
1774 #if defined (STM32WB06) || defined (STM32WB07)
1775   HAL_RADIO_TIMER_WakeUpCallback();
1776 #endif
1777 }
1778 
HAL_RADIO_TIMER_ERROR_IRQHandler(void)1779 void HAL_RADIO_TIMER_ERROR_IRQHandler(void)
1780 {
1781   volatile uint32_t debug_cmd = 0;
1782   UNUSED(debug_cmd);
1783   BLUE->DEBUGCMDREG |= 1;
1784 
1785   /* If the device is configured with
1786      System clock = 64 MHz and BLE clock = 16 MHz
1787      a register read is necessary to end fine
1788      the clear interrupt register operation,
1789      due the AHB down converter latency */
1790   debug_cmd = BLUE->DEBUGCMDREG;
1791 }
1792 
1793 /**
1794   * @}
1795   */
1796 
1797 /**
1798   * @}
1799   */
1800 
1801 /**
1802   * @}
1803   */
1804