1 /*
2  * Copyright (c) 2020 Libre Solar Technologies GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/watchdog.h>
10 #include <zephyr/sys/reboot.h>
11 #include <zephyr/task_wdt/task_wdt.h>
12 #include <zephyr/sys/printk.h>
13 #include <stdbool.h>
14 
15 /*
16  * To use this sample, either the devicetree's /aliases must have a
17  * 'watchdog0' property, or one of the following watchdog compatibles
18  * must have an enabled node.
19  *
20  * If the devicetree has a watchdog node, we get the watchdog device
21  * from there. Otherwise, the task watchdog will be used without a
22  * hardware watchdog fallback.
23  */
24 #if DT_NODE_HAS_STATUS_OKAY(DT_ALIAS(watchdog0))
25 #define WDT_NODE DT_ALIAS(watchdog0)
26 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_window_watchdog)
27 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_window_watchdog)
28 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_watchdog)
29 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_watchdog)
30 #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_wdt)
31 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nordic_nrf_wdt)
32 #elif DT_HAS_COMPAT_STATUS_OKAY(espressif_esp32_watchdog)
33 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(espressif_esp32_watchdog)
34 #elif DT_HAS_COMPAT_STATUS_OKAY(silabs_gecko_wdog)
35 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(silabs_gecko_wdog)
36 #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_wdog32)
37 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_wdog32)
38 #elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_watchdog)
39 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(microchip_xec_watchdog)
40 #else
41 #define WDT_NODE DT_INVALID_NODE
42 #endif
43 
task_wdt_callback(int channel_id,void * user_data)44 static void task_wdt_callback(int channel_id, void *user_data)
45 {
46 	printk("Task watchdog channel %d callback, thread: %s\n",
47 		channel_id, k_thread_name_get((k_tid_t)user_data));
48 
49 	/*
50 	 * If the issue could be resolved, call task_wdt_feed(channel_id) here
51 	 * to continue operation.
52 	 *
53 	 * Otherwise we can perform some cleanup and reset the device.
54 	 */
55 
56 	printk("Resetting device...\n");
57 
58 	sys_reboot(SYS_REBOOT_COLD);
59 }
60 
main(void)61 int main(void)
62 {
63 	int ret;
64 	const struct device *const hw_wdt_dev = DEVICE_DT_GET_OR_NULL(WDT_NODE);
65 
66 	printk("Task watchdog sample application.\n");
67 
68 	if (!device_is_ready(hw_wdt_dev)) {
69 		printk("Hardware watchdog not ready; ignoring it.\n");
70 		ret = task_wdt_init(NULL);
71 	} else {
72 		ret = task_wdt_init(hw_wdt_dev);
73 	}
74 
75 	if (ret != 0) {
76 		printk("task wdt init failure: %d\n", ret);
77 		return 0;
78 	}
79 
80 
81 	/* passing NULL instead of callback to trigger system reset */
82 	int task_wdt_id = task_wdt_add(1100U, NULL, NULL);
83 
84 	while (true) {
85 		printk("Main thread still alive...\n");
86 		task_wdt_feed(task_wdt_id);
87 		k_sleep(K_MSEC(1000));
88 	}
89 	return 0;
90 }
91 
92 /*
93  * This high-priority thread needs a tight timing
94  */
control_thread(void)95 void control_thread(void)
96 {
97 	int task_wdt_id;
98 	int count = 0;
99 
100 	printk("Control thread started.\n");
101 
102 	/*
103 	 * Add a new task watchdog channel with custom callback function and
104 	 * the current thread ID as user data.
105 	 */
106 	task_wdt_id = task_wdt_add(100U, task_wdt_callback,
107 		(void *)k_current_get());
108 
109 	while (true) {
110 		if (count == 50) {
111 			printk("Control thread getting stuck...\n");
112 			k_sleep(K_FOREVER);
113 		}
114 
115 		task_wdt_feed(task_wdt_id);
116 		k_sleep(K_MSEC(50));
117 		count++;
118 	}
119 }
120 
121 K_THREAD_DEFINE(control, 1024, control_thread, NULL, NULL, NULL, -1, 0, 1000);
122