1 /*
2  * Copyright (c) 2025 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(wdt_vars, LOG_LEVEL_INF);
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/cache.h>
12 #include <zephyr/drivers/watchdog.h>
13 
14 #define WDT_WINDOW_MAX	(500)
15 
16 /* Watchdog related variables */
17 static const struct device *const my_wdt_device = DEVICE_DT_GET(DT_ALIAS(watchdog0));
18 static struct wdt_timeout_cfg m_cfg_wdt0;
19 
20 /* No init section will contain WDT_HAS_FIRED if watchdog has fired */
21 #define WDT_HAS_FIRED	(12345678U)
22 #define TEST_VALUE		(2U)
23 
24 #define NOINIT_SECTION ".noinit.test_wdt"
25 static volatile uint32_t wdt_status __attribute__((section(NOINIT_SECTION)));
26 
27 /* Global variables to verify */
28 static int global_tmp_0;
29 static int global_tmp_1 = TEST_VALUE;
30 
31 
wdt_int_cb(const struct device * wdt_dev,int channel_id)32 static void wdt_int_cb(const struct device *wdt_dev, int channel_id)
33 {
34 	ARG_UNUSED(wdt_dev);
35 	ARG_UNUSED(channel_id);
36 	wdt_status = WDT_HAS_FIRED;
37 
38 	/* Flush cache as reboot may invalidate all lines. */
39 	sys_cache_data_flush_range((void *) &wdt_status, sizeof(wdt_status));
40 }
41 
main(void)42 int main(void)
43 {
44 	int ret;
45 	static int tmp_0;
46 	static int tmp_1 = TEST_VALUE;
47 
48 	LOG_INF("wdt_variables test on %s", CONFIG_BOARD_TARGET);
49 
50 	global_tmp_0++;
51 	global_tmp_1++;
52 	tmp_0++;
53 	tmp_1++;
54 
55 	LOG_DBG("global_tmp_0 = %d", global_tmp_0);
56 	LOG_DBG("global_tmp_1 = %d", global_tmp_1);
57 	LOG_DBG("tmp_0 = %d", tmp_0);
58 	LOG_DBG("tmp_1 = %d", tmp_1);
59 
60 	/* When watchdog fires, variable wdt_status is set to the value of WDT_HAS_FIRED
61 	 * in WDT callback wdt_int_cb(). Then, target is reset.
62 	 * Check value of wdt_status to prevent reset loop.
63 	 */
64 	if (wdt_status != WDT_HAS_FIRED) {
65 
66 		LOG_INF("Reset wasn't due to watchdog.");
67 
68 		if (!device_is_ready(my_wdt_device)) {
69 			LOG_ERR("WDT device %s is not ready", my_wdt_device->name);
70 			return 1;
71 		}
72 
73 		/* Configure Watchdog */
74 		m_cfg_wdt0.callback = wdt_int_cb;
75 		m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC;
76 		m_cfg_wdt0.window.min = 0U;
77 		m_cfg_wdt0.window.max = WDT_WINDOW_MAX;
78 		ret = wdt_install_timeout(my_wdt_device, &m_cfg_wdt0);
79 		if (ret < 0) {
80 			LOG_ERR("wdt_install_timeout() returned %d", ret);
81 			return 1;
82 		}
83 
84 		/* Start Watchdog */
85 		ret = wdt_setup(my_wdt_device, WDT_OPT_PAUSE_HALTED_BY_DBG);
86 		if (ret < 0) {
87 			LOG_ERR("wdt_setup() returned %d", ret);
88 			return 1;
89 		}
90 
91 		LOG_INF("Watchdog shall fire in ~%u miliseconds", WDT_WINDOW_MAX);
92 		k_sleep(K_FOREVER);
93 	} else {
94 		bool test_passing = true;
95 
96 		LOG_INF("Watchod has fired");
97 
98 		if (global_tmp_0 != 1) {
99 			LOG_ERR("global_tmp_0 is %d instead of 1", global_tmp_0);
100 			test_passing = false;
101 		}
102 
103 		if (global_tmp_1 != (TEST_VALUE + 1)) {
104 			LOG_ERR("global_tmp_1 is %d instead of %d", global_tmp_1, TEST_VALUE + 1);
105 			test_passing = false;
106 		}
107 
108 		if (tmp_0 != 1) {
109 			LOG_ERR("tmp_0 is %d instead of 1", tmp_0);
110 			test_passing = false;
111 		}
112 
113 		if (tmp_1 != (TEST_VALUE + 1)) {
114 			LOG_ERR("tmp_1 is %d instead of %d", tmp_1, TEST_VALUE + 1);
115 			test_passing = false;
116 		}
117 
118 		/* Cleanup */
119 		wdt_status = 0;
120 		sys_cache_data_flush_range((void *) &wdt_status, sizeof(wdt_status));
121 
122 		if (test_passing) {
123 			LOG_INF("Test completed successfully");
124 		} else {
125 			LOG_INF("Test failed");
126 		}
127 	}
128 
129 	return 0;
130 }
131