From bbba97af82e8e7c773147ea6645db158155e6ff6 Mon Sep 17 00:00:00 2001 From: seteiro Date: Sat, 17 Oct 2026 22:36:14 +0800 Subject: [PATCH] [utest][watchdog] Add watchdog smoke test for #11446 Add components.drivers.watchdog.smoke covering device find/open and timeout set/get. Optional start/keepalive/stop stays off by default to avoid board reset when STOP is unsupported. Co-Authored-By: Grok --- components/drivers/watchdog/SConscript | 7 +- components/drivers/watchdog/utest/Kconfig | 37 ++++ components/drivers/watchdog/utest/SConscript | 13 ++ components/drivers/watchdog/utest/wdt_tc.c | 179 +++++++++++++++++++ components/utilities/utest/Kconfig | 1 + 5 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 components/drivers/watchdog/utest/Kconfig create mode 100644 components/drivers/watchdog/utest/SConscript create mode 100644 components/drivers/watchdog/utest/wdt_tc.c diff --git a/components/drivers/watchdog/SConscript b/components/drivers/watchdog/SConscript index 93740cde3d80..3bc43a631083 100644 --- a/components/drivers/watchdog/SConscript +++ b/components/drivers/watchdog/SConscript @@ -1,4 +1,5 @@ from building import * +import os group = [] @@ -6,7 +7,6 @@ if not GetDepend(['RT_USING_WDT']): Return('group') cwd = GetCurrentDir() -list = os.listdir(cwd) CPPPATH = [cwd + '/../include'] src = ['dev_watchdog.c'] @@ -19,4 +19,9 @@ if GetDepend(['RT_WDT_I6300ESB']): group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) +list = os.listdir(cwd) +for item in list: + if os.path.isfile(os.path.join(cwd, item, 'SConscript')): + group = group + SConscript(os.path.join(item, 'SConscript')) + Return('group') diff --git a/components/drivers/watchdog/utest/Kconfig b/components/drivers/watchdog/utest/Kconfig new file mode 100644 index 000000000000..6e115cb2acfa --- /dev/null +++ b/components/drivers/watchdog/utest/Kconfig @@ -0,0 +1,37 @@ +menu "Watchdog Test" + depends on RT_USING_WDT + +config RT_UTEST_WDT + bool "Watchdog Smoke Test" + default n + help + Validate watchdog device find/open and timeout set/get. Optional + start/keepalive/stop is off by default to avoid board reset when the + hardware cannot stop the WDT. + +if RT_UTEST_WDT + + config RT_UTEST_WDT_DEVICE_NAME + string "Watchdog Device Name" + default "wdt" + help + Device name registered by the BSP, usually "wdt". + + config RT_UTEST_WDT_TIMEOUT_SEC + int "Timeout Used by Smoke Test (Seconds)" + range 1 60 + default 5 + help + Timeout value written by SET_TIMEOUT and checked by GET_TIMEOUT. + + config RT_UTEST_WDT_START + bool "Also Start/Keepalive/Stop Watchdog" + default n + help + When enabled, the test starts the WDT with the configured timeout, + feeds it once, then stops it. Keep this off unless the BSP WDT can + be stopped safely; otherwise the board may reset if STOP fails. + +endif + +endmenu diff --git a/components/drivers/watchdog/utest/SConscript b/components/drivers/watchdog/utest/SConscript new file mode 100644 index 000000000000..7bf6eb396b14 --- /dev/null +++ b/components/drivers/watchdog/utest/SConscript @@ -0,0 +1,13 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd, cwd + '/../../include'] + +if GetDepend(['RT_UTEST_WDT']): + src += ['wdt_tc.c'] + +group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES', 'RT_USING_WDT'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/watchdog/utest/wdt_tc.c b/components/drivers/watchdog/utest/wdt_tc.c new file mode 100644 index 000000000000..9cfd97c43402 --- /dev/null +++ b/components/drivers/watchdog/utest/wdt_tc.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2006-2026 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-10-17 seteiro add watchdog smoke utest for #11446 + */ + +/** + * Test Case Name: Watchdog Smoke Test + * + * Test Objectives: + * - Verify that the watchdog device can be found and opened. + * - Verify SET_TIMEOUT / GET_TIMEOUT round-trip. + * - Optionally verify START / KEEPALIVE / STOP when enabled. + * + * Dependencies: + * - Requires `RT_UTEST_WDT` and `RT_USING_WDT`. + * - BSP must register a watchdog device (default name `wdt`). + * - START path is optional (`RT_UTEST_WDT_START`); leave it off when the + * hardware cannot stop the WDT, otherwise the board may reset. + * + * Expected Results: + * - Find/open and timeout set/get checks pass. + * - When START is enabled, start/keepalive/stop also pass. + * + * Board notes: + * - qemu-vexpress-a9 enables `RT_USING_WDT` but does not register a WDT + * device; enable this case on a BSP that provides `wdt` (e.g. CH32/STM32). + */ + +#include +#include +#include +#include "utest.h" + +#ifdef RT_UTEST_WDT + +#ifndef RT_UTEST_WDT_DEVICE_NAME +#define RT_UTEST_WDT_DEVICE_NAME "wdt" +#endif + +#ifndef RT_UTEST_WDT_TIMEOUT_SEC +#define RT_UTEST_WDT_TIMEOUT_SEC 5 +#endif + +#define WDT_TC_SUITE_TIMEOUT 10 + +static rt_device_t wdt_tc_device; +static rt_bool_t wdt_tc_device_opened; + +static void wdt_timeout_set_get_test(void) +{ + rt_err_t result; + rt_uint32_t timeout; + rt_uint32_t readback; + + timeout = RT_UTEST_WDT_TIMEOUT_SEC; + result = rt_device_control(wdt_tc_device, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &timeout); + uassert_int_equal(result, RT_EOK); + if (result != RT_EOK) + { + return; + } + + readback = 0; + result = rt_device_control(wdt_tc_device, RT_DEVICE_CTRL_WDT_GET_TIMEOUT, &readback); + if (result == -RT_ENOSYS) + { + LOG_W("GET_TIMEOUT not supported, skip readback check"); + return; + } + + uassert_int_equal(result, RT_EOK); + if (result != RT_EOK) + { + return; + } + + LOG_I("WDT timeout set=%u get=%u", (unsigned)timeout, (unsigned)readback); + uassert_int_equal(readback, timeout); +} + +#ifdef RT_UTEST_WDT_START +static void wdt_start_keepalive_stop_test(void) +{ + rt_err_t result; + rt_uint32_t timeout; + + timeout = RT_UTEST_WDT_TIMEOUT_SEC; + result = rt_device_control(wdt_tc_device, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &timeout); + uassert_int_equal(result, RT_EOK); + if (result != RT_EOK) + { + return; + } + + result = rt_device_control(wdt_tc_device, RT_DEVICE_CTRL_WDT_START, RT_NULL); + uassert_int_equal(result, RT_EOK); + if (result != RT_EOK) + { + return; + } + + result = rt_device_control(wdt_tc_device, RT_DEVICE_CTRL_WDT_KEEPALIVE, RT_NULL); + uassert_int_equal(result, RT_EOK); + + result = rt_device_control(wdt_tc_device, RT_DEVICE_CTRL_WDT_STOP, RT_NULL); + uassert_int_equal(result, RT_EOK); + if (result != RT_EOK) + { + LOG_E("WDT STOP failed; board may reset when timeout expires"); + } +} +#endif /* RT_UTEST_WDT_START */ + +static rt_err_t utest_tc_init(void) +{ + rt_err_t result; + rt_device_t wdt_device; + + wdt_tc_device = RT_NULL; + wdt_tc_device_opened = RT_FALSE; + + wdt_device = rt_device_find(RT_UTEST_WDT_DEVICE_NAME); + if (wdt_device == RT_NULL) + { + LOG_E("Watchdog device %s is not registered", RT_UTEST_WDT_DEVICE_NAME); + return -RT_ERROR; + } + if (wdt_device->type != RT_Device_Class_WDT) + { + LOG_E("Device %s is not a watchdog device", RT_UTEST_WDT_DEVICE_NAME); + return -RT_ERROR; + } + + result = rt_device_open(wdt_device, RT_DEVICE_OFLAG_RDWR); + if (result != RT_EOK) + { + return result; + } + + wdt_tc_device = wdt_device; + wdt_tc_device_opened = RT_TRUE; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + rt_err_t result; + + result = RT_EOK; + if (wdt_tc_device_opened) + { + result = rt_device_close(wdt_tc_device); + wdt_tc_device = RT_NULL; + wdt_tc_device_opened = RT_FALSE; + } + + return result; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(wdt_timeout_set_get_test); +#ifdef RT_UTEST_WDT_START + UTEST_UNIT_RUN(wdt_start_keepalive_stop_test); +#endif +} + +UTEST_TC_EXPORT(testcase, + "components.drivers.watchdog.smoke", + utest_tc_init, + utest_tc_cleanup, + WDT_TC_SUITE_TIMEOUT); + +#endif /* RT_UTEST_WDT */ diff --git a/components/utilities/utest/Kconfig b/components/utilities/utest/Kconfig index 10781a43315b..d6daaf14295c 100644 --- a/components/utilities/utest/Kconfig +++ b/components/utilities/utest/Kconfig @@ -22,6 +22,7 @@ menu "RT-Thread Utestcases" rsource "../../../components/drivers/serial/utest/Kconfig" rsource "../../../components/drivers/smp_call/utest/Kconfig" rsource "../../../components/drivers/spi/utest/Kconfig" + rsource "../../../components/drivers/watchdog/utest/Kconfig" endmenu rsource "../../../components/dfs/utest/Kconfig"