1 /*
2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include "sdkconfig.h"
11 #include "hal/wdt_hal.h"
12 #include "esp_err.h"
13 #include "esp_attr.h"
14 #include "esp_check.h"
15 #include "esp_log.h"
16 #include "esp_debug_helpers.h"
17 #include "esp_timer.h"
18 #include "esp_private/esp_task_wdt_impl.h"
19
20 /**
21 * Context for the software implementation of the Task WatchDog Timer.
22 * This will be passed as a parameter to public functions below. */
23 typedef struct {
24 esp_timer_handle_t sw_timer;
25 uint32_t period_ms;
26 } twdt_ctx_soft_t;
27
28 /**
29 * Declare the initial context as static. It will be passed to the
30 * task_wdt implementation as the implementation context in the
31 * init function. */
32 static twdt_ctx_soft_t init_context;
33
34 static const char *TAG = "task_wdt_impl_soft";
35
36
esp_task_wdt_impl_timer_allocate(const esp_task_wdt_config_t * config,twdt_isr_callback callback,twdt_ctx_t * obj)37 esp_err_t esp_task_wdt_impl_timer_allocate(const esp_task_wdt_config_t *config,
38 twdt_isr_callback callback,
39 twdt_ctx_t *obj)
40 {
41 twdt_ctx_soft_t *ctx = &init_context;
42 const esp_timer_create_args_t timer_args = {
43 .callback = callback,
44 .arg = NULL,
45 .dispatch_method = ESP_TIMER_ISR,
46 .name = "Task software watchdog",
47 .skip_unhandled_events = true
48 };
49
50 /* Software Task timer. As we don't have a spare hardware watchdog timer, we will use esp_timer to simulate one */
51 esp_err_t ret = esp_timer_create(&timer_args, &ctx->sw_timer);
52 ESP_GOTO_ON_FALSE((ret == ESP_OK), ret, reterr, TAG, "could not start periodic timer");
53
54 /* Configure it as a periodic timer, so that we check the Tasks everytime it is triggered.
55 * No need to start the timer here, it will be started later with `esp_task_wdt_impl_timer_restart` */
56 ctx->period_ms = config->timeout_ms;
57
58 /* Return our context to the caller */
59 *obj = (twdt_ctx_t) ctx;
60
61 reterr:
62 return ret;
63 }
64
esp_task_wdt_impl_timer_reconfigure(twdt_ctx_t obj,const esp_task_wdt_config_t * config)65 esp_err_t esp_task_wdt_impl_timer_reconfigure(twdt_ctx_t obj, const esp_task_wdt_config_t *config)
66 {
67 esp_err_t ret = ESP_OK;
68 twdt_ctx_soft_t* ctx = (twdt_ctx_soft_t*) obj;
69
70 if (config == NULL || ctx == NULL) {
71 ret = ESP_ERR_INVALID_STATE;
72 }
73
74 if (ret == ESP_OK) {
75 /* The timer is stopped, we only need to update the period in our context, next time we start the
76 * timer with `esp_task_wdt_impl_timer_restart`, we will pass the context's period to the
77 * underlying esp_timer instance. */
78 ctx->period_ms = config->timeout_ms;
79 }
80
81 return ret;
82 }
83
84
esp_task_wdt_impl_timer_free(twdt_ctx_t obj)85 void esp_task_wdt_impl_timer_free(twdt_ctx_t obj)
86 {
87 const twdt_ctx_soft_t* ctx = (twdt_ctx_soft_t*) obj;
88
89 if (ctx != NULL && ctx->sw_timer != NULL) {
90 ESP_ERROR_CHECK(esp_timer_delete(ctx->sw_timer));
91 }
92 }
93
94
esp_task_wdt_impl_timer_feed(twdt_ctx_t obj)95 esp_err_t esp_task_wdt_impl_timer_feed(twdt_ctx_t obj)
96 {
97 esp_err_t ret = ESP_OK;
98 const twdt_ctx_soft_t* ctx = (twdt_ctx_soft_t*) obj;
99
100 if (ctx == NULL) {
101 ret = ESP_ERR_INVALID_STATE;
102 }
103
104 if (ret == ESP_OK) {
105 /* Feed the periodic timer by restarting it, specifying the same period */
106 ret = esp_timer_restart(ctx->sw_timer, ctx->period_ms * 1000);
107 }
108
109 return ret;
110 }
111
112
esp_task_wdt_impl_timeout_triggered(twdt_ctx_t obj)113 void esp_task_wdt_impl_timeout_triggered(twdt_ctx_t obj)
114 {
115 (void) obj;
116 }
117
118
esp_task_wdt_impl_timer_stop(twdt_ctx_t obj)119 esp_err_t esp_task_wdt_impl_timer_stop(twdt_ctx_t obj)
120 {
121 esp_err_t ret = ESP_OK;
122 const twdt_ctx_soft_t* ctx = (twdt_ctx_soft_t*) obj;
123
124 if (ctx == NULL || ctx->sw_timer == NULL) {
125 ret = ESP_ERR_INVALID_STATE;
126 }
127
128 if (ret == ESP_OK) {
129 ret = esp_timer_stop(ctx->sw_timer);
130 }
131
132 return ret;
133 }
134
135
esp_task_wdt_impl_timer_restart(twdt_ctx_t obj)136 esp_err_t esp_task_wdt_impl_timer_restart(twdt_ctx_t obj)
137 {
138 esp_err_t ret = ESP_OK;
139 twdt_ctx_soft_t* ctx = (twdt_ctx_soft_t*) obj;
140
141 if (ctx == NULL || ctx->sw_timer == NULL) {
142 ret = ESP_ERR_INVALID_STATE;
143 }
144
145 if (ret == ESP_OK) {
146 esp_timer_start_periodic(ctx->sw_timer, ctx->period_ms * 1000);
147 }
148
149 return ret;
150 }
151