From f17a9c93b46008e0ebe07e69d0657f1fc1a354ad Mon Sep 17 00:00:00 2001 From: Christoph Schramm Date: Fri, 19 Oct 2018 09:37:47 +0200 Subject: [PATCH] shell: Add a Segger RTT backend Fixes: #8394 Signed-off-by: Christoph Schramm --- include/shell/shell_rtt.h | 46 ++++++++++++++ subsys/shell/CMakeLists.txt | 5 ++ subsys/shell/Kconfig.backends | 6 ++ subsys/shell/shell_rtt.c | 116 ++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 include/shell/shell_rtt.h create mode 100644 subsys/shell/shell_rtt.c diff --git a/include/shell/shell_rtt.h b/include/shell/shell_rtt.h new file mode 100644 index 00000000000..cf749c0e029 --- /dev/null +++ b/include/shell/shell_rtt.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018 Makaio GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SHELL_RTT_H__ +#define SHELL_RTT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct shell_transport_api shell_rtt_transport_api; + +struct shell_rtt { + shell_transport_handler_t handler; + struct k_timer timer; + void *context; + u8_t rx[5]; + size_t rx_cnt; +}; + +#define SHELL_RTT_DEFINE(_name) \ + static struct shell_rtt _name##_shell_rtt; \ + struct shell_transport _name = { \ + .api = &shell_rtt_transport_api, \ + .ctx = (struct shell_rtt *)&_name##_shell_rtt \ + } + +/** + * @brief Function provides pointer to shell rtt backend instance. + * + * Function returns pointer to the shell rtt 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_rtt_get_ptr(void); +#ifdef __cplusplus +} +#endif + +#endif /* SHELL_RTT_H__ */ diff --git a/subsys/shell/CMakeLists.txt b/subsys/shell/CMakeLists.txt index f6b73076411..415c496a63f 100644 --- a/subsys/shell/CMakeLists.txt +++ b/subsys/shell/CMakeLists.txt @@ -28,6 +28,11 @@ zephyr_sources_ifdef( shell_dummy.c ) +zephyr_sources_ifdef( + CONFIG_SHELL_BACKEND_RTT + shell_rtt.c +) + zephyr_sources_ifdef( CONFIG_SHELL_CMDS shell_cmds.c diff --git a/subsys/shell/Kconfig.backends b/subsys/shell/Kconfig.backends index 29e8dbf78f7..c53711cf7ac 100644 --- a/subsys/shell/Kconfig.backends +++ b/subsys/shell/Kconfig.backends @@ -21,6 +21,12 @@ config SHELL_BACKEND_SERIAL help Enable serial backends. +config SHELL_BACKEND_RTT + bool "Enable RTT backend." + select RTT_CONSOLE + help + Enable RTT backend. + config SHELL_BACKEND_DUMMY bool "Enable dummy backend." help diff --git a/subsys/shell/shell_rtt.c b/subsys/shell/shell_rtt.c new file mode 100644 index 00000000000..64640c238cb --- /dev/null +++ b/subsys/shell/shell_rtt.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2018 Makaio GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +SHELL_RTT_DEFINE(shell_transport_rtt); +SHELL_DEFINE(rtt_shell, "rtt:~$ ", &shell_transport_rtt, 10, + SHELL_FLAG_OLF_CRLF); + +static struct k_thread rtt_rx_thread; +static K_THREAD_STACK_DEFINE(rtt_rx_stack, 1024); + +static void shell_rtt_rx_process(struct shell_rtt *sh_rtt) +{ + u32_t count; + + while (1) { + count = SEGGER_RTT_Read(0, sh_rtt->rx, sizeof(sh_rtt->rx)); + + if (count > 0) { + sh_rtt->rx_cnt = count; + sh_rtt->handler(SHELL_TRANSPORT_EVT_RX_RDY, sh_rtt->context); + } + + k_sleep(K_MSEC(10)); + } +} + + +static int init(const struct shell_transport *transport, + const void *config, + shell_transport_handler_t evt_handler, + void *context) +{ + struct shell_rtt *sh_rtt = (struct shell_rtt *)transport->ctx; + + sh_rtt->handler = evt_handler; + sh_rtt->context = context; + + k_thread_create(&rtt_rx_thread, rtt_rx_stack, + K_THREAD_STACK_SIZEOF(rtt_rx_stack), + (k_thread_entry_t)shell_rtt_rx_process, + sh_rtt, NULL, NULL, K_PRIO_COOP(8), + 0, K_NO_WAIT); + + return 0; +} + +static int uninit(const struct shell_transport *transport) +{ + return 0; +} + +static int enable(const struct shell_transport *transport, bool blocking) +{ + return 0; +} + +static int write(const struct shell_transport *transport, + const void *data, size_t length, size_t *cnt) +{ + struct shell_rtt *sh_rtt = (struct shell_rtt *)transport->ctx; + const u8_t *data8 = (const u8_t *)data; + + SEGGER_RTT_Write(0, data8, length); + *cnt = length; + + sh_rtt->handler(SHELL_TRANSPORT_EVT_TX_RDY, sh_rtt->context); + return 0; +} + +static int read(const struct shell_transport *transport, + void *data, size_t length, size_t *cnt) +{ + struct shell_rtt *sh_rtt = (struct shell_rtt *)transport->ctx; + + if (sh_rtt->rx_cnt) { + memcpy(data, sh_rtt->rx, sh_rtt->rx_cnt); + *cnt = sh_rtt->rx_cnt; + sh_rtt->rx_cnt = 0; + } else { + *cnt = 0; + } + + return 0; +} + +const struct shell_transport_api shell_rtt_transport_api = { + .init = init, + .uninit = uninit, + .enable = enable, + .write = write, + .read = read +}; + +static int enable_shell_rtt(struct device *arg) +{ + ARG_UNUSED(arg); + + shell_init(&rtt_shell, NULL, false, false, LOG_LEVEL_INF); + + return 0; +} + +/* Function is used for testing purposes */ +const struct shell *shell_backend_rtt_get_ptr(void) +{ + return &rtt_shell; +} +SYS_INIT(enable_shell_rtt, POST_KERNEL, 0);