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