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