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(DT_ALIAS(watchdog0), okay)
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_kinetis_wdog32)
37 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_kinetis_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 	}
71 
72 	ret = task_wdt_init(hw_wdt_dev);
73 	if (ret != 0) {
74 		printk("task wdt init failure: %d\n", ret);
75 		return 0;
76 	}
77 
78 
79 	/* passing NULL instead of callback to trigger system reset */
80 	int task_wdt_id = task_wdt_add(1100U, NULL, NULL);
81 
82 	while (true) {
83 		printk("Main thread still alive...\n");
84 		task_wdt_feed(task_wdt_id);
85 		k_sleep(K_MSEC(1000));
86 	}
87 	return 0;
88 }
89 
90 /*
91  * This high-priority thread needs a tight timing
92  */
control_thread(void)93 void control_thread(void)
94 {
95 	int task_wdt_id;
96 	int count = 0;
97 
98 	printk("Control thread started.\n");
99 
100 	/*
101 	 * Add a new task watchdog channel with custom callback function and
102 	 * the current thread ID as user data.
103 	 */
104 	task_wdt_id = task_wdt_add(100U, task_wdt_callback,
105 		(void *)k_current_get());
106 
107 	while (true) {
108 		if (count == 50) {
109 			printk("Control thread getting stuck...\n");
110 			k_sleep(K_FOREVER);
111 		}
112 
113 		task_wdt_feed(task_wdt_id);
114 		k_sleep(K_MSEC(50));
115 		count++;
116 	}
117 }
118 
119 K_THREAD_DEFINE(control, 1024, control_thread, NULL, NULL, NULL, -1, 0, 1000);
120