From b7648f89c460641b34dfd90101bf995d584e8c7e Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sun, 1 Sep 2024 17:35:19 +0200 Subject: [PATCH] drivers: comparator: add shell Add shell for comparator device drivers. Signed-off-by: Bjarki Arge Andreasen --- drivers/comparator/CMakeLists.txt | 1 + drivers/comparator/Kconfig | 1 + drivers/comparator/Kconfig.shell | 21 ++ drivers/comparator/comparator_shell.c | 279 ++++++++++++++++++++++++++ 4 files changed, 302 insertions(+) create mode 100644 drivers/comparator/Kconfig.shell create mode 100644 drivers/comparator/comparator_shell.c diff --git a/drivers/comparator/CMakeLists.txt b/drivers/comparator/CMakeLists.txt index b5fe633a333..f4378c76a77 100644 --- a/drivers/comparator/CMakeLists.txt +++ b/drivers/comparator/CMakeLists.txt @@ -9,3 +9,4 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE comparator_handlers.c) zephyr_library_sources_ifdef(CONFIG_COMPARATOR_MCUX_ACMP comparator_mcux_acmp.c) zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_COMP comparator_nrf_comp.c) zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_LPCOMP comparator_nrf_lpcomp.c) +zephyr_library_sources_ifdef(CONFIG_COMPARATOR_SHELL comparator_shell.c) diff --git a/drivers/comparator/Kconfig b/drivers/comparator/Kconfig index 871ee5d9ed6..f49ff182562 100644 --- a/drivers/comparator/Kconfig +++ b/drivers/comparator/Kconfig @@ -21,5 +21,6 @@ config COMPARATOR_INIT_PRIORITY rsource "Kconfig.mcux_acmp" rsource "Kconfig.nrf_comp" rsource "Kconfig.nrf_lpcomp" +rsource "Kconfig.shell" endif # COMPARATOR diff --git a/drivers/comparator/Kconfig.shell b/drivers/comparator/Kconfig.shell new file mode 100644 index 00000000000..de244619be3 --- /dev/null +++ b/drivers/comparator/Kconfig.shell @@ -0,0 +1,21 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config COMPARATOR_SHELL + bool "Comparator shell" + default y + depends on SHELL + help + Comparator device driver shell. + +if COMPARATOR_SHELL + +config COMPARATOR_SHELL_AWAIT_TRIGGER_DEFAULT_TIMEOUT + int "Default timeout for await_trigger command in seconds" + default 10 + +config COMPARATOR_SHELL_AWAIT_TRIGGER_MAX_TIMEOUT + int "Max timeout for await_trigger command in seconds" + default 60 + +endif # COMPARATOR_SHELL diff --git a/drivers/comparator/comparator_shell.c b/drivers/comparator/comparator_shell.c new file mode 100644 index 00000000000..2d747530871 --- /dev/null +++ b/drivers/comparator/comparator_shell.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#define AWAIT_TRIGGER_DEFAULT_TIMEOUT \ + CONFIG_COMPARATOR_SHELL_AWAIT_TRIGGER_DEFAULT_TIMEOUT + +#define AWAIT_TRIGGER_MAX_TIMEOUT \ + CONFIG_COMPARATOR_SHELL_AWAIT_TRIGGER_MAX_TIMEOUT + +/* Mapped 1-1 to enum comparator_trigger */ +static const char *const trigger_lookup[] = { + "NONE", + "RISING_EDGE", + "FALLING_EDGE", + "BOTH_EDGES", +}; + +static K_SEM_DEFINE(triggered_sem, 0, 1); + +static int get_device_from_str(const struct shell *sh, + const char *dev_str, + const struct device **dev) +{ + *dev = device_get_binding(dev_str); + + if (*dev == NULL) { + shell_error(sh, "%s not %s", dev_str, "found"); + return -ENODEV; + } + + if (!device_is_ready(*dev)) { + shell_error(sh, "%s not %s", dev_str, "ready"); + return -ENODEV; + } + + return 0; +} + +static int cmd_get_output(const struct shell *sh, size_t argc, char **argv) +{ + int ret; + const char *dev_str; + const struct device *dev; + + ARG_UNUSED(argc); + + dev_str = argv[1]; + ret = get_device_from_str(sh, dev_str, &dev); + if (ret < 0) { + return ret; + } + + ret = comparator_get_output(dev); + if (ret < 0) { + shell_error(sh, "failed to %s %s", "get", "output"); + return -EIO; + } + + shell_print(sh, "%i", ret); + return 0; +} + +static int get_trigger_from_str(const struct shell *sh, + const char *trigger_str, + enum comparator_trigger *trigger) +{ + ARRAY_FOR_EACH(trigger_lookup, i) { + if (strcmp(trigger_lookup[i], trigger_str) == 0) { + *trigger = (enum comparator_trigger)i; + return 0; + } + } + + shell_error(sh, "%s not %s", trigger_str, "valid"); + return -EINVAL; +} + +static int cmd_set_trigger(const struct shell *sh, size_t argc, char **argv) +{ + const char *dev_str; + const char *trigger_str; + int ret; + const struct device *dev; + enum comparator_trigger trigger; + + ARG_UNUSED(argc); + + dev_str = argv[1]; + ret = get_device_from_str(sh, dev_str, &dev); + if (ret < 0) { + return ret; + } + + trigger_str = argv[2]; + ret = get_trigger_from_str(sh, trigger_str, &trigger); + if (ret < 0) { + return ret; + } + + ret = comparator_set_trigger(dev, trigger); + if (ret < 0) { + shell_error(sh, "failed to %s %s", "set", "trigger"); + return -EIO; + } + + return 0; +} + +static int get_timeout_from_str(const struct shell *sh, + const char *timeout_str, + k_timeout_t *timeout) +{ + long seconds; + char *end; + + seconds = strtol(timeout_str, &end, 10); + if ((*end != '\0') || + (seconds < 1) || + (seconds > AWAIT_TRIGGER_MAX_TIMEOUT)) { + shell_error(sh, "%s not %s", timeout_str, "valid"); + return -EINVAL; + } + + *timeout = K_SECONDS(seconds); + return 0; +} + +static void trigger_cb(const struct device *dev, void *user_data) +{ + ARG_UNUSED(dev); + ARG_UNUSED(user_data); + + k_sem_give(&triggered_sem); +} + +static int cmd_await_trigger(const struct shell *sh, size_t argc, char **argv) +{ + const char *dev_str; + const char *timeout_str; + int ret; + const struct device *dev; + k_timeout_t timeout; + + dev_str = argv[1]; + ret = get_device_from_str(sh, dev_str, &dev); + if (ret < 0) { + return ret; + } + + if (argc == 3) { + timeout_str = argv[2]; + ret = get_timeout_from_str(sh, timeout_str, &timeout); + if (ret < 0) { + return ret; + } + } else { + timeout = K_SECONDS(AWAIT_TRIGGER_DEFAULT_TIMEOUT); + } + + k_sem_reset(&triggered_sem); + + ret = comparator_set_trigger_callback(dev, trigger_cb, NULL); + if (ret < 0) { + shell_error(sh, "failed to %s %s", "set", "trigger callback"); + return -EIO; + } + + ret = k_sem_take(&triggered_sem, timeout); + if (ret == 0) { + shell_print(sh, "triggered"); + } else if (ret == -EAGAIN) { + shell_print(sh, "timed out"); + } else { + shell_error(sh, "internal error"); + } + + ret = comparator_set_trigger_callback(dev, NULL, NULL); + if (ret < 0) { + shell_error(sh, "failed to %s %s", "clear", "trigger callback"); + return -EIO; + } + + return 0; +} + +static int cmd_trigger_is_pending(const struct shell *sh, size_t argc, char **argv) +{ + int ret; + const char *dev_str; + const struct device *dev; + + ARG_UNUSED(argc); + + dev_str = argv[1]; + ret = get_device_from_str(sh, dev_str, &dev); + if (ret < 0) { + return ret; + } + + ret = comparator_trigger_is_pending(dev); + if (ret < 0) { + shell_error(sh, "failed to %s %s", "get", "trigger status"); + return -EIO; + } + + shell_print(sh, "%i", ret); + return 0; +} + +static void dsub_set_trigger_lookup_1(size_t idx, struct shell_static_entry *entry) +{ + entry->syntax = (idx < ARRAY_SIZE(trigger_lookup)) ? trigger_lookup[idx] : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_set_trigger_1, dsub_set_trigger_lookup_1); + +static void dsub_set_trigger_lookup_0(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 = &dsub_set_trigger_1; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_set_trigger_0, dsub_set_trigger_lookup_0); + +static void dsub_device_lookup_0(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_0, dsub_device_lookup_0); + +#define GET_OUTPUT_HELP \ + ("comp get_output ") + +#define SET_TRIGGER_HELP \ + ("comp set_trigger ") + +#define AWAIT_TRIGGER_HELP \ + ("comp await_trigger [timeout] (default " \ + STRINGIFY(AWAIT_TRIGGER_DEFAULT_TIMEOUT) \ + "s, max " \ + STRINGIFY(AWAIT_TRIGGER_MAX_TIMEOUT) \ + "s)") + +#define TRIGGER_PENDING_HELP \ + ("comp trigger_is_pending ") + +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_comp, + SHELL_CMD_ARG(get_output, &dsub_device_0, GET_OUTPUT_HELP, cmd_get_output, 2, 0), + SHELL_CMD_ARG(set_trigger, &dsub_set_trigger_0, SET_TRIGGER_HELP, cmd_set_trigger, 3, 0), + SHELL_CMD_ARG(await_trigger, &dsub_device_0, AWAIT_TRIGGER_HELP, cmd_await_trigger, 2, 1), + SHELL_CMD_ARG(trigger_is_pending, &dsub_device_0, TRIGGER_PENDING_HELP, + cmd_trigger_is_pending, 2, 1), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_REGISTER(comp, &sub_comp, "Comparator device commands", NULL);