From 3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 23 Aug 2018 17:08:59 +0200 Subject: o Initial import. --- .../ble_app_interactive/ble_app_interactive.eww | 6 + .../experimental/ble_app_interactive/ble_m.c | 1899 ++ .../experimental/ble_app_interactive/ble_m.h | 260 + .../experimental/ble_app_interactive/cli_m.c | 2121 ++ .../experimental/ble_app_interactive/cli_m.h | 101 + .../experimental/ble_app_interactive/main.c | 250 + .../ble_app_interactive/nfc_central_m.c | 466 + .../ble_app_interactive/nfc_central_m.h | 110 + .../experimental/ble_app_interactive/nfc_m.c | 76 + .../experimental/ble_app_interactive/nfc_m.h | 69 + .../ble_app_interactive/nfc_pair_lib_m.c | 422 + .../ble_app_interactive/nfc_pair_lib_m.h | 94 + .../arm4/ble_app_interactive_s132_pca10040.uvopt | 51 + .../arm4/ble_app_interactive_s132_pca10040.uvproj | 19032 ++++++++++++++++++ .../ble_app_interactive_s132_pca10040.uvoptx | 221 + .../ble_app_interactive_s132_pca10040.uvprojx | 18901 ++++++++++++++++++ .../pca10040/s132/armgcc/Makefile | 508 + .../s132/armgcc/ble_app_interactive_gcc_nrf52.ld | 117 + .../pca10040/s132/config/sdk_config.h | 13155 ++++++++++++ .../s132/iar/ble_app_interactive_iar_nRF5x.icf | 36 + .../s132/iar/ble_app_interactive_s132_pca10040.ewd | 1350 ++ .../s132/iar/ble_app_interactive_s132_pca10040.ewp | 1527 ++ .../ble_app_interactive_s132_pca10040.emProject | 311 + .../ble_app_interactive_s132_pca10040.emSession | 7 + .../pca10040/s132/ses/flash_placement.xml | 50 + .../ble_app_interactive_s140_pca10056.uvoptx | 221 + .../ble_app_interactive_s140_pca10056.uvprojx | 19939 +++++++++++++++++++ .../pca10056/s140/armgcc/Makefile | 516 + .../s140/armgcc/ble_app_interactive_gcc_nrf52.ld | 117 + .../pca10056/s140/config/sdk_config.h | 13559 +++++++++++++ .../ble_app_interactive_s140_pca10056.emProject | 325 + .../ble_app_interactive_s140_pca10056.emSession | 7 + .../pca10056/s140/ses/flash_placement.xml | 50 + .../experimental/ble_app_interactive/pm_m.c | 271 + .../experimental/ble_app_interactive/pm_m.h | 56 + 35 files changed, 96201 insertions(+) create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_app_interactive.eww create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_m.c create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_m.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/cli_m.c create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/cli_m.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/main.c create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/nfc_central_m.c create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/nfc_central_m.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/nfc_m.c create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/nfc_m.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/nfc_pair_lib_m.c create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/nfc_pair_lib_m.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/arm4/ble_app_interactive_s132_pca10040.uvopt create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/arm4/ble_app_interactive_s132_pca10040.uvproj create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/arm5_no_packs/ble_app_interactive_s132_pca10040.uvoptx create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/arm5_no_packs/ble_app_interactive_s132_pca10040.uvprojx create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/armgcc/Makefile create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/armgcc/ble_app_interactive_gcc_nrf52.ld create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/config/sdk_config.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/iar/ble_app_interactive_iar_nRF5x.icf create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/iar/ble_app_interactive_s132_pca10040.ewd create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/iar/ble_app_interactive_s132_pca10040.ewp create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/ses/ble_app_interactive_s132_pca10040.emProject create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/ses/ble_app_interactive_s132_pca10040.emSession create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10040/s132/ses/flash_placement.xml create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10056/s140/arm5_no_packs/ble_app_interactive_s140_pca10056.uvoptx create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10056/s140/arm5_no_packs/ble_app_interactive_s140_pca10056.uvprojx create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10056/s140/armgcc/Makefile create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10056/s140/armgcc/ble_app_interactive_gcc_nrf52.ld create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10056/s140/config/sdk_config.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10056/s140/ses/ble_app_interactive_s140_pca10056.emProject create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10056/s140/ses/ble_app_interactive_s140_pca10056.emSession create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pca10056/s140/ses/flash_placement.xml create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pm_m.c create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/pm_m.h (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive') diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_app_interactive.eww b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_app_interactive.eww new file mode 100644 index 0000000..0d7fb3d --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_app_interactive.eww @@ -0,0 +1,6 @@ + + + + $WS_DIR$\pca10040\s132\iar\ble_app_interactive_s132_pca10040.ewp + + \ No newline at end of file diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_m.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_m.c new file mode 100644 index 0000000..019291a --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_m.c @@ -0,0 +1,1899 @@ +/** + * 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 +#include +#include +#include "ble_m.h" +#include "cli_m.h" +#include "bsp_btn_ble.h" +#include "ble_bas.h" +#include "ble.h" +#include "app_util.h" +#include "ble_advdata.h" +#include "ble_advertising.h" +#include "ble_conn_params.h" +#include "ble_conn_state.h" +#include "nrf_log.h" +#include "ble_advertising.h" +#include "ble_hci.h" +#include "nrf_sdh.h" +#include "nrf_sdh_soc.h" +#include "nrf_sdh_ble.h" +#include "nrf_ble_gatt.h" +#include "nrf_balloc.h" +#include "nfc_central_m.h" +#include "nfc_ble_oob_advdata_parser.h" + +#define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */ + +#define CENTRAL_SCANNING_LED BSP_BOARD_LED_0 +#define CENTRAL_CONNECTED_LED BSP_BOARD_LED_1 +#define PERIPHERAL_ADVERTISING_LED BSP_BOARD_LED_2 +#define PERIPHERAL_CONNECTED_LED BSP_BOARD_LED_3 + + +#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000) /**< Time from initiating an event (connect or start of notification) to the first time sd_ble_gap_conn_param_update is called (5 seconds). */ +#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */ +#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Max count of connections parameters update. */ + +#define SCAN_DURATION 0x0000 /**< Duration of the scanning in units of 10 milliseconds. If set to 0x0000, scanning will continue until it is explicitly disabled. */ +#define APP_ADV_DURATION 18000 /**< The advertising duration (180 seconds) in units of 10 milliseconds. */ + +#define APP_FEATURE_NOT_SUPPORTED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2 /**< Reply when unsupported features are requested. */ +#define CCCD_DESCRIPTOR_UUID BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG /**< UUID of characteristic CCCD descriptors. */ +#define L2CAP_HDR_LEN 4 /**< Length of a L2CAP header, in bytes. */ +#define BATTERY_INITIAL_LVL 100 /**< Battery initial level. */ +#define UUID_STRING_LEN 5 /**< UUID uint16_t string length. */ + +/**@brief Priority of the application BLE event handler. + * @note You should not need to modify this value. + */ +#define APP_BLE_OBSERVER_PRIO 1 + +BLE_BAS_DEF(m_bas); +NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */ +BLE_ADVERTISING_DEF(m_advertising); /**< Advertising module instance. */ + +// Structure storing data of all discovered services. +typedef struct +{ + ble_gattc_service_t services[MAX_SERVICE_COUNT]; /**< Data of the found services. */ + uint8_t count; /**< Count of the found services. */ +} device_srv_t; + + +typedef struct +{ + ble_uuid_t uuid; /**< Characteristic UUID. */ + uint16_t decl_handle; /**< Handle of the Characteristic Declaration. */ + uint16_t value_handle; /**< Handle of the Characteristic Value. */ + uint16_t cccd_desc_handle; /**< Handle of CCCD descriptors. */ + bool notify; /**< True when notification of the value permitted. */ +} char_data_t; + +// Structure storing the data of all discovered characteristics. +typedef struct +{ + char_data_t char_data[MAX_CHARACTERISTIC_COUNT]; /**< Characteristics data. */ + uint8_t count; /**< Characteristics count. */ +} srv_char_t; + +scanned_device_t m_device[DEVICE_TO_FIND_MAX]; /**< Storage device info from scan data. */ +char m_addr_str_for_connection[ADDR_STRING_LEN]; /**< Store device address as string for establishing a connection. */ +srv_char_t m_srv_char; /**< Storing all the characteristics data from one service to allow further operations. */ +uint16_t m_desc_handle; /**< Found CCCD Descriptor handle. */ +device_srv_t * mp_device_srv[NRF_BLE_LINK_COUNT]; /**< Pointers to allocated memory needed to discover the services on the server. */ +static bool m_numeric_match_requested = false; /**< Numeric match request. */ +static uint16_t m_num_comp_conn_handle; /**< Numeric comparison connection handle. */ +static conn_peer_t m_connected_peers[NRF_BLE_LINK_COUNT]; /**< Connected devices data. */ +bool m_scanning = false; /**< Variable informing about ongoing scanning. True when scan is on. */ +bool m_vendor_uuid_read = false; /**< Variable informing about the read request for a 128-bit service UUID. */ +uint8_t m_uuid_attr_handle; + +NRF_BALLOC_DEF(m_srv_pool, sizeof(device_srv_t), NRF_BLE_LINK_COUNT); + +/**@brief UUIDs which the central applications will scan for if the name above is set to an empty string, + * and which will be advertised by the peripherals. + */ +ble_uuid_t m_adv_uuids[] = { { BLE_UUID_BATTERY_SERVICE, BLE_UUID_TYPE_BLE }, + { BLE_UUID_RUNNING_SPEED_AND_CADENCE, BLE_UUID_TYPE_BLE } }; + +static char * mp_roles_str[] = +{ + "INVALID_ROLE", + "CENTRAL", + "PERIPHERAL", +}; + + +/**@brief Parameters used when scanning. + */ +static ble_gap_scan_params_t const m_scan_params = +{ + .active = 1, + .interval = SCAN_INTERVAL, + .window = SCAN_WINDOW, + .timeout = SCAN_DURATION, + .scan_phys = BLE_GAP_PHY_1MBPS, + .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL, +}; + +static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; /**< Buffer where advertising reports will be stored by the SoftDevice. */ + +/**@brief Pointer to the buffer where advertising reports will be stored by the SoftDevice. */ +static ble_data_t m_scan_buffer = +{ + m_scan_buffer_data, + BLE_GAP_SCAN_BUFFER_MIN +}; + + +/**@brief Connection parameters requested for connection. + */ +static ble_gap_conn_params_t const m_connection_param = +{ + MIN_CONNECTION_INTERVAL, + MAX_CONNECTION_INTERVAL, + SLAVE_LATENCY, + SUPERVISION_TIMEOUT +}; + + +/**@brief Function for handling asserts in the SoftDevice. + * + * @details This function will be called in case of an assert in the SoftDevice. + * + * @warning This handler is an example only and does not fit a final product. You need to analyze + * how your product is supposed to react in case of an assert. + * @warning On assert from the SoftDevice, the system can only recover on reset. + * + * @param[in] line_num Line number of the failing ASSERT call. + * @param[in] p_file_name File name of the failing ASSERT call. + */ +void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) +{ + ASSERT(p_file_name); + + app_error_handler(0xDEADBEEF, line_num, p_file_name); +} + + +/**@brief Function for handling errors from the Connection Parameters module. + * + * @param[in] nrf_error Error code containing information about what went wrong. + */ +static void conn_params_error_handler(uint32_t nrf_error) +{ + APP_ERROR_HANDLER(nrf_error); +} + + +bool is_scanning(void) +{ + return m_scanning; +} + + +void addr_store_value_set(char const * const p_address_str) +{ + ASSERT(p_address_str); + + strcpy(m_addr_str_for_connection, p_address_str); +} + + +scanned_device_t * scan_device_info_get(void) +{ + return m_device; +} + + +void scan_device_info_clear(void) +{ + memset(m_device, 0, sizeof(m_device)); +} + + +bool is_numeric_match_requested(void) +{ + return m_numeric_match_requested; +} + + +void numeric_match_request_clear(void) +{ + m_numeric_match_requested = false; +} + + +uint16_t numeric_match_request_conn_handle_get(void) +{ + return m_num_comp_conn_handle; +} + + +void preferred_phy_set(ble_gap_phys_t const * const p_phy, uint16_t conn_handle) +{ + ASSERT(p_phy); + + ret_code_t err_code; + + err_code = sd_ble_gap_phy_update(conn_handle, p_phy); + APP_ERROR_CHECK(err_code); +} + + +uint16_t cccd_descriptors_handle_get(char const * const p_char_uuid_str) +{ + ASSERT(p_char_uuid_str); + + char uuid_str[UUID_STRING_LEN] = {0}; + + // Searching for characteristic. + for (uint8_t i = 0; i < m_srv_char.count; i++) + { + + sprintf(uuid_str, "%X", m_srv_char.char_data[i].uuid.uuid); + + if ((!strcmp(uuid_str, p_char_uuid_str)) && m_srv_char.char_data[i].notify) + { + return m_srv_char.char_data[i].cccd_desc_handle; + } + } + + return BLE_GATT_HANDLE_INVALID; +} + + +/**@brief Function for searching for the CCCD of a characteristic. + * + * @param[in] char_uuid Characteristic UUID. + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + */ + +static void cccd_descriptors_search(uint16_t char_uuid, uint16_t conn_handle) +{ + uint8_t i; + ret_code_t err_code; + ble_gattc_handle_range_t handle_range; + uint16_t start_handle = 0; + uint16_t end_handle = 0; + + // Searching for the initial characteristic's handle. + for (i = 0; i < m_srv_char.count; i++) + { + if (m_srv_char.char_data[i].uuid.uuid == char_uuid) + { + start_handle = m_srv_char.char_data[i].value_handle + 1; + break; + } + } + + // Searching for the final characteristic's handle if the characteristic is not last in the service. + if ((i < (m_srv_char.count - 1)) && (m_srv_char.char_data[i + 1].uuid.uuid != 0)) + { + // If the characteristic is not last, start a handle equal to the declaration handle of the next characteristic's Declaration Handle. + end_handle = m_srv_char.char_data[i + 1].decl_handle - 1; + } + // Searching for the final characteristic handle if the characteristic is last in the service, the end handle is equal to the service end handle. + else + { + for (uint8_t j = 0; j < mp_device_srv[conn_handle]->count; j++) + { + if ((start_handle > + mp_device_srv[conn_handle]->services[j].handle_range.start_handle) && + (start_handle < mp_device_srv[conn_handle]->services[j].handle_range.end_handle)) + { + end_handle = mp_device_srv[conn_handle]->services[j].handle_range.end_handle; + break; + } + } + } + + handle_range.start_handle = start_handle; + handle_range.end_handle = end_handle; + + // Discovery descriptors inside, the found handle range. + err_code = sd_ble_gattc_descriptors_discover(conn_handle, &handle_range); + APP_ERROR_CHECK(err_code); +} + + +uint16_t handle_value_search(char const * const p_service_uuid_str) +{ + ASSERT(p_service_uuid_str); + + char buffer[UUID_STRING_LEN] = {0}; + + for (uint8_t i = 0; i < m_srv_char.count; i++) + { + sprintf(buffer, "%X", m_srv_char.char_data[i].uuid.uuid); + + if (!strcmp(buffer, p_service_uuid_str)) + { + return m_srv_char.char_data[i].value_handle; + } + } + + return BLE_GATT_HANDLE_INVALID; +} + + +ble_gattc_handle_range_t * handle_range_search(char const * const p_service_uuid_str, + uint16_t conn_handle) +{ + ASSERT(p_service_uuid_str); + + char buffer[UUID_STRING_LEN] = {0}; + + for (uint8_t i = 0; i < mp_device_srv[conn_handle]->count; i++) + { + + sprintf(buffer, "%X", mp_device_srv[conn_handle]->services[i].uuid.uuid); + if (!strcmp(buffer, p_service_uuid_str)) + { + return &mp_device_srv[conn_handle]->services[i].handle_range; + } + } + + return NULL; +} + + +void link_layer_data_length_set(char * p_data_length, uint16_t conn_handle) +{ + ASSERT(p_data_length); + + ret_code_t err_code; + uint8_t value; + uint16_t mtu; + + // Get actual MTU. + mtu = nrf_ble_gatt_eff_mtu_get(&m_gatt, conn_handle); + + value = atoi(p_data_length); + + // Check that new data length has a correct value. + if ((value > (mtu + L2CAP_HDR_LEN)) || (value < (BLE_GATT_ATT_MTU_DEFAULT + L2CAP_HDR_LEN))) + { + NRF_LOG_RAW_INFO("Data Length value should be less than: %d and bigger than %d\r\n", + (mtu + L2CAP_HDR_LEN), + (BLE_GATT_ATT_MTU_DEFAULT + L2CAP_HDR_LEN)); + return; + } + + // Set data length. + err_code = nrf_ble_gatt_data_length_set(&m_gatt, conn_handle, value); + APP_ERROR_CHECK(err_code); +} + + +void gatt_mtu_set(char const * const p_mtu_value) +{ + ASSERT(p_mtu_value); + + ret_code_t err_code; + uint16_t mtu_val; + + mtu_val = atoi(p_mtu_value); + + // Checking the new MTU value. + if ((mtu_val < BLE_GATT_ATT_MTU_DEFAULT) || + (mtu_val > NRF_SDH_BLE_GATT_MAX_MTU_SIZE)) + { + NRF_LOG_RAW_INFO("%s %d - %d \r\n", + "MTU value should be between", + BLE_GATT_ATT_MTU_DEFAULT, + NRF_SDH_BLE_GATT_MAX_MTU_SIZE); + return; + } + + // New maxiumum MTU must be set before a connection is established. + err_code = nrf_ble_gatt_att_mtu_central_set(&m_gatt, mtu_val); + APP_ERROR_CHECK(err_code); + + err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, mtu_val); + APP_ERROR_CHECK(err_code); + + NRF_LOG_RAW_INFO("MTU will be changed for next connection. Processing MTU change.\r\n"); +} + + +char const * phy_str(ble_gap_phys_t const * const p_phys) +{ + ASSERT(p_phys); + + static char const * p_str[] = + { + "1 Mbps", + "2 Mbps", + "Coded", + "Unknown" + }; + + switch (p_phys->tx_phys) + { + case BLE_GAP_PHY_1MBPS: + return p_str[0]; + + case BLE_GAP_PHY_2MBPS: + case (BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS): + case (BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_CODED): + return p_str[1]; + + case BLE_GAP_PHY_CODED: + return p_str[2]; + + default: + return p_str[3]; + } +} + + +void int_addr_to_hex_str(char * p_result, uint8_t result_len, uint8_t const * const p_addr) +{ + ASSERT(p_result); + ASSERT(p_addr); + + if (result_len > BLE_GAP_ADDR_LEN) + { + return; + } + + char buffer[BLE_GAP_ADDR_LEN] = {0}; + + memset(p_result, 0, result_len); + + for (uint8_t i = 0; i < result_len; ++i) + { + sprintf(buffer, "%.2X", p_addr[result_len - (i + 1)]); + strcat(p_result, buffer); + + if (i < (result_len - 1)) + { + strcat(p_result, ":"); + } + } +} + + +/**@brief Function for printing the services UUID. + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] service_p Pointer to ble_gattc_service_t. + */ +static void uuid_print(uint16_t conn_handle, ble_gattc_service_t const * p_service) +{ + NRF_LOG_RAW_INFO("Found services UUID: \r\n"); + + for (uint8_t i = 0; i < mp_device_srv[conn_handle]->count; i++) + { + NRF_LOG_RAW_INFO("%s: %X %s: 0x%X\r\n", + "UUID", + p_service[i].uuid.uuid, + "type", + p_service[i].uuid.type); + } +} + + +bool is_address_compare(ble_gap_addr_t const * const p_connected_addr, char const * const p_addr) +{ + ASSERT(p_connected_addr); + ASSERT(p_addr); + + char string_addr_buf[ADDR_STRING_LEN] = {0}; + + int_addr_to_hex_str(string_addr_buf, + BLE_GAP_ADDR_LEN, + p_connected_addr->addr); + + return (memcmp(string_addr_buf, p_addr, sizeof(string_addr_buf))) ? false : true; +} + + +uint16_t addr_string_to_conn_handle(char const * const p_addr) +{ + ASSERT(p_addr); + + uint16_t conn_handle = 0; + uint8_t idx; + + for (idx = 0; idx < NRF_BLE_LINK_COUNT; idx++) + { + if (is_address_compare(&m_connected_peers[idx].address, p_addr)) + { + conn_handle = idx; + return conn_handle; + } + } + + return BLE_CONN_HANDLE_INVALID; +} + + +/**@brief Function for searching for a device name and adding it to a dynamic command. + * + * @details Use this function to parse the received advertising data and to find a given + * name in them either as 'complete_local_name' or as 'short_local_name'. + * + * @param[in] p_adv_report Advertising data to parse. + */ +static void device_to_list_add(ble_gap_evt_adv_report_t const * p_adv_report) +{ + uint8_t idx = 0; + uint16_t dev_name_offset = 0; + uint16_t field_len; + data_t adv_data; + + + // Initialize advertisement report for parsing + adv_data.p_data = (uint8_t *)p_adv_report->data.p_data; + adv_data.data_len = p_adv_report->data.len; + + for ( idx = 0; idx < DEVICE_TO_FIND_MAX; idx++) + { + // If address is duplicated, then return. + if (memcmp(p_adv_report->peer_addr.addr, + m_device[idx].addr, + sizeof(p_adv_report->peer_addr.addr)) == 0) + { + return; + } + } + + // Add device data if an empty record is found. + for (idx = 0; idx < DEVICE_TO_FIND_MAX; idx++) + { + if (!m_device[idx].is_not_empty) + { + memcpy(m_device[idx].addr, + p_adv_report->peer_addr.addr, + sizeof(p_adv_report->peer_addr.addr)); + + m_device[idx].is_not_empty = true; + + // Search for advertising names. + field_len = ble_advdata_search(adv_data.p_data, + adv_data.data_len, + &dev_name_offset, + BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME); + + if (field_len == 0) + { + field_len = ble_advdata_search(adv_data.p_data, + adv_data.data_len, + &dev_name_offset, + BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME); + // If name is not found, then return. + if (field_len == 0) + { + return; + } + } + memcpy(m_device[idx].dev_name, &adv_data.p_data[dev_name_offset], field_len); + m_device[idx].dev_name[field_len] = 0; + + return; + } + } +} + + +/**@brief Function for displaying an address in HEX format. + */ +static void hex_addr_display(uint8_t const * p_addr, size_t size) +{ + NRF_LOG_RAW_INFO("Connected to address: "); + + for (uint8_t i = 0; i < size; ++i) + { + NRF_LOG_RAW_INFO("%.2X ", p_addr[size - (i + 1)]); + } + + NRF_LOG_RAW_INFO("\r\n"); +} + + +/**@brief Function for parsing data from NFC central and connecting if data matches. + * + * @param[in] p_gap_evt Pointer to GAP data event. + * @param[in] p_peer_addr Pointer to adv_report address. + */ +static void nfc_central_connect(ble_gap_evt_t const * p_gap_evt, + ble_gap_addr_t const * const p_peer_addr) +{ + ret_code_t err_code; + uint8_t * p_adv_data; + uint16_t data_len; + uint16_t dev_name_offset = 0; + uint16_t field_len; + char dev_name[32]; + + // Initialize advertisement report for parsing. + p_adv_data = (uint8_t *)p_gap_evt->params.adv_report.data.p_data; + data_len = p_gap_evt->params.adv_report.data.len; + + // Search for advertising names. + field_len = ble_advdata_search(p_adv_data, + data_len, + &dev_name_offset, + BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME); + + if (field_len == 0) + { + // Look for the short local name if it was not found as complete. + field_len = ble_advdata_search(p_adv_data, + data_len, + &dev_name_offset, + BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME); + + if (field_len == 0) + { + // If data cannot be parsed, then exit. + return; + } + } + + memcpy(dev_name, &p_adv_data[dev_name_offset], field_len); + dev_name[field_len] = 0; + + NRF_LOG_DEBUG("Found advertising device: %s", nrf_log_push( (char *)dev_name)); + + // Check if device address is the same as the address taken from the NFC tag. + if (nfc_oob_pairing_tag_match(p_peer_addr)) + { + // If the address is correct, stop scanning and initiate a connection with the peripheral device. + err_code = sd_ble_gap_scan_stop(); + APP_ERROR_CHECK(err_code); + + err_code = sd_ble_gap_connect(p_peer_addr, &m_scan_params, + &m_connection_param, + APP_BLE_CONN_CFG_TAG); + APP_ERROR_CHECK(err_code); + } +} + + +void private_connect(pm_peer_id_t const * p_peers_id) +{ + ASSERT(p_peers_id); + + ret_code_t err_code; + ble_gap_addr_t public_addr; + + memset(&public_addr, 0, sizeof(public_addr)); + pm_peer_data_bonding_t data; + memset(&data, 0, sizeof(data)); + + // Load device bonding data. + err_code = pm_peer_data_bonding_load(*p_peers_id, &data); + + if (err_code != NRF_SUCCESS) + { + NRF_LOG_INFO("Try again with correct peer ID."); + return; + } + + memcpy(&public_addr, + &data.peer_ble_id.id_addr_info, + sizeof(public_addr)); + + // Stop scanning. + (void)sd_ble_gap_scan_stop(); + + // Set device identities list. + err_code = pm_device_identities_list_set(p_peers_id, 1); + APP_ERROR_CHECK(err_code); + + scan_start(); + + // Connect with device using privacy by public address. + err_code = sd_ble_gap_connect(&public_addr, &m_scan_params, + &m_connection_param, + APP_BLE_CONN_CFG_TAG); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Function for handling primary service discovery response. + * + * @details This function will handle the primary service discovery response. + * + * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. + */ +static void on_primary_srv_discovery_rsp(ble_gattc_evt_t const * p_ble_gattc_evt) +{ + uint16_t count; + uint16_t bytes_to_copy; + uint16_t conn_handle; + static uint16_t offset = 0; + ret_code_t err_code; + + // For readability. + ble_gattc_evt_prim_srvc_disc_rsp_t const * p_prim_serv = + &(p_ble_gattc_evt->params.prim_srvc_disc_rsp); + conn_handle = p_ble_gattc_evt->conn_handle; + ble_gattc_service_t * const p_service = + mp_device_srv[conn_handle]->services; + + // Number of discovered services. + count = p_prim_serv->count; + + // If no more services are found. + if ((count != 0) && + (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS)) + { + if ((count + offset) > MAX_SERVICE_COUNT) + { + bytes_to_copy = MAX_SERVICE_COUNT - offset; + } + else + { + bytes_to_copy = count; + } + + // Save services data. + memcpy((p_service + offset), + p_prim_serv->services, + bytes_to_copy * sizeof(ble_gattc_service_t)); + + offset += count; + + // If the last service has not been reached, this function must be called again with a new start handle. + err_code = sd_ble_gattc_primary_services_discover( + conn_handle, + p_prim_serv->services[count - 1].handle_range.end_handle, + NULL); + APP_ERROR_CHECK(err_code); + } + else + { + mp_device_srv[conn_handle]->count = offset; + + // If service UUID type is unknown, then look for a 128-bit UUID. + // Only the first one is searched for here, the rest is searched for in the @ref on_read_rsp. + for (uint8_t i = 0; i < offset; i++) + { + if (p_service[i].uuid.type == BLE_UUID_TYPE_UNKNOWN) + { + m_vendor_uuid_read = true; + // Read service 128-bit UUID. + err_code = sd_ble_gattc_read(conn_handle, p_service[i].handle_range.start_handle, 0); + APP_ERROR_CHECK(err_code); + offset = 0; + + return; + } + } + + NRF_LOG_INFO("Services count: %d", offset); + uuid_print(p_ble_gattc_evt->conn_handle, p_service); + + offset = 0; + } +} + + +/**@brief Function for starting a discovery of CCCD descriptors. + * + * @details If characteristics can be notified, then look for CCCD descriptors in all + * characteristics inside the service. + * + * @param[in] p_ble_gattc_evt + */ +static void cccd_descriptors_discovery(ble_gattc_evt_t const * p_ble_gattc_evt) +{ + for (uint8_t i = 0; i < m_srv_char.count; i++) + { + // If it is possible to enable notification. + if (m_srv_char.char_data[i].notify) + { + // Search for CCCD descriptor handle + cccd_descriptors_search(m_srv_char.char_data[i].uuid.uuid, p_ble_gattc_evt->conn_handle); + } + } +} + + +/**@brief Function for handling a characteristic discovery response. + * + * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. + */ +static void on_characteristics_discovery_rsp(ble_gattc_evt_t const * p_ble_gattc_evt) +{ + uint16_t count; + static uint16_t offset = 0;; + uint16_t bytes_to_copy; + ret_code_t err_code; + uint16_t conn_handle = p_ble_gattc_evt->conn_handle; + + // For readability. + count = p_ble_gattc_evt->params.char_disc_rsp.count; + ble_gattc_evt_char_disc_rsp_t const * p_char_disc_rsp_evt; + + p_char_disc_rsp_evt = &(p_ble_gattc_evt->params.char_disc_rsp); + + if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS) + { + if ((count + offset) > MAX_CHARACTERISTIC_COUNT) + { + bytes_to_copy = MAX_CHARACTERISTIC_COUNT - offset; + NRF_LOG_RAW_INFO("Too many characteristics discovered\r\n"); + } + else + { + bytes_to_copy = count; + } + + // Save characteristics data. + for (uint8_t i = offset; i < bytes_to_copy; i++) + { + m_srv_char.char_data[i].decl_handle = p_char_disc_rsp_evt->chars[i].handle_decl; + m_srv_char.char_data[i].value_handle = p_char_disc_rsp_evt->chars[i].handle_value; + m_srv_char.char_data[i].uuid = p_char_disc_rsp_evt->chars[i].uuid; + m_srv_char.char_data[i].notify = p_char_disc_rsp_evt->chars[i].char_props.notify; + m_srv_char.char_data[i].cccd_desc_handle = 0; + + offset++; + } + + // Display characteristics data. + for (uint8_t i = 0; i < offset; i++) + { + ble_gatt_char_props_t char_param = + p_ble_gattc_evt->params.char_disc_rsp.chars[i].char_props; + + NRF_LOG_RAW_INFO("Characteristic UUID: %X\r\n", + p_ble_gattc_evt->params.char_disc_rsp.chars[i].uuid.uuid); + NRF_LOG_RAW_INFO("Parameters:\r\n"); + NRF_LOG_RAW_INFO("broadcast: %d ", char_param.broadcast); + NRF_LOG_RAW_INFO("read: %d ", char_param.read); + NRF_LOG_RAW_INFO("write_wo_resp: %d ", char_param.write_wo_resp); + NRF_LOG_RAW_INFO("write: %d ", char_param.write); + NRF_LOG_RAW_INFO("notify: %d\r\n", char_param.notify); + NRF_LOG_RAW_INFO("indicate: %d ", char_param.indicate); + NRF_LOG_RAW_INFO("auth_signed_wr: %d\r\n", char_param.auth_signed_wr); + } + } + // If the last characteristic has not been reached, look for a new handle range. + ble_gattc_handle_range_t handle_range; + + handle_range.start_handle = m_srv_char.char_data[offset - 1].value_handle + 1; + + // Search for end handle. + for (uint8_t j = 0; j < mp_device_srv[conn_handle]->count; j++) + { + if (handle_range.start_handle > + mp_device_srv[conn_handle]->services[j].handle_range.start_handle) + { + handle_range.end_handle = + mp_device_srv[conn_handle]->services[j].handle_range.end_handle; + break; + } + } + + // Handle value of the characteristic being discovered is less than the end handle of + // the service being discovered. There is no possibility of more characteristics being + // present. + if ((m_srv_char.char_data[offset - 1].value_handle >= handle_range.end_handle) || + (offset == MAX_CHARACTERISTIC_COUNT) || + (p_ble_gattc_evt->gatt_status != BLE_GATT_STATUS_SUCCESS)) + { + NRF_LOG_RAW_INFO("Number of characteristics: %d\r\n", offset); + m_srv_char.count = offset; + offset = 0; + + // Search for the CCCD descriptors. + cccd_descriptors_discovery(p_ble_gattc_evt); + + return; + } + + // If the last Characteristic has not been reached, this function must be called again with new handle range. + err_code = sd_ble_gattc_characteristics_discover(p_ble_gattc_evt->conn_handle, &handle_range); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Function for handling descriptor discovery response. + * + * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. + */ +static void on_descriptor_discovery_rsp(const ble_gattc_evt_t * const p_ble_gattc_evt) +{ + uint16_t count; + uint16_t conn_handle = p_ble_gattc_evt->conn_handle; + ret_code_t err_code; + + count = p_ble_gattc_evt->params.desc_disc_rsp.count; + + // If no more descriptors are found. + if (count == 0) + { + NRF_LOG_RAW_INFO("No descriptors for characteristic, ", + "notifications and indications not possible\r\n"); + return; + } + + if (p_ble_gattc_evt->gatt_status != BLE_GATT_STATUS_SUCCESS) + { + return; + } + + // If the descriptor was found, connect it to the characteristic. + for (uint8_t i = 0; i < count; i++) + { + if (p_ble_gattc_evt->params.desc_disc_rsp.descs[i].uuid.uuid == CCCD_DESCRIPTOR_UUID) + { + for (uint8_t j = 0; j < m_srv_char.count; j++) + { + if (m_srv_char.char_data[j].cccd_desc_handle == 0 && m_srv_char.char_data[j].notify) + { + m_srv_char.char_data[j].cccd_desc_handle = + p_ble_gattc_evt->params.desc_disc_rsp.descs[i].handle; + } + } + return; + } + } + + // If the last descriptors have not been found, look for a new handle range to search for. + ble_gattc_handle_range_t handle_range; + memset(&handle_range, 0, sizeof(handle_range)); + + handle_range.start_handle = p_ble_gattc_evt->params.desc_disc_rsp.descs[count - 1].handle + 1; + + for (uint8_t i = 0; i < m_srv_char.count; i++) + { + // Search for end handle, to descriptors searching. + if ((handle_range.start_handle >= m_srv_char.char_data[i].value_handle) && + (i < (m_srv_char.count - 1))) + { + // If current characteristic is not last in service + handle_range.end_handle = m_srv_char.char_data[i + 1].decl_handle - 1; + break; + } + // If the characteristic is last into service, search for service end handle. + if (i == (m_srv_char.count - 1)) + { + for (uint8_t j = 0; j < mp_device_srv[conn_handle]->count; j++) + { + if ((handle_range.start_handle > + mp_device_srv[conn_handle]->services[j].handle_range.start_handle) && + (handle_range.start_handle < + mp_device_srv[conn_handle]->services[j].handle_range.end_handle)) + { + handle_range.end_handle = + mp_device_srv[conn_handle]->services[j].handle_range.end_handle; + break; + } + } + } + } + + // If the last descriptors have not been reached, this function must be called again with a new handle range. + err_code = sd_ble_gattc_descriptors_discover(conn_handle, &handle_range); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Function for handling a read response. + * + * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. + */ +static void on_read_rsp(const ble_gattc_evt_t * const p_ble_gattc_evt) +{ + ret_code_t err_code; + uint16_t conn_handle = p_ble_gattc_evt->conn_handle; + ble_uuid128_t uuid; + const ble_gattc_evt_read_rsp_t * p_read_rsp = &(p_ble_gattc_evt->params.read_rsp); + + if (m_vendor_uuid_read) + { + for (uint8_t i = 0; i < mp_device_srv[conn_handle]->count; i++) + { + if (p_read_rsp->handle == + mp_device_srv[conn_handle]->services[i].handle_range.start_handle) + { + //lint -save -e420 + memcpy(uuid.uuid128, p_read_rsp->data, sizeof(uuid.uuid128)); + //lint -restore + err_code = sd_ble_uuid_vs_add(&uuid, &mp_device_srv[conn_handle]->services[i].uuid.type); + APP_ERROR_CHECK(err_code); + break; + } + } + + // If service UUID type is unknown, then try to search for the 128-bit UUID. + for (uint8_t i = 0; i < mp_device_srv[conn_handle]->count; i++) + { + if (mp_device_srv[conn_handle]->services[i].uuid.type == BLE_UUID_TYPE_UNKNOWN) + { + m_vendor_uuid_read = true; + // Look for service 128-bit UUID. + err_code = sd_ble_gattc_read(conn_handle, mp_device_srv[conn_handle]->services[i].handle_range.start_handle, 0); + APP_ERROR_CHECK(err_code); + return; + } + + // If service is last. + if (i == (mp_device_srv[conn_handle]->count - 1)) + { + NRF_LOG_INFO("Services count: %d", mp_device_srv[conn_handle]->count); + m_vendor_uuid_read = false; + // Print services UUID. When you first discover services, the 128-bit UUIDs may not be displayed. + // In such case, you should rediscover the services. + uuid_print(p_ble_gattc_evt->conn_handle, mp_device_srv[conn_handle]->services); + } + } + + return; + } + + NRF_LOG_RAW_INFO("Read data:\r\n"); + + for (uint8_t i = 0; i < p_read_rsp->len; i++) + { + NRF_LOG_RAW_INFO("0x%X ", p_read_rsp->data[i]); + } + + NRF_LOG_RAW_INFO("\r\n"); + + // The application only supports reading data of length less than MTU which was set for this connection. +} + + +/**@brief Function for handling a write response. + * + * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. + */ +static void on_write_rsp(const ble_gattc_evt_t * const p_ble_gattc_evt) +{ + // For readability. + const ble_gattc_evt_write_rsp_t * p_write_rsp = &(p_ble_gattc_evt->params.write_rsp); + + // Display gattc write status. + NRF_LOG_RAW_INFO("Type of write operation: 0x%x\r\n", p_write_rsp->write_op); + NRF_LOG_RAW_INFO("Data was written to the server \r\n"); + + for (uint8_t i = 0; i < p_write_rsp->len; i++) + { + NRF_LOG_RAW_INFO("%d ", p_write_rsp->data[i]); + } + + if (p_write_rsp->len > 0) + { + NRF_LOG_RAW_INFO("\r\n"); + } + +} + + +static void on_ble_evt(uint16_t conn_handle, ble_evt_t const * p_ble_evt) +{ + ret_code_t err_code; + char passkey[BLE_GAP_PASSKEY_LEN + 1]; + uint16_t role = ble_conn_state_role(conn_handle); + + switch (p_ble_evt->header.evt_id) + { + case BLE_GAP_EVT_CONNECTED: + { + // Store device data to dynamic command buffer and for futher operations. + m_connected_peers[conn_handle].address = + p_ble_evt->evt.gap_evt.params.connected.peer_addr; + connected_to_cmd_add(m_connected_peers, conn_handle); + // Display device address. + hex_addr_display(p_ble_evt->evt.gap_evt.params.connected.peer_addr.addr, + BLE_GAP_ADDR_LEN); + // Allocation memory for services data. + mp_device_srv[conn_handle] = (device_srv_t *)nrf_balloc_alloc(&m_srv_pool); + } + break; + + case BLE_GAP_EVT_DISCONNECTED: + // Clearing device data. + connected_to_cmd_remove(m_connected_peers, conn_handle); + memset(&m_connected_peers[conn_handle], 0x00, sizeof(m_connected_peers[0])); + // Release of allocated memory. + nrf_balloc_free(&m_srv_pool, mp_device_srv[conn_handle]); + break; + + case BLE_GAP_EVT_PASSKEY_DISPLAY: + memcpy(passkey, + p_ble_evt->evt.gap_evt.params.passkey_display.passkey, + BLE_GAP_PASSKEY_LEN); + passkey[BLE_GAP_PASSKEY_LEN] = 0x00; + NRF_LOG_INFO("%s: BLE_GAP_EVT_PASSKEY_DISPLAY: passkey=%s match_req=%d", + nrf_log_push(mp_roles_str[role]), + nrf_log_push(passkey), + p_ble_evt->evt.gap_evt.params.passkey_display.match_request); + + if (p_ble_evt->evt.gap_evt.params.passkey_display.match_request) + { + NRF_LOG_INFO("Type /numeric accept/ to confirm, /numeric reject/ to reject"); + m_num_comp_conn_handle = conn_handle; + m_numeric_match_requested = true; + } + + break; + + case BLE_GAP_EVT_AUTH_KEY_REQUEST: + key_request_set(); + NRF_LOG_DEBUG("%s: BLE_GAP_EVT_AUTH_KEY_REQUEST", nrf_log_push(mp_roles_str[role])); + break; + + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: + NRF_LOG_DEBUG("%s: BLE_GAP_EVT_LESC_DHKEY_REQUEST", nrf_log_push(mp_roles_str[role])); + break; + + case BLE_GAP_EVT_AUTH_STATUS: + NRF_LOG_INFO( + "%s: BLE_GAP_EVT_AUTH_STATUS: status=0x%x bond=0x%x lv4: %d", + nrf_log_push(mp_roles_str[role]), + p_ble_evt->evt.gap_evt.params.auth_status.auth_status, + p_ble_evt->evt.gap_evt.params.auth_status.bonded, + p_ble_evt->evt.gap_evt.params.auth_status.sm1_levels.lv4); + NRF_LOG_DEBUG("kdist_own:0x%x kdist_peer:0x%x", + *( (uint8_t *)&p_ble_evt->evt.gap_evt.params.auth_status.kdist_own), + *( (uint8_t *)&p_ble_evt->evt.gap_evt.params.auth_status.kdist_peer)); + break; + + case BLE_GAP_EVT_PHY_UPDATE_REQUEST: + { + ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt; + NRF_LOG_RAW_INFO("PHY update request\r\n"); + ble_gap_phys_t phy_param = + { + .rx_phys = BLE_GAP_PHY_AUTO, + .tx_phys = BLE_GAP_PHY_AUTO, + }; + err_code = sd_ble_gap_phy_update(p_gap_evt->conn_handle, &phy_param); + APP_ERROR_CHECK(err_code); + } + break; + + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + { + on_primary_srv_discovery_rsp(&(p_ble_evt->evt.gattc_evt)); + } + break; + + case BLE_GATTC_EVT_CHAR_DISC_RSP: + { + on_characteristics_discovery_rsp(&(p_ble_evt->evt.gattc_evt)); + } + break; + + case BLE_GATTC_EVT_DESC_DISC_RSP: + { + on_descriptor_discovery_rsp(&(p_ble_evt->evt.gattc_evt)); + } + break; + + case BLE_GATTC_EVT_READ_RSP: + { + on_read_rsp(&(p_ble_evt->evt.gattc_evt)); + } + break; + + case BLE_GATTC_EVT_WRITE_RSP: + { + on_write_rsp(&(p_ble_evt->evt.gattc_evt)); + } + break; + + case BLE_GATTC_EVT_HVX: + { + // If server sends an indication, then send a Handle Value Confirmation to the GATT Server. + if (p_ble_evt->evt.gattc_evt.params.hvx.type == BLE_GATT_HVX_INDICATION) + { + err_code = sd_ble_gattc_hv_confirm(p_ble_evt->evt.gattc_evt.conn_handle, + p_ble_evt->evt.gattc_evt.params.hvx.handle); + APP_ERROR_CHECK(err_code); + } + + uint8_t data_len = p_ble_evt->evt.gattc_evt.params.hvx.len; + NRF_LOG_RAW_INFO( + "%s data: ", + (p_ble_evt->evt.gattc_evt.params.hvx.type != + BLE_GATT_HVX_NOTIFICATION) ? "Indication" : "Notification"); + + // Display notifications or indication data. + for (uint8_t i = 0; i < data_len; i++) + { + NRF_LOG_RAW_INFO("%d ", p_ble_evt->evt.gattc_evt.params.hvx.data[i]); + } + + NRF_LOG_RAW_INFO("\r\n"); + } + break; + + default: + // No implementation needed. + break; + } +} + + +/**@brief Function for handling BLE Stack events concerning central applications. + * + * @details This function keeps the connection handles of central applications up-to-date. It + * parses scanning reports, initiating a connection attempt to peripherals, + * and manages connection parameter update requests. Additionally, it updates the status + * of LEDs used to report central applications' activity. + * + * @note Since this function updates the connection handles, @ref BLE_GAP_EVT_DISCONNECTED events + * should be dispatched to the target application before invoking this function. + * + * @param[in] p_ble_evt Bluetooth stack event. + */ +static void on_ble_central_evt(ble_evt_t const * p_ble_evt) +{ + ret_code_t err_code; + // For readability + ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt; + ble_gap_addr_t const * const p_peer_addr = &p_gap_evt->params.adv_report.peer_addr; + + switch (p_ble_evt->header.evt_id) + { + // Upon connection, update LEDs status. + case BLE_GAP_EVT_CONNECTED: + { + NRF_LOG_INFO("CENTRAL: Connected, handle: %d.", p_gap_evt->conn_handle); + memset(m_addr_str_for_connection, 0, sizeof(m_addr_str_for_connection)); + + // Update LEDs status. + bsp_board_led_off(CENTRAL_SCANNING_LED); + bsp_board_led_on(CENTRAL_CONNECTED_LED); + } + break; // BLE_GAP_EVT_CONNECTED + + // Upon disconnection, reset the connection handle of the peer which disconnected, update + // the LEDs status. + case BLE_GAP_EVT_DISCONNECTED: + { + NRF_LOG_INFO("CENTRAL: Disconnected, handle: %d, reason: 0x%x", + p_gap_evt->conn_handle, + p_gap_evt->params.disconnected.reason); + + // Update LEDs status. + bsp_board_led_off(CENTRAL_CONNECTED_LED); + } + break; // BLE_GAP_EVT_DISCONNECTED + + case BLE_GAP_EVT_ADV_REPORT: + { + if (is_address_compare(&p_gap_evt->params.adv_report.peer_addr, + m_addr_str_for_connection)) + { + memset(m_addr_str_for_connection, 0, sizeof(m_addr_str_for_connection)); + + // Initiate connection. + NRF_LOG_INFO("CENTRAL: Connecting..."); + err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.peer_addr, + &m_scan_params, &m_connection_param, + APP_BLE_CONN_CFG_TAG); + + if (err_code != NRF_SUCCESS) + { + NRF_LOG_DEBUG("Connection Request Failed, reason %d", err_code); + return; + } + } + else + { + err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer); + APP_ERROR_CHECK(err_code); + } + + // If pairing request in NFC central role, then compare data and connect. + nfc_central_connect(p_gap_evt, p_peer_addr); + + // Add device address and name (if exists) from the scan report to dynamic CLI command. + device_to_list_add(&p_gap_evt->params.adv_report); + address_to_cmd_add(&p_gap_evt->params.adv_report.peer_addr); + } + break; // BLE_GAP_ADV_REPORT + + case BLE_GAP_EVT_TIMEOUT: + { + // Time-out for scanning has not been specified, so only connection attemps can time out. + if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) + { + NRF_LOG_DEBUG("CENTRAL: Connection Request timed out."); + } + } + break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE: + { + NRF_LOG_RAW_INFO("Connection parameters update success\r\n"); + } + break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: + { + // Accept parameters requested by the peer. + err_code = sd_ble_gap_conn_param_update( + p_gap_evt->conn_handle, + &p_gap_evt->params.conn_param_update_request. + conn_params); + APP_ERROR_CHECK(err_code); + } + break; + + case BLE_GATTC_EVT_TIMEOUT: + // Disconnect on GATT Client time-out event. + NRF_LOG_DEBUG("CENTRAL: GATT Client Time-out."); + err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, + BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + APP_ERROR_CHECK(err_code); + break; + + case BLE_GATTS_EVT_TIMEOUT: + // Disconnect on GATT Server time-out event. + NRF_LOG_DEBUG("CENTRAL: GATT Server Time-out."); + err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, + BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + APP_ERROR_CHECK(err_code); + break; + + case BLE_GATTC_EVT_EXCHANGE_MTU_RSP: + NRF_LOG_RAW_INFO("Current MTU: %d\r\n", + p_ble_evt->evt.gattc_evt.params.exchange_mtu_rsp.server_rx_mtu); + + break; + + case BLE_GAP_EVT_PHY_UPDATE: + { + ble_gap_evt_phy_update_t const * p_phy_evt = &p_ble_evt->evt.gap_evt.params.phy_update; + + if (p_phy_evt->status == BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION) + { + // Ignore LL collisions. + NRF_LOG_DEBUG("LL transaction collision during PHY update."); + break; + } + + ble_gap_phys_t phys = { 0 }; + phys.tx_phys = p_phy_evt->tx_phy; + phys.rx_phys = p_phy_evt->rx_phy; + + NRF_LOG_INFO("PHY update %s. PHY set to %s.", + (p_phy_evt->status == BLE_HCI_STATUS_CODE_SUCCESS) ? + "accepted" : "rejected", + phy_str(&phys)); + } + break; + + default: + // No implementation needed. + break; + } +} + + +/**@brief Function for handling BLE Stack events involving peripheral applications. Manages the + * LEDs used to report the status of the peripheral applications. + * + * @param[in] p_ble_evt Bluetooth stack event. + */ +static void on_ble_peripheral_evt(ble_evt_t const * p_ble_evt) +{ + ret_code_t err_code; + + switch (p_ble_evt->header.evt_id) + { + case BLE_GAP_EVT_CONNECTED: + NRF_LOG_INFO("PERIPHERAL: Connected, handle %d.", p_ble_evt->evt.gap_evt.conn_handle); + bsp_board_led_off(PERIPHERAL_ADVERTISING_LED); + bsp_board_led_on(PERIPHERAL_CONNECTED_LED); + break; + + case BLE_GAP_EVT_DISCONNECTED: + NRF_LOG_INFO("PERIPHERAL: Disconnected, handle %d, reason 0x%x.", + p_ble_evt->evt.gap_evt.conn_handle, + p_ble_evt->evt.gap_evt.params.disconnected.reason); + bsp_board_led_off(PERIPHERAL_CONNECTED_LED); + break; + + case BLE_GATTC_EVT_TIMEOUT: + // Disconnect on GATT Client time-out event. + NRF_LOG_DEBUG("PERIPHERAL: GATT Client Time-out."); + err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, + BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + APP_ERROR_CHECK(err_code); + break; + + case BLE_GATTS_EVT_TIMEOUT: + // Disconnect on GATT Server time-out event. + NRF_LOG_DEBUG("PERIPHERAL: GATT Server Time-out."); + err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, + BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + APP_ERROR_CHECK(err_code); + break; + + case BLE_EVT_USER_MEM_REQUEST: + err_code = sd_ble_user_mem_reply(p_ble_evt->evt.gap_evt.conn_handle, NULL); + APP_ERROR_CHECK(err_code); + break; + + case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: + { + ble_gatts_evt_rw_authorize_request_t req; + ble_gatts_rw_authorize_reply_params_t auth_reply; + + req = p_ble_evt->evt.gatts_evt.params.authorize_request; + + if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID) + { + if ((req.request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ) || + (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) || + (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) + { + if (req.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) + { + auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; + } + else + { + auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ; + } + + auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED; + err_code = sd_ble_gatts_rw_authorize_reply( + p_ble_evt->evt.gatts_evt.conn_handle, + &auth_reply); + APP_ERROR_CHECK(err_code); + } + } + } + break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST + + case BLE_GAP_EVT_PHY_UPDATE: + { + ble_gap_evt_phy_update_t const * p_phy_evt = &p_ble_evt->evt.gap_evt.params.phy_update; + + if (p_phy_evt->status == BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION) + { + // Ignore LL collisions. + NRF_LOG_INFO("LL transaction collision during PHY update."); + break; + } + + ble_gap_phys_t phys = {0}; + phys.tx_phys = p_phy_evt->tx_phy; + phys.rx_phys = p_phy_evt->rx_phy; + + NRF_LOG_INFO("PHY update %s. PHY set to %s.", + (p_phy_evt->status == BLE_HCI_STATUS_CODE_SUCCESS) ? + "accepted" : "rejected", + phy_str(&phys)); + } + break; + + default: + // No implementation needed. + break; + } +} + + +/**@brief Function for handling advertising events. + * + * @param[in] ble_adv_evt Advertising event. + */ +static inline void on_adv_evt(ble_adv_evt_t ble_adv_evt) +{ + switch (ble_adv_evt) + { + case BLE_ADV_EVT_FAST: + bsp_board_led_on(PERIPHERAL_ADVERTISING_LED); + break; + + default: + // No implementation needed. + break; + } +} + + +/**@brief Function for handling BLE events. + * + * @param[in] p_ble_evt Bluetooth stack event. + * @param[in] p_context Unused. + */ +static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) +{ + uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle; + uint16_t role = ble_conn_state_role(conn_handle); + + on_ble_evt(conn_handle, p_ble_evt); + + if (role == BLE_GAP_ROLE_PERIPH) + { + // Manages peripheral LEDs. + on_ble_peripheral_evt(p_ble_evt); + } + else if ((role == BLE_GAP_ROLE_CENTRAL) || + (p_ble_evt->header.evt_id == BLE_GAP_EVT_ADV_REPORT)) + { + on_ble_central_evt(p_ble_evt); + } + else + { + } +} + + +/**@brief Function for initiating scanning. + */ +void scan_start(void) +{ + ret_code_t err_code; + + (void)sd_ble_gap_scan_stop(); + + //Clear the current device address. + memset(m_addr_str_for_connection, 0, sizeof(m_addr_str_for_connection)); + + connect_addr_clear(); + + err_code = sd_ble_gap_scan_start(&m_scan_params, &m_scan_buffer); + APP_ERROR_CHECK(err_code); + + bsp_board_led_on(CENTRAL_SCANNING_LED); + + NRF_LOG_INFO("Scanning"); + m_scanning = true; +} + + +/**@brief Function for stopping scanning. + */ +void scan_stop(void) +{ + (void)sd_ble_gap_scan_stop(); + bsp_board_led_off(CENTRAL_SCANNING_LED); + m_scanning = false; +} + + +/**@brief Function for initiating advertising. + */ +void adv_start(void) +{ + ret_code_t err_code; + + // Turn on the LED to signal advertising. + bsp_board_led_on(PERIPHERAL_ADVERTISING_LED); + + // Start advertising. + err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST); + + if (err_code == NRF_ERROR_CONN_COUNT) + { + NRF_LOG_INFO("Maximum connection count exceeded.\r\n"); + return; + } + + APP_ERROR_CHECK(err_code); + + NRF_LOG_INFO("Advertising"); +} + + +/**@brief Function for disabling advertising and scanning. + */ +void adv_stop(void) +{ + ret_code_t err_code; + + // Turn off the LED to signal advertising. + bsp_board_led_off(PERIPHERAL_ADVERTISING_LED); + err_code = sd_ble_gap_adv_stop(m_advertising.adv_handle); + + if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE) && (err_code != BLE_ERROR_INVALID_ADV_HANDLE)) + { + APP_ERROR_CHECK(err_code); + } +} + + +/**@brief Function for initializing the BLE stack. + * + * @details Initializes the SoftDevice and the BLE event interrupts. + */ +static void ble_stack_init(void) +{ + ret_code_t err_code; + + err_code = nrf_sdh_enable_request(); + APP_ERROR_CHECK(err_code); + + // Configure the BLE stack using the default settings. + // Fetch the start address of the application RAM. + uint32_t ram_start = 0; + err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start); + APP_ERROR_CHECK(err_code); + + // Enable BLE stack. + err_code = nrf_sdh_ble_enable(&ram_start); + APP_ERROR_CHECK(err_code); + + // Register a handler for BLE events. + NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL); +} + + +/**@brief Function for handling events from the BSP module. + * + * @param[in] event Event generated by button press. + */ +static void bsp_event_handler(bsp_event_t event) +{ + ret_code_t err_code; + + switch (event) + { + case BSP_EVENT_KEY_0: + err_code = ble_bas_battery_level_update(&m_bas, 87, BLE_CONN_HANDLE_ALL); + + if ((err_code != NRF_SUCCESS) && + (err_code != NRF_ERROR_INVALID_STATE) && + (err_code != NRF_ERROR_RESOURCES) && + (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) + ) + { + APP_ERROR_HANDLER(err_code); + } + + break; + + default: + break; + } +} + + +/**@brief Function for initializing buttons and LEDs. + */ +static inline void buttons_leds_init(void) +{ + ret_code_t err_code; + + err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Function for the GAP initialization. + * + * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the + * device including the device name, appearance, and the preferred connection parameters. + */ +static void gap_params_init(void) +{ + ret_code_t err_code; + ble_gap_conn_params_t gap_conn_params; + ble_gap_conn_sec_mode_t sec_mode; + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + + err_code = sd_ble_gap_device_name_set(&sec_mode, + (const uint8_t *)DEVICE_NAME, + strlen(DEVICE_NAME)); + APP_ERROR_CHECK(err_code); + + memset(&gap_conn_params, 0, sizeof(gap_conn_params)); + + gap_conn_params.min_conn_interval = MIN_CONNECTION_INTERVAL; + gap_conn_params.max_conn_interval = MAX_CONNECTION_INTERVAL; + gap_conn_params.slave_latency = SLAVE_LATENCY; + gap_conn_params.conn_sup_timeout = SUPERVISION_TIMEOUT; + + err_code = sd_ble_gap_ppcp_set(&gap_conn_params); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Function for handling BLE stack GATT events. + */ +static void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt) +{ + switch (p_evt->evt_id) + { + case NRF_BLE_GATT_EVT_ATT_MTU_UPDATED: + + NRF_LOG_RAW_INFO("MTU changed successfully\r\n"); + + break; + + case NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED: + NRF_LOG_INFO("Data length updated to %u bytes.", p_evt->params.data_length); + break; + + default: + break; + } +} + + +/**@brief Function for initializing the GATT module. + */ +static inline void gatt_init(void) +{ + ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler); + + APP_ERROR_CHECK(err_code); +} + + +/**@brief Function for handling the Connection Parameters Module. + * + * @details This function will be called for all events in the Connection Parameters Module which + * are passed to the application. + * @note All this function does is to disconnect. This could have been done by simply + * setting the disconnect_on_fail config parameter, but instead we use the event + * handler mechanism to demonstrate its use. + * + * @param[in] p_evt Event received from the Connection Parameters Module. + */ +static void on_conn_params_evt(ble_conn_params_evt_t * p_evt) +{ + ret_code_t err_code; + uint16_t conn_handle = p_evt->conn_handle; + + if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED) + { + err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE); + APP_ERROR_CHECK(err_code); + } +} + + +/**@brief Function for initializing the Connection Parameters module. + */ +static void conn_params_init(void) +{ + ret_code_t err_code; + ble_conn_params_init_t cp_init; + + memset(&cp_init, 0, sizeof(cp_init)); + + cp_init.p_conn_params = NULL; + cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY; + cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY; + cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT; + cp_init.start_on_notify_cccd_handle = BLE_CONN_HANDLE_INVALID; // Start upon connection. + cp_init.disconnect_on_fail = true; + cp_init.evt_handler = on_conn_params_evt; + cp_init.error_handler = conn_params_error_handler; + + err_code = ble_conn_params_init(&cp_init); + APP_ERROR_CHECK(err_code); +} + + +void advertising_init(void) +{ + ret_code_t err_code; + ble_advertising_init_t init; + + memset(&init, 0, sizeof(init)); + + init.advdata.name_type = BLE_ADVDATA_FULL_NAME; + init.advdata.include_appearance = true; + init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; + init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]); + init.advdata.uuids_complete.p_uuids = m_adv_uuids; + + init.config.ble_adv_fast_enabled = true; + init.config.ble_adv_fast_interval = ADV_INTERVAL; + init.config.ble_adv_fast_timeout = APP_ADV_DURATION; + + init.evt_handler = on_adv_evt; + + err_code = ble_advertising_init(&m_advertising, &init); + APP_ERROR_CHECK(err_code); + + ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); +} + + +/** + * @brief Function for initializing a block allocator. + */ +static inline void balloc_init(void) +{ + ret_code_t err_code; + + err_code = nrf_balloc_init(&m_srv_pool); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Function for initializing the Battery service. */ +static void bas_init(void) +{ + ret_code_t err_code; + ble_bas_init_t bas_init_struct; + uint8_t initial_batt_lvl; + + // Initialize the Battery Service. + initial_batt_lvl = BATTERY_INITIAL_LVL; + + memset(&bas_init_struct, 0, sizeof(bas_init_struct)); + + bas_init_struct.evt_handler = NULL; + bas_init_struct.support_notification = true; + bas_init_struct.p_report_ref = NULL; + bas_init_struct.initial_batt_level = initial_batt_lvl; + + // Require LESC with MITM (Numeric Comparison) + BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&bas_init_struct.battery_level_char_attr_md.cccd_write_perm); + BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init_struct.battery_level_char_attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init_struct.battery_level_char_attr_md.write_perm); + + // Require LESC with MITM (Numeric Comparison) + BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&bas_init_struct.battery_level_report_read_perm); + + err_code = ble_bas_init(&m_bas, &bas_init_struct); + APP_ERROR_CHECK(err_code); +} + + +void ble_m_init(void) +{ + // Initialization of required BLE components. + balloc_init(); + buttons_leds_init(); + ble_stack_init(); + gap_params_init(); + gatt_init(); + bas_init(); + conn_params_init(); + advertising_init(); +} + + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_m.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_m.h new file mode 100644 index 0000000..8355b17 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/ble_m.h @@ -0,0 +1,260 @@ +/** + * 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. + * + */ + +/** @brief Application BLE module. + * @details This module contains most of the functions used + * by the application to manage BLE stack events + * and BLE connections. + */ + +#ifndef BLE_M_H__ +#define BLE_M_H__ + +#include +#include +#include "ble_gap.h" +#include "ble_gattc.h" +#include "sdk_config.h" +#include "ble_advertising.h" +#include "peer_manager.h" + +#define MIN_CONNECTION_INTERVAL (uint16_t)MSEC_TO_UNITS(MINIMUM_CONNECTION_INTERVAL, UNIT_1_25_MS) /**< Determines minimum connection interval in milliseconds. */ +#define MAX_CONNECTION_INTERVAL (uint16_t)MSEC_TO_UNITS(MAXIMUM_CONNECTION_INTERVAL, UNIT_1_25_MS) /**< Determines maximum connection interval in milliseconds. */ +#define SLAVE_LATENCY CONNECTION_SLAVE_LATENCY /**< Determines slave latency in terms of connection events. */ +#define SUPERVISION_TIMEOUT (uint16_t)MSEC_TO_UNITS(CONNECTION_SUPERVISION_TIMEOUT, UNIT_10_MS) /**< Determines supervision time-out in units of 10 milliseconds. */ + +/**@brief The maximum number of peripheral and central links combined. + */ +#define NRF_BLE_LINK_COUNT (NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + NRF_SDH_BLE_CENTRAL_LINK_COUNT) +#define ADDR_STRING_LEN (2 * (BLE_GAP_ADDR_LEN)+6) /**< Determines device BLE address length in string format. Address formatting: XX:XX:XX:XX:XX:XX. + The hex number in the string format takes twice as much space. 6 is added in place of ":" or spaces beetwen numbers and for the string terminator. */ +#define HEX_BYTE_STRING_LEN (3) /**< Determines string length for a 1-byte hex number. */ + +typedef struct +{ + bool is_not_empty; /**< Indicates that the structure is not empty. */ + uint8_t addr[BLE_GAP_ADDR_LEN]; /**< Device address. */ + char dev_name[DEVICE_NAME_MAX_SIZE]; /**< Device name. */ +} scanned_device_t; + +typedef struct +{ + uint8_t * p_data; /**< Pointer to data. */ + uint16_t data_len; /**< Length of data. */ +} data_t; + + +/**@brief Function for establishing a connection with a device that uses privacy. + * + * @param[in] p_peers_id Pointer to a handle to uniquely identify a peer for which data has been persistently stored. + */ +void private_connect(pm_peer_id_t const * p_peers_id); + + +/**@brief Function for setting the address for the connection. + * + * @param[in] address_str Device address in string format. + */ +void addr_store_value_set(char const * const p_address_str); + + +/**@brief Function for checking scan state. + * + * @retval true If scanning is in progress. + * @retval false Otherwise. + */ +bool is_scanning(void); + + +/**@brief Function for getting CCCD descriptors handle. + * + * @param[in] p_char_uuid_str Characterisctic UUID in string format. + * + * @retval If exist, CCCD descriptor handle, otherwise BLE_GATT_HANDLE_INVALID. + */ +uint16_t cccd_descriptors_handle_get(char const * const p_char_uuid_str); + + +/**@brief Function for getting a devices scan list. + * + * @return Pointer to an array containing information about nearby devices that are advertising. + Array size is defined as DEVICE_TO_FIND_MAX. + */ +scanned_device_t * scan_device_info_get(void); + + +/**@brief Function for clearing the array of nearby advertisers. + */ +void scan_device_info_clear(void); + + +/**@brief Function for checking if the user needs to confirm a numerical value. + * + * @retval true If the user needs to confirm a numerical value. + * @retval false Otherwise. + */ +bool is_numeric_match_requested(void); + +/** + * @brief Function for clearing the numeric match request flag. + */ +void numeric_match_request_clear(void); + + +/**@brief Function for getting the connection handle where the numeric match was requested. + * + * @return Connection handle. + */ +uint16_t numeric_match_request_conn_handle_get(void); + + +/**@brief Function for searching for the characteristic handle. + * + * @param[in] service_uuid_str Primary service UUID. + * + * @return Characteristic handle. + */ +uint16_t handle_value_search(char const * const p_service_uuid_str); + + +/**@brief Function for searching for a service handle range. + * + * @param[in] service_uuid_str Service UUID. + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * + * @return A pointer to the range of handles of the characteristic to perform this procedure on. + */ +ble_gattc_handle_range_t * handle_range_search(char const * const p_service_uuid_str, + uint16_t conn_handle); + + +/**@brief Function for setting the preferred PHY. + * + * @param[in] p_phy Pointer to the PHY structure. + * @param[in] conn_handle Connection handle identifying the connection to perform this procedure on. + */ +void preferred_phy_set(ble_gap_phys_t const * const p_phy, uint16_t conn_handle); + + +/**@brief Function for changing Link Layer data length for the connection. + * + * @param[in] data_length New data length value. + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + */ +void link_layer_data_length_set(char * p_data_length, uint16_t conn_handle); + + +/**@brief Function for setting MTU for central and peripheral connections. + * + * @param[in] mtu_value New MTU value. + */ +void gatt_mtu_set(char const * const p_mtu_value); + + +/**@brief Function for returning the current PHY mode in string format. + * + * @param[in] phys PHY structure. + * + * @return PHY mode in string format. + */ +char const * phy_str(ble_gap_phys_t const * const p_phys); + + +/**@brief Function for converting a 6-byte int address into a hex string. + * + * @param[in] addr Device address. + * @param[out] result Output buffer for the device address in string. + * @param[i] result_len Length of output buffer. Should be BLE_GAP_ADDR_LEN for BLE GAP address. + */ +void int_addr_to_hex_str(char * p_result, uint8_t result_len, uint8_t const * const p_addr); + + +/**@brief Function for finding a connection handle from a BLE address string. + * + * @param[in] addr BLE device address in string format. + * + * @return The connection handle identifying the connection to perform this procedure on. + */ +uint16_t addr_string_to_conn_handle(char const * const p_addr); + + +/**@brief Function for comparing an int address with a string address. + * + * @param[in] p_connected_adr Device address in hex format. + * @param[in] addr Device address in string format. + * + * @return True if addresses are the same or false if addresses are different. + */ +bool is_address_compare(ble_gap_addr_t const * const p_connected_addr, char const * const p_addr); + + +/**@brief Function for initiating advertising. + */ +void adv_start(void); + +/**@brief Function for disabling advertising. + */ +void adv_stop(void); + + +/**@brief Function for stopping scanning. + */ +void scan_stop(void); + + +/**@brief Function for initiating scanning. + */ +void scan_start(void); + + +/**@brief Function for initializing advertising. + */ +void advertising_init(void); + + +/**@brief Function for initializing the BLE module. + * + * @details Initializes buttons and LEDs, the block memory allocator module,the BLE stack, the GAP and GATT, + * the Connection Parameters module, the Heart Rate service, and the advertising functionality. + */ +void ble_m_init(void); + + +#endif // BLE_M_H_ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/cli_m.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/cli_m.c new file mode 100644 index 0000000..e551620 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/examples/ble_central_and_peripheral/experimental/ble_app_interactive/cli_m.c @@ -0,0 +1,2121 @@ +/** + * 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 +#include "cli_m.h" +#include "nrf_cli.h" +#include "nrf_ble_gatt.h" +#include "nrf_log.h" +#include "ble_m.h" +#include "ble_hci.h" +#include "ble_conn_params.h" +#include "peer_manager.h" +#include "nfc_m.h" +#include "nfc_central_m.h" +#include "adafruit_pn532.h" + +#define UNKNOWN_PARAMETER "unknown parameter: " +#define WRONG_PARAMETER_COUNT "wrong parameter count \r\n" +#define KEY_PASSKEY_LEN (6U) + +#define UNIT_TO_MSEC(uint, resolution) (uint16_t)(((uint) * (resolution)) / 1000) /**< Macro for converting ticks into milliseconds. */ + +#define SEC_PARAM_CENTRAL_DEFAULT \ + { \ + .bond = 1, \ + .mitm = 0, \ + .lesc = 0, \ + .keypress = 0, \ + .io_caps = BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY, \ + .oob = 0, \ + .min_key_size = BLE_SEC_PARAM_MIN_KEY_SIZE, \ + .max_key_size = BLE_SEC_PARAM_MAX_KEY_SIZE, \ + .kdist_own.enc = 1, \ + .kdist_own.id = 1, \ + .kdist_peer.enc = 1, \ + .kdist_peer.id = 1, \ + } + +typedef union +{ + char connect_addr_cmd_buffer[DEVICE_TO_FIND_MAX][CLI_MAX_CMD_LEN]; /**< Device address from scan buffer. */ + char connected_cmd_buffer[NRF_BLE_LINK_COUNT][CLI_MAX_CMD_LEN]; /**< Connected device address buffer. */ + char bond_cmd_buffer[BOND_DEVICE_MAX][CLI_MAX_CMD_LEN]; /**< Bonded device address buffer. */ +} cli_cmd_buffer_t; + +typedef struct +{ + cli_cmd_buffer_t buffer_type; /**< Dynamic command buffer type. */ + uint8_t cmd_counter; /**< Dynamic command counter. */ +} cli_cmd_connect_addr_t; + +typedef enum +{ + CLI_CMD_CONNECT_ADDR, /**< Device address from scan. */ + CLI_CMD_CONNECTED, /**< Connected device address. */ + CLI_CMD_BONDED, /**< Bonded device address. */ +} cli_cmd_buffer_type_t; + +bool m_key_request_event = false; /**< Flag informing about a key request event. */ +char m_device_name[DEVICE_NAME_MAX_SIZE]; /**< Device name. */ +uint16_t m_conn_handle; /**< Connection handle for pairing and key request. */ +cli_cmd_connect_addr_t m_cli_connect_addr; /**< List of BLE address strings for all devices found during scanning using as CLI commands. */ +cli_cmd_connect_addr_t m_cli_connected; /**< List of connected devices address string using as CLI commands. */ +cli_cmd_connect_addr_t m_cli_bonded; /**< List of bonded devices address string using as CLI commands. */ +ble_gap_sec_params_t m_sec_params_central = SEC_PARAM_CENTRAL_DEFAULT; +ble_gap_conn_params_t m_params_update = +{ + .min_conn_interval = MIN_CONNECTION_INTERVAL, + .max_conn_interval = MAX_CONNECTION_INTERVAL, + .slave_latency = SLAVE_LATENCY, + .conn_sup_timeout = SUPERVISION_TIMEOUT +}; + + +/**@Function for verification connection handle. + */ +static inline bool conn_handle_is_valid(uint16_t conn_handle, nrf_cli_t const * p_cli) +{ + if (conn_handle == BLE_CONN_HANDLE_INVALID) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "Invalid device address\r\n"); + return false; + } + + return true; +} + + +/**@Function for verification of the error code. + */ +static inline void ret_code_verify(ret_code_t err_code) +{ + if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) + { + APP_ERROR_CHECK(err_code); + } +} + + +/* Function required by qsort */ +static int string_cmp(void const * p_a, void const * p_b) +{ + ASSERT(p_a); + ASSERT(p_b); + return strcmp( (char const *)p_a, (char const *)p_b); +} + + +/**@brief Function for adding BLE address string as command to the dynamic command buffer. + * + * @param[in] p_data BLE address to remove. + * @param[in] p_cli_buffer Dynamic command buffer. + * @param[in] type Type of the dynamic command buffer. + */ +static void cli_addr_string_to_command_add(uint8_t const * p_data, + cli_cmd_connect_addr_t * p_cli_buffer, + cli_cmd_buffer_type_t type) +{ + uint8_t idx; + uint8_t size; + uint8_t * p_cmd_counter = &p_cli_buffer->cmd_counter; + char (*p_buffer)[CLI_MAX_CMD_LEN]; + + switch (type) + { + case CLI_CMD_CONNECT_ADDR: + size = DEVICE_TO_FIND_MAX; + p_buffer = p_cli_buffer->buffer_type.connect_addr_cmd_buffer; + break; + + case CLI_CMD_CONNECTED: + size = NRF_BLE_LINK_COUNT; + p_buffer = p_cli_buffer->buffer_type.connected_cmd_buffer; + break; + + case CLI_CMD_BONDED: + size = BOND_DEVICE_MAX; + p_buffer = p_cli_buffer->buffer_type.bond_cmd_buffer; + break; + + default: + return; + + } + + char string_buf[ADDR_STRING_LEN]; + + memset(string_buf, 0, ADDR_STRING_LEN); + + // Address conversion to string. + int_addr_to_hex_str(string_buf, BLE_GAP_ADDR_LEN, p_data); + + // If no place in buffer then return. + if (*p_cmd_counter >= size) + { + return; + } + + // Check if the address is repeated. + for (idx = 0; idx < size; idx++) + { + if (!strcmp(p_buffer[idx], string_buf)) + { + return; + } + } + + //Add address to buffer. + sprintf(p_buffer[(*p_cmd_counter)++], "%s", string_buf); + qsort(p_buffer, + *p_cmd_counter, + sizeof(p_buffer[0]), + string_cmp); +} + + +/**@brief Function for removing a BLE address string from the dynamic command buffer. + * + * @param[in] p_data BLE address to remove. + * @param[in] p_cli_buffer Dynamic command buffer. + * @param[in] type Type of the dynamic command buffer. + */ +static void cli_addr_from_command_remove(char * const p_data, + cli_cmd_connect_addr_t * p_cli_buffer, + cli_cmd_buffer_type_t type) +{ + uint8_t size; + uint8_t * p_cmd_counter = &p_cli_buffer->cmd_counter; + char (*p_buffer)[CLI_MAX_CMD_LEN]; + + switch (type) + { + case CLI_CMD_CONNECT_ADDR: + size = DEVICE_TO_FIND_MAX; + p_buffer = p_cli_buffer->buffer_type.connect_addr_cmd_buffer; + break; + + case CLI_CMD_CONNECTED: + size = NRF_BLE_LINK_COUNT; + p_buffer = p_cli_buffer->buffer_type.connected_cmd_buffer; + break; + + case CLI_CMD_BONDED: + size = BOND_DEVICE_MAX; + p_buffer = p_cli_buffer->buffer_type.bond_cmd_buffer; + break; + + default: + return; + + } + for (uint8_t idx = 0; idx < *p_cmd_counter; idx++) + { + if (!strcmp(p_buffer[idx], p_data)) + { + if (idx == size - 1) + { + p_buffer[idx][0] = '\0'; + } + else + { + memmove(p_buffer[idx], + p_buffer[idx + 1], + sizeof(p_buffer[idx]) * (*p_cmd_counter - idx)); + } + + --(*p_cmd_counter); + + return; + } + } +} + + +void connected_to_cmd_add(conn_peer_t * p_connected_peers, uint16_t conn_handle) +{ + ASSERT(p_connected_peers); + + cli_addr_string_to_command_add(p_connected_peers[conn_handle].address.addr, + &m_cli_connected, + CLI_CMD_CONNECTED); +} + + +void connected_to_cmd_remove(conn_peer_t * p_connected_peers, uint16_t conn_handle) +{ + ASSERT(p_connected_peers); + + char string_addr_buf[ADDR_STRING_LEN]; + + // Convert address to format XX:XX:XX:XX:XX:XX. + int_addr_to_hex_str(string_addr_buf, + BLE_GAP_ADDR_LEN, + p_connected_peers[conn_handle].address.addr); + + // Remove address from command buffer. + cli_addr_from_command_remove(string_addr_buf, + &m_cli_connected, + CLI_CMD_CONNECTED); +} + + +void address_to_cmd_add(ble_gap_addr_t const * p_connected_addr) +{ + ASSERT(p_connected_addr); + // Add address to command buffer. + cli_addr_string_to_command_add(p_connected_addr->addr, + &m_cli_connect_addr, + CLI_CMD_CONNECT_ADDR); +} + + +void connect_addr_clear(void) +{ + /* Erasing the dynamically created command (address, name) and commands counters */ + memset(&m_cli_connect_addr, 0, sizeof(m_cli_connect_addr)); +} + + +void bond_get(void) +{ + ret_code_t err_code; + pm_peer_id_t current_peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID); + + memset(&m_cli_bonded, 0, sizeof(m_cli_bonded)); + + // Reading all peer`s bonding data. + while (current_peer_id != PM_PEER_ID_INVALID) + { + pm_peer_data_bonding_t p_data; + + err_code = pm_peer_data_bonding_load(current_peer_id, &p_data); + + if (err_code == NRF_SUCCESS) + { + // Add bonded device address to CLI commands. + cli_addr_string_to_command_add(p_data.peer_ble_id.id_addr_info.addr, + &m_cli_bonded, + CLI_CMD_BONDED); + } + + current_peer_id = pm_next_peer_id_get(current_peer_id); + } +} + + +void bonds_delete(void) +{ + ret_code_t err_code; + + // Delete all data stored for all peers. + err_code = pm_peers_delete(); + APP_ERROR_CHECK(err_code); + memset(&m_cli_bonded, 0, sizeof(m_cli_bonded) ); +} + + +void key_request_set(void) +{ + m_key_request_event = true; +} + + +/**@brief Function for setting the PHY. + * + * @param[in] value New PHY value. + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + */ +static void phy_set(nrf_cli_t const * p_cli, uint8_t value, uint16_t conn_handle) +{ + ble_gap_phys_t phy = + { + .rx_phys = value, + .tx_phys = value, + }; + + // Set new PHY value. + preferred_phy_set(&phy, conn_handle); + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Preferred PHY set to %s.\r\n", phy_str(&phy)); +} + + +/**@brief Function for restoring the default connection parameters. + * + * @param[out] Pointer to conn_params. + */ +static void default_con_param(ble_gap_conn_params_t * p_params_update) +{ + p_params_update->min_conn_interval = MIN_CONNECTION_INTERVAL; + p_params_update->max_conn_interval = MAX_CONNECTION_INTERVAL; + p_params_update->slave_latency = SLAVE_LATENCY; + p_params_update->conn_sup_timeout = SUPERVISION_TIMEOUT; +} + + +/**@brief Function for printing the connectable devices. + * + *@details Function print list of available to connect device address and name (if exist). + * Display format: XX:XX:XX:XX:XX:XX device_name . + * + * @param[in] p_cli Pointer to the instance of the command line module. + * @param[in] device Pointer to the struct storing the scanned devices. + */ +static void device_list_print(nrf_cli_t const * p_cli, scanned_device_t * p_device) +{ + for (uint8_t i = 0; i < DEVICE_TO_FIND_MAX; i++) + { + if (p_device[i].is_not_empty) + { + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Device "); + + char buffer[ADDR_STRING_LEN]; + int_addr_to_hex_str(buffer, BLE_GAP_ADDR_LEN, p_device[i].addr); + + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%s %s\r\n", buffer, p_device[i].dev_name); + } + } +} + + +/**@brief Function for setting the CCCD Descriptor value. + * + * @param[in] p_cli Instance of the command line. + * @param[in] cccd New CCCD value. + * @param[in] addr Device address in string format. + * @param[in] uuid Characteristic UUID in string format. + */ +static void cccd_set(nrf_cli_t const * p_cli, uint16_t cccd, char * p_addr, char * p_uuid) +{ + uint16_t conn_handle; + uint16_t desc_handle; + ret_code_t err_code; + ble_gattc_write_params_t write_params; + + // Search for connection handle. + conn_handle = addr_string_to_conn_handle(p_addr); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + memset(&write_params, 0, sizeof(write_params)); + + desc_handle = cccd_descriptors_handle_get(p_uuid); + + if (desc_handle == BLE_GATT_HANDLE_INVALID) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "Wrong characteristic UUID or the CCCD descriptor has not been found yet\r\n"); + return; + } + + uint16_t cccd_val = cccd; + uint8_t data_buf[2] = {LSB_16(cccd_val), MSB_16(cccd_val)}; + uint8_t data_len = sizeof(data_buf); + + write_params.write_op = BLE_GATT_OP_WRITE_REQ; + write_params.handle = desc_handle; + write_params.len = data_len; + write_params.p_value = data_buf; + write_params.offset = 0; + write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE; + + // Set CCCD descriptor value. + err_code = sd_ble_gattc_write(conn_handle, &write_params); + + if (err_code != NRF_SUCCESS) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "wrong characteristic UUID or the CCCD descriptor has not been found yet\r\n"); + } +} + + +/**@brief Command handler for displaying the connected devices. + */ +static void cmd_connected_display(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; + } + + ret_code_t err_code; + uint16_t conn_handle; + ble_gap_conn_sec_t security_params; + memset(&security_params, 0, sizeof(security_params)); + + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Connected devices:\r\n"); + + for (uint8_t i = 0; i < m_cli_connected.cmd_counter; i++) + { + conn_handle = addr_string_to_conn_handle( + m_cli_connected.buffer_type.connected_cmd_buffer[i]); + + // Get connection security level. + err_code = sd_ble_gap_conn_sec_get(conn_handle, &security_params); + + if (err_code != NRF_SUCCESS) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "Security level reading has failed\r\n"); + + return; + } + nrf_cli_fprintf(p_cli, + NRF_CLI_NORMAL, + "%d. %s Security level: %d \r\n", + i, + m_cli_connected.buffer_type.connected_cmd_buffer[i], + security_params.sec_mode.lv); + } +} + + +static void cmd_privacy(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argv); + + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); + +} + +/** @brief Command handler for setting privacy. + */ +static void cmd_privacy_on(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(p_cli); + UNUSED_VARIABLE(argc); + UNUSED_VARIABLE(argv); + + ret_code_t err_code; + ble_gap_privacy_params_t privacy_params; + + // Privacy settings cannot be changed while advertising, scanning, or creating a connection. + (void)sd_ble_gap_scan_stop(); + adv_stop(); + err_code = sd_ble_gap_connect_cancel(); + ret_code_verify(err_code); + + memset(&privacy_params, 0, sizeof(privacy_params)); + + // Privacy setting. + privacy_params.privacy_mode = BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY; + privacy_params.private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE; + privacy_params.private_addr_cycle_s = PRIVATE_ADDRESS_INTERVAL; + privacy_params.p_device_irk = NULL; + + // Set privacy. + err_code = sd_ble_gap_privacy_set(&privacy_params); + APP_ERROR_CHECK(err_code); + + // Set device indentities list. + err_code = sd_ble_gap_device_identities_set(NULL, NULL, NRF_SDH_BLE_PERIPHERAL_LINK_COUNT); + APP_ERROR_CHECK(err_code); +} + +/**@brief Command handler for disabling privacy. + */ +static void cmd_privacy_off(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(p_cli); + UNUSED_VARIABLE(argc); + UNUSED_VARIABLE(argv); + + ret_code_t err_code; + ble_gap_privacy_params_t privacy_params; + + // Privacy settings cannot be changed while advertising, scanning, or creating a connection. + (void)sd_ble_gap_scan_stop(); + + adv_stop(); + + err_code = sd_ble_gap_connect_cancel(); + ret_code_verify(err_code); + + memset(&privacy_params, 0, sizeof(privacy_params)); + privacy_params.privacy_mode = BLE_GAP_PRIVACY_MODE_OFF; + privacy_params.private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC; + privacy_params.private_addr_cycle_s = BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S; + privacy_params.p_device_irk = NULL; + + // Set privacy. + err_code = sd_ble_gap_privacy_set(&privacy_params); + APP_ERROR_CHECK(err_code); +} + + +static void cmd_numeric(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s\r\n", UNKNOWN_PARAMETER, argv[1]); +} + + +/**@brief Command handler for accepting a numeric value. + */ +static void cmd_numeric_accept(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argc); + UNUSED_VARIABLE(argv); + + ret_code_t err_code; + + if (is_numeric_match_requested()) + { + // If numeric match request and keys on the both devices are the same then accept. + err_code = sd_ble_gap_auth_key_reply(numeric_match_request_conn_handle_get(), + BLE_GAP_AUTH_KEY_TYPE_PASSKEY, NULL); // Accept + APP_ERROR_CHECK(err_code); + + // Clear numeric match flag. + numeric_match_request_clear(); + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Numeric Match\r\n"); + } + else + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "This command can be used only with numeric comparison pairing\r\n"); + } +} + + +/**@brief Command handler for rejecting a numeric value. + */ +static void cmd_numeric_reject(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argc); + UNUSED_VARIABLE(argv); + + ret_code_t err_code; + + if (is_numeric_match_requested()) + { + // If numeric match request and keys on both devices are not the same, then reject. + err_code = sd_ble_gap_auth_key_reply(numeric_match_request_conn_handle_get(), + BLE_GAP_AUTH_KEY_TYPE_NONE, NULL); // Reject + APP_ERROR_CHECK(err_code); + + // Clear a numeric match flag. + numeric_match_request_clear(); + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Numeric Reject\r\n"); + } + else + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "This command can be used only with numeric comparison pairing\r\n"); + } +} + + +#if NRF_MODULE_ENABLED(ADAFRUIT_SHIELD) +static void cmd_nfc_reader(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); +} + + +/**@brief Command handler for pairing by NFC in central role. + */ +static void cmd_nfc_reader_on(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argv); + + if (argc != 1) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + ret_code_t err_code; + + // In order to avoid a mistake when reusing the command. + nfc_pair_stop(); + err_code = adafruit_pn532_field_off(); + ret_code_verify(err_code); + + // Turn on the Adafruit tag reader. + err_code = adafruit_pn532_field_on(); + APP_ERROR_CHECK(err_code); + + nfc_pair_start(); + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "NFC reader ON\r\n"); +} + + +/**@brief Command handler for disabling pairing by NFC in central role. + */ +static void cmd_nfc_reader_off(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argv); + + ret_code_t err_code; + + if (argc != 1) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + nfc_pair_stop(); + err_code = adafruit_pn532_field_off(); + ret_code_verify(err_code); + + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "NFC reader OFF\r\n"); +} + + +#endif // ADAFRUIT_SHIELD + +static void cmd_gatt(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); +} + + + +/**@brief Command handler for services discovery. + */ +static void cmd_services_discovery(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + ret_code_t err_code; + uint16_t conn_handle; + + // Start handle to look for services. + uint16_t handle = 0x0001; + conn_handle = addr_string_to_conn_handle(argv[1]); + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // Discovery primary services. + err_code = sd_ble_gattc_primary_services_discover(conn_handle, handle, NULL); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Command handler for characteristics discovery. + */ +static void cmd_char_get(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + uint16_t conn_handle; + ret_code_t err_code; + + // Search for a connection handle. + conn_handle = addr_string_to_conn_handle(argv[1]); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // Look for start handle range. + ble_gattc_handle_range_t * p_handle_range = handle_range_search(argv[2], conn_handle); + + // Characteristic discovery. + err_code = sd_ble_gattc_characteristics_discover(conn_handle, p_handle_range); + + if (err_code != NRF_SUCCESS) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "incorrect service UUID or service does not exist\r\n"); + } +} + + + +/**@brief Command handler for reading a characteristic value. + */ +static void cmd_char_read(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + uint16_t conn_handle; + uint16_t val_handle; + ret_code_t err_code; + + // Search for a connection handle. + conn_handle = addr_string_to_conn_handle(argv[1]); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // Search for a Characterisctic Value Handle. + val_handle = handle_value_search(argv[2]); + if (val_handle == BLE_GATT_HANDLE_INVALID) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "%s%s\r\n", + "The selected service does not contain the characteristic - ", + argv[2]); + return; + } + + // Read characteristic data. + err_code = sd_ble_gattc_read(conn_handle, val_handle, 0); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Command handler for writing a value to the characteristic. + */ +static void cmd_char_write(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + uint16_t conn_handle; + ret_code_t err_code; + ble_gattc_write_params_t write_params; + uint8_t data_buf[GATT_DATA_WRITE_SIZE]; + uint16_t val_handle; + + // Calculate data length, first 4 argv are commands, the rest of argv are data. + uint16_t data_len = argc - 4; + + memset(&write_params, 0, sizeof(write_params)); + + if (!strcmp(argv[1], "command")) + { + write_params.write_op = BLE_GATT_OP_WRITE_CMD; + } + else if (!strcmp(argv[1], "request")) + { + write_params.write_op = BLE_GATT_OP_WRITE_REQ; + } + else + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); + return; + } + + // Search for a connection handle. + conn_handle = addr_string_to_conn_handle(argv[2]); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // Search for a Characteristic Value Handle. + val_handle = handle_value_search(argv[3]); + + if (val_handle == BLE_GATT_HANDLE_INVALID) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "%s%s\r\n", + "The selected service does not contain the characteristic - ", + argv[3]); + return; + } + + write_params.handle = val_handle; + write_params.len = data_len; + write_params.p_value = data_buf; + write_params.offset = 0; + write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE; + + for (uint8_t i = 0; i < data_len; i++) + { + data_buf[i] = atoi(argv[i + 4]); + } + + // Write data to characteristic. + err_code = sd_ble_gattc_write(conn_handle, &write_params); + APP_ERROR_CHECK(err_code); +} + + +static void cmd_notify(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); +} + +/**@brief Command handler for enabling a notification. + */ +static void cmd_notify_on(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argc); + + // In order to enable the notification, the CCCD descriptor should take the value 1. + cccd_set(p_cli, 0x01, argv[1], argv[2]); +} + + +/**@brief Command handler for disabling a notification. + */ +static void cmd_notify_off(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argc); + // In order to disable the notification, the CCCD descriptor should take the value 0. + cccd_set(p_cli, 0x00, argv[1], argv[2]); +} + + +static void cmd_ind(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); + +} + + +/**@brief Command handler for enabling an indication. + */ +static void cmd_ind_on(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argc); + + // In order to enable the indication, the CCCD descriptor should take the value 2. + cccd_set(p_cli, 0x02, argv[1], argv[2]); +} + + +/**@brief Command handler for disabling an indication. + */ +static void cmd_ind_off(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argc); + + // In order to disable the indication, the CCCD descriptor should take the value 0. + cccd_set(p_cli, 0x00, argv[1], argv[2]); +} + + +/**@brief Command handler for setting link layer data length. + */ +static void cmd_data_length_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if (argc != 3) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + uint16_t conn_handle; + + for (uint8_t i = 0; i < strlen(argv[2]); i++) + { + if (!isdigit((int) argv[2][i])) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "data length must be a number\r\n"); + return; + } + } + + // Search for connection handle. + conn_handle = addr_string_to_conn_handle(argv[1]); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // Set new link layer data length. + link_layer_data_length_set(argv[2], conn_handle); +} + + +/**@brief Command handler for setting the PHY to 1 MBPS. + */ +static void cmd_phy_1m_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argc); + + uint16_t conn_handle; + + // Search for a connection handle. + conn_handle = addr_string_to_conn_handle(argv[1]); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // PHY value set. + phy_set(p_cli, BLE_GAP_PHY_1MBPS, conn_handle); +} + + + +/**@brief Command handler for setting the PHY to 2 MBPS. + */ +static void cmd_phy_2m_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argc); + + uint16_t conn_handle; + + // Search for a connection handle. + conn_handle = addr_string_to_conn_handle(argv[1]); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // PHY value set. + phy_set(p_cli, BLE_GAP_PHY_2MBPS, conn_handle); +} + + +#ifdef NRF52840_XXAA +/**@brief Command handler for setting the PHY to coded. + */ +static void cmd_phy_coded_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + UNUSED_VARIABLE(argc); + + uint16_t conn_handle; + + // Search for a connection handle. + conn_handle = addr_string_to_conn_handle(argv[1]); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // PHY value set. + phy_set(p_cli, BLE_GAP_PHY_CODED, conn_handle); +} + + +#endif + +static void cmd_phy(nrf_cli_t const * p_cli, size_t argc, char * * argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); + +} + + +static void cmd_parameters(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); +} + + +/**@brief Command handler for setting the MTU. + */ +static void cmd_mtu_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if (argc != 2) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + if (nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + for (uint8_t i = 0; i < strlen(argv[1]); i++) + { + if (!isdigit((int) argv[1][i])) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "MTU must be a number\r\n"); + return; + } + } + + // Set a new MTU value. + gatt_mtu_set(argv[1]); +} + + +/**@brief Command handler for setting the Minimum Connection Interval. + */ +static void cmd_min_conn_interval_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + uint16_t value; + + if (argc != 2) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + for (uint8_t i = 0; i < strlen(argv[1]); i++) + { + if (!isdigit((int) argv[1][i])) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "min_conn_interval must be a number\r\n"); + return; + } + } + + value = (uint16_t)MSEC_TO_UNITS(atoi(argv[1]), UNIT_1_25_MS); + + // Checking the value is within the required range. + if ((value < MSEC_TO_UNITS(BLE_GAP_CP_MIN_CONN_INTVL_MIN, UNIT_1_25_MS)) || + (value > MSEC_TO_UNITS(BLE_GAP_CP_MIN_CONN_INTVL_MAX, UNIT_1_25_MS))) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s %d and %d.\r\n", + "Minimum connection interval must be between", + BLE_GAP_CP_MIN_CONN_INTVL_MIN, + BLE_GAP_CP_MIN_CONN_INTVL_MAX); + return; + } + + m_params_update.min_conn_interval = value; +} + + +/**@brief Command handler for setting Maximum Connection Interval. + */ +static void cmd_max_conn_interval_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + uint16_t value; + + if (argc != 2) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + for (uint8_t i = 0; i < strlen(argv[1]); i++) + { + if (!isdigit((int) argv[1][i])) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "max_conn_interval must be a number.\r\n"); + return; + } + } + + value = (uint16_t)MSEC_TO_UNITS(atoi(argv[1]), UNIT_1_25_MS); + + // Checking whether the value is within the required range. + if ((value < MSEC_TO_UNITS(BLE_GAP_CP_MAX_CONN_INTVL_MIN, UNIT_1_25_MS)) || + (value > MSEC_TO_UNITS(BLE_GAP_CP_MAX_CONN_INTVL_MAX, UNIT_1_25_MS))) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s %d and %d.\r\n", + "Maximum connection interval must be between", + BLE_GAP_CP_MAX_CONN_INTVL_MIN, + BLE_GAP_CP_MAX_CONN_INTVL_MAX); + return; + } + + m_params_update.max_conn_interval = value; +} + + +/**@brief Command handler for setting Slave Latency. + */ +static void cmd_slave_latency_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + uint16_t value; + + if (argc != 2) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + for (uint8_t i = 0; i < strlen(argv[1]); i++) + { + if (!isdigit((int) argv[1][i])) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "Slave latency must be a number\r\n"); + return; + } + } + + value = atoi(argv[1]); + + if (value > BLE_GAP_CP_SLAVE_LATENCY_MAX) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "%s%d.\r\n", + "Slave latency should be less than: ", + BLE_GAP_CP_SLAVE_LATENCY_MAX); + return; + } + + m_params_update.slave_latency = value; +} + + +/**@brief Command handler for setting Supervisory time-out. + */ +static void cmd_sup_timeout_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + uint16_t value; + uint16_t check; + uint16_t valid; + + if (argc != 2) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + for (uint8_t i = 0; i < strlen(argv[1]); i++) + { + if (!isdigit((int) argv[1][i])) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "Supervision time-out must be a number.\r\n"); + return; + } + } + + check = atoi(argv[1]); + value = (uint16_t)MSEC_TO_UNITS(check, UNIT_10_MS); + valid = (1 + m_params_update.slave_latency) * UNIT_TO_MSEC(m_params_update.max_conn_interval, + UNIT_1_25_MS) * 2; + // Checking whether the value is within the required range. + if ((value < MSEC_TO_UNITS(BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN, UNIT_10_MS)) || + (value > MSEC_TO_UNITS(BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX, UNIT_10_MS))) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "%s %d and %d.\r\n", + "Supervision time-out must be between", + BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN, + BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX); + return; + } + + if (check <= valid) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "%s \r\n%s%d\r\n", + "Supervision_Timeout in milliseconds shall be larger than:", + "(1 + Slave_Latency) * Conn_Interval_Max * 2 - ", + valid); + return; + } + + m_params_update.conn_sup_timeout = value; +} + + +/**@brief Command handler for setting connection parameters. + */ +static void cmd_connection_params_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if (argc != 2) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + ret_code_t err_code; + uint16_t conn_handle; + + // Search for a connection handle. + conn_handle = addr_string_to_conn_handle(argv[1]); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // Set connection parameters for the connection. + err_code = sd_ble_gap_conn_param_update(conn_handle, &m_params_update); + + if (err_code == NRF_SUCCESS) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_NORMAL, + "Preferred connection parameters changed successfully\r\n"); + + default_con_param(&m_params_update); + } + else + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "Connection parameters could not be changed\r\n"); + } +} + + +/**@brief Command handler for displaying connectable devices. + */ +static void cmd_devices_display(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if (argc >= 2) + { + if (nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + else + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "%s:%s%s\r\n", + argv[0], + " bad parameter ", + argv[1]); + return; + } + } + + // Print connectable devices from scan data. + scanned_device_t * p_device_list = scan_device_info_get(); + device_list_print(p_cli, p_device_list); +} + + +static void cmd_remove(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); +} + + +/**@brief Command handler for displaying bonded devices. + */ +static void cmd_bonded_devices_display(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if (argc > 1) + { + if (nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Peers count: %d \r\n", pm_peer_count()); + + pm_peer_id_t current_peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID); + + // Display all bonded devices. + while (current_peer_id != PM_PEER_ID_INVALID) + { + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "ID: %d address: ", current_peer_id); + + ret_code_t err_code; + pm_peer_data_bonding_t data; + char string_addr_buf[ADDR_STRING_LEN]; + + // Get bonding data. + err_code = pm_peer_data_bonding_load(current_peer_id, &data); + APP_ERROR_CHECK(err_code); + current_peer_id = pm_next_peer_id_get(current_peer_id); + + // Convert device address to string. + int_addr_to_hex_str(string_addr_buf, + BLE_GAP_ADDR_LEN, + data.peer_ble_id.id_addr_info.addr); + + // Display bonded device. + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%s\r\n", string_addr_buf); + } +} + + +/**@brief Command handler for pairing with a device. + */ +static void cmd_device_pair(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + if (!strcmp(argv[1], "LESC")) + { + m_sec_params_central.lesc = 1; + } + else if (!strcmp(argv[1], "LEGACY")) + { + m_sec_params_central.lesc = 0; + } + else + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s:%s%s\r\n", argv[0], " wrong command ", argv[1]); + return; + } + + ret_code_t err_code; + + // Search for connection handle. + m_conn_handle = addr_string_to_conn_handle(argv[2]); + + if(!conn_handle_is_valid(m_conn_handle, p_cli)) + { + return; + } + + if (!strcmp(argv[3], "mitm")) + { + m_sec_params_central.mitm = 1; + m_sec_params_central.io_caps = BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY; + } + else + { + m_sec_params_central.mitm = 0; + m_sec_params_central.io_caps = BLE_GAP_IO_CAPS_NONE; + } + + if (!strcmp(argv[3], "oob")) + { + m_sec_params_central.mitm = 1; + m_sec_params_central.oob = 1; + m_sec_params_central.io_caps = BLE_GAP_IO_CAPS_NONE; + } + + // Based on command parameters, set security parameters. + err_code = pm_sec_params_set(&m_sec_params_central); + APP_ERROR_CHECK(err_code); + + // Establishing encryption on a connection, and optionally establishing a bond. + err_code = pm_conn_secure(m_conn_handle, false); + + if (err_code != NRF_SUCCESS) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "Device is not connected or is already paired\r\n"); + } + else + { + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Start pairing\r\n"); + } +} + + +/**@brief Command handler for reply to BLE_GAP_EVT_AUTH_KEY_REQUEST. + */ +static void cmd_key_reply(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if (argc > 2) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + if (!m_key_request_event) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "No key request\r\n"); + return; + } + + if (strlen(argv[1]) != KEY_PASSKEY_LEN) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s", "invalid key length!\r\n"); + return; + } + + ret_code_t err_code; + uint8_t key[KEY_PASSKEY_LEN]; + + for (uint8_t i = 0; i < KEY_PASSKEY_LEN; i++) + { + if (!isdigit((int) argv[1][i])) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "the key must consist of digits\r\n"); + return; + } + + key[i] = argv[1][i]; + } + + // Reply with an authentication key. + err_code = sd_ble_gap_auth_key_reply(m_conn_handle, + BLE_GAP_AUTH_KEY_TYPE_PASSKEY, + key); + m_key_request_event = false; + + if (err_code != NRF_SUCCESS) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "Error sending key\r\n"); + } + else + { + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Key sending success\r\n"); + } +} + + +/**@brief Command handler for setting a device name. + */ +static void cmd_device_name_set(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + ret_code_t err_code; + ble_gap_conn_sec_mode_t sec_mode; + char buf[DEVICE_NAME_MAX_SIZE]; + + memset(buf, 0, DEVICE_NAME_MAX_SIZE); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + + for (uint8_t i = 1; i < argc; i++) + { + strcat(buf, argv[i]); + + if (i == (argc - 1)) + { + break; + } + + strcat(buf, " "); + } + + // Set new device name. + err_code = sd_ble_gap_device_name_set(&sec_mode, + (const uint8_t *)buf, + strlen(buf)); + + //Re-initialization of advertising with new device name. + advertising_init(); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Command handler for enabling advertising. + */ +static void cmd_advertise_on(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + ret_code_t err_code; + + if (argc > 1) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + adv_stop(); + err_code = nfc_ble_pair_stop(); + ret_code_verify(err_code); + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Advertising enabled\r\n"); + adv_start(); + err_code = nfc_ble_pair_start(); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Command handler for disabling advertising. + */ +static void cmd_advertise_off(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + ret_code_t err_code; + + if (argc > 1) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + return; + } + + adv_stop(); + err_code = nfc_ble_pair_stop(); + ret_code_verify(err_code); + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Advertising disabled\r\n"); +} + + +static void cmd_advertise(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); +} + + +/**@brief Command handler for disabling scanning. + */ +static void cmd_scan_off(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if (argc != 1) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "%s %s: %s", + argv[-1], + argv[0], + WRONG_PARAMETER_COUNT); + return; + } + + scan_stop(); + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Scan stopped\r\n"); +} + + +/**@brief Command handler for enabling scanning. + */ +static void cmd_scan_on(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if (argc != 1) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "%s %s: %s", + argv[-1], + argv[0], + WRONG_PARAMETER_COUNT); + return; + } + + scan_start(); + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Scan started\r\n"); +} + + +static void cmd_scan(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "%s%s\r\n", + UNKNOWN_PARAMETER, + argv[1]); +} + + +/**@brief Command handler for establishing a connection. + */ +static void cmd_device_connect(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + if (argc == 2) + { + //Connect by peer ID if davice was bonded and using privacy. + if (strlen(argv[1]) < (ADDR_STRING_LEN - 1)) + { + uint16_t pm_id; + pm_id = atoi(argv[1]); + private_connect(&pm_id); + return; + } + + // If address or peer ID have incorrect format, then return. + if (strlen(argv[1]) != (ADDR_STRING_LEN - 1)) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "wrong address length - Correct format: XX:XX:XX:XX:XX:XX\r\n"); + return; + } + + //Connect by device address. + addr_store_value_set(argv[1]); + } + else + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, WRONG_PARAMETER_COUNT); + } +} + + +/**@brief Command handler for disconnecting from a device. + */ +static void cmd_device_disconnect(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + if (argc > 2) + { + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s: %s", argv[0], WRONG_PARAMETER_COUNT); + return; + } + + if (strlen(argv[1]) != (ADDR_STRING_LEN - 1)) + { + nrf_cli_fprintf(p_cli, + NRF_CLI_ERROR, + "wrong address length - Correct format: XX:XX:XX:XX:XX:XX\r\n"); + return; + } + + uint16_t conn_handle; + ret_code_t err_code; + + // Search for a connection handle. + conn_handle = addr_string_to_conn_handle(argv[1]); + + if(!conn_handle_is_valid(conn_handle, p_cli)) + { + return; + } + + // Disconnect from a device. + err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + ret_code_verify(err_code); +} + + +static void cmd_all_bonds_delete(nrf_cli_t const * p_cli, size_t argc, char * * argv) +{ + if (argc == 1) + { + nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Bonding data deleted\r\n"); + bonds_delete(); + return; + } + + if (nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s%s\r\n", UNKNOWN_PARAMETER, argv[1]); +} + + +/**@brief Command handler for removing device bonding data. + */ +static void cmd_device_remove(nrf_cli_t const * p_cli, size_t argc, char ** argv) +{ + if ((argc == 1) || nrf_cli_help_requested(p_cli)) + { + nrf_cli_help_print(p_cli, NULL, 0); + return; + } + + ret_code_t err_code; + pm_peer_id_t current_peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID); + + // Search for device bondind data. + while (current_peer_id != PM_PEER_ID_INVALID) + { + pm_peer_data_bonding_t p_data; + + err_code = pm_peer_data_bonding_load(current_peer_id, &p_data); + APP_ERROR_CHECK(err_code); + + if (is_address_compare(&p_data.peer_ble_id.id_addr_info, argv[1])) + { + // If bonding data was found, then remove. + err_code = pm_peer_delete(current_peer_id); + APP_ERROR_CHECK(err_code); + + // Remove device from bonded device command buffer. + cli_addr_from_command_remove(argv[1], + &m_cli_bonded, + CLI_CMD_BONDED); + } + + current_peer_id = pm_next_peer_id_get(current_peer_id); + } +} + + +/* Dynamic command creation */ +static void connected_get(size_t idx, nrf_cli_static_entry_t * p_static) +{ + // Must be sorted alphabetically to ensure correct CLI completion. + p_static->p_syntax = (idx < m_cli_connected.cmd_counter) ? + m_cli_connected.buffer_type.connected_cmd_buffer[idx] : NULL; + p_static->handler = NULL; + p_static->p_subcmd = NULL; + p_static->p_help = 0; +} + + +/* Dynamic command creation */ +static void connect_addr_get(size_t idx, nrf_cli_static_entry_t * p_static) +{ + // Must be sorted alphabetically to ensure correct CLI completion. + p_static->p_syntax = (idx < m_cli_connect_addr.cmd_counter) ? + m_cli_connect_addr.buffer_type.connect_addr_cmd_buffer[idx] : NULL; + p_static->handler = NULL; + p_static->p_subcmd = NULL; + p_static->p_help = "Connect with address."; +} + + +/* Dynamic command creation */ +static void delete_bond_get(size_t idx, nrf_cli_static_entry_t * p_static) +{ + // Must be sorted alphabetically to ensure correct CLI completion. + p_static->p_syntax = (idx < m_cli_bonded.cmd_counter) ? + m_cli_bonded.buffer_type.bond_cmd_buffer[idx] : NULL; + p_static->handler = NULL; + p_static->p_subcmd = NULL; + p_static->p_help = "Delete device bond by address."; +} + + + + + +/* Creating subcommands (level 1) for command "LESC and Legacy */ +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_pairing_opt) +{ + NRF_CLI_CMD(mitm, NULL, "MITM protection", NULL), + NRF_CLI_CMD(oob, NULL, "OOB pair mode", NULL), + NRF_CLI_SUBCMD_SET_END +}; + + +/* Dynamic command creation */ +static void pairing_get(size_t idx, nrf_cli_static_entry_t * p_static) +{ + // Must be sorted alphabetically to ensure correct CLI completion. + p_static->p_syntax = (idx < m_cli_connected.cmd_counter) ? + m_cli_connected.buffer_type.connected_cmd_buffer[idx] : NULL; + p_static->handler = NULL; + p_static->p_subcmd = &m_sub_pairing_opt; + p_static->p_help = NULL; +} + + +/* Creating dynamic subcommands (level 2) */ +NRF_CLI_CREATE_DYNAMIC_CMD(m_sub_connect_addr_collection, connect_addr_get); +NRF_CLI_CREATE_DYNAMIC_CMD(m_sub_pairing_set, pairing_get); + +/* Creating dynamic subcommands (level 1) */ +NRF_CLI_CREATE_DYNAMIC_CMD(m_sub_connected_collection, connected_get); +NRF_CLI_CREATE_DYNAMIC_CMD(m_sub_delete_bond_collection, delete_bond_get); + +/* Creating subcommands (level 2) for command "phy" */ +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_phy) +{ + NRF_CLI_CMD(1M, + &m_sub_connected_collection, + "Set preferred PHY to 1 Mbps.", + cmd_phy_1m_set), + NRF_CLI_CMD(2M, + &m_sub_connected_collection, + "Set preferred PHY to 2 Mbps.", + cmd_phy_2m_set), +#ifdef NRF52840_XXAA + NRF_CLI_CMD(coded, + &m_sub_connected_collection, + "Set preferred PHY to Coded.", + cmd_phy_coded_set), +#endif + NRF_CLI_SUBCMD_SET_END +}; + +/* Creating subcommands (level 2)*/ +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_write) +{ + NRF_CLI_CMD(command, + &m_sub_connected_collection, + " Write characteristic value(request).", + NULL), + NRF_CLI_CMD(request, + &m_sub_connected_collection, + " Write characteristic value(command).", + NULL), + NRF_CLI_SUBCMD_SET_END +}; + +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_notify) +{ + NRF_CLI_CMD(off, &m_sub_connected_collection, "Notifications off.", cmd_notify_off), + NRF_CLI_CMD(on, &m_sub_connected_collection, "Notifications on.", cmd_notify_on), + NRF_CLI_SUBCMD_SET_END +}; + +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_ind) +{ + NRF_CLI_CMD(off, &m_sub_connected_collection, "Indications off.", cmd_ind_off), + NRF_CLI_CMD(on, &m_sub_connected_collection, "Indications on.", cmd_ind_on), + NRF_CLI_SUBCMD_SET_END +}; + +/* Creating subcommands (level 1)*/ +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_privacy) +{ + NRF_CLI_CMD(off, NULL, "Privacy advertising mode off.", cmd_privacy_off), + NRF_CLI_CMD(on, NULL, "Privacy advertising mode on.", cmd_privacy_on), + NRF_CLI_SUBCMD_SET_END +}; +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_numeric) +{ + NRF_CLI_CMD(accept, NULL, "Accepts pin value.", cmd_numeric_accept), + NRF_CLI_CMD(reject, NULL, "Reject pin value.", cmd_numeric_reject), + NRF_CLI_SUBCMD_SET_END +}; + +#if NRF_MODULE_ENABLED(ADAFRUIT_SHIELD) +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_nfc_reader) +{ + NRF_CLI_CMD(off, NULL, "NFC reader off.", cmd_nfc_reader_off), + NRF_CLI_CMD(on, NULL, "NFC reader on.", cmd_nfc_reader_on), + NRF_CLI_SUBCMD_SET_END +}; +#endif // ADAFRUIT_SHIELD +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_gatt) +{ + NRF_CLI_CMD(characteristics, + &m_sub_connected_collection, + "
Get information about the contents of a service.", + cmd_char_get), + NRF_CLI_CMD(indication, + &m_sub_ind, + "
Change indication state.", + cmd_ind), + NRF_CLI_CMD(notification, + &m_sub_notify, + "
Change notification state.", + cmd_notify), + NRF_CLI_CMD(read, + &m_sub_connected_collection, + "
Read characteristic value.", + cmd_char_read), + NRF_CLI_CMD(services, + &m_sub_connected_collection, + "
Download list of services.", + cmd_services_discovery), + NRF_CLI_CMD(write, + &m_sub_write, + "
Write characteristic value.", + cmd_char_write), + NRF_CLI_SUBCMD_SET_END +}; + +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_parameters) +{ + NRF_CLI_CMD(apply, + &m_sub_connected_collection, + "
Change connection parameters for the device.", + cmd_connection_params_set), + NRF_CLI_CMD(data_length, + &m_sub_connected_collection, + "
Data length change.", + cmd_data_length_set), + NRF_CLI_CMD(max_conn_interval, + NULL, + " Set maximum connection interval.", + cmd_max_conn_interval_set), + NRF_CLI_CMD(min_conn_interval, + NULL, + " Set minimum connection interval.", + cmd_min_conn_interval_set), + NRF_CLI_CMD(mtu, NULL, " Change MTU value.", cmd_mtu_set), + NRF_CLI_CMD(phy, &m_sub_phy, "
PHY change. ", cmd_phy), + NRF_CLI_CMD(slave_latency, NULL, " Set slave latency.", cmd_slave_latency_set), + NRF_CLI_CMD(sup_timeout, NULL, " Set connection supervision time-out.", cmd_sup_timeout_set), + NRF_CLI_SUBCMD_SET_END +}; +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_remove) +{ + NRF_CLI_CMD(all, NULL, "Remove all bonded devices.", cmd_all_bonds_delete), + NRF_CLI_CMD(device, + &m_sub_delete_bond_collection, + "
Remove one bonded device.", + cmd_device_remove), + NRF_CLI_SUBCMD_SET_END +}; +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_pairing) +{ + NRF_CLI_CMD(LEGACY, &m_sub_pairing_set, "Legacy pairing mode.", NULL), + NRF_CLI_CMD(LESC, &m_sub_pairing_set, "LESC pairing mode.", NULL), + NRF_CLI_SUBCMD_SET_END +}; + +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_advertise) +{ + NRF_CLI_CMD(off, NULL, "Advertising off.", cmd_advertise_off), + NRF_CLI_CMD(on, NULL, "Advertising on.", cmd_advertise_on), + NRF_CLI_SUBCMD_SET_END +}; + +NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_scan) +{ + NRF_CLI_CMD(off, NULL, "Stop scanning.", cmd_scan_off), + NRF_CLI_CMD(on, NULL, "Start scanning.", cmd_scan_on), + NRF_CLI_SUBCMD_SET_END +}; + +/* Creating root (level 0) command */ +NRF_CLI_CMD_REGISTER(connected_devices, + NULL, + "Display connected devices and information about security level.", + cmd_connected_display); +NRF_CLI_CMD_REGISTER(privacy, &m_sub_privacy, "Set privacy settings.", cmd_privacy); +NRF_CLI_CMD_REGISTER(numeric, + &m_sub_numeric, + "Confirm or reject the value of the pin code.", + cmd_numeric); +#if NRF_MODULE_ENABLED(ADAFRUIT_SHIELD) +NRF_CLI_CMD_REGISTER(nfc_read, + &m_sub_nfc_reader, + "Turn on NFC for reading .", + cmd_nfc_reader); +#endif // ADAFRUIT_SHIELD +NRF_CLI_CMD_REGISTER(gatt, &m_sub_gatt, "Gatt options.", cmd_gatt); +NRF_CLI_CMD_REGISTER(parameters, + &m_sub_parameters, + " Change connection and link layer parameters.", + cmd_parameters); +NRF_CLI_CMD_REGISTER(bonded_devices, + NULL, + "List bonded devices (The devices are identified by public address).", + cmd_bonded_devices_display); +NRF_CLI_CMD_REGISTER(devices, NULL, "List available devices.", cmd_devices_display); +NRF_CLI_CMD_REGISTER(remove_bond, &m_sub_remove, " Remove bonded device.", cmd_remove); +NRF_CLI_CMD_REGISTER(key_reply, NULL, " Enter key from another device.", cmd_key_reply); +NRF_CLI_CMD_REGISTER(pair, + &m_sub_pairing, + "