1 /*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <sys/param.h>
7 #include <string.h>
8 #include "soc/soc.h"
9 #include "esp_types.h"
10 #include "esp_attr.h"
11 #include "esp_err.h"
12
13 #include "esp_task.h"
14 #include "esp_log.h"
15 #include "esp_timer.h"
16 #include "esp_timer_impl.h"
17 #include "sdkconfig.h"
18
19 #include <zephyr/kernel.h>
20
21 #include "esp_private/startup_internal.h"
22 #include "esp_private/esp_timer_private.h"
23 #include "esp_private/system_internal.h"
24 #define LOG_MODULE_NAME esp_timer
25 #include <zephyr/logging/log.h>
26 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
27
28
29 #if CONFIG_IDF_TARGET_ESP32
30 #include "esp32/rtc.h"
31 #include "esp32/rom/ets_sys.h"
32 #elif CONFIG_IDF_TARGET_ESP32S2
33 #include "esp32s2/rtc.h"
34 #include "esp32s2/rom/ets_sys.h"
35 #elif CONFIG_IDF_TARGET_ESP32S3
36 #include "esp32s3/rtc.h"
37 #include "esp32s3/rom/ets_sys.h"
38 #elif CONFIG_IDF_TARGET_ESP32C3
39 #include "esp32c3/rtc.h"
40 #include "esp32c3/rom/ets_sys.h"
41 #elif CONFIG_IDF_TARGET_ESP32H2
42 #include "esp32h2/rtc.h"
43 #include "esp32h2/rom/ets_sys.h"
44 #endif
45
46 #ifdef CONFIG_ESP_TIMER_PROFILING
47 #define WITH_PROFILING 1
48 #endif
49
50 #ifndef NDEBUG
51 // Enable built-in checks in queue.h in debug builds
52 #define INVARIANTS
53 #endif
54 #include "sys/queue.h"
55
56 #define EVENT_ID_DELETE_TIMER 0xF0DE1E1E
57
58 #define TIMER_EVENT_QUEUE_SIZE 16
59 typedef enum {
60 FL_ISR_DISPATCH_METHOD = (1 << 0), //!< 0=Callback is called from timer task, 1=Callback is called from timer ISR
61 FL_SKIP_UNHANDLED_EVENTS = (1 << 1), //!< 0=NOT skip unhandled events for periodic timers, 1=Skip unhandled events for periodic timers
62 } flags_t;
63
64 struct esp_timer {
65 uint64_t alarm;
66 uint64_t period:56;
67 flags_t flags:8;
68 union {
69 esp_timer_cb_t callback;
70 uint32_t event_id;
71 };
72 void* arg;
73 #if WITH_PROFILING
74 const char* name;
75 size_t times_triggered;
76 size_t times_armed;
77 size_t times_skipped;
78 uint64_t total_callback_run_time;
79 #endif // WITH_PROFILING
80 LIST_ENTRY(esp_timer) list_entry;
81 };
82
83 K_KERNEL_STACK_MEMBER(timer_task_stack, 4096);
84 static bool init_status = false;
85
86 static bool is_initialized(void);
87 static esp_err_t timer_insert(esp_timer_handle_t timer, bool without_update_alarm);
88 static esp_err_t timer_remove(esp_timer_handle_t timer);
89 static bool timer_armed(esp_timer_handle_t timer);
90 static void timer_list_lock(esp_timer_dispatch_t timer_type);
91 static void timer_list_unlock(esp_timer_dispatch_t timer_type);
92
93 #if WITH_PROFILING
94 static void timer_insert_inactive(esp_timer_handle_t timer);
95 static void timer_remove_inactive(esp_timer_handle_t timer);
96 #endif // WITH_PROFILING
97
98 // lists of currently armed timers for two dispatch methods: ISR and TASK
99 static LIST_HEAD(esp_timer_list, esp_timer) s_timers[ESP_TIMER_MAX] = {
100 [0 ... (ESP_TIMER_MAX - 1)] = LIST_HEAD_INITIALIZER(s_timers)
101 };
102 #if WITH_PROFILING
103 // lists of unarmed timers for two dispatch methods: ISR and TASK,
104 // used only to be able to dump statistics about all the timers
105 static LIST_HEAD(esp_inactive_timer_list, esp_timer) s_inactive_timers[ESP_TIMER_MAX] = {
106 [0 ... (ESP_TIMER_MAX - 1)] = LIST_HEAD_INITIALIZER(s_timers)
107 };
108 #endif
109 // task used to dispatch timer callbacks
110 static struct k_thread s_timer_task;
111 // counting semaphore used to notify the timer task from ISR
112 static struct k_sem s_timer_semaphore;
113
114 #if CONFIG_SPIRAM_USE_MALLOC
115 // memory for s_timer_semaphore
116 // static StaticQueue_t s_timer_semaphore_memory;
117 #endif
118
119 // lock protecting s_timers, s_inactive_timers
120 static unsigned int s_timer_lock[ESP_TIMER_MAX] = {
121 [0 ... (ESP_TIMER_MAX - 1)] = 0
122 };
123
124 #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
125 // For ISR dispatch method, a callback function of the timer may require a context switch
126 //static volatile BaseType_t s_isr_dispatch_need_yield = pdFALSE;
127 #endif // CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
esp_timer_create(const esp_timer_create_args_t * args,esp_timer_handle_t * out_handle)128 esp_err_t esp_timer_create(const esp_timer_create_args_t* args,
129 esp_timer_handle_t* out_handle)
130 {
131 if (!is_initialized()) {
132 return ESP_ERR_INVALID_STATE;
133 }
134 if (args == NULL || args->callback == NULL || out_handle == NULL ||
135 args->dispatch_method < 0 || args->dispatch_method >= ESP_TIMER_MAX) {
136 return ESP_ERR_INVALID_ARG;
137 }
138 esp_timer_handle_t result = (esp_timer_handle_t) k_calloc(1, sizeof(*result));
139 if (result == NULL) {
140 return ESP_ERR_NO_MEM;
141 }
142 result->callback = args->callback;
143 result->arg = args->arg;
144 result->flags = (args->dispatch_method ? FL_ISR_DISPATCH_METHOD : 0) |
145 (args->skip_unhandled_events ? FL_SKIP_UNHANDLED_EVENTS : 0);
146 #if WITH_PROFILING
147 result->name = args->name;
148 esp_timer_dispatch_t dispatch_method = result->flags & FL_ISR_DISPATCH_METHOD;
149 timer_list_lock(dispatch_method);
150 timer_insert_inactive(result);
151 timer_list_unlock(dispatch_method);
152 #endif
153 *out_handle = result;
154 return ESP_OK;
155 }
156
esp_timer_start_once(esp_timer_handle_t timer,uint64_t timeout_us)157 esp_err_t IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us)
158 {
159 if (timer == NULL) {
160 return ESP_ERR_INVALID_ARG;
161 }
162 if (!is_initialized() || timer_armed(timer)) {
163 return ESP_ERR_INVALID_STATE;
164 }
165 int64_t alarm = esp_timer_get_time() + timeout_us;
166 esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
167 timer_list_lock(dispatch_method);
168 timer->alarm = alarm;
169 timer->period = 0;
170 #if WITH_PROFILING
171 timer->times_armed++;
172 #endif
173 esp_err_t err = timer_insert(timer, false);
174 timer_list_unlock(dispatch_method);
175 return err;
176 }
177
esp_timer_start_periodic(esp_timer_handle_t timer,uint64_t period_us)178 esp_err_t IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period_us)
179 {
180 if (timer == NULL) {
181 return ESP_ERR_INVALID_ARG;
182 }
183 if (!is_initialized() || timer_armed(timer)) {
184 return ESP_ERR_INVALID_STATE;
185 }
186 period_us = MAX(period_us, esp_timer_impl_get_min_period_us());
187 int64_t alarm = esp_timer_get_time() + period_us;
188 esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
189 timer_list_lock(dispatch_method);
190 timer->alarm = alarm;
191 timer->period = period_us;
192 #if WITH_PROFILING
193 timer->times_armed++;
194 timer->times_skipped = 0;
195 #endif
196 esp_err_t err = timer_insert(timer, false);
197 timer_list_unlock(dispatch_method);
198 return err;
199 }
200
esp_timer_stop(esp_timer_handle_t timer)201 esp_err_t IRAM_ATTR esp_timer_stop(esp_timer_handle_t timer)
202 {
203 if (timer == NULL) {
204 return ESP_ERR_INVALID_ARG;
205 }
206 if (!is_initialized() || !timer_armed(timer)) {
207 return ESP_ERR_INVALID_STATE;
208 }
209 return timer_remove(timer);
210 }
211
esp_timer_delete(esp_timer_handle_t timer)212 esp_err_t esp_timer_delete(esp_timer_handle_t timer)
213 {
214 if (timer == NULL) {
215 return ESP_ERR_INVALID_ARG;
216 }
217 if (timer_armed(timer)) {
218 return ESP_ERR_INVALID_STATE;
219 }
220 // A case for the timer with ESP_TIMER_ISR:
221 // This ISR timer was removed from the ISR list in esp_timer_stop() or in timer_process_alarm() -> LIST_REMOVE(it, list_entry)
222 // and here this timer will be added to another the TASK list, see below.
223 // We do this because we want to free memory of the timer in a task context instead of an isr context.
224 int64_t alarm = esp_timer_get_time();
225 timer_list_lock(ESP_TIMER_TASK);
226 timer->flags &= ~FL_ISR_DISPATCH_METHOD;
227 timer->event_id = EVENT_ID_DELETE_TIMER;
228 timer->alarm = alarm;
229 timer->period = 0;
230 timer_insert(timer, false);
231 timer_list_unlock(ESP_TIMER_TASK);
232 return ESP_OK;
233 }
234
timer_insert(esp_timer_handle_t timer,bool without_update_alarm)235 static IRAM_ATTR esp_err_t timer_insert(esp_timer_handle_t timer, bool without_update_alarm)
236 {
237 #if WITH_PROFILING
238 timer_remove_inactive(timer);
239 #endif
240 esp_timer_handle_t it, last = NULL;
241 esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
242 if (LIST_FIRST(&s_timers[dispatch_method]) == NULL) {
243 LIST_INSERT_HEAD(&s_timers[dispatch_method], timer, list_entry);
244 } else {
245 LIST_FOREACH(it, &s_timers[dispatch_method], list_entry) {
246 if (timer->alarm < it->alarm) {
247 LIST_INSERT_BEFORE(it, timer, list_entry);
248 break;
249 }
250 last = it;
251 }
252 if (it == NULL) {
253 assert(last);
254 LIST_INSERT_AFTER(last, timer, list_entry);
255 }
256 }
257 if (without_update_alarm == false && timer == LIST_FIRST(&s_timers[dispatch_method])) {
258 esp_timer_impl_set_alarm_id(timer->alarm, dispatch_method);
259 }
260 return ESP_OK;
261 }
262
timer_remove(esp_timer_handle_t timer)263 static IRAM_ATTR esp_err_t timer_remove(esp_timer_handle_t timer)
264 {
265 esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
266 timer_list_lock(dispatch_method);
267 esp_timer_handle_t first_timer = LIST_FIRST(&s_timers[dispatch_method]);
268 LIST_REMOVE(timer, list_entry);
269 timer->alarm = 0;
270 timer->period = 0;
271 if (timer == first_timer) { // if this timer was the first in the list.
272 uint64_t next_timestamp = UINT64_MAX;
273 first_timer = LIST_FIRST(&s_timers[dispatch_method]);
274 if (first_timer) { // if after removing the timer from the list, this list is not empty.
275 next_timestamp = first_timer->alarm;
276 }
277 esp_timer_impl_set_alarm_id(next_timestamp, dispatch_method);
278 }
279 #if WITH_PROFILING
280 timer_insert_inactive(timer);
281 #endif
282 timer_list_unlock(dispatch_method);
283 return ESP_OK;
284 }
285
286 #if WITH_PROFILING
287
timer_insert_inactive(esp_timer_handle_t timer)288 static IRAM_ATTR void timer_insert_inactive(esp_timer_handle_t timer)
289 {
290 /* May be locked or not, depending on where this is called from.
291 * Lock recursively.
292 */
293 esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
294 esp_timer_handle_t head = LIST_FIRST(&s_inactive_timers[dispatch_method]);
295 if (head == NULL) {
296 LIST_INSERT_HEAD(&s_inactive_timers[dispatch_method], timer, list_entry);
297 } else {
298 /* Insert as head element as this is the fastest thing to do.
299 * Removal is O(1) anyway.
300 */
301 LIST_INSERT_BEFORE(head, timer, list_entry);
302 }
303 }
304
timer_remove_inactive(esp_timer_handle_t timer)305 static IRAM_ATTR void timer_remove_inactive(esp_timer_handle_t timer)
306 {
307 LIST_REMOVE(timer, list_entry);
308 }
309
310 #endif // WITH_PROFILING
311
timer_armed(esp_timer_handle_t timer)312 static IRAM_ATTR bool timer_armed(esp_timer_handle_t timer)
313 {
314 return timer->alarm > 0;
315 }
316
timer_list_lock(esp_timer_dispatch_t timer_type)317 static IRAM_ATTR void timer_list_lock(esp_timer_dispatch_t timer_type)
318 {
319 s_timer_lock[timer_type] = irq_lock();
320 }
321
timer_list_unlock(esp_timer_dispatch_t timer_type)322 static IRAM_ATTR void timer_list_unlock(esp_timer_dispatch_t timer_type)
323 {
324 irq_unlock(s_timer_lock[timer_type]);
325 }
326
327 #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
timer_process_alarm(esp_timer_dispatch_t dispatch_method)328 static IRAM_ATTR bool timer_process_alarm(esp_timer_dispatch_t dispatch_method)
329 #else
330 static bool timer_process_alarm(esp_timer_dispatch_t dispatch_method)
331 #endif
332 {
333 timer_list_lock(dispatch_method);
334 bool processed = false;
335 esp_timer_handle_t it;
336 while (1) {
337 it = LIST_FIRST(&s_timers[dispatch_method]);
338 int64_t now = esp_timer_impl_get_time();
339 if (it == NULL || it->alarm > now) {
340 break;
341 }
342 processed = true;
343 LIST_REMOVE(it, list_entry);
344 if (it->event_id == EVENT_ID_DELETE_TIMER) {
345 // It is handled only by ESP_TIMER_TASK (see esp_timer_delete()).
346 k_free(it);
347 it = NULL;
348 } else {
349 if (it->period > 0) {
350 int skipped = (now - it->alarm) / it->period;
351 if ((it->flags & FL_SKIP_UNHANDLED_EVENTS) && (skipped > 1)) {
352 it->alarm = now + it->period;
353 #if WITH_PROFILING
354 it->times_skipped += skipped;
355 #endif
356 } else {
357 it->alarm += it->period;
358 }
359 timer_insert(it, true);
360 } else {
361 it->alarm = 0;
362 #if WITH_PROFILING
363 timer_insert_inactive(it);
364 #endif
365 }
366 #if WITH_PROFILING
367 uint64_t callback_start = now;
368 #endif
369 esp_timer_cb_t callback = it->callback;
370 void* arg = it->arg;
371 timer_list_unlock(dispatch_method);
372 (*callback)(arg);
373 timer_list_lock(dispatch_method);
374 #if WITH_PROFILING
375 it->times_triggered++;
376 it->total_callback_run_time += esp_timer_impl_get_time() - callback_start;
377 #endif
378 }
379 } // while(1)
380 if (it) {
381 if (dispatch_method == ESP_TIMER_TASK || (dispatch_method != ESP_TIMER_TASK && processed == true)) {
382 esp_timer_impl_set_alarm_id(it->alarm, dispatch_method);
383 }
384 } else {
385 if (processed) {
386 esp_timer_impl_set_alarm_id(UINT64_MAX, dispatch_method);
387 }
388 }
389 timer_list_unlock(dispatch_method);
390 return processed;
391 }
392
timer_task(void * arg)393 static void timer_task(void* arg)
394 {
395 while (true){
396 k_sem_take(&s_timer_semaphore, K_FOREVER);
397 // all deferred events are processed at a time
398 timer_process_alarm(ESP_TIMER_TASK);
399 }
400 }
401
402 #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
esp_timer_isr_dispatch_need_yield(void)403 IRAM_ATTR void esp_timer_isr_dispatch_need_yield(void)
404 {
405 assert(k_is_in_isr());
406 s_isr_dispatch_need_yield = pdTRUE;
407 }
408 #endif
409
timer_alarm_handler(void * arg)410 static void IRAM_ATTR timer_alarm_handler(void* arg)
411 {
412 bool isr_timers_processed = false;
413
414 #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
415 // process timers with ISR dispatch method
416 isr_timers_processed = timer_process_alarm(ESP_TIMER_ISR);
417 s_isr_dispatch_need_yield = pdFALSE;
418 #endif
419
420 if (isr_timers_processed == false) {
421 k_sem_give(&s_timer_semaphore);
422 }
423 }
424
is_initialized(void)425 static IRAM_ATTR inline bool is_initialized(void)
426 {
427 return init_status;
428 }
429
esp_timer_early_init(void)430 esp_err_t esp_timer_early_init(void)
431 {
432 esp_timer_impl_early_init();
433 #if CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
434 esp_timer_impl_init_system_time();
435 #endif
436 return ESP_OK;
437 }
438
esp_timer_init(void)439 esp_err_t esp_timer_init(void)
440 {
441 esp_err_t err;
442 if (is_initialized()) {
443 return ESP_ERR_INVALID_STATE;
444 }
445
446 int ret = k_sem_init(&s_timer_semaphore, 0, TIMER_EVENT_QUEUE_SIZE);
447 if (ret != 0)
448 {
449 goto out;
450 }
451
452 k_tid_t tid = k_thread_create(&s_timer_task, timer_task_stack,
453 4096, (k_thread_entry_t)timer_task, NULL, NULL, NULL,
454 3, K_INHERIT_PERMS, K_NO_WAIT);
455
456 if (!tid)
457 {
458 goto out;
459 }
460
461 k_thread_name_set(tid, "esp_timer");
462
463 err = esp_timer_impl_init(&timer_alarm_handler);
464 if (err != ESP_OK) {
465 goto out;
466 }
467
468 init_status = true;
469
470 return ESP_OK;
471
472 out:
473 LOG_ERR("could not start esp timer");
474 init_status = false;
475
476 return ESP_ERR_NO_MEM;
477 }
478
esp_timer_deinit(void)479 esp_err_t esp_timer_deinit(void)
480 {
481 if (!is_initialized()) {
482 return ESP_ERR_INVALID_STATE;
483 }
484
485 /* Check if there are any active timers */
486 for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
487 if (!LIST_EMPTY(&s_timers[dispatch_method])) {
488 return ESP_ERR_INVALID_STATE;
489 }
490 }
491
492 /* We can only check if there are any timers which are not deleted if
493 * profiling is enabled.
494 */
495 #if WITH_PROFILING
496 for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
497 if (!LIST_EMPTY(&s_inactive_timers[dispatch_method])) {
498 return ESP_ERR_INVALID_STATE;
499 }
500 }
501 #endif
502
503 esp_timer_impl_deinit();
504
505 init_status = false;
506 return ESP_OK;
507 }
508
print_timer_info(esp_timer_handle_t t,char ** dst,size_t * dst_size)509 static void print_timer_info(esp_timer_handle_t t, char** dst, size_t* dst_size)
510 {
511 #if WITH_PROFILING
512 size_t cb;
513 // name is optional, might be missed.
514 if (t->name) {
515 cb = snprintf(*dst, *dst_size, "%-20.20s ", t->name);
516 } else {
517 cb = snprintf(*dst, *dst_size, "timer@%-10p ", t);
518 }
519 cb += snprintf(*dst + cb, *dst_size + cb, "%-10lld %-12lld %-12d %-12d %-12d %-12lld\n",
520 (uint64_t)t->period, t->alarm, t->times_armed,
521 t->times_triggered, t->times_skipped, t->total_callback_run_time);
522 /* keep this in sync with the format string, used in esp_timer_dump */
523 #define TIMER_INFO_LINE_LEN 90
524 #else
525 size_t cb = snprintf(*dst, *dst_size, "timer@%-14p %-10lld %-12lld\n", t, (uint64_t)t->period, t->alarm);
526 #define TIMER_INFO_LINE_LEN 46
527 #endif
528 *dst += cb;
529 *dst_size -= cb;
530 }
531
532
esp_timer_dump(FILE * stream)533 esp_err_t esp_timer_dump(FILE* stream)
534 {
535 /* Since timer lock is a critical section, we don't want to print directly
536 * to stdout, since that may cause a deadlock if stdout is interrupt-driven
537 * (via the UART driver). Allocate sufficiently large chunk of memory first,
538 * print to it, then dump this memory to stdout.
539 */
540
541 esp_timer_handle_t it;
542
543 /* First count the number of timers */
544 size_t timer_count = 0;
545 for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
546 timer_list_lock(dispatch_method);
547 LIST_FOREACH(it, &s_timers[dispatch_method], list_entry) {
548 ++timer_count;
549 }
550 #if WITH_PROFILING
551 LIST_FOREACH(it, &s_inactive_timers[dispatch_method], list_entry) {
552 ++timer_count;
553 }
554 #endif
555 timer_list_unlock(dispatch_method);
556 }
557
558 /* Allocate the memory for this number of timers. Since we have unlocked,
559 * we may find that there are more timers. There's no bulletproof solution
560 * for this (can't allocate from a critical section), but we allocate
561 * slightly more and the output will be truncated if that is not enough.
562 */
563 size_t buf_size = TIMER_INFO_LINE_LEN * (timer_count + 3);
564 char* print_buf = k_calloc(1, buf_size + 1);
565 if (print_buf == NULL) {
566 return ESP_ERR_NO_MEM;
567 }
568
569 /* Print to the buffer */
570 char* pos = print_buf;
571 for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
572 timer_list_lock(dispatch_method);
573 LIST_FOREACH(it, &s_timers[dispatch_method], list_entry) {
574 print_timer_info(it, &pos, &buf_size);
575 }
576 #if WITH_PROFILING
577 LIST_FOREACH(it, &s_inactive_timers[dispatch_method], list_entry) {
578 print_timer_info(it, &pos, &buf_size);
579 }
580 #endif
581 timer_list_unlock(dispatch_method);
582 }
583
584 if (stream != NULL) {
585 fprintf(stream, "Timer stats:\n");
586 #if WITH_PROFILING
587 fprintf(stream, "%-20s %-10s %-12s %-12s %-12s %-12s %-12s\n",
588 "Name", "Period", "Alarm", "Times_armed", "Times_trigg", "Times_skip", "Cb_exec_time");
589 #else
590 fprintf(stream, "%-20s %-10s %-12s\n", "Name", "Period", "Alarm");
591 #endif
592
593 /* Print the buffer */
594 fputs(print_buf, stream);
595 }
596
597 k_free(print_buf);
598 return ESP_OK;
599 }
600
esp_timer_get_next_alarm(void)601 int64_t IRAM_ATTR esp_timer_get_next_alarm(void)
602 {
603 int64_t next_alarm = INT64_MAX;
604 for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
605 timer_list_lock(dispatch_method);
606 esp_timer_handle_t it = LIST_FIRST(&s_timers[dispatch_method]);
607 if (it) {
608 if (next_alarm > it->alarm) {
609 next_alarm = it->alarm;
610 }
611 }
612 timer_list_unlock(dispatch_method);
613 }
614 return next_alarm;
615 }
616
esp_timer_get_next_alarm_for_wake_up(void)617 int64_t IRAM_ATTR esp_timer_get_next_alarm_for_wake_up(void)
618 {
619 int64_t next_alarm = INT64_MAX;
620 for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
621 timer_list_lock(dispatch_method);
622 esp_timer_handle_t it;
623 LIST_FOREACH(it, &s_timers[dispatch_method], list_entry) {
624 if (it == NULL) {
625 break;
626 }
627 // timers with the SKIP_UNHANDLED_EVENTS flag do not want to wake up CPU from a sleep mode.
628 if ((it->flags & FL_SKIP_UNHANDLED_EVENTS) == 0) {
629 if (next_alarm > it->alarm) {
630 next_alarm = it->alarm;
631 }
632 break;
633 }
634 }
635 timer_list_unlock(dispatch_method);
636 }
637 return next_alarm;
638 }
639
esp_timer_is_active(esp_timer_handle_t timer)640 bool esp_timer_is_active(esp_timer_handle_t timer)
641 {
642 return timer_armed(timer);
643 }
644