Data Logger BLE Cellular Board
Loading...
Searching...
No Matches
watchdog_app.c
Go to the documentation of this file.
1/**
2 * \file watchdog_app.c
3 *
4 * \brief Watchdog application wrapper for initializing, starting, and feeding the
5 * watchdog timer using Zephyr watchdog APIs.
6 *
7 * \copyright 2021 Nordic Semiconductor ASA
8 * \note SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
9 *
10 */
11
13#include <zephyr/device.h>
14#include <zephyr/drivers/watchdog.h>
15#include <zephyr/kernel.h>
16
17#include "watchdog_app.h"
18
19#include <zephyr/logging/log.h>
20// If a specific logging level is configured for the watchdog module, enable it here.
21// LOG_MODULE_REGISTER(watchdog_app, CONFIG_WATCHDOG_LOG_LEVEL);
22LOG_MODULE_REGISTER(watchdog_app);
23
24#define WDT_FEED_WORKER_DELAY_MS ((CONFIG_WATCHDOG_APPLICATION_TIMEOUT_SEC * 1000) / 2)
25#define WATCHDOG_TIMEOUT_MSEC (CONFIG_WATCHDOG_APPLICATION_TIMEOUT_SEC * 1000)
26
27/**
28 * \brief Watchdog configuration storage.
29 *
30 * This structure holds the watchdog device pointer used for
31 * initialization and operation of the watchdog timer.
32 */
34 const struct device *wdt; /*!< Pointer to the watchdog device instance. */
35};
36
37/**
38 * \brief Watchdog runtime data storage.
39 *
40 * This structure holds the installed watchdog channel ID and the delayed work
41 * item used to periodically feed the watchdog.
42 */
44 int wdt_channel_id; /*!< Watchdog channel ID installed with the driver. */
45 struct k_work_delayable system_workqueue_work; /*!< Delayed work used to feed the watchdog periodically. */
46};
47
48static watchdog_evt_handler_t app_evt_handler; //!< Registered application event handler.
49
50static bool init_and_start; //!< Flag set when the library has been initialized and started. */
51
52/**
53 * \fn static void watchdog_notify_event(const struct watchdog_evt *evt)
54 *
55 * \brief Notify the registered watchdog event handler of an event.
56 *
57 * \param evt Pointer to the watchdog event data.
58 */
59static void watchdog_notify_event(const struct watchdog_evt *evt) {
60 __ASSERT(evt != NULL, "Library event not found");
61
62 if (app_evt_handler != NULL) {
63 app_evt_handler(evt);
64 }
65}
66
67/** \brief Watchdog device configuration storage. */
68static const struct wdt_config_storage wdt_config = {
69 .wdt = DEVICE_DT_GET(DT_NODELABEL(wdt)),
70};
71
73
74/** \fn static void primary_feed_worker(struct k_work *work_desc)
75 *
76 * \brief Primary watchdog feeding work handler.
77 *
78 * This work handler feeds the watchdog timer periodically unless
79 * the stopWDTFeed flag is set. If feeding succeeds, the work is
80 * rescheduled after WDT_FEED_WORKER_DELAY_MS. If the flag is set,
81 * the function returns early to allow the watchdog to timeout.
82 *
83 * \param work_desc Pointer to the work item descriptor.
84 */
85static void primary_feed_worker(struct k_work *work_desc) {
86 if (stopWDTFeed)
87 return; /* force a WDT timeout */
88 struct watchdog_evt evt = {
89 .type = WATCHDOG_EVT_FEED,
90 };
91
92 int err = wdt_feed(wdt_config.wdt, wdt_data.wdt_channel_id);
93
94 // myPrintkI("Feeding watchdog\n");
95 LOG_DBG("Feeding watchdog");
96
97 if (err) {
98 myPrintkE("Cannot feed watchdog. Error code: %d\n", err);
99 LOG_ERR("Cannot feed watchdog. Error code: %d", err);
100 } else {
101 k_work_reschedule(&wdt_data.system_workqueue_work, K_MSEC(WDT_FEED_WORKER_DELAY_MS));
102 }
103
105}
106
107/** \fn watchdog_timeout_install(const struct wdt_config_storage *config, struct wdt_data_storage *data)
108 *
109 * \brief Installs a watchdog timeout configuration and registers it with the WDT device.
110 *
111 * \param config Pointer to the watchdog configuration storage containing the WDT device.
112 * \param data Pointer to the watchdog data storage where the channel ID will be stored.
113 *
114 * \return 0 on success, -EFAULT if timeout installation fails.
115 */
116static int watchdog_timeout_install(const struct wdt_config_storage *config, struct wdt_data_storage *data) {
117 static const struct wdt_timeout_cfg wdt_settings = {.window =
118 {
119 .min = 0,
121 },
122 .callback = NULL,
123 .flags = WDT_FLAG_RESET_SOC};
124 struct watchdog_evt evt = {.type = WATCHDOG_EVT_TIMEOUT_INSTALLED, .timeout = WATCHDOG_TIMEOUT_MSEC};
125
126 __ASSERT_NO_MSG(config != NULL);
127 __ASSERT_NO_MSG(data != NULL);
128
129 data->wdt_channel_id = wdt_install_timeout(config->wdt, &wdt_settings);
130 if (data->wdt_channel_id < 0) {
131 myPrintkE("Cannot install watchdog timer! Error code: %d\n", data->wdt_channel_id);
132 LOG_ERR("Cannot install watchdog timer! Error code: %d", data->wdt_channel_id);
133 return -EFAULT;
134 }
135
137
138 myPrintkI("Watchdog timeout installed. Timeout: %d Seconds\n", CONFIG_WATCHDOG_APPLICATION_TIMEOUT_SEC);
139 LOG_DBG("Watchdog timeout installed. Timeout: %d", CONFIG_WATCHDOG_APPLICATION_TIMEOUT_SEC);
140 return 0;
141}
142
143/** \fn watchdog_start(const struct wdt_config_storage *config)
144 *
145 * \brief Starts the watchdog timer hardware instance.
146 *
147 * \param config Pointer to watchdog configuration storage.
148 *
149 * \return 0 on success, or a negative errno on failure.
150 */
151static int watchdog_start(const struct wdt_config_storage *config) {
152 __ASSERT_NO_MSG(config != NULL);
153
154 int err = wdt_setup(config->wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
155
156 if (err) {
157 myPrintkE("Cannot start watchdog! Error code: %d\n", err);
158 LOG_ERR("Cannot start watchdog! Error code: %d", err);
159 } else {
160 myPrintkI("Watchdog started\n");
161 LOG_DBG("Watchdog started");
162 }
163 return err;
164}
165
166/**
167 * \fn static int watchdog_feed_enable(const struct wdt_config_storage *config, struct wdt_data_storage *data)
168 *
169 * \brief Enable periodic feeding of the hardware watchdog.
170 *
171 * \param config: Pointer to the stored watchdog configuration (must not be NULL).
172 * \param data: Pointer to runtime watchdog data (must not be NULL).
173 *
174 * This function initializes a delayed work item which will periodically
175 * call primary_feed_worker to feed the watchdog and schedules the first
176 * invocation. It also performs an immediate feed to ensure the watchdog
177 * does not expire while setup completes and notifies interested subsystems
178 * about the feed event.
179 *
180 * \return 0 on success, or a negative errno on failure.
181 */
182static int watchdog_feed_enable(const struct wdt_config_storage *config, struct wdt_data_storage *data) {
183 __ASSERT_NO_MSG(config != NULL);
184 __ASSERT_NO_MSG(data != NULL);
185
186 /* Prepare a feed event to notify subscribers after a successful feed */
187 struct watchdog_evt evt = {
188 .type = WATCHDOG_EVT_FEED,
189 };
190
191 /* Initialize the delayed work that will perform periodic feeds */
192 k_work_init_delayable(&data->system_workqueue_work, primary_feed_worker);
193
194 /* Perform an immediate feed on the configured channel */
195 int err = wdt_feed(config->wdt, data->wdt_channel_id);
196
197 if (err) {
198 LOG_ERR("Cannot feed watchdog. Error code: %d", err);
199 return err;
200 }
201
202 /* Notify listeners that a feed occurred */
204
205 /* Schedule periodic feed worker (delay defined by WDT_FEED_WORKER_DELAY_MS) */
206 k_work_schedule(&data->system_workqueue_work, K_MSEC(WDT_FEED_WORKER_DELAY_MS));
207 myPrintkI("Watchdog feed enabled. Timeout: %d Seconds\n", WDT_FEED_WORKER_DELAY_MS / 1000);
208 LOG_DBG("Watchdog feed enabled. Timeout: %d", WDT_FEED_WORKER_DELAY_MS / 1000);
209
210 return err;
211}
212
213/** \fn static int watchdog_enable(const struct wdt_config_storage *config, struct wdt_data_storage *data)
214 *
215 * \brief Enable and initialize the watchdog: verify device readiness, install the
216 * timeout, start the watchdog hardware, and enable periodic feeding.
217 *
218 * \param config: pointer to watchdog configuration storage (wdt device and params)
219 * \param data: pointer to watchdog runtime data storage (channel id, workqueue, etc.)
220 *
221 * \return 0 on success or a negative errno on failure.
222 */
223static int watchdog_enable(const struct wdt_config_storage *config, struct wdt_data_storage *data) {
224 int err;
225
226 __ASSERT_NO_MSG(data != NULL);
227
228 if (!device_is_ready(config->wdt)) {
229 myPrintkI("Watchdog device not ready\n");
230 LOG_ERR("Watchdog device not ready");
231 return -ENODEV;
232 }
233
234 err = watchdog_timeout_install(config, data);
235 if (err) {
236 return err;
237 }
238
239 err = watchdog_start(config);
240 if (err) {
241 return err;
242 }
243
244 err = watchdog_feed_enable(config, data);
245 if (err) {
246 return err;
247 }
248
249 return 0;
250}
251
252/** \fn int watchdog_init_and_start(void)
253 *
254 * \brief Initialize and start the watchdog timer.
255 *
256 * \return 0 on success, or a negative error code on failure.
257 */
259 int err;
260 struct watchdog_evt evt = {.type = WATCHDOG_EVT_START};
261
262 myPrintkI("start watchdog\n");
263 LOG_INF("start watchdog\n");
264 LOG_WRN("start watchdog\n");
265 LOG_DBG("start watchdog\n");
266 LOG_INF("start watchdog\n");
267
269 if (err) {
270 myPrintkE("Failed to enable watchdog, error: %d\n", err);
271 LOG_ERR("Failed to enable watchdog, error: %d", err);
272 return err;
273 }
274
276
277 init_and_start = true;
278 return 0;
279}
280
281/** \fn void watchdog_register_handler(watchdog_evt_handler_t evt_handler)
282 *
283 * @brief Register handler to receive watchdog callback events.
284 *
285 * @note The library only allows for one event handler to be registered
286 * at a time. A passed in event handler in this function will
287 * overwrite the previously set event handler.
288 *
289 * @param evt_handler Event handler. Handler is de-registered if parameter is NULL.
290 */
292 if (evt_handler == NULL) {
293 app_evt_handler = NULL;
294
295 myPrintkI("Previously registered handler %p de-registered\n", app_evt_handler);
296 LOG_DBG("Previously registered handler %p de-registered", app_evt_handler);
297
298 return;
299 }
300
301 myPrintkI("Registering handler %p\n", evt_handler);
302 LOG_DBG("Registering handler %p", evt_handler);
303
304 app_evt_handler = evt_handler;
305
306 /* If the application watchdog already has been initialized and started prior to an
307 * external module registering a handler, the newly registered handler is notified that
308 * the library has been started and that a watchdog timeout has been installed.
309 */
310 if (init_and_start) {
311 struct watchdog_evt evt = {
312 .type = WATCHDOG_EVT_START,
313 };
314
316
319
321 }
322}
uint8_t stopWDTFeed
stop Watch Dog Timer feed causing a WDT interrupt for testing
Definition globals.c:38
common struct, enum, externs, prototypes
int myPrintkI(char *restrict fmt,...)
prints an information message to the UART
Definition main.c:2386
int myPrintkE(char *restrict fmt,...)
prints an error message to the UART
Definition main.c:2452
enum watchdog_evt_type type
uint32_t timeout
Watchdog configuration storage.
const struct device * wdt
Watchdog runtime data storage.
struct k_work_delayable system_workqueue_work
static int watchdog_start(const struct wdt_config_storage *config)
Starts the watchdog timer hardware instance.
static int watchdog_enable(const struct wdt_config_storage *config, struct wdt_data_storage *data)
Enable and initialize the watchdog: verify device readiness, install the timeout, start the watchdog ...
static int watchdog_feed_enable(const struct wdt_config_storage *config, struct wdt_data_storage *data)
Enable periodic feeding of the hardware watchdog.
int watchdog_init_and_start(void)
Initialize and start the watchdog timer.
static void watchdog_notify_event(const struct watchdog_evt *evt)
Notify the registered watchdog event handler of an event.
LOG_MODULE_REGISTER(watchdog_app)
#define WDT_FEED_WORKER_DELAY_MS
static const struct wdt_config_storage wdt_config
Watchdog device configuration storage.
static struct wdt_data_storage wdt_data
static watchdog_evt_handler_t app_evt_handler
Registered application event handler.
static void primary_feed_worker(struct k_work *work_desc)
Primary watchdog feeding work handler.
static int watchdog_timeout_install(const struct wdt_config_storage *config, struct wdt_data_storage *data)
Installs a watchdog timeout configuration and registers it with the WDT device.
#define WATCHDOG_TIMEOUT_MSEC
static bool init_and_start
Flag set when the library has been initialized and started. *‍/.
void watchdog_register_handler(watchdog_evt_handler_t evt_handler)
Register handler to receive watchdog callback events.
Watchdog module for Asset Tracker v2.
void(* watchdog_evt_handler_t)(const struct watchdog_evt *evt)
Watchdog library event handler.
@ WATCHDOG_EVT_FEED
@ WATCHDOG_EVT_START
@ WATCHDOG_EVT_TIMEOUT_INSTALLED