| /* |
| * Copyright (c) 2023 Centralp |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <stdlib.h> |
| #include <zephyr/shell/shell.h> |
| #include <zephyr/drivers/watchdog.h> |
| |
| #define WDT_SETUP_HELP \ |
| "Set up watchdog instance. Syntax:\n" \ |
| "<device>" |
| |
| #define WDT_DISABLE_HELP \ |
| "Disable watchdog instance. Syntax:\n" \ |
| "<device>" |
| |
| #define WDT_TIMEOUT_HELP \ |
| "Install a new timeout. Syntax:\n" \ |
| "<device> <none|cpu|soc> <min_ms> <max_ms>" |
| |
| #define WDT_FEED_HELP \ |
| "Feed specified watchdog timeout. Syntax:\n" \ |
| "<device> <channel_id>" |
| |
| static const char *const wdt_reset_name[] = { |
| [WDT_FLAG_RESET_NONE] = "none", |
| [WDT_FLAG_RESET_CPU_CORE] = "cpu", |
| [WDT_FLAG_RESET_SOC] = "soc", |
| }; |
| |
| struct args_index { |
| uint8_t device; |
| uint8_t reset; |
| uint8_t timeout_min; |
| uint8_t timeout_max; |
| uint8_t channel_id; |
| }; |
| |
| static const struct args_index args_indx = { |
| .device = 1, |
| .reset = 2, |
| .timeout_min = 3, |
| .timeout_max = 4, |
| .channel_id = 2, |
| }; |
| |
| static int parse_named_int(const char *name, const char *const keystack[], size_t count) |
| { |
| char *endptr; |
| int i; |
| |
| /* Attempt to parse name as a number first */ |
| i = strtoul(name, &endptr, 0); |
| |
| if (*endptr == '\0') { |
| return i; |
| } |
| |
| /* Name is not a number, look it up */ |
| for (i = 0; i < count; i++) { |
| if (strcmp(name, keystack[i]) == 0) { |
| return i; |
| } |
| } |
| |
| return -ENOTSUP; |
| } |
| |
| static int cmd_setup(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| const struct device *dev; |
| |
| dev = device_get_binding(argv[args_indx.device]); |
| if (!dev) { |
| shell_error(sh, "WDT device not found"); |
| return -ENODEV; |
| } |
| |
| return wdt_setup(dev, 0); |
| } |
| |
| static int cmd_disable(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| const struct device *dev; |
| |
| dev = device_get_binding(argv[args_indx.device]); |
| if (!dev) { |
| shell_error(sh, "WDT device not found"); |
| return -ENODEV; |
| } |
| |
| return wdt_disable(dev); |
| } |
| |
| static int cmd_timeout(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| const struct device *dev; |
| int flags; |
| int timeout_min; |
| int timeout_max; |
| struct wdt_timeout_cfg cfg; |
| int rc; |
| |
| dev = device_get_binding(argv[args_indx.device]); |
| if (!dev) { |
| shell_error(sh, "WDT device not found"); |
| return -ENODEV; |
| } |
| |
| flags = parse_named_int(argv[args_indx.reset], wdt_reset_name, ARRAY_SIZE(wdt_reset_name)); |
| if (flags < 0) { |
| shell_error(sh, "Reset mode '%s' unknown", argv[args_indx.reset]); |
| return -EINVAL; |
| } |
| |
| timeout_min = parse_named_int(argv[args_indx.timeout_min], NULL, 0); |
| if (timeout_min < 0) { |
| shell_error(sh, "Unable to convert '%s' to integer", argv[args_indx.timeout_min]); |
| return -EINVAL; |
| } |
| |
| timeout_max = parse_named_int(argv[args_indx.timeout_max], NULL, 0); |
| if (timeout_max < 0) { |
| shell_error(sh, "Unable to convert '%s' to integer", argv[args_indx.timeout_max]); |
| return -EINVAL; |
| } |
| |
| cfg.window.min = timeout_min; |
| cfg.window.max = timeout_max; |
| cfg.callback = NULL; |
| cfg.flags = flags; |
| |
| rc = wdt_install_timeout(dev, &cfg); |
| if (rc >= 0) { |
| shell_print(sh, "Channel ID = %d", rc); |
| } |
| |
| return rc; |
| } |
| |
| static int cmd_feed(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| const struct device *dev; |
| int channel_id; |
| |
| dev = device_get_binding(argv[args_indx.device]); |
| if (!dev) { |
| shell_error(sh, "WDT device not found"); |
| return -ENODEV; |
| } |
| |
| channel_id = parse_named_int(argv[args_indx.channel_id], NULL, 0); |
| if (channel_id < 0) { |
| shell_error(sh, "Unable to convert '%s' to integer", argv[args_indx.channel_id]); |
| return -EINVAL; |
| } |
| |
| return wdt_feed(dev, channel_id); |
| } |
| |
| /* Device name autocompletion support */ |
| static void device_name_get(size_t idx, struct shell_static_entry *entry) |
| { |
| const struct device *dev = shell_device_lookup(idx, NULL); |
| |
| entry->syntax = (dev != NULL) ? dev->name : NULL; |
| entry->handler = NULL; |
| entry->help = NULL; |
| entry->subcmd = NULL; |
| } |
| |
| SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); |
| |
| /* clang-format off */ |
| SHELL_STATIC_SUBCMD_SET_CREATE(sub_wdt, |
| SHELL_CMD_ARG(setup, &dsub_device_name, WDT_SETUP_HELP, cmd_setup, |
| 2, 0), |
| SHELL_CMD_ARG(disable, &dsub_device_name, WDT_DISABLE_HELP, cmd_disable, |
| 2, 0), |
| SHELL_CMD_ARG(timeout, &dsub_device_name, WDT_TIMEOUT_HELP, cmd_timeout, |
| 5, 0), |
| SHELL_CMD_ARG(feed, &dsub_device_name, WDT_FEED_HELP, cmd_feed, |
| 3, 0), |
| SHELL_SUBCMD_SET_END |
| ); |
| /* clang-format on */ |
| |
| SHELL_CMD_REGISTER(wdt, &sub_wdt, "Watchdog commands", NULL); |