diff --git a/include/zephyr/shell/shell.h b/include/zephyr/shell/shell.h index 5115e35339be8..abe0a4f866bfb 100644 --- a/include/zephyr/shell/shell.h +++ b/include/zephyr/shell/shell.h @@ -129,7 +129,44 @@ struct shell_static_args { * start with this text. Pass null if no prefix match is required. */ const struct device *shell_device_lookup(size_t idx, - const char *prefix); + const char *prefix); + +/** + * @brief Get by index a device that matches . + * + * This can be used, for example, to identify I2C_1 as the second I2C + * device. + * + * Devices that failed to initialize - or deferred to be - are included + * from the candidates for a match, minus the ones who do not have + * a non-empty name. + * + * @param idx the device number starting from zero. + * + * @param prefix optional name prefix used to restrict candidate + * devices. Indexing is done relative to devices with names that + * start with this text. Pass null if no prefix match is required. + */ +const struct device *shell_device_lookup_all(size_t idx, + const char *prefix); + +/** + * @brief Get by index a non-initialized device that matches . + * + * This can be used, for example, to identify I2C_1 as the second I2C + * device. + * + * Devices that initialized successfully or do not have a non-empty name + * are excluded. + * + * @param idx the device number starting from zero. + * + * @param prefix optional name prefix used to restrict candidate + * devices. Indexing is done relative to devices with names that + * start with this text. Pass null if no prefix match is required. + */ +const struct device *shell_device_lookup_non_ready(size_t idx, + const char *prefix); /** * @brief Filter callback type, for use with shell_device_lookup_filter @@ -181,6 +218,23 @@ const struct device *shell_device_filter(size_t idx, */ const struct device *shell_device_get_binding(const char *name); +/** + * @brief Get a @ref device reference from its @ref device.name field or label. + * + * This function iterates through the devices on the system. If a device with + * the given @p name field is found, this function returns a pointer to the + * device. + * + * If no device has the given @p name, this function returns `NULL`. + * + * @param name device name to search for. A null pointer, or a pointer to an + * empty string, will cause NULL to be returned. + * + * @return pointer to device structure with the given name; `NULL` if the device + * is not found. + */ +const struct device *shell_device_get_binding_all(const char *name); + /** * @brief Shell command handler prototype. * diff --git a/subsys/shell/modules/device_service.c b/subsys/shell/modules/device_service.c index 98f9fd1d420ae..6ce567f3faca7 100644 --- a/subsys/shell/modules/device_service.c +++ b/subsys/shell/modules/device_service.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2018 Nordic Semiconductor ASA * Copyright (c) 2016 Intel Corporation + * Copyright (C) 2025 Bang & Olufsen A/S, Denmark * * SPDX-License-Identifier: Apache-2.0 */ @@ -117,6 +118,33 @@ static int cmd_device_list(const struct shell *sh, return 0; } +static int cmd_device_init(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + int ret; + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Device unknown (%s)", argv[1]); + return -ENODEV; + } + + if (device_is_ready(dev)) { + shell_info(sh, "Device %s is already initialized", argv[1]); + return 0; + } + + ret = device_init(dev); + if (ret != 0) { + shell_error(sh, "Device %s initalization failed with err=%d", + argv[1], ret); + } else { + shell_info(sh, "Device %s inialized successfully", argv[1]); + } + + return ret; +} + #ifdef CONFIG_PM_DEVICE_RUNTIME static int cmd_device_pm_toggle(const struct shell *sh, size_t argc, char **argv) @@ -156,10 +184,24 @@ static int cmd_device_pm_toggle(const struct shell *sh, #define PM_SHELL_CMD #endif /* CONFIG_PM_DEVICE_RUNTIME */ +static void device_name_get_non_ready(size_t idx, + struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup_non_ready(idx, NULL); + + entry->syntax = dev != NULL ? dev->name : NULL; + entry->handler = NULL; + entry->help = "device"; + entry->subcmd = NULL; +} +SHELL_DYNAMIC_CMD_CREATE(dsub_device_name_non_ready, device_name_get_non_ready); SHELL_STATIC_SUBCMD_SET_CREATE(sub_device, - SHELL_CMD(list, NULL, "List configured devices", cmd_device_list), + SHELL_CMD(list, &dsub_device_name_all, + "List configured devices", cmd_device_list), + SHELL_CMD_ARG(init, &dsub_device_name_non_ready, + "Manually initialize a device", cmd_device_init, 2, 0), PM_SHELL_CMD SHELL_SUBCMD_SET_END /* Array terminated. */ ); diff --git a/subsys/shell/shell_utils.c b/subsys/shell/shell_utils.c index c06e703501097..01b47f3f981c8 100644 --- a/subsys/shell/shell_utils.c +++ b/subsys/shell/shell_utils.c @@ -496,9 +496,16 @@ void z_shell_cmd_trim(const struct shell *sh) sh->ctx->cmd_buff_pos = sh->ctx->cmd_buff_len; } +enum shell_device_status { + SHELL_DEVICE_STATUS_ANY, + SHELL_DEVICE_STATUS_READY, + SHELL_DEVICE_STATUS_NON_READY +}; + static const struct device *shell_device_internal(size_t idx, const char *prefix, - shell_device_filter_t filter) + shell_device_filter_t filter, + enum shell_device_status status) { size_t match_idx = 0; const struct device *dev; @@ -506,7 +513,11 @@ static const struct device *shell_device_internal(size_t idx, const struct device *dev_end = dev + len; while (dev < dev_end) { - if (device_is_ready(dev) + if ((status == SHELL_DEVICE_STATUS_ANY + || (status == SHELL_DEVICE_STATUS_READY && + device_is_ready(dev)) + || (status == SHELL_DEVICE_STATUS_NON_READY && + !device_is_ready(dev))) && (dev->name != NULL) && (strlen(dev->name) != 0) && ((prefix == NULL) @@ -527,13 +538,29 @@ static const struct device *shell_device_internal(size_t idx, const struct device *shell_device_filter(size_t idx, shell_device_filter_t filter) { - return shell_device_internal(idx, NULL, filter); + return shell_device_internal(idx, NULL, filter, + SHELL_DEVICE_STATUS_READY); } const struct device *shell_device_lookup(size_t idx, const char *prefix) { - return shell_device_internal(idx, prefix, NULL); + return shell_device_internal(idx, prefix, NULL, + SHELL_DEVICE_STATUS_READY); +} + +const struct device *shell_device_lookup_all(size_t idx, + const char *prefix) +{ + return shell_device_internal(idx, prefix, NULL, + SHELL_DEVICE_STATUS_ANY); +} + +const struct device *shell_device_lookup_non_ready(size_t idx, + const char *prefix) +{ + return shell_device_internal(idx, prefix, NULL, + SHELL_DEVICE_STATUS_NON_READY); } const struct device *shell_device_get_binding(const char *name) @@ -547,6 +574,22 @@ const struct device *shell_device_get_binding(const char *name) return dev; } +const struct device *shell_device_get_binding_all(const char *name) +{ + const struct device *dev; + size_t len = z_device_get_all_static(&dev); + const struct device *dev_end = dev + len; + + for (; dev < dev_end; dev++) { + if ((dev->name != NULL) && + (strncmp(name, dev->name, strlen(name)) == 0)) { + return dev; + } + } + + return NULL; +} + long shell_strtol(const char *str, int base, int *err) { long val;