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