aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/ble_uart/nrf_cli_ble_uart.c317
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/ble_uart/nrf_cli_ble_uart.h123
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.c242
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.h95
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cli_utils_cmds.c164
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/libuarte/nrf_cli_libuarte.c247
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/libuarte/nrf_cli_libuarte.h112
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli.c3500
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli.h636
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli_types.h102
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli_vt100.h625
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/rtt/nrf_cli_rtt.c223
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/rtt/nrf_cli_rtt.h100
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/uart/nrf_cli_uart.c308
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/uart/nrf_cli_uart.h115
15 files changed, 6909 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/ble_uart/nrf_cli_ble_uart.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/ble_uart/nrf_cli_ble_uart.c
new file mode 100644
index 0000000..e469853
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/ble_uart/nrf_cli_ble_uart.c
@@ -0,0 +1,317 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(NRF_CLI_BLE_UART)
+#include "nrf_cli_ble_uart.h"
+#include "ble_nus.h"
+#include "nrf_ringbuf.h"
+#include "app_timer.h"
+#include "nrf_assert.h"
+#include "nrf_ble_gatt.h"
+#define NRF_LOG_MODULE_NAME cli_ble
+
+#if NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL NRF_CLI_BLE_UART_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR NRF_CLI_BLE_UART_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR NRF_CLI_BLE_UART_CONFIG_DEBUG_COLOR
+
+#else //NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL 0
+#endif //NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#if NRF_CLI_BLE_UART_MAX_CLIENTS > NRF_SDH_BLE_TOTAL_LINK_COUNT
+ #error "Too few BLE peripheral links are supported by the BLE SDH module for the maximal number \
+ of BLE transport instances"
+#endif
+
+#define NRF_CLI_BLE_UART_TIMEOUT_MS 50
+#define OVERHEAD_LENGTH (OPCODE_LENGTH + HANDLE_LENGTH)
+
+BLE_NUS_DEF(m_nus, NRF_CLI_BLE_UART_MAX_CLIENTS);
+BLE_LINK_CTX_MANAGER_DEF(m_link_ctx_storage,
+ NRF_CLI_BLE_UART_MAX_CLIENTS,
+ sizeof(nrf_cli_ble_uart_internal_t *));
+
+static void tx_try(nrf_cli_ble_uart_internal_t * p_instance, uint32_t threshold)
+{
+ uint8_t * p_out_data;
+ size_t out_data_len =
+ nrf_ble_gatt_eff_mtu_get(p_instance->p_gatt, p_instance->p_cb->conn_handle) -
+ OVERHEAD_LENGTH;
+
+ ret_code_t err_code = nrf_ringbuf_get(p_instance->p_tx_ringbuf,
+ &p_out_data,
+ &out_data_len,
+ true);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (out_data_len >= threshold)
+ {
+ size_t req_data_len = out_data_len;
+ err_code = ble_nus_data_send(&m_nus,
+ p_out_data,
+ (uint16_t*)&out_data_len,
+ p_instance->p_cb->conn_handle);
+
+ if ((err_code == NRF_ERROR_BUSY) || (err_code == NRF_ERROR_RESOURCES))
+ {
+ out_data_len = 0;
+ }
+ NRF_LOG_INFO("Conn_handle:%d TX req_len: %d, len: %d",
+ p_instance->p_cb->conn_handle, req_data_len, out_data_len);
+ NRF_LOG_HEXDUMP_DEBUG(p_out_data, out_data_len);
+ err_code = nrf_ringbuf_free(p_instance->p_tx_ringbuf, out_data_len);
+ ASSERT(err_code == NRF_SUCCESS);
+ }
+ else
+ {
+ err_code = nrf_ringbuf_free(p_instance->p_tx_ringbuf, 0);
+ ASSERT(err_code == NRF_SUCCESS);
+ }
+ }
+}
+
+static void nus_data_handler(ble_nus_evt_t * p_nus_evt)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ nrf_cli_ble_uart_internal_t * p_instance;
+ nrf_cli_ble_uart_internal_t ** pp_instance;
+
+ err_code = blcm_link_ctx_get(&m_link_ctx_storage, p_nus_evt->conn_handle, (void *) &pp_instance);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ p_instance = *pp_instance;
+
+ switch (p_nus_evt->type)
+ {
+ case BLE_NUS_EVT_RX_DATA:
+ {
+ NRF_LOG_INFO("Conn_handle:%d, Received: %d",
+ p_instance->p_cb->conn_handle, p_nus_evt->params.rx_data.length);
+ NRF_LOG_HEXDUMP_DEBUG(p_nus_evt->params.rx_data.p_data, p_nus_evt->params.rx_data.length);
+ size_t len = ((size_t) p_nus_evt->params.rx_data.length) & 0x0000FFFF;
+ err_code = nrf_ringbuf_cpy_put(p_instance->p_rx_ringbuf,
+ p_nus_evt->params.rx_data.p_data,
+ (size_t *)&len);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ p_instance->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY, p_instance->p_cb->p_context);
+ break;
+ }
+ case BLE_NUS_EVT_TX_RDY:
+ {
+ //TX_Complete
+ uint32_t max_tx_len = nrf_ble_gatt_eff_mtu_get(p_instance->p_gatt,
+ p_instance->p_cb->conn_handle) -
+ OVERHEAD_LENGTH;
+ tx_try(p_instance, max_tx_len);
+ p_instance->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_instance->p_cb->p_context);
+ break;
+ }
+ case BLE_NUS_EVT_COMM_STARTED:
+ p_instance->p_cb->service_started = true;
+ err_code = app_timer_start(*p_instance->p_timer,
+ APP_TIMER_TICKS(NRF_CLI_BLE_UART_TIMEOUT_MS),
+ p_instance);
+ ASSERT(err_code == NRF_SUCCESS);
+ NRF_LOG_INFO("Conn_handle:%d, communication started", p_instance->p_cb->conn_handle);
+ break;
+ case BLE_NUS_EVT_COMM_STOPPED:
+ (void)app_timer_stop(*p_instance->p_timer);
+ p_instance->p_cb->service_started = false;
+ NRF_LOG_INFO("Conn_handle:%d, communication stopped", p_instance->p_cb->conn_handle);
+ break;
+ default:
+ break;
+ }
+}
+
+static void timer_handler(void * p_context)
+{
+ nrf_cli_ble_uart_internal_t * p_instance = (nrf_cli_ble_uart_internal_t *) p_context;
+ tx_try(p_instance, 1);
+
+ ret_code_t err_code = app_timer_start(*p_instance->p_timer,
+ APP_TIMER_TICKS(NRF_CLI_BLE_UART_TIMEOUT_MS), (void *)p_instance);
+ ASSERT(err_code == NRF_SUCCESS);
+ UNUSED_VARIABLE(err_code);
+ UNUSED_PARAMETER(p_context);
+}
+
+ret_code_t nrf_cli_ble_uart_service_init(void)
+{
+ ble_nus_init_t nus_init;
+
+ memset(&nus_init, 0, sizeof(nus_init));
+ nus_init.data_handler = nus_data_handler;
+
+ return ble_nus_init(&m_nus, &nus_init);
+}
+
+static ret_code_t cli_ble_uart_init(nrf_cli_transport_t const * p_transport,
+ void const * p_config,
+ nrf_cli_transport_handler_t evt_handler,
+ void * p_context)
+{
+ ret_code_t err_code;
+ nrf_cli_ble_uart_internal_t ** pp_instance;
+ nrf_cli_ble_uart_internal_t * p_instance =
+ CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
+ nrf_cli_ble_uart_config_t * p_ble_uart_config = (nrf_cli_ble_uart_config_t *)p_config;
+
+ p_instance->p_cb->handler = evt_handler;
+ p_instance->p_cb->p_context = p_context;
+ p_instance->p_cb->service_started = false;
+ p_instance->p_cb->conn_handle = p_ble_uart_config->conn_handle;
+
+ NRF_LOG_INFO("Conn_handle:%d init.", p_ble_uart_config->conn_handle);
+ nrf_ringbuf_init(p_instance->p_rx_ringbuf);
+ nrf_ringbuf_init(p_instance->p_tx_ringbuf);
+
+ err_code = blcm_link_ctx_get(&m_link_ctx_storage,
+ p_ble_uart_config->conn_handle,
+ (void *) &pp_instance);
+ VERIFY_SUCCESS(err_code);
+
+ *pp_instance = p_instance;
+
+ return NRF_SUCCESS;
+}
+
+static ret_code_t cli_ble_uart_uninit(nrf_cli_transport_t const * p_transport)
+{
+ nrf_cli_ble_uart_internal_t * p_instance =
+ CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
+
+ NRF_LOG_INFO("Conn_handle:%d uninit.", p_instance->p_cb->conn_handle);
+ ret_code_t ret = app_timer_stop(*p_instance->p_timer);
+
+ return ret;
+}
+
+static ret_code_t cli_ble_uart_enable(nrf_cli_transport_t const * p_transport, bool blocking)
+{
+ nrf_cli_ble_uart_internal_t * p_instance =
+ CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
+
+
+ NRF_LOG_INFO("Conn_handle:%d, enable blocking:%d", blocking, p_instance->p_cb->conn_handle);
+ if (blocking)
+ {
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+ else
+ {
+ ret_code_t err_code = NRF_SUCCESS;
+ if (!p_instance->p_cb->timer_created)
+ {
+ err_code = app_timer_create(p_instance->p_timer,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ timer_handler);
+ p_instance->p_cb->timer_created = true;
+ }
+ return err_code;
+ }
+}
+
+static ret_code_t cli_ble_uart_read(nrf_cli_transport_t const * p_transport,
+ void * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ nrf_cli_ble_uart_internal_t * p_instance =
+ CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
+ *p_cnt = length;
+ ret_code_t err_code = nrf_ringbuf_cpy_get(p_instance->p_rx_ringbuf, p_data, p_cnt);
+
+ if (*p_cnt)
+ {
+ NRF_LOG_INFO("Conn_handle:%d, read req_len:%d read_len: %d",
+ p_instance->p_cb->conn_handle,
+ length,
+ *p_cnt);
+ NRF_LOG_HEXDUMP_DEBUG(p_data, *p_cnt);
+ }
+
+ return err_code;
+}
+
+static ret_code_t cli_ble_uart_write(nrf_cli_transport_t const * p_transport,
+ const void * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ nrf_cli_ble_uart_internal_t * p_instance =
+ CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
+ ret_code_t err_code = NRF_SUCCESS;
+ if (p_instance->p_cb->service_started)
+ {
+ *p_cnt = length;
+ err_code = nrf_ringbuf_cpy_put(p_instance->p_tx_ringbuf, p_data, p_cnt);
+
+ NRF_LOG_INFO("Conn_handle:%d, write req:%d, buffered:%d",
+ p_instance->p_cb->conn_handle, length, *p_cnt);
+ NRF_LOG_HEXDUMP_DEBUG(p_data, *p_cnt);
+ }
+ else
+ {
+ NRF_LOG_INFO("Conn_handle:%d, write req:%d. Notifications not enabled",
+ p_instance->p_cb->conn_handle, length);
+ *p_cnt = length;
+ p_instance->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_instance->p_cb->p_context);
+ }
+ return err_code;
+}
+
+const nrf_cli_transport_api_t nrf_cli_ble_uart_transport_api = {
+ .init = cli_ble_uart_init,
+ .uninit = cli_ble_uart_uninit,
+ .enable = cli_ble_uart_enable,
+ .read = cli_ble_uart_read,
+ .write = cli_ble_uart_write,
+};
+
+#endif //NRF_MODULE_ENABLED(NRF_CLI_BLE_UART)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/ble_uart/nrf_cli_ble_uart.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/ble_uart/nrf_cli_ble_uart.h
new file mode 100644
index 0000000..6111940
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/ble_uart/nrf_cli_ble_uart.h
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NRF_CLI_BLE_UART_H__
+#define NRF_CLI_BLE_UART_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "nrf_cli.h"
+#include "ble.h"
+#include "app_timer.h"
+#include "nrf_ringbuf.h"
+#include "nordic_common.h"
+#include "nrf_ble_gatt.h"
+/**@file
+ *
+ * @defgroup nrf_cli_ble_uart BLE UART command line interface transport layer
+ * @ingroup nrf_cli
+ *
+ * @{
+ *
+ */
+
+/**
+ * @brief Command line interface transport.
+ */
+
+ret_code_t nrf_cli_ble_uart_service_init(void);
+
+extern const nrf_cli_transport_api_t nrf_cli_ble_uart_transport_api;
+
+typedef struct nrf_cli_ble_uart_internal_s nrf_cli_ble_uart_internal_t;
+
+typedef struct {
+ nrf_cli_transport_handler_t handler;
+ void * p_context;
+ uint16_t conn_handle;
+ bool timer_created;
+ bool service_started;
+} nrf_cli_ble_uart_internal_cb_t;
+
+
+struct nrf_cli_ble_uart_internal_s {
+ nrf_cli_transport_t transport;
+ nrf_cli_ble_uart_internal_cb_t * p_cb;
+ app_timer_id_t const * p_timer;
+ nrf_ringbuf_t const * p_rx_ringbuf;
+ nrf_ringbuf_t const * p_tx_ringbuf;
+ nrf_ble_gatt_t const * p_gatt;
+};
+
+typedef struct {
+ uint16_t conn_handle;
+} nrf_cli_ble_uart_config_t;
+
+/**@brief CLI Bluetooth transport definition.
+ *
+ * @param _name Name of the instance.
+ * @param _p_gatt Pointer to the nrf_ble_gatt module.
+ * @param _tx_buf_sz Size of TX ring buffer.
+ * @param _rx_buf_sz Size of RX ring buffer.
+ */
+#define NRF_CLI_BLE_UART_DEF(_name, _p_gatt, _tx_buf_sz, _rx_buf_sz) \
+ APP_TIMER_DEF(CONCAT_2(_name, _timer)); \
+ NRF_RINGBUF_DEF(CONCAT_2(_name,_tx_ringbuf), _tx_buf_sz); \
+ NRF_RINGBUF_DEF(CONCAT_2(_name,_rx_ringbuf), _rx_buf_sz); \
+ static nrf_cli_ble_uart_internal_cb_t CONCAT_2(_name, _cb); \
+ static const nrf_cli_ble_uart_internal_t _name = { \
+ .transport = {.p_api = &nrf_cli_ble_uart_transport_api}, \
+ .p_cb = &CONCAT_2(_name, _cb), \
+ .p_timer = &CONCAT_2(_name, _timer), \
+ .p_rx_ringbuf = &CONCAT_2(_name,_rx_ringbuf), \
+ .p_tx_ringbuf = &CONCAT_2(_name,_tx_ringbuf), \
+ .p_gatt = _p_gatt, \
+ }
+
+
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NRF_CLI_BLE_UART_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.c
new file mode 100644
index 0000000..42adb75
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.c
@@ -0,0 +1,242 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(NRF_CLI_CDC_ACM)
+#include "nrf_cli_cdc_acm.h"
+#include "nrf_queue.h"
+#include "app_error.h"
+#include "nrf_assert.h"
+
+
+#if APP_USBD_CONFIG_EVENT_QUEUE_ENABLE
+#error "Current CLI CDC implementation supports only USB with event queue disabled (see APP_USBD_CONFIG_EVENT_QUEUE_ENABLE)"
+#endif
+
+static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
+ app_usbd_cdc_acm_user_event_t event);
+
+/*lint -save -e26 -e40 -e64 -e123 -e505 -e651*/
+
+/**
+ * @brief CDC_ACM class instance.
+ * */
+APP_USBD_CDC_ACM_GLOBAL_DEF(nrf_cli_cdc_acm,
+ cdc_acm_user_ev_handler,
+ NRF_CLI_CDC_ACM_COMM_INTERFACE,
+ NRF_CLI_CDC_ACM_DATA_INTERFACE,
+ NRF_CLI_CDC_ACM_COMM_EPIN,
+ NRF_CLI_CDC_ACM_DATA_EPIN,
+ NRF_CLI_CDC_ACM_DATA_EPOUT,
+ APP_USBD_CDC_COMM_PROTOCOL_AT_V250
+);
+
+/*lint -restore*/
+
+NRF_QUEUE_DEF(uint8_t,
+ m_rx_queue,
+ 2*NRF_DRV_USBD_EPSIZE,
+ NRF_QUEUE_MODE_OVERFLOW);
+
+static char m_rx_buffer[NRF_DRV_USBD_EPSIZE];
+
+static nrf_cli_cdc_acm_internal_t * mp_internal;
+
+/**
+ * @brief Set new buffer and process any data if already present
+ *
+ * This is internal function.
+ * The result of its execution is the library waiting for the event of the new data.
+ * If there is already any data that was returned from the CDC internal buffer
+ * it would be processed here.
+ */
+static void cdc_acm_process_and_prepare_buffer(app_usbd_cdc_acm_t const * p_cdc_acm)
+{
+ for (;;)
+ {
+ if (!nrf_queue_is_empty(&m_rx_queue))
+ {
+ mp_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY, mp_internal->p_cb->p_context);
+ }
+ ret_code_t ret = app_usbd_cdc_acm_read_any(&nrf_cli_cdc_acm,
+ m_rx_buffer,
+ sizeof(m_rx_buffer));
+ if (ret == NRF_SUCCESS)
+ {
+ size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
+ size_t qsize = nrf_queue_in(&m_rx_queue, m_rx_buffer, size);
+ ASSERT(size == qsize);
+ UNUSED_VARIABLE(qsize);
+ }
+ else if (ret == NRF_ERROR_IO_PENDING)
+ {
+ break;
+ }
+ else
+ {
+ APP_ERROR_CHECK(ret);
+ break;
+ }
+ }
+}
+
+/**
+ * @brief User event handler.
+ * */
+static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
+ app_usbd_cdc_acm_user_event_t event)
+{
+ app_usbd_cdc_acm_t const * p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst);
+
+
+ switch (event)
+ {
+ case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
+ {
+ /*Setup first transfer*/
+ cdc_acm_process_and_prepare_buffer(p_cdc_acm);
+ break;
+ }
+ case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
+ break;
+ case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
+ mp_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, mp_internal->p_cb->p_context);
+ break;
+ case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
+ {
+ /*Get amount of data transfered*/
+ size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
+ size_t qsize = nrf_queue_in(&m_rx_queue, m_rx_buffer, size);
+ ASSERT(size == qsize);
+ UNUSED_VARIABLE(qsize);
+
+ /*Setup next transfer*/
+ cdc_acm_process_and_prepare_buffer(p_cdc_acm);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static ret_code_t cli_cdc_acm_init(nrf_cli_transport_t const * p_transport,
+ void const * p_config,
+ nrf_cli_transport_handler_t evt_handler,
+ void * p_context)
+{
+ UNUSED_PARAMETER(p_config);
+ nrf_cli_cdc_acm_internal_t * p_internal =
+ CONTAINER_OF(p_transport, nrf_cli_cdc_acm_internal_t, transport);
+ p_internal->p_cb->handler = evt_handler;
+ p_internal->p_cb->p_context = p_context;
+
+ mp_internal = p_internal;
+ return NRF_SUCCESS;
+}
+
+static ret_code_t cli_cdc_acm_uninit(nrf_cli_transport_t const * p_transport)
+{
+ UNUSED_PARAMETER(p_transport);
+ return NRF_SUCCESS;
+}
+
+static ret_code_t cli_cdc_acm_enable(nrf_cli_transport_t const * p_transport,
+ bool blocking)
+{
+ UNUSED_PARAMETER(p_transport);
+ if (blocking)
+ {
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+ else
+ {
+ return NRF_SUCCESS;
+ }
+}
+
+static ret_code_t cli_cdc_acm_read(nrf_cli_transport_t const * p_transport,
+ void * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ UNUSED_PARAMETER(p_transport);
+ size_t size = nrf_queue_out(&m_rx_queue, p_data, length);
+ *p_cnt = size;
+
+ return NRF_SUCCESS;
+}
+
+static ret_code_t cli_cdc_acm_write(nrf_cli_transport_t const * p_transport,
+ void const * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ UNUSED_PARAMETER(p_transport);
+ ret_code_t ret;
+
+ ret = app_usbd_cdc_acm_write(&nrf_cli_cdc_acm, p_data, length);
+ if (ret == NRF_SUCCESS || ret == NRF_ERROR_INVALID_STATE)
+ {
+ *p_cnt = length;
+ ret = NRF_SUCCESS;
+ }
+ else if (ret == NRF_ERROR_BUSY)
+ {
+ *p_cnt = 0;
+ ret = NRF_SUCCESS;
+ }
+ else
+ {
+ /* Nothing to do */
+ }
+
+ return ret;
+}
+
+const nrf_cli_transport_api_t nrf_cli_cdc_acm_transport_api = {
+ .init = cli_cdc_acm_init,
+ .uninit = cli_cdc_acm_uninit,
+ .enable = cli_cdc_acm_enable,
+ .read = cli_cdc_acm_read,
+ .write = cli_cdc_acm_write,
+};
+
+#endif // NRF_MODULE_ENABLED(NRF_CLI_CDC_ACM)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.h
new file mode 100644
index 0000000..a6d8829
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.h
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NRF_CLI_CDC_ACM_H__
+#define NRF_CLI_CDC_ACM_H__
+
+#include <stdbool.h>
+
+#include "nrf_cli.h"
+#include "app_usbd_cdc_acm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@file
+ *
+ * @defgroup nrf_cli_cdc_acm CDC ACM command line interface transport layer
+ * @ingroup nrf_cli
+ *
+ * @{
+ *
+ */
+
+/**
+ * @brief Command line interface transport.
+ */
+extern const nrf_cli_transport_api_t nrf_cli_cdc_acm_transport_api;
+
+/**
+ * @brief Command line interface class instance.
+ */
+extern const app_usbd_cdc_acm_t nrf_cli_cdc_acm;
+
+typedef struct {
+ nrf_cli_transport_handler_t handler;
+ void * p_context;
+} nrf_cli_cdc_acm_internal_cb_t;
+
+typedef struct {
+ nrf_cli_transport_t transport;
+ nrf_cli_cdc_acm_internal_cb_t * p_cb;
+} nrf_cli_cdc_acm_internal_t;
+
+/**@brief CLI USB transport definition */
+#define NRF_CLI_CDC_ACM_DEF(_name_) \
+ static nrf_cli_cdc_acm_internal_cb_t CONCAT_2(_name_, _cb); \
+ static const nrf_cli_cdc_acm_internal_t _name_ = { \
+ .transport = {.p_api = &nrf_cli_cdc_acm_transport_api}, \
+ .p_cb = &CONCAT_2(_name_, _cb), \
+ }
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NRF_CLI_CDC_ACM_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cli_utils_cmds.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cli_utils_cmds.c
new file mode 100644
index 0000000..9c0805d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/cli_utils_cmds.c
@@ -0,0 +1,164 @@
+/**
+ * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "nrf_cli.h"
+#include "nrf_log.h"
+
+static void cmd_reset(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(argv);
+
+ if (nrf_cli_help_requested(p_cli))
+ {
+ nrf_cli_help_print(p_cli, NULL, 0);
+ return;
+ }
+
+ NVIC_SystemReset();
+}
+
+
+static void cmd_error(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(argv);
+
+ if (nrf_cli_help_requested(p_cli))
+ {
+ nrf_cli_help_print(p_cli, NULL, 0);
+ return;
+ }
+
+ APP_ERROR_CHECK(NRF_ERROR_INTERNAL);
+}
+
+
+static void cmd_app_size(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(argv);
+
+ if (nrf_cli_help_requested(p_cli))
+ {
+ nrf_cli_help_print(p_cli, NULL, 0);
+ return;
+ }
+
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "Application address:%d (0x%08X), size: %d (0x%08X)\r\n",
+ CODE_START,
+ CODE_START,
+ CODE_SIZE,
+ CODE_SIZE);
+}
+
+
+static void cmd_log_msg_error(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_help_requested(p_cli))
+ {
+ nrf_cli_help_print(p_cli, NULL, 0);
+ return;
+ }
+
+ switch (argc-1)
+ {
+ case 0:
+ NRF_LOG_ERROR("test error message");
+ break;
+ case 1:
+ NRF_LOG_ERROR("test error message: %d", strtol(argv[1], NULL, 10));
+ break;
+ case 2:
+ NRF_LOG_ERROR("test error message: %d %d", strtol(argv[1], NULL, 10),
+ strtol(argv[2], NULL, 10));
+ break;
+ default:
+ NRF_LOG_ERROR("test error message with more than 3 arguments");
+ break;
+ }
+}
+
+
+static void cmd_log_msg_warning(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_help_requested(p_cli))
+ {
+ nrf_cli_help_print(p_cli, NULL, 0);
+ return;
+ }
+
+ switch (argc-1)
+ {
+ case 0:
+ NRF_LOG_WARNING("test warning message");
+ break;
+ case 1:
+ NRF_LOG_WARNING("test warning message: %d", strtol(argv[1], NULL, 10));
+ break;
+ case 2:
+ NRF_LOG_WARNING("test warning message: %d %d", strtol(argv[1], NULL, 10),
+ strtol(argv[2], NULL, 10));
+ break;
+ default:
+ NRF_LOG_WARNING("test warning message with more than 3 arguments");
+ break;
+ }
+}
+
+/**
+ * @brief Command set array
+ * */
+
+NRF_CLI_CMD_REGISTER(reset, NULL, "System reset.", cmd_reset);
+
+NRF_CLI_CMD_REGISTER(error, NULL, "Trigger error.", cmd_error);
+
+NRF_CLI_CMD_REGISTER(app_size, NULL, "Print application size.", cmd_app_size);
+
+NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_log_msg)
+{
+ NRF_CLI_CMD(error, NULL, "Error log message with parameters", cmd_log_msg_error),
+ NRF_CLI_CMD(warning, NULL, "Warning log message with parameters", cmd_log_msg_warning),
+ NRF_CLI_SUBCMD_SET_END
+};
+
+NRF_CLI_CMD_REGISTER(log_msg, &m_sub_log_msg, "Trigger log message with decimal arguments", NULL);
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/libuarte/nrf_cli_libuarte.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/libuarte/nrf_cli_libuarte.c
new file mode 100644
index 0000000..d64e141
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/libuarte/nrf_cli_libuarte.c
@@ -0,0 +1,247 @@
+/**
+ * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#include "nrf_cli_libuarte.h"
+#include "nrf_libuarte_async.h"
+#include "nrf_assert.h"
+
+#define NRF_LOG_MODULE_NAME cli_libuarte
+#if NRF_CLI_LIBUARTE_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL NRF_CLI_LIBUARTE_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR NRF_CLI_LIBUARTE_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR NRF_CLI_LIBUARTE_CONFIG_DEBUG_COLOR
+#else //NRF_CLI_LIBUARTE_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL 0
+#endif //NRF_CLI_LIBUARTE_CONFIG_LOG_ENABLED
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+static cli_libuarte_internal_t * mp_internal;
+static bool m_uart_busy;
+
+static void uart_event_handler(nrf_libuarte_async_evt_t * p_event)
+{
+ cli_libuarte_internal_t * p_internal = mp_internal;
+ ret_code_t err_code = NRF_SUCCESS;
+ size_t len;
+ UNUSED_VARIABLE(err_code);
+ switch (p_event->type)
+ {
+ case NRF_LIBUARTE_ASYNC_EVT_ERROR:
+ NRF_LOG_WARNING("(evt) ERROR");
+
+ break;
+
+ case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
+ {
+ len = (size_t)((uint32_t)p_event->data.rxtx.length & 0x0000FFFF);
+ err_code = nrf_ringbuf_cpy_put(p_internal->p_rx_ringbuf,
+ p_event->data.rxtx.p_data,
+ &len);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ if (len != p_event->data.rxtx.length)
+ {
+ NRF_LOG_WARNING("Data lost, no room in RX ringbuf");
+ }
+ nrf_libuarte_async_rx_free(p_event->data.rxtx.p_data, p_event->data.rxtx.length);
+
+ if (p_event->data.rxtx.length)
+ {
+ NRF_LOG_DEBUG("(evt) RXRDY length:%d", p_event->data.rxtx.length);
+ NRF_LOG_HEXDUMP_DEBUG(p_event->data.rxtx.p_data, p_event->data.rxtx.length);
+ p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY,
+ p_internal->p_cb->p_context);
+ }
+
+ break;
+ }
+
+ case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
+ err_code = nrf_ringbuf_free(p_internal->p_tx_ringbuf, p_event->data.rxtx.length);
+ ASSERT(err_code == NRF_SUCCESS);
+ uint8_t * p_data;
+ len = 255;
+ err_code = nrf_ringbuf_get(p_internal->p_tx_ringbuf, &p_data, &len, true);
+ ASSERT(err_code == NRF_SUCCESS);
+ if (len)
+ {
+ NRF_LOG_DEBUG("(evt) Started TX (%d).", len);
+ err_code = nrf_libuarte_async_tx(p_data, len);
+ ASSERT(err_code == NRF_SUCCESS);
+ }
+ else
+ {
+ m_uart_busy = false;
+ }
+ p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_internal->p_cb->p_context);
+ NRF_LOG_DEBUG("(evt) TX completed (%d)", p_event->data.rxtx.length);
+ break;
+
+ default:
+ NRF_LOG_ERROR("(evt) Unknown event");
+ ASSERT(false);
+ break;
+ }
+}
+
+static ret_code_t cli_libuarte_init(nrf_cli_transport_t const * p_transport,
+ void const * p_config,
+ nrf_cli_transport_handler_t evt_handler,
+ void * p_context)
+{
+ cli_libuarte_internal_t * p_internal = CONTAINER_OF(p_transport,
+ cli_libuarte_internal_t,
+ transport);
+ mp_internal = p_internal;
+ m_uart_busy = false;
+
+ p_internal->p_cb->handler = evt_handler;
+ p_internal->p_cb->p_context = p_context;
+ p_internal->p_cb->blocking = false;
+
+ cli_libuarte_config_t const * p_cli_libuarte_config = (cli_libuarte_config_t *)p_config;
+ nrf_libuarte_async_config_t uart_async_config = {
+ .tx_pin = p_cli_libuarte_config->tx_pin,
+ .rx_pin = p_cli_libuarte_config->rx_pin,
+ .baudrate = p_cli_libuarte_config->baudrate,
+ .parity = p_cli_libuarte_config->parity,
+ .hwfc = p_cli_libuarte_config->hwfc,
+ .timeout_us = 100,
+ };
+ ret_code_t err_code = nrf_libuarte_async_init(&uart_async_config, uart_event_handler);
+ if (err_code == NRF_SUCCESS)
+ {
+ nrf_ringbuf_init(p_internal->p_rx_ringbuf);
+ nrf_ringbuf_init(p_internal->p_tx_ringbuf);
+ }
+ return err_code;
+}
+
+static ret_code_t cli_libuarte_uninit(nrf_cli_transport_t const * p_transport)
+{
+ UNUSED_PARAMETER(p_transport);
+ nrf_libuarte_async_uninit();
+ return NRF_SUCCESS;
+}
+
+static ret_code_t cli_libuarte_enable(nrf_cli_transport_t const * p_transport,
+ bool blocking)
+{
+ UNUSED_PARAMETER(p_transport);
+ if (blocking)
+ {
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+ else
+ {
+ nrf_libuarte_async_enable(255);
+ }
+ return NRF_SUCCESS;
+}
+
+static ret_code_t cli_libuarte_read(nrf_cli_transport_t const * p_transport,
+ void * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ cli_libuarte_internal_t * p_instance =
+ CONTAINER_OF(p_transport, cli_libuarte_internal_t, transport);
+
+ *p_cnt = length;
+ ret_code_t err_code = nrf_ringbuf_cpy_get(p_instance->p_rx_ringbuf, p_data, p_cnt);
+
+ if (*p_cnt)
+ {
+ NRF_LOG_DEBUG("Read %d bytes (requested %d)", *p_cnt, length);
+ }
+
+ return err_code;
+}
+
+static ret_code_t cli_libuarte_write(nrf_cli_transport_t const * p_transport,
+ void const * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ cli_libuarte_internal_t * p_instance = CONTAINER_OF(p_transport,
+ cli_libuarte_internal_t,
+ transport);
+ *p_cnt = length;
+ ret_code_t err_code = nrf_ringbuf_cpy_put(p_instance->p_tx_ringbuf, p_data, p_cnt);
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_DEBUG("Requested write: %d, copied to ringbuf: %d.", length, *p_cnt);
+
+ if (m_uart_busy)
+ {
+ return err_code;
+ }
+
+ uint8_t * p_buf;
+ size_t len = 255;
+ if (nrf_ringbuf_get(p_instance->p_tx_ringbuf, &p_buf, &len, true) == NRF_SUCCESS)
+ {
+ NRF_LOG_DEBUG("Started TX (%d).", len);
+
+ err_code = nrf_libuarte_async_tx(p_buf, len);
+ if (p_instance->p_cb->blocking && (err_code == NRF_SUCCESS))
+ {
+ (void)nrf_ringbuf_free(p_instance->p_tx_ringbuf, len);
+ }
+ else
+ {
+ m_uart_busy = true;
+ }
+ }
+ }
+ return err_code;
+}
+
+const nrf_cli_transport_api_t cli_libuarte_transport_api = {
+ .init = cli_libuarte_init,
+ .uninit = cli_libuarte_uninit,
+ .enable = cli_libuarte_enable,
+ .read = cli_libuarte_read,
+ .write = cli_libuarte_write,
+};
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/libuarte/nrf_cli_libuarte.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/libuarte/nrf_cli_libuarte.h
new file mode 100644
index 0000000..e37fe64
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/libuarte/nrf_cli_libuarte.h
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NRF_LOG_BACKEND_LIBUARTE_H__
+#define NRF_LOG_BACKEND_LIBUARTE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "nrf_cli.h"
+#include "nrf_libuarte.h"
+#include "nrf_ringbuf.h"
+#include "app_timer.h"
+
+/**@file
+ *
+ * @defgroup nrf_cli_libuarte libUARTE command line interface transport layer.
+ * @ingroup nrf_cli
+ *
+ * @{
+ *
+ */
+
+/**
+ * @brief Command line interface transport.
+ * */
+extern const nrf_cli_transport_api_t cli_libuarte_transport_api;
+
+typedef struct cli_libuarte_internal_s cli_libuarte_internal_t;
+
+typedef struct {
+ nrf_cli_transport_handler_t handler;
+ void * p_context;
+ bool blocking;
+} cli_libuarte_internal_cb_t;
+
+struct cli_libuarte_internal_s {
+ nrf_cli_transport_t transport;
+ cli_libuarte_internal_cb_t * p_cb;
+ nrf_ringbuf_t const * p_rx_ringbuf;
+ nrf_ringbuf_t const * p_tx_ringbuf;
+};
+
+typedef struct
+{
+ uint32_t tx_pin;
+ uint32_t rx_pin;
+ nrf_uarte_hwfc_t hwfc; ///< Flow control configuration.
+ nrf_uarte_parity_t parity; ///< Parity configuration.
+ nrf_uarte_baudrate_t baudrate; ///< Baudrate.
+} cli_libuarte_config_t;
+
+/**@brief CLI libUARTE transport definition.
+ *
+ * @param _name Name of instance.
+ * @param _tx_buf_sz Size of TX ring buffer.
+ * @param _rx_buf_sz Size of RX ring buffer.
+ */
+#define NRF_CLI_LIBUARTE_DEF(_name, _tx_buf_sz, _rx_buf_sz) \
+ NRF_RINGBUF_DEF(CONCAT_2(_name,_tx_ringbuf), _tx_buf_sz); \
+ NRF_RINGBUF_DEF(CONCAT_2(_name,_rx_ringbuf), _rx_buf_sz); \
+ static cli_libuarte_internal_cb_t CONCAT_2(_name, _cb); \
+ static const cli_libuarte_internal_t _name = { \
+ .transport = {.p_api = &cli_libuarte_transport_api}, \
+ .p_cb = &CONCAT_2(_name, _cb), \
+ .p_rx_ringbuf = &CONCAT_2(_name,_rx_ringbuf), \
+ .p_tx_ringbuf = &CONCAT_2(_name,_tx_ringbuf), \
+ }
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NRF_LOG_BACKEND_LIBUARTE_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli.c
new file mode 100644
index 0000000..1e4eba5
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli.c
@@ -0,0 +1,3500 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(NRF_CLI)
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include "nrf_cli.h"
+#include "nrf_cli_vt100.h"
+#include "app_error.h"
+#include "nrf_assert.h"
+#include "nrf_delay.h"
+#include "nrf_pwr_mgmt.h"
+#include "nrf_atomic.h"
+
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+#include "fnmatch.h"
+#endif
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+ #if NRF_CLI_HISTORY_ELEMENT_SIZE * NRF_CLI_HISTORY_ELEMENT_COUNT == 0
+ #error Not proper memory size allocated for NRF_CLI_HISTORY
+ #endif
+#endif
+
+/* 2 == 1 char for cmd + 1 char for '\0' */
+#if NRF_CLI_CMD_BUFF_SIZE < 2
+ #error too small NRF_CLI_CMD_BUFF_SIZE
+#endif
+
+#if NRF_CLI_PRINTF_BUFF_SIZE < 1
+ #error too small NRF_CLI_PRINTF_BUFF_SIZE
+#endif
+
+#define NRF_CLI_HELP_CLEAR "Clear screen."
+#define NRF_CLI_HELP_COLORS "Toggle colored syntax."
+#define NRF_CLI_HELP_COLORS_OFF "Disable colored syntax."
+#define NRF_CLI_HELP_COLORS_ON "Enable colored syntax."
+#define NRF_CLI_HELP_STATISTICS "CLI statistics."
+#define NRF_CLI_HELP_STATISTICS_SHOW "Get CLI statistics for the Logger module."
+#define NRF_CLI_HELP_STATISTICS_RESET "Reset CLI statistics for the Logger module."
+#define NRF_CLI_HELP_RESIZE "Console gets terminal screen size or assumes 80 in case " \
+ "the readout fails. It must be executed after each terminal " \
+ "width change to ensure correct text display."
+#define NRF_CLI_HELP_RESIZE_DEFAULT "Assume 80 chars screen width and send this setting " \
+ "to the terminal."
+#define NRF_CLI_HELP_HISTORY "Command history."
+#define NRF_CLI_HELP_ECHO "Toggle CLI echo."
+#define NRF_CLI_HELP_ECHO_ON "Enable CLI echo."
+#define NRF_CLI_HELP_ECHO_OFF "Disable CLI echo. Arrows and buttons: Backspace, " \
+ "Delete, End, Home, Insert are not handled."
+#define NRF_CLI_HELP_CLI "Useful, not Unix-like CLI commands."
+
+#define NRF_CLI_MSG_SPECIFY_SUBCOMMAND "Please specify a subcommand.\r\n"
+#define NRF_CLI_MSG_UNKNOWN_PARAMETER " unknown parameter: "
+#define NRF_CLI_MSG_COMMAND_NOT_FOUND ": command not found"
+#define NRF_CLI_MSG_TAB_OVERFLOWED "Tab function: commands counter overflowed.\r\n"
+
+/*lint -save -esym(526,cli_command*) -esym(526,cli_sorted_cmd_ptrs*)*/
+NRF_SECTION_DEF(cli_command, nrf_cli_cmd_entry_t);
+#define CLI_DATA_SECTION_ITEM_GET(i) NRF_SECTION_ITEM_GET(cli_command, nrf_cli_cmd_entry_t, (i))
+#define CLI_DATA_SECTION_ITEM_COUNT NRF_SECTION_ITEM_COUNT(cli_command, nrf_cli_cmd_entry_t)
+
+NRF_SECTION_DEF(cli_sorted_cmd_ptrs, const char *);
+/*lint -restore*/
+#define CLI_SORTED_CMD_PTRS_ITEM_GET(i) NRF_SECTION_ITEM_GET(cli_sorted_cmd_ptrs, const char *, (i))
+#define CLI_SORTED_CMD_PTRS_START_ADDR_GET NRF_SECTION_START_ADDR(cli_sorted_cmd_ptrs)
+
+#if defined(NRF_CLI_LOG_BACKEND) && NRF_CLI_LOG_BACKEND
+#include "nrf_log_str_formatter.h"
+#include "nrf_log_internal.h"
+#endif
+
+#define NRF_CLI_INIT_OPTION_PRINTER (NULL)
+
+#define NRF_CLI_MAX_TERMINAL_SIZE (250u)
+#define NRF_CLI_CURSOR_POSITION_BUFFER (10u) /* 10 == {esc, [, 2, 5, 0, ;, 2, 5, 0, '\0'} */
+#define NRF_CLI_DEFAULT_TERMINAL_WIDTH (80u) /* Default PuTTY width. */
+#define NRF_CLI_DEFAULT_TERMINAL_HEIGHT (24u) /* Default PuTTY height. */
+#define NRF_CLI_INITIAL_CURS_POS (1u) /* Initial cursor position is: (1, 1). */
+
+#define NRF_CLI_CMD_ROOT_LVL (0u)
+
+/* Macro to send VT100 commands. */
+#define NRF_CLI_VT100_CMD(_p_cli_, _cmd_) { \
+ ASSERT(_p_cli_); \
+ ASSERT(_p_cli_->p_fprintf_ctx); \
+ static char const cmd[] = _cmd_; \
+ nrf_fprintf(_p_cli_->p_fprintf_ctx, "%s", cmd); \
+}
+
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+typedef enum
+{
+ WILDCARD_CMD_ADDED,
+ WILDCARD_CMD_ADDED_MISSING_SPACE,
+ WILDCARD_CMD_NO_MATCH_FOUND
+} wildcard_cmd_status_t;
+#endif
+
+
+static bool cli_log_entry_process(nrf_cli_t const * p_cli, bool skip);
+static void cli_execute(nrf_cli_t const * p_cli);
+
+
+static inline void transport_buffer_flush(nrf_cli_t const * p_cli)
+{
+ nrf_fprintf_buffer_flush(p_cli->p_fprintf_ctx);
+}
+
+static inline void cli_flag_help_set(nrf_cli_t const * p_cli)
+{
+ p_cli->p_ctx->internal.flag.show_help = 1;
+}
+static inline void cli_flag_help_clear(nrf_cli_t const * p_cli)
+{
+ p_cli->p_ctx->internal.flag.show_help = 0;
+}
+
+static inline void cli_flag_echo_set(nrf_cli_t const * p_cli)
+{
+ p_cli->p_ctx->internal.flag.echo = 1;
+}
+
+static inline void cli_flag_echo_clear(nrf_cli_t const * p_cli)
+{
+ p_cli->p_ctx->internal.flag.echo = 0;
+}
+
+static inline bool cli_flag_echo_is_set(nrf_cli_t const * p_cli)
+{
+ return p_cli->p_ctx->internal.flag.echo == 1 ? true : false;
+}
+
+static inline bool cli_flag_processing_is_set(nrf_cli_t const * p_cli)
+{
+ return p_cli->p_ctx->internal.flag.processing == 1 ? true : false;
+}
+
+static inline void recieve_state_change(nrf_cli_t const * p_cli, nrf_cli_receive_t state)
+{
+ p_cli->p_ctx->receive_state = state;
+}
+
+static inline size_t cli_strlen(char const * str)
+{
+ return str == NULL ? 0 : strlen(str);
+}
+
+/* Function returns true if cursor is at beginning of an empty line. */
+static inline bool cursor_in_empty_line(nrf_cli_t const * p_cli)
+{
+ return ( (p_cli->p_ctx->cmd_buff_pos + cli_strlen(p_cli->p_name)) %
+ p_cli->p_ctx->vt100_ctx.cons.terminal_wid == 0);
+}
+
+/* Function returns true if command length is equal to multiplicity of terminal width. */
+static inline bool full_line_cmd(nrf_cli_t const * p_cli)
+{
+ return ((p_cli->p_ctx->cmd_buff_len + cli_strlen(p_cli->p_name)) %
+ p_cli->p_ctx->vt100_ctx.cons.terminal_wid == 0);
+}
+
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+/* Function returns true if string contains wildcard character: '?' or '*'. */
+static bool wildcard_character_exist(char * p_str)
+{
+ size_t str_len = cli_strlen(p_str);
+ for (size_t i = 0; i < str_len; i++)
+ {
+ if ((p_str[i] == '?') || (p_str[i] == '*'))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
+/* Function sends data stream to the CLI instance. Each time before the cli_write function is called,
+ * it must be ensured that IO buffer of fprintf is flushed to avoid synchronization issues.
+ * For that purpose, use function transport_buffer_flush(p_cli) */
+static void cli_write(nrf_cli_t const * p_cli,
+ void const * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cli && p_data);
+ ASSERT(p_cli->p_iface->p_api);
+ size_t offset = 0;
+ size_t cnt;
+ while (length)
+ {
+ ret_code_t ret = p_cli->p_iface->p_api->write(p_cli->p_iface,
+ &((uint8_t const *)p_data)[offset],
+ length,
+ &cnt);
+ UNUSED_VARIABLE(ret);
+ ASSERT(ret == NRF_SUCCESS);
+ ASSERT(length >= cnt);
+ offset += cnt;
+ length -= cnt;
+ if (cnt == 0 && (p_cli->p_ctx->state != NRF_CLI_STATE_PANIC_MODE_ACTIVE))
+ {
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+ (void)task_events_wait(NRF_CLI_TRANSPORT_TX_RDY_TASK_EVT);
+#else
+ while (p_cli->p_ctx->internal.flag.tx_rdy == 0)
+ {
+ ;
+ }
+ p_cli->p_ctx->internal.flag.tx_rdy = 0;
+#endif
+ }
+ }
+
+ if (p_cnt)
+ {
+ *p_cnt = cnt;
+ }
+}
+
+/* Function sends 1 character to the CLI instance. */
+static inline void cli_putc(nrf_cli_t const * p_cli, char ch)
+{
+ nrf_fprintf(p_cli->p_fprintf_ctx, "%c", ch);
+}
+
+/* Function reads data from the CLI instance. */
+static void cli_read(nrf_cli_t const * p_cli,
+ void * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cli && p_data);
+ ASSERT(p_cli->p_iface);
+
+ ret_code_t ret = p_cli->p_iface->p_api->read(p_cli->p_iface, p_data, length, p_cnt);
+ UNUSED_VARIABLE(ret);
+}
+
+/* Function cmd_get shall be used to search commands. It moves the pointer pp_entry to command
+ * of static command structure. If the command cannot be found, the function will set pp_entry to NULL.
+ * p_command Pointer to command which will be processed (no matter the root command).
+ * lvl Level of the requested command.
+ * idx Index of the requested command.
+ * pp_entry Pointer which points to subcommand[idx] after function execution.
+ * p_st_entry Pointer to the structure where dynamic entry data can be stored.
+ */
+static void cmd_get(nrf_cli_cmd_entry_t const * p_command,
+ size_t lvl,
+ size_t idx,
+ nrf_cli_static_entry_t const ** pp_entry,
+ nrf_cli_static_entry_t * p_st_entry)
+{
+ ASSERT (pp_entry != NULL);
+ ASSERT (p_st_entry != NULL);
+
+ if (lvl == NRF_CLI_CMD_ROOT_LVL)
+ {
+ if (idx < CLI_DATA_SECTION_ITEM_COUNT)
+ {
+ nrf_cli_cmd_entry_t const * p_cmd = NULL;
+ char const * * pp_sorted_cmds = (char const * *)CLI_SORTED_CMD_PTRS_START_ADDR_GET;
+ for (size_t i = 0; i < CLI_DATA_SECTION_ITEM_COUNT; i++)
+ {
+ p_cmd = CLI_DATA_SECTION_ITEM_GET(i);
+ if (!strcmp(pp_sorted_cmds[idx], p_cmd->u.p_static->p_syntax))
+ {
+ *pp_entry = p_cmd->u.p_static;
+ return;
+ }
+ }
+ }
+ *pp_entry = NULL;
+ return;
+ }
+
+ if (p_command == NULL)
+ {
+ *pp_entry = NULL;
+ return;
+ }
+
+ if (p_command->is_dynamic)
+ {
+ p_command->u.p_dynamic_get(idx, p_st_entry);
+ if (p_st_entry->p_syntax == NULL)
+ {
+ *pp_entry = NULL;
+ }
+ else
+ {
+ *pp_entry = p_st_entry;
+ }
+ }
+ else
+ {
+ if (p_command->u.p_static[idx].p_syntax != NULL)
+ {
+ *pp_entry = &p_command->u.p_static[idx];
+ }
+ else
+ {
+ *pp_entry = NULL;
+ }
+ }
+}
+
+/* Function multiline_console_data_check checks the current cursor position (x, y) on terminal screen
+ * based on: command length, console name length, and terminal width.
+ * Example 1:
+ * || - cursor
+ * ----------------------------
+ * |console_name $: || |
+ * ----------------------------
+ * => coordinates are: cur_x = 17, cur_x_end = 17,
+ * cur_y = 1, cur_y_end = 1
+ * Example 2:
+ * ----------------------------
+ * |console_name $: test command|
+ * |showing |e|xample |
+ * ----------------------------
+ * => coordinates are: cur_x = 9, cur_x_end = 18 (cursor can be one column after 'e')
+ * => cur_y = 2, cur_y_end = 2
+ * Example 3:
+ * ----------------------------
+ * |console_name $: test command|
+ * |showing e|x|ample with more |
+ * |parameters |
+ * ----------------------------
+ * => coordinates are: cur_x = 10, cur_x_end = 11 (cursor can be one column after 's')
+ * => cur_y = 2, cur_y_end = 3
+ */
+static nrf_cli_multiline_cons_t const * multiline_console_data_check(nrf_cli_t const * p_cli)
+{
+ nrf_cli_ctx_t * p_ctx = p_cli->p_ctx;
+ nrf_cli_multiline_cons_t * p_cons = &p_cli->p_ctx->vt100_ctx.cons;
+
+ p_cons->name_len = cli_strlen(p_cli->p_name);
+
+ /* Current cursor position in command.
+ * +1 -> because home position is (1, 1) */
+ p_cons->cur_x = (p_ctx->cmd_buff_pos + p_cons->name_len) % p_cons->terminal_wid + 1;
+ p_cons->cur_y = (p_ctx->cmd_buff_pos + p_cons->name_len) / p_cons->terminal_wid + 1;
+
+ /* Extreme position when cursor is at the end of command. */
+ p_cons->cur_y_end = (p_ctx->cmd_buff_len + p_cons->name_len) / p_cons->terminal_wid + 1;
+ p_cons->cur_x_end = (p_ctx->cmd_buff_len + p_cons->name_len) % p_cons->terminal_wid + 1;
+
+ return p_cons;
+}
+
+/* Function sends VT100 command to clear the screen from cursor position to end of the screen. */
+static inline void cli_clear_eos(nrf_cli_t const * p_cli)
+{
+ NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_CLEAREOS);
+}
+
+/* Function sends VT100 command to save cursor position. */
+static inline void cli_cursor_save(nrf_cli_t const * p_cli)
+{
+ NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_SAVECURSOR);
+}
+
+/* Function sends VT100 command to restore saved cursor position. */
+static inline void cli_cursor_restore(nrf_cli_t const * p_cli)
+{
+ NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_RESTORECURSOR);
+}
+
+/* Function forcing new line - cannot be replaced with function cursor_down_move. */
+static inline void cursor_next_line_move(nrf_cli_t const * p_cli)
+{
+ NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_NEXTLINE);
+}
+
+/* Function moves cursor left by n positions. */
+static inline void cursor_left_move(nrf_cli_t const * p_cli, nrf_cli_cmd_len_t n)
+{
+ if (n > 0)
+ {
+ nrf_fprintf(p_cli->p_fprintf_ctx, "\033[%dD", n);
+ }
+}
+
+/* Function moves cursor right by n positions. */
+static inline void cursor_right_move(nrf_cli_t const * p_cli, nrf_cli_cmd_len_t n)
+{
+ if (n > 0)
+ {
+ nrf_fprintf(p_cli->p_fprintf_ctx, "\033[%dC", n);
+ }
+}
+
+/* Function moves cursor up by n positions. */
+static inline void cursor_up_move(nrf_cli_t const * p_cli, nrf_cli_cmd_len_t n)
+{
+ if (n > 0)
+ {
+ nrf_fprintf(p_cli->p_fprintf_ctx, "\033[%dA", n);
+ }
+}
+
+/* Function moves cursor down by n positions but it will bring no effect if cursor is in the last
+ * line of terminal screen. In such case, the cursor_next_line_move function shall be invoked. */
+static inline void cursor_down_move(nrf_cli_t const * p_cli, nrf_cli_cmd_len_t n)
+{
+ if (n > 0)
+ {
+ nrf_fprintf(p_cli->p_fprintf_ctx, "\033[%dB", n);
+ }
+}
+
+/* Function increments cursor position (if possible) and moves cursor to new line if necessary. */
+static void cursor_position_increment(nrf_cli_t const * p_cli)
+{
+ if (p_cli->p_ctx->cmd_buff_pos >= p_cli->p_ctx->cmd_buff_len)
+ {
+ return; /* incrementation not possible */
+ }
+
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+ nrf_cli_cmd_len_t cur_y = p_cons->cur_y;
+ ++p_cli->p_ctx->cmd_buff_pos;
+ p_cons = multiline_console_data_check(p_cli);
+
+ if (cur_y == p_cons->cur_y)
+ {
+ cursor_right_move(p_cli, 1);
+ }
+ else
+ {
+ cursor_next_line_move(p_cli);
+ }
+}
+
+/* Function will move cursor back to position == cmd_buff_pos. Example usage is when cursor needs
+ * to be moved back after printing some text. This function cannot be used to move cursor to new
+ * location by manual change of cmd_buff_pos.*/
+static void cursor_position_synchronize(nrf_cli_t const * p_cli)
+{
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+ bool last_line = p_cons->cur_y == p_cons->cur_y_end ? true : false;
+
+ /* In case cursor reaches the bottom line of a terminal, it will be moved to the next line. */
+ if (cursor_in_empty_line(p_cli) || full_line_cmd(p_cli))
+ {
+ cursor_next_line_move(p_cli);
+ }
+
+ if (last_line)
+ {
+ cursor_left_move(p_cli, p_cons->cur_x_end - p_cons->cur_x);
+ }
+ else
+ {
+ cursor_up_move(p_cli, p_cons->cur_y_end - p_cons->cur_y);
+ if (p_cons->cur_x > p_cons->cur_x_end)
+ {
+ cursor_right_move(p_cli, p_cons->cur_x - p_cons->cur_x_end);
+ }
+ else
+ {
+ cursor_left_move(p_cli, p_cons->cur_x_end - p_cons->cur_x);
+ }
+ }
+}
+
+/* Function moves cursor to begin of command position, just after console name. */
+static void cursor_home_position_move(nrf_cli_t const * p_cli)
+{
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+
+ if ((p_cons->cur_x == p_cons->name_len + NRF_CLI_INITIAL_CURS_POS) &&
+ (p_cons->cur_y == NRF_CLI_INITIAL_CURS_POS))
+ {
+ return; /* nothing to handle because cursor is in start position */
+ }
+
+ if (p_cons->cur_y > NRF_CLI_INITIAL_CURS_POS)
+ {
+ cursor_up_move(p_cli, p_cons->cur_y - NRF_CLI_INITIAL_CURS_POS);
+ }
+
+ if (p_cons->cur_x > p_cons->name_len)
+ {
+ cursor_left_move(p_cli, p_cons->cur_x - NRF_CLI_INITIAL_CURS_POS - p_cons->name_len);
+ }
+ else
+ {
+ cursor_right_move(p_cli, p_cons->name_len + NRF_CLI_INITIAL_CURS_POS - p_cons->cur_x);
+ }
+ /* align data buffer pointer with cursor position */
+ p_cli->p_ctx->cmd_buff_pos = 0;
+}
+
+/* Function moves cursor to end of command. */
+static void cursor_end_position_move(nrf_cli_t const * p_cli)
+{
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+
+ if ((p_cons->cur_x == p_cons->cur_x_end) && (p_cons->cur_y == p_cons->cur_y_end))
+ {
+ return; /* nothing to handle because cursor is in end position */
+ }
+
+ if (p_cons->cur_y_end > p_cons->cur_y)
+ {
+ cursor_down_move(p_cli, p_cons->cur_y_end - p_cons->cur_y);
+ }
+
+ if (p_cons->cur_x > p_cons->cur_x_end)
+ {
+ cursor_left_move(p_cli, p_cons->cur_x - p_cons->cur_x_end);
+ }
+ else
+ {
+ cursor_right_move(p_cli, p_cons->cur_x_end - p_cons->cur_x);
+ }
+ /* align data buffer pointer with cursor position */
+ p_cli->p_ctx->cmd_buff_pos = p_cli->p_ctx->cmd_buff_len;
+}
+
+#if NRF_MODULE_ENABLED(NRF_CLI_BUILD_IN_CMDS)
+/* Function reads cursor position from terminal. */
+static ret_code_t cursor_position_get(nrf_cli_t const * p_cli)
+{
+ size_t cnt;
+ uint16_t x = 0; /* horizontal position */
+ uint16_t y = 0; /* vertical position */
+ char c = 0;
+
+ nrf_cli_cmd_len_t buff_idx = 0;
+
+ /* clear temp buffer */
+ memset(p_cli->p_ctx->temp_buff, 0, sizeof(p_cli->p_ctx->temp_buff));
+
+ /* escape code asking terminal about its size */
+ static char const cmd_get_terminal_size[] = "\033[6n";
+
+ nrf_fprintf(p_cli->p_fprintf_ctx, cmd_get_terminal_size);
+ /* fprintf buffer needs to be flushed to start sending prepared escape code to the terminal */
+ transport_buffer_flush(p_cli);
+
+ /* timeout for terminal response = ~1s */
+ for (uint16_t i = 0; i < 1000; i++)
+ {
+ do
+ {
+ cli_read(p_cli, &c, sizeof(c), &cnt);
+ if (cnt == 0)
+ {
+ nrf_delay_us(999);
+ continue;
+ }
+ if ((c != NRF_CLI_VT100_ASCII_ESC) &&
+ (p_cli->p_ctx->temp_buff[0] != NRF_CLI_VT100_ASCII_ESC))
+ {
+ continue;
+ }
+
+ if (c == 'R') /* end of response from the terminal */
+ {
+ p_cli->p_ctx->temp_buff[buff_idx] = '\0';
+ if (p_cli->p_ctx->temp_buff[1] != '[')
+ {
+ p_cli->p_ctx->temp_buff[0] = 0;
+ return NRF_ERROR_INVALID_DATA;
+ }
+ buff_idx = 2; /* index start position in the buffer where 'y' is stored */
+ while (p_cli->p_ctx->temp_buff[buff_idx] != ';')
+ {
+ y = y * 10 + (p_cli->p_ctx->temp_buff[buff_idx++] - '0');
+ if (buff_idx >= NRF_CLI_CMD_BUFF_SIZE)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+ }
+ if (++buff_idx >= NRF_CLI_CMD_BUFF_SIZE)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+ while (p_cli->p_ctx->temp_buff[buff_idx] != '\0')
+ {
+ x = x * 10 + (p_cli->p_ctx->temp_buff[buff_idx++] - '0');
+ if (buff_idx >= NRF_CLI_CMD_BUFF_SIZE)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+ }
+ /* horizontal cursor position */
+ if (x > NRF_CLI_MAX_TERMINAL_SIZE)
+ {
+ p_cli->p_ctx->vt100_ctx.cons.cur_x = NRF_CLI_MAX_TERMINAL_SIZE;
+ }
+ else
+ {
+ p_cli->p_ctx->vt100_ctx.cons.cur_x = (nrf_cli_cmd_len_t)x;
+ }
+ /* vertical cursor position */
+ if (y > NRF_CLI_MAX_TERMINAL_SIZE)
+ {
+ p_cli->p_ctx->vt100_ctx.cons.cur_y = NRF_CLI_MAX_TERMINAL_SIZE;
+ }
+ else
+ {
+ p_cli->p_ctx->vt100_ctx.cons.cur_y = (nrf_cli_cmd_len_t)y;
+ }
+ p_cli->p_ctx->temp_buff[0] = 0;
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ p_cli->p_ctx->temp_buff[buff_idx] = c;
+ }
+
+ if (++buff_idx > NRF_CLI_CURSOR_POSITION_BUFFER - 1)
+ {
+ p_cli->p_ctx->temp_buff[0] = 0;
+ /* data_buf[NRF_CLI_CURSOR_POSITION_BUFFER - 1] is reserved for '\0' */
+ return NRF_ERROR_NO_MEM;
+ }
+
+ } while (cnt > 0);
+ }
+ return NRF_ERROR_TIMEOUT;
+}
+
+/* Function gets terminal width and height. */
+static ret_code_t terminal_size_get(nrf_cli_t const * p_cli,
+ nrf_cli_cmd_len_t * p_length,
+ nrf_cli_cmd_len_t * p_height)
+{
+ ASSERT(p_length);
+ ASSERT(p_height);
+
+ uint16_t x;
+ uint16_t y;
+
+ if (cursor_position_get(p_cli) == NRF_SUCCESS)
+ {
+ x = p_cli->p_ctx->vt100_ctx.cons.cur_x;
+ y = p_cli->p_ctx->vt100_ctx.cons.cur_y;
+ /* assumption: terminal widht and height < 999 */
+ cursor_right_move(p_cli, NRF_CLI_MAX_TERMINAL_SIZE); /* move to last column */
+ cursor_down_move(p_cli, NRF_CLI_MAX_TERMINAL_SIZE); /* move to last row */
+ }
+ else
+ {
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+
+ if (cursor_position_get(p_cli) == NRF_SUCCESS)
+ {
+ *p_length = p_cli->p_ctx->vt100_ctx.cons.cur_x;
+ *p_height = p_cli->p_ctx->vt100_ctx.cons.cur_y;
+ cursor_left_move(p_cli, *p_length - x);
+ cursor_up_move(p_cli, *p_height - y);
+
+ return NRF_SUCCESS;
+ }
+ return NRF_ERROR_NOT_SUPPORTED;
+}
+#endif // NRF_MODULE_ENABLED(NRF_CLI_BUILD_IN_CMDS)
+
+#if NRF_MODULE_ENABLED(NRF_CLI_VT100_COLORS)
+static void vt100_color_set(nrf_cli_t const * p_cli, nrf_cli_vt100_color_t color)
+{
+ if (color != NRF_CLI_DEFAULT)
+ {
+ if (p_cli->p_ctx->vt100_ctx.col.col == color)
+ {
+ return;
+ }
+
+ uint8_t cmd[] = NRF_CLI_VT100_COLOR(color - 1);
+
+ p_cli->p_ctx->vt100_ctx.col.col = color;
+ nrf_fprintf(p_cli->p_fprintf_ctx, "%s", cmd);
+ }
+ else
+ {
+ static uint8_t const cmd[] = NRF_CLI_VT100_MODESOFF;
+
+ p_cli->p_ctx->vt100_ctx.col.col = color;
+ nrf_fprintf(p_cli->p_fprintf_ctx, "%s", cmd);
+ }
+}
+
+static void vt100_bgcolor_set(nrf_cli_t const * p_cli, nrf_cli_vt100_color_t bgcolor)
+{
+ if (bgcolor != NRF_CLI_DEFAULT)
+ {
+ if (p_cli->p_ctx->vt100_ctx.col.bgcol == bgcolor)
+ {
+ return;
+ }
+ /* -1 because default value is first in enum */
+ uint8_t cmd[] = NRF_CLI_VT100_BGCOLOR(bgcolor - 1);
+
+ p_cli->p_ctx->vt100_ctx.col.bgcol = bgcolor;
+ nrf_fprintf(p_cli->p_fprintf_ctx, "%s", cmd);
+ }
+}
+
+static inline void vt100_colors_store(nrf_cli_t const * p_cli,
+ nrf_cli_vt100_colors_t * p_color)
+{
+ memcpy(p_color, &p_cli->p_ctx->vt100_ctx.col, sizeof(nrf_cli_vt100_colors_t));
+}
+
+static void vt100_colors_restore(nrf_cli_t const * p_cli,
+ nrf_cli_vt100_colors_t const * p_color)
+{
+ vt100_color_set(p_cli, p_color->col);
+ vt100_bgcolor_set(p_cli, p_color->bgcol);
+}
+#endif // NRF_MODULE_ENABLED(NRF_CLI_VT100_COLORS)
+
+static void left_arrow_handle(nrf_cli_t const * p_cli)
+{
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+
+ if ((p_cons->cur_x == p_cons->name_len + NRF_CLI_INITIAL_CURS_POS) &&
+ (p_cons->cur_y == NRF_CLI_INITIAL_CURS_POS))
+ {
+ return; /* nothing to handle because cursor is in start position */
+ }
+
+ if (p_cons->cur_x == NRF_CLI_INITIAL_CURS_POS)
+ { /* go to previous line */
+ cursor_up_move(p_cli, 1);
+ cursor_right_move(p_cli, p_cons->terminal_wid);
+ --p_cli->p_ctx->cmd_buff_pos;
+ }
+ else
+ {
+ cursor_left_move(p_cli, 1);
+ --p_cli->p_ctx->cmd_buff_pos;
+ }
+}
+
+static void right_arrow_handle(nrf_cli_t const * p_cli)
+{
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+
+ if ((p_cons->cur_x == p_cons->cur_x_end) &&
+ (p_cons->cur_y == p_cons->cur_y_end))
+ {
+ return; /* nothing to handle because cursor is in start position */
+ }
+
+ if (p_cons->cur_x == p_cons->terminal_wid) /* go to next line */
+ {
+ cursor_down_move(p_cli, 1);
+ cursor_left_move(p_cli, p_cons->terminal_wid);
+ ++p_cli->p_ctx->cmd_buff_pos;
+ }
+ else
+ {
+ cursor_right_move(p_cli, 1);
+ ++p_cli->p_ctx->cmd_buff_pos;
+ }
+}
+
+static inline void char_insert_echo_off(nrf_cli_t const * p_cli, char data)
+{
+ if (p_cli->p_ctx->cmd_buff_len >= (NRF_CLI_CMD_BUFF_SIZE - 1))
+ {
+ return;
+ }
+
+ p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos++] = data;
+ p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos] = '\0';
+ ++p_cli->p_ctx->cmd_buff_len;
+}
+
+static void char_insert(nrf_cli_t const * p_cli, char data)
+{
+ nrf_cli_cmd_len_t diff;
+ bool ins_mode = (bool)p_cli->p_ctx->internal.flag.insert_mode;
+
+ diff = p_cli->p_ctx->cmd_buff_len - p_cli->p_ctx->cmd_buff_pos;
+
+ if (!ins_mode)
+ {
+ if (p_cli->p_ctx->cmd_buff_len >= (NRF_CLI_CMD_BUFF_SIZE - 1))
+ {
+ return;
+ }
+ if (diff > 0)
+ {
+ memmove(&p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos + 1],
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos],
+ diff);
+ }
+ }
+ else
+ {
+ if ((p_cli->p_ctx->cmd_buff_len >= (NRF_CLI_CMD_BUFF_SIZE - 1)) &&
+ (diff == 0))
+ {
+ /* If cmd buffer is full, it is possible to replace chars but adding new
+ is not allowed. */
+ return;
+ }
+ }
+
+ p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos] = data;
+
+ if (!ins_mode)
+ {
+ p_cli->p_ctx->cmd_buff[++p_cli->p_ctx->cmd_buff_len] = '\0';
+ }
+
+ if (diff > 0)
+ {
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+ bool last_line = p_cons->cur_y == p_cons->cur_y_end ? true : false;
+
+ /* Below if-else statement is to minimize esc codes transmission. */
+ if (last_line)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "%s",
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos]);
+ /* Move cursor one position left less in case of insert mode. */
+ cursor_left_move(p_cli, diff - ins_mode);
+ }
+ else
+ {
+ /* Save the current cursor position in order to get back after fprintf function. */
+ cli_cursor_save(p_cli);
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "%s",
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos]);
+ cli_cursor_restore(p_cli);
+ /* Move cursor right by one position to edit the next character. */
+ cursor_right_move(p_cli, 1);
+ }
+ }
+ else
+ {
+ /* New char appended at the end of buffer. */
+ if (ins_mode)
+ {
+ p_cli->p_ctx->cmd_buff[++p_cli->p_ctx->cmd_buff_len] = '\0';
+ }
+ cli_putc(p_cli, data);
+ }
+
+ /* Incrementation needs to be executed before invoking function: cursor_in_empty_line. */
+ ++p_cli->p_ctx->cmd_buff_pos;
+
+ /* Forcing terminal to switch to a new line if the command is too long. */
+ if (cursor_in_empty_line(p_cli))
+ {
+ cursor_next_line_move(p_cli);
+ return;
+ }
+
+ if (full_line_cmd(p_cli))
+ {
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+
+ /* The code below will force the terminal to scroll one line down when the currently entered command
+ * reaches lower right corner of the terminal screen. */
+ cursor_down_move(p_cli, p_cons->cur_y_end - p_cons->cur_y - 1);
+ cursor_next_line_move(p_cli);
+ cursor_up_move(p_cli, p_cons->cur_y_end - p_cons->cur_y);
+ cursor_right_move(p_cli, p_cons->cur_x - 1);
+ return;
+ }
+}
+
+static void char_backspace(nrf_cli_t const * p_cli)
+{
+ nrf_cli_cmd_len_t diff;
+
+ if ((p_cli->p_ctx->cmd_buff_len == 0) || (p_cli->p_ctx->cmd_buff_pos == 0))
+ {
+ return;
+ }
+
+ diff = p_cli->p_ctx->cmd_buff_len - p_cli->p_ctx->cmd_buff_pos;
+
+ memmove(&p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos - 1],
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos],
+ diff + 1);
+
+ --p_cli->p_ctx->cmd_buff_pos;
+ --p_cli->p_ctx->cmd_buff_len;
+
+ if (diff > 0)
+ {
+ cli_putc(p_cli, NRF_CLI_VT100_ASCII_BSPACE);
+
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+ bool last_line = p_cons->cur_y == p_cons->cur_y_end ? true : false;
+
+ if (last_line)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "%s",
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos]);
+ cli_clear_eos(p_cli);
+ cursor_left_move(p_cli, diff);
+ }
+ else
+ {
+ /* If cursor is not in last cmd line, its position needs to be saved by
+ * VT100 command. */
+ cli_cursor_save(p_cli);
+ cli_clear_eos(p_cli);
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "%s",
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos]);
+ cli_cursor_restore(p_cli);
+ }
+ }
+ else
+ {
+ static char const cmd_bspace[] = {
+ NRF_CLI_VT100_ASCII_BSPACE, ' ', NRF_CLI_VT100_ASCII_BSPACE, '\0'};
+ nrf_fprintf(p_cli->p_fprintf_ctx, "%s", cmd_bspace);
+ }
+}
+
+static void char_delete(nrf_cli_t const * p_cli)
+{
+ nrf_cli_cmd_len_t diff;
+
+ diff = p_cli->p_ctx->cmd_buff_len - p_cli->p_ctx->cmd_buff_pos;
+
+ if (diff == 0)
+ {
+ return;
+ }
+
+ memmove(&p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos],
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos + 1],
+ diff);
+
+ --p_cli->p_ctx->cmd_buff_len;
+
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+ bool last_line = p_cons->cur_y == p_cons->cur_y_end ? true : false;
+
+ /* If last line of command is edited, there is no need for saving cursor position. */
+ if (last_line)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "%s",
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos]);
+ NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_CLEAREOL);
+ cursor_left_move(p_cli, --diff);
+ }
+ else
+ {
+ cli_cursor_save(p_cli);
+ cli_clear_eos(p_cli);
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "%s",
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos]);
+ cli_cursor_restore(p_cli);
+ }
+}
+
+static char make_argv(size_t * p_argc, char ** pp_argv, char * p_cmd, uint8_t max_argc)
+{
+ char c;
+ char quote = 0;
+
+ *p_argc = 0;
+ do
+ {
+ c = *p_cmd;
+ if (c == '\0')
+ {
+ break;
+ }
+
+ if (isspace((int)c))
+ {
+ *p_cmd++ = '\0';
+ continue;
+ }
+
+ pp_argv[(*p_argc)++] = p_cmd;
+ quote = 0;
+
+ while (1)
+ {
+ c = *p_cmd;
+
+ if (c == '\0')
+ {
+ break;
+ }
+
+ if (!quote)
+ {
+ switch (c)
+ {
+ case '\\':
+ memmove(p_cmd, p_cmd + 1, cli_strlen(p_cmd));
+ p_cmd += 1;
+ continue;
+
+ case '\'':
+ case '\"':
+ memmove(p_cmd, p_cmd + 1, cli_strlen(p_cmd));
+ quote = c;
+ continue;
+ default:
+ break;
+ }
+ }
+
+ if (quote == c)
+ {
+ memmove(p_cmd, p_cmd + 1, cli_strlen(p_cmd));
+ quote = 0;
+ continue;
+ }
+
+ if (quote && c == '\\')
+ {
+ char t = *(p_cmd + 1);
+
+ if (t == quote)
+ {
+ memmove(p_cmd, p_cmd + 1, cli_strlen(p_cmd));
+ p_cmd += 1;
+ continue;
+ }
+
+ if (t == '0')
+ {
+ uint8_t i;
+ uint8_t v = 0;
+
+ for (i = 2; i < (2 + 3); i++)
+ {
+ t = *(p_cmd + i);
+
+ if (t >= '0' && t <= '7')
+ {
+ v = (v << 3) | (t - '0');
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (i > 2)
+ {
+ memmove(p_cmd, p_cmd + (i - 1), cli_strlen(p_cmd) - (i - 2));
+ *p_cmd++ = v;
+ continue;
+ }
+ }
+
+ if (t == 'x')
+ {
+ uint8_t i;
+ uint8_t v = 0;
+
+ for (i = 2; i < (2 + 2); i++)
+ {
+ t = *(p_cmd + i);
+
+ if (t >= '0' && t <= '9')
+ {
+ v = (v << 4) | (t - '0');
+ }
+ else if (t >= 'a' && t <= 'f')
+ {
+ v = (v << 4) | (t - 'a' + 10);
+ }
+ else if (t >= 'A' && t <= 'F')
+ {
+ v = (v << 4) | (t - 'A' + 10);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (i > 2)
+ {
+ memmove(p_cmd, p_cmd + (i - 1), cli_strlen(p_cmd) - (i - 2));
+ *p_cmd++ = v;
+ continue;
+ }
+ }
+ }
+ if (!quote && isspace((int)c))
+ {
+ break;
+ }
+
+ p_cmd += 1;
+ }
+ } while (*p_argc < max_argc);
+
+ ASSERT(*p_argc <= NRF_CLI_ARGC_MAX);
+ pp_argv[*p_argc] = 0;
+
+ return quote;
+}
+
+static void cli_state_set(nrf_cli_t const * p_cli, nrf_cli_state_t state)
+{
+ p_cli->p_ctx->state = state;
+
+ if (state == NRF_CLI_STATE_ACTIVE)
+ {
+ p_cli->p_ctx->cmd_buff[0] = '\0'; /* clear command buffer */
+ p_cli->p_ctx->cmd_buff_pos = 0;
+ p_cli->p_ctx->cmd_buff_len = 0;
+ nrf_cli_fprintf(p_cli, NRF_CLI_INFO, "%s", p_cli->p_name);
+ }
+}
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+static inline void history_mode_exit(nrf_cli_t const * p_cli)
+{
+ p_cli->p_ctx->p_cmd_list_element = NULL;
+}
+
+static void history_handle(nrf_cli_t const * p_cli, bool up)
+{
+ nrf_cli_memobj_header_t header = {
+ .p_prev = NULL,
+ .p_next = NULL,
+ .cmd_len = 0
+ };
+ nrf_cli_cmd_len_t current_cmd_len;
+ bool skip = false;
+
+ if (!up) /* button down */
+ {
+ if (p_cli->p_ctx->p_cmd_list_element == NULL)
+ {
+ return;
+ }
+ cursor_home_position_move(p_cli);
+
+ nrf_memobj_read(p_cli->p_ctx->p_cmd_list_element,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+
+ p_cli->p_ctx->p_cmd_list_element = header.p_next;
+ current_cmd_len = p_cli->p_ctx->cmd_buff_len;
+
+ if (p_cli->p_ctx->p_cmd_list_element == NULL)
+ {
+ if (cli_strlen(p_cli->p_ctx->temp_buff) > 0)
+ {
+ strcpy(p_cli->p_ctx->cmd_buff, p_cli->p_ctx->temp_buff);
+ }
+ else
+ {
+ p_cli->p_ctx->cmd_buff[0] = '\0';
+ }
+ header.cmd_len = cli_strlen(p_cli->p_ctx->cmd_buff);
+ skip = true;
+ }
+ }
+ else /* button up */
+ {
+ if ((p_cli->p_ctx->p_cmd_list_element == p_cli->p_ctx->p_cmd_list_tail) ||
+ (p_cli->p_ctx->p_cmd_list_head == NULL))
+ {
+ /* Nothing to display. */
+ return;
+ }
+ cursor_home_position_move(p_cli);
+
+ if (p_cli->p_ctx->p_cmd_list_element == NULL)
+ {
+ current_cmd_len = cli_strlen(p_cli->p_ctx->cmd_buff);
+
+ p_cli->p_ctx->p_cmd_list_element = p_cli->p_ctx->p_cmd_list_head;
+ /* Save the currently entered and not executed command. */
+ if (current_cmd_len > 0)
+ {
+ strcpy(p_cli->p_ctx->temp_buff, p_cli->p_ctx->cmd_buff);
+ }
+ else
+ {
+ p_cli->p_ctx->temp_buff[0] = '\0';
+ }
+ }
+ else
+ {
+ nrf_memobj_read(p_cli->p_ctx->p_cmd_list_element,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+ current_cmd_len = header.cmd_len;
+ p_cli->p_ctx->p_cmd_list_element = header.p_prev;
+ }
+ }
+ if (!skip)
+ {
+ nrf_memobj_read(p_cli->p_ctx->p_cmd_list_element,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+
+ nrf_memobj_read(p_cli->p_ctx->p_cmd_list_element,
+ p_cli->p_ctx->cmd_buff,
+ header.cmd_len + 1, /* +1 for '\0' */
+ (uint32_t)NRF_CLI_HISTORY_HEADER_SIZE);
+ }
+
+ p_cli->p_ctx->cmd_buff_pos = header.cmd_len;
+ p_cli->p_ctx->cmd_buff_len = header.cmd_len;
+
+ if (current_cmd_len > header.cmd_len)
+ {
+ cli_clear_eos(p_cli);
+ }
+
+ nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%s", p_cli->p_ctx->cmd_buff);
+ if (cursor_in_empty_line(p_cli) || full_line_cmd(p_cli))
+ {
+ cursor_next_line_move(p_cli);
+ }
+}
+
+static void history_list_element_add(nrf_cli_t const * p_cli, nrf_memobj_t * p_memobj)
+{
+ ASSERT(p_memobj != NULL);
+
+ nrf_cli_memobj_header_t header;
+
+ if (p_cli->p_ctx->p_cmd_list_head == NULL)
+ {
+ p_cli->p_ctx->p_cmd_list_head = p_memobj;
+ p_cli->p_ctx->p_cmd_list_tail = p_memobj;
+ header.p_prev = NULL;
+ header.p_next = NULL;
+ header.cmd_len = p_cli->p_ctx->cmd_buff_len;
+ }
+ else
+ {
+ nrf_memobj_read(p_cli->p_ctx->p_cmd_list_head,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+
+ header.p_next = p_memobj;
+
+ nrf_memobj_write(p_cli->p_ctx->p_cmd_list_head,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+
+ header.p_next = NULL;
+ header.p_prev = p_cli->p_ctx->p_cmd_list_head;
+ header.cmd_len = p_cli->p_ctx->cmd_buff_len;
+
+ p_cli->p_ctx->p_cmd_list_head = p_memobj;
+ }
+
+ nrf_memobj_write(p_memobj,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+
+ nrf_memobj_write(p_memobj,
+ p_cli->p_ctx->cmd_buff,
+ p_cli->p_ctx->cmd_buff_len + 1, /* +1 for '\0' */
+ (uint32_t)NRF_CLI_HISTORY_HEADER_SIZE);
+}
+
+static void history_list_element_oldest_remove(nrf_cli_t const * p_cli)
+{
+ if (p_cli->p_ctx->p_cmd_list_tail == NULL)
+ {
+ return; // nothing to do
+ }
+
+ nrf_cli_memobj_header_t header;
+ nrf_memobj_t * p_memobj = p_cli->p_ctx->p_cmd_list_tail;
+
+ nrf_memobj_read(p_memobj,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+
+ p_cli->p_ctx->p_cmd_list_tail = header.p_next;
+ memset(&header, 0, sizeof(nrf_cli_memobj_header_t));
+ nrf_memobj_write(p_memobj, &header, NRF_CLI_HISTORY_HEADER_SIZE, 0);
+ nrf_memobj_free(p_memobj);
+
+ /* Checking if memory objects list is empty. */
+ if (p_cli->p_ctx->p_cmd_list_tail == NULL)
+ {
+ p_cli->p_ctx->p_cmd_list_head = NULL;
+ return;
+ }
+
+ nrf_memobj_read(p_cli->p_ctx->p_cmd_list_tail,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+
+ header.p_prev = NULL;
+ nrf_memobj_write(p_cli->p_ctx->p_cmd_list_tail, &header, NRF_CLI_HISTORY_HEADER_SIZE, 0);
+}
+
+static void history_list_free_memory(nrf_cli_t const * p_cli)
+{
+ while (p_cli->p_ctx->p_cmd_list_tail != NULL)
+ {
+ history_list_element_oldest_remove(p_cli);
+ }
+}
+
+static void history_save(nrf_cli_t const * p_cli)
+{
+ nrf_cli_cmd_len_t cmd_new_len = cli_strlen(p_cli->p_ctx->cmd_buff);
+
+ history_mode_exit(p_cli);
+
+ if (cmd_new_len == 0)
+ {
+ return;
+ }
+
+ /* Checking if newly entered command is not duplicated with previous one. */
+ if (p_cli->p_ctx->p_cmd_list_head != NULL)
+ {
+ nrf_cli_memobj_header_t header;
+
+ nrf_memobj_read(p_cli->p_ctx->p_cmd_list_head,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+ if (cmd_new_len == header.cmd_len)
+ {
+ nrf_memobj_read(p_cli->p_ctx->p_cmd_list_head,
+ p_cli->p_ctx->temp_buff,
+ header.cmd_len + 1, /* +1 for '\0' */
+ (uint32_t)NRF_CLI_HISTORY_HEADER_SIZE);
+
+ if (strcmp(p_cli->p_ctx->cmd_buff, p_cli->p_ctx->temp_buff) == 0)
+ {
+ /* Duplicated command, nothing to save. */
+ p_cli->p_ctx->temp_buff[0] = '\0';
+ return;
+ }
+ p_cli->p_ctx->temp_buff[0] = '\0';
+ }
+ }
+
+ for (size_t idx = 0; idx < NRF_CLI_HISTORY_ELEMENT_COUNT; idx++)
+ {
+ nrf_memobj_t * p_memobj;
+
+ p_memobj = nrf_memobj_alloc(p_cli->p_cmd_hist_mempool,
+ ((size_t)NRF_CLI_HISTORY_HEADER_SIZE + cmd_new_len + 1));
+ if (p_memobj != NULL)
+ {
+ history_list_element_add(p_cli, p_memobj);
+ return;
+ }
+ else
+ {
+ history_list_element_oldest_remove(p_cli);
+ }
+ }
+ return;
+}
+#endif // NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+
+/* Function checks how many identical characters have two strings starting from the first character. */
+static nrf_cli_cmd_len_t str_similarity_check(char const * str_a, char const * str_b)
+{
+ nrf_cli_cmd_len_t cnt = 0;
+
+ while (str_a[cnt] != '\0')
+ {
+ if (str_a[cnt] != str_b[cnt])
+ {
+ return cnt;
+ }
+
+ if (++cnt == 0)
+ {
+ return --cnt; /* too long strings */
+ }
+ }
+ return cnt;
+}
+
+static void completion_insert(nrf_cli_t const * p_cli,
+ char const * p_compl,
+ nrf_cli_cmd_len_t compl_len)
+{
+ ASSERT (p_compl);
+
+ nrf_cli_cmd_len_t diff = p_cli->p_ctx->cmd_buff_len - p_cli->p_ctx->cmd_buff_pos;
+
+ if ((p_cli->p_ctx->cmd_buff_len + compl_len > NRF_CLI_CMD_BUFF_SIZE - 1) ||
+ (compl_len == 0))
+ {
+ return;
+ }
+
+ /* Make space for completion. */
+ memmove(&p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos + compl_len],
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos],
+ diff + 1); /* + 1 for '\0' */
+
+ /* Insert completion. */
+ memmove(&p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos],
+ p_compl,
+ compl_len);
+
+ p_cli->p_ctx->cmd_buff_len = cli_strlen(p_cli->p_ctx->cmd_buff);
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "%s",
+ &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos]);
+ p_cli->p_ctx->cmd_buff_pos += compl_len;
+
+ if (cursor_in_empty_line(p_cli) || full_line_cmd(p_cli))
+ {
+ cursor_next_line_move(p_cli);
+ }
+
+ if (diff > 0)
+ {
+ cursor_position_synchronize(p_cli);
+ }
+}
+
+static void option_print(nrf_cli_t const * p_cli,
+ char const * p_option,
+ nrf_cli_cmd_len_t longest_option)
+{
+ static char const * tab = " ";
+
+ /* Function initialization has been requested. */
+ if (p_option == NULL)
+ {
+ p_cli->p_ctx->vt100_ctx.printed_cmd = 0;
+ return;
+ }
+ longest_option += cli_strlen(tab);
+
+ nrf_cli_cmd_len_t columns =
+ (p_cli->p_ctx->vt100_ctx.cons.terminal_wid - cli_strlen(tab)) / longest_option;
+ nrf_cli_cmd_len_t diff = longest_option - cli_strlen(p_option);
+
+ if (p_cli->p_ctx->vt100_ctx.printed_cmd++ % columns == 0)
+ {
+ nrf_cli_fprintf(p_cli, NRF_CLI_OPTION, "\r\n%s%s", tab, p_option);
+ }
+ else
+ {
+ nrf_cli_fprintf(p_cli, NRF_CLI_OPTION, "%s", p_option);
+ }
+ cursor_right_move(p_cli, diff);
+}
+
+static void cli_tab_handle(nrf_cli_t const * p_cli)
+{
+ size_t cmd_idx;
+ size_t cmd_last = 0;
+ size_t cmd_first = 0;
+
+ size_t argc;
+ char * argv[NRF_CLI_ARGC_MAX + 1]; /* +1 reserved for NULL in function make_argv */
+
+ nrf_cli_cmd_len_t cmd_lvl = NRF_CLI_CMD_ROOT_LVL;
+ nrf_cli_cmd_len_t cmd_longest = 0; /* longest matching command */
+
+ /* Calculating the longest possible completion length. -1 for '\0'. */
+ nrf_cli_cmd_len_t compl_len = (NRF_CLI_CMD_BUFF_SIZE - 1) - p_cli->p_ctx->cmd_buff_len;
+
+ if (compl_len == 0)
+ {
+ return;
+ }
+
+ /* Copy command from its beginning to cursor position. */
+ memcpy(p_cli->p_ctx->temp_buff,
+ p_cli->p_ctx->cmd_buff,
+ p_cli->p_ctx->cmd_buff_pos);
+
+ p_cli->p_ctx->temp_buff[p_cli->p_ctx->cmd_buff_pos] = '\0';
+
+ /* Check if the current cursor position points to the 'space' character. */
+ bool space = isspace((int)p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos - 1]);
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+ /* If the Tab key is pressed, "history mode" must be terminated because tab and history handlers
+ are sharing the same array: temp_buff. */
+ history_mode_exit(p_cli);
+#endif
+
+ /* Create argument list. */
+ (void)make_argv(&argc,
+ &argv[0],
+ p_cli->p_ctx->temp_buff,
+ NRF_CLI_ARGC_MAX);
+
+ nrf_cli_cmd_len_t arg_len = cli_strlen(argv[cmd_lvl]);
+
+ /* Variable 'static_entry' is needed to handle dynamic commands. */
+ nrf_cli_static_entry_t static_entry;
+
+ nrf_cli_cmd_entry_t const * p_cmd = NULL;
+ nrf_cli_static_entry_t const * p_st_cmd = NULL;
+ nrf_cli_static_entry_t const * p_st_cmd_last = NULL;
+
+ do
+ {
+ if ((argc == 0) ||
+ (cmd_lvl >= argc - 1 + space))
+ {
+ if (space)
+ {
+ arg_len = 0;
+ }
+ else
+ {
+ arg_len = cli_strlen(argv[cmd_lvl]);
+ }
+
+ cmd_idx = 0;
+
+ while (1)
+ {
+ cmd_get(p_cmd, cmd_lvl, cmd_idx++, &p_st_cmd, &static_entry);
+
+ if (p_st_cmd == NULL)
+ {
+ /* No more commands available. */
+ break;
+ }
+
+ if (strncmp(argv[cmd_lvl], p_st_cmd->p_syntax, arg_len) != 0)
+ {
+ if (p_st_cmd_last != NULL)
+ {
+ /* No more matches will be found as commands are sorted alphabetically. */
+ break;
+ }
+ continue;
+ }
+ if (p_st_cmd_last == NULL)
+ {
+ cmd_first = cmd_idx - 1;
+ cmd_longest = cli_strlen(p_st_cmd->p_syntax);
+ if (compl_len > (cmd_longest - arg_len))
+ {
+ compl_len = cmd_longest - arg_len;
+ }
+ }
+ else
+ {
+ nrf_cli_cmd_len_t len = cli_strlen(p_st_cmd->p_syntax);
+ if (len > cmd_longest)
+ {
+ cmd_longest = len;
+ }
+
+ if (compl_len > 0) /* Checking if partial completion is possible */
+ {
+ nrf_cli_static_entry_t last_entry;
+ cmd_get(p_cmd, cmd_lvl, cmd_last, &p_st_cmd_last, &last_entry);
+
+ len = str_similarity_check(p_st_cmd->p_syntax + arg_len,
+ p_st_cmd_last->p_syntax + arg_len);
+ if (compl_len > len)
+ {
+ /* Determining the longest possible completion. */
+ compl_len = len;
+ }
+ }
+ }
+ cmd_last = cmd_idx - 1;
+ p_st_cmd_last = p_st_cmd;
+
+ if (cmd_idx == 0) /* Too many possibilities */
+ {
+ nrf_cli_fprintf(p_cli, NRF_CLI_WARNING, NRF_CLI_MSG_TAB_OVERFLOWED);
+ break;
+ }
+ }
+ }
+ else
+ {
+ cmd_idx = 0;
+
+ while (1)
+ {
+ cmd_get(p_cmd, cmd_lvl, cmd_idx++, &p_st_cmd, &static_entry);
+
+ if (cmd_idx == 0)
+ {
+ /* No match found and commands counter overflowed. */
+ nrf_cli_fprintf(p_cli, NRF_CLI_WARNING, NRF_CLI_MSG_TAB_OVERFLOWED);
+ return;
+ }
+
+ if (p_st_cmd == NULL) /* No more commands available */
+ {
+ return;
+ }
+
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+ /* Ignore wildcard character arguments if they are "standalone". Example:
+ 1. log enable info b*<tab> -> "b*" is treated as a command so no match found
+ 2. log enable info b* <tab> -> "b* " is ignored, <tab> will prompt all available
+ commands. */
+ if (wildcard_character_exist(argv[cmd_lvl]))
+ {
+ break;
+ }
+#endif
+ /* Fuction "strcmp" is used because an exact match is required. */
+ if (strcmp(argv[cmd_lvl], p_st_cmd->p_syntax) == 0)
+ {
+ p_cmd = p_st_cmd->p_subcmd;
+ break;
+ }
+ }
+ }
+
+ if ((p_cmd == NULL) || (p_st_cmd == NULL))
+ {
+ break;
+ }
+
+ } while (++cmd_lvl < argc + space);
+
+ if (p_st_cmd_last == NULL)
+ {
+ /* No match found. */
+ return;
+ }
+
+ if (cmd_first == cmd_last) /* only one match found */
+ {
+ if (p_cmd->is_dynamic)
+ {
+ /* In case of dynamic entry, function cmd_get shall be called again for matching
+ * command index (cmd_last). It is because static_entry is most likely appended by
+ * not valid data.
+ */
+ cmd_get(p_cmd, cmd_lvl, cmd_last, &p_st_cmd_last, &static_entry);
+ }
+ if (cli_strlen(p_st_cmd_last->p_syntax) != arg_len) /* no exact match found */
+ {
+ completion_insert(p_cli, p_st_cmd_last->p_syntax + arg_len, compl_len);
+ }
+
+ /* Next character in the buffer is not 'space'. */
+ if (!isspace((int)p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_pos]))
+ {
+ if (p_cli->p_ctx->internal.flag.insert_mode)
+ {
+ p_cli->p_ctx->internal.flag.insert_mode = 0;
+ char_insert(p_cli, ' ');
+ p_cli->p_ctx->internal.flag.insert_mode = 1;
+ }
+ else
+ {
+ char_insert(p_cli, ' ');
+ }
+ }
+ else
+ {
+ /* case:
+ | | -> cursor
+ cons_name $: valid_cmd valid_sub_cmd| |argument <tab>
+ */
+ cursor_position_increment(p_cli);
+ /* result:
+ cons_name $: valid_cmd valid_sub_cmd |a|rgument
+ */
+ }
+ return;
+ }
+
+ /* Printing all matching commands (options). */
+ option_print(p_cli, NRF_CLI_INIT_OPTION_PRINTER, cmd_longest);
+ for (cmd_idx = cmd_first; cmd_idx <= cmd_last; cmd_idx++)
+ {
+ cmd_get(p_cmd, cmd_lvl, cmd_idx, &p_st_cmd, &static_entry);
+ option_print(p_cli, p_st_cmd->p_syntax, cmd_longest);
+ }
+
+ nrf_cli_fprintf(p_cli, NRF_CLI_INFO, "\r\n%s", p_cli->p_name);
+ nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%s", p_cli->p_ctx->cmd_buff);
+
+ cursor_position_synchronize(p_cli);
+ completion_insert(p_cli, p_st_cmd_last->p_syntax + arg_len, compl_len);
+}
+
+#define NRF_CLI_ASCII_MAX_CHAR (127u)
+static inline ret_code_t ascii_filter(char const data)
+{
+ return (uint8_t)data > NRF_CLI_ASCII_MAX_CHAR ? NRF_ERROR_INVALID_DATA : NRF_SUCCESS;
+}
+
+static void cli_state_collect(nrf_cli_t const * p_cli)
+{
+ size_t count = 0;
+ char data;
+
+ while (1)
+ {
+ cli_read(p_cli, &data, sizeof(data), &count);
+ if (count == 0)
+ {
+ return;
+ }
+
+ if (ascii_filter(data) != NRF_SUCCESS)
+ {
+ continue;
+ }
+
+#if NRF_MODULE_ENABLED(NRF_PWR_MGMT)
+ nrf_pwr_mgmt_feed();
+#endif
+
+ switch (p_cli->p_ctx->receive_state)
+ {
+ case NRF_CLI_RECEIVE_DEFAULT:
+ if (data == p_cli->newline_char)
+ {
+ if (p_cli->p_ctx->cmd_buff_len == 0)
+ {
+ cursor_next_line_move(p_cli);
+ }
+ else
+ {
+ /* Command execution */
+ cli_execute(p_cli);
+ }
+ cli_state_set(p_cli, NRF_CLI_STATE_ACTIVE);
+ return;
+ }
+ switch (data)
+ {
+ case NRF_CLI_VT100_ASCII_ESC: /* ESCAPE */
+ recieve_state_change(p_cli, NRF_CLI_RECEIVE_ESC);
+ break;
+ case '\0':
+ break;
+ case '\t': /* TAB */
+ if (cli_flag_echo_is_set(p_cli))
+ {
+ cli_tab_handle(p_cli);
+ }
+ break;
+ case NRF_CLI_VT100_ASCII_BSPACE: /* BACKSPACE */
+ if (cli_flag_echo_is_set(p_cli))
+ {
+ char_backspace(p_cli);
+ }
+ break;
+ case NRF_CLI_VT100_ASCII_DEL: /* DELETE */
+ if (cli_flag_echo_is_set(p_cli))
+ {
+ char_delete(p_cli);
+ }
+ break;
+ default:
+ if (isprint((int)data))
+ {
+ if (cli_flag_echo_is_set(p_cli))
+ {
+ char_insert(p_cli, data);
+ }
+ else
+ {
+ char_insert_echo_off(p_cli, data);
+ }
+ }
+ break;
+ }
+ break;
+ case NRF_CLI_RECEIVE_ESC:
+ if (data == '[')
+ {
+ recieve_state_change(p_cli, NRF_CLI_RECEIVE_ESC_SEQ);
+ }
+ else
+ {
+ recieve_state_change(p_cli, NRF_CLI_RECEIVE_DEFAULT);
+ }
+ break;
+ case NRF_CLI_RECEIVE_ESC_SEQ:
+ recieve_state_change(p_cli, NRF_CLI_RECEIVE_DEFAULT);
+
+ if (!cli_flag_echo_is_set(p_cli))
+ {
+ return;
+ }
+
+ switch (data)
+ {
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+ case 'A': /* UP arrow */
+ history_handle(p_cli, true);
+ break;
+ case 'B': /* DOWN arrow */
+ history_handle(p_cli, false);
+ break;
+#endif
+ case 'C': /* RIGHT arrow */
+ right_arrow_handle(p_cli);
+ break;
+ case 'D': /* LEFT arrow */
+ left_arrow_handle(p_cli);
+ break;
+ case 'F': /* END Button */
+ cursor_end_position_move(p_cli);
+ break;
+ case 'H': /* HOME Button */
+ cursor_home_position_move(p_cli);
+ break;
+ case 'L': /* INSERT Button */
+ p_cli->p_ctx->internal.flag.insert_mode ^= 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ recieve_state_change(p_cli, NRF_CLI_RECEIVE_DEFAULT);
+ break;
+ }
+ }
+}
+
+/* Function remove white chars from beginning and end of command buffer. */
+static void cmd_trim(nrf_cli_t const * p_cli)
+{
+ nrf_cli_cmd_len_t i = 0;
+
+ if (p_cli->p_ctx->cmd_buff[0] == '\0') /* no command in the buffer */
+ {
+ return;
+ }
+
+ /* Counting white characters starting from beginning of the command. */
+ while (isspace((int)p_cli->p_ctx->cmd_buff[i++]))
+ {
+ if (i == 0)
+ {
+ p_cli->p_ctx->cmd_buff[0] = '\0';
+ return;
+ }
+ }
+
+ /* Removing counted white characters. */
+ if (--i > 0)
+ {
+ memmove(p_cli->p_ctx->cmd_buff,
+ p_cli->p_ctx->cmd_buff + i,
+ (p_cli->p_ctx->cmd_buff_len + 1) - i); /* +1 for '\0' */
+ p_cli->p_ctx->cmd_buff_len = p_cli->p_ctx->cmd_buff_len - i;
+ p_cli->p_ctx->cmd_buff_pos = p_cli->p_ctx->cmd_buff_len;
+ }
+
+ /* Counting white characters starting from end of command. */
+ char * p_end = &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_len - 1];
+ i = 0;
+ while (isspace((int)*p_end))
+ {
+ ++i;
+ --p_end;
+ }
+
+ /* Removing counted white characters. */
+ if (p_end != &p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_len - 1])
+ {
+ p_cli->p_ctx->cmd_buff[p_cli->p_ctx->cmd_buff_len - i] = '\0';
+ p_cli->p_ctx->cmd_buff_len = p_cli->p_ctx->cmd_buff_len - i;
+ p_cli->p_ctx->cmd_buff_pos = p_cli->p_ctx->cmd_buff_len;
+ }
+}
+
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+static void spaces_trim(char * p_char)
+{
+ nrf_cli_cmd_len_t shift = 0;
+ nrf_cli_cmd_len_t len = cli_strlen(p_char);
+
+ if (p_char == NULL)
+ {
+ return;
+ }
+
+ for (nrf_cli_cmd_len_t i = 0; i < len - 1; i++)
+ {
+ if (isspace((int)p_char[i]))
+ {
+ for (nrf_cli_cmd_len_t j = i + 1; j < len; j++)
+ {
+ if (isspace((int)p_char[j]))
+ {
+ shift++;
+ continue;
+ }
+ if (shift > 0)
+ {
+ memmove(&p_char[i + 1], &p_char[j], len - shift + 1); // +1 for EOS
+ len -= shift;
+ shift = 0;
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* Adds new command and one space just before pattern */
+static bool command_to_tmp_buffer_add(nrf_cli_t const * p_cli,
+ char const * p_new_cmd,
+ char const * p_pattern)
+{
+ nrf_cli_cmd_len_t cmd_len = cli_strlen(p_new_cmd);
+ nrf_cli_cmd_len_t shift;
+ char * p_cmd_source_addr;
+
+ /* +1 for space */
+ if (((size_t)p_cli->p_ctx->cmd_tmp_buff_len + cmd_len + 1) > NRF_CLI_CMD_BUFF_SIZE)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_WARNING,
+ "Command buffer is too short to expand all commands matching "
+ "wildcard pattern\r\n");
+ return false;
+ }
+
+ p_cmd_source_addr = strstr(p_cli->p_ctx->temp_buff, p_pattern);
+
+ if (p_cmd_source_addr == NULL)
+ {
+ return false;
+ }
+
+ shift = cli_strlen(p_cmd_source_addr);
+
+ /* make place for new command: + 1 for space + 1 for EOS */
+ memmove(p_cmd_source_addr + cmd_len + 1, p_cmd_source_addr, shift + 1);
+ memcpy(p_cmd_source_addr, p_new_cmd, cmd_len);
+ p_cmd_source_addr[cmd_len] = ' ';
+
+ p_cli->p_ctx->cmd_tmp_buff_len += cmd_len + 1; // + 1 for space
+
+ return true;
+}
+
+/* removes pattern and following space */
+static void pattern_from_tmp_buffer_remove(nrf_cli_t const * p_cli,
+ char const * p_pattern)
+{
+ size_t shift;
+ char * p_pattern_addr = strstr(p_cli->p_ctx->temp_buff, p_pattern);
+
+ nrf_cli_cmd_len_t pattern_len = cli_strlen(p_pattern);
+
+ if (p_pattern_addr == NULL)
+ {
+ return;
+ }
+
+ if (p_pattern_addr > p_cli->p_ctx->temp_buff)
+ {
+ if (*(p_pattern_addr - 1) == ' ')
+ {
+ pattern_len++; /* space needs to be removed as well */
+ p_pattern_addr--; /* set pointer to space */
+ }
+ }
+
+ shift = cli_strlen(p_pattern_addr) - pattern_len + 1; /* +1 for EOS */
+ p_cli->p_ctx->cmd_tmp_buff_len -= pattern_len;
+
+ memmove(p_pattern_addr, p_pattern_addr + pattern_len, shift);
+}
+
+/**
+ * @internal @brief Function for searching and adding commands matching to wildcard pattern.
+ *
+ * This function is internal to nrf_cli module and shall be not called directly.
+ *
+ * @param[in/out] p_cli Pointer to the CLI instance.
+ * @param[in] p_cmd Pointer to command which will be processed
+ * @param[in] cmd_lvl Command level in the command tree.
+ * @param[in] p_pattern Pointer to wildcard pattern.
+ * @param[out] p_counter Number of found and added commands.
+ *
+ * @retval WILDCARD_CMD_ADDED All matching commands added to the buffer.
+ * @retval WILDCARD_CMD_ADDED_MISSING_SPACE Not all matching commands added because
+ * NRF_CLI_CMD_BUFF_SIZE is too small.
+ * @retval WILDCARD_CMD_NO_MATCH_FOUND No matching command found.
+ */
+static wildcard_cmd_status_t commands_expand(nrf_cli_t const * p_cli,
+ nrf_cli_cmd_entry_t const * p_cmd,
+ size_t cmd_lvl,
+ char * p_pattern,
+ size_t * p_counter)
+{
+ size_t cmd_idx = 0;
+ size_t counter = 0;
+ bool success = false;
+
+ nrf_cli_static_entry_t static_entry;
+ nrf_cli_static_entry_t const * p_static_entry = NULL;
+ wildcard_cmd_status_t ret_val = WILDCARD_CMD_NO_MATCH_FOUND;
+
+ do
+ {
+ cmd_get(p_cmd,
+ cmd_lvl,
+ cmd_idx++,
+ &p_static_entry,
+ &static_entry);
+
+ if (p_static_entry == NULL)
+ {
+ break;
+ }
+
+ if (0 == fnmatch(p_pattern, p_static_entry->p_syntax, 0))
+ {
+ success = command_to_tmp_buffer_add(p_cli,
+ p_static_entry->p_syntax,
+ p_pattern);
+ if (!success)
+ {
+ break;
+ }
+ counter++;
+ }
+
+ } while(cmd_idx != 0);
+
+ if (counter > 0)
+ {
+ *p_counter = counter;
+ pattern_from_tmp_buffer_remove(p_cli, p_pattern);
+
+ if (success)
+ {
+ ret_val = WILDCARD_CMD_ADDED;
+ }
+ else
+ {
+ ret_val = WILDCARD_CMD_ADDED_MISSING_SPACE;
+ }
+ }
+
+ return ret_val;
+}
+#endif // NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+
+/* Function is analyzing the command buffer to find matching commands. Next, it invokes the last recognized
+ * command which has a handler and passes the rest of command buffer as arguments. */
+static void cli_execute(nrf_cli_t const * p_cli)
+{
+ char quote;
+ size_t argc;
+ char * argv[NRF_CLI_ARGC_MAX + 1]; /* +1 reserved for NULL added by function make_argv */
+
+ size_t cmd_idx; /* currently analyzed command in cmd_level */
+ size_t cmd_lvl = NRF_CLI_CMD_ROOT_LVL; /* currently analyzed command level */
+ size_t cmd_handler_lvl = 0; /* last command level for which a handler has been found */
+ size_t cmd_handler_idx = 0; /* last command index for which a handler has been found */
+
+ nrf_cli_cmd_entry_t const * p_cmd = NULL;
+
+ cmd_trim(p_cli);
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+ history_save(p_cli);
+#endif
+
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+/* Wildcard can be correctly handled under following conditions:
+ - wildcard command does not have a handler
+ - wildcard command is on the deepest commands level
+ - other commands on the same level as wildcard command shall also not have a handler
+
+ Algorithm:
+ 1. Command buffer is copied to Temp buffer.
+ 2. Algorithm goes through Command buffer to find handlers and subcommands.
+ 3. If algorithm will find a wildcard character it switches to Temp buffer.
+ 4. In the Temp buffer command with found wildcard character is changed into matching command(s).
+ 5. Algorithm switch back to Command buffer and analyzes next command.
+ 6. When all arguments are analyzed from Command buffer, Temp buffer is copied to Command buffer.
+ 7. Last found handler is executed with all arguments in the Command buffer.
+*/
+ size_t commands_expanded = 0;
+
+ memset(p_cli->p_ctx->temp_buff, 0, sizeof(p_cli->p_ctx->temp_buff));
+ memcpy(p_cli->p_ctx->temp_buff,
+ p_cli->p_ctx->cmd_buff,
+ p_cli->p_ctx->cmd_buff_len);
+
+ /* Function spaces_trim must be used instead of make_argv. At this point it is important to keep
+ temp_buff as a one string. It will allow to find wildcard commands easly with strstr
+ function. */
+ spaces_trim(p_cli->p_ctx->temp_buff);
+ p_cli->p_ctx->cmd_tmp_buff_len = cli_strlen(p_cli->p_ctx->temp_buff) + 1; // +1 for EOS
+#endif
+
+ cursor_end_position_move(p_cli);
+ if (!cursor_in_empty_line(p_cli))
+ {
+ cursor_next_line_move(p_cli);
+ }
+
+ /* create argument list */
+ quote = make_argv(&argc,
+ &argv[0],
+ p_cli->p_ctx->cmd_buff,
+ NRF_CLI_ARGC_MAX);
+
+ if (!argc)
+ {
+ cursor_next_line_move(p_cli);
+ return;
+ }
+
+ if (quote != 0)
+ {
+ nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "not terminated: %c\r\n", quote);
+ return;
+ }
+
+ /* Searching for a matching root command. */
+ for (cmd_idx = 0; cmd_idx <= CLI_DATA_SECTION_ITEM_COUNT; ++cmd_idx)
+ {
+ if (cmd_idx >= CLI_DATA_SECTION_ITEM_COUNT)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_ERROR,
+ "%s%s\r\n",
+ argv[0],
+ NRF_CLI_MSG_COMMAND_NOT_FOUND);
+ return;
+ }
+
+ p_cmd = CLI_DATA_SECTION_ITEM_GET(cmd_idx);
+ if (strcmp(argv[cmd_lvl], p_cmd->u.p_static->p_syntax) != 0)
+ {
+ continue;
+ }
+ break;
+ }
+
+ /* Root command shall be always static. */
+ ASSERT(p_cmd->is_dynamic == false);
+
+ /* Pointer to the deepest command level with a handler. */
+ nrf_cli_cmd_entry_t const * p_cmd_low_level_entry = NULL;
+
+ /* Memory reserved for dynamic commands. */
+ nrf_cli_static_entry_t static_entry;
+ nrf_cli_static_entry_t const * p_static_entry = NULL;
+
+ nrf_cli_cmd_handler handler_cmd_lvl_0 = p_cmd->u.p_static->handler;
+ if (handler_cmd_lvl_0 != NULL)
+ {
+ p_cli->p_ctx->p_current_stcmd = p_cmd->u.p_static;
+ }
+
+ p_cmd = p_cmd->u.p_static->p_subcmd;
+ cmd_lvl++;
+ cmd_idx = 0;
+
+ while (1)
+ {
+ if (cmd_lvl >= argc)
+ {
+ break;
+ }
+
+ if (!strcmp(argv[cmd_lvl], "-h") || !strcmp(argv[cmd_lvl], "--help"))
+ {
+ /* Command called with help option so it makes no sense to search deeper commands. */
+ cli_flag_help_set(p_cli);
+ break;
+ }
+
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+ /* Wildcard character is found */
+ if (wildcard_character_exist(argv[cmd_lvl]))
+ {
+ size_t counter = 0;
+ wildcard_cmd_status_t status;
+
+ /* Function will search commands tree for commands matching wildcard pattern stored in
+ argv[cmd_lvl]. If match is found wildcard pattern will be replaced by matching
+ commands in temp_buffer. If there is no space to add all matching commands function
+ will add as many as possible. Next it will continue to search for next wildcard
+ pattern and it will try to add matching commands. */
+ status = commands_expand(p_cli, p_cmd, cmd_lvl, argv[cmd_lvl], &counter);
+ if (WILDCARD_CMD_NO_MATCH_FOUND == status)
+ {
+ break;
+ }
+ commands_expanded += counter;
+ cmd_lvl++;
+ continue;
+ }
+#endif
+
+ cmd_get(p_cmd,
+ cmd_lvl,
+ cmd_idx++,
+ &p_static_entry,
+ &static_entry);
+
+ if ((cmd_idx == 0) || (p_static_entry == NULL))
+ {
+ break;
+ }
+
+ if (strcmp(argv[cmd_lvl], p_static_entry->p_syntax) == 0)
+ {
+ /* checking if command has a handler */
+ if (p_static_entry->handler != NULL)
+ {
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+ if (commands_expanded > 0)
+ {
+ cursor_end_position_move(p_cli);
+ if (!cursor_in_empty_line(p_cli))
+ {
+ cursor_next_line_move(p_cli);
+ }
+ /* An error occured, fnmatch argument cannot be followed by argument
+ * with a handler to avoid multiple function calls. */
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_ERROR,
+ "Error: requested multiple function executions\r\n");
+ cli_flag_help_clear(p_cli);
+ return;
+ }
+#endif
+ /* Storing p_st_cmd->handler is not feasible for dynamic commands. Data will be
+ * invalid with the next loop iteration. */
+ cmd_handler_lvl = cmd_lvl;
+ cmd_handler_idx = cmd_idx - 1;
+ p_cmd_low_level_entry = p_cmd;
+ }
+ cmd_lvl++;
+ cmd_idx = 0;
+ p_cmd = p_static_entry->p_subcmd;
+ }
+ }
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+ if (commands_expanded > 0)
+ {
+ /* Copy temp_buff to cmd_buff */
+ memcpy(p_cli->p_ctx->cmd_buff,
+ p_cli->p_ctx->temp_buff,
+ p_cli->p_ctx->cmd_tmp_buff_len);
+ p_cli->p_ctx->cmd_buff_len = p_cli->p_ctx->cmd_tmp_buff_len;
+
+ /* calling make_arg function again because cmd_buffer has additional commads */
+ (void)make_argv(&argc,
+ &argv[0],
+ p_cli->p_ctx->cmd_buff,
+ NRF_CLI_ARGC_MAX);
+ }
+ #endif
+
+ /* Executing the deepest found handler. */
+ if (p_cmd_low_level_entry != NULL)
+ {
+ cmd_get(p_cmd_low_level_entry,
+ cmd_handler_lvl,
+ cmd_handler_idx,
+ &p_static_entry,
+ &static_entry);
+
+ p_cli->p_ctx->p_current_stcmd = p_static_entry;
+
+ p_cli->p_ctx->p_current_stcmd->handler(p_cli,
+ argc - cmd_handler_lvl,
+ &argv[cmd_handler_lvl]);
+ }
+ else if (handler_cmd_lvl_0 != NULL)
+ {
+ handler_cmd_lvl_0(p_cli, argc, &argv[0]);
+ }
+ else
+ {
+ nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, NRF_CLI_MSG_SPECIFY_SUBCOMMAND);
+ }
+ cli_flag_help_clear(p_cli);
+}
+
+/* Function required by qsort. */
+static int string_cmp(void const * pp_a, void const * pp_b)
+{
+ ASSERT(pp_a);
+ ASSERT(pp_b);
+
+ char const ** pp_str_a = (char const **)pp_a;
+ char const ** pp_str_b = (char const **)pp_b;
+
+ return strcmp(*pp_str_a, *pp_str_b);
+}
+
+static void cli_transport_evt_handler(nrf_cli_transport_evt_t evt_type, void * p_context)
+{
+ nrf_cli_t * p_cli = (nrf_cli_t *)p_context;
+ ASSERT(p_cli);
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+ task_events_set(p_cli->p_ctx->task_id, evt_type == NRF_CLI_TRANSPORT_EVT_RX_RDY ?
+ NRF_CLI_TRANSPORT_RX_RDY_TASK_EVT : NRF_CLI_TRANSPORT_TX_RDY_TASK_EVT);
+#else
+
+ if (evt_type == NRF_CLI_TRANSPORT_EVT_RX_RDY)
+ {
+
+ }
+ else
+ {
+ /* wr done evt */
+ p_cli->p_ctx->internal.flag.tx_rdy = 1;
+ }
+#endif
+}
+
+static ret_code_t nrf_cli_instance_init(nrf_cli_t const * p_cli,
+ void const * p_config,
+ bool use_colors)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+ ASSERT((p_cli->newline_char == '\n') || (p_cli->newline_char == '\r'));
+
+#if defined(NRF_CLI_LOG_BACKEND) && NRF_CLI_LOG_BACKEND
+ p_cli->p_log_backend->p_cli = p_cli;
+#endif
+ ret_code_t ret = p_cli->p_iface->p_api->init(p_cli->p_iface,
+ p_config,
+ cli_transport_evt_handler,
+ (void *)p_cli);
+ if (ret != NRF_SUCCESS)
+ {
+ return ret;
+ }
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+ ASSERT(p_cli->p_cmd_hist_mempool);
+ ret = nrf_memobj_pool_init(p_cli->p_cmd_hist_mempool);
+ if (ret != NRF_SUCCESS)
+ {
+ return ret;
+ }
+ p_cli->p_ctx->p_cmd_list_head = NULL;
+ p_cli->p_ctx->p_cmd_list_tail = NULL;
+#endif
+
+ memset(p_cli->p_ctx, 0, sizeof(nrf_cli_ctx_t));
+ p_cli->p_ctx->internal.flag.tx_rdy = 1;
+
+#if NRF_MODULE_ENABLED(NRF_CLI_VT100_COLORS)
+ p_cli->p_ctx->internal.flag.use_colors = use_colors;
+#endif
+ p_cli->p_ctx->internal.flag.echo = NRF_CLI_ECHO_STATUS;
+ p_cli->p_ctx->state = NRF_CLI_STATE_INITIALIZED;
+ p_cli->p_ctx->vt100_ctx.cons.terminal_wid = NRF_CLI_DEFAULT_TERMINAL_WIDTH;
+ p_cli->p_ctx->vt100_ctx.cons.terminal_hei = NRF_CLI_DEFAULT_TERMINAL_HEIGHT;
+
+ const char * * pp_sorted_cmds = (const char * *)CLI_SORTED_CMD_PTRS_START_ADDR_GET;
+ for (size_t i = 0; i < CLI_DATA_SECTION_ITEM_COUNT; i++)
+ {
+ const nrf_cli_cmd_entry_t * cmd;
+ cmd = CLI_DATA_SECTION_ITEM_GET(i);
+
+ /* NULL syntax commands not allowed. */
+ ASSERT(cmd);
+ ASSERT(cmd->u.p_static->p_syntax);
+
+ pp_sorted_cmds[i] = cmd->u.p_static->p_syntax;
+ }
+
+ if (CLI_DATA_SECTION_ITEM_COUNT > 0)
+ {
+ qsort(pp_sorted_cmds,
+ CLI_DATA_SECTION_ITEM_COUNT,
+ sizeof (char *),
+ string_cmp);
+ }
+
+ return NRF_SUCCESS;
+}
+
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+static ret_code_t nrf_cli_instance_uninit(nrf_cli_t const * p_cli);
+void console_task(void * p_context)
+{
+ nrf_cli_t * p_cli = (nrf_cli_t *)p_context;
+
+ ret_code_t ret = nrf_cli_start(p_cli);
+ APP_ERROR_CHECK(ret);
+
+ while (1)
+ {
+ uint32_t evts = task_events_wait(NRF_CLI_TASK_EVTS);
+
+ if (evts & NRF_CLI_KILL_TASK_EVT)
+ {
+ (void)nrf_cli_instance_uninit(p_cli);
+ task_exit();
+ }
+ else
+ {
+ nrf_cli_process(p_cli);
+ }
+ }
+}
+#endif
+
+ret_code_t nrf_cli_init(nrf_cli_t const * p_cli,
+ void const * p_config,
+ bool use_colors,
+ bool log_backend,
+ nrf_log_severity_t init_lvl)
+{
+ ASSERT(p_cli);
+
+ ret_code_t err_code = nrf_cli_instance_init(p_cli, p_config, use_colors);
+
+#if NRF_CLI_LOG_BACKEND && NRF_MODULE_ENABLED(NRF_LOG)
+ if ((err_code == NRF_SUCCESS) && log_backend && NRF_CLI_LOG_BACKEND)
+ {
+ int32_t id = nrf_log_backend_add(&p_cli->p_log_backend->backend, init_lvl);
+ if (id < 0)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ nrf_log_backend_enable(&p_cli->p_log_backend->backend);
+ }
+#endif
+ return err_code;
+}
+
+ret_code_t nrf_cli_task_create(nrf_cli_t const * p_cli)
+{
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+ p_cli->p_ctx->task_id = task_create(console_task, p_cli->p_name,(void *)p_cli);
+ if (p_cli->p_ctx->task_id == TASK_ID_INVALID)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+ else
+ {
+ return NRF_SUCCESS;
+ }
+#else
+ return NRF_ERROR_NOT_SUPPORTED;
+#endif
+}
+
+static ret_code_t nrf_cli_instance_uninit(nrf_cli_t const * p_cli)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+
+ if (cli_flag_processing_is_set(p_cli))
+ {
+ return NRF_ERROR_BUSY;
+ }
+
+#if NRF_CLI_LOG_BACKEND && NRF_MODULE_ENABLED(NRF_LOG)
+ if (p_cli->p_log_backend != NULL)
+ {
+ nrf_log_backend_disable(&p_cli->p_log_backend->backend);
+ nrf_log_backend_remove(&p_cli->p_log_backend->backend);
+ }
+#endif
+
+ ret_code_t ret = p_cli->p_iface->p_api->uninit(p_cli->p_iface);
+ if (ret != NRF_SUCCESS)
+ {
+ return ret;
+ }
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+ history_list_free_memory(p_cli);
+#endif
+
+ memset(p_cli->p_ctx, 0, sizeof(nrf_cli_ctx_t));
+ p_cli->p_ctx->state = NRF_CLI_STATE_UNINITIALIZED;
+
+ return NRF_SUCCESS;
+}
+
+ret_code_t nrf_cli_uninit(nrf_cli_t const * p_cli)
+{
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+ if (cli_flag_processing_is_set(p_cli))
+ {
+ return NRF_ERROR_BUSY;
+ }
+ task_events_set(p_cli->p_ctx->task_id, NRF_CLI_KILL_TASK_EVT);
+ return NRF_SUCCESS;
+#else
+ return nrf_cli_instance_uninit(p_cli);
+#endif
+}
+
+ret_code_t nrf_cli_start(nrf_cli_t const * p_cli)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+
+ if (p_cli->p_ctx->state != NRF_CLI_STATE_INITIALIZED)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+ void * p_context = (void *)((uint32_t)task_id_get());
+ p_cli->p_log_backend->p_context = p_context;
+#endif
+
+ ret_code_t err_code = p_cli->p_iface->p_api->enable(p_cli->p_iface, false);
+
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+ task_events_set(task_id_get(), NRF_CLI_TRANSPORT_RX_RDY_TASK_EVT);
+#endif
+
+ if (err_code == NRF_SUCCESS)
+ {
+#if NRF_CLI_VT100_COLORS_ENABLED
+ vt100_color_set(p_cli, NRF_CLI_NORMAL);
+ vt100_bgcolor_set(p_cli, NRF_CLI_VT100_COLOR_BLACK);
+#endif
+ nrf_fprintf(p_cli->p_fprintf_ctx, "\r\n\n");
+ cli_state_set(p_cli, NRF_CLI_STATE_ACTIVE);
+ }
+
+ return err_code;
+}
+
+ret_code_t nrf_cli_stop(nrf_cli_t const * p_cli)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+
+ if (p_cli->p_ctx->state == NRF_CLI_STATE_INITIALIZED ||
+ p_cli->p_ctx->state == NRF_CLI_STATE_UNINITIALIZED)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ cli_state_set(p_cli, NRF_CLI_STATE_INITIALIZED);
+ return NRF_SUCCESS;
+}
+
+void nrf_cli_process(nrf_cli_t const * p_cli)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+
+ nrf_cli_internal_t internal;
+ internal.value = 0;
+ internal.flag.processing = 1;
+ (void)nrf_atomic_u32_or((nrf_atomic_u32_t *)&p_cli->p_ctx->internal.value,
+ internal.value);
+
+ switch (p_cli->p_ctx->state)
+ {
+ case NRF_CLI_STATE_UNINITIALIZED:
+ case NRF_CLI_STATE_INITIALIZED:
+ /* Console initialized but not started. */
+ break;
+ case NRF_CLI_STATE_ACTIVE:
+ {
+ cli_state_collect(p_cli);
+ bool log_processed = cli_log_entry_process(p_cli, false);
+ if (log_processed)
+ {
+ nrf_cli_fprintf(p_cli, NRF_CLI_INFO, "%s", p_cli->p_name);
+ if (cli_flag_echo_is_set(p_cli))
+ {
+ nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%s", p_cli->p_ctx->cmd_buff);
+ cursor_position_synchronize(p_cli);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ transport_buffer_flush(p_cli);
+ internal.value = (uint32_t)0xFFFFFFFF;
+ internal.flag.processing = 0;
+ (void)nrf_atomic_u32_and((nrf_atomic_u32_t *)&p_cli->p_ctx->internal.value,
+ internal.value);
+}
+
+/* Function shall be only used by the nrf_fprintf module. */
+void nrf_cli_print_stream(void const * p_user_ctx, char const * p_data, size_t data_len)
+{
+ cli_write((nrf_cli_t const *)p_user_ctx,
+ p_data,
+ data_len,
+ NULL);
+}
+
+void nrf_cli_fprintf(nrf_cli_t const * p_cli,
+ nrf_cli_vt100_color_t color,
+ char const * p_fmt,
+ ...)
+{
+ ASSERT(p_fmt);
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+
+ va_list args = {0};
+ va_start(args, p_fmt);
+
+#if NRF_MODULE_ENABLED(NRF_CLI_VT100_COLORS)
+ if ((p_cli->p_ctx->internal.flag.use_colors) &&
+ (color != p_cli->p_ctx->vt100_ctx.col.col))
+ {
+ nrf_cli_vt100_colors_t col;
+
+ vt100_colors_store(p_cli, &col);
+ vt100_color_set(p_cli, color);
+
+ nrf_fprintf_fmt(p_cli->p_fprintf_ctx, p_fmt, &args);
+
+ vt100_colors_restore(p_cli, &col);
+ }
+ else
+#endif // NRF_MODULE_ENABLED(NRF_CLI_VT100_COLORS)
+ {
+ nrf_fprintf_fmt(p_cli->p_fprintf_ctx, p_fmt, &args);
+ }
+
+ va_end(args);
+}
+
+/* Function prints a string on terminal screen with requested margin.
+ * It takes care to not divide words.
+ * p_cli Pointer to CLI instance.
+ * p_str Pointer to string to be printed.
+ * terminal_offset Requested left margin.
+ * offset_first_line Add margin to the first printed line.
+ */
+static void format_offset_string_print(nrf_cli_t const * p_cli,
+ char const * p_str,
+ size_t terminal_offset,
+ bool offset_first_line)
+{
+ if (p_str == NULL)
+ {
+ return;
+ }
+
+ if (offset_first_line)
+ {
+ cursor_right_move(p_cli, terminal_offset);
+ }
+
+ size_t length;
+ size_t offset = 0;
+
+ /* Skipping whitespace. */
+ while (isspace((int)*(p_str + offset)))
+ {
+ ++offset;
+ }
+
+ while (1)
+ {
+ size_t idx = 0;
+ length = cli_strlen(p_str) - offset;
+
+ if (length <= p_cli->p_ctx->vt100_ctx.cons.terminal_wid - terminal_offset)
+ {
+ for (idx = 0; idx < length; idx++)
+ {
+ if (*(p_str + offset + idx) == '\n')
+ {
+ transport_buffer_flush(p_cli);
+ cli_write(p_cli, p_str + offset, idx, NULL);
+ offset += idx + 1;
+ cursor_next_line_move(p_cli);
+ cursor_right_move(p_cli, terminal_offset);
+ break;
+ }
+ }
+ /* String will fit in one line. */
+ nrf_fprintf(p_cli->p_fprintf_ctx, p_str + offset);
+ break;
+ }
+ else
+ {
+ /* String is longer than terminal line so text needs to divide in the way
+ to not divide words. */
+ length = p_cli->p_ctx->vt100_ctx.cons.terminal_wid - terminal_offset;
+
+ while (1)
+ {
+ /* Determining line break. */
+ if (isspace((int)(*(p_str + offset + idx))))
+ {
+ length = idx;
+ if (*(p_str + offset + idx) == '\n')
+ {
+ break;
+ }
+ }
+ if ((idx + terminal_offset) >= p_cli->p_ctx->vt100_ctx.cons.terminal_wid)
+ {
+ /* End of line reached. */
+ break;
+ }
+ ++idx;
+ }
+
+ /* Writing one line, fprintf IO buffer must be flushed before calling cli_write. */
+ transport_buffer_flush(p_cli);
+ cli_write(p_cli, p_str + offset, length, NULL);
+ offset += length;
+
+ /* Calculating text offset to ensure that next line will not begin with a space. */
+ while (isspace((int)(*(p_str + offset))))
+ {
+ ++offset;
+ }
+ cursor_next_line_move(p_cli);
+ cursor_right_move(p_cli, terminal_offset);
+ }
+ }
+ cursor_next_line_move(p_cli);
+}
+
+void nrf_cli_help_print(nrf_cli_t const * p_cli,
+ nrf_cli_getopt_option_t const * p_opt,
+ size_t opt_len)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+
+ static uint8_t const tab_len = 2;
+ static char const opt_sep[] =", "; /* options separator */
+ static char const help[] = "-h, --help";
+ static char const cmd_sep[] = " - "; /* command separator */
+ uint16_t field_width = 0;
+ uint16_t longest_string = cli_strlen(help) - cli_strlen(opt_sep);
+
+ /* Printing help string for command. */
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "%s%s",
+ p_cli->p_ctx->p_current_stcmd->p_syntax,
+ cmd_sep);
+
+ field_width = cli_strlen(p_cli->p_ctx->p_current_stcmd->p_syntax) + cli_strlen(cmd_sep);
+ format_offset_string_print(p_cli, p_cli->p_ctx->p_current_stcmd->p_help, field_width, false);
+
+ nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Options:\r\n");
+
+ /* Looking for the longest option string. */
+ if ((opt_len > 0) && (p_opt != NULL))
+ {
+ for (size_t i = 0; i < opt_len; ++i)
+ {
+ if (cli_strlen(p_opt[i].p_optname_short) + cli_strlen(p_opt[i].p_optname)
+ > longest_string)
+ {
+ longest_string = cli_strlen(p_opt[i].p_optname_short)
+ + cli_strlen(p_opt[i].p_optname);
+ }
+ }
+ }
+ longest_string += cli_strlen(opt_sep) + tab_len;
+
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ " %-*s:",
+ longest_string,
+ help);
+
+ /* Print help string for options (only -h and --help). */
+ field_width = longest_string + tab_len + 1; /* tab_len + 1 == " " and ':' from: " %-*s:" */
+ format_offset_string_print(p_cli, "Show command help.", field_width, false);
+
+ /* Formating and printing all available options (except -h, --help). */
+ if (p_opt != NULL)
+ {
+ for (size_t i = 0; i < opt_len; ++i)
+ {
+ if ((p_opt[i].p_optname_short != NULL) && (p_opt[i].p_optname != NULL))
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ " %s%s%s",
+ p_opt[i].p_optname_short,
+ opt_sep,
+ p_opt[i].p_optname);
+ field_width = longest_string + tab_len;
+ cursor_right_move(p_cli,
+ field_width - ( cli_strlen(p_opt[i].p_optname_short)
+ + cli_strlen(p_opt[i].p_optname)
+ + tab_len
+ + cli_strlen(opt_sep)));
+ cli_putc(p_cli, ':');
+ ++field_width; /* incrementing because char ':' was already printed above */
+ }
+ else if (p_opt[i].p_optname_short != NULL)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ " %-*s:",
+ longest_string,
+ p_opt[i].p_optname_short);
+ /* tab_len + 1 == " " and ':' from: " %-*s:" */
+ field_width = longest_string + tab_len + 1;
+ }
+ else if (p_opt[i].p_optname != NULL)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ " %-*s:",
+ longest_string,
+ p_opt[i].p_optname);
+ /* tab_len + 1 == " " and ':' from: " %-*s:" */
+ field_width = longest_string + tab_len + 1;
+ }
+ else
+ {
+ /* Do nothing. */
+ }
+
+ if (p_opt[i].p_optname_help != NULL)
+ {
+ format_offset_string_print(p_cli, p_opt[i].p_optname_help, field_width, false);
+ }
+ else
+ {
+ cursor_next_line_move(p_cli);
+ }
+ }
+ }
+
+ /* Checking if there are any subcommands avilable. */
+ if (p_cli->p_ctx->p_current_stcmd->p_subcmd == NULL)
+ {
+ return;
+ }
+
+ /* Printing formatted help of one level deeper subcommands. */
+ nrf_cli_static_entry_t static_entry;
+ nrf_cli_cmd_entry_t const * p_cmd = p_cli->p_ctx->p_current_stcmd->p_subcmd;
+ nrf_cli_static_entry_t const * p_st_cmd = NULL;
+
+ field_width = 0;
+ longest_string = 0;
+
+ size_t cmd_idx = 0;
+
+ /* Searching for the longest subcommand to print. */
+ while (1)
+ {
+ cmd_get(p_cmd, !NRF_CLI_CMD_ROOT_LVL, cmd_idx++, &p_st_cmd, &static_entry);
+
+ if (p_st_cmd == NULL)
+ {
+ break;
+ }
+ if (cli_strlen(p_st_cmd->p_syntax) > longest_string)
+ {
+ longest_string = cli_strlen(p_st_cmd->p_syntax);
+ }
+ }
+
+ /* Checking if there are dynamic subcommands. */
+ if (cmd_idx == 1)
+ {
+ /* No dynamic subcommands available. */
+ return;
+ }
+
+ nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Subcommands:\r\n");
+
+ /* Printing subcommands and help string (if exists). */
+ cmd_idx = 0;
+ while (1)
+ {
+ cmd_get(p_cmd, !NRF_CLI_CMD_ROOT_LVL, cmd_idx++, &p_st_cmd, &static_entry);
+
+ if (p_st_cmd == NULL)
+ {
+ break;
+ }
+
+ field_width = longest_string + tab_len;
+ nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL," %-*s:", field_width, p_st_cmd->p_syntax);
+ field_width += tab_len + 1; /* tab_len + 1 == " " and ':' from: " %-*s:" */
+
+ if (p_st_cmd->p_help != NULL)
+ {
+ format_offset_string_print(p_cli, p_st_cmd->p_help, field_width, false);
+ }
+ else
+ {
+ cursor_next_line_move(p_cli);
+ }
+ }
+}
+
+#if NRF_CLI_LOG_BACKEND && NRF_MODULE_ENABLED(NRF_LOG)
+
+#define NRF_CLI_LOG_MSG_OVERFLOW_MSK ((uint32_t)7)
+static bool cli_log_entry_process(nrf_cli_t const * p_cli, bool skip)
+{
+ nrf_log_entry_t entry;
+
+#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+ bool print_msg = false;
+#endif
+
+ if (nrf_queue_pop(p_cli->p_log_backend->p_queue, &entry) != NRF_SUCCESS)
+ {
+ return false;
+ }
+
+ if (skip)
+ {
+ nrf_memobj_put(entry);
+#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+ ++p_cli->p_ctx->statistics.log_lost_cnt;
+ if ((p_cli->p_ctx->statistics.log_lost_cnt & NRF_CLI_LOG_MSG_OVERFLOW_MSK) == 1)
+ {
+ /* Set flag to print a message after clearing the currently entered command. */
+ print_msg = true;
+ }
+ else
+#endif
+ {
+ return true;
+ }
+ }
+ {
+ /* Erasing the currently displayed command and console name. */
+ nrf_cli_multiline_cons_t const * p_cons = multiline_console_data_check(p_cli);
+
+ if (p_cons->cur_y > NRF_CLI_INITIAL_CURS_POS)
+ {
+ cursor_up_move(p_cli, p_cons->cur_y - NRF_CLI_INITIAL_CURS_POS);
+ }
+
+ if (p_cons->cur_x > NRF_CLI_INITIAL_CURS_POS)
+ {
+ cursor_left_move(p_cli, p_cons->cur_x - NRF_CLI_INITIAL_CURS_POS);
+ }
+ cli_clear_eos(p_cli);
+ }
+
+#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+ if (print_msg)
+ {
+ /* Print the requested string and exit function. */
+ nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "Lost logs - increase log backend queue size.\r\n");
+
+ return true;
+ }
+#endif
+
+ /* Printing logs from the queue. */
+ do
+ {
+ nrf_log_header_t header;
+ uint32_t memobj_offset = 0;
+ nrf_log_str_formatter_entry_params_t params;
+
+ nrf_memobj_read(entry, &header, HEADER_SIZE*sizeof(uint32_t), memobj_offset);
+ memobj_offset = HEADER_SIZE * sizeof(uint32_t);
+
+ params.timestamp = header.timestamp;
+ params.module_id = header.module_id;
+ params.dropped = header.dropped;
+ params.use_colors = NRF_LOG_USES_COLORS; /* Color will be provided by the console application. */
+
+ if (header.base.generic.type == HEADER_TYPE_STD)
+ {
+ char const * p_log_str = (char const *)((uint32_t)header.base.std.addr);
+ params.severity = (nrf_log_severity_t)header.base.std.severity;
+ uint32_t nargs = header.base.std.nargs;
+ uint32_t args[6];
+
+ nrf_memobj_read(entry, args, nargs*sizeof(uint32_t), memobj_offset);
+ nrf_log_std_entry_process(p_log_str,
+ args,
+ nargs,
+ &params,
+ p_cli->p_fprintf_ctx);
+ }
+ else if (header.base.generic.type == HEADER_TYPE_HEXDUMP)
+ {
+ uint32_t data_len;
+ uint8_t data_buf[8];
+ uint32_t chunk_len;
+
+ data_len = header.base.hexdump.len;
+ params.severity = (nrf_log_severity_t)header.base.hexdump.severity;
+
+ do
+ {
+ chunk_len = sizeof(data_buf) > data_len ? data_len : sizeof(data_buf);
+ nrf_memobj_read(entry, data_buf, chunk_len, memobj_offset);
+ memobj_offset += chunk_len;
+ data_len -= chunk_len;
+ nrf_log_hexdump_entry_process(data_buf, chunk_len, &params, p_cli->p_fprintf_ctx);
+ } while (data_len > 0);
+ }
+
+ nrf_memobj_put(entry);
+ } while (nrf_queue_pop(p_cli->p_log_backend->p_queue, &entry) == NRF_SUCCESS);
+ return true;
+}
+
+static void nrf_log_backend_cli_put(nrf_log_backend_t const * p_backend, nrf_log_entry_t * p_msg)
+{
+ nrf_cli_log_backend_t * p_backend_cli = CONTAINER_OF(p_backend, nrf_cli_log_backend_t, backend);
+ nrf_cli_t const * p_cli = p_backend_cli->p_cli;
+
+ //If panic mode cannot be handled, stop handling new requests.
+ if (p_cli->p_ctx->state != NRF_CLI_STATE_PANIC_MODE_INACTIVE)
+ {
+ bool panic_mode = (p_cli->p_ctx->state == NRF_CLI_STATE_PANIC_MODE_ACTIVE);
+ //If there is no place for a new log entry, remove the oldest one.
+ ret_code_t err_code = nrf_queue_push(p_backend_cli->p_queue, &p_msg);
+ while (err_code != NRF_SUCCESS)
+ {
+ (void)cli_log_entry_process(p_cli, panic_mode ? false : true);
+
+ err_code = nrf_queue_push(p_backend_cli->p_queue, &p_msg);
+ }
+ nrf_memobj_get(p_msg);
+
+ if (panic_mode)
+ {
+ (void)cli_log_entry_process(p_cli, false);
+ }
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+ else
+ {
+ task_events_set((task_id_t)((uint32_t)p_backend_cli->p_context & 0x000000FF),
+ NRF_CLI_LOG_PENDING_TASK_EVT);
+ }
+#endif
+ }
+}
+
+static void nrf_log_backend_cli_flush(nrf_log_backend_t const * p_backend)
+{
+ nrf_cli_log_backend_t * p_backend_cli;
+ nrf_cli_t const * p_cli;
+ nrf_log_entry_t * p_msg;
+
+ p_backend_cli = CONTAINER_OF(p_backend, nrf_cli_log_backend_t, backend);
+ p_cli = p_backend_cli->p_cli;
+
+ if (nrf_queue_pop(p_backend_cli->p_queue, &p_msg) == NRF_SUCCESS)
+ {
+ (void)cli_log_entry_process(p_cli, false);
+ }
+ UNUSED_PARAMETER(p_backend);
+}
+
+static void nrf_log_backend_cli_panic_set(nrf_log_backend_t const * p_backend)
+{
+ nrf_cli_log_backend_t * p_backend_cli = CONTAINER_OF(p_backend, nrf_cli_log_backend_t, backend);
+ nrf_cli_t const * p_cli = p_backend_cli->p_cli;
+
+ if (p_cli->p_iface->p_api->enable(p_cli->p_iface, true) == NRF_SUCCESS)
+ {
+ p_cli->p_ctx->state = NRF_CLI_STATE_PANIC_MODE_ACTIVE;
+ }
+ else
+ {
+ p_cli->p_ctx->state = NRF_CLI_STATE_PANIC_MODE_INACTIVE;
+ }
+}
+
+const nrf_log_backend_api_t nrf_log_backend_cli_api = {
+ .put = nrf_log_backend_cli_put,
+ .flush = nrf_log_backend_cli_flush,
+ .panic_set = nrf_log_backend_cli_panic_set,
+};
+#else
+static bool cli_log_entry_process(nrf_cli_t const * p_cli, bool skip)
+{
+ UNUSED_PARAMETER(p_cli);
+ UNUSED_PARAMETER(skip);
+ return false;
+}
+#endif // NRF_CLI_LOG_BACKEND
+
+/* ============ built-in commands ============ */
+#if NRF_MODULE_ENABLED(NRF_CLI_BUILD_IN_CMDS)
+
+static bool nrf_cli_build_in_cmd_common_executed(nrf_cli_t const * p_cli,
+ bool arg_cnt_nok,
+ nrf_cli_getopt_option_t const * p_opt,
+ size_t opt_len)
+{
+ if (nrf_cli_help_requested(p_cli))
+ {
+ nrf_cli_help_print(p_cli, p_opt, opt_len);
+ return true;
+ }
+
+ if (arg_cnt_nok)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_ERROR,
+ "%s: wrong parameter count\r\n",
+ p_cli->p_ctx->p_current_stcmd->p_syntax);
+ return true;
+ }
+
+ return false;
+}
+
+static void nrf_cli_cmd_clear(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+ UNUSED_PARAMETER(argv);
+
+ if ((argc == 2) && (nrf_cli_help_requested(p_cli)))
+ {
+ nrf_cli_help_print(p_cli, NULL, 0);
+ return;
+ }
+ NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_CURSORHOME);
+ NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_CLEARSCREEN);
+}
+
+static void nrf_cli_cmd_cli(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+ UNUSED_PARAMETER(argv);
+
+ if ((argc == 1) || ((argc == 2) && nrf_cli_help_requested(p_cli)) )
+ {
+ nrf_cli_help_print(p_cli, NULL, 0);
+ return;
+ }
+ nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, NRF_CLI_MSG_SPECIFY_SUBCOMMAND);
+}
+
+#if NRF_MODULE_ENABLED(NRF_CLI_VT100_COLORS)
+static void nrf_cli_cmd_colors_off(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != 1), NULL, 0))
+ {
+ return;
+ }
+ p_cli->p_ctx->internal.flag.use_colors = 0;
+}
+
+static void nrf_cli_cmd_colors_on(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != 1), NULL, 0))
+ {
+ return;
+ }
+ p_cli->p_ctx->internal.flag.use_colors = 1;
+}
+
+static void nrf_cli_cmd_colors(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+
+ if (argc == 1)
+ {
+ nrf_cli_help_print(p_cli, NULL, 0);
+ return;
+ }
+
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != 2), NULL, 0))
+ {
+ return;
+ }
+
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_ERROR,
+ "%s:%s%s\r\n",
+ argv[0],
+ NRF_CLI_MSG_UNKNOWN_PARAMETER,
+ argv[1]);
+}
+#endif // NRF_MODULE_ENABLED(NRF_CLI_VT100_COLORS)
+
+static void nrf_cli_cmd_echo(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc > 2), NULL, 0))
+ {
+ return;
+ }
+
+ if (argc == 2)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_ERROR,
+ "%s:%s%s\r\n",
+ argv[0],
+ NRF_CLI_MSG_UNKNOWN_PARAMETER,
+ argv[1]);
+ return;
+ }
+
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "Echo status: %s\r\n",
+ cli_flag_echo_is_set(p_cli) ? "on" : "off");
+}
+
+static void nrf_cli_cmd_echo_off(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != 1), NULL, 0))
+ {
+ return;
+ }
+
+ cli_flag_echo_clear(p_cli);
+}
+
+static void nrf_cli_cmd_echo_on(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != 1), NULL, 0))
+ {
+ return;
+ }
+
+ cli_flag_echo_set(p_cli);
+}
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+static void nrf_cli_cmd_history(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != 1), NULL, 0))
+ {
+ return;
+ }
+
+ size_t i = 0;
+ nrf_memobj_t const * p_cmd_list = p_cli->p_ctx->p_cmd_list_tail;
+ nrf_cli_memobj_header_t header;
+
+ while (1)
+ {
+ if ((p_cmd_list == NULL) || (i >= NRF_CLI_HISTORY_ELEMENT_COUNT))
+ {
+ break;
+ }
+ nrf_memobj_read((nrf_memobj_t * )p_cmd_list,
+ &header,
+ NRF_CLI_HISTORY_HEADER_SIZE,
+ (uint32_t)0);
+ nrf_memobj_read((nrf_memobj_t * )p_cmd_list,
+ p_cli->p_ctx->temp_buff,
+ header.cmd_len + 1,
+ (uint32_t)NRF_CLI_HISTORY_HEADER_SIZE);
+ p_cmd_list = header.p_next;
+ nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "[%3d] %s\r\n", i++, p_cli->p_ctx->temp_buff);
+ }
+ p_cli->p_ctx->temp_buff[0] = '\0';
+}
+#endif // NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+
+#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+void nrf_cli_cmd_cli_stats(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (argc == 1)
+ {
+ nrf_cli_help_print(p_cli, NULL, 0);
+ return;
+ }
+
+ if (argc == 2)
+ {
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_ERROR,
+ "%s:%s%s\r\n",
+ argv[0],
+ NRF_CLI_MSG_UNKNOWN_PARAMETER,
+ argv[1]);
+ return;
+ }
+
+ UNUSED_RETURN_VALUE(nrf_cli_build_in_cmd_common_executed(p_cli, (argc > 2), NULL, 0));
+}
+
+void nrf_cli_cmd_cli_stats_show(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != 1), NULL, 0))
+ {
+ return;
+ }
+
+ uint8_t max_util = nrf_queue_max_utilization_get(p_cli->p_log_backend->p_queue);
+ uint8_t utilization = (uint8_t)(max_util * 100ul / p_cli->p_log_backend->p_queue->size);
+
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_NORMAL,
+ "Lost logs: %u\r\n"
+ "Max log queue utilization: %u%% [%u/%u]\r\n",
+ p_cli->p_ctx->statistics.log_lost_cnt,
+ utilization,
+ max_util,
+ p_cli->p_log_backend->p_queue->size);
+}
+
+void nrf_cli_cmd_cli_stats_reset(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != 1), NULL, 0))
+ {
+ return;
+ }
+
+ p_cli->p_ctx->statistics.log_lost_cnt = 0;
+ nrf_queue_max_utilization_reset(p_cli->p_log_backend->p_queue);
+}
+#endif // NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+
+static void nrf_cli_cmd_resize_default(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != 1), NULL, 0))
+ {
+ return;
+ }
+
+ NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_SETCOL_80);
+ p_cli->p_ctx->vt100_ctx.cons.terminal_wid = NRF_CLI_DEFAULT_TERMINAL_WIDTH;
+ p_cli->p_ctx->vt100_ctx.cons.terminal_hei = NRF_CLI_DEFAULT_TERMINAL_HEIGHT;
+}
+
+static void nrf_cli_cmd_resize(nrf_cli_t const * p_cli, size_t argc, char **argv)
+{
+ ASSERT(p_cli);
+ ASSERT(p_cli->p_ctx && p_cli->p_iface && p_cli->p_name);
+
+ if (argc == 1)
+ {
+ if (terminal_size_get(p_cli,
+ &p_cli->p_ctx->vt100_ctx.cons.terminal_wid,
+ &p_cli->p_ctx->vt100_ctx.cons.terminal_hei) != NRF_SUCCESS)
+ {
+ p_cli->p_ctx->vt100_ctx.cons.terminal_wid = NRF_CLI_DEFAULT_TERMINAL_WIDTH;
+ p_cli->p_ctx->vt100_ctx.cons.terminal_hei = NRF_CLI_DEFAULT_TERMINAL_HEIGHT;
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_WARNING,
+ "No response from the terminal, assumed 80x24 screen size\r\n");
+ }
+ return;
+ }
+
+ if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc > 2), NULL, 0))
+ {
+ return;
+ }
+
+ nrf_cli_fprintf(p_cli,
+ NRF_CLI_ERROR,
+ "%s:%s%s\r\n",
+ argv[0],
+ NRF_CLI_MSG_UNKNOWN_PARAMETER,
+ argv[1]);
+}
+
+#if NRF_MODULE_ENABLED(NRF_CLI_VT100_COLORS)
+NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_colors)
+{
+ NRF_CLI_CMD(off, NULL, NRF_CLI_HELP_COLORS_OFF, nrf_cli_cmd_colors_off),
+ NRF_CLI_CMD(on, NULL, NRF_CLI_HELP_COLORS_ON, nrf_cli_cmd_colors_on),
+ NRF_CLI_SUBCMD_SET_END
+};
+#endif
+
+NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_echo)
+{
+ NRF_CLI_CMD(off, NULL, NRF_CLI_HELP_ECHO_OFF, nrf_cli_cmd_echo_off),
+ NRF_CLI_CMD(on, NULL, NRF_CLI_HELP_ECHO_ON, nrf_cli_cmd_echo_on),
+ NRF_CLI_SUBCMD_SET_END
+};
+
+#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_cli_stats)
+{
+ NRF_CLI_CMD(reset, NULL, NRF_CLI_HELP_STATISTICS_RESET, nrf_cli_cmd_cli_stats_reset),
+ NRF_CLI_CMD(show, NULL, NRF_CLI_HELP_STATISTICS_SHOW, nrf_cli_cmd_cli_stats_show),
+ NRF_CLI_SUBCMD_SET_END
+};
+#endif // NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+
+NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_cli)
+{
+#if NRF_MODULE_ENABLED(NRF_CLI_VT100_COLORS)
+ NRF_CLI_CMD(colors, &m_sub_colors, NRF_CLI_HELP_COLORS, nrf_cli_cmd_colors),
+#endif
+ NRF_CLI_CMD(echo, &m_sub_echo, NRF_CLI_HELP_ECHO, nrf_cli_cmd_echo),
+#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+ NRF_CLI_CMD(stats, &m_sub_cli_stats, NRF_CLI_HELP_STATISTICS, nrf_cli_cmd_cli_stats),
+#endif
+ NRF_CLI_SUBCMD_SET_END
+};
+
+NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_resize)
+{
+ NRF_CLI_CMD(default, NULL, NRF_CLI_HELP_RESIZE_DEFAULT, nrf_cli_cmd_resize_default),
+ NRF_CLI_SUBCMD_SET_END
+};
+
+NRF_CLI_CMD_REGISTER(clear, NULL, NRF_CLI_HELP_CLEAR, nrf_cli_cmd_clear);
+NRF_CLI_CMD_REGISTER(cli, &m_sub_cli, NRF_CLI_HELP_CLI, nrf_cli_cmd_cli);
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+NRF_CLI_CMD_REGISTER(history, NULL, NRF_CLI_HELP_HISTORY, nrf_cli_cmd_history);
+#endif
+NRF_CLI_CMD_REGISTER(resize, &m_sub_resize, NRF_CLI_HELP_RESIZE, nrf_cli_cmd_resize);
+
+#endif // NRF_MODULE_ENABLED(NRF_CLI_BUILD_IN_CMDS)
+
+#endif // NRF_MODULE_ENABLED(NRF_CLI)
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli.h
new file mode 100644
index 0000000..480b453
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli.h
@@ -0,0 +1,636 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NRF_CLI_H__
+#define NRF_CLI_H__
+
+#include "sdk_common.h"
+#include "nrf_cli_types.h"
+#include "nrf_section.h"
+#include "nrf_log_backend_interface.h"
+#include "nrf_queue.h"
+#include "nrf_log_ctrl.h"
+#include "app_util_platform.h"
+
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+#include "task_manager.h"
+#endif
+
+#include "nrf_fprintf.h"
+#include "nrf_fprintf_format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NRF_CLI_RX_BUFF_SIZE 16
+
+/* CLI reserves top task manager flags, bits 0...18 are available for application. */
+#define NRF_CLI_TRANSPORT_TX_RDY_TASK_EVT (1UL << 19)
+#define NRF_CLI_TRANSPORT_RX_RDY_TASK_EVT (1UL << 20)
+#define NRF_CLI_LOG_PENDING_TASK_EVT (1UL << 21)
+#define NRF_CLI_CMD_EXECUTE_EVT (1UL << 22)
+#define NRF_CLI_KILL_TASK_EVT (1UL << 23)
+
+#define NRF_CLI_TASK_EVTS (NRF_CLI_TRANSPORT_TX_RDY_TASK_EVT | \
+ NRF_CLI_TRANSPORT_RX_RDY_TASK_EVT | \
+ NRF_CLI_LOG_PENDING_TASK_EVT | \
+ NRF_CLI_CMD_EXECUTE_EVT | \
+ NRF_CLI_KILL_TASK_EVT)
+/**
+ * @defgroup nrf_cli Command Line Interface
+ * @ingroup app_common
+ *
+ * @brief Module for unified command line handling.
+ *
+ * @{
+ */
+
+/**
+ * @brief Aliases to: @ref nrf_cli, @ref nrf_cli_cmd_entry, and @ref nrf_cli_static_entry.
+ * Must be created here to satisfy module declaration order dependencies.
+ */
+typedef struct nrf_cli nrf_cli_t;
+typedef struct nrf_cli_cmd_entry nrf_cli_cmd_entry_t;
+typedef struct nrf_cli_static_entry nrf_cli_static_entry_t;
+
+/**
+ * @brief CLI dynamic command descriptor.
+ *
+ * @details Function shall fill the received @ref nrf_cli_static_entry structure with requested (idx)
+ * dynamic subcommand data. If there is more than one dynamic subcommand available,
+ * the function shall ensure that the returned commands: p_static->p_syntax are sorted in
+ * alphabetical order. If idx exceeds the available dynamic subcommands, the function must write
+ * to p_static->p_syntax NULL value. This will indicate to the CLI module that
+ * there are no more dynamic commands to read.
+ */
+typedef void (*nrf_cli_dynamic_get)(size_t idx, nrf_cli_static_entry_t * p_static);
+
+/**
+ * @brief CLI command descriptor.
+ */
+struct nrf_cli_cmd_entry
+{
+ bool is_dynamic;
+ union
+ {
+ nrf_cli_dynamic_get p_dynamic_get; //!< Pointer to function returning dynamic commands.
+ nrf_cli_static_entry_t const * p_static; //!< Pointer to array of static commands.
+ } u;
+};
+
+/**
+ * @brief CLI command handler prototype.
+ */
+typedef void (*nrf_cli_cmd_handler)(nrf_cli_t const * p_cli, size_t argc, char **argv);
+
+/**
+ * @brief CLI static command descriptor.
+ */
+struct nrf_cli_static_entry
+{
+ char const * p_syntax; //!< Command syntax strings.
+ char const * p_help; //!< Command help string.
+
+ nrf_cli_cmd_entry_t const * p_subcmd; //!< Pointer to subcommand.
+
+ nrf_cli_cmd_handler handler; //!< Command handler.
+};
+
+/**
+ * @brief Macro for defining and adding a root command (level 0).
+ *
+ * @note Each root command shall have unique syntax.
+ *
+ * @param[in] p_syntax Command syntax (for example: history).
+ * @param[in] p_subcmd Pointer to a subcommands array.
+ * @param[in] p_help Pointer to a command help string.
+ * @param[in] p_handler Pointer to a function handler.
+ */
+#define NRF_CLI_CMD_REGISTER(p_syntax, p_subcmd, p_help, p_handler) \
+ nrf_cli_static_entry_t const CONCAT_3(nrf_cli_, p_syntax, _raw) = \
+ NRF_CLI_CMD(p_syntax, p_subcmd, p_help, p_handler); \
+ NRF_SECTION_ITEM_REGISTER(cli_command, \
+ nrf_cli_cmd_entry_t const CONCAT_3(nrf_cli_, p_syntax, _const)) = { \
+ .is_dynamic = false, \
+ .u.p_static = &CONCAT_3(nrf_cli_, p_syntax, _raw) \
+ }; \
+ NRF_SECTION_ITEM_REGISTER(cli_sorted_cmd_ptrs, char const * CONCAT_2(p_syntax, _str_ptr))
+
+/**
+ * @brief Macro for creating a subcommand set. It must be used outside of any function body.
+ *
+ * @param[in] name Name of the subcommand set.
+ */
+#define NRF_CLI_CREATE_STATIC_SUBCMD_SET(name) \
+ /*lint -save -e85 -e31*/ \
+ static nrf_cli_static_entry_t const CONCAT_2(name, _raw)[]; \
+ static nrf_cli_cmd_entry_t const name = { \
+ .is_dynamic = false, \
+ .u.p_static = CONCAT_2(name, _raw) \
+ }; \
+ static nrf_cli_static_entry_t const CONCAT_2(name, _raw)[] = /*lint -restore*/
+
+/**
+ * @brief Define ending subcommands set.
+ *
+ */
+#define NRF_CLI_SUBCMD_SET_END {NULL}
+
+/**
+ * @brief Macro for creating a dynamic entry.
+ *
+ * @param[in] name Name of the dynamic entry.
+ * @param[in] p_get Pointer to the function returning dynamic commands array @ref nrf_cli_dynamic_get.
+ */
+#define NRF_CLI_CREATE_DYNAMIC_CMD(name, p_get) \
+ /*lint -save -e19*/ \
+ static nrf_cli_cmd_entry_t const name = { \
+ .is_dynamic = true, \
+ .u.p_dynamic_get = p_get \
+}; /*lint -restore*/
+
+/**
+ * @brief Initializes a CLI command (@ref nrf_cli_static_entry).
+ *
+ * @param[in] _p_syntax Command syntax (for example: history).
+ * @param[in] _p_subcmd Pointer to a subcommands array.
+ * @param[in] _p_help Pointer to a command help string.
+ * @param[in] _p_handler Pointer to a function handler.
+ */
+#define NRF_CLI_CMD(_p_syntax, _p_subcmd, _p_help, _p_handler) { \
+ .p_syntax = (const char *) STRINGIFY(_p_syntax), \
+ .p_subcmd = _p_subcmd, \
+ .p_help = (const char *) _p_help, \
+ .handler = _p_handler \
+}
+
+/**
+ * @internal @brief Internal CLI state in response to data received from the terminal.
+ */
+typedef enum
+{
+ NRF_CLI_RECEIVE_DEFAULT,
+ NRF_CLI_RECEIVE_ESC,
+ NRF_CLI_RECEIVE_ESC_SEQ
+} nrf_cli_receive_t;
+
+
+/**
+ * @internal @brief Internal CLI state.
+ */
+typedef enum
+{
+ NRF_CLI_STATE_UNINITIALIZED, //!< State uninitialized.
+ NRF_CLI_STATE_INITIALIZED, //!< State initialized but not active.
+ NRF_CLI_STATE_ACTIVE, //!< State active.
+ NRF_CLI_STATE_PANIC_MODE_ACTIVE, //!< State panic mode activated.
+ NRF_CLI_STATE_PANIC_MODE_INACTIVE //!< State panic mode requested but not supported.
+} nrf_cli_state_t;
+
+/**
+ * @brief Event type from CLI transport.
+ */
+typedef enum
+{
+ NRF_CLI_TRANSPORT_EVT_RX_RDY,
+ NRF_CLI_TRANSPORT_EVT_TX_RDY
+} nrf_cli_transport_evt_t;
+
+typedef void (*nrf_cli_transport_handler_t)(nrf_cli_transport_evt_t evt_type, void * p_context);
+
+typedef struct nrf_cli_transport_s nrf_cli_transport_t;
+
+/**
+ * @brief Unified CLI transport interface.
+ */
+typedef struct
+{
+ /**
+ * @brief Function for initializing the CLI transport interface.
+ *
+ * @param[in] p_transport Pointer to the transfer instance.
+ * @param[in] p_config Pointer to instance configuration.
+ * @param[in] evt_handler Event handler.
+ * @param[in] p_context Pointer to the context passed to event handler.
+ *
+ * @return Standard error code.
+ */
+ ret_code_t (*init)(nrf_cli_transport_t const * p_transport,
+ void const * p_config,
+ nrf_cli_transport_handler_t evt_handler,
+ void * p_context);
+
+ /**
+ * @brief Function for uninitializing the CLI transport interface.
+ *
+ * @param[in] p_transport Pointer to the transfer instance.
+ *
+ * @return Standard error code.
+ */
+ ret_code_t (*uninit)(nrf_cli_transport_t const * p_transport);
+
+ /**
+ * @brief Function for reconfiguring the transport to work in blocking mode.
+ *
+ * @param p_transport Pointer to the transfer instance.
+ * @param blocking If true, the transport is enabled in blocking mode.
+ *
+ * @return NRF_SUCCESS on successful enabling, error otherwise (also if not supported).
+ */
+ ret_code_t (*enable)(nrf_cli_transport_t const * p_transport,
+ bool blocking);
+
+ /**
+ * @brief Function for writing data to the transport interface.
+ *
+ * @param[in] p_transport Pointer to the transfer instance.
+ * @param[in] p_data Pointer to the source buffer.
+ * @param[in] length Source buffer length.
+ * @param[in] p_cnt Pointer to the sent bytes counter.
+ *
+ * @return Standard error code.
+ */
+ ret_code_t (*write)(nrf_cli_transport_t const * p_transport,
+ const void * p_data,
+ size_t length,
+ size_t * p_cnt);
+
+ /**
+ * @brief Function for reading data from the transport interface.
+ *
+ * @param[in] p_transport Pointer to the transfer instance.
+ * @param[in] p_data Pointer to the destination buffer.
+ * @param[in] length Destination buffer length.
+ * @param[in] p_cnt Pointer to the received bytes counter.
+ *
+ * @return Standard error code.
+ */
+ ret_code_t (*read)(nrf_cli_transport_t const * p_transport,
+ void * p_data,
+ size_t length,
+ size_t * p_cnt);
+
+} nrf_cli_transport_api_t;
+
+struct nrf_cli_transport_s
+{
+ nrf_cli_transport_api_t const * p_api;
+};
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+/**
+ * @brief CLI history object header.
+ */
+typedef PACKED_STRUCT
+{
+ nrf_memobj_t * p_prev; //!< Pointer to the next object.
+ nrf_memobj_t * p_next; //!< Pointer to the previous object.
+ nrf_cli_cmd_len_t cmd_len; //!< Command length.
+} nrf_cli_memobj_header_t;
+#endif
+
+#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+typedef struct
+{
+ uint32_t log_lost_cnt; //!< Lost log counter.
+} nrf_cli_statistics_t;
+#endif
+
+/**
+ * @internal @brief Flags for internal CLI usage.
+ */
+typedef struct
+{
+ uint32_t insert_mode : 1; //!< Enables or disables console insert mode for text introduction.
+ uint32_t show_help : 1; //!< Shows help if the command was called with -h or --help parameter.
+ uint32_t use_colors : 1; //!< Enables or disables colored syntax.
+ uint32_t echo : 1; //!< Enables or disables CLI echo.
+ uint32_t processing : 1; //!< CLI is executing process function.
+ uint32_t tx_rdy : 1;
+} nrf_cli_flag_t;
+STATIC_ASSERT(sizeof(nrf_cli_flag_t) == sizeof(uint32_t));
+
+/**
+ * @internal @brief Union for internal CLI usage.
+ */
+typedef union
+{
+ uint32_t value;
+ nrf_cli_flag_t flag;
+} nrf_cli_internal_t;
+
+/**
+ * @brief CLI instance context.
+ */
+typedef struct
+{
+ nrf_cli_state_t state; //!< Internal module state.
+ nrf_cli_receive_t receive_state; //!< Escape sequence indicator.
+
+ nrf_cli_static_entry_t const * p_current_stcmd; //!< Currently executed command.
+
+ nrf_cli_vt100_ctx_t vt100_ctx; //!< VT100 color and cursor position, terminal width.
+
+ nrf_cli_cmd_len_t cmd_buff_len; //!< Command length.
+ nrf_cli_cmd_len_t cmd_buff_pos; //!< Command buffer cursor position.
+
+#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
+ nrf_cli_cmd_len_t cmd_tmp_buff_len; //!< Command length in tmp buffer
+#endif
+
+ char cmd_buff[NRF_CLI_CMD_BUFF_SIZE]; //!< Command input buffer.
+ char temp_buff[NRF_CLI_CMD_BUFF_SIZE]; //!< Temporary buffer used by various functions.
+ char printf_buff[NRF_CLI_PRINTF_BUFF_SIZE]; //!< Printf buffer size.
+
+#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
+ nrf_cli_statistics_t statistics; //!< CLI statistics.
+#endif
+
+#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
+ task_id_t task_id;
+#endif
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+ nrf_memobj_t * p_cmd_list_head; //!< Pointer to the head of history list.
+ nrf_memobj_t * p_cmd_list_tail; //!< Pointer to the tail of history list.
+ nrf_memobj_t * p_cmd_list_element; //!< Pointer to an element of history list.
+#endif
+ volatile nrf_cli_internal_t internal; //!< Internal CLI data
+} nrf_cli_ctx_t;
+
+extern const nrf_log_backend_api_t nrf_log_backend_cli_api;
+
+typedef struct
+{
+ nrf_log_backend_t backend;
+ nrf_queue_t const * p_queue;
+ void * p_context;
+ nrf_cli_t const * p_cli;
+} nrf_cli_log_backend_t;
+
+#if NRF_CLI_LOG_BACKEND && NRF_MODULE_ENABLED(NRF_LOG)
+#define NRF_LOG_BACKEND_CLI_DEF(_name_, _queue_size_) \
+ NRF_QUEUE_DEF(nrf_log_entry_t, \
+ CONCAT_2(_name_, _queue),_queue_size_, NRF_QUEUE_MODE_NO_OVERFLOW); \
+ static nrf_cli_log_backend_t _name_ = { \
+ .backend = {.p_api = &nrf_log_backend_cli_api}, \
+ .p_queue = &CONCAT_2(_name_, _queue), \
+ }
+
+#define NRF_CLI_BACKEND_PTR(_name_) &CONCAT_2(_name_, _log_backend)
+#else
+#define NRF_LOG_BACKEND_CLI_DEF(_name_, _queue_sz_)
+#define NRF_CLI_BACKEND_PTR(_name_) NULL
+#endif
+
+#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
+/* Header consists memory for cmd length and pointer to: prev and next element. */
+#define NRF_CLI_HISTORY_HEADER_SIZE (sizeof(nrf_cli_memobj_header_t))
+
+#define NRF_CLI_HISTORY_MEM_OBJ(name) \
+ NRF_MEMOBJ_POOL_DEF(CONCAT_2(name, _cmd_hist_memobj), \
+ NRF_CLI_HISTORY_HEADER_SIZE + \
+ NRF_CLI_HISTORY_ELEMENT_SIZE, \
+ NRF_CLI_HISTORY_ELEMENT_COUNT)
+
+#define NRF_CLI_MEMOBJ_PTR(_name_) &CONCAT_2(_name_, _cmd_hist_memobj)
+#else
+#define NRF_CLI_MEMOBJ_PTR(_name_) NULL
+#define NRF_CLI_HISTORY_MEM_OBJ(name)
+#endif
+
+/**
+ * @brief CLI instance internals.
+ *
+ * @ref nrf_cli_t
+ */
+struct nrf_cli
+{
+ char const * const p_name; //!< Terminal name.
+
+ nrf_cli_transport_t const * p_iface; //!< Transport interface.
+ nrf_cli_ctx_t * p_ctx; //!< Internal context.
+ nrf_cli_log_backend_t * p_log_backend; //!< Logger backend.
+ nrf_fprintf_ctx_t * p_fprintf_ctx; //!< fprintf context.
+ nrf_memobj_pool_t const * p_cmd_hist_mempool; //!< Memory reserved for commands history.
+ char const newline_char; //!< New line character, only allowed values: \\n and \\r.
+};
+
+/**
+ * @brief Macro for defining a command line interface instance.
+ *
+ * @param[in] name Instance name.
+ * @param[in] cli_prefix CLI prefix string.
+ * @param[in] p_transport_iface Pointer to the transport interface.
+ * @param[in] newline_ch New line character - only allowed values are '\\n' or '\\r'.
+ * @param[in] log_queue_size Logger processing queue size.
+ */
+#define NRF_CLI_DEF(name, cli_prefix, p_transport_iface, newline_ch, log_queue_size) \
+ static nrf_cli_t const name; \
+ static nrf_cli_ctx_t CONCAT_2(name, _ctx); \
+ NRF_FPRINTF_DEF(CONCAT_2(name, _fprintf_ctx), \
+ &name, \
+ CONCAT_2(name, _ctx).printf_buff, \
+ NRF_CLI_PRINTF_BUFF_SIZE, \
+ false, \
+ nrf_cli_print_stream); \
+ NRF_LOG_BACKEND_CLI_DEF(CONCAT_2(name, _log_backend), log_queue_size); \
+ NRF_CLI_HISTORY_MEM_OBJ(name); \
+ /*lint -save -e31*/ \
+ static nrf_cli_t const name = { \
+ .p_name = cli_prefix, \
+ .p_iface = p_transport_iface, \
+ .p_ctx = &CONCAT_2(name, _ctx), \
+ .p_log_backend = NRF_CLI_BACKEND_PTR(name), \
+ .p_fprintf_ctx = &CONCAT_2(name, _fprintf_ctx), \
+ .p_cmd_hist_mempool = NRF_CLI_MEMOBJ_PTR(name), \
+ .newline_char = newline_ch \
+ } /*lint -restore*/
+
+/**
+ * @brief Function for initializing a transport layer and internal CLI state.
+ *
+ * @param[in] p_cli Pointer to CLI instance.
+ * @param[in] p_transport_config Configuration forwarded to the transport during initialization.
+ * @param[in] use_colors Enables colored prints.
+ * @param[in] log_backend If true, the console will be used as logger backend.
+ * @param[in] init_lvl Default severity level for the logger.
+ *
+ * @return Standard error code.
+ */
+ret_code_t nrf_cli_init(nrf_cli_t const * p_cli,
+ void const * p_transport_config,
+ bool use_colors,
+ bool log_backend,
+ nrf_log_severity_t init_lvl);
+
+ret_code_t nrf_cli_task_create(nrf_cli_t const * p_cli);
+
+/**
+ * @brief Function for uninitializing a transport layer and internal CLI state.
+ * If function returns NRF_ERROR_BUSY, you must call @ref nrf_cli_process before calling
+ * nrf_cli_uninit again.
+ *
+ * @param p_cli Pointer to CLI instance.
+ *
+ * @return Standard error code.
+ */
+ret_code_t nrf_cli_uninit(nrf_cli_t const * p_cli);
+
+/**
+ * @brief Function for starting CLI processing.
+ *
+ * @param p_cli Pointer to the CLI instance.
+ *
+ * @return Standard error code.
+ */
+ret_code_t nrf_cli_start(nrf_cli_t const * p_cli);
+
+/**
+ * @brief Function for stopping CLI processing.
+ *
+ * @param p_cli Pointer to CLI instance.
+ *
+ * @return Standard error code.
+ */
+ret_code_t nrf_cli_stop(nrf_cli_t const * p_cli);
+
+/**
+ * @brief CLI colors for @ref nrf_cli_fprintf function.
+ */
+#define NRF_CLI_DEFAULT NRF_CLI_VT100_COLOR_DEFAULT /**< Turn off character attributes. */
+#define NRF_CLI_NORMAL NRF_CLI_VT100_COLOR_WHITE /**< Normal color printf. */
+#define NRF_CLI_INFO NRF_CLI_VT100_COLOR_GREEN /**< Info color printf. */
+#define NRF_CLI_OPTION NRF_CLI_VT100_COLOR_CYAN /**< Option color printf. */
+#define NRF_CLI_WARNING NRF_CLI_VT100_COLOR_YELLOW /**< Warning color printf. */
+#define NRF_CLI_ERROR NRF_CLI_VT100_COLOR_RED /**< Error color printf. */
+
+/**
+ * @brief Printf-like function which sends formatted data stream to the CLI.
+ * This function shall not be used outside of the CLI module or CLI command context.
+ *
+ * @param[in] p_cli Pointer to the CLI instance.
+ * @param[in] color Printf color.
+ * @param[in] p_fmt Format string.
+ * @param[in] ... List of parameters to print.
+ */
+void nrf_cli_fprintf(nrf_cli_t const * p_cli,
+ nrf_cli_vt100_color_t color,
+ char const * p_fmt,
+ ...);
+
+/**
+ * @brief Process function, which should be executed when data is ready in the transport interface.
+ *
+ * @param[in] p_cli Pointer to the CLI instance.
+ */
+void nrf_cli_process(nrf_cli_t const * p_cli);
+
+
+/**
+ * @brief Option descriptor.
+ */
+typedef struct nrf_cli_getopt_option
+{
+ char const * p_optname; //!< Option long name.
+ char const * p_optname_short; //!< Option short name.
+ char const * p_optname_help; //!< Option help string.
+} nrf_cli_getopt_option_t;
+
+
+/**
+ * @brief Option structure initializer @ref nrf_cli_getopt_option.
+ *
+ * @param[in] _p_optname Option name long.
+ * @param[in] _p_shortname Option name short.
+ * @param[in] _p_help Option help string.
+ */
+#define NRF_CLI_OPT(_p_optname, _p_shortname, _p_help) { \
+ .p_optname = _p_optname, \
+ .p_optname_short = _p_shortname, \
+ .p_optname_help = _p_help, \
+}
+
+/**
+ * @brief Informs that a command has been called with -h or --help option.
+ *
+ * @param[in] p_cli Pointer to the CLI instance.
+ *
+ * @return True if help has been requested.
+ */
+__STATIC_INLINE bool nrf_cli_help_requested(nrf_cli_t const * p_cli);
+
+#ifndef SUPPRESS_INLINE_IMPLEMENTATION
+__STATIC_INLINE bool nrf_cli_help_requested(nrf_cli_t const * p_cli)
+{
+ return p_cli->p_ctx->internal.flag.show_help;
+}
+#endif
+
+/**
+ * @brief Prints the current command help.
+ * @details Function will print a help string with: the currently entered command, its options,
+ * and subcommands (if they exist).
+ *
+ * @param[in] p_cli Pointer to the CLI instance.
+ * @param[in] p_opt Pointer to the optional option array.
+ * @param[in] opt_len Option array size.
+ */
+void nrf_cli_help_print(nrf_cli_t const * p_cli,
+ nrf_cli_getopt_option_t const * p_opt,
+ size_t opt_len);
+
+/**
+ * @internal @brief This function shall not be used directly, it is required by the
+ * nrf_fprintf module.
+ *
+ * @param[in] p_user_ctx Pointer to the context for the CLI instance.
+ * @param[in] p_data Pointer to the data buffer.
+ * @param[in] data_len Data buffer size.
+ */
+void nrf_cli_print_stream(void const * p_user_ctx, char const * p_data, size_t data_len);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NRF_CLI_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli_types.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli_types.h
new file mode 100644
index 0000000..ca4ca75
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli_types.h
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NRF_CLI_TYPES_H__
+#define NRF_CLI_TYPES_H__
+
+#include <inttypes.h>
+#include "sdk_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (NRF_CLI_CMD_BUFF_SIZE > 65535)
+ typedef uint32_t nrf_cli_cmd_len_t;
+#elif (NRF_CLI_CMD_BUFF_SIZE > 255)
+ typedef uint16_t nrf_cli_cmd_len_t;
+#else
+ typedef uint8_t nrf_cli_cmd_len_t;
+#endif
+
+typedef enum
+{
+ NRF_CLI_VT100_COLOR_DEFAULT,
+ NRF_CLI_VT100_COLOR_BLACK,
+ NRF_CLI_VT100_COLOR_RED,
+ NRF_CLI_VT100_COLOR_GREEN,
+ NRF_CLI_VT100_COLOR_YELLOW,
+ NRF_CLI_VT100_COLOR_BLUE,
+ NRF_CLI_VT100_COLOR_MAGENTA,
+ NRF_CLI_VT100_COLOR_CYAN,
+ NRF_CLI_VT100_COLOR_WHITE,
+
+ VT100_COLOR_END
+} nrf_cli_vt100_color_t;
+
+typedef struct
+{
+ nrf_cli_vt100_color_t col; // text color
+ nrf_cli_vt100_color_t bgcol; // background color
+} nrf_cli_vt100_colors_t;
+
+typedef struct
+{
+ nrf_cli_cmd_len_t cur_x; // horizontal cursor position in edited command line
+ nrf_cli_cmd_len_t cur_x_end; // horizontal cursor position at the end of command
+ nrf_cli_cmd_len_t cur_y; // vertical cursor position in edited command
+ nrf_cli_cmd_len_t cur_y_end; // vertical cursor position at the end of command
+ nrf_cli_cmd_len_t terminal_hei; // terminal screen height
+ nrf_cli_cmd_len_t terminal_wid; // terminal screen width
+ uint8_t name_len; // console name length
+} nrf_cli_multiline_cons_t;
+
+typedef struct
+{
+ nrf_cli_multiline_cons_t cons;
+ nrf_cli_vt100_colors_t col;
+ nrf_cli_cmd_len_t printed_cmd; // printed commands counter
+} nrf_cli_vt100_ctx_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NRF_CLI_TYPES_H__ */
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli_vt100.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli_vt100.h
new file mode 100644
index 0000000..d581423
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/nrf_cli_vt100.h
@@ -0,0 +1,625 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NRF_CLI_VT100_H__
+#define NRF_CLI_VT100_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NRF_CLI_VT100_ASCII_ESC (0x1b)
+#define NRF_CLI_VT100_ASCII_DEL (0x7F)
+#define NRF_CLI_VT100_ASCII_BSPACE (0x08)
+
+#define NRF_CLI_VT100_SETNL \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', '0', 'h', '\0' \
+ } /* Set new line mode */
+#define NRF_CLI_VT100_SETAPPL \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '1', 'h', '\0' \
+ } /* Set cursor key to application */
+#define NRF_CLI_VT100_SETCOL_132 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '3', 'h', '\0' \
+ } /* Set number of columns to 132 */
+#define NRF_CLI_VT100_SETSMOOTH \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '4', 'h', '\0' \
+ } /* Set smooth scrolling */
+#define NRF_CLI_VT100_SETREVSCRN \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '5', 'h', '\0' \
+ } /* Set reverse video on screen */
+#define NRF_CLI_VT100_SETORGREL \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '6', 'h', '\0' \
+ } /* Set origin to relative */
+#define NRF_CLI_VT100_SETWRAP_ON \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '7', 'h', '\0' \
+ } /* Set auto-wrap mode */
+#define NRF_CLI_VT100_SETWRAP_OFF \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '7', 'l', '\0' \
+ } /* Set auto-wrap mode */
+
+#define NRF_CLI_VT100_SETREP \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '8', 'h', '\0' \
+ } /* Set auto-repeat mode */
+#define NRF_CLI_VT100_SETINTER \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '9', 'h', '\0' \
+ } /* Set interlacing mode */
+
+#define NRF_CLI_VT100_SETLF \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', '0', 'l', '\0' \
+ } /* Set line feed mode */
+#define NRF_CLI_VT100_SETCURSOR \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '1', 'l', '\0' \
+ } /* Set cursor key to cursor */
+#define NRF_CLI_VT100_SETVT52 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '2', 'l', '\0' \
+ } /* Set VT52 (versus ANSI) */
+#define NRF_CLI_VT100_SETCOL_80 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '3', 'l', '\0' \
+ } /* Set number of columns to 80 */
+#define NRF_CLI_VT100_SETJUMP \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '4', 'l', '\0' \
+ } /* Set jump scrolling */
+#define NRF_CLI_VT100_SETNORMSCRN \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '5', 'l', '\0' \
+ } /* Set normal video on screen */
+#define NRF_CLI_VT100_SETORGABS \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '6', 'l', '\0' \
+ } /* Set origin to absolute */
+#define NRF_CLI_VT100_RESETWRAP \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '7', 'l', '\0' \
+ } /* Reset auto-wrap mode */
+#define NRF_CLI_VT100_RESETREP \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '8', 'l', '\0' \
+ } /* Reset auto-repeat mode */
+#define NRF_CLI_VT100_RESETINTER \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '9', 'l', '\0' \
+ } /* Reset interlacing mode */
+
+#define NRF_CLI_VT100_ALTKEYPAD \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '=', '\0' \
+ } /* Set alternate keypad mode */
+#define NRF_CLI_VT100_NUMKEYPAD \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '>', '\0' \
+ } /* Set numeric keypad mode */
+
+#define NRF_CLI_VT100_SETUKG0 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '(', 'A', '\0' \
+ } /* Set United Kingdom G0 character set */
+#define NRF_CLI_VT100_SETUKG1 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, ')', 'A', '\0' \
+ } /* Set United Kingdom G1 character set */
+#define NRF_CLI_VT100_SETUSG0 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '(', 'B', '\0' \
+ } /* Set United States G0 character set */
+#define NRF_CLI_VT100_SETUSG1 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, ')', 'B', '\0' \
+ } /* Set United States G1 character set */
+#define NRF_CLI_VT100_SETSPECG0 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '(', '0', '\0' \
+ } /* Set G0 special chars. & line set */
+#define NRF_CLI_VT100_SETSPECG1 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, ')', '0', '\0' \
+ } /* Set G1 special chars. & line set */
+#define NRF_CLI_VT100_SETALTG0 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '(', '1', '\0' \
+ } /* Set G0 alternate character ROM */
+#define NRF_CLI_VT100_SETALTG1 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, ')', '1', '\0' \
+ } /* Set G1 alternate character ROM */
+#define NRF_CLI_VT100_SETALTSPECG0 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '(', '2', '\0' \
+ } /* Set G0 alt char ROM and spec. graphics */
+#define NRF_CLI_VT100_SETALTSPECG1 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, ')', '2', '\0' \
+ } /* Set G1 alt char ROM and spec. graphics */
+
+#define NRF_CLI_VT100_SETSS2 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'N', '\0' \
+ } /* Set single shift 2 */
+#define NRF_CLI_VT100_SETSS3 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', '\0' \
+ } /* Set single shift 3 */
+
+#define NRF_CLI_VT100_MODESOFF \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', 'm', '\0' \
+ } /* Turn off character attributes */
+#define NRF_CLI_VT100_MODESOFF_ \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '0', 'm', '\0' \
+ } /* Turn off character attributes */
+#define NRF_CLI_VT100_BOLD \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '1', 'm', '\0' \
+ } /* Turn bold mode on */
+#define NRF_CLI_VT100_LOWINT \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', 'm', '\0' \
+ } /* Turn low intensity mode on */
+#define NRF_CLI_VT100_UNDERLINE \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '4', 'm', '\0' \
+ } /* Turn underline mode on */
+#define NRF_CLI_VT100_BLINK \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '5', 'm', '\0' \
+ } /* Turn blinking mode on */
+#define NRF_CLI_VT100_REVERSE \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '7', 'm', '\0' \
+ } /* Turn reverse video on */
+#define NRF_CLI_VT100_INVISIBLE \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '8', 'm', '\0' \
+ } /* Turn invisible text mode on */
+
+#define NRF_CLI_VT100_SETWIN(t, b) \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', (t), ';', (b), 'r', '\0' \
+ } /* Set top and bottom line#s of a window */
+
+#define NRF_CLI_VT100_CURSORUP(n) \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', (n), 'A', '\0' \
+ } /* Move cursor up n lines */
+#define NRF_CLI_VT100_CURSORDN(n) \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', (n), 'B', '\0' \
+ } /* Move cursor down n lines */
+#define NRF_CLI_VT100_CURSORRT(n) \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', (n), 'C', '\0' \
+ } /* Move cursor right n lines */
+#define NRF_CLI_VT100_CURSORLF(n) \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', (n), 'D', '\0' \
+ } /* Move cursor left n lines */
+#define NRF_CLI_VT100_CURSORHOME \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', 'H', '\0' \
+ } /* Move cursor to upper left corner */
+#define NRF_CLI_VT100_CURSORHOME_ \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', ';', 'H', '\0' \
+ } /* Move cursor to upper left corner */
+#define NRF_CLI_VT100_CURSORPOS(v, h) \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', (v), ';', (h), 'H', '\0' \
+ } /* Move cursor to screen location v,h */
+
+#define NRF_CLI_VT100_HVHOME \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', 'f', '\0' \
+ } /* Move cursor to upper left corner */
+#define NRF_CLI_VT100_HVHOME_ \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', ';', 'f', '\0' \
+ } /* Move cursor to upper left corner */
+#define NRF_CLI_VT100_HVPOS(v, h) \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', (v), ';', (h), 'f', '\0' \
+ } /* Move cursor to screen location v,h */
+#define NRF_CLI_VT100_INDEX \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'D', '\0' \
+ } /* Move/scroll window up one line */
+#define NRF_CLI_VT100_REVINDEX \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'M', '\0' \
+ } /* Move/scroll window down one line */
+#define NRF_CLI_VT100_NEXTLINE \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'E', '\0' \
+ } /* Move to next line */
+#define NRF_CLI_VT100_SAVECURSOR \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '7', '\0' \
+ } /* Save cursor position and attributes */
+#define NRF_CLI_VT100_RESTORECURSOR \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '8', '\0' \
+ } /* Restore cursor position and attribute */
+
+#define NRF_CLI_VT100_TABSET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'H', '\0' \
+ } /* Set a tab at the current column */
+#define NRF_CLI_VT100_TABCLR \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', 'g', '\0' \
+ } /* Clear a tab at the current column */
+#define NRF_CLI_VT100_TABCLR_ \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '0', 'g', '\0' \
+ } /* Clear a tab at the current column */
+#define NRF_CLI_VT100_TABCLRALL \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '3', 'g', '\0' \
+ } /* Clear all tabs */
+
+#define NRF_CLI_VT100_DHTOP \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '#', '3', '\0' \
+ } /* Double-height letters, top half */
+#define NRF_CLI_VT100_DHBOT \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '#', '4', '\0' \
+ } /* Double-height letters, bottom hal */
+#define NRF_CLI_VT100_SWSH \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '#', '5', '\0' \
+ } /* Single width, single height letters */
+#define NRF_CLI_VT100_DWSH \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '#', '6', '\0' \
+ } /* Double width, single height letters */
+
+#define NRF_CLI_VT100_CLEAREOL \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', 'K', '\0' \
+ } /* Clear line from cursor right */
+#define NRF_CLI_VT100_CLEAREOL_ \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '0', 'K', '\0' \
+ } /* Clear line from cursor right */
+#define NRF_CLI_VT100_CLEARBOL \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '1', 'K', '\0' \
+ } /* Clear line from cursor left */
+#define NRF_CLI_VT100_CLEARLINE \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', 'K', '\0' \
+ } /* Clear entire line */
+
+#define NRF_CLI_VT100_CLEAREOS \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', 'J', '\0' \
+ } /* Clear screen from cursor down */
+#define NRF_CLI_VT100_CLEAREOS_ \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '0', 'J', '\0' \
+ } /* Clear screen from cursor down */
+#define NRF_CLI_VT100_CLEARBOS \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '1', 'J', '\0' \
+ } /* Clear screen from cursor up */
+#define NRF_CLI_VT100_CLEARSCREEN \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', 'J', '\0' \
+ } /* Clear entire screen */
+
+#define NRF_CLI_VT100_DEVSTAT \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '5', 'n', '\0' \
+ } /* Device status report */
+#define NRF_CLI_VT100_TERMOK \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '0', 'n', '\0' \
+ } /* Response: terminal is OK */
+#define NRF_CLI_VT100_TERMNOK \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '3', 'n', '\0' \
+ } /* Response: terminal is not OK */
+
+#define NRF_CLI_VT100_GETCURSOR \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '6', 'n', '\0' \
+ } /* Get cursor position */
+#define NRF_CLI_VT100_CURSORPOSAT \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, (v), ';', (h), 'R', '\0' \
+ } /* Response: cursor is at v,h */
+
+#define NRF_CLI_VT100_IDENT \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', 'c', '\0' \
+ } /* Identify what terminal type */
+#define NRF_CLI_VT100_IDENT_ \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '0', 'c', '\0' \
+ } /* Identify what terminal type */
+#define NRF_CLI_VT100_GETTYPE \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '?', '1', ';', (n), '0', 'c', '\0'\
+ } /* Response: terminal type code n */
+
+#define NRF_CLI_VT100_RESET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'c', '\0' \
+ } /* Reset terminal to initial state */
+
+#define NRF_CLI_VT100_ALIGN \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '#', '8', '\0' \
+ } /* Screen alignment display */
+#define NRF_CLI_VT100_TESTPU \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', ';', '1', 'y', '\0' \
+ } /* Confidence power up test */
+#define NRF_CLI_VT100_TESTLB \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', ';', '2', 'y', '\0' \
+ } /* Confidence loopback test */
+#define NRF_CLI_VT100_TESTPUREP \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', ';', '9', 'y', '\0' \
+ } /* Repeat power up test */
+#define NRF_CLI_VT100_TESTLBREP \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', ';', '1', '0', 'y', '\0' \
+ } /* Repeat loopback test */
+
+#define NRF_CLI_VT100_LEDSOFF \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '0', 'q', '\0' \
+ } /* Turn off all four leds */
+#define NRF_CLI_VT100_LED1 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '1', 'q', '\0' \
+ } /* Turn on LED #1 */
+#define NRF_CLI_VT100_LED2 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '2', 'q', '\0' \
+ } /* Turn on LED #2 */
+#define NRF_CLI_VT100_LED3 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '3', 'q', '\0' \
+ } /* Turn on LED #3 */
+#define NRF_CLI_VT100_LED4 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '4', 'q', '\0' \
+ } /* Turn on LED #4 */
+
+/* Function Keys */
+
+#define NRF_CLI_VT100_PF1 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'P', '\0' \
+ }
+#define NRF_CLI_VT100_PF2 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'Q', '\0' \
+ }
+#define NRF_CLI_VT100_PF3 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'R', '\0' \
+ }
+#define NRF_CLI_VT100_PF4 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'S', '\0' \
+ }
+
+/* Arrow keys */
+
+#define NRF_CLI_VT100_UP_RESET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'A', '\0' \
+ }
+#define NRF_CLI_VT100_UP_SET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'A', '\0' \
+ }
+#define NRF_CLI_VT100_DOWN_RESET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'B', '\0' \
+ }
+#define NRF_CLI_VT100_DOWN_SET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'B', '\0' \
+ }
+#define NRF_CLI_VT100_RIGHT_RESET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'C', '\0' \
+ }
+#define NRF_CLI_VT100_RIGHT_SET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'C', '\0' \
+ }
+#define NRF_CLI_VT100_LEFT_RESET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'D', '\0' \
+ }
+#define NRF_CLI_VT100_LEFT_SET \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'D', '\0' \
+ }
+
+/* Numeric Keypad Keys */
+
+#define NRF_CLI_VT100_NUMERIC_0 \
+ { \
+ '0', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_0 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'p', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_1 \
+ { \
+ '1', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_1 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'q', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_2 \
+ { \
+ '2', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_2 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'r', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_3 \
+ { \
+ '3', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_3 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 's', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_4 \
+ { \
+ '4', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_4 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 't', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_5 \
+ { \
+ '5', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_5 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'u', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_6 \
+ { \
+ '6', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_6 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'v', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_7 \
+ { \
+ '7', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_7 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'w', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_8 \
+ { \
+ '8', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_8 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'x', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_9 \
+ { \
+ '9', '\0'
+#define NRF_CLI_VT100_ALT_9 \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'y' \
+ }
+#define NRF_CLI_VT100_NUMERIC_MINUS \
+ { \
+ '-', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_MINUS \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'm', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_COMMA \
+ { \
+ ',', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_COMMA \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'l', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_PERIOD \
+ { \
+ '.', '\0' \
+ }
+#define NRF_CLI_VT100_ALT_PERIOD \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'n', '\0' \
+ }
+#define NRF_CLI_VT100_NUMERIC_ENTER \
+ { \
+ ASCII_CR \
+ }
+#define NRF_CLI_VT100_ALT_ENTER \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, 'O', 'M', '\0' \
+ }
+
+#define NRF_CLI_VT100_COLOR(__col) \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '1', ';', '3', '0' + (__col), 'm', '\0' \
+ }
+#define NRF_CLI_VT100_BGCOLOR(__col) \
+ { \
+ NRF_CLI_VT100_ASCII_ESC, '[', '4', '0' + (__col), 'm', '\0' \
+ }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NRF_CLI_VT100_H__ */
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/rtt/nrf_cli_rtt.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/rtt/nrf_cli_rtt.c
new file mode 100644
index 0000000..badcd04
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/rtt/nrf_cli_rtt.c
@@ -0,0 +1,223 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(NRF_CLI_RTT)
+#include <SEGGER_RTT_Conf.h>
+#include <SEGGER_RTT.h>
+#include "nrf_cli_rtt.h"
+#include "nrf_assert.h"
+#include "nrf_delay.h"
+
+#define RTT_RX_TIMEOUT 100
+
+static bool m_host_present;
+
+static void timer_handler(void * p_context)
+{
+ nrf_cli_rtt_internal_t * p_internal = (nrf_cli_rtt_internal_t *)p_context;
+ if (SEGGER_RTT_HasData(0))
+ {
+ p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY, p_internal->p_cb->p_context);
+ }
+ p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_internal->p_cb->p_context);
+
+ ret_code_t err_code = app_timer_start(*p_internal->p_timer,
+ APP_TIMER_TICKS(RTT_RX_TIMEOUT),
+ p_context);
+ ASSERT(err_code == NRF_SUCCESS);
+ UNUSED_VARIABLE(err_code);
+}
+
+static ret_code_t cli_rtt_init(nrf_cli_transport_t const * p_transport,
+ void const * p_config,
+ nrf_cli_transport_handler_t evt_handler,
+ void * p_context)
+{
+ UNUSED_PARAMETER(p_config);
+
+ nrf_cli_rtt_internal_t * p_internal =
+ CONTAINER_OF(p_transport, nrf_cli_rtt_internal_t, transport);
+ p_internal->p_cb->handler = evt_handler;
+ p_internal->p_cb->p_context = p_context;
+ p_internal->p_cb->timer_created = false;
+
+ SEGGER_RTT_Init();
+
+ m_host_present = true;
+
+ return NRF_SUCCESS;
+}
+
+static ret_code_t cli_rtt_uninit(nrf_cli_transport_t const * p_transport)
+{
+ nrf_cli_rtt_internal_t * p_internal =
+ CONTAINER_OF(p_transport, nrf_cli_rtt_internal_t, transport);
+
+ return app_timer_stop(*p_internal->p_timer);
+}
+
+static ret_code_t cli_rtt_enable(nrf_cli_transport_t const * p_transport,
+ bool blocking)
+{
+ nrf_cli_rtt_internal_t * p_internal =
+ CONTAINER_OF(p_transport, nrf_cli_rtt_internal_t, transport);
+ ret_code_t err_code = NRF_SUCCESS;
+
+ if (p_internal->p_cb->timer_created)
+ {
+ err_code = app_timer_stop(*p_internal->p_timer); //Timer may be running or inactive
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE))
+ {
+ return err_code;
+ }
+ else
+ {
+ err_code = NRF_SUCCESS;
+ }
+ }
+ if (!blocking)
+ {
+ if (!p_internal->p_cb->timer_created)
+ {
+ err_code = app_timer_create(p_internal->p_timer,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ timer_handler);
+ p_internal->p_cb->timer_created = true;
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = app_timer_start(*p_internal->p_timer,
+ APP_TIMER_TICKS(RTT_RX_TIMEOUT),
+ p_internal);
+ SEGGER_RTT_Init();
+ }
+ }
+ return err_code;
+}
+static ret_code_t cli_rtt_read(nrf_cli_transport_t const * p_transport,
+ void * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ UNUSED_PARAMETER(p_transport);
+
+ size_t rcnt = SEGGER_RTT_Read(NRF_CLI_RTT_TERMINAL_ID, p_data, length);
+ *p_cnt = rcnt;
+
+ return NRF_SUCCESS;
+}
+
+static ret_code_t cli_rtt_write(nrf_cli_transport_t const * p_transport,
+ const void * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ UNUSED_PARAMETER(p_transport);
+
+ if (!(CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk))
+ {
+ /* If an RTT session is not active, but the RTT console is processed, the program may hang.
+ * Workaround: If the debugger is not connected, always return NRF_SUCCESS.
+ */
+ *p_cnt = length;
+ return NRF_SUCCESS;
+ }
+
+ size_t idx = 0;
+ uint32_t processed;
+ uint32_t watchdog_counter = NRF_CLI_RTT_TX_RETRY_CNT;
+ const uint8_t * p_buffer = (const uint8_t *)p_data;
+ do {
+ processed = SEGGER_RTT_Write(NRF_CLI_RTT_TERMINAL_ID, &p_buffer[idx], length);
+ if (processed == 0)
+ {
+ /* There are two possible reasons for not writing any data to RTT:
+ * - The host is not connected and not reading the data.
+ * - The buffer got full and will be read by the host.
+ * These two situations are distinguished using the following algorithm.
+ * At the begining, the module assumes that the host is active,
+ * so when no data is read, it busy waits and retries.
+ * If, after retrying, the host reads the data, the module assumes that the host is active.
+ * If it fails, the module assumes that the host is inactive and stores that information. On next
+ * call, only one attempt takes place. The host is marked as active if the attempt is successful.
+ */
+ if (!m_host_present)
+ {
+ break;
+ }
+ else
+ {
+ nrf_delay_ms(NRF_CLI_RTT_TX_RETRY_DELAY_MS);
+ watchdog_counter--;
+ if (watchdog_counter == 0)
+ {
+ m_host_present = false;
+ break;
+ }
+ }
+ }
+ m_host_present = true;
+ idx += processed;
+ length -= processed;
+ } while (length);
+
+ if (idx > 0)
+ {
+ *p_cnt = idx;
+ }
+ else
+ {
+ *p_cnt = length;
+ }
+ return NRF_SUCCESS;
+}
+
+const nrf_cli_transport_api_t nrf_cli_rtt_transport_api = {
+ .init = cli_rtt_init,
+ .uninit = cli_rtt_uninit,
+ .enable = cli_rtt_enable,
+ .read = cli_rtt_read,
+ .write = cli_rtt_write,
+};
+
+#endif
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/rtt/nrf_cli_rtt.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/rtt/nrf_cli_rtt.h
new file mode 100644
index 0000000..4cb44e1
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/rtt/nrf_cli_rtt.h
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NRF_CLI_RTT_H__
+#define NRF_CLI_RTT_H__
+
+#include "nrf_cli.h"
+#include "app_timer.h"
+#include "nordic_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@file
+ *
+ * @defgroup nrf_cli_rtt RTT command line interface transport layer
+ * @ingroup nrf_cli
+ *
+ * @{
+ *
+ */
+
+/**
+ * @brief Command line interface transport.
+ */
+extern const nrf_cli_transport_api_t nrf_cli_rtt_transport_api;
+
+/**
+ * @brief CLI RTT transport control block structure.
+ */
+typedef struct {
+ nrf_cli_transport_handler_t handler; //!< Event handler
+ void * p_context; //!< User context.
+ bool timer_created;//!< Flag indicating whether a timer is created.
+} nrf_cli_rtt_internal_cb_t;
+
+/**
+ * @brief CLI RTT transport instance structure.
+ */
+typedef struct {
+ nrf_cli_transport_t transport; //!< Transport structure.
+ nrf_cli_rtt_internal_cb_t * p_cb; //!< Pointer to the instance control block.
+ app_timer_id_t const * p_timer; //!< Pointer to the app_timer instance.
+} nrf_cli_rtt_internal_t;
+
+/**@brief CLI RTT transport definition */
+#define NRF_CLI_RTT_DEF(_name_) \
+ APP_TIMER_DEF(CONCAT_2(_name_, _timer)); \
+ static nrf_cli_rtt_internal_cb_t CONCAT_2(_name_, _cb); \
+ static const nrf_cli_rtt_internal_t _name_ = { \
+ .transport = {.p_api = &nrf_cli_rtt_transport_api}, \
+ .p_cb = &CONCAT_2(_name_, _cb), \
+ .p_timer = &CONCAT_2(_name_, _timer) \
+ }
+
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NRF_CLI_RTT_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/uart/nrf_cli_uart.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/uart/nrf_cli_uart.c
new file mode 100644
index 0000000..d38941a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/uart/nrf_cli_uart.c
@@ -0,0 +1,308 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(NRF_CLI_UART)
+#include "nrf_cli_uart.h"
+#include "nrf_drv_uart.h"
+#include "nrf_assert.h"
+
+#define NRF_LOG_MODULE_NAME cli_uart
+
+#define NRF_LOG_LEVEL (NRF_CLI_UART_CONFIG_LOG_ENABLED ? NRF_CLI_UART_CONFIG_LOG_LEVEL : 0)
+#define NRF_LOG_INFO_COLOR NRF_CLI_UART_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR NRF_CLI_UART_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define CLI_UART_RX_TIMEOUT 100
+
+static ret_code_t rx_try(nrf_cli_uart_internal_t * p_internal)
+{
+ ret_code_t err_code;
+ size_t len = 255;
+ uint8_t * p_data;
+
+ err_code = nrf_ringbuf_alloc(p_internal->p_rx_ringbuf, &p_data, &len, true);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ if ((err_code == NRF_SUCCESS) && len)
+ {
+ err_code = nrf_drv_uart_rx(p_internal->p_uart, p_data, len);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = app_timer_start(*p_internal->p_timer,
+ APP_TIMER_TICKS(CLI_UART_RX_TIMEOUT),
+ p_internal);
+ }
+ }
+
+ return err_code;
+}
+
+static void uart_event_handler(nrf_drv_uart_event_t * p_event, void * p_context)
+{
+ nrf_cli_uart_internal_t * p_internal = (nrf_cli_uart_internal_t *)p_context;
+ ret_code_t err_code = NRF_SUCCESS;
+ UNUSED_VARIABLE(err_code);
+ uint8_t * p_data;
+ size_t len = 255;
+ switch (p_event->type)
+ {
+ case NRF_DRV_UART_EVT_ERROR:
+ NRF_LOG_WARNING("id:%d, evt: ERROR:%d",
+ p_internal->p_uart->inst_idx,
+ p_event->data.error.error_mask);
+ err_code = nrf_ringbuf_put(p_internal->p_rx_ringbuf, p_event->data.error.rxtx.bytes);
+ ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NO_MEM));
+ err_code = rx_try(p_internal);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ break;
+
+ case NRF_DRV_UART_EVT_RX_DONE:
+ err_code = nrf_ringbuf_put(p_internal->p_rx_ringbuf, p_event->data.rxtx.bytes);
+ ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NO_MEM));
+
+ if (p_event->data.rxtx.bytes)
+ {
+ NRF_LOG_INFO("id:%d, evt: RXRDY len:%d",
+ p_internal->p_uart->inst_idx,
+ p_event->data.rxtx.bytes);
+ NRF_LOG_HEXDUMP_DEBUG(p_event->data.rxtx.p_data, p_event->data.rxtx.bytes);
+ p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY,
+ p_internal->p_cb->p_context);
+ }
+ err_code = rx_try(p_internal);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ break;
+
+ case NRF_DRV_UART_EVT_TX_DONE:
+ err_code = nrf_ringbuf_free(p_internal->p_tx_ringbuf, p_event->data.rxtx.bytes);
+ ASSERT(err_code == NRF_SUCCESS);
+ len = 255;
+ err_code = nrf_ringbuf_get(p_internal->p_tx_ringbuf, &p_data, &len, true);
+ ASSERT(err_code == NRF_SUCCESS);
+ if (len)
+ {
+ NRF_LOG_INFO("id:%d, evt uart_tx, len:%d", p_internal->p_uart->inst_idx, len);
+ err_code = nrf_drv_uart_tx(p_internal->p_uart, p_data, len);
+ ASSERT(err_code == NRF_SUCCESS);
+ }
+ p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_internal->p_cb->p_context);
+ NRF_LOG_INFO("id:%d, evt: TXRDY, len:%d",
+ p_internal->p_uart->inst_idx,
+ p_event->data.rxtx.bytes);
+ break;
+
+ default:
+ NRF_LOG_ERROR("Unknown event");
+ ASSERT(false);
+ }
+}
+
+static void timer_handler(void * p_context)
+{
+ nrf_cli_uart_internal_t * p_internal = (nrf_cli_uart_internal_t *)p_context;
+ NRF_LOG_DEBUG("id:%d, evt: Timeout", p_internal->p_uart->inst_idx);
+ nrf_drv_uart_rx_abort(p_internal->p_uart);
+}
+
+static ret_code_t cli_uart_init(nrf_cli_transport_t const * p_transport,
+ void const * p_config,
+ nrf_cli_transport_handler_t evt_handler,
+ void * p_context)
+{
+ nrf_cli_uart_internal_t * p_internal =
+ CONTAINER_OF(p_transport,
+ nrf_cli_uart_internal_t,
+ transport);
+ p_internal->p_cb->handler = evt_handler;
+ p_internal->p_cb->p_context = p_context;
+ p_internal->p_cb->timer_created = false;
+ p_internal->p_cb->blocking = false;
+
+ nrf_drv_uart_config_t * p_uart_config = (nrf_drv_uart_config_t *)p_config;
+ memcpy(&p_internal->p_cb->uart_config, p_uart_config, sizeof(nrf_drv_uart_config_t));
+ p_uart_config->p_context = (void *)p_internal;
+ ret_code_t err_code = nrf_drv_uart_init(p_internal->p_uart,
+ p_uart_config,
+ uart_event_handler);
+ if (err_code == NRF_SUCCESS)
+ {
+ nrf_ringbuf_init(p_internal->p_rx_ringbuf);
+ nrf_ringbuf_init(p_internal->p_tx_ringbuf);
+ }
+ return err_code;
+}
+
+static ret_code_t cli_uart_uninit(nrf_cli_transport_t const * p_transport)
+{
+ nrf_cli_uart_internal_t * p_internal =
+ CONTAINER_OF(p_transport,
+ nrf_cli_uart_internal_t,
+ transport);
+
+ nrf_drv_uart_uninit(p_internal->p_uart);
+
+ return app_timer_stop(*p_internal->p_timer);
+}
+
+static ret_code_t cli_uart_enable(nrf_cli_transport_t const * p_transport,
+ bool blocking)
+{
+ nrf_cli_uart_internal_t * p_internal =
+ CONTAINER_OF(p_transport,
+ nrf_cli_uart_internal_t,
+ transport);
+ ret_code_t err_code = NRF_SUCCESS;
+
+ if (p_internal->p_cb->timer_created)
+ {
+ err_code = app_timer_stop(*p_internal->p_timer); //Timer may be running or inactive
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE))
+ {
+ return err_code;
+ }
+ else
+ {
+ err_code = NRF_SUCCESS;
+ }
+ }
+
+ if (blocking)
+ {
+ nrf_drv_uart_uninit(p_internal->p_uart);
+ err_code = nrf_drv_uart_init(p_internal->p_uart, &p_internal->p_cb->uart_config, NULL);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_internal->p_cb->blocking = true;
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+ }
+ else
+ {
+ if (!p_internal->p_cb->timer_created)
+ {
+ err_code = app_timer_create(p_internal->p_timer,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ timer_handler);
+ p_internal->p_cb->timer_created = true;
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = rx_try(p_internal);
+ }
+ }
+ return err_code;
+}
+
+static ret_code_t cli_uart_read(nrf_cli_transport_t const * p_transport,
+ void * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ nrf_cli_uart_internal_t * p_instance =
+ CONTAINER_OF(p_transport, nrf_cli_uart_internal_t, transport);
+
+ *p_cnt = length;
+ ret_code_t err_code = nrf_ringbuf_cpy_get(p_instance->p_rx_ringbuf, p_data, p_cnt);
+
+ if (*p_cnt)
+ {
+ NRF_LOG_INFO("id:%d, read:%d", p_instance->p_uart->inst_idx, *p_cnt);
+ }
+
+ return err_code;
+}
+
+static ret_code_t cli_uart_write(nrf_cli_transport_t const * p_transport,
+ void const * p_data,
+ size_t length,
+ size_t * p_cnt)
+{
+ ASSERT(p_cnt);
+ nrf_cli_uart_internal_t * p_instance =
+ CONTAINER_OF(p_transport, nrf_cli_uart_internal_t, transport);
+ ret_code_t err_code;
+ *p_cnt = length;
+ err_code = nrf_ringbuf_cpy_put(p_instance->p_tx_ringbuf, p_data, p_cnt);
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_INFO("id:%d, write, req:%d, done:%d",
+ p_instance->p_uart->inst_idx,
+ length,
+ *p_cnt);
+
+ if (!nrf_drv_uart_tx_in_progress(p_instance->p_uart))
+ {
+ uint8_t * p_buf;
+ size_t len = 255;
+ if (nrf_ringbuf_get(p_instance->p_tx_ringbuf, &p_buf, &len, true) == NRF_SUCCESS)
+ {
+ NRF_LOG_INFO("id:%d, uart_tx, len:%d", p_instance->p_uart->inst_idx, len);
+
+ err_code = nrf_drv_uart_tx(p_instance->p_uart, p_buf, len);
+ if (p_instance->p_cb->blocking && (err_code == NRF_SUCCESS))
+ {
+ (void)nrf_ringbuf_free(p_instance->p_tx_ringbuf, len);
+ }
+ }
+ }
+ }
+ return err_code;
+}
+
+const nrf_cli_transport_api_t nrf_cli_uart_transport_api = {
+ .init = cli_uart_init,
+ .uninit = cli_uart_uninit,
+ .enable = cli_uart_enable,
+ .read = cli_uart_read,
+ .write = cli_uart_write,
+};
+
+#endif
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/uart/nrf_cli_uart.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/uart/nrf_cli_uart.h
new file mode 100644
index 0000000..1a827a4
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/cli/uart/nrf_cli_uart.h
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NRF_CLI_UART_H__
+#define NRF_CLI_UART_H__
+
+#include "nrf_cli.h"
+#include "nrf_drv_uart.h"
+#include "nrf_ringbuf.h"
+#include "app_timer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@file
+ *
+ * @defgroup nrf_cli_uart UART command line interface transport layer
+ * @ingroup nrf_cli
+ *
+ * @{
+ *
+ */
+
+/**
+ * @brief Command line interface transport.
+ */
+extern const nrf_cli_transport_api_t nrf_cli_uart_transport_api;
+
+typedef struct nrf_cli_uart_internal_s nrf_cli_uart_internal_t;
+
+typedef struct {
+ nrf_cli_transport_handler_t handler;
+ void * p_context;
+ nrf_drv_uart_config_t uart_config;
+ bool timer_created;
+ bool blocking;
+} nrf_cli_uart_internal_cb_t;
+
+struct nrf_cli_uart_internal_s {
+ nrf_cli_transport_t transport;
+ nrf_cli_uart_internal_cb_t * p_cb;
+ app_timer_id_t const * p_timer;
+ nrf_ringbuf_t const * p_rx_ringbuf;
+ nrf_ringbuf_t const * p_tx_ringbuf;
+ nrf_drv_uart_t const * p_uart;
+};
+
+typedef nrf_drv_uart_config_t nrf_cli_uart_config_t;
+
+/**@brief CLI UART transport definition.
+ *
+ * @param _name Name of the instance.
+ * @param _uart_id UART instance ID.
+ * @param _tx_buf_sz Size of TX ring buffer.
+ * @param _rx_buf_sz Size of RX ring buffer.
+ */
+#define NRF_CLI_UART_DEF(_name, _uart_id, _tx_buf_sz, _rx_buf_sz) \
+ APP_TIMER_DEF(CONCAT_2(_name, _timer)); \
+ NRF_RINGBUF_DEF(CONCAT_2(_name,_tx_ringbuf), _tx_buf_sz); \
+ NRF_RINGBUF_DEF(CONCAT_2(_name,_rx_ringbuf), _rx_buf_sz); \
+ static const nrf_drv_uart_t CONCAT_2(_name,_uart) = \
+ NRF_DRV_UART_INSTANCE(_uart_id); \
+ static nrf_cli_uart_internal_cb_t CONCAT_2(_name, _cb); \
+ static const nrf_cli_uart_internal_t _name = { \
+ .transport = {.p_api = &nrf_cli_uart_transport_api}, \
+ .p_cb = &CONCAT_2(_name, _cb), \
+ .p_timer = &CONCAT_2(_name, _timer), \
+ .p_rx_ringbuf = &CONCAT_2(_name,_rx_ringbuf), \
+ .p_tx_ringbuf = &CONCAT_2(_name,_tx_ringbuf), \
+ .p_uart = &CONCAT_2(_name,_uart), \
+ }
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NRF_CLI_UART_H__ */