1 /***************************************************************************//**
2  * @file
3  * @brief SLEEPTIMER API implementation.
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 #include <time.h>
31 #include <stdlib.h>
32 
33 #include "em_device.h"
34 #include "sl_core.h"
35 #include "sl_sleeptimer.h"
36 #include "sli_sleeptimer_hal.h"
37 #include "sl_atomic.h"
38 #include "sl_sleeptimer_config.h"
39 
40 #if defined(SL_COMPONENT_CATALOG_PRESENT)
41 #include "sl_component_catalog.h"
42 #endif
43 #if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
44 #include "sl_power_manager.h"
45 #include "sli_power_manager.h"
46 #endif
47 
48 #define TIME_UNIX_EPOCH                         (1970u)
49 #define TIME_NTP_EPOCH                          (1900u)
50 #define TIME_ZIGBEE_EPOCH                       (2000u)
51 #define TIME_64_EPOCH                           TIME_NTP_EPOCH
52 #define TIME_NTP_UNIX_EPOCH_DIFF                (TIME_UNIX_EPOCH - TIME_NTP_EPOCH)
53 #define TIME_ZIGBEE_UNIX_EPOCH_DIFF             (TIME_ZIGBEE_EPOCH - TIME_UNIX_EPOCH)
54 #define TIME_DAY_COUNT_NTP_TO_UNIX_EPOCH        (TIME_NTP_UNIX_EPOCH_DIFF * 365u + 17u)                  ///< 70 years and 17 leap days
55 #define TIME_DAY_COUNT_ZIGBEE_TO_UNIX_EPOCH     (TIME_ZIGBEE_UNIX_EPOCH_DIFF * 365u + 7u)                ///< 30 years and 7 leap days
56 #define TIME_SEC_PER_DAY                        (60u * 60u * 24u)
57 #define TIME_NTP_EPOCH_OFFSET_SEC               (TIME_DAY_COUNT_NTP_TO_UNIX_EPOCH * TIME_SEC_PER_DAY)
58 #define TIME_ZIGBEE_EPOCH_OFFSET_SEC            (TIME_DAY_COUNT_ZIGBEE_TO_UNIX_EPOCH * TIME_SEC_PER_DAY)
59 #define TIME_DAY_PER_YEAR                       (365u)
60 #define TIME_SEC_PER_YEAR                       (TIME_SEC_PER_DAY * TIME_DAY_PER_YEAR)
61 #define TIME_UNIX_TIMESTAMP_MAX                 (0x7FFFFFFF)
62 #define TIME_64_BIT_UNIX_TIMESTAMP_MAX          (0x497968BD7F)                                           /// Max 64 bit timestamp supported is 11:59:59 PM 12/31/11899
63 #define TIME_UNIX_YEAR_MAX                      (2038u - TIME_NTP_EPOCH)                                 ///< Max UNIX year based from a 1900 epoch
64 #define TIME_64_BIT_YEAR_MAX                    (11899u - TIME_NTP_EPOCH)                                ///< Max 64 bit format year based from a 1900 epoch
65 #define TIME_64_TO_32_EPOCH_OFFSET_SEC          TIME_NTP_EPOCH_OFFSET_SEC
66 #define TIME_UNIX_TO_NTP_MAX                    (0xFFFFFFFF - TIME_NTP_EPOCH_OFFSET_SEC)
67 
68 // Minimum count difference used when evaluating if a timer expired or not after an interrupt
69 // by comparing the current count value and the expected expiration count value.
70 // The difference should be null or of few ticks since the counter never stop.
71 #define MIN_DIFF_BETWEEN_COUNT_AND_EXPIRATION  2
72 
73 /// @brief Time Format.
SLEEPTIMER_ENUM(sl_sleeptimer_time_format_t)74 SLEEPTIMER_ENUM(sl_sleeptimer_time_format_t) {
75   TIME_FORMAT_UNIX = 0,           ///< Number of seconds since January 1, 1970, 00:00. Type is signed, so represented on 31 bit.
76   TIME_FORMAT_NTP = 1,            ///< Number of seconds since January 1, 1900, 00:00. Type is unsigned, so represented on 32 bit.
77   TIME_FORMAT_ZIGBEE_CLUSTER = 2, ///< Number of seconds since January 1, 2000, 00:00. Type is unsigned, so represented on 32 bit.
78   TIME_FORMAT_UNIX_64_BIT = 3,    ///< Number of seconds since January 1, 1900, 00:00. Type is unsigned, so represented on 64 bit.
79 };
80 
81 // tick_count, it can wrap around.
82 typedef uint32_t sl_sleeptimer_tick_count_t;
83 
84 // Overflow counter used to provide 64-bits tick count.
85 static volatile uint32_t overflow_counter;
86 
87 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
88 // Current time count.
89 static volatile sl_sleeptimer_timestamp_64_t second_count;
90 // Tick rest when the frequency is not a divider of the timer width.
91 static volatile uint32_t overflow_tick_rest = 0;
92 // Current time zone offset.
93 static sl_sleeptimer_time_zone_offset_t tz_offset = 0;
94 // Precalculated tick rest in case of overflow.
95 static uint32_t calculated_tick_rest = 0;
96 // Precalculated timer overflow duration in seconds.
97 static uint32_t calculated_sec_count = 0;
98 #endif
99 
100 // Timer frequency in Hz.
101 static uint32_t timer_frequency;
102 
103 // Head of timer list.
104 static sl_sleeptimer_timer_handle_t *timer_head;
105 
106 // Count at last update of delta of first timer.
107 static volatile sl_sleeptimer_tick_count_t last_delta_update_count;
108 
109 // Initialization flag.
110 static bool is_sleeptimer_initialized = false;
111 
112 // Flag that indicates if power manager's timer will expire at next compare match.
113 static volatile bool next_timer_to_expire_is_power_manager = false;
114 
115 // Precalculated value to avoid millisecond to tick conversion overflow.
116 static uint32_t max_millisecond_conversion;
117 
118 // Sleep on ISR exit flag.
119 static volatile bool sleep_on_isr_exit = false;
120 
121 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
122 static void delta_list_insert_timer(sl_sleeptimer_timer_handle_t *handle,
123                                     sl_sleeptimer_tick_count_t timeout);
124 
125 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
126 static sl_status_t delta_list_remove_timer(sl_sleeptimer_timer_handle_t *handle);
127 
128 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
129 static sl_status_t set_comparator_for_next_timer(void);
130 
131 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
132 static void update_delta_list(void);
133 
134 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
135 __STATIC_INLINE uint32_t div_to_log2(uint32_t div);
136 
137 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
138 __STATIC_INLINE bool is_power_of_2(uint32_t nbr);
139 
140 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
141 static sl_status_t create_timer(sl_sleeptimer_timer_handle_t *handle,
142                                 sl_sleeptimer_tick_count_t timeout_initial,
143                                 sl_sleeptimer_tick_count_t timeout_periodic,
144                                 sl_sleeptimer_timer_callback_t callback,
145                                 void *callback_data,
146                                 uint8_t priority,
147                                 uint16_t option_flags);
148 
149 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
150 static void process_expired_timer(sl_sleeptimer_timer_handle_t *timer);
151 
152 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
153 static void update_next_timer_to_expire_is_power_manager(void);
154 
155 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
156 static void delay_callback(sl_sleeptimer_timer_handle_t *handle,
157                            void *data);
158 
159 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
160 static bool is_leap_year(uint16_t year);
161 static uint16_t number_of_leap_days(uint32_t base_year, uint32_t current_year);
162 
163 static sl_sleeptimer_weekDay_t compute_day_of_week(uint32_t day);
164 static sl_sleeptimer_weekDay_t compute_day_of_week_64(uint64_t day);
165 static uint16_t compute_day_of_year(sl_sleeptimer_month_t month, uint8_t day, bool isLeapYear);
166 
167 static bool is_valid_time(sl_sleeptimer_timestamp_t time,
168                           sl_sleeptimer_time_format_t format,
169                           sl_sleeptimer_time_zone_offset_t time_zone);
170 
171 static bool is_valid_time_64(sl_sleeptimer_timestamp_64_t time,
172                              sl_sleeptimer_time_format_t format,
173                              sl_sleeptimer_time_zone_offset_t time_zone);
174 
175 static bool is_valid_date(sl_sleeptimer_date_t *date);
176 
177 static bool is_valid_date_64(sl_sleeptimer_date_t *date);
178 
179 static const uint8_t days_in_month[2u][12] = {
180   /* Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec */
181   { 31u, 28u, 31u, 30u, 31u, 30u, 31u, 31u, 30u, 31u, 30u, 31u },
182   { 31u, 29u, 31u, 30u, 31u, 30u, 31u, 31u, 30u, 31u, 30u, 31u }
183 };
184 #endif
185 
186 /**************************************************************************//**
187  * Initializes sleep timer.
188  *****************************************************************************/
sl_sleeptimer_init(void)189 sl_status_t sl_sleeptimer_init(void)
190 {
191   CORE_DECLARE_IRQ_STATE;
192 
193   CORE_ENTER_ATOMIC();
194   if (!is_sleeptimer_initialized) {
195     timer_head  = NULL;
196     last_delta_update_count = 0u;
197     overflow_counter = 0u;
198     sleeptimer_hal_init_timer();
199     sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_OF);
200     timer_frequency = sleeptimer_hal_get_timer_frequency();
201     if (timer_frequency == 0) {
202       CORE_EXIT_ATOMIC();
203       return SL_STATUS_INVALID_CONFIGURATION;
204     }
205 
206 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
207     second_count = 0;
208     calculated_tick_rest = ((uint64_t)UINT32_MAX + 1) % (uint64_t)timer_frequency;
209     calculated_sec_count = (((uint64_t)UINT32_MAX + 1) / (uint64_t)timer_frequency);
210 #endif
211     max_millisecond_conversion = (uint32_t)(((uint64_t)UINT32_MAX * (uint64_t)1000u) / timer_frequency);
212     is_sleeptimer_initialized = true;
213   }
214   CORE_EXIT_ATOMIC();
215 
216   return SL_STATUS_OK;
217 }
218 
219 /**************************************************************************//**
220  * Starts a 32 bits timer.
221  *****************************************************************************/
sl_sleeptimer_start_timer(sl_sleeptimer_timer_handle_t * handle,uint32_t timeout,sl_sleeptimer_timer_callback_t callback,void * callback_data,uint8_t priority,uint16_t option_flags)222 sl_status_t sl_sleeptimer_start_timer(sl_sleeptimer_timer_handle_t *handle,
223                                       uint32_t timeout,
224                                       sl_sleeptimer_timer_callback_t callback,
225                                       void *callback_data,
226                                       uint8_t priority,
227                                       uint16_t option_flags)
228 {
229   bool is_running = false;
230 
231   if (handle == NULL) {
232     return SL_STATUS_NULL_POINTER;
233   }
234 
235   handle->conversion_error = 0;
236   handle->accumulated_error = 0;
237 
238   sl_sleeptimer_is_timer_running(handle, &is_running);
239   if (is_running == true) {
240     return SL_STATUS_NOT_READY;
241   }
242 
243   return create_timer(handle,
244                       timeout,
245                       0,
246                       callback,
247                       callback_data,
248                       priority,
249                       option_flags);
250 }
251 
252 /**************************************************************************//**
253  * Restarts a 32 bits timer.
254  *****************************************************************************/
sl_sleeptimer_restart_timer(sl_sleeptimer_timer_handle_t * handle,uint32_t timeout,sl_sleeptimer_timer_callback_t callback,void * callback_data,uint8_t priority,uint16_t option_flags)255 sl_status_t sl_sleeptimer_restart_timer(sl_sleeptimer_timer_handle_t *handle,
256                                         uint32_t timeout,
257                                         sl_sleeptimer_timer_callback_t callback,
258                                         void *callback_data,
259                                         uint8_t priority,
260                                         uint16_t option_flags)
261 {
262   if (handle == NULL) {
263     return SL_STATUS_NULL_POINTER;
264   }
265 
266   handle->conversion_error = 0;
267   handle->accumulated_error = 0;
268 
269   //Trying to stop the Timer. Failing to do so implies the timer is not running.
270   sl_sleeptimer_stop_timer(handle);
271 
272   //Creates the timer in any case.
273   return create_timer(handle,
274                       timeout,
275                       0,
276                       callback,
277                       callback_data,
278                       priority,
279                       option_flags);
280 }
281 
282 /**************************************************************************//**
283  * Starts a 32 bits periodic timer.
284  *****************************************************************************/
sl_sleeptimer_start_periodic_timer(sl_sleeptimer_timer_handle_t * handle,uint32_t timeout,sl_sleeptimer_timer_callback_t callback,void * callback_data,uint8_t priority,uint16_t option_flags)285 sl_status_t sl_sleeptimer_start_periodic_timer(sl_sleeptimer_timer_handle_t *handle,
286                                                uint32_t timeout,
287                                                sl_sleeptimer_timer_callback_t callback,
288                                                void *callback_data,
289                                                uint8_t priority,
290                                                uint16_t option_flags)
291 {
292   bool is_running = false;
293 
294   if (handle == NULL) {
295     return SL_STATUS_NULL_POINTER;
296   }
297 
298   handle->conversion_error = 0;
299   handle->accumulated_error = 0;
300 
301   sl_sleeptimer_is_timer_running(handle, &is_running);
302   if (is_running == true) {
303     return SL_STATUS_INVALID_STATE;
304   }
305 
306   return create_timer(handle,
307                       timeout,
308                       timeout,
309                       callback,
310                       callback_data,
311                       priority,
312                       option_flags);
313 }
314 
315 /**************************************************************************//**
316  * Starts a 32 bits periodic timer using milliseconds as the timebase.
317  *****************************************************************************/
sl_sleeptimer_start_periodic_timer_ms(sl_sleeptimer_timer_handle_t * handle,uint32_t timeout_ms,sl_sleeptimer_timer_callback_t callback,void * callback_data,uint8_t priority,uint16_t option_flags)318 sl_status_t sl_sleeptimer_start_periodic_timer_ms(sl_sleeptimer_timer_handle_t *handle,
319                                                   uint32_t timeout_ms,
320                                                   sl_sleeptimer_timer_callback_t callback,
321                                                   void *callback_data,
322                                                   uint8_t priority,
323                                                   uint16_t option_flags)
324 {
325   bool is_running = false;
326   sl_status_t status;
327   uint32_t timeout_tick;
328 
329   if (handle == NULL) {
330     return SL_STATUS_NULL_POINTER;
331   }
332 
333   sl_sleeptimer_is_timer_running(handle, &is_running);
334   if (is_running == true) {
335     return SL_STATUS_INVALID_STATE;
336   }
337 
338   status = sl_sleeptimer_ms32_to_tick(timeout_ms, &timeout_tick);
339   if (status != SL_STATUS_OK) {
340     return status;
341   }
342 
343   // Calculate ms to ticks conversion error
344   handle->conversion_error = 1000
345                              - ((uint64_t)(timeout_ms * sl_sleeptimer_get_timer_frequency())
346                                 % 1000);
347   if (handle->conversion_error == 1000) {
348     handle->conversion_error = 0;
349   }
350   // Initialize accumulated error to 0. The calculated conversion error will
351   // be added to this variable each time a timer in the series of periodic timers
352   // expires.
353   handle->accumulated_error = 0;
354 
355   return create_timer(handle,
356                       timeout_tick,
357                       timeout_tick,
358                       callback,
359                       callback_data,
360                       priority,
361                       option_flags);
362 }
363 
364 /**************************************************************************//**
365  * Restarts a 32 bits periodic timer.
366  *****************************************************************************/
sl_sleeptimer_restart_periodic_timer(sl_sleeptimer_timer_handle_t * handle,uint32_t timeout,sl_sleeptimer_timer_callback_t callback,void * callback_data,uint8_t priority,uint16_t option_flags)367 sl_status_t sl_sleeptimer_restart_periodic_timer(sl_sleeptimer_timer_handle_t *handle,
368                                                  uint32_t timeout,
369                                                  sl_sleeptimer_timer_callback_t callback,
370                                                  void *callback_data,
371                                                  uint8_t priority,
372                                                  uint16_t option_flags)
373 {
374   if (handle == NULL) {
375     return SL_STATUS_NULL_POINTER;
376   }
377 
378   handle->conversion_error = 0;
379   handle->accumulated_error = 0;
380 
381   //Trying to stop the Timer. Failing to do so implies the timer has already been stopped.
382   sl_sleeptimer_stop_timer(handle);
383 
384   //Creates the timer in any case.
385   return create_timer(handle,
386                       timeout,
387                       timeout,
388                       callback,
389                       callback_data,
390                       priority,
391                       option_flags);
392 }
393 
394 /**************************************************************************//**
395  * Restarts a 32 bits periodic timer using milliseconds as the timebase.
396  *****************************************************************************/
sl_sleeptimer_restart_periodic_timer_ms(sl_sleeptimer_timer_handle_t * handle,uint32_t timeout_ms,sl_sleeptimer_timer_callback_t callback,void * callback_data,uint8_t priority,uint16_t option_flags)397 sl_status_t sl_sleeptimer_restart_periodic_timer_ms(sl_sleeptimer_timer_handle_t *handle,
398                                                     uint32_t timeout_ms,
399                                                     sl_sleeptimer_timer_callback_t callback,
400                                                     void *callback_data,
401                                                     uint8_t priority,
402                                                     uint16_t option_flags)
403 {
404   sl_status_t status;
405   uint32_t timeout_tick;
406 
407   if (handle == NULL) {
408     return SL_STATUS_NULL_POINTER;
409   }
410 
411   status = sl_sleeptimer_ms32_to_tick(timeout_ms, &timeout_tick);
412   if (status != SL_STATUS_OK) {
413     return status;
414   }
415 
416   // Calculate ms to ticks conversion error
417   handle->conversion_error = 1000
418                              - ((uint64_t)(timeout_ms * sl_sleeptimer_get_timer_frequency())
419                                 % 1000);
420   if (handle->conversion_error == 1000) {
421     handle->conversion_error = 0;
422   }
423 
424   // Initialize accumulated error to 0. The calculated conversion error will
425   // be added to this variable each time a timer in the series of periodic timers
426   // expires.
427   handle->accumulated_error = 0;
428 
429   //Trying to stop the Timer. Failing to do so implies the timer has already been stopped.
430   sl_sleeptimer_stop_timer(handle);
431 
432   //Creates the timer in any case.
433   return create_timer(handle,
434                       timeout_tick,
435                       timeout_tick,
436                       callback,
437                       callback_data,
438                       priority,
439                       option_flags);
440 }
441 
442 /**************************************************************************//**
443  * Stops a 32 bits timer.
444  *****************************************************************************/
sl_sleeptimer_stop_timer(sl_sleeptimer_timer_handle_t * handle)445 sl_status_t sl_sleeptimer_stop_timer(sl_sleeptimer_timer_handle_t *handle)
446 {
447   CORE_DECLARE_IRQ_STATE;
448   sl_status_t error;
449   bool set_comparator = false;
450 
451   // Disable PRS compare and capture channel, if configured for early wakeup
452 #if ((SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_SYSRTC) \
453   && defined(SL_CATALOG_POWER_MANAGER_PRESENT)                     \
454   && !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT))
455   if (handle->option_flags == (SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG | SLI_SLEEPTIMER_POWER_MANAGER_HF_ACCURACY_CLK_FLAG)) {
456     sleeptimer_hal_disable_prs_compare_and_capture_channel();
457   }
458 #endif
459 
460   if (handle == NULL) {
461     return SL_STATUS_NULL_POINTER;
462   }
463 
464   CORE_ENTER_CRITICAL();
465   update_delta_list();
466 
467   // If first timer in list, update timer comparator.
468   if (timer_head == handle) {
469     set_comparator = true;
470   }
471 
472   error = delta_list_remove_timer(handle);
473   if (error != SL_STATUS_OK) {
474     CORE_EXIT_CRITICAL();
475 
476     return error;
477   }
478 
479   if (set_comparator) {
480     error = set_comparator_for_next_timer();
481     if (error == SL_STATUS_NULL_POINTER) {
482       sleeptimer_hal_disable_int(SLEEPTIMER_EVENT_COMP);
483     }
484   }
485   CORE_EXIT_CRITICAL();
486 
487   return SL_STATUS_OK;
488 }
489 
490 /**************************************************************************//**
491  * Gets the status of a timer.
492  *****************************************************************************/
sl_sleeptimer_is_timer_running(const sl_sleeptimer_timer_handle_t * handle,bool * running)493 sl_status_t sl_sleeptimer_is_timer_running(const sl_sleeptimer_timer_handle_t *handle,
494                                            bool *running)
495 {
496   CORE_DECLARE_IRQ_STATE;
497   sl_sleeptimer_timer_handle_t *current;
498 
499   if (handle == NULL || running == NULL) {
500     return SL_STATUS_NULL_POINTER;
501   } else {
502     *running = false;
503     CORE_ENTER_ATOMIC();
504     current = timer_head;
505     while (current != NULL && !*running) {
506       if (current == handle) {
507         *running = true;
508       } else {
509         current = current->next;
510       }
511     }
512     CORE_EXIT_ATOMIC();
513   }
514   return SL_STATUS_OK;
515 }
516 
517 /**************************************************************************//**
518  * Gets a 32 bits timer's time remaining.
519  *****************************************************************************/
sl_sleeptimer_get_timer_time_remaining(const sl_sleeptimer_timer_handle_t * handle,uint32_t * time)520 sl_status_t sl_sleeptimer_get_timer_time_remaining(const sl_sleeptimer_timer_handle_t *handle,
521                                                    uint32_t *time)
522 {
523   CORE_DECLARE_IRQ_STATE;
524   sl_sleeptimer_timer_handle_t *current;
525 
526   if (handle == NULL || time == NULL) {
527     return SL_STATUS_NULL_POINTER;
528   }
529 
530   CORE_ENTER_ATOMIC();
531 
532   update_delta_list();
533   *time  = handle->delta;
534 
535   // Retrieve timer in list and add the deltas.
536   current = timer_head;
537   while (current != handle && current != NULL) {
538     *time += current->delta;
539     current = current->next;
540   }
541 
542   if (current != handle) {
543     CORE_EXIT_ATOMIC();
544 
545     return SL_STATUS_NOT_READY;
546   }
547 
548   // Substract time since last compare match.
549   if (*time > sleeptimer_hal_get_counter() - last_delta_update_count) {
550     *time -= sleeptimer_hal_get_counter() - last_delta_update_count;
551   } else {
552     *time = 0;
553   }
554 
555   CORE_EXIT_ATOMIC();
556 
557   return SL_STATUS_OK;
558 }
559 
560 /**************************************************************************//**
561  * Gets the time remaining until the first timer with the matching set of flags
562  * expires.
563  *****************************************************************************/
sl_sleeptimer_get_remaining_time_of_first_timer(uint16_t option_flags,uint32_t * time_remaining)564 sl_status_t sl_sleeptimer_get_remaining_time_of_first_timer(uint16_t option_flags,
565                                                             uint32_t *time_remaining)
566 {
567   CORE_DECLARE_IRQ_STATE;
568   sl_sleeptimer_timer_handle_t *current;
569   uint32_t time = 0;
570 
571   CORE_ENTER_ATOMIC();
572   // parse list and retrieve first timer with option flags requirement.
573   current = timer_head;
574   while (current != NULL) {
575     // save time remaining for timer.
576     time += current->delta;
577     // Check if the current timer has the flags requested
578     if (current->option_flags == option_flags
579         || option_flags == SL_SLEEPTIMER_ANY_FLAG) {
580       // Substract time since last compare match.
581       if (time > (sleeptimer_hal_get_counter() - last_delta_update_count)) {
582         time -= (sleeptimer_hal_get_counter() - last_delta_update_count);
583       } else {
584         time = 0;
585       }
586       *time_remaining = time;
587       CORE_EXIT_ATOMIC();
588 
589       return SL_STATUS_OK;
590     }
591     current = current->next;
592   }
593   CORE_EXIT_ATOMIC();
594 
595   return SL_STATUS_EMPTY;
596 }
597 
598 /**************************************************************************//**
599  * Determines if next timer to expire has the option flag
600  * "SL_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG".
601  *
602  * @note This function is for internal use only.
603  *
604  * @note A check to validate that the Power Manager Sleeptimer is expired on
605  *       top of being the next timer was added. This is because
606  *       this function is called when coming back from EM2 sleep to validate
607  *       that the system woke up because of this precise timer expiration.
608  *       Some race conditions, seen with FreeRTOS, could create invalid RTC
609  *       interrupt leading to believe that the power manager timer was expired
610  *       when it was not.
611  *****************************************************************************/
sli_sleeptimer_is_power_manager_timer_next_to_expire(void)612 bool sli_sleeptimer_is_power_manager_timer_next_to_expire(void)
613 {
614   bool next_timer_is_power_manager;
615 
616   sl_atomic_load(next_timer_is_power_manager, next_timer_to_expire_is_power_manager);
617 
618   // Make sure that the Power Manager Sleeptimer is actually expired in addition
619   // to being the next timer.
620   if (next_timer_is_power_manager
621       && ((sl_sleeptimer_get_tick_count() - timer_head->timeout_expected_tc) > MIN_DIFF_BETWEEN_COUNT_AND_EXPIRATION)) {
622     next_timer_is_power_manager = false;
623   }
624 
625   return next_timer_is_power_manager;
626 }
627 
628 /***************************************************************************//**
629 * Gets current 32 bits tick count.
630 *******************************************************************************/
sl_sleeptimer_get_tick_count(void)631 uint32_t sl_sleeptimer_get_tick_count(void)
632 {
633   uint32_t cnt;
634   CORE_DECLARE_IRQ_STATE;
635 
636   CORE_ENTER_ATOMIC();
637   cnt = sleeptimer_hal_get_counter();
638   CORE_EXIT_ATOMIC();
639 
640   return cnt;
641 }
642 
643 /***************************************************************************//**
644 * Gets current 64 bits tick count.
645 *******************************************************************************/
sl_sleeptimer_get_tick_count64(void)646 uint64_t sl_sleeptimer_get_tick_count64(void)
647 {
648   uint32_t tick_cnt;
649   uint32_t of_cnt;
650   CORE_DECLARE_IRQ_STATE;
651 
652   CORE_ENTER_ATOMIC();
653   tick_cnt = sleeptimer_hal_get_counter();
654   of_cnt = overflow_counter;
655 
656   if (sli_sleeptimer_hal_is_int_status_set(SLEEPTIMER_EVENT_OF)) {
657     tick_cnt = sleeptimer_hal_get_counter();
658     of_cnt++;
659   }
660   CORE_EXIT_ATOMIC();
661 
662   return (((uint64_t) of_cnt) << 32) | tick_cnt;
663 }
664 
665 /***************************************************************************//**
666  * Get timer frequency.
667  ******************************************************************************/
sl_sleeptimer_get_timer_frequency(void)668 uint32_t sl_sleeptimer_get_timer_frequency(void)
669 {
670   return timer_frequency;
671 }
672 
673 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
674 /***************************************************************************//**
675  * Retrieves current 32 bit time.
676  ******************************************************************************/
sl_sleeptimer_get_time(void)677 sl_sleeptimer_timestamp_t sl_sleeptimer_get_time(void)
678 {
679   uint64_t temp_time = sl_sleeptimer_get_time_64();
680   // Add offset for 64 to 32 bit time
681   if (temp_time >= TIME_64_TO_32_EPOCH_OFFSET_SEC) {
682     temp_time -= TIME_64_TO_32_EPOCH_OFFSET_SEC;
683   }
684   // Return lower 32 bits of 64 bit time
685   uint32_t time = (temp_time & 0xFFFFFFFF);
686 
687   return time;
688 }
689 
690 /***************************************************************************//**
691  * Retrieves current 64 bit time.
692  ******************************************************************************/
sl_sleeptimer_get_time_64(void)693 sl_sleeptimer_timestamp_64_t sl_sleeptimer_get_time_64(void)
694 {
695   uint32_t cnt = 0u;
696   uint32_t freq = 0u;
697   sl_sleeptimer_timestamp_64_t time;
698   CORE_DECLARE_IRQ_STATE;
699 
700   cnt = sleeptimer_hal_get_counter();
701   freq = sl_sleeptimer_get_timer_frequency();
702 
703   CORE_ENTER_ATOMIC();
704   time = second_count + cnt / freq;
705 
706   if (cnt % freq + overflow_tick_rest >= freq) {
707     time++;
708   }
709   CORE_EXIT_ATOMIC();
710 
711   return time;
712 }
713 
714 /***************************************************************************//**
715  * Sets current time from 32 bit variable.
716  ******************************************************************************/
sl_sleeptimer_set_time(sl_sleeptimer_timestamp_t time)717 sl_status_t sl_sleeptimer_set_time(sl_sleeptimer_timestamp_t time)
718 {
719   // convert 32 bit time to 64 bit time
720   uint64_t temp_time = time + (uint64_t)TIME_64_TO_32_EPOCH_OFFSET_SEC;
721   sl_status_t err_code = sl_sleeptimer_set_time_64(temp_time);
722   return err_code;
723 }
724 
725 /***************************************************************************//**
726  * Sets current time from 64 bit variable.
727  ******************************************************************************/
sl_sleeptimer_set_time_64(sl_sleeptimer_timestamp_64_t time)728 sl_status_t sl_sleeptimer_set_time_64(sl_sleeptimer_timestamp_64_t time)
729 {
730   uint32_t freq = 0u;
731   uint32_t counter_sec = 0u;
732   uint32_t cnt = 0;
733   CORE_DECLARE_IRQ_STATE;
734 
735   // convert 64 bit time to 32 bit time
736   if (!is_valid_time_64(time, TIME_FORMAT_UNIX_64_BIT, 0u)) {
737     return SL_STATUS_INVALID_PARAMETER;
738   }
739 
740   freq = sl_sleeptimer_get_timer_frequency();
741   cnt = sleeptimer_hal_get_counter();
742 
743   CORE_ENTER_ATOMIC();
744   // store 64 bit time as 64 bits's
745   second_count = time;
746 
747   // Convert 64 bit time to 32 bit time in order to check for overflow
748   // i.e. if 32 bit time is >=counter_sec
749   uint64_t temp_time = second_count - TIME_64_TO_32_EPOCH_OFFSET_SEC;
750   uint32_t second_time_32 = (temp_time & 0xFFFFFFFF);
751 
752   overflow_tick_rest = 0;
753   counter_sec = cnt / freq;
754 
755   if (second_time_32 >= counter_sec) {
756     second_count -= counter_sec;
757   } else {
758     CORE_EXIT_ATOMIC();
759 
760     return SL_STATUS_INVALID_PARAMETER;
761   }
762 
763   CORE_EXIT_ATOMIC();
764 
765   return SL_STATUS_OK;
766 }
767 
768 /***************************************************************************//**
769  * Gets current date.
770  ******************************************************************************/
sl_sleeptimer_get_datetime(sl_sleeptimer_date_t * date)771 sl_status_t sl_sleeptimer_get_datetime(sl_sleeptimer_date_t *date)
772 {
773   sl_sleeptimer_timestamp_64_t time = 0u;
774   sl_sleeptimer_time_zone_offset_t tz;
775   sl_status_t err_code = SL_STATUS_OK;
776 
777   // Fetch 64 bit timestamp
778   time = sl_sleeptimer_get_time_64();
779   tz = sl_sleeptimer_get_tz();
780   err_code = sl_sleeptimer_convert_time_to_date_64(time, tz, date);
781 
782   return err_code;
783 }
784 
785 /***************************************************************************//**
786  * Sets current time, in date format.
787  ******************************************************************************/
sl_sleeptimer_set_datetime(sl_sleeptimer_date_t * date)788 sl_status_t sl_sleeptimer_set_datetime(sl_sleeptimer_date_t *date)
789 {
790   sl_sleeptimer_timestamp_64_t time = 0u;
791   sl_status_t err_code = SL_STATUS_OK;
792   CORE_DECLARE_IRQ_STATE;
793 
794   if (!is_valid_date_64(date)) {
795     return SL_STATUS_INVALID_PARAMETER;
796   }
797 
798   err_code = sl_sleeptimer_convert_date_to_time_64(date, &time);
799   if (err_code != SL_STATUS_OK) {
800     return err_code;
801   }
802 
803   CORE_ENTER_ATOMIC();
804   // sets the 64 bit second_time value
805   err_code = sl_sleeptimer_set_time_64(time);
806   if (err_code == SL_STATUS_OK) {
807     sl_sleeptimer_set_tz(date->time_zone);
808   }
809   CORE_EXIT_ATOMIC();
810 
811   return err_code;
812 }
813 
814 /***************************************************************************//**
815  * Builds a date time structure based on the provided parameters.
816  ******************************************************************************/
sl_sleeptimer_build_datetime(sl_sleeptimer_date_t * date,uint16_t year,sl_sleeptimer_month_t month,uint8_t month_day,uint8_t hour,uint8_t min,uint8_t sec,sl_sleeptimer_time_zone_offset_t tz_offset)817 sl_status_t sl_sleeptimer_build_datetime(sl_sleeptimer_date_t *date,
818                                          uint16_t year,
819                                          sl_sleeptimer_month_t month,
820                                          uint8_t month_day,
821                                          uint8_t hour,
822                                          uint8_t min,
823                                          uint8_t sec,
824                                          sl_sleeptimer_time_zone_offset_t tz_offset)
825 {
826   if (date == NULL) {
827     return SL_STATUS_NULL_POINTER;
828   }
829 
830   // If year is smaller than 1900, assume NTP Epoch is used.
831   date->year = ((year < TIME_NTP_EPOCH) ? year : (year - TIME_NTP_EPOCH));
832   date->month = month;
833   date->month_day = month_day;
834   date->hour = hour;
835   date->min = min;
836   date->sec = sec;
837   date->time_zone = tz_offset;
838 
839   // Validate that input parameters are correct before filing the missing fields
840   if (!is_valid_date(date)) {
841     return SL_STATUS_INVALID_PARAMETER;
842   }
843 
844   date->day_of_year = compute_day_of_year(date->month, date->month_day, is_leap_year(date->year));
845   date->day_of_week = compute_day_of_week(((date->year - TIME_NTP_UNIX_EPOCH_DIFF)  * TIME_DAY_PER_YEAR)
846                                           + number_of_leap_days(TIME_UNIX_EPOCH, (date->year + TIME_NTP_EPOCH))
847                                           + date->day_of_year - 1);
848 
849   return SL_STATUS_OK;
850 }
851 
852 /***************************************************************************//**
853  * Builds a date time structure based on the provided parameters.
854  ******************************************************************************/
sl_sleeptimer_build_datetime_64(sl_sleeptimer_date_t * date,uint16_t year,sl_sleeptimer_month_t month,uint8_t month_day,uint8_t hour,uint8_t min,uint8_t sec,sl_sleeptimer_time_zone_offset_t tz_offset)855 sl_status_t sl_sleeptimer_build_datetime_64(sl_sleeptimer_date_t *date,
856                                             uint16_t year,
857                                             sl_sleeptimer_month_t month,
858                                             uint8_t month_day,
859                                             uint8_t hour,
860                                             uint8_t min,
861                                             uint8_t sec,
862                                             sl_sleeptimer_time_zone_offset_t tz_offset)
863 {
864   if (date == NULL) {
865     return SL_STATUS_NULL_POINTER;
866   }
867 
868   // Ensure that year is greater than 1900 and based on 0 epoch
869   if (year < TIME_NTP_EPOCH) {
870     return SL_STATUS_INVALID_PARAMETER;
871   }
872 
873   // Convert year based on 0 epoch to a valid date->year based on 1900 epoch
874   date->year = (year - TIME_NTP_EPOCH);
875   date->month = month;
876   date->month_day = month_day;
877   date->hour = hour;
878   date->min = min;
879   date->sec = sec;
880   date->time_zone = tz_offset;
881 
882   // Validate that input parameters are correct before filing the missing fields
883   if (!is_valid_date_64(date)) {
884     return SL_STATUS_INVALID_PARAMETER;
885   }
886 
887   date->day_of_year = compute_day_of_year(date->month, date->month_day, is_leap_year(date->year));
888   date->day_of_week = compute_day_of_week_64((date->year * TIME_DAY_PER_YEAR)
889                                              + number_of_leap_days(TIME_NTP_EPOCH, (date->year + TIME_NTP_EPOCH))
890                                              + date->day_of_year - 1);
891 
892   return SL_STATUS_OK;
893 }
894 
895 /*******************************************************************************
896  * Convert a 32 bit time stamp into a date structure.
897  ******************************************************************************/
sl_sleeptimer_convert_time_to_date(sl_sleeptimer_timestamp_t time,sl_sleeptimer_time_zone_offset_t time_zone,sl_sleeptimer_date_t * date)898 sl_status_t sl_sleeptimer_convert_time_to_date(sl_sleeptimer_timestamp_t time,
899                                                sl_sleeptimer_time_zone_offset_t time_zone,
900                                                sl_sleeptimer_date_t *date)
901 {
902   // convert 32 bit timestamp to 64 bit
903   sl_sleeptimer_timestamp_64_t temp_time = (uint64_t)time + TIME_64_TO_32_EPOCH_OFFSET_SEC;
904   sl_status_t err_code = sl_sleeptimer_convert_time_to_date_64(temp_time, time_zone, date);
905   return err_code;
906 }
907 
908 /*******************************************************************************
909  * Convert a 64 bit time stamp into a date structure.
910  ******************************************************************************/
sl_sleeptimer_convert_time_to_date_64(sl_sleeptimer_timestamp_64_t time,sl_sleeptimer_time_zone_offset_t time_zone,sl_sleeptimer_date_t * date)911 sl_status_t sl_sleeptimer_convert_time_to_date_64(sl_sleeptimer_timestamp_64_t time,
912                                                   sl_sleeptimer_time_zone_offset_t time_zone,
913                                                   sl_sleeptimer_date_t *date)
914 {
915   uint16_t full_year = 0;
916   uint16_t leap_day = 0;
917   uint8_t leap_year_flag = 0;
918   uint8_t current_month = 0;
919 
920   if (!is_valid_time_64(time, TIME_FORMAT_UNIX_64_BIT, time_zone)) {
921     return SL_STATUS_INVALID_PARAMETER;
922   }
923 
924   time += time_zone;  // add UTC offset to convert to Standard Time
925   date->sec = time % 60;
926   time /= 60;
927   date->min = time % 60;
928   time /= 60;
929   date->hour = time % 24;
930   time /= 24; // time is now the number of days since 1900
931 
932   date->day_of_week = (sl_sleeptimer_weekDay_t)compute_day_of_week_64(time);
933 
934   full_year = time / TIME_DAY_PER_YEAR; // Approximates the number of full years
935   uint32_t base_year = 1900u;
936   uint32_t current_year = full_year + base_year;
937 
938   if (full_year > 4) { // 1904 is the first leap year since 1900
939     leap_day = number_of_leap_days(base_year, current_year);  // Approximates the number of leap days.
940     full_year = (time - leap_day) / TIME_DAY_PER_YEAR; // Computes the number of year integrating the leap days.
941     current_year = full_year + base_year;
942     leap_day = number_of_leap_days(base_year, current_year); // Computes the actual number of leap days of the previous years.
943   }
944   date->year = full_year; // Year in date struct must be based on a 1900 epoch.
945   if (is_leap_year(date->year)) {
946     leap_year_flag = 1;
947   }
948 
949   time = (time - leap_day) - (TIME_DAY_PER_YEAR * full_year);  // Subtracts days of previous year.
950   date->day_of_year = time + 1;
951 
952   while (time >= days_in_month[leap_year_flag][current_month]) {
953     time -= days_in_month[leap_year_flag][current_month]; // Subtracts the number of days of the passed month.
954     current_month++;
955   }
956   date->month = (sl_sleeptimer_month_t)current_month;
957   date->month_day = time + 1;
958   date->time_zone = time_zone;
959 
960   return SL_STATUS_OK;
961 }
962 
963 /*******************************************************************************
964  * Convert a date structure into a 32 bit time stamp.
965  ******************************************************************************/
sl_sleeptimer_convert_date_to_time(sl_sleeptimer_date_t * date,sl_sleeptimer_timestamp_t * time)966 sl_status_t sl_sleeptimer_convert_date_to_time(sl_sleeptimer_date_t *date,
967                                                sl_sleeptimer_timestamp_t *time)
968 {
969   // Create a 64 bit time stamp
970   sl_sleeptimer_timestamp_64_t temp_time =  0;
971   sl_status_t err_code = sl_sleeptimer_convert_date_to_time_64(date, &temp_time);
972 
973   if (err_code != SL_STATUS_OK) {
974     return err_code;
975   }
976   // Convert 64 bit time to 32 bit time
977 
978   sl_sleeptimer_timestamp_64_t time_32 = temp_time;
979   time_32 -= TIME_64_TO_32_EPOCH_OFFSET_SEC;
980   *time = (time_32 & 0xFFFFFFFF);
981 
982   return err_code;
983 }
984 
985 /*******************************************************************************
986  * Convert a date structure into a 64 bit time stamp.
987  ******************************************************************************/
sl_sleeptimer_convert_date_to_time_64(sl_sleeptimer_date_t * date,sl_sleeptimer_timestamp_64_t * time)988 sl_status_t sl_sleeptimer_convert_date_to_time_64(sl_sleeptimer_date_t *date,
989                                                   sl_sleeptimer_timestamp_64_t *time)
990 {
991   uint16_t month_days = 0;
992   uint8_t  month;
993   uint16_t  full_year = 0;
994   uint8_t  leap_year_flag = 0;
995   uint16_t  leap_days = 0;
996 
997   if (!is_valid_date_64(date)) {
998     return SL_STATUS_INVALID_PARAMETER;
999   }
1000 
1001   full_year = (date->year);                                  // base year for 64 bits its 1900 not 1970
1002   month = date->month;                              // offset to get months value from 1 to 12.
1003 
1004   uint32_t base_year = 1900u;
1005   uint32_t current_year = full_year + base_year;
1006 
1007   *time = (full_year * (uint64_t)TIME_SEC_PER_YEAR);
1008 
1009   if (full_year > 4) {                                       // 1904 is the first leap year since 1900
1010     leap_days = number_of_leap_days(base_year, current_year);
1011     month_days = leap_days;
1012   }
1013 
1014   if (is_leap_year(date->year)) {
1015     leap_year_flag = 1;
1016   }
1017 
1018   for (int i = 0; i < month; i++) {
1019     month_days += days_in_month[leap_year_flag][i];         // Add the number of days of the month of the year.
1020   }
1021 
1022   month_days += (date->month_day - 1);                       // Add full days of the current month.
1023   *time += month_days * TIME_SEC_PER_DAY;
1024   *time += (3600 * date->hour) + (60 * date->min) + date->sec;
1025   *time -= date->time_zone;
1026 
1027   return SL_STATUS_OK;
1028 }
1029 
1030 /*******************************************************************************
1031  * Convert a date structure to string.
1032  ******************************************************************************/
sl_sleeptimer_convert_date_to_str(char * str,size_t size,const uint8_t * format,sl_sleeptimer_date_t * date)1033 uint32_t sl_sleeptimer_convert_date_to_str(char *str,
1034                                            size_t size,
1035                                            const uint8_t *format,
1036                                            sl_sleeptimer_date_t *date)
1037 {
1038   uint32_t  return_size = 0u;
1039   if (is_valid_date(date)) {
1040     struct tm date_struct;
1041 
1042     date_struct.tm_hour = date->hour;
1043     date_struct.tm_mday = date->month_day;
1044     date_struct.tm_min = date->min;
1045     date_struct.tm_mon = date->month;
1046     date_struct.tm_sec = date->sec;
1047     date_struct.tm_wday = date->day_of_week;
1048     date_struct.tm_yday = date->day_of_year;
1049     date_struct.tm_year = date->year;
1050 
1051     return_size = strftime(str,
1052                            size,
1053                            (const char *)format,
1054                            &date_struct);
1055   }
1056 
1057   return return_size;
1058 }
1059 
1060 /***************************************************************************//**
1061  * Sets time zone offset.
1062  *
1063  * @param  offset  Time zone offset, in seconds.
1064  ******************************************************************************/
sl_sleeptimer_set_tz(sl_sleeptimer_time_zone_offset_t offset)1065 void sl_sleeptimer_set_tz(sl_sleeptimer_time_zone_offset_t offset)
1066 {
1067   CORE_DECLARE_IRQ_STATE;
1068 
1069   CORE_ENTER_ATOMIC();
1070   tz_offset = offset;
1071   CORE_EXIT_ATOMIC();
1072 }
1073 
1074 /***************************************************************************//**
1075  * Gets time zone offset.
1076  *
1077  * @return Time zone offset, in seconds.
1078  ******************************************************************************/
sl_sleeptimer_get_tz(void)1079 sl_sleeptimer_time_zone_offset_t sl_sleeptimer_get_tz(void)
1080 {
1081   sl_sleeptimer_time_zone_offset_t offset;
1082   CORE_DECLARE_IRQ_STATE;
1083 
1084   CORE_ENTER_ATOMIC();
1085   offset = tz_offset;
1086   CORE_EXIT_ATOMIC();
1087 
1088   return offset;
1089 }
1090 
1091 /***************************************************************************//**
1092  * Converts Unix 32 timestamp into NTP timestamp.
1093  ******************************************************************************/
sl_sleeptimer_convert_unix_time_to_ntp(sl_sleeptimer_timestamp_t time,uint32_t * ntp_time)1094 sl_status_t sl_sleeptimer_convert_unix_time_to_ntp(sl_sleeptimer_timestamp_t time,
1095                                                    uint32_t *ntp_time)
1096 {
1097   if (time > TIME_UNIX_TO_NTP_MAX) {
1098     // Maximum Unix timestamp that can be converted to NTP is 2085978495
1099     return SL_STATUS_INVALID_PARAMETER;
1100   }
1101 
1102   uint32_t temp_ntp_time;
1103   temp_ntp_time = time + TIME_NTP_EPOCH_OFFSET_SEC;
1104   if (!is_valid_time(temp_ntp_time, TIME_FORMAT_NTP, 0u)) {
1105     return SL_STATUS_INVALID_PARAMETER;
1106   } else {
1107     *ntp_time = temp_ntp_time;
1108     return SL_STATUS_OK;
1109   }
1110 }
1111 
1112 /***************************************************************************//**
1113  * Converts NTP timestamp into Unix timestamp.
1114  ******************************************************************************/
sl_sleeptimer_convert_ntp_time_to_unix(uint32_t ntp_time,sl_sleeptimer_timestamp_t * time)1115 sl_status_t sl_sleeptimer_convert_ntp_time_to_unix(uint32_t ntp_time,
1116                                                    sl_sleeptimer_timestamp_t *time)
1117 {
1118   uint32_t temp_time;
1119   temp_time = ntp_time - TIME_NTP_EPOCH_OFFSET_SEC;
1120   if (!is_valid_time(temp_time, TIME_FORMAT_UNIX, 0u)) {
1121     return SL_STATUS_INVALID_PARAMETER;
1122   } else {
1123     *time = temp_time;
1124     return SL_STATUS_OK;
1125   }
1126 }
1127 
1128 /***************************************************************************//**
1129  * Converts Unix timestamp into Zigbee timestamp.
1130  ******************************************************************************/
sl_sleeptimer_convert_unix_time_to_zigbee(sl_sleeptimer_timestamp_t time,uint32_t * zigbee_time)1131 sl_status_t sl_sleeptimer_convert_unix_time_to_zigbee(sl_sleeptimer_timestamp_t time,
1132                                                       uint32_t *zigbee_time)
1133 {
1134   uint32_t temp_zigbee_time;
1135   temp_zigbee_time = time - TIME_ZIGBEE_EPOCH_OFFSET_SEC;
1136   if (!is_valid_time(temp_zigbee_time, TIME_FORMAT_ZIGBEE_CLUSTER, 0u)) {
1137     return SL_STATUS_INVALID_PARAMETER;
1138   } else {
1139     *zigbee_time = temp_zigbee_time;
1140     return SL_STATUS_OK;
1141   }
1142 }
1143 
1144 /***************************************************************************//**
1145  * Converts Zigbee timestamp into Unix timestamp.
1146  ******************************************************************************/
sl_sleeptimer_convert_zigbee_time_to_unix(uint32_t zigbee_time,sl_sleeptimer_timestamp_t * time)1147 sl_status_t sl_sleeptimer_convert_zigbee_time_to_unix(uint32_t zigbee_time,
1148                                                       sl_sleeptimer_timestamp_t *time)
1149 {
1150   uint32_t temp_time;
1151   temp_time = zigbee_time + TIME_ZIGBEE_EPOCH_OFFSET_SEC;
1152   if (!is_valid_time(temp_time, TIME_FORMAT_UNIX, 0u)) {
1153     return SL_STATUS_INVALID_PARAMETER;
1154   } else {
1155     *time = temp_time;
1156     return SL_STATUS_OK;
1157   }
1158 }
1159 
1160 #endif // SL_SLEEPTIMER_WALLCLOCK_CONFIG
1161 
1162 /*******************************************************************************
1163  * Active delay of 'time_ms' milliseconds.
1164  ******************************************************************************/
sl_sleeptimer_delay_millisecond(uint16_t time_ms)1165 void sl_sleeptimer_delay_millisecond(uint16_t time_ms)
1166 {
1167   volatile bool wait = true;
1168   sl_status_t error_code;
1169   sl_sleeptimer_timer_handle_t delay_timer;
1170   uint32_t delay = sl_sleeptimer_ms_to_tick(time_ms);
1171 
1172   error_code = sl_sleeptimer_start_timer(&delay_timer,
1173                                          delay,
1174                                          delay_callback,
1175                                          (void *)&wait,
1176                                          0,
1177                                          0);
1178   if (error_code == SL_STATUS_OK) {
1179     while (wait) { // Active delay loop.
1180     }
1181   }
1182 }
1183 
1184 /*******************************************************************************
1185  * Converts milliseconds in ticks.
1186  ******************************************************************************/
sl_sleeptimer_ms_to_tick(uint16_t time_ms)1187 uint32_t sl_sleeptimer_ms_to_tick(uint16_t time_ms)
1188 {
1189   return (uint32_t)((((uint64_t)time_ms * timer_frequency) + 999) / 1000);
1190 }
1191 
1192 /*******************************************************************************
1193  * Converts 32-bits milliseconds in ticks.
1194  ******************************************************************************/
sl_sleeptimer_ms32_to_tick(uint32_t time_ms,uint32_t * tick)1195 sl_status_t sl_sleeptimer_ms32_to_tick(uint32_t time_ms,
1196                                        uint32_t *tick)
1197 {
1198   if (time_ms <= max_millisecond_conversion) {
1199     *tick = (uint32_t)((((uint64_t)time_ms * timer_frequency) + 999) / 1000u);
1200     return SL_STATUS_OK;
1201   } else {
1202     return SL_STATUS_INVALID_PARAMETER;
1203   }
1204 }
1205 
1206 /***************************************************************************//**
1207  * Gets the maximum value that can be passed to the functions that have a
1208  * 32-bits time or timeout argument expressed in milliseconds.
1209  ******************************************************************************/
sl_sleeptimer_get_max_ms32_conversion(void)1210 uint32_t sl_sleeptimer_get_max_ms32_conversion(void)
1211 {
1212   return max_millisecond_conversion;
1213 }
1214 
1215 /*******************************************************************************
1216  * Converts ticks in milliseconds.
1217  ******************************************************************************/
sl_sleeptimer_tick_to_ms(uint32_t tick)1218 uint32_t sl_sleeptimer_tick_to_ms(uint32_t tick)
1219 {
1220   uint32_t time_ms;
1221   time_ms = 0;
1222 
1223   if (timer_frequency != 0u) {
1224     if (is_power_of_2(timer_frequency)) {
1225       time_ms = (uint32_t)(((uint64_t)tick * (uint64_t)1000u) >> div_to_log2(timer_frequency));
1226     } else {
1227       time_ms = (uint32_t)(((uint64_t)tick * (uint64_t)1000u) / timer_frequency);
1228     }
1229   }
1230 
1231   return time_ms;
1232 }
1233 
1234 /*******************************************************************************
1235  * Converts 64-bits ticks in milliseconds.
1236  ******************************************************************************/
sl_sleeptimer_tick64_to_ms(uint64_t tick,uint64_t * ms)1237 sl_status_t sl_sleeptimer_tick64_to_ms(uint64_t tick,
1238                                        uint64_t *ms)
1239 
1240 {
1241   if ((tick <= UINT64_MAX / 1000)
1242       && (timer_frequency != 0u)) {
1243     if (is_power_of_2(timer_frequency)) {
1244       *ms = (tick * (uint64_t)1000u) >> div_to_log2(timer_frequency);
1245       return SL_STATUS_OK;
1246     } else {
1247       *ms = (tick * (uint64_t)1000u) / timer_frequency;
1248       return SL_STATUS_OK;
1249     }
1250   } else {
1251     return SL_STATUS_INVALID_PARAMETER;
1252   }
1253 }
1254 
1255 /*******************************************************************************
1256  * Process timer interrupt.
1257  *
1258  * @param local_flag Flag indicating the type of timer interrupt.
1259  ******************************************************************************/
process_timer_irq(uint8_t local_flag)1260 void process_timer_irq(uint8_t local_flag)
1261 {
1262   CORE_DECLARE_IRQ_STATE;
1263   if (local_flag & SLEEPTIMER_EVENT_OF) {
1264 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
1265     uint32_t timer_freq = sl_sleeptimer_get_timer_frequency();
1266 
1267     overflow_tick_rest += calculated_tick_rest;
1268     if (overflow_tick_rest >= timer_freq) {
1269       second_count++;
1270       overflow_tick_rest -= timer_freq;
1271     }
1272     second_count = second_count + calculated_sec_count;
1273 #endif
1274     overflow_counter++;
1275 
1276     update_delta_list();
1277 
1278     set_comparator_for_next_timer();
1279   }
1280 
1281   if (local_flag & SLEEPTIMER_EVENT_COMP) {
1282     sl_sleeptimer_timer_handle_t *current = NULL;
1283 
1284     uint32_t nb_timer_expire = 0u;
1285     uint16_t option_flags = 0;
1286 
1287     CORE_ENTER_ATOMIC();
1288     // Make sure the timers list is up to date with the time elapsed since the last update
1289     update_delta_list();
1290 
1291     // Process all timers that have expired.
1292     while (timer_head && (timer_head->delta == 0)) {
1293       sl_sleeptimer_timer_handle_t *temp = timer_head;
1294       current = timer_head;
1295 
1296       // Process timers with higher priority first
1297       while ((temp != NULL) && (temp->delta == 0)) {
1298         if (current->priority > temp->priority) {
1299           current = temp;
1300         }
1301         temp = temp->next;
1302       }
1303       CORE_EXIT_ATOMIC();
1304 
1305       process_expired_timer(current);
1306 
1307       // Save current option flag and the number of timers that expired.
1308       option_flags = current->option_flags;
1309       nb_timer_expire++;
1310 
1311       CORE_ENTER_ATOMIC();
1312 
1313       // Re-update the list to account for delays during timer's callback.
1314       update_delta_list();
1315     }
1316 
1317     // If the only timer expired is the internal Power Manager one,
1318     // from the Sleeptimer perspective, the system can go back to sleep after the ISR handling.
1319     sleep_on_isr_exit = false;
1320     if ((nb_timer_expire == 1u) && (option_flags & SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG)) {
1321       sleep_on_isr_exit = true;
1322     }
1323 
1324     sl_status_t error = set_comparator_for_next_timer();
1325     if (error == SL_STATUS_NULL_POINTER) {
1326       sleeptimer_hal_disable_int(SLEEPTIMER_EVENT_COMP);
1327     }
1328     CORE_EXIT_ATOMIC();
1329   }
1330 }
1331 
1332 /*******************************************************************************
1333  * Timer expiration callback for the delay function.
1334  *
1335  * @param handle Pointer to handle to timer.
1336  * @param data Pointer to delay flag.
1337  ******************************************************************************/
delay_callback(sl_sleeptimer_timer_handle_t * handle,void * data)1338 static void delay_callback(sl_sleeptimer_timer_handle_t *handle,
1339                            void *data)
1340 {
1341   volatile bool *wait_flag = (bool *)data;
1342 
1343   (void)handle;  // Unused parameter.
1344 
1345   *wait_flag = false;
1346 }
1347 
1348 /*******************************************************************************
1349  * Inserts a timer in the delta list.
1350  *
1351  * @param handle Pointer to handle to timer.
1352  * @param timeout Timer timeout, in ticks.
1353  ******************************************************************************/
delta_list_insert_timer(sl_sleeptimer_timer_handle_t * handle,sl_sleeptimer_tick_count_t timeout)1354 static void delta_list_insert_timer(sl_sleeptimer_timer_handle_t *handle,
1355                                     sl_sleeptimer_tick_count_t timeout)
1356 {
1357   sl_sleeptimer_tick_count_t local_handle_delta = timeout;
1358 
1359 #ifdef SL_CATALOG_POWER_MANAGER_PRESENT
1360   // If Power Manager is present, it's possible that a clock restore is needed right away
1361   // if we are in the context of a deepsleep and the timeout value is smaller than the restore time.
1362   // If it's the case, the restore will be started and the timeout value will be updated to match
1363   // the restore delay.
1364   if (handle->option_flags == 0) {
1365     uint32_t wakeup_delay = sli_power_manager_get_restore_delay();
1366 
1367     if (local_handle_delta < wakeup_delay) {
1368       local_handle_delta = wakeup_delay;
1369       sli_power_manager_initiate_restore();
1370     }
1371   }
1372 #endif
1373 
1374   handle->delta = local_handle_delta;
1375 
1376   if (timer_head != NULL) {
1377     sl_sleeptimer_timer_handle_t *prev = NULL;
1378     sl_sleeptimer_timer_handle_t *current = timer_head;
1379     // Find timer position taking into accounts the deltas and priority.
1380     while (current != NULL
1381            && (local_handle_delta >= current->delta || current->delta == 0u
1382                || (((local_handle_delta - current->delta) == 0) && (handle->priority > current->priority)))) {
1383       local_handle_delta -= current->delta;
1384       handle->delta = local_handle_delta;
1385       prev = current;
1386       current = current->next;
1387     }
1388 
1389     // Insert timer in middle of delta list.
1390     if (prev != NULL) {
1391       prev->next = handle;
1392     } else {
1393       timer_head = handle;
1394     }
1395     handle->next = current;
1396 
1397     if (current != NULL) {
1398       current->delta -= local_handle_delta;
1399     }
1400   } else {
1401     timer_head = handle;
1402     handle->next = NULL;
1403   }
1404 }
1405 
1406 /*******************************************************************************
1407  * Removes a timer from delta list.
1408  *
1409  * @param handle Pointer to handle to timer.
1410  *
1411  * @return 0 if successful. Error code otherwise.
1412  ******************************************************************************/
delta_list_remove_timer(sl_sleeptimer_timer_handle_t * handle)1413 static sl_status_t delta_list_remove_timer(sl_sleeptimer_timer_handle_t *handle)
1414 {
1415   sl_sleeptimer_timer_handle_t *prev = NULL;
1416   sl_sleeptimer_timer_handle_t *current = timer_head;
1417 
1418   if (handle == NULL) {
1419     return SL_STATUS_NULL_POINTER;
1420   }
1421 
1422   // Retrieve timer in delta list.
1423   while (current != NULL && current != handle) {
1424     prev = current;
1425     current = current->next;
1426   }
1427 
1428   if (current != handle) {
1429     return SL_STATUS_INVALID_STATE;
1430   }
1431 
1432   if (prev != NULL) {
1433     prev->next = handle->next;
1434   } else {
1435     timer_head = handle->next;
1436   }
1437 
1438   // Update delta of next timer
1439   if (handle->next != NULL) {
1440     handle->next->delta += handle->delta;
1441   }
1442 
1443   return SL_STATUS_OK;
1444 }
1445 
1446 /*******************************************************************************
1447  * Sets comparator for next timer.
1448  ******************************************************************************/
set_comparator_for_next_timer(void)1449 static sl_status_t set_comparator_for_next_timer(void)
1450 {
1451   if (timer_head) {
1452     if (timer_head->delta > 0) {
1453       sl_sleeptimer_tick_count_t compare_value;
1454 
1455       compare_value = last_delta_update_count + timer_head->delta;
1456 
1457       sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
1458       sleeptimer_hal_set_compare(compare_value);
1459     } else {
1460       // In case timer has already expire, don't attempt to set comparator. Just
1461       // trigger compare match interrupt.
1462       sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
1463       sleeptimer_hal_set_int(SLEEPTIMER_EVENT_COMP);
1464     }
1465     update_next_timer_to_expire_is_power_manager();
1466     return SL_STATUS_OK;
1467   }
1468 
1469   return SL_STATUS_NULL_POINTER;
1470 }
1471 
1472 /*******************************************************************************
1473  * Updates timer list's deltas.
1474  ******************************************************************************/
update_delta_list(void)1475 static void update_delta_list(void)
1476 {
1477   sl_sleeptimer_tick_count_t current_cnt = sleeptimer_hal_get_counter();
1478   sl_sleeptimer_timer_handle_t *timer_handle = timer_head;
1479   sl_sleeptimer_tick_count_t time_diff = current_cnt - last_delta_update_count;
1480 
1481   // Go through the delta timer list and update every necessary deltas
1482   // according to the time elapsed since the last update.
1483   while (timer_handle != NULL && time_diff > 0) {
1484     if (timer_handle->delta >= time_diff) {
1485       timer_handle->delta -= time_diff;
1486       time_diff = 0;
1487     } else {
1488       time_diff -= timer_handle->delta;
1489       timer_handle->delta = 0;
1490     }
1491     timer_handle = timer_handle->next;
1492   }
1493 
1494   last_delta_update_count = current_cnt;
1495 }
1496 
1497 /*******************************************************************************
1498  * Creates and start a 32 bits timer.
1499  *
1500  * @param handle Pointer to handle to timer.
1501  * @param timeout_initial Initial timeout, in timer ticks.
1502  * @param timeout_periodic Periodic timeout, in timer ticks. This timeout
1503  *        applies once timeoutInitial expires. Can be set to 0 for a one
1504  *        shot timer.
1505  * @param callback Callback function that will be called when
1506  *        initial/periodic timeout expires.
1507  * @param callback_data Pointer to user data that will be passed to callback.
1508  * @param priority Priority of callback. Useful in case multiple timer expire
1509  *        at the same time. 0 = highest priority.
1510  *
1511  * @return 0 if successful. Error code otherwise.
1512  ******************************************************************************/
create_timer(sl_sleeptimer_timer_handle_t * handle,sl_sleeptimer_tick_count_t timeout_initial,sl_sleeptimer_tick_count_t timeout_periodic,sl_sleeptimer_timer_callback_t callback,void * callback_data,uint8_t priority,uint16_t option_flags)1513 static sl_status_t create_timer(sl_sleeptimer_timer_handle_t *handle,
1514                                 sl_sleeptimer_tick_count_t timeout_initial,
1515                                 sl_sleeptimer_tick_count_t timeout_periodic,
1516                                 sl_sleeptimer_timer_callback_t callback,
1517                                 void *callback_data,
1518                                 uint8_t priority,
1519                                 uint16_t option_flags)
1520 {
1521   CORE_DECLARE_IRQ_STATE;
1522 
1523   handle->priority = priority;
1524   handle->callback_data = callback_data;
1525   handle->next = NULL;
1526   handle->timeout_periodic = timeout_periodic;
1527   handle->callback = callback;
1528   handle->option_flags = option_flags;
1529   if (timeout_periodic == 0) {
1530     handle->timeout_expected_tc = sleeptimer_hal_get_counter() + timeout_initial;
1531   } else {
1532     handle->timeout_expected_tc = sleeptimer_hal_get_counter() + timeout_periodic;
1533   }
1534 
1535   if (timeout_initial == 0) {
1536     handle->delta = 0;
1537     if (handle->callback != NULL) {
1538       handle->callback(handle, handle->callback_data);
1539     }
1540     if (timeout_periodic != 0) {
1541       timeout_initial = timeout_periodic;
1542     } else {
1543       return SL_STATUS_OK;
1544     }
1545   }
1546 
1547 #if ((SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_SYSRTC) \
1548   && defined(SL_CATALOG_POWER_MANAGER_PRESENT)                     \
1549   && !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT))
1550   if (option_flags == (SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG | SLI_SLEEPTIMER_POWER_MANAGER_HF_ACCURACY_CLK_FLAG)) {
1551     HFXO0->CTRL |= HFXO_CTRL_EM23ONDEMAND;
1552     sleeptimer_hal_set_compare_prs_hfxo_startup(timeout_initial);
1553     return SL_STATUS_OK;
1554   }
1555 #endif
1556 
1557   CORE_ENTER_CRITICAL();
1558   update_delta_list();
1559   delta_list_insert_timer(handle, timeout_initial);
1560 
1561   // If first timer, update timer comparator.
1562   if (timer_head == handle) {
1563     set_comparator_for_next_timer();
1564   }
1565 
1566   CORE_EXIT_CRITICAL();
1567 
1568   return SL_STATUS_OK;
1569 }
1570 
1571 /***************************************************************************//**
1572  * Processes an expired timer.
1573  *
1574  * @param timer Expired timer to process.
1575  ******************************************************************************/
process_expired_timer(sl_sleeptimer_timer_handle_t * timer)1576 static void process_expired_timer(sl_sleeptimer_timer_handle_t *timer)
1577 {
1578   CORE_DECLARE_IRQ_STATE;
1579   int32_t periodic_correction = 0u;
1580   int64_t timeout_temp = 0;
1581   bool skip_remove = false;
1582 
1583   // Check if periodic timer was delayed more than its actual timeout value
1584   // and keep it at the head of the timers list if it's the case so that the
1585   // callback function can be called the number of required time.
1586   if (timer->timeout_periodic != 0u) {
1587     timeout_temp = timer->timeout_periodic;
1588 
1589     periodic_correction = sleeptimer_hal_get_counter() - timer->timeout_expected_tc;
1590     if (periodic_correction >= timeout_temp) {
1591       skip_remove = true;
1592       timer->timeout_expected_tc += timer->timeout_periodic;
1593     }
1594   }
1595 
1596   // Remove timer from list except if the timer is a periodic timer that was
1597   // intentionally kept at the head of the timers list.
1598   if (skip_remove != true) {
1599     CORE_ENTER_ATOMIC();
1600     delta_list_remove_timer(timer);
1601     CORE_EXIT_ATOMIC();
1602   }
1603 
1604   // Re-insert periodic timer that was previsouly removed from the list
1605   // and compensate for any deviation from the periodic timer frequency.
1606   if (timer->timeout_periodic != 0u && skip_remove != true) {
1607     timeout_temp -= periodic_correction;
1608     EFM_ASSERT(timeout_temp > 0);
1609     // Compensate for drift caused by ms to ticks conversion
1610     if (timer->conversion_error > 0) {
1611       // Increment accumulated error by the ms to ticks conversion error
1612       timer->accumulated_error += timer->conversion_error;
1613       // If the accumulated error exceeds a tick, subtract that tick from the next
1614       // periodic timer's timeout value.
1615       if (timer->accumulated_error >= 1000) {
1616         timer->accumulated_error -= 1000;
1617         timeout_temp -= 1;
1618         timer->timeout_expected_tc -= 1;
1619       }
1620     }
1621     CORE_ENTER_ATOMIC();
1622     delta_list_insert_timer(timer, (sl_sleeptimer_tick_count_t)timeout_temp);
1623     timer->timeout_expected_tc += timer->timeout_periodic;
1624     CORE_EXIT_ATOMIC();
1625   }
1626 
1627   // Call timer callback function if any.
1628   if (timer->callback != NULL) {
1629     timer->callback(timer, timer->callback_data);
1630   }
1631 }
1632 
1633 /*******************************************************************************
1634  * Updates internal flag that indicates if next timer to expire is the power
1635  * manager's one.
1636  ******************************************************************************/
update_next_timer_to_expire_is_power_manager(void)1637 static void update_next_timer_to_expire_is_power_manager(void)
1638 {
1639   sl_sleeptimer_timer_handle_t *current = timer_head;
1640   uint32_t delta_diff_with_first = 0;
1641 
1642   next_timer_to_expire_is_power_manager = false;
1643 
1644   while ((delta_diff_with_first <= 1) && (current != NULL)) {
1645     if (current->option_flags & SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG) {
1646       next_timer_to_expire_is_power_manager = true;
1647       break;
1648     }
1649 
1650     current = current->next;
1651     if (current != NULL) {
1652       delta_diff_with_first += current->delta;
1653     }
1654   }
1655 }
1656 
1657 /**************************************************************************//**
1658  * Determines if the power manager's early wakeup expired during the last ISR
1659  * and it was the only timer to expire in that period.
1660  *
1661  * @return true if power manager sleep can return to sleep,
1662  *         false otherwise.
1663  *****************************************************************************/
sl_sleeptimer_is_power_manager_early_restore_timer_latest_to_expire(void)1664 bool sl_sleeptimer_is_power_manager_early_restore_timer_latest_to_expire(void)
1665 {
1666   CORE_DECLARE_IRQ_STATE;
1667   bool sleep;
1668 
1669   CORE_ENTER_ATOMIC();
1670   sleep = sleep_on_isr_exit;
1671   CORE_EXIT_ATOMIC();
1672 
1673   return sleep;
1674 }
1675 
1676 /*******************************************************************************
1677  * Convert dividend to logarithmic value. It only works for even
1678  * numbers equal to 2^n.
1679  *
1680  * @param  div An unscaled dividend.
1681  *
1682  * @return Logarithm of 2.
1683  ******************************************************************************/
div_to_log2(uint32_t div)1684 __STATIC_INLINE uint32_t div_to_log2(uint32_t div)
1685 {
1686   return 31UL - __CLZ(div);  // Count leading zeroes and "reverse" result.
1687 }
1688 
1689 /*******************************************************************************
1690  * Determines if a number is a power of two.
1691  *
1692  * @param  nbr Input value.
1693  *
1694  * @return True if the number is a power of two.
1695  ******************************************************************************/
is_power_of_2(uint32_t nbr)1696 __STATIC_INLINE bool is_power_of_2(uint32_t nbr)
1697 {
1698   if ((nbr != 0u) && ((nbr & (nbr - 1u)) == 0u)) {
1699     return true;
1700   } else {
1701     return false;
1702   }
1703 }
1704 
1705 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
1706 /*******************************************************************************
1707  * Compute the day of the week.
1708  *
1709  * @param day Days since January 1st of 1970.
1710  *
1711  * @return the day of the week.
1712  ******************************************************************************/
compute_day_of_week(uint32_t day)1713 static sl_sleeptimer_weekDay_t compute_day_of_week(uint32_t day)
1714 {
1715   return (sl_sleeptimer_weekDay_t)((day + 4) % 7); // January 1st was a Thursday(4) in 1970
1716 }
1717 
1718 /*******************************************************************************
1719  * Compute the day of the week.
1720  *
1721  * @param day Days since January 1st of 1900.
1722  *
1723  * @return the day of the week.
1724  ******************************************************************************/
compute_day_of_week_64(uint64_t day)1725 static sl_sleeptimer_weekDay_t compute_day_of_week_64(uint64_t day)
1726 {
1727   return (sl_sleeptimer_weekDay_t)((day + 1) % 7);  // January 1st was a Monday(1) in 1900
1728 }
1729 
1730 /*******************************************************************************
1731  * Compute the day of the year. This function assumes that the inputs are properly
1732  * sanitized.
1733  *
1734  * @param month Number of months since January.
1735  * @param day Day of the month
1736  * @param is_leap_year Specifies if the year computed against is a leap year.
1737  *
1738  * @return the number of days since the beginning of the year
1739  ******************************************************************************/
compute_day_of_year(sl_sleeptimer_month_t month,uint8_t day,bool is_leap_year)1740 static uint16_t compute_day_of_year(sl_sleeptimer_month_t month, uint8_t day, bool is_leap_year)
1741 {
1742   uint8_t i;
1743   uint16_t dayOfYear = 0;
1744 
1745   for (i = 0; i < month; ++i) {
1746     dayOfYear += days_in_month[is_leap_year][i];
1747   }
1748   dayOfYear += day;
1749 
1750   return dayOfYear;
1751 }
1752 
1753 /*******************************************************************************
1754  * Checks if the year is a leap year.
1755  *
1756  * @param year Year to check.
1757  *
1758  * @return true if the year is a leap year. False otherwise.
1759  ******************************************************************************/
is_leap_year(uint16_t year)1760 static bool is_leap_year(uint16_t year)
1761 {
1762   // 1900 is not a leap year but 0 % anything is 0.
1763   if (year == 0) {
1764     return false;
1765   }
1766 
1767   bool leap_year;
1768 
1769   leap_year = (((year %   4u) == 0u)
1770                && (((year % 100u) != 0u) || ((year % 400u) == 0u))) ? true : false;
1771 
1772   return (leap_year);
1773 }
1774 
1775 /*******************************************************************************
1776  * Checks if the time stamp, format and time zone are
1777  *  within the supported range.
1778  *
1779  * @param base_year Year to start from to compute leap days.
1780  * @param current_year Year end at for computing leap days.
1781  *
1782  * @return leap_days Days number of leap days between base_year and current_year.
1783  ******************************************************************************/
number_of_leap_days(uint32_t base_year,uint32_t current_year)1784 static uint16_t number_of_leap_days(uint32_t base_year, uint32_t current_year)
1785 {
1786   // Regular leap years
1787   uint16_t lo_reg = (base_year - 0) / 4;
1788   uint16_t hi_reg = (current_year - 1) / 4;
1789   uint16_t leap_days = hi_reg - lo_reg;
1790 
1791   // Account for non leap years
1792   uint16_t lo_century = (base_year - 0) / 100;
1793   uint16_t hi_century = (current_year - 1) / 100;
1794   leap_days -= hi_century - lo_century;
1795 
1796   // Account for quad century leap years
1797   uint16_t lo_quad = (base_year - 0) / 400;
1798   uint16_t hi_quad = (current_year - 1) / 400;
1799   leap_days += hi_quad - lo_quad;
1800 
1801   return (leap_days);
1802 }
1803 
1804 /*******************************************************************************
1805  * Checks if the time stamp, format and time zone are
1806  *  within the supported range.
1807  *
1808  * @param time Time stamp to check.
1809  * @param format Format of the time.
1810  * @param time_zone Time zone offset in second.
1811  *
1812  * @return true if the time is valid. False otherwise.
1813  ******************************************************************************/
is_valid_time(sl_sleeptimer_timestamp_t time,sl_sleeptimer_time_format_t format,sl_sleeptimer_time_zone_offset_t time_zone)1814 static bool is_valid_time(sl_sleeptimer_timestamp_t time,
1815                           sl_sleeptimer_time_format_t format,
1816                           sl_sleeptimer_time_zone_offset_t time_zone)
1817 {
1818   bool valid_time = false;
1819 
1820   // Check for overflow.
1821   if ((time_zone < 0 && time > (uint32_t)abs(time_zone)) \
1822       || (time_zone >= 0 && (time <= UINT32_MAX - time_zone))) {
1823     valid_time = true;
1824   }
1825   if (format == TIME_FORMAT_UNIX) {
1826     if (time > TIME_UNIX_TIMESTAMP_MAX) { // Check if Unix time stamp is an unsigned 31 bits.
1827       valid_time = false;
1828     }
1829   } else {
1830     if ((format == TIME_FORMAT_NTP) && (time >= TIME_NTP_EPOCH_OFFSET_SEC)) {
1831       valid_time &= true;
1832     } else if ((format == TIME_FORMAT_ZIGBEE_CLUSTER) && (time <= TIME_UNIX_TIMESTAMP_MAX - TIME_ZIGBEE_EPOCH_OFFSET_SEC)) {
1833       valid_time &= true;
1834     } else {
1835       valid_time = false;
1836     }
1837   }
1838   return valid_time;
1839 }
1840 
1841 /*******************************************************************************
1842  * Checks if the time stamp, format and time zone are
1843  *  within the supported range.
1844  *
1845  * @param time Time stamp to check.
1846  * @param format Format of the time.
1847  * @param time_zone Time zone offset in second.
1848  *
1849  * @return true if the time is valid. False otherwise.
1850  ******************************************************************************/
is_valid_time_64(sl_sleeptimer_timestamp_64_t time,sl_sleeptimer_time_format_t format,sl_sleeptimer_time_zone_offset_t time_zone)1851 static bool is_valid_time_64(sl_sleeptimer_timestamp_64_t time,
1852                              sl_sleeptimer_time_format_t format,
1853                              sl_sleeptimer_time_zone_offset_t time_zone)
1854 {
1855   bool valid_time = false;
1856 
1857   // Check for overflow.
1858   if ((time_zone < 0 && time > (uint64_t)abs(time_zone))
1859       || (time_zone >= 0 && (time <= UINT64_MAX - time_zone))) {
1860     valid_time = true;
1861   }
1862   if (format == TIME_FORMAT_UNIX_64_BIT) {
1863     if (time > TIME_64_BIT_UNIX_TIMESTAMP_MAX) { // Check if time stamp is an unsigned 64 bits.
1864       valid_time = false;
1865     }
1866   }
1867   return valid_time;
1868 }
1869 
1870 /*******************************************************************************
1871  * Checks if the date is valid.
1872  *
1873  * @param date Date to check.
1874  *
1875  * @return true if the date is valid. False otherwise.
1876  ******************************************************************************/
is_valid_date(sl_sleeptimer_date_t * date)1877 static bool is_valid_date(sl_sleeptimer_date_t *date)
1878 {
1879   if ((date == NULL)
1880       || (date->year > TIME_UNIX_YEAR_MAX)
1881       || (date->month > MONTH_DECEMBER)
1882       || (date->month_day == 0 || date->month_day > days_in_month[is_leap_year(date->year)][date->month])
1883       || (date->hour > 23)
1884       || (date->min > 59)
1885       || (date->sec > 59)) {
1886     return false;
1887   }
1888 
1889   // Unix is valid until the 19th of January 2038 at 03:14:07
1890   if (date->year == TIME_UNIX_YEAR_MAX) {
1891     if ((uint8_t)date->month > (uint8_t)MONTH_JANUARY) {
1892       return false;
1893     } else if (date->month_day > 19) {
1894       return false;
1895     } else if (date->hour > 3) {
1896       return false;
1897     } else if (date->min > 14) {
1898       return false;
1899     } else if (date->sec > 7) {
1900       return false;
1901     }
1902   }
1903 
1904   return true;
1905 }
1906 
1907 /*******************************************************************************
1908  * Checks if the date is valid.
1909  *
1910  * @param date Date to check.
1911  *
1912  * @return true if the date is valid. False otherwise.
1913  ******************************************************************************/
is_valid_date_64(sl_sleeptimer_date_t * date)1914 static bool is_valid_date_64(sl_sleeptimer_date_t *date)
1915 {
1916   if ((date == NULL)
1917       || (date->year > TIME_64_BIT_YEAR_MAX)
1918       || (date->month > MONTH_DECEMBER)
1919       || (date->month_day == 0 || date->month_day > days_in_month[is_leap_year(date->year)][date->month])
1920       || (date->hour > 23)
1921       || (date->min > 59)
1922       || (date->sec > 59)) {
1923     return false;
1924   }
1925   return true;
1926 }
1927 #endif
1928 
1929 /*******************************************************************************
1930  * @brief
1931  *   Gets the precision (in PPM) of the sleeptimer's clock.
1932  *
1933  * @return
1934  *   Clock accuracy, in PPM.
1935  *
1936  ******************************************************************************/
sl_sleeptimer_get_clock_accuracy(void)1937 uint16_t sl_sleeptimer_get_clock_accuracy(void)
1938 {
1939   return sleeptimer_hal_get_clock_accuracy();
1940 }
1941 
1942 /***************************************************************************//**
1943  * @brief
1944  *   Update sleep_on_isr_exit flag.
1945  *
1946  * @param flag Value update_sleep_on_isr_exit will be set to.
1947  ******************************************************************************/
sli_sleeptimer_update_sleep_on_isr_exit(bool flag)1948 void sli_sleeptimer_update_sleep_on_isr_exit(bool flag)
1949 {
1950   sleep_on_isr_exit = flag;
1951 }
1952 
1953 /*******************************************************************************
1954  * Gets the associated peripheral capture channel current value.
1955  ******************************************************************************/
sli_sleeptimer_get_capture(void)1956 uint32_t sli_sleeptimer_get_capture(void)
1957 {
1958   return sleeptimer_hal_get_capture();
1959 }
1960 
1961 /*******************************************************************************
1962  * Resets the PRS signal triggered by the associated peripheral.
1963  ******************************************************************************/
sli_sleeptimer_reset_prs_signal(void)1964 void sli_sleeptimer_reset_prs_signal(void)
1965 {
1966   sleeptimer_hal_reset_prs_signal();
1967 }
1968