This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 3959bceea4a752a9c6226c91b70f552887897b22 Author: Daniel P. Carvalho <[email protected]> AuthorDate: Fri Oct 23 00:42:50 2026 -0300 drivers/timers: add a watchdog implemented by a wdog timer. Add CONFIG_WATCHDOG_WDOG and watchdog_wdog_initialize(), a watchdog lower half built on a wdog timer, like timer_wdog.c does for the timer interface. It is meant for the platforms with no watchdog hardware, such as the simulator: when it is not fed in time it panics, reboots or powers off the board, as selected by CONFIG_WATCHDOG_WDOG_ACTION. It can not detect a system where the tick stopped. Register it from sim_bringup() when CONFIG_WATCHDOG_WDOG is set. The simulator cannot reset, so the new sim:watchdog configuration powers it off with status 77 when the watchdog expires, and runs the wdog example. Document it. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Daniel P. Carvalho <[email protected]> --- .../platforms/sim/sim/boards/sim/index.rst | 12 ++ boards/sim/sim/sim/configs/watchdog/defconfig | 88 +++++++++ boards/sim/sim/sim/src/sim_bringup.c | 12 ++ drivers/timers/CMakeLists.txt | 3 + drivers/timers/Kconfig | 43 +++++ drivers/timers/Make.defs | 3 + drivers/timers/watchdog_wdog.c | 211 +++++++++++++++++++++ include/nuttx/timers/watchdog_wdog.h | 75 ++++++++ 8 files changed, 447 insertions(+) diff --git a/Documentation/platforms/sim/sim/boards/sim/index.rst b/Documentation/platforms/sim/sim/boards/sim/index.rst index ff1de014568..f23d8c482c3 100644 --- a/Documentation/platforms/sim/sim/boards/sim/index.rst +++ b/Documentation/platforms/sim/sim/boards/sim/index.rst @@ -1815,6 +1815,18 @@ since there are some compatibility issues. By default SIM will be blocked at startup to wait client connection, if a client connected, then the fb example will launch. +watchdog +-------- + +This configuration enables ``CONFIG_WATCHDOG_WDOG``, a watchdog timer +registered at ``CONFIG_WATCHDOG_DEVPATH``. The simulator cannot reset itself, +so the watchdog powers it off when it expires, with status 77 +(``CONFIG_WATCHDOG_WDOG_STATUS``). It enables the ``wdog`` example: it feeds +the watchdog for a while, stops, and the simulator exits with that status when +the timeout expires:: + + nsh> wdog + vpnkit ------ diff --git a/boards/sim/sim/sim/configs/watchdog/defconfig b/boards/sim/sim/sim/configs/watchdog/defconfig new file mode 100644 index 00000000000..f628ba79068 --- /dev/null +++ b/boards/sim/sim/sim/configs/watchdog/defconfig @@ -0,0 +1,88 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="sim" +CONFIG_ARCH_BOARD="sim" +CONFIG_ARCH_BOARD_SIM=y +CONFIG_ARCH_CHIP="sim" +CONFIG_ARCH_SIM=y +CONFIG_BOARDCTL_APP_SYMTAB=y +CONFIG_BOARDCTL_POWEROFF=y +CONFIG_BOARD_LOOPSPERMSEC=0 +CONFIG_BOOT_RUNFROMEXTSRAM=y +CONFIG_BUILTIN=y +CONFIG_COVERAGE_ALL=y +CONFIG_COVERAGE_TOOLCHAIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_ASSERTIONS_EXPRESSION=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEV_GPIO=y +CONFIG_DEV_LOOP=y +CONFIG_ETC_FATDEVNO=2 +CONFIG_ETC_ROMFS=y +CONFIG_ETC_ROMFSDEVNO=1 +CONFIG_EXAMPLES_GPIO=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_WATCHDOG=y +CONFIG_EXPERIMENTAL=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FS_BINFS=y +CONFIG_FS_FAT=y +CONFIG_FS_HOSTFS=y +CONFIG_FS_LINKS=y +CONFIG_FS_PROCFS=y +CONFIG_FS_RAMMAP=y +CONFIG_FS_ROMFS=y +CONFIG_GPIO_LOWER_HALF=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=4096 +CONFIG_INIT_ENTRYPOINT="init_main" +CONFIG_IOEXPANDER=y +CONFIG_IOEXPANDER_DUMMY=y +CONFIG_LIBC_ENVPATH=y +CONFIG_LIBC_EXECFUNCS=y +CONFIG_LIBC_LOCALE=y +CONFIG_LIBC_LOCALE_CATALOG=y +CONFIG_LIBC_LOCALE_GETTEXT=y +CONFIG_LIBC_MAX_EXITFUNS=1 +CONFIG_LIBC_NUMBERED_ARGS=y +CONFIG_NDEBUG=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILE_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_PATH_INITIAL="/bin" +CONFIG_PIPES=y +CONFIG_PSEUDOFS_ATTRIBUTES=y +CONFIG_PSEUDOFS_FILE=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_EDIT_EMACS=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_RTC=y +CONFIG_RTC_ARCH=y +CONFIG_RTC_DRIVER=y +CONFIG_SCHED_BACKTRACE=y +CONFIG_SCHED_CHILD_STATUS=y +CONFIG_SCHED_EVENTS=y +CONFIG_SCHED_HAVE_PARENT=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SIM_HOSTFS=y +CONFIG_SIM_WALLTIME_SIGNAL=y +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2008 +CONFIG_SYSTEM_DUMPSTACK=y +CONFIG_SYSTEM_GCOV=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_NXINIT=y +CONFIG_TASK_NAME_SIZE=15 +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_WDOG=y +CONFIG_WATCHDOG_WDOG_POWEROFF=y +CONFIG_WATCHDOG_WDOG_STATUS=77 diff --git a/boards/sim/sim/sim/src/sim_bringup.c b/boards/sim/sim/sim/src/sim_bringup.c index 9dc6bcf21d0..c47f9646a8c 100644 --- a/boards/sim/sim/sim/src/sim_bringup.c +++ b/boards/sim/sim/sim/src/sim_bringup.c @@ -74,6 +74,10 @@ #include <nuttx/timers/timer_wdog.h> #endif +#ifdef CONFIG_WATCHDOG_WDOG +#include <nuttx/timers/watchdog_wdog.h> +#endif + #include "sim_internal.h" #include "sim.h" @@ -599,6 +603,14 @@ int sim_bringup(void) } #endif +#ifdef CONFIG_WATCHDOG_WDOG + ret = watchdog_wdog_initialize(CONFIG_WATCHDOG_DEVPATH); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: watchdog_wdog_initialize failed: %d\n", ret); + } +#endif + #ifdef CONFIG_TIMER_WDOG ret = timer_wdog_initialize(0); if (ret < 0) diff --git a/drivers/timers/CMakeLists.txt b/drivers/timers/CMakeLists.txt index f819a283336..5aa04fd5c36 100644 --- a/drivers/timers/CMakeLists.txt +++ b/drivers/timers/CMakeLists.txt @@ -24,6 +24,9 @@ set(SRCS) if(CONFIG_WATCHDOG) list(APPEND SRCS watchdog.c) + if(CONFIG_WATCHDOG_WDOG) + list(APPEND SRCS watchdog_wdog.c) + endif() endif() if(CONFIG_TIMER) diff --git a/drivers/timers/Kconfig b/drivers/timers/Kconfig index f1c518d9313..2cf30db1bec 100644 --- a/drivers/timers/Kconfig +++ b/drivers/timers/Kconfig @@ -480,6 +480,49 @@ menuconfig WATCHDOG if WATCHDOG +config WATCHDOG_WDOG + bool "Watchdog implemented by wdog timer" + default n + depends on !WATCHDOG_AUTOMONITOR_BY_ONESHOT && !WATCHDOG_AUTOMONITOR_BY_TIMER + ---help--- + Build a watchdog timer on top of the wdog timers, for the platforms + that have no watchdog hardware, e.g. the simulator. It cannot detect + a system where the tick stopped. Not to be confused with + WATCHDOG_AUTOMONITOR_BY_WDOG, where a wdog feeds a real watchdog. It + is not available with the oneshot and timer auto-monitors, which + change the watchdog_register() prototype. Call + watchdog_wdog_initialize() from the board to register it. + +if WATCHDOG_WDOG + +config WATCHDOG_WDOG_TIMEOUT + int "Initial timeout (millisecond)" + default 5000 + +choice WATCHDOG_WDOG_ACTION + prompt "Action when the watchdog expires" + default WATCHDOG_WDOG_PANIC + +config WATCHDOG_WDOG_PANIC + bool "Panic" + +config WATCHDOG_WDOG_REBOOT + bool "Reboot" + depends on BOARDCTL_RESET + +config WATCHDOG_WDOG_POWEROFF + bool "Power off" + depends on BOARDCTL_POWEROFF + +endchoice # WATCHDOG_WDOG_ACTION + +config WATCHDOG_WDOG_STATUS + int "Status passed to the board when it reboots or powers off" + default 0 + depends on WATCHDOG_WDOG_REBOOT || WATCHDOG_WDOG_POWEROFF + +endif # WATCHDOG_WDOG + config WATCHDOG_DEVPATH string "Watchdog Device Path" default "/dev/watchdog0" diff --git a/drivers/timers/Make.defs b/drivers/timers/Make.defs index 1b0bf427fb8..3c48a32f2e1 100644 --- a/drivers/timers/Make.defs +++ b/drivers/timers/Make.defs @@ -24,6 +24,9 @@ ifeq ($(CONFIG_WATCHDOG),y) CSRCS += watchdog.c + ifeq ($(CONFIG_WATCHDOG_WDOG),y) + CSRCS += watchdog_wdog.c + endif TMRDEPPATH = --dep-path timers TMRVPATH = :timers endif diff --git a/drivers/timers/watchdog_wdog.c b/drivers/timers/watchdog_wdog.c new file mode 100644 index 00000000000..c2345507db1 --- /dev/null +++ b/drivers/timers/watchdog_wdog.c @@ -0,0 +1,211 @@ +/**************************************************************************** + * drivers/timers/watchdog_wdog.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <assert.h> +#include <errno.h> +#include <stdint.h> +#include <stdbool.h> + +#include <nuttx/board.h> +#include <nuttx/clock.h> +#include <nuttx/debug.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wdog.h> +#include <nuttx/timers/watchdog.h> +#include <nuttx/timers/watchdog_wdog.h> + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct watchdog_wdog_s +{ + struct watchdog_lowerhalf_s lower; /* Must be first */ + struct wdog_s wdog; /* The timer that expires */ + uint32_t timeout; /* Timeout in milliseconds */ + bool started; /* Is the watchdog running */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int watchdog_wdog_start(FAR struct watchdog_lowerhalf_s *lower); +static int watchdog_wdog_stop(FAR struct watchdog_lowerhalf_s *lower); +static int watchdog_wdog_keepalive(FAR struct watchdog_lowerhalf_s *lower); +static int watchdog_wdog_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status); +static int watchdog_wdog_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct watchdog_ops_s g_watchdog_wdog_ops = +{ + .start = watchdog_wdog_start, + .stop = watchdog_wdog_stop, + .keepalive = watchdog_wdog_keepalive, + .getstatus = watchdog_wdog_getstatus, + .settimeout = watchdog_wdog_settimeout, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: watchdog_wdog_expire + * + * Description: + * The wdog handler: the watchdog was not fed in time. + * + ****************************************************************************/ + +static void watchdog_wdog_expire(wdparm_t arg) +{ + _alert("Watchdog expired\n"); + +#if defined(CONFIG_WATCHDOG_WDOG_REBOOT) + board_reset(CONFIG_WATCHDOG_WDOG_STATUS); +#elif defined(CONFIG_WATCHDOG_WDOG_POWEROFF) + board_power_off(CONFIG_WATCHDOG_WDOG_STATUS); +#else + PANIC(); +#endif +} + +/**************************************************************************** + * Name: watchdog_wdog_arm + ****************************************************************************/ + +static int watchdog_wdog_arm(FAR struct watchdog_wdog_s *priv) +{ + return wd_start(&priv->wdog, MSEC2TICK(priv->timeout), + watchdog_wdog_expire, (wdparm_t)priv); +} + +static int watchdog_wdog_start(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct watchdog_wdog_s *priv = (FAR struct watchdog_wdog_s *)lower; + int ret; + + ret = watchdog_wdog_arm(priv); + if (ret >= 0) + { + priv->started = true; + } + + return ret; +} + +static int watchdog_wdog_stop(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct watchdog_wdog_s *priv = (FAR struct watchdog_wdog_s *)lower; + + priv->started = false; + wd_cancel(&priv->wdog); + return OK; +} + +static int watchdog_wdog_keepalive(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct watchdog_wdog_s *priv = (FAR struct watchdog_wdog_s *)lower; + + return priv->started ? watchdog_wdog_arm(priv) : OK; +} + +static int watchdog_wdog_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status) +{ + FAR struct watchdog_wdog_s *priv = (FAR struct watchdog_wdog_s *)lower; + + status->flags = priv->started ? WDFLAGS_ACTIVE | WDFLAGS_RESET : 0; + status->timeout = priv->timeout; + status->timeleft = 0; + + if (priv->started) + { + /* wd_start() adds a tick, do not report more than the timeout */ + + status->timeleft = TICK2MSEC(wd_gettime(&priv->wdog)); + if (status->timeleft > priv->timeout) + { + status->timeleft = priv->timeout; + } + } + + return OK; +} + +static int watchdog_wdog_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout) +{ + FAR struct watchdog_wdog_s *priv = (FAR struct watchdog_wdog_s *)lower; + + if (timeout == 0) + { + return -EINVAL; + } + + priv->timeout = timeout; + return watchdog_wdog_keepalive(lower); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: watchdog_wdog_initialize + ****************************************************************************/ + +int watchdog_wdog_initialize(FAR const char *path) +{ + FAR struct watchdog_wdog_s *priv; + + DEBUGASSERT(path != NULL); + + priv = kmm_zalloc(sizeof(struct watchdog_wdog_s)); + if (priv == NULL) + { + return -ENOMEM; + } + + priv->lower.ops = &g_watchdog_wdog_ops; + priv->timeout = CONFIG_WATCHDOG_WDOG_TIMEOUT; + + if (watchdog_register(path, &priv->lower) == NULL) + { + kmm_free(priv); + return -EEXIST; + } + + return OK; +} diff --git a/include/nuttx/timers/watchdog_wdog.h b/include/nuttx/timers/watchdog_wdog.h new file mode 100644 index 00000000000..a5b3779a70f --- /dev/null +++ b/include/nuttx/timers/watchdog_wdog.h @@ -0,0 +1,75 @@ +/**************************************************************************** + * include/nuttx/timers/watchdog_wdog.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_TIMERS_WATCHDOG_WDOG_H +#define __INCLUDE_NUTTX_TIMERS_WATCHDOG_WDOG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#ifdef CONFIG_WATCHDOG_WDOG +/**************************************************************************** + * Name: watchdog_wdog_initialize + * + * Description: + * Register a watchdog timer implemented by a wdog timer, for the + * platforms that have no watchdog hardware (e.g. the simulator). Like any + * watchdog it expires if it is not fed within its timeout, but since + * there is no hardware to reset the system it does what + * CONFIG_WATCHDOG_WDOG_ACTION selects (panic, reboot or power off). It + * does not fire if the system tick stops. + * + * Input Parameters: + * path - The device path, e.g. CONFIG_WATCHDOG_DEVPATH. The initial + * timeout is CONFIG_WATCHDOG_WDOG_TIMEOUT. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int watchdog_wdog_initialize(FAR const char *path); +#endif + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_TIMERS_WATCHDOG_WDOG_H */
