diff --git a/CODEOWNERS b/CODEOWNERS index 894d9bf784..d1aa3b824e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -38,6 +38,7 @@ # Include /include/*.h @nrfconnect/ncs-bm /include/bluetooth/ @nrfconnect/ncs-bm +/include/shell/ @nrfconnect/ncs-bm /include/s115/ @nrfconnect/ncs-bm @nrfconnect/ncs-dragoon # Libraries @@ -58,11 +59,13 @@ /samples/boot/ @nrfconnect/ncs-pluto /samples/mcumgr/ @nrfconnect/ncs-pluto /samples/peripherals/ @nrfconnect/ncs-bm +/samples/shell/ @nrfconnect/ncs-bm # Samples documentation /samples/**/*.rst @nrfconnect/ncs-bm-doc /samples/bluetooth/**/*.rst @nrfconnect/ncs-bm-doc /samples/peripherals/**/*.rst @nrfconnect/ncs-bm-doc +/samples/shell/**/*.rst @nrfconnect/ncs-bm-doc # Scripts /scripts/ @nrfconnect/ncs-bm @@ -73,6 +76,7 @@ /subsys/bm_installs/ @nrfconnect/ncs-pluto /subsys/logging/ @nrfconnect/ncs-bm /subsys/mgmt/mcumgr/ @nrfconnect/ncs-pluto +/subsys/shell/ @nrfconnect/ncs-bm /subsys/softdevice/ @nrfconnect/ncs-bm @nrfconnect/ncs-dragoon /subsys/softdevice_handler/ @nrfconnect/ncs-bm /subsys/storage/flash_map/ @nrfconnect/ncs-pluto diff --git a/boards/nordic/bm_nrf54l15dk/include/board-config.h b/boards/nordic/bm_nrf54l15dk/include/board-config.h index 2ef67f752f..85aeb338e6 100644 --- a/boards/nordic/bm_nrf54l15dk/include/board-config.h +++ b/boards/nordic/bm_nrf54l15dk/include/board-config.h @@ -63,6 +63,23 @@ extern "C" { #define BOARD_CONSOLE_UARTE_PIN_CTS NRF_PIN_PORT_TO_PIN_NUMBER(7, 1) #endif +/* UART Shell configuration */ +#ifndef BOARD_SHELL_UARTE_INST +#define BOARD_SHELL_UARTE_INST 30 +#endif +#ifndef BOARD_SHELL_UARTE_PIN_TX +#define BOARD_SHELL_UARTE_PIN_TX NRF_PIN_PORT_TO_PIN_NUMBER(0, 0) +#endif +#ifndef BOARD_SHELL_UARTE_PIN_RX +#define BOARD_SHELL_UARTE_PIN_RX NRF_PIN_PORT_TO_PIN_NUMBER(1, 0) +#endif +#ifndef BOARD_SHELL_UARTE_PIN_RTS +#define BOARD_SHELL_UARTE_PIN_RTS NRF_PIN_PORT_TO_PIN_NUMBER(2, 0) +#endif +#ifndef BOARD_SHELL_UARTE_PIN_CTS +#define BOARD_SHELL_UARTE_PIN_CTS NRF_PIN_PORT_TO_PIN_NUMBER(3, 0) +#endif + /* Application UART configuration */ #ifndef BOARD_APP_UARTE_INST #define BOARD_APP_UARTE_INST 30 diff --git a/doc/nrf-bm/sample/shell.rst b/doc/nrf-bm/sample/shell.rst new file mode 100644 index 0000000000..9b5c93727e --- /dev/null +++ b/doc/nrf-bm/sample/shell.rst @@ -0,0 +1,13 @@ +.. _shell_samples: + +Shell samples +############# + +This section lists the available samples for shell support. + +.. toctree:: + :maxdepth: 1 + :caption: Subpages + :glob: + + ../samples/shell/bm_uarte/README.rst diff --git a/doc/nrf-bm/samples.rst b/doc/nrf-bm/samples.rst index 9319b69491..fffb62c088 100644 --- a/doc/nrf-bm/samples.rst +++ b/doc/nrf-bm/samples.rst @@ -15,3 +15,4 @@ All other samples and applications that are included in the distribution must be sample/ble sample/peripheral + sample/shell diff --git a/include/shell/backend_bm_uarte.h b/include/shell/backend_bm_uarte.h new file mode 100644 index 0000000000..49ad028355 --- /dev/null +++ b/include/shell/backend_bm_uarte.h @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* Get pointer to BM UARTE shell backend */ +const struct shell *shell_backend_bm_uarte_get_ptr(void); diff --git a/samples/shell/bm_uarte/CMakeLists.txt b/samples/shell/bm_uarte/CMakeLists.txt new file mode 100644 index 0000000000..e9f4111236 --- /dev/null +++ b/samples/shell/bm_uarte/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(shell_bm_uarte) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/shell/bm_uarte/README.rst b/samples/shell/bm_uarte/README.rst new file mode 100644 index 0000000000..aaeeb0416c --- /dev/null +++ b/samples/shell/bm_uarte/README.rst @@ -0,0 +1,59 @@ +.. _shell_bm_uarte_sample: + +UARTE shell sample +################## + +.. contents:: + :local: + :depth: 2 + +The Shell sample demonstrates how to initialize and use the shell subsystem with an nrfx UARTE based backend with |BMlong|. + +Requirements +************ + +The sample supports the following development kits: + +.. list-table:: + :header-rows: 1 + + * - Hardware platform + - PCA + - Board target + * - `nRF54L15 DK`_ + - PCA10156 + - bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice + * - `nRF54L15 DK`_ (emulating nRF54L10) + - PCA10156 + - bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice + * - `nRF54L15 DK`_ (emulating nRF54L05) + - PCA10156 + - bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice + +Overview +******** + +The sample initializes and starts an interactive shell, which can be terminated by using the ``terminate`` shell command. + +Building and running +******************** + +This sample can be found under :file:`samples/shell/bm_uarte/` in the |BMshort| folder structure. + +.. include:: /includes/create_sample.txt + +.. include:: /includes/configure_and_build_sample.txt + +.. include:: /includes/program_sample.txt + +Testing +======= + +You can test this sample by performing the following steps: + +1. Compile and program the application. +#. Observe that the ``bm-uarte:~$`` prompt is printed. +#. Type ``terminate`` and press Enter. +#. Observe that the ``goodbye`` message is printed. +#. Observe that the ``bm-uarte:~$`` prompt is printed. +#. Observe that shell is now unresponsive. diff --git a/samples/shell/bm_uarte/prj.conf b/samples/shell/bm_uarte/prj.conf new file mode 100644 index 0000000000..f1790a9fb3 --- /dev/null +++ b/samples/shell/bm_uarte/prj.conf @@ -0,0 +1,3 @@ +CONFIG_SHELL=y +CONFIG_SHELL_MINIMAL=y +CONFIG_SHELL_BACKEND_BM_UARTE=y diff --git a/samples/shell/bm_uarte/sample.yaml b/samples/shell/bm_uarte/sample.yaml new file mode 100644 index 0000000000..e5d6ff0399 --- /dev/null +++ b/samples/shell/bm_uarte/sample.yaml @@ -0,0 +1,15 @@ +sample: + name: Shell sample +tests: + sample.shell.bm_uarte: + sysbuild: true + build_only: true + integration_platforms: + - bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice + - bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice + - bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice + platform_allow: + - bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice + - bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice + - bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice + tags: ci_build diff --git a/samples/shell/bm_uarte/src/main.c b/samples/shell/bm_uarte/src/main.c new file mode 100644 index 0000000000..9f5bf0abbc --- /dev/null +++ b/samples/shell/bm_uarte/src/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include + +#include + +static atomic_t running = ATOMIC_INIT(1); + +static int sample_terminate_cmd(const struct shell *sh, size_t argc, char **argv) +{ + shell_print(sh, "goodbye"); + atomic_set(&running, 0); + return 0; +} + +SHELL_CMD_REGISTER(terminate, NULL, "terminate shell", sample_terminate_cmd); + +int main(void) +{ + const struct shell_backend_config_flags cfg_flags = SHELL_DEFAULT_BACKEND_CONFIG_FLAGS; + + shell_init(shell_backend_bm_uarte_get_ptr(), NULL, cfg_flags, false, 0); + shell_start(shell_backend_bm_uarte_get_ptr()); + printk("shell started\n"); + while (atomic_get(&running)) { + shell_process(shell_backend_bm_uarte_get_ptr()); + k_busy_wait(10000); + } + shell_uninit(shell_backend_bm_uarte_get_ptr(), NULL); + printk("shell terminated\n"); + return 0; +} diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 0602761c04..9beb326602 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(bluetooth) add_subdirectory(bm_installs) add_subdirectory(logging) +add_subdirectory(shell) add_subdirectory_ifdef(CONFIG_NCS_BM_MCUMGR mgmt/mcumgr) add_subdirectory_ifdef(CONFIG_NRF_SDH softdevice_handler) add_subdirectory_ifdef(CONFIG_SOFTDEVICE softdevice) diff --git a/subsys/Kconfig b/subsys/Kconfig index 3b1ff6e7b0..8d2fff6338 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -11,6 +11,7 @@ rsource "bluetooth/Kconfig" rsource "bm_installs/Kconfig" rsource "logging/Kconfig" rsource "mgmt/mcumgr/Kconfig" +rsource "shell/Kconfig" rsource "softdevice/Kconfig" rsource "softdevice_handler/Kconfig" rsource "storage/flash_map/Kconfig" diff --git a/subsys/shell/CMakeLists.txt b/subsys/shell/CMakeLists.txt new file mode 100644 index 0000000000..ca010f312d --- /dev/null +++ b/subsys/shell/CMakeLists.txt @@ -0,0 +1,7 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +add_subdirectory(backends) diff --git a/subsys/shell/Kconfig b/subsys/shell/Kconfig new file mode 100644 index 0000000000..39b7dc010d --- /dev/null +++ b/subsys/shell/Kconfig @@ -0,0 +1,10 @@ +# +# Copyright (c) 2025 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +menu "Shell" + +rsource "backends/Kconfig" + +endmenu diff --git a/subsys/shell/backends/CMakeLists.txt b/subsys/shell/backends/CMakeLists.txt new file mode 100644 index 0000000000..1deead66be --- /dev/null +++ b/subsys/shell/backends/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_sources_ifdef( + CONFIG_SHELL_BACKEND_BM_UARTE + bm_uarte.c +) diff --git a/subsys/shell/backends/Kconfig b/subsys/shell/backends/Kconfig new file mode 100644 index 0000000000..58133e5166 --- /dev/null +++ b/subsys/shell/backends/Kconfig @@ -0,0 +1,11 @@ +# +# Copyright (c) 2025 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +menu "Backends" + +rsource "Kconfig.bm_uarte" + +endmenu diff --git a/subsys/shell/backends/Kconfig.bm_uarte b/subsys/shell/backends/Kconfig.bm_uarte new file mode 100644 index 0000000000..303a7d852c --- /dev/null +++ b/subsys/shell/backends/Kconfig.bm_uarte @@ -0,0 +1,43 @@ +# +# Copyright (c) 2025 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config SHELL_BACKEND_BM_UARTE + bool "UARTE shell backend" + select RING_BUFFER + help + When enabled, the backend uses the nrfx UARTE driver as the shell transport layer. + +if SHELL_BACKEND_BM_UARTE + +config SHELL_BACKEND_BM_UARTE_RX_RBUF_SIZE + int "Receive ring buffer size in bytes" + default 128 + help + The size of the receive ring buffer the receive double buffer + is copied to. + +config SHELL_BACKEND_BM_UARTE_RX_DBUF_SIZE + int "Receive double buffer size in bytes" + default 64 + help + The total size of the receive double buffer. + +config SHELL_BACKEND_BM_UARTE_IRQ_PRIO + int "IRQ priority" + range 3 7 + default 5 + +config SHELL_BACKEND_BM_UARTE_USE_HWFC + bool "Use hardware flow control" + +config SHELL_BACKEND_BM_UARTE_PARITY_INCLUDED + bool "Use parity" + +# Disable zephyrs default serial (UART) backend +config SHELL_BACKEND_SERIAL + default n + +endif diff --git a/subsys/shell/backends/bm_uarte.c b/subsys/shell/backends/bm_uarte.c new file mode 100644 index 0000000000..96707ead00 --- /dev/null +++ b/subsys/shell/backends/bm_uarte.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +static shell_transport_handler_t sh_handler; +static void *sh_context; +static const nrfx_uarte_t uarte_inst = NRFX_UARTE_INSTANCE(BOARD_SHELL_UARTE_INST); +static const nrfx_uarte_config_t uarte_config = { + .txd_pin = BOARD_SHELL_UARTE_PIN_TX, + .rxd_pin = BOARD_SHELL_UARTE_PIN_RX, + .rts_pin = COND_CODE_1(CONFIG_SHELL_BACKEND_BM_UARTE_USE_HWFC, + (BOARD_SHELL_UARTE_PIN_RTS), + (NRF_UARTE_PSEL_DISCONNECTED)), + .cts_pin = COND_CODE_1(CONFIG_SHELL_BACKEND_BM_UARTE_USE_HWFC, + (BOARD_SHELL_UARTE_PIN_CTS), + (NRF_UARTE_PSEL_DISCONNECTED)), + .baudrate = NRF_UARTE_BAUDRATE_115200, + .config = { + .hwfc = COND_CODE_1(CONFIG_SHELL_BACKEND_BM_UARTE_USE_HWFC, + (NRF_UARTE_HWFC_ENABLED), + (NRF_UARTE_HWFC_DISABLED)), + .parity = COND_CODE_1(CONFIG_SHELL_BACKEND_BM_UARTE_PARITY_INCLUDED, + (NRF_UARTE_PARITY_INCLUDED), + (NRF_UARTE_PARITY_EXCLUDED)), + NRFX_COND_CODE_1(NRF_UART_HAS_STOP_BITS, + (.stop = (nrf_uarte_stop_t)NRF_UARTE_STOP_ONE,), ()) + NRFX_COND_CODE_1(NRF_UART_HAS_PARITY_BIT, + (.paritytype = NRF_UARTE_PARITYTYPE_EVEN,), ()) + }, + .interrupt_priority = CONFIG_SHELL_BACKEND_BM_UARTE_IRQ_PRIO, +}; + +static uint8_t dbuf[2][CONFIG_SHELL_BACKEND_BM_UARTE_RX_DBUF_SIZE / 2]; +static uint8_t dbuf_idx; +static struct ring_buf rbuf; +static uint8_t rbuf_data[CONFIG_SHELL_BACKEND_BM_UARTE_RX_RBUF_SIZE]; + +static void uarte_event_handler(nrfx_uarte_event_t const *p_event, void *p_context) +{ + switch (p_event->type) { + case NRFX_UARTE_EVT_RX_DONE: + ring_buf_put(&rbuf, p_event->data.rx.p_buffer, p_event->data.rx.length); + sh_handler(SHELL_TRANSPORT_EVT_RX_RDY, sh_context); + break; + + case NRFX_UARTE_EVT_RX_BUF_REQUEST: + dbuf_idx = dbuf_idx ? 0 : 1; + (void)nrfx_uarte_rx_buffer_set(&uarte_inst, + dbuf[dbuf_idx], + sizeof(dbuf[dbuf_idx])); + break; + + default: + break; + } +} + +static int backend_init(const struct shell_transport *transport, + const void *config, + shell_transport_handler_t evt_handler, + void *context) +{ + nrfx_err_t err; + + sh_handler = evt_handler; + sh_context = context; + + IRQ_CONNECT( + NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(BOARD_SHELL_UARTE_INST)), + CONFIG_SHELL_BACKEND_BM_UARTE_IRQ_PRIO, + NRFX_UARTE_INST_HANDLER_GET(BOARD_SHELL_UARTE_INST), + 0, + 0 + ); + + irq_enable(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(BOARD_SHELL_UARTE_INST))); + + dbuf_idx = 1; + ring_buf_init(&rbuf, sizeof(rbuf_data), rbuf_data); + + err = nrfx_uarte_init(&uarte_inst, &uarte_config, uarte_event_handler); + if (err != NRFX_SUCCESS) { + return -ENODEV; + } + + err = nrfx_uarte_rx_enable(&uarte_inst, NRFX_UARTE_RX_ENABLE_CONT); + if (err != NRFX_SUCCESS) { + return -ENODEV; + } + + return 0; +} + +static int backend_uninit(const struct shell_transport *transport) +{ + nrfx_err_t err; + + err = nrfx_uarte_rx_abort(&uarte_inst, true, true); + if (err != NRFX_SUCCESS) { + return -EIO; + } + + nrfx_uarte_uninit(&uarte_inst); + return 0; +} + +static int backend_write(const struct shell_transport *transport, + const void *data, + size_t length, + size_t *cnt) +{ + nrfx_err_t err; + + *cnt = length; + + err = nrfx_uarte_tx(&uarte_inst, data, length, NRFX_UARTE_TX_BLOCKING); + return err == NRFX_SUCCESS ? 0 : -EIO; +} + +static int backend_read(const struct shell_transport *transport, + void *data, + size_t length, + size_t *cnt) +{ + nrfx_uarte_rx_abort(&uarte_inst, false, false); + irq_disable(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(BOARD_SHELL_UARTE_INST))); + *cnt = ring_buf_get(&rbuf, data, length); + irq_enable(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(BOARD_SHELL_UARTE_INST))); + return 0; +} + +const struct shell_transport_api bm_shell_uarte_transport_api = { + .init = backend_init, + .uninit = backend_uninit, + .write = backend_write, + .read = backend_read, +}; + +const struct shell_transport bm_shell_uarte_transport = { + .api = &bm_shell_uarte_transport_api, +}; + +SHELL_DEFINE(bm_shell_uarte_shell, + "bm-uart:~$ ", + &bm_shell_uarte_transport, + 0, + 0, + SHELL_FLAG_OLF_CRLF); + +const struct shell *shell_backend_bm_uarte_get_ptr(void) +{ + return &bm_shell_uarte_shell; +} diff --git a/west.yml b/west.yml index a6eaf07264..2a49617e0b 100644 --- a/west.yml +++ b/west.yml @@ -14,7 +14,7 @@ manifest: projects: - name: nrf repo-path: sdk-nrf - revision: 3106bb595e35b40bd00c22e29fd06167a8768534 + revision: pull/23334/head import: name-allowlist: - cmsis