From e05aa6dc3e517d0e0045279fb4f2af02b8f76821 Mon Sep 17 00:00:00 2001 From: Krzysztof Chruscinski Date: Wed, 9 Jun 2021 10:53:53 +0200 Subject: [PATCH] shell: Add option to bypass shell Added api call that can set a callback that is called whenever data is received on shell. When callback is set, shell processing is bypassed and data is passed to that callback. Signed-off-by: Krzysztof Chruscinski --- include/shell/shell.h | 23 +++++++++++++++++++++++ subsys/shell/shell.c | 31 ++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/include/shell/shell.h b/include/shell/shell.h index 00221ad4bfa..ee3e7a8f722 100644 --- a/include/shell/shell.h +++ b/include/shell/shell.h @@ -501,6 +501,16 @@ typedef void (*shell_transport_handler_t)(enum shell_transport_evt evt, typedef void (*shell_uninit_cb_t)(const struct shell *shell, int res); +/** @brief Bypass callback. + * + * @param shell Shell instance. + * @param data Raw data from transport. + * @param len Data length. + */ +typedef void (*shell_bypass_cb_t)(const struct shell *shell, + uint8_t *data, + size_t len); + struct shell_transport; /** @@ -663,6 +673,9 @@ struct shell_ctx { */ shell_uninit_cb_t uninit_cb; + /*!< When bypass is set, all incoming data is passed to the callback. */ + shell_bypass_cb_t bypass; + #if defined CONFIG_SHELL_GETOPT /*!< getopt context for a shell backend. */ struct getopt_state getopt_state; @@ -1044,6 +1057,16 @@ int shell_execute_cmd(const struct shell *shell, const char *cmd); */ int shell_set_root_cmd(const char *cmd); +/** @brief Set bypass callback. + * + * Bypass callback is called whenever data is received. Shell is bypassed and + * data is passed directly to the callback. Use null to disable bypass functionality. + * + * @param[in] shell Pointer to the shell instance. + * @param[in] bypass Bypass callback or null to disable. + */ +void shell_set_bypass(const struct shell *shell, shell_bypass_cb_t bypass); + /** * @brief Allow application to control text insert mode. * Value is modified atomically and the previous value is returned. diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index c71f54e6844..5ddf137ca12 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -88,7 +88,7 @@ static inline void state_set(const struct shell *shell, enum shell_state state) { shell->ctx->state = state; - if (state == SHELL_STATE_ACTIVE) { + if (state == SHELL_STATE_ACTIVE && !shell->ctx->bypass) { cmd_buffer_clear(shell); if (z_flag_print_noinit_get(shell)) { z_shell_fprintf(shell, SHELL_WARNING, "%s", @@ -940,6 +940,26 @@ static void state_collect(const struct shell *shell) char data; while (true) { + shell_bypass_cb_t bypass = shell->ctx->bypass; + + if (bypass) { + uint8_t buf[16]; + + (void)shell->iface->api->read(shell->iface, buf, + sizeof(buf), &count); + if (count) { + bypass(shell, buf, count); + /* Check if bypass mode ended. */ + if (!(volatile shell_bypass_cb_t *)shell->ctx->bypass) { + state_set(shell, SHELL_STATE_ACTIVE); + } else { + continue; + } + } + + return; + } + (void)shell->iface->api->read(shell->iface, &data, sizeof(data), &count); if (count == 0) { @@ -1447,11 +1467,11 @@ void shell_vfprintf(const struct shell *shell, enum shell_vt100_color color, } k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER); - if (!z_flag_cmd_ctx_get(shell)) { + if (!z_flag_cmd_ctx_get(shell) && !shell->ctx->bypass) { z_shell_cmd_line_erase(shell); } z_shell_vfprintf(shell, color, fmt, args); - if (!z_flag_cmd_ctx_get(shell)) { + if (!z_flag_cmd_ctx_get(shell) && !shell->ctx->bypass) { z_shell_print_prompt_and_cmd(shell); } z_transport_buffer_flush(shell); @@ -1627,6 +1647,11 @@ int shell_mode_delete_set(const struct shell *shell, bool val) return (int)z_flag_mode_delete_set(shell, val); } +void shell_set_bypass(const struct shell *sh, shell_bypass_cb_t bypass) +{ + sh->ctx->bypass = bypass; +} + static int cmd_help(const struct shell *shell, size_t argc, char **argv) { ARG_UNUSED(argc);