From c3bc7180b0a3a1bc28a9d5af67194972ff040c58 Mon Sep 17 00:00:00 2001 From: Jakub Rzeszutko Date: Tue, 2 Oct 2018 14:47:20 +0200 Subject: [PATCH] subsys: shell: add dummy backend to simplify commands testing Added dummy backend which can be enabled with Kconfig. By default it is disabled because it needs the same amount of memory as other phisical backends. It shall be use only for commands testing purposes. Improved shell_execute_cmd function, now it clears command context before new command will be executed. Signed-off-by: Jakub Rzeszutko --- include/shell/shell.h | 4 +- include/shell/shell_dummy.h | 44 +++++++++++++++ include/shell/shell_uart.h | 10 ++++ subsys/shell/CMakeLists.txt | 7 ++- subsys/shell/Kconfig.backends | 7 +++ subsys/shell/shell.c | 12 +++- subsys/shell/shell_dummy.c | 102 ++++++++++++++++++++++++++++++++++ subsys/shell/shell_uart.c | 5 ++ 8 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 include/shell/shell_dummy.h create mode 100644 subsys/shell/shell_dummy.c diff --git a/include/shell/shell.h b/include/shell/shell.h index 186fe3a75dd..2025ca2ef4e 100644 --- a/include/shell/shell.h +++ b/include/shell/shell.h @@ -600,7 +600,9 @@ void shell_print_stream(const void *user_ctx, const char *data, * Note: This by no means makes any of the commands a stable interface, so * this function should only be used for debugging/diagnostic. * - * @param[in] shell Pointer to the shell instance. + * @param[in] shell Pointer to the shell instance. It can be NULL when + * the :option:`CONFIG_SHELL_BACKEND_DUMMY` option is + * enabled. * @param[in] cmd Command to be executed. * * @returns Result of the execution diff --git a/include/shell/shell_dummy.h b/include/shell/shell_dummy.h new file mode 100644 index 00000000000..c39eeb88fca --- /dev/null +++ b/include/shell/shell_dummy.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SHELL_DUMMY_H__ +#define SHELL_DUMMY_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct shell_transport_api shell_dummy_transport_api; + +struct shell_dummy { + bool initialized; +}; + +#define SHELL_DUMMY_DEFINE(_name) \ + static struct shell_dummy _name##_shell_dummy; \ + struct shell_transport _name = { \ + .api = &shell_dummy_transport_api, \ + .ctx = (struct shell_dummy *)&_name##_shell_dummy \ + } + +/** + * @brief This function shall not be used directly. It provides pointer to shell + * dummy backend instance. + * + * Function returns pointer to the shell dummy instance. This instance can be + * next used with shell_execute_cmd function in order to test commands behavior. + * + * @returns Pointer to the shell instance. + */ +const struct shell *shell_backend_dummy_get_ptr(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SHELL_DUMMY_H__ */ diff --git a/include/shell/shell_uart.h b/include/shell/shell_uart.h index a1e4b1ba168..17f2d311543 100644 --- a/include/shell/shell_uart.h +++ b/include/shell/shell_uart.h @@ -31,6 +31,16 @@ struct shell_uart { .ctx = (struct shell_uart *)&_name##_shell_uart \ } +/** + * @brief This function provides pointer to shell uart backend instance. + * + * Function returns pointer to the shell uart instance. This instance can be + * next used with shell_execute_cmd function in order to test commands behavior. + * + * @returns Pointer to the shell instance. + */ +const struct shell *shell_backend_uart_get_ptr(void); + #ifdef __cplusplus } #endif diff --git a/subsys/shell/CMakeLists.txt b/subsys/shell/CMakeLists.txt index f364c5854ee..f6b73076411 100644 --- a/subsys/shell/CMakeLists.txt +++ b/subsys/shell/CMakeLists.txt @@ -21,7 +21,12 @@ zephyr_sources_ifdef( zephyr_sources_ifdef( CONFIG_SHELL_BACKEND_SERIAL shell_uart.c - ) +) + +zephyr_sources_ifdef( + CONFIG_SHELL_BACKEND_DUMMY + shell_dummy.c +) zephyr_sources_ifdef( CONFIG_SHELL_CMDS diff --git a/subsys/shell/Kconfig.backends b/subsys/shell/Kconfig.backends index 7ef1b9296b5..982cf762bd2 100644 --- a/subsys/shell/Kconfig.backends +++ b/subsys/shell/Kconfig.backends @@ -21,5 +21,12 @@ config SHELL_BACKEND_SERIAL help Enable serial backends. +config SHELL_BACKEND_DUMMY + bool "Enable dummy backend." + select SERIAL + help + Enable dummy backend which can be used to test commands with no need + for physical transport interface. + endif # SHELL_BACKENDS diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index 535b41cf223..20a47fe399f 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "shell_utils.h" #include "shell_ops.h" #include "shell_wildcard.h" @@ -1748,7 +1749,7 @@ int shell_execute_cmd(const struct shell *shell, const char *cmd) { u16_t cmd_len = shell_strlen(cmd); - if ((cmd == NULL) || (shell == NULL)) { + if (cmd == NULL) { return -ENOEXEC; } @@ -1756,8 +1757,17 @@ int shell_execute_cmd(const struct shell *shell, const char *cmd) return -ENOEXEC; } + if (shell == NULL) { +#if CONFIG_SHELL_BACKEND_DUMMY + shell = shell_backend_dummy_get_ptr(); +#else + return -EINVAL; +#endif + } + strcpy(shell->ctx->cmd_buff, cmd); shell->ctx->cmd_buff_len = cmd_len; + shell->ctx->cmd_buff_pos = cmd_len; return shell_execute(shell); } diff --git a/subsys/shell/shell_dummy.c b/subsys/shell/shell_dummy.c new file mode 100644 index 00000000000..313cc558e9c --- /dev/null +++ b/subsys/shell/shell_dummy.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +SHELL_DUMMY_DEFINE(shell_transport_dummy); +SHELL_DEFINE(dummy_shell, "~$ ", &shell_transport_dummy, 10, + SHELL_FLAG_OLF_CRLF); + +static int init(const struct shell_transport *transport, + const void *config, + shell_transport_handler_t evt_handler, + void *context) +{ + struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx; + + if (sh_dummy->initialized) { + return -EINVAL; + } + + sh_dummy->initialized = true; + + return 0; +} + +static int uninit(const struct shell_transport *transport) +{ + struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx; + + if (sh_dummy->initialized == false) { + return -EINVAL; + } + + sh_dummy->initialized = false; + + return 0; +} + +static int enable(const struct shell_transport *transport, bool blocking) +{ + struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx; + + if (sh_dummy->initialized == false) { + return -EINVAL; + } + + return 0; +} + +static int write(const struct shell_transport *transport, + const void *data, size_t length, size_t *cnt) +{ + struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx; + + if (!sh_dummy->initialized) { + *cnt = 0; + return -EINVAL; + } + + *cnt = length; + return 0; +} + +static int read(const struct shell_transport *transport, + void *data, size_t length, size_t *cnt) +{ + struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx; + + + if (sh_dummy->initialized) { + return -EINVAL; + } + + *cnt = 0; + + return 0; +} + +const struct shell_transport_api shell_dummy_transport_api = { + .init = init, + .uninit = uninit, + .enable = enable, + .write = write, + .read = read +}; + +static int enable_shell_dummy(struct device *arg) +{ + ARG_UNUSED(arg); + shell_init(&dummy_shell, NULL, true, true, LOG_LEVEL_INF); + return 0; +} +SYS_INIT(enable_shell_dummy, POST_KERNEL, 0); + +const struct shell *shell_backend_dummy_get_ptr(void) +{ + return &dummy_shell; +} diff --git a/subsys/shell/shell_uart.c b/subsys/shell/shell_uart.c index 50b25025aae..901b63fc87a 100644 --- a/subsys/shell/shell_uart.c +++ b/subsys/shell/shell_uart.c @@ -100,3 +100,8 @@ static int enable_shell_uart(struct device *arg) return 0; } SYS_INIT(enable_shell_uart, POST_KERNEL, 0); + +const struct shell *shell_backend_uart_get_ptr(void) +{ + return &uart_shell; +}