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_common.h"
35 #include "em_core.h"
36 #include "sl_sleeptimer.h"
37 #include "sli_sleeptimer_hal.h"
38 #include "sl_atomic.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_NTP_UNIX_EPOCH_DIFF                (TIME_UNIX_EPOCH - TIME_NTP_EPOCH)
52 #define TIME_ZIGBEE_UNIX_EPOCH_DIFF             (TIME_ZIGBEE_EPOCH - TIME_UNIX_EPOCH)
53 #define TIME_DAY_COUNT_NTP_TO_UNIX_EPOCH        (TIME_NTP_UNIX_EPOCH_DIFF * 365u + 17u)                  ///< 70 years and 17 leap days
54 #define TIME_DAY_COUNT_ZIGBEE_TO_UNIX_EPOCH     (TIME_ZIGBEE_UNIX_EPOCH_DIFF * 365u + 7u)                ///< 30 years and 7 leap days
55 #define TIME_SEC_PER_DAY                        (60u * 60u * 24u)
56 #define TIME_NTP_EPOCH_OFFSET_SEC               (TIME_DAY_COUNT_NTP_TO_UNIX_EPOCH * TIME_SEC_PER_DAY)
57 #define TIME_ZIGBEE_EPOCH_OFFSET_SEC            (TIME_DAY_COUNT_ZIGBEE_TO_UNIX_EPOCH * TIME_SEC_PER_DAY)
58 #define TIME_DAY_PER_YEAR                       (365u)
59 #define TIME_SEC_PER_YEAR                       (TIME_SEC_PER_DAY * TIME_DAY_PER_YEAR)
60 #define TIME_UNIX_TIMESTAMP_MAX                 (0x7FFFFFFF)
61 #define TIME_UNIX_YEAR_MAX                      (2038u - TIME_NTP_EPOCH)                                 ///< Max UNIX year based from a 1900 epoch
62 
63 #define TIME_LEAP_DAYS_UP_TO_YEAR(year)         (((year - 3) / 4) + 1)
64 
65 /// @brief Time Format.
SLEEPTIMER_ENUM(sl_sleeptimer_time_format_t)66 SLEEPTIMER_ENUM(sl_sleeptimer_time_format_t) {
67   TIME_FORMAT_UNIX = 0,           ///< Number of seconds since January 1, 1970, 00:00. Type is signed, so represented on 31 bit.
68   TIME_FORMAT_NTP = 1,            ///< Number of seconds since January 1, 1900, 00:00. Type is unsigned, so represented on 32 bit.
69   TIME_FORMAT_ZIGBEE_CLUSTER = 2, ///< Number of seconds since January 1, 2000, 00:00. Type is unsigned, so represented on 32 bit.
70 };
71 
72 // tick_count, it can wrap around.
73 typedef uint32_t sl_sleeptimer_tick_count_t;
74 
75 // Overflow counter used to provide 64-bits tick count.
76 static volatile uint16_t overflow_counter;
77 
78 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
79 // Current time count.
80 static sl_sleeptimer_timestamp_t second_count;
81 // Tick rest when the frequency is not a divider of the timer width.
82 static uint32_t overflow_tick_rest = 0;
83 // Current time zone offset.
84 static sl_sleeptimer_time_zone_offset_t tz_offset = 0;
85 // Precalculated tick rest in case of overflow.
86 static uint32_t calculated_tick_rest = 0;
87 // Precalculated timer overflow duration in seconds.
88 static uint32_t calculated_sec_count = 0;
89 #endif
90 
91 // Timer frequency in Hz.
92 static uint32_t timer_frequency;
93 
94 // Head of timer list.
95 static sl_sleeptimer_timer_handle_t *timer_head;
96 
97 // Count at last update of delta of first timer.
98 static volatile sl_sleeptimer_tick_count_t last_delta_update_count;
99 
100 // Initialization flag.
101 static bool is_sleeptimer_initialized = false;
102 
103 // Flag that indicates if power manager's timer will expire at next compare match.
104 static bool next_timer_to_expire_is_power_manager = false;
105 
106 // Precalculated value to avoid millisecond to tick conversion overflow.
107 static uint32_t max_millisecond_conversion;
108 
109 // Sleep on ISR exit flag.
110 static bool sleep_on_isr_exit = false;
111 
112 static void delta_list_insert_timer(sl_sleeptimer_timer_handle_t *handle,
113                                     sl_sleeptimer_tick_count_t timeout);
114 
115 static sl_status_t delta_list_remove_timer(sl_sleeptimer_timer_handle_t *handle);
116 
117 static void set_comparator_for_next_timer(void);
118 
119 static void update_delta_list(void);
120 
121 __STATIC_INLINE uint32_t div_to_log2(uint32_t div);
122 
123 __STATIC_INLINE bool is_power_of_2(uint32_t nbr);
124 
125 static sl_status_t create_timer(sl_sleeptimer_timer_handle_t *handle,
126                                 sl_sleeptimer_tick_count_t timeout_initial,
127                                 sl_sleeptimer_tick_count_t timeout_periodic,
128                                 sl_sleeptimer_timer_callback_t callback,
129                                 void *callback_data,
130                                 uint8_t priority,
131                                 uint16_t option_flags);
132 
133 static void update_next_timer_to_expire_is_power_manager(void);
134 
135 static void delay_callback(sl_sleeptimer_timer_handle_t *handle,
136                            void *data);
137 
138 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
139 static bool is_leap_year(uint16_t year);
140 
141 static sl_sleeptimer_weekDay_t compute_day_of_week(uint32_t day);
142 static uint16_t compute_day_of_year(sl_sleeptimer_month_t month, uint8_t day, bool isLeapYear);
143 
144 static bool is_valid_time(sl_sleeptimer_timestamp_t time,
145                           sl_sleeptimer_time_format_t format,
146                           sl_sleeptimer_time_zone_offset_t time_zone);
147 
148 static bool is_valid_date(sl_sleeptimer_date_t *date);
149 
150 static const uint8_t days_in_month[2u][12] = {
151   /* Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec */
152   { 31u, 28u, 31u, 30u, 31u, 30u, 31u, 31u, 30u, 31u, 30u, 31u },
153   { 31u, 29u, 31u, 30u, 31u, 30u, 31u, 31u, 30u, 31u, 30u, 31u }
154 };
155 #endif
156 
157 /**************************************************************************//**
158  * Initializes sleep timer.
159  *****************************************************************************/
sl_sleeptimer_init(void)160 sl_status_t sl_sleeptimer_init(void)
161 {
162   CORE_DECLARE_IRQ_STATE;
163 
164   CORE_ENTER_ATOMIC();
165   if (!is_sleeptimer_initialized) {
166     timer_head  = NULL;
167     last_delta_update_count = 0u;
168     overflow_counter = 0u;
169     sleeptimer_hal_init_timer();
170     sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_OF);
171     timer_frequency = sleeptimer_hal_get_timer_frequency();
172     if (timer_frequency == 0) {
173       CORE_EXIT_ATOMIC();
174       return SL_STATUS_INVALID_CONFIGURATION;
175     }
176 
177 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
178     second_count = 0;
179     calculated_tick_rest = ((uint64_t)UINT32_MAX + 1) % (uint64_t)timer_frequency;
180     calculated_sec_count = (((uint64_t)UINT32_MAX + 1) / (uint64_t)timer_frequency);
181 #endif
182     max_millisecond_conversion = (uint32_t)(((uint64_t)UINT32_MAX * (uint64_t)1000u) / timer_frequency);
183     is_sleeptimer_initialized = true;
184   }
185   CORE_EXIT_ATOMIC();
186 
187   return SL_STATUS_OK;
188 }
189 
190 /**************************************************************************//**
191  * Starts a 32 bits timer.
192  *****************************************************************************/
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)193 sl_status_t sl_sleeptimer_start_timer(sl_sleeptimer_timer_handle_t *handle,
194                                       uint32_t timeout,
195                                       sl_sleeptimer_timer_callback_t callback,
196                                       void *callback_data,
197                                       uint8_t priority,
198                                       uint16_t option_flags)
199 {
200   bool is_running = false;
201 
202   if (handle == NULL) {
203     return SL_STATUS_NULL_POINTER;
204   }
205 
206   sl_sleeptimer_is_timer_running(handle, &is_running);
207   if (is_running == true) {
208     return SL_STATUS_NOT_READY;
209   }
210 
211   return create_timer(handle,
212                       timeout,
213                       0,
214                       callback,
215                       callback_data,
216                       priority,
217                       option_flags);
218 }
219 
220 /**************************************************************************//**
221  * Restarts a 32 bits timer.
222  *****************************************************************************/
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)223 sl_status_t sl_sleeptimer_restart_timer(sl_sleeptimer_timer_handle_t *handle,
224                                         uint32_t timeout,
225                                         sl_sleeptimer_timer_callback_t callback,
226                                         void *callback_data,
227                                         uint8_t priority,
228                                         uint16_t option_flags)
229 {
230   if (handle == NULL) {
231     return SL_STATUS_NULL_POINTER;
232   }
233 
234   //Trying to stop the Timer. Failing to do so implies the timer is not running.
235   sl_sleeptimer_stop_timer(handle);
236 
237   //Creates the timer in any case.
238   return create_timer(handle,
239                       timeout,
240                       0,
241                       callback,
242                       callback_data,
243                       priority,
244                       option_flags);
245 }
246 
247 /**************************************************************************//**
248  * Starts a 32 bits periodic timer.
249  *****************************************************************************/
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)250 sl_status_t sl_sleeptimer_start_periodic_timer(sl_sleeptimer_timer_handle_t *handle,
251                                                uint32_t timeout,
252                                                sl_sleeptimer_timer_callback_t callback,
253                                                void *callback_data,
254                                                uint8_t priority,
255                                                uint16_t option_flags)
256 {
257   bool is_running = false;
258 
259   if (handle == NULL) {
260     return SL_STATUS_NULL_POINTER;
261   }
262 
263   sl_sleeptimer_is_timer_running(handle, &is_running);
264   if (is_running == true) {
265     return SL_STATUS_INVALID_STATE;
266   }
267 
268   return create_timer(handle,
269                       timeout,
270                       timeout,
271                       callback,
272                       callback_data,
273                       priority,
274                       option_flags);
275 }
276 
277 /**************************************************************************//**
278  * Restarts a 32 bits periodic timer.
279  *****************************************************************************/
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)280 sl_status_t sl_sleeptimer_restart_periodic_timer(sl_sleeptimer_timer_handle_t *handle,
281                                                  uint32_t timeout,
282                                                  sl_sleeptimer_timer_callback_t callback,
283                                                  void *callback_data,
284                                                  uint8_t priority,
285                                                  uint16_t option_flags)
286 {
287   if (handle == NULL) {
288     return SL_STATUS_NULL_POINTER;
289   }
290 
291   //Trying to stop the Timer. Failing to do so implies the timer has already been stopped.
292   sl_sleeptimer_stop_timer(handle);
293 
294   //Creates the timer in any case.
295   return create_timer(handle,
296                       timeout,
297                       timeout,
298                       callback,
299                       callback_data,
300                       priority,
301                       option_flags);
302 }
303 
304 /**************************************************************************//**
305  * Stops a 32 bits timer.
306  *****************************************************************************/
sl_sleeptimer_stop_timer(sl_sleeptimer_timer_handle_t * handle)307 sl_status_t sl_sleeptimer_stop_timer(sl_sleeptimer_timer_handle_t *handle)
308 {
309   CORE_DECLARE_IRQ_STATE;
310   sl_status_t error;
311   bool set_comparator = false;
312 
313   if (handle == NULL) {
314     return SL_STATUS_NULL_POINTER;
315   }
316 
317   CORE_ENTER_CRITICAL();
318   update_delta_list();
319 
320   // If first timer in list, update timer comparator.
321   if (timer_head == handle) {
322     set_comparator = true;
323   }
324 
325   error = delta_list_remove_timer(handle);
326   if (error != SL_STATUS_OK) {
327     CORE_EXIT_CRITICAL();
328     return error;
329   }
330 
331   if (set_comparator && timer_head) {
332     set_comparator_for_next_timer();
333   } else if (!timer_head) {
334     sleeptimer_hal_disable_int(SLEEPTIMER_EVENT_COMP);
335   }
336 
337   CORE_EXIT_CRITICAL();
338   return SL_STATUS_OK;
339 }
340 
341 /**************************************************************************//**
342  * Gets the status of a timer.
343  *****************************************************************************/
sl_sleeptimer_is_timer_running(sl_sleeptimer_timer_handle_t * handle,bool * running)344 sl_status_t sl_sleeptimer_is_timer_running(sl_sleeptimer_timer_handle_t *handle,
345                                            bool *running)
346 {
347   CORE_DECLARE_IRQ_STATE;
348   sl_sleeptimer_timer_handle_t *current;
349 
350   if (handle == NULL || running == NULL) {
351     return SL_STATUS_NULL_POINTER;
352   } else {
353     *running = false;
354     CORE_ENTER_ATOMIC();
355     current = timer_head;
356     while (current != NULL && !*running) {
357       if (current == handle) {
358         *running = true;
359       } else {
360         current = current->next;
361       }
362     }
363     CORE_EXIT_ATOMIC();
364   }
365   return SL_STATUS_OK;
366 }
367 
368 /**************************************************************************//**
369  * Gets a 32 bits timer's time remaining.
370  *****************************************************************************/
sl_sleeptimer_get_timer_time_remaining(sl_sleeptimer_timer_handle_t * handle,uint32_t * time)371 sl_status_t sl_sleeptimer_get_timer_time_remaining(sl_sleeptimer_timer_handle_t *handle,
372                                                    uint32_t *time)
373 {
374   CORE_DECLARE_IRQ_STATE;
375   sl_sleeptimer_timer_handle_t *current;
376 
377   if (handle == NULL || time == NULL) {
378     return SL_STATUS_NULL_POINTER;
379   }
380 
381   CORE_ENTER_ATOMIC();
382 
383   update_delta_list();
384   *time  = handle->delta;
385 
386   // Retrieve timer in list and add the deltas.
387   current = timer_head;
388   while (current != handle && current != NULL) {
389     *time += current->delta;
390     current = current->next;
391   }
392 
393   if (current != handle) {
394     CORE_EXIT_ATOMIC();
395     return SL_STATUS_NOT_READY;
396   }
397 
398   // Substract time since last compare match.
399   if (*time > sleeptimer_hal_get_counter() - last_delta_update_count) {
400     *time -= sleeptimer_hal_get_counter() - last_delta_update_count;
401   } else {
402     *time = 0;
403   }
404 
405   CORE_EXIT_ATOMIC();
406 
407   return SL_STATUS_OK;
408 }
409 
410 /**************************************************************************//**
411  * Gets the time remaining until the first timer with the matching set of flags
412  * expires.
413  *****************************************************************************/
sl_sleeptimer_get_remaining_time_of_first_timer(uint16_t option_flags,uint32_t * time_remaining)414 sl_status_t sl_sleeptimer_get_remaining_time_of_first_timer(uint16_t option_flags,
415                                                             uint32_t *time_remaining)
416 {
417   CORE_DECLARE_IRQ_STATE;
418   sl_sleeptimer_timer_handle_t *current;
419   uint32_t time = 0;
420 
421   CORE_ENTER_ATOMIC();
422   // parse list and retrieve first timer with HF requirement.
423   current = timer_head;
424   while (current != NULL) {
425     // save time remaining for timer.
426     time += current->delta;
427     // Check if the current timer has the flags requested
428     if (current->option_flags == option_flags) {
429       // Substract time since last compare match.
430       if (time > (sleeptimer_hal_get_counter() - last_delta_update_count)) {
431         time -= (sleeptimer_hal_get_counter() - last_delta_update_count);
432       } else {
433         time = 0;
434       }
435       *time_remaining = time;
436       CORE_EXIT_ATOMIC();
437       return SL_STATUS_OK;
438     }
439     current = current->next;
440   }
441   CORE_EXIT_ATOMIC();
442 
443   return SL_STATUS_EMPTY;
444 }
445 
446 /**************************************************************************//**
447  * Determines if next timer to expire has the option flag
448  * "SL_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG".
449  *
450  * This function is for internal use only.
451  *****************************************************************************/
sli_sleeptimer_is_power_manager_timer_next_to_expire(void)452 bool sli_sleeptimer_is_power_manager_timer_next_to_expire(void)
453 {
454   bool next_timer_is_power_manager;
455 
456   sl_atomic_load(next_timer_is_power_manager, next_timer_to_expire_is_power_manager);
457 
458   return next_timer_is_power_manager;
459 }
460 
461 /***************************************************************************//**
462 * Gets current 32 bits tick count.
463 *******************************************************************************/
sl_sleeptimer_get_tick_count(void)464 uint32_t sl_sleeptimer_get_tick_count(void)
465 {
466   uint32_t cnt;
467   CORE_DECLARE_IRQ_STATE;
468 
469   CORE_ENTER_ATOMIC();
470   cnt = sleeptimer_hal_get_counter();
471   CORE_EXIT_ATOMIC();
472 
473   return cnt;
474 }
475 
476 /***************************************************************************//**
477 * Gets current 64 bits tick count.
478 *******************************************************************************/
sl_sleeptimer_get_tick_count64(void)479 uint64_t sl_sleeptimer_get_tick_count64(void)
480 {
481   uint32_t tick_cnt;
482   uint32_t of_cnt;
483   CORE_DECLARE_IRQ_STATE;
484 
485   CORE_ENTER_ATOMIC();
486   tick_cnt = sleeptimer_hal_get_counter();
487   of_cnt = overflow_counter;
488 
489   if (sli_sleeptimer_hal_is_int_status_set(SLEEPTIMER_EVENT_OF)) {
490     tick_cnt = sleeptimer_hal_get_counter();
491     of_cnt++;
492   }
493   CORE_EXIT_ATOMIC();
494 
495   return (((uint64_t) of_cnt) << 32) | tick_cnt;
496 }
497 
498 /***************************************************************************//**
499  * Get timer frequency.
500  ******************************************************************************/
sl_sleeptimer_get_timer_frequency(void)501 uint32_t sl_sleeptimer_get_timer_frequency(void)
502 {
503   return timer_frequency;
504 }
505 
506 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
507 /***************************************************************************//**
508  * Retrieves current time.
509  ******************************************************************************/
sl_sleeptimer_get_time(void)510 sl_sleeptimer_timestamp_t sl_sleeptimer_get_time(void)
511 {
512   uint32_t cnt = 0u;
513   uint32_t freq = 0u;
514   sl_sleeptimer_timestamp_t time;
515   CORE_DECLARE_IRQ_STATE;
516 
517   cnt = sleeptimer_hal_get_counter();
518   freq = sl_sleeptimer_get_timer_frequency();
519 
520   CORE_ENTER_ATOMIC();
521   time = second_count + cnt / freq;
522   if (cnt % freq + overflow_tick_rest >= freq) {
523     time++;
524   }
525   CORE_EXIT_ATOMIC();
526 
527   return time;
528 }
529 
530 /***************************************************************************//**
531  * Sets current time.
532  ******************************************************************************/
sl_sleeptimer_set_time(sl_sleeptimer_timestamp_t time)533 sl_status_t sl_sleeptimer_set_time(sl_sleeptimer_timestamp_t time)
534 {
535   uint32_t freq = 0u;
536   uint32_t counter_sec = 0u;
537   uint32_t cnt = 0;
538   CORE_DECLARE_IRQ_STATE;
539 
540   if (!is_valid_time(time, TIME_FORMAT_UNIX, 0u)) {
541     return SL_STATUS_INVALID_PARAMETER;
542   }
543 
544   freq = sl_sleeptimer_get_timer_frequency();
545   cnt = sleeptimer_hal_get_counter();
546 
547   CORE_ENTER_ATOMIC();
548   second_count = time;
549   overflow_tick_rest = 0;
550   counter_sec = cnt / freq;
551 
552   if (second_count >= counter_sec) {
553     second_count -= counter_sec;
554   } else {
555     CORE_EXIT_ATOMIC();
556     return SL_STATUS_INVALID_PARAMETER;
557   }
558 
559   CORE_EXIT_ATOMIC();
560 
561   return SL_STATUS_OK;
562 }
563 
564 /***************************************************************************//**
565  * Gets current date.
566  ******************************************************************************/
sl_sleeptimer_get_datetime(sl_sleeptimer_date_t * date)567 sl_status_t sl_sleeptimer_get_datetime(sl_sleeptimer_date_t *date)
568 {
569   sl_sleeptimer_timestamp_t time = 0u;
570   sl_sleeptimer_time_zone_offset_t tz;
571   sl_status_t err_code = SL_STATUS_OK;
572 
573   time = sl_sleeptimer_get_time();
574   tz = sl_sleeptimer_get_tz();
575   err_code = sl_sleeptimer_convert_time_to_date(time, tz, date);
576 
577   return err_code;
578 }
579 
580 /***************************************************************************//**
581  * Sets current time, in date format.
582  ******************************************************************************/
sl_sleeptimer_set_datetime(sl_sleeptimer_date_t * date)583 sl_status_t sl_sleeptimer_set_datetime(sl_sleeptimer_date_t *date)
584 {
585   sl_sleeptimer_timestamp_t time = 0u;
586   sl_status_t err_code = SL_STATUS_OK;
587   CORE_DECLARE_IRQ_STATE;
588 
589   if (!is_valid_date(date)) {
590     return SL_STATUS_INVALID_PARAMETER;
591   }
592 
593   err_code = sl_sleeptimer_convert_date_to_time(date, &time);
594   if (err_code != SL_STATUS_OK) {
595     return err_code;
596   }
597 
598   CORE_ENTER_ATOMIC();
599   err_code = sl_sleeptimer_set_time(time);
600   if (err_code == SL_STATUS_OK) {
601     sl_sleeptimer_set_tz(date->time_zone);
602   }
603   CORE_EXIT_ATOMIC();
604 
605   return err_code;
606 }
607 
608 /***************************************************************************//**
609  * Builds a date time structure based on the provided parameters.
610  ******************************************************************************/
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)611 sl_status_t sl_sleeptimer_build_datetime(sl_sleeptimer_date_t *date,
612                                          uint16_t year,
613                                          sl_sleeptimer_month_t month,
614                                          uint8_t month_day,
615                                          uint8_t hour,
616                                          uint8_t min,
617                                          uint8_t sec,
618                                          sl_sleeptimer_time_zone_offset_t tz_offset)
619 {
620   if (date == NULL) {
621     return SL_STATUS_NULL_POINTER;
622   }
623 
624   // If year is smaller than 1900, assume NTP Epoch is used.
625   date->year = ((year < TIME_NTP_EPOCH) ? year : (year - TIME_NTP_EPOCH));
626   date->month = month;
627   date->month_day = month_day;
628   date->hour = hour;
629   date->min = min;
630   date->sec = sec;
631   date->time_zone = tz_offset;
632 
633   // Validate that input parameters are correct before filing the missing fields
634   if (!is_valid_date(date)) {
635     return SL_STATUS_INVALID_PARAMETER;
636   }
637 
638   date->day_of_year = compute_day_of_year(date->month, date->month_day, is_leap_year(date->year));
639   date->day_of_week = compute_day_of_week(((date->year - TIME_NTP_UNIX_EPOCH_DIFF)  * TIME_DAY_PER_YEAR)
640                                           + TIME_LEAP_DAYS_UP_TO_YEAR(date->year - TIME_NTP_UNIX_EPOCH_DIFF)
641                                           + date->day_of_year - 1);
642 
643   return SL_STATUS_OK;
644 }
645 
646 /*******************************************************************************
647  * Convert a time stamp into a date structure.
648  ******************************************************************************/
sl_sleeptimer_convert_time_to_date(sl_sleeptimer_timestamp_t time,sl_sleeptimer_time_zone_offset_t time_zone,sl_sleeptimer_date_t * date)649 sl_status_t sl_sleeptimer_convert_time_to_date(sl_sleeptimer_timestamp_t time,
650                                                sl_sleeptimer_time_zone_offset_t time_zone,
651                                                sl_sleeptimer_date_t *date)
652 {
653   uint8_t full_year = 0;
654   uint8_t leap_day = 0;
655   uint8_t leap_year_flag = 0;
656   uint8_t current_month = 0;
657 
658   if (!is_valid_time(time, TIME_FORMAT_UNIX, time_zone)) {
659     return SL_STATUS_INVALID_PARAMETER;
660   }
661 
662   date->sec = time % 60;
663   time /= 60;
664   date->min = time % 60;
665   time /= 60;
666   date->hour = time % 24;
667   time /= 24; // time is now the number of days since 1970.
668 
669   date->day_of_week = (sl_sleeptimer_weekDay_t)compute_day_of_week(time);
670 
671   full_year = time / (TIME_DAY_PER_YEAR); // Approximates the number of full years.
672   if (full_year > 2) {
673     leap_day = TIME_LEAP_DAYS_UP_TO_YEAR(full_year);  // Approximates the number of leap days.
674     full_year = (time - leap_day) / (TIME_DAY_PER_YEAR); // Computes the number of year integrating the leap days.
675     leap_day = TIME_LEAP_DAYS_UP_TO_YEAR(full_year);  // Computes the actual number of leap days of the previous years.
676   }
677   date->year = TIME_NTP_UNIX_EPOCH_DIFF + full_year; // Year in date struct must be based on a 1900 epoch.
678   if (is_leap_year(date->year)) {
679     leap_year_flag = 1;
680   }
681 
682   time = (time - leap_day) - (TIME_DAY_PER_YEAR * full_year);  // Subtracts days of previous year.
683   date->day_of_year = time + 1;
684 
685   while (time >= days_in_month[leap_year_flag][current_month]) {
686     time -= days_in_month[leap_year_flag][current_month]; // Subtracts the number of days of the passed month.
687     current_month++;
688   }
689   date->month = (sl_sleeptimer_month_t) current_month;
690   date->month_day = time + 1;
691   date->time_zone = time_zone;
692 
693   return SL_STATUS_OK;
694 }
695 
696 /*******************************************************************************
697  * Convert a date structure into a time stamp.
698  ******************************************************************************/
sl_sleeptimer_convert_date_to_time(sl_sleeptimer_date_t * date,sl_sleeptimer_timestamp_t * time)699 sl_status_t sl_sleeptimer_convert_date_to_time(sl_sleeptimer_date_t *date,
700                                                sl_sleeptimer_timestamp_t *time)
701 {
702   uint16_t month_days = 0;
703   uint8_t  month;
704   uint8_t  full_year = 0;
705   uint8_t  leap_year_flag = 0;
706   uint8_t  leap_days = 0;
707   if (!is_valid_date(date)) {
708     return SL_STATUS_INVALID_PARAMETER;
709   }
710 
711   full_year = (date->year - TIME_NTP_UNIX_EPOCH_DIFF);       // Timestamp returned must follow the UNIX epoch.
712   month = (uint8_t)date->month;                              // offset to get months value from 1 to 12.
713 
714   *time = full_year * TIME_SEC_PER_YEAR;
715 
716   if (full_year > 2) {
717     leap_days = TIME_LEAP_DAYS_UP_TO_YEAR(full_year);
718     month_days = leap_days;
719   }
720 
721   if (is_leap_year(date->year)) {
722     leap_year_flag = 1;
723   }
724 
725   for (int i = 0; i < month; i++) {
726     month_days += days_in_month[leap_year_flag][i];         // Add the number of days of the month of the year.
727   }
728 
729   month_days += (date->month_day - 1);                       // Add full days of the current month.
730   *time += month_days * TIME_SEC_PER_DAY;
731   *time += (3600 * date->hour) + (60 * date->min) + date->sec;
732   *time += date->time_zone;
733 
734   return SL_STATUS_OK;
735 }
736 
737 /*******************************************************************************
738  * Convert a date structure to string.
739  ******************************************************************************/
sl_sleeptimer_convert_date_to_str(char * str,size_t size,const uint8_t * format,sl_sleeptimer_date_t * date)740 uint32_t sl_sleeptimer_convert_date_to_str(char *str,
741                                            size_t size,
742                                            const uint8_t *format,
743                                            sl_sleeptimer_date_t *date)
744 {
745   uint32_t  return_size = 0u;
746   if (is_valid_date(date)) {
747     struct tm date_struct;
748 
749     date_struct.tm_hour = date->hour;
750     date_struct.tm_mday = date->month_day;
751     date_struct.tm_min = date->min;
752     date_struct.tm_mon = date->month;
753     date_struct.tm_sec = date->sec;
754     date_struct.tm_wday = date->day_of_week;
755     date_struct.tm_yday = date->day_of_year;
756     date_struct.tm_year = date->year;
757 
758     return_size = strftime(str,
759                            size,
760                            (const char *)format,
761                            &date_struct);
762   }
763 
764   return return_size;
765 }
766 
767 /***************************************************************************//**
768  * Sets time zone offset.
769  *
770  * @param  offset  Time zone offset, in seconds.
771  ******************************************************************************/
sl_sleeptimer_set_tz(sl_sleeptimer_time_zone_offset_t offset)772 void sl_sleeptimer_set_tz(sl_sleeptimer_time_zone_offset_t offset)
773 {
774   CORE_DECLARE_IRQ_STATE;
775 
776   CORE_ENTER_ATOMIC();
777   tz_offset = offset;
778   CORE_EXIT_ATOMIC();
779 }
780 
781 /***************************************************************************//**
782  * Gets time zone offset.
783  *
784  * @return Time zone offset, in seconds.
785  ******************************************************************************/
sl_sleeptimer_get_tz(void)786 sl_sleeptimer_time_zone_offset_t sl_sleeptimer_get_tz(void)
787 {
788   sl_sleeptimer_time_zone_offset_t offset;
789   CORE_DECLARE_IRQ_STATE;
790 
791   CORE_ENTER_ATOMIC();
792   offset = tz_offset;
793   CORE_EXIT_ATOMIC();
794 
795   return offset;
796 }
797 
798 /***************************************************************************//**
799  * Converts Unix timestamp into NTP timestamp.
800  ******************************************************************************/
sl_sleeptimer_convert_unix_time_to_ntp(sl_sleeptimer_timestamp_t time,uint32_t * ntp_time)801 sl_status_t sl_sleeptimer_convert_unix_time_to_ntp(sl_sleeptimer_timestamp_t time,
802                                                    uint32_t *ntp_time)
803 {
804   uint32_t temp_ntp_time;
805   temp_ntp_time = time + TIME_NTP_EPOCH_OFFSET_SEC;
806   if (!is_valid_time(temp_ntp_time, TIME_FORMAT_NTP, 0u)) {
807     return SL_STATUS_INVALID_PARAMETER;
808   } else {
809     *ntp_time = temp_ntp_time;
810     return SL_STATUS_OK;
811   }
812 }
813 
814 /***************************************************************************//**
815  * Converts NTP timestamp into Unix timestamp.
816  ******************************************************************************/
sl_sleeptimer_convert_ntp_time_to_unix(uint32_t ntp_time,sl_sleeptimer_timestamp_t * time)817 sl_status_t sl_sleeptimer_convert_ntp_time_to_unix(uint32_t ntp_time,
818                                                    sl_sleeptimer_timestamp_t *time)
819 {
820   uint32_t temp_time;
821   temp_time = ntp_time - TIME_NTP_EPOCH_OFFSET_SEC;
822   if (!is_valid_time(temp_time, TIME_FORMAT_UNIX, 0u)) {
823     return SL_STATUS_INVALID_PARAMETER;
824   } else {
825     *time = temp_time;
826     return SL_STATUS_OK;
827   }
828 }
829 
830 /***************************************************************************//**
831  * Converts Unix timestamp into Zigbee timestamp.
832  ******************************************************************************/
sl_sleeptimer_convert_unix_time_to_zigbee(sl_sleeptimer_timestamp_t time,uint32_t * zigbee_time)833 sl_status_t sl_sleeptimer_convert_unix_time_to_zigbee(sl_sleeptimer_timestamp_t time,
834                                                       uint32_t *zigbee_time)
835 {
836   uint32_t temp_zigbee_time;
837   temp_zigbee_time = time - TIME_ZIGBEE_EPOCH_OFFSET_SEC;
838   if (!is_valid_time(temp_zigbee_time, TIME_FORMAT_ZIGBEE_CLUSTER, 0u)) {
839     return SL_STATUS_INVALID_PARAMETER;
840   } else {
841     *zigbee_time = temp_zigbee_time;
842     return SL_STATUS_OK;
843   }
844 }
845 
846 /***************************************************************************//**
847  * Converts Zigbee timestamp into Unix timestamp.
848  ******************************************************************************/
sl_sleeptimer_convert_zigbee_time_to_unix(uint32_t zigbee_time,sl_sleeptimer_timestamp_t * time)849 sl_status_t sl_sleeptimer_convert_zigbee_time_to_unix(uint32_t zigbee_time,
850                                                       sl_sleeptimer_timestamp_t *time)
851 {
852   uint32_t temp_time;
853   temp_time = zigbee_time + TIME_ZIGBEE_EPOCH_OFFSET_SEC;
854   if (!is_valid_time(temp_time, TIME_FORMAT_UNIX, 0u)) {
855     return SL_STATUS_INVALID_PARAMETER;
856   } else {
857     *time = temp_time;
858     return SL_STATUS_OK;
859   }
860 }
861 
862 #endif // SL_SLEEPTIMER_WALLCLOCK_CONFIG
863 
864 /*******************************************************************************
865  * Active delay of 'time_ms' milliseconds.
866  ******************************************************************************/
sl_sleeptimer_delay_millisecond(uint16_t time_ms)867 void sl_sleeptimer_delay_millisecond(uint16_t time_ms)
868 {
869   volatile bool wait = true;
870   sl_status_t error_code;
871   sl_sleeptimer_timer_handle_t delay_timer;
872   uint32_t delay = sl_sleeptimer_ms_to_tick(time_ms);
873 
874   error_code = sl_sleeptimer_start_timer(&delay_timer,
875                                          delay,
876                                          delay_callback,
877                                          (void *)&wait,
878                                          0,
879                                          0);
880   if (error_code == SL_STATUS_OK) {
881     while (wait) { // Active delay loop.
882     }
883   }
884 }
885 
886 /*******************************************************************************
887  * Converts milliseconds in ticks.
888  ******************************************************************************/
sl_sleeptimer_ms_to_tick(uint16_t time_ms)889 uint32_t sl_sleeptimer_ms_to_tick(uint16_t time_ms)
890 {
891   return (uint32_t)((((uint32_t)time_ms * timer_frequency) + 999) / 1000);
892 }
893 
894 /*******************************************************************************
895  * Converts 32-bits milliseconds in ticks.
896  ******************************************************************************/
sl_sleeptimer_ms32_to_tick(uint32_t time_ms,uint32_t * tick)897 sl_status_t sl_sleeptimer_ms32_to_tick(uint32_t time_ms,
898                                        uint32_t *tick)
899 {
900   if (time_ms <= max_millisecond_conversion) {
901     *tick = (uint32_t)((((uint64_t)time_ms * timer_frequency) + 999) / 1000u);
902     return SL_STATUS_OK;
903   } else {
904     return SL_STATUS_INVALID_PARAMETER;
905   }
906 }
907 
908 /***************************************************************************//**
909  * Gets the maximum value that can be passed to the functions that have a
910  * 32-bits time or timeout argument expressed in milliseconds.
911  ******************************************************************************/
sl_sleeptimer_get_max_ms32_conversion(void)912 uint32_t sl_sleeptimer_get_max_ms32_conversion(void)
913 {
914   return max_millisecond_conversion;
915 }
916 
917 /*******************************************************************************
918  * Converts ticks in milliseconds.
919  ******************************************************************************/
sl_sleeptimer_tick_to_ms(uint32_t tick)920 uint32_t sl_sleeptimer_tick_to_ms(uint32_t tick)
921 {
922   if (timer_frequency != 0u) {
923     if (is_power_of_2(timer_frequency)) {
924       return (uint32_t)(((uint64_t)tick * (uint64_t)1000u) >> div_to_log2(timer_frequency));
925     } else {
926       return (uint32_t)(((uint64_t)tick * (uint64_t)1000u) / timer_frequency);
927     }
928   }
929 
930   return 0u;
931 }
932 
933 /*******************************************************************************
934  * Converts 64-bits ticks in milliseconds.
935  ******************************************************************************/
sl_sleeptimer_tick64_to_ms(uint64_t tick,uint64_t * ms)936 sl_status_t sl_sleeptimer_tick64_to_ms(uint64_t tick,
937                                        uint64_t *ms)
938 {
939   if ((tick <= UINT64_MAX / 1000)
940       && (timer_frequency != 0u)) {
941     if (is_power_of_2(timer_frequency)) {
942       *ms =  (uint64_t)(((uint64_t)tick * (uint64_t)1000u) >> div_to_log2(timer_frequency));
943       return SL_STATUS_OK;
944     } else {
945       *ms = (uint64_t)(((uint64_t)tick * (uint64_t)1000u) / timer_frequency);
946       return SL_STATUS_OK;
947     }
948   } else {
949     return SL_STATUS_INVALID_PARAMETER;
950   }
951 }
952 
953 /*******************************************************************************
954  * Process timer interrupt.
955  *
956  * @param local_flag Flag indicating the type of timer interrupt.
957  ******************************************************************************/
process_timer_irq(uint8_t local_flag)958 void process_timer_irq(uint8_t local_flag)
959 {
960   CORE_DECLARE_IRQ_STATE;
961   if (local_flag & SLEEPTIMER_EVENT_OF) {
962 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
963     uint32_t timer_freq = sl_sleeptimer_get_timer_frequency();
964 
965     overflow_tick_rest += calculated_tick_rest;
966     if (overflow_tick_rest >= timer_freq) {
967       second_count++;
968       overflow_tick_rest -= timer_freq;
969     }
970     second_count = second_count + calculated_sec_count;
971 #endif
972     overflow_counter++;
973 
974     update_delta_list();
975 
976     if (timer_head) {
977       set_comparator_for_next_timer();
978     }
979   }
980 
981   if (local_flag & SLEEPTIMER_EVENT_COMP) {
982     sl_sleeptimer_timer_handle_t *current = NULL;
983     uint32_t nb_timer_expire = 0u;
984     uint16_t option_flags = 0;
985 
986     CORE_ENTER_ATOMIC();
987     // Make sure the timers list is up to date with the time elapsed since the last update
988     update_delta_list();
989 
990     // Process all timers that have expired.
991     while ((timer_head) && (timer_head->delta == 0)) {
992       sl_sleeptimer_timer_handle_t *temp = timer_head;
993       current = timer_head;
994       int32_t periodic_correction = 0u;
995       int64_t timeout_temp = 0;
996       bool skip_remove = false;
997 
998       // Process timers with higher priority first
999       while ((temp != NULL) && (temp->delta == 0)) {
1000         if (current->priority > temp->priority) {
1001           current = temp;
1002         }
1003         temp = temp->next;
1004       }
1005       CORE_EXIT_ATOMIC();
1006 
1007       // Check if current periodic timer was delayed more than its actual timeout value
1008       // and keep it at the head of the timers list if it's the case so that the
1009       // callback function can be called the number of required time.
1010       if (current->timeout_periodic != 0u) {
1011         timeout_temp = current->timeout_periodic;
1012 
1013         periodic_correction = sleeptimer_hal_get_counter() - current->timeout_expected_tc;
1014         if (periodic_correction > timeout_temp) {
1015           skip_remove = true;
1016           current->timeout_expected_tc += current->timeout_periodic;
1017         }
1018       }
1019 
1020       // Remove current timer from timer list except if the current timer is a periodic timer
1021       // that was intentionally kept at the head of the timers list.
1022       if (skip_remove != true) {
1023         CORE_ENTER_ATOMIC();
1024         delta_list_remove_timer(current);
1025         CORE_EXIT_ATOMIC();
1026       }
1027 
1028       // Re-insert periodic timer that was previsouly removed from the list
1029       // and compensate for any deviation from the periodic timer frequency.
1030       if (current->timeout_periodic != 0u && skip_remove != true) {
1031         timeout_temp -= periodic_correction;
1032         EFM_ASSERT(timeout_temp >= 0);
1033         CORE_ENTER_ATOMIC();
1034         delta_list_insert_timer(current, (sl_sleeptimer_tick_count_t)timeout_temp);
1035         current->timeout_expected_tc += current->timeout_periodic;
1036         CORE_EXIT_ATOMIC();
1037       }
1038 
1039       // Save current option flag and the number of timers that expired.
1040       option_flags = current->option_flags;
1041       nb_timer_expire++;
1042 
1043       // Call current timer callback function if any.
1044       if (current->callback != NULL) {
1045         current->callback(current, current->callback_data);
1046       }
1047 
1048       CORE_ENTER_ATOMIC();
1049 
1050       // Re-update the list to account for delays during timer's callback.
1051       update_delta_list();
1052     }
1053 
1054     // If the only timer expired is the internal Power Manager one,
1055     // from the Sleeptimer perspective, the system can go back to sleep after the ISR handling.
1056     sleep_on_isr_exit = false;
1057     if (nb_timer_expire == 1u) {
1058       if (option_flags == SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG) {
1059         sleep_on_isr_exit = true;
1060       }
1061     }
1062 
1063     if (timer_head) {
1064       set_comparator_for_next_timer();
1065     } else {
1066       sleeptimer_hal_disable_int(SLEEPTIMER_EVENT_COMP);
1067     }
1068     CORE_EXIT_ATOMIC();
1069   }
1070 }
1071 
1072 /*******************************************************************************
1073  * Timer expiration callback for the delay function.
1074  *
1075  * @param handle Pointer to handle to timer.
1076  * @param data Pointer to delay flag.
1077  ******************************************************************************/
delay_callback(sl_sleeptimer_timer_handle_t * handle,void * data)1078 static void delay_callback(sl_sleeptimer_timer_handle_t *handle,
1079                            void *data)
1080 {
1081   volatile bool *wait_flag = (bool *)data;
1082 
1083   (void)handle;  // Unused parameter.
1084 
1085   *wait_flag = false;
1086 }
1087 
1088 /*******************************************************************************
1089  * Inserts a timer in the delta list.
1090  *
1091  * @param handle Pointer to handle to timer.
1092  * @param timeout Timer timeout, in ticks.
1093  ******************************************************************************/
delta_list_insert_timer(sl_sleeptimer_timer_handle_t * handle,sl_sleeptimer_tick_count_t timeout)1094 static void delta_list_insert_timer(sl_sleeptimer_timer_handle_t *handle,
1095                                     sl_sleeptimer_tick_count_t timeout)
1096 {
1097   sl_sleeptimer_tick_count_t local_handle_delta = timeout;
1098 
1099 #ifdef SL_CATALOG_POWER_MANAGER_PRESENT
1100   // If Power Manager is present, it's possible that a clock restore is needed right away
1101   // if we are in the context of a deepsleep and the timeout value is smaller than the restore time.
1102   // If it's the case, the restore will be started and the timeout value will be updated to match
1103   // the restore delay.
1104   if (handle->option_flags == 0) {
1105     uint32_t wakeup_delay = sli_power_manager_get_restore_delay();
1106 
1107     if (local_handle_delta < wakeup_delay) {
1108       local_handle_delta = wakeup_delay;
1109       sli_power_manager_initiate_restore();
1110     }
1111   }
1112 #endif
1113 
1114   handle->delta = local_handle_delta;
1115 
1116   if (timer_head != NULL) {
1117     sl_sleeptimer_timer_handle_t *prev = NULL;
1118     sl_sleeptimer_timer_handle_t *current = timer_head;
1119     // Find timer position taking into accounts the deltas and priority.
1120     while (current != NULL
1121            && (local_handle_delta >= current->delta || current->delta == 0u
1122                || (((local_handle_delta - current->delta) == 0) && (handle->priority > current->priority)))) {
1123       local_handle_delta -= current->delta;
1124       handle->delta = local_handle_delta;
1125       prev = current;
1126       current = current->next;
1127     }
1128 
1129     // Insert timer in middle of delta list.
1130     if (prev != NULL) {
1131       prev->next = handle;
1132     } else {
1133       timer_head = handle;
1134     }
1135     handle->next = current;
1136 
1137     if (current != NULL) {
1138       current->delta -= local_handle_delta;
1139     }
1140   } else {
1141     timer_head = handle;
1142     handle->next = NULL;
1143   }
1144 }
1145 
1146 /*******************************************************************************
1147  * Removes a timer from delta list.
1148  *
1149  * @param handle Pointer to handle to timer.
1150  *
1151  * @return 0 if successful. Error code otherwise.
1152  ******************************************************************************/
delta_list_remove_timer(sl_sleeptimer_timer_handle_t * handle)1153 static sl_status_t delta_list_remove_timer(sl_sleeptimer_timer_handle_t *handle)
1154 {
1155   sl_sleeptimer_timer_handle_t *prev = NULL;
1156   sl_sleeptimer_timer_handle_t *current = timer_head;
1157 
1158   // Retrieve timer in delta list.
1159   while (current != NULL && current != handle) {
1160     prev = current;
1161     current = current->next;
1162   }
1163 
1164   if (current != handle) {
1165     return SL_STATUS_INVALID_STATE;
1166   }
1167 
1168   if (prev != NULL) {
1169     prev->next = handle->next;
1170   } else {
1171     timer_head = handle->next;
1172   }
1173 
1174   // Update delta of next timer
1175   if (handle->next != NULL) {
1176     handle->next->delta += handle->delta;
1177   }
1178 
1179   return SL_STATUS_OK;
1180 }
1181 
1182 /*******************************************************************************
1183  * Sets comparator for next timer.
1184  ******************************************************************************/
set_comparator_for_next_timer(void)1185 static void set_comparator_for_next_timer(void)
1186 {
1187   if (timer_head->delta > 0) {
1188     sl_sleeptimer_tick_count_t compare_value;
1189 
1190     compare_value = last_delta_update_count + timer_head->delta;
1191 
1192     sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
1193     sleeptimer_hal_set_compare(compare_value);
1194   } else {
1195     // In case timer has already expire, don't attempt to set comparator. Just
1196     // trigger compare match interrupt.
1197     sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
1198     sleeptimer_hal_set_int(SLEEPTIMER_EVENT_COMP);
1199   }
1200 
1201   update_next_timer_to_expire_is_power_manager();
1202 }
1203 
1204 /*******************************************************************************
1205  * Updates timer list's deltas.
1206  ******************************************************************************/
update_delta_list(void)1207 static void update_delta_list(void)
1208 {
1209   sl_sleeptimer_tick_count_t current_cnt = sleeptimer_hal_get_counter();
1210   sl_sleeptimer_timer_handle_t *timer_handle = timer_head;
1211   sl_sleeptimer_tick_count_t time_diff = current_cnt - last_delta_update_count;
1212 
1213   // Go through the delta timer list and update every necessary deltas
1214   // according to the time elapsed since the last update.
1215   while (timer_handle != NULL && time_diff > 0) {
1216     if (timer_handle->delta >= time_diff) {
1217       timer_handle->delta -= time_diff;
1218       time_diff = 0;
1219     } else {
1220       time_diff -= timer_handle->delta;
1221       timer_handle->delta = 0;
1222     }
1223     timer_handle = timer_handle->next;
1224   }
1225 
1226   last_delta_update_count = current_cnt;
1227 }
1228 
1229 /*******************************************************************************
1230  * Creates and start a 32 bits timer.
1231  *
1232  * @param handle Pointer to handle to timer.
1233  * @param timeout_initial Initial timeout, in timer ticks.
1234  * @param timeout_periodic Periodic timeout, in timer ticks. This timeout
1235  *        applies once timeoutInitial expires. Can be set to 0 for a one
1236  *        shot timer.
1237  * @param callback Callback function that will be called when
1238  *        initial/periodic timeout expires.
1239  * @param callback_data Pointer to user data that will be passed to callback.
1240  * @param priority Priority of callback. Useful in case multiple timer expire
1241  *        at the same time. 0 = highest priority.
1242  *
1243  * @return 0 if successful. Error code otherwise.
1244  ******************************************************************************/
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)1245 static sl_status_t create_timer(sl_sleeptimer_timer_handle_t *handle,
1246                                 sl_sleeptimer_tick_count_t timeout_initial,
1247                                 sl_sleeptimer_tick_count_t timeout_periodic,
1248                                 sl_sleeptimer_timer_callback_t callback,
1249                                 void *callback_data,
1250                                 uint8_t priority,
1251                                 uint16_t option_flags)
1252 {
1253   CORE_DECLARE_IRQ_STATE;
1254 
1255   handle->priority = priority;
1256   handle->callback_data = callback_data;
1257   handle->next = NULL;
1258   handle->timeout_periodic = timeout_periodic;
1259   handle->callback = callback;
1260   handle->option_flags = option_flags;
1261   handle->timeout_expected_tc = sleeptimer_hal_get_counter() + timeout_periodic;
1262 
1263   if (timeout_initial == 0) {
1264     handle->delta = 0;
1265     if (handle->callback != NULL) {
1266       handle->callback(handle, handle->callback_data);
1267     }
1268     if (timeout_periodic != 0) {
1269       timeout_initial = timeout_periodic;
1270     } else {
1271       return SL_STATUS_OK;
1272     }
1273   }
1274 
1275   CORE_ENTER_CRITICAL();
1276   update_delta_list();
1277   delta_list_insert_timer(handle, timeout_initial);
1278 
1279   // If first timer, update timer comparator.
1280   if (timer_head == handle) {
1281     set_comparator_for_next_timer();
1282   }
1283 
1284   CORE_EXIT_CRITICAL();
1285 
1286   return SL_STATUS_OK;
1287 }
1288 
1289 /*******************************************************************************
1290  * Updates internal flag that indicates if next timer to expire is the power
1291  * manager's one.
1292  ******************************************************************************/
update_next_timer_to_expire_is_power_manager(void)1293 static void update_next_timer_to_expire_is_power_manager(void)
1294 {
1295   sl_sleeptimer_timer_handle_t *current = timer_head;
1296   uint32_t delta_diff_with_first = 0;
1297 
1298   next_timer_to_expire_is_power_manager = false;
1299 
1300   while (delta_diff_with_first <= 1) {
1301     if (current->option_flags & SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG) {
1302       next_timer_to_expire_is_power_manager = true;
1303       break;
1304     }
1305 
1306     current = current->next;
1307     if (current == NULL) {
1308       break;
1309     }
1310 
1311     delta_diff_with_first += current->delta;
1312   }
1313 }
1314 
1315 /**************************************************************************//**
1316  * Determines if the power manager's early wakeup expired during the last ISR
1317  * and it was the only timer to expire in that period.
1318  *
1319  * @return true if power manager sleep can return to sleep,
1320  *         false otherwise.
1321  *****************************************************************************/
sl_sleeptimer_is_power_manager_early_restore_timer_latest_to_expire(void)1322 bool sl_sleeptimer_is_power_manager_early_restore_timer_latest_to_expire(void)
1323 {
1324   CORE_DECLARE_IRQ_STATE;
1325   bool sleep;
1326 
1327   CORE_ENTER_ATOMIC();
1328   sleep = sleep_on_isr_exit;
1329   CORE_EXIT_ATOMIC();
1330 
1331   return sleep;
1332 }
1333 
1334 /*******************************************************************************
1335  * Convert dividend to logarithmic value. It only works for even
1336  * numbers equal to 2^n.
1337  *
1338  * @param  div An unscaled dividend.
1339  *
1340  * @return Logarithm of 2.
1341  ******************************************************************************/
div_to_log2(uint32_t div)1342 __STATIC_INLINE uint32_t div_to_log2(uint32_t div)
1343 {
1344   return 31UL - __CLZ(div);  // Count leading zeroes and "reverse" result.
1345 }
1346 
1347 /*******************************************************************************
1348  * Determines if a number is a power of two.
1349  *
1350  * @param  nbr Input value.
1351  *
1352  * @return True if the number is a power of two.
1353  ******************************************************************************/
is_power_of_2(uint32_t nbr)1354 __STATIC_INLINE bool is_power_of_2(uint32_t nbr)
1355 {
1356   if ((((nbr) != 0u) && (((nbr) & ((nbr) - 1u)) == 0u))) {
1357     return true;
1358   } else {
1359     return false;
1360   }
1361 }
1362 
1363 #if SL_SLEEPTIMER_WALLCLOCK_CONFIG
1364 /*******************************************************************************
1365  * Compute the day of the week.
1366  *
1367  * @param day Days since January 1st of 1970.
1368  *
1369  * @return the day of the week.
1370  ******************************************************************************/
compute_day_of_week(uint32_t day)1371 static sl_sleeptimer_weekDay_t compute_day_of_week(uint32_t day)
1372 {
1373   return (sl_sleeptimer_weekDay_t)((day + 4) % 7);
1374 }
1375 
1376 /*******************************************************************************
1377  * Compute the day of the year. This function assumes that the inputs are properly
1378  * sanitized.
1379  *
1380  * @param month Number of months since January.
1381  * @param day Day of the month
1382  * @param is_leap_year Specifies if the year computed against is a leap year.
1383  *
1384  * @return the number of days since the beginning of the year
1385  ******************************************************************************/
compute_day_of_year(sl_sleeptimer_month_t month,uint8_t day,bool is_leap_year)1386 static uint16_t compute_day_of_year(sl_sleeptimer_month_t month, uint8_t day, bool is_leap_year)
1387 {
1388   uint8_t i;
1389   uint16_t dayOfYear = 0;
1390 
1391   for (i = 0; i < month; ++i) {
1392     dayOfYear += days_in_month[is_leap_year][i];
1393   }
1394   dayOfYear += day;
1395 
1396   return dayOfYear;
1397 }
1398 
1399 /*******************************************************************************
1400  * Checks if the year is a leap year.
1401  *
1402  * @param year Year to check.
1403  *
1404  * @return true if the year is a leap year. False otherwise.
1405  ******************************************************************************/
is_leap_year(uint16_t year)1406 static bool is_leap_year(uint16_t year)
1407 {
1408   bool leap_year;
1409 
1410   leap_year = (((year %   4u) == 0u)
1411                && (((year % 100u) != 0u) || ((year % 400u) == 0u))) ? true : false;
1412 
1413   return (leap_year);
1414 }
1415 
1416 /*******************************************************************************
1417  * Checks if the time stamp, format and time zone are
1418  *  within the supported range.
1419  *
1420  * @param time Time stamp to check.
1421  * @param format Format of the time.
1422  * @param time_zone Time zone offset in second.
1423  *
1424  * @return true if the time is valid. False otherwise.
1425  ******************************************************************************/
is_valid_time(sl_sleeptimer_timestamp_t time,sl_sleeptimer_time_format_t format,sl_sleeptimer_time_zone_offset_t time_zone)1426 static bool is_valid_time(sl_sleeptimer_timestamp_t time,
1427                           sl_sleeptimer_time_format_t format,
1428                           sl_sleeptimer_time_zone_offset_t time_zone)
1429 {
1430   bool valid_time = false;
1431 
1432   // Check for overflow.
1433   if ((time_zone < 0 && time > (uint32_t)abs(time_zone)) \
1434       || (time_zone >= 0 && (time <= UINT32_MAX - time_zone))) {
1435     valid_time = true;
1436   }
1437   if (format == TIME_FORMAT_UNIX) {
1438     if (time > TIME_UNIX_TIMESTAMP_MAX) { // Check if Unix time stamp is an unsigned 31 bits.
1439       valid_time = false;
1440     }
1441   } else {
1442     if ((format == TIME_FORMAT_NTP) && (time >= TIME_NTP_EPOCH_OFFSET_SEC)) {
1443       valid_time &= true;
1444     } else if ((format == TIME_FORMAT_ZIGBEE_CLUSTER) && (time <= TIME_UNIX_TIMESTAMP_MAX - TIME_ZIGBEE_EPOCH_OFFSET_SEC)) {
1445       valid_time &= true;
1446     } else {
1447       valid_time = false;
1448     }
1449   }
1450   return valid_time;
1451 }
1452 
1453 /*******************************************************************************
1454  * Checks if the date is valid.
1455  *
1456  * @param date Date to check.
1457  *
1458  * @return true if the date is valid. False otherwise.
1459  ******************************************************************************/
is_valid_date(sl_sleeptimer_date_t * date)1460 static bool is_valid_date(sl_sleeptimer_date_t *date)
1461 {
1462   if ((date == NULL)
1463       || (date->year > TIME_UNIX_YEAR_MAX)
1464       || (date->month > MONTH_DECEMBER)
1465       || (date->month_day == 0 || date->month_day > days_in_month[is_leap_year(date->year)][date->month])
1466       || (date->hour > 23)
1467       || (date->min > 59)
1468       || (date->sec > 59)) {
1469     return false;
1470   }
1471 
1472   // Unix is valid until the 19th of January 2038 at 03:14:07
1473   if (date->year == TIME_UNIX_YEAR_MAX) {
1474     if ((uint8_t)date->month > (uint8_t)MONTH_JANUARY) {
1475       return false;
1476     } else if (date->month_day > 19) {
1477       return false;
1478     } else if (date->hour > 3) {
1479       return false;
1480     } else if (date->min > 14) {
1481       return false;
1482     } else if (date->sec > 7) {
1483       return false;
1484     }
1485   }
1486 
1487   return true;
1488 }
1489 #endif
1490