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