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