Hello, everyone
I used NRF52832 as the center and tried to connect to a peripheral, but after connecting for a fixed period of time, the center would actively disconnect from the peripheral. This problem is inevitable. This seems to be the result of an abnormal connector? And unfortunately, I couldn't fix the problem by modifying the peripheral configuration, only by modifying the center code.
The central application code is very simple, just a serial port passthrough service, and handles AT instructions from the serial port.
I provided the sniffer's log file, the center's main code file, and the Soc's log file.
Thank you
Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<info> app: result=AT+CONN, cmp_len=7, ok_count=7, leng=21, at_code=7
<debug> ble_scan: Filter set on address 0x
<debug> ble_scan: B6 FF 93 37 1D CA |...7..
<debug> ble_scan: Scanning
<debug> ble_scan: Connecting
<debug> ble_scan: Connection status: 0
<debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0.
<debug> nrf_ble_gatt: Updating data length to 251 on connection 0x0.
<info> app: Connecting to target B6FF93371DCA
<debug> nrf_ble_gq: Purging request queue with id: 0
<debug> nrf_ble_gq: Registering connection handle: 0x0000
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
<info> app: result=AT+CONN, cmp_len=7, ok_count=7, leng=21, at_code=7 <debug> ble_scan: Filter set on address 0x <debug> ble_scan: B6 FF 93 37 1D CA |...7.. <debug> ble_scan: Scanning <debug> ble_scan: Connecting <debug> ble_scan: Connection status: 0 <debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0. <debug> nrf_ble_gatt: Updating data length to 251 on connection 0x0. <info> app: Connecting to target B6FF93371DCA <debug> nrf_ble_gq: Purging request queue with id: 0 <debug> nrf_ble_gq: Registering connection handle: 0x0000 <debug> ble_db_disc: Starting discovery of service with UUID 0xAE30 on connection handle 0x0. <debug> nrf_ble_gq: Adding item to the request queue <debug> nrf_ble_gq: GATTC Primary Services Discovery Request <debug> nrf_ble_gq: SD is currently busy. The GATT request procedure will be attempted again later. <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: GATTC Primary Service Discovery Request <debug> nrf_ble_gq: SD is currently busy. The GATT request procedure will be attempted again later. <debug> nrf_ble_gatt: Data length updated to 27 on connection 0x0. <debug> nrf_ble_gatt: max_rx_octets: 27 <debug> nrf_ble_gatt: max_tx_octets: 27 <debug> nrf_ble_gatt: max_rx_time: 328 <debug> nrf_ble_gatt: max_tx_time: 328 <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: GATTC Primary Service Discovery Request <error> nrf_ble_gq: SD GATT procedure (2) failed on connection handle 0 with error: 0x0000000D. <debug> app: GATT Client Timeout. <info> app: Disconnected. <info> app: Disconnected. conn_handle: 0x0, reason: 0x16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<info> app: result=AT+CONN, cmp_len=7, ok_count=7, leng=21, at_code=7
<debug> ble_scan: Filter set on address 0x
<debug> ble_scan: B6 FF 93 37 1D CA |...7..
<debug> ble_scan: Scanning
<debug> ble_scan: Connecting
<debug> ble_scan: Connection status: 0
<debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0.
<debug> nrf_ble_gatt: Updating data length to 251 on connection 0x0.
<info> app: Connecting to target B6FF93371DCA
<debug> nrf_ble_gq: Purging request queue with id: 0
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
<info> app: result=AT+CONN, cmp_len=7, ok_count=7, leng=21, at_code=7 <debug> ble_scan: Filter set on address 0x <debug> ble_scan: B6 FF 93 37 1D CA |...7.. <debug> ble_scan: Scanning <debug> ble_scan: Connecting <debug> ble_scan: Connection status: 0 <debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0. <debug> nrf_ble_gatt: Updating data length to 251 on connection 0x0. <info> app: Connecting to target B6FF93371DCA <debug> nrf_ble_gq: Purging request queue with id: 0 <debug> nrf_ble_gq: Registering connection handle: 0x0000 <debug> ble_db_disc: Starting discovery of service with UUID 0xAE30 on connection handle 0x0. <debug> nrf_ble_gq: Adding item to the request queue <debug> nrf_ble_gq: GATTC Primary Services Discovery Request <debug> nrf_ble_gq: SD is currently busy. The GATT request procedure will be attempted again later. <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: GATTC Primary Service Discovery Request <debug> nrf_ble_gq: SD is currently busy. The GATT request procedure will be attempted again later. <debug> nrf_ble_gatt: Data length updated to 27 on connection 0x0. <debug> nrf_ble_gatt: max_rx_octets: 27 <debug> nrf_ble_gatt: max_tx_octets: 27 <debug> nrf_ble_gatt: max_rx_time: 328 <debug> nrf_ble_gatt: max_tx_time: 328 <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: GATTC Primary Service Discovery Request <error> nrf_ble_gq: SD GATT procedure (2) failed on connection handle 0 with error: 0x0000000D. <debug> app: GATT Client Timeout. <info> app: Disconnected. <info> app: Disconnected. conn_handle: 0x0, reason: 0x16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Copyright (c) 2016 - 2021, 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
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
/** * Copyright (c) 2016 - 2021, 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 <stdio.h> #include <stdint.h> #include <stdbool.h> #include "nordic_common.h" #include "app_error.h" #include "app_uart.h" #include "ble_db_discovery.h" #include "app_timer.h" #include "app_util.h" #include "bsp_btn_ble.h" #include "ble.h" #include "ble_gap.h" #include "ble_hci.h" #include "nrf_sdh.h" #include "nrf_sdh_ble.h" #include "nrf_sdh_soc.h" #include "ble_nus_c.h" #include "nrf_ble_gatt.h" #include "nrf_pwr_mgmt.h" #include "nrf_ble_scan.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "ble_conn_state.h" #include "at_cmd.h" #define VERSION_STRING_APP "ver:V1.0.0 build:"__DATE__" "__TIME__ static uint32_t find_adv_name(const ble_gap_evt_adv_report_t *p_adv_report, uint8_t *p_name); static void AT_SCNT_Handler(uint8_t *p_data, uint16_t data_len); static void AT_SCAN_Handler(uint8_t *p_data, uint16_t data_len); static void AT_COMI_Handler(uint8_t *p_data, uint16_t data_len); static void AT_COMA_Handler(uint8_t *p_data, uint16_t data_len); static void AT_COLA_Handler(uint8_t *p_data, uint16_t data_len); static void AT_COSU_Handler(uint8_t *p_data, uint16_t data_len); static void AT_CONN_Handler(uint8_t *p_data, uint16_t data_len); static void AT_CONC_Handler(uint8_t *p_data, uint16_t data_len); static void AT_DISC_Handler(uint8_t *p_data, uint16_t data_len); static void AT_DATA_Handler(uint8_t *p_data, uint16_t data_len); static void AT_VERS_Handler(uint8_t *p_data, uint16_t data_len); static void AT_TEST_Handler(uint8_t *p_data, uint16_t data_len); #define APP_BLE_CONN_CFG_TAG 1 /**< Tag that refers to the BLE stack configuration set with @ref sd_ble_cfg_set. The default tag is @ref BLE_CONN_CFG_TAG_DEFAULT. */ #define APP_BLE_OBSERVER_PRIO 3 /**< BLE observer priority of the application. There is no need to modify this value. */ #define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */ #define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */ #define NUS_SERVICE_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN /**< UUID type for the Nordic UART Service (vendor specific). */ #define ECHOBACK_BLE_UART_DATA 0 /**< Echo the UART data that is received over the Nordic UART Service (NUS) back to the sender. */ BLE_NUS_C_ARRAY_DEF(m_ble_nus_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT); /**< BLE Nordic UART Service (NUS) client instance. */ NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */ BLE_DB_DISCOVERY_ARRAY_DEF(m_db_disc, NRF_SDH_BLE_CENTRAL_LINK_COUNT); /**< Database discovery module instance. */ NRF_BLE_SCAN_DEF(m_scan); /**< Scanning Module instance. */ NRF_BLE_GQ_DEF(m_ble_gatt_queue, /**< BLE GATT Queue instance. */ NRF_SDH_BLE_CENTRAL_LINK_COUNT, NRF_BLE_GQ_QUEUE_SIZE); static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */ #define SCAN_NAME_BUFFER_SIZE (NRF_BLE_SCAN_NAME_MAX_LEN) /*��ʱ�洢�㲥���֣�*/ #define SCAN_TIMEOUT_DEFAULT (500)/**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */ static ble_gap_scan_params_t m_scan_param = { .active = 0x01, .interval = NRF_BLE_SCAN_SCAN_INTERVAL, .window = NRF_BLE_SCAN_SCAN_WINDOW, .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL, .timeout = SCAN_TIMEOUT_DEFAULT, .scan_phys = BLE_GAP_PHY_1MBPS,// 1 Mbps PHY }; static ble_gap_conn_params_t m_conn_param = { .min_conn_interval = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL, UNIT_1_25_MS), /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ .max_conn_interval = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL, UNIT_1_25_MS), /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ .slave_latency = (uint16_t)NRF_BLE_SCAN_SLAVE_LATENCY, /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ .conn_sup_timeout = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_SUPERVISION_TIMEOUT, UNIT_10_MS), /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ }; #define UART_TIMER_TIMEOUT (30) APP_TIMER_DEF(m_uart_rx_tmr); static uint8_t uart_rx_buf[BLE_NUS_MAX_DATA_LEN]; static uint8_t uart_rx_index = 0; static uint16_t uart_rx_leng = 0; /* at command define */ static volatile uint8_t at_received = 0; //at data has received static volatile at_code_typ at_process = AT_NULL; at_member_str const at_member_array[] = { {AT_COMI, AT_COMI_CODE}, {AT_COMA, AT_COMA_CODE}, {AT_COLA, AT_COLA_CODE}, {AT_COSU, AT_COSU_CODE}, {AT_SCNT, AT_SCNT_CODE}, {AT_SCAN, AT_SCAN_CODE}, {AT_CONN, AT_CONN_CODE}, {AT_CONC, AT_CONC_CODE}, {AT_DISC, AT_DISC_CODE}, {AT_DATA, AT_DATA_CODE}, {AT_VERS, AT_VERS_CODE}, {AT_TEST, AT_TEST_CODE}, {NULL, AT_NULL} }; /* current connection param define */ struct curr_conn_param_str { uint8_t channel; uint8_t filter_address[6]; } curr_conn_param = {0, 0, 0, 0, 0, 0, 0}; uint16_t conn_handle_array[2] = {BLE_CONN_HANDLE_INVALID,BLE_CONN_HANDLE_INVALID}; #define GET_CHANNEL_INDEX_BY_BLE_NUS_C(conn_handle_) (m_ble_nus_c[0].conn_handle == conn_handle_)?(0):(1) #define GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(conn_handle_) (conn_handle_array[0] == conn_handle_)?(0):(1) #define GET_CHANNEL_ACTIVE(channel_) (m_ble_nus_c[channel_].conn_handle == BLE_CONN_HANDLE_INVALID)?(0):(1) /**@brief NUS UUID. static ble_uuid_t const m_nus_uuid = { .uuid = BLE_UUID_NUS_SERVICE, .type = NUS_SERVICE_UUID_TYPE };*/ /* static uint8_t const m_name[] = "OTC Clarity Units-R"; static uint8_t const m_address[] = {0x11, 0x00, 0x40, 0x37, 0x03, 0x80}; */ /**@brief Function for handling asserts in the SoftDevice. * * @details This function is called in case of an assert in the SoftDevice. * * @warning This handler is only an example and is not meant for the final product. You need to analyze * how your product is supposed to react in case of 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) { app_error_handler(0xDEADBEEF, line_num, p_file_name); } /**@brief Function for handling the Nordic UART Service Client errors. * * @param[in] nrf_error Error code containing information about what went wrong. */ static void nus_error_handler(uint32_t nrf_error) { APP_ERROR_HANDLER(nrf_error); } /* static uint8_t const m_name_l[] = "OTC Clarity Units-L"; static uint8_t const m_address_l[] = {0x10, 0x00, 0x40, 0x37, 0x03, 0x80}; static void scan_reconfig(void) { ret_code_t err_code; nrf_ble_scan_stop(); nrf_ble_scan_filters_disable(&m_scan); nrf_ble_scan_all_filter_remove(&m_scan); err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_name_l); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_NAME_FILTER, false); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_ADDR_FILTER, m_address_l); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_ADDR_FILTER, false); APP_ERROR_CHECK(err_code); } */ /**@brief Function to start scanning. */ static void scan_start(void) { ret_code_t ret; ret = nrf_ble_scan_start(&m_scan); APP_ERROR_CHECK(ret); // ret = bsp_indication_set(BSP_INDICATE_SCANNING); // APP_ERROR_CHECK(ret); } //�����豸��ַ void device_stor(ble_nus_c_t * p_ble_nus_c,ble_gap_evt_connected_t const * p_addr) { p_ble_nus_c->addr.addr[0] = p_addr->peer_addr.addr[0]; p_ble_nus_c->addr.addr[1] = p_addr->peer_addr.addr[1]; p_ble_nus_c->addr.addr[2] = p_addr->peer_addr.addr[2]; p_ble_nus_c->addr.addr[3] = p_addr->peer_addr.addr[3]; p_ble_nus_c->addr.addr[4] = p_addr->peer_addr.addr[4]; p_ble_nus_c->addr.addr[5] = p_addr->peer_addr.addr[5]; } /**@brief Function for handling Scanning Module events. */ static void scan_evt_handler(scan_evt_t const * p_scan_evt) { ret_code_t err_code; switch(p_scan_evt->scan_evt_id) { case NRF_BLE_SCAN_EVT_CONNECTING_ERROR: { err_code = p_scan_evt->params.connecting_err.err_code; APP_ERROR_CHECK(err_code); if (at_process == AT_CONN_CODE) { printf("OK+CONNE\r\n"); at_process = AT_NULL; } } break; case NRF_BLE_SCAN_EVT_CONNECTED: { ble_gap_evt_connected_t const * p_connected = p_scan_evt->params.connected.p_connected; //device_stor(&m_ble_nus_c[p_scan_evt->params.connected.conn_handle],p_connected); device_stor(&m_ble_nus_c[curr_conn_param.channel],p_connected); // Scan is automatically stopped by the connection. NRF_LOG_INFO("Connecting to target %02x%02x%02x%02x%02x%02x", p_connected->peer_addr.addr[0], p_connected->peer_addr.addr[1], p_connected->peer_addr.addr[2], p_connected->peer_addr.addr[3], p_connected->peer_addr.addr[4], p_connected->peer_addr.addr[5] ); if (at_process == AT_CONN_CODE) { printf("OK+CONN%dS\r\n", curr_conn_param.channel); at_process = AT_NULL; } } break; case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT: { NRF_LOG_INFO("Scan timed out."); if (at_process == AT_SCAN_CODE) { if ((GET_CHANNEL_ACTIVE(0)) || (GET_CHANNEL_ACTIVE(1))) { if (GET_CHANNEL_ACTIVE(0)) { bsp_indication_set(BSP_INDICATE_USER_SCANNER_END_ONLY_1); } else { bsp_indication_set(BSP_INDICATE_USER_SCANNER_END_ONLY_0); } } else { bsp_indication_set(BSP_INDICATE_USER_SCANNER_END); } printf("OK+SCANE\r\n"); at_process = AT_NULL; } if (at_process == AT_CONN_CODE) { if (curr_conn_param.channel) { bsp_indication_set(BSP_INDICATE_USER_SCANNER_END_ONLY_1); } else { bsp_indication_set(BSP_INDICATE_USER_SCANNER_END_ONLY_0); } printf("OK+CONNF\r\n"); at_process = AT_NULL; } } break; case NRF_BLE_SCAN_EVT_NOT_FOUND: if (at_process == AT_SCAN_CODE) { uint8_t name_buffer[SCAN_NAME_BUFFER_SIZE]; memset(name_buffer, 0, SCAN_NAME_BUFFER_SIZE); ble_gap_evt_adv_report_t const * p_adv = p_scan_evt->params.p_not_found; if(find_adv_name(p_adv, name_buffer) != NRF_SUCCESS) { memset(name_buffer, 0, SCAN_NAME_BUFFER_SIZE); } else { printf("OK+SCAN%02X%02X%02X%02X%02X%02X:%d:%s\r\n", p_adv->peer_addr.addr[0], p_adv->peer_addr.addr[1], p_adv->peer_addr.addr[2], p_adv->peer_addr.addr[3], p_adv->peer_addr.addr[4], p_adv->peer_addr.addr[5], p_adv->rssi, name_buffer ); } } break; default: break; } } /**@brief Function for initializing the scanning and setting the filters. */ static void scan_init(bool use_filter) { ret_code_t err_code; nrf_ble_scan_init_t init_scan; memset(&init_scan, 0, sizeof(init_scan)); init_scan.connect_if_match = use_filter; init_scan.conn_cfg_tag = APP_BLE_CONN_CFG_TAG; init_scan.p_scan_param = &m_scan_param; init_scan.p_conn_param = &m_conn_param; err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler); APP_ERROR_CHECK(err_code); if (use_filter) { err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_ADDR_FILTER, curr_conn_param.filter_address); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_ADDR_FILTER, false); APP_ERROR_CHECK(err_code); } else { err_code = nrf_ble_scan_filters_disable(&m_scan); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_all_filter_remove(&m_scan); APP_ERROR_CHECK(err_code); } /* err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_name); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_NAME_FILTER, false); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_ADDR_FILTER, m_address); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_ADDR_FILTER, false); APP_ERROR_CHECK(err_code); */ /* err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_UUID_FILTER, &m_nus_uuid); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_UUID_FILTER, false); APP_ERROR_CHECK(err_code); */ } /**@brief Function for handling database discovery events. * * @details This function is a callback function to handle events from the database discovery module. * Depending on the UUIDs that are discovered, this function forwards the events * to their respective services. * * @param[in] p_event Pointer to the database discovery event. */ static void db_disc_handler(ble_db_discovery_evt_t * p_evt) { //ble_nus_c_on_db_disc_evt(&m_ble_nus_c[p_evt->conn_handle], p_evt); ble_nus_c_on_db_disc_evt(&m_ble_nus_c[GET_CHANNEL_INDEX_BY_BLE_NUS_C(p_evt->conn_handle)], p_evt); } /**@brief Function for handling characters received by the Nordic UART Service (NUS). * * @details This function takes a list of characters of length data_len and prints the characters out on UART. * If @ref ECHOBACK_BLE_UART_DATA is set, the data is sent back to sender. */ static void ble_nus_chars_received_uart_print(uint8_t * p_data, uint16_t data_len, uint8_t channel) { ret_code_t ret_val; NRF_LOG_DEBUG("Receiving data."); NRF_LOG_HEXDUMP_DEBUG(p_data, data_len); printf("OK+DATA%d:%d:", channel, data_len); for (uint32_t i = 0; i < data_len; i++) { do { ret_val = app_uart_put(p_data[i]); if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_BUSY)) { NRF_LOG_ERROR("app_uart_put failed for index 0x%04x.", i); APP_ERROR_CHECK(ret_val); } } while (ret_val == NRF_ERROR_BUSY); } if (ECHOBACK_BLE_UART_DATA) { /* // Send data back to the peripheral. do { ret_val = ble_nus_c_string_send(&m_ble_nus_c, p_data, data_len); if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_BUSY)) { NRF_LOG_ERROR("Failed sending NUS message. Error 0x%x. ", ret_val); APP_ERROR_CHECK(ret_val); } } while (ret_val == NRF_ERROR_BUSY);*/ } } /**@brief Function for handling app_uart events. * * @details This function receives a single character from the app_uart module and appends it to * a string. The string is sent over BLE when the last character received is a * 'new line' '\n' (hex 0x0A) or if the string reaches the maximum data length. */ void uart_event_handle(app_uart_evt_t * p_event) { switch (p_event->evt_type) { /**@snippet [Handling data from UART] */ case APP_UART_DATA_READY: if ((at_process == AT_NULL) && (at_received == 0) && (uart_rx_index < sizeof(uart_rx_buf))) { UNUSED_VARIABLE(app_uart_get(&uart_rx_buf[uart_rx_index++])); APP_ERROR_CHECK(app_timer_start(m_uart_rx_tmr, APP_TIMER_TICKS(UART_TIMER_TIMEOUT), NULL)); } break; /**@snippet [Handling data from UART] */ case APP_UART_COMMUNICATION_ERROR: NRF_LOG_ERROR("Communication error occurred while handling UART."); APP_ERROR_HANDLER(p_event->data.error_communication); break; case APP_UART_FIFO_ERROR: NRF_LOG_ERROR("Error occurred in FIFO module used by UART."); APP_ERROR_HANDLER(p_event->data.error_code); break; default: break; } } /**@brief Callback handling Nordic UART Service (NUS) client events. * * @details This function is called to notify the application of NUS client events. * * @param[in] p_ble_nus_c NUS client handle. This identifies the NUS client. * @param[in] p_ble_nus_evt Pointer to the NUS client event. */ /**@snippet [Handling events from the ble_nus_c module] */ static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt) { ret_code_t err_code; switch (p_ble_nus_evt->evt_type) { case BLE_NUS_C_EVT_DISCOVERY_COMPLETE: NRF_LOG_INFO("Discovery complete."); err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles); APP_ERROR_CHECK(err_code); err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c); APP_ERROR_CHECK(err_code); NRF_LOG_INFO("Connected to device with Nordic UART Service."); break; case BLE_NUS_C_EVT_NUS_TX_EVT: NRF_LOG_INFO("receive data for mac: %02X %02X %02X %02X %02X %02X\r\n", p_ble_nus_c->addr.addr[0], p_ble_nus_c->addr.addr[1], p_ble_nus_c->addr.addr[2], p_ble_nus_c->addr.addr[3], p_ble_nus_c->addr.addr[4], p_ble_nus_c->addr.addr[5] ); ble_nus_chars_received_uart_print(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len, GET_CHANNEL_INDEX_BY_BLE_NUS_C(p_ble_nus_c->conn_handle)); break; case BLE_NUS_C_EVT_DISCONNECTED: NRF_LOG_INFO("Disconnected."); // scan_start(); break; } } /**@snippet [Handling events from the ble_nus_c module] */ /** * @brief Function for handling shutdown events. * * @param[in] event Shutdown type. */ static bool shutdown_handler(nrf_pwr_mgmt_evt_t event) { ret_code_t err_code; err_code = bsp_indication_set(BSP_INDICATE_IDLE); APP_ERROR_CHECK(err_code); switch (event) { case NRF_PWR_MGMT_EVT_PREPARE_WAKEUP: // Prepare wakeup buttons. err_code = bsp_btn_ble_sleep_mode_prepare(); APP_ERROR_CHECK(err_code); break; default: break; } return true; } NRF_PWR_MGMT_HANDLER_REGISTER(shutdown_handler, APP_SHUTDOWN_HANDLER_PRIORITY); /**@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) { ret_code_t err_code; ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: APP_ERROR_CHECK_BOOL(p_gap_evt->conn_handle < NRF_SDH_BLE_CENTRAL_LINK_COUNT); //err_code = ble_nus_c_handles_assign(&m_ble_nus_c[p_gap_evt->conn_handle], p_ble_evt->evt.gap_evt.conn_handle, NULL); err_code = ble_nus_c_handles_assign(&m_ble_nus_c[curr_conn_param.channel], p_ble_evt->evt.gap_evt.conn_handle, NULL); APP_ERROR_CHECK(err_code); conn_handle_array[curr_conn_param.channel] = p_ble_evt->evt.gap_evt.conn_handle; err_code = bsp_indication_set((curr_conn_param.channel)?(BSP_INDICATE_USER_CHANNEL_1_ACTIVE):(BSP_INDICATE_USER_CHANNEL_0_ACTIVE)); APP_ERROR_CHECK(err_code); // start discovery of services. The NUS Client waits for a discovery result //err_code = ble_db_discovery_start(&m_db_disc[p_gap_evt->conn_handle], p_ble_evt->evt.gap_evt.conn_handle); err_code = ble_db_discovery_start(&m_db_disc[curr_conn_param.channel], p_ble_evt->evt.gap_evt.conn_handle); APP_ERROR_CHECK(err_code); /* if (ble_conn_state_central_conn_count() == NRF_SDH_BLE_CENTRAL_LINK_COUNT) { NRF_LOG_INFO("central counter two!"); } else { // scan_reconfig(); // scan_start(); }*/ break; case BLE_GAP_EVT_DISCONNECTED: NRF_LOG_INFO("Disconnected. conn_handle: 0x%x, reason: 0x%x", p_gap_evt->conn_handle, p_gap_evt->params.disconnected.reason); printf("OK+LOST%d:%02X%02X%02X%02X%02X%02X\r\n", GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(p_gap_evt->conn_handle), m_ble_nus_c[GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(p_gap_evt->conn_handle)].addr.addr[0], m_ble_nus_c[GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(p_gap_evt->conn_handle)].addr.addr[1], m_ble_nus_c[GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(p_gap_evt->conn_handle)].addr.addr[2], m_ble_nus_c[GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(p_gap_evt->conn_handle)].addr.addr[3], m_ble_nus_c[GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(p_gap_evt->conn_handle)].addr.addr[4], m_ble_nus_c[GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(p_gap_evt->conn_handle)].addr.addr[5] ); err_code = bsp_indication_set( (GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(p_gap_evt->conn_handle))? (BSP_INDICATE_USER_CHANNEL_1_INVALID):(BSP_INDICATE_USER_CHANNEL_0_INVALID)); APP_ERROR_CHECK(err_code); conn_handle_array[GET_CHANNEL_INDEX_BY_CONN_HANDLE_ARR(p_gap_evt->conn_handle)] = BLE_CONN_HANDLE_INVALID; break; case BLE_GAP_EVT_TIMEOUT: if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { NRF_LOG_INFO("Connection Request timed out."); } if (at_process == AT_CONN_CODE) { printf("OK+CONNF\r\n"); at_process = AT_NULL; } break; case BLE_GAP_EVT_SEC_PARAMS_REQUEST: // Pairing not supported. err_code = sd_ble_gap_sec_params_reply(p_ble_evt->evt.gap_evt.conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); APP_ERROR_CHECK(err_code); break; case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: // Accepting parameters requested by 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_GAP_EVT_PHY_UPDATE_REQUEST: { NRF_LOG_DEBUG("PHY update request."); ble_gap_phys_t const phys = { .rx_phys = BLE_GAP_PHY_AUTO, .tx_phys = BLE_GAP_PHY_AUTO, }; err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys); APP_ERROR_CHECK(err_code); } break; case BLE_GATTC_EVT_TIMEOUT: // Disconnect on GATT Client timeout event. NRF_LOG_DEBUG("GATT Client Timeout."); 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 timeout event. NRF_LOG_DEBUG("GATT Server Timeout."); 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; default: break; } } /**@brief Function for initializing the BLE stack. * * @details Initializes the SoftDevice and the BLE event interrupt. */ 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 GATT library. */ void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt) { if (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED) { NRF_LOG_INFO("ATT MTU exchange completed."); m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH; NRF_LOG_INFO("Ble NUS max data length set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len); } } /**@brief Function for initializing the GATT library. */ void gatt_init(void) { ret_code_t err_code; err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler); APP_ERROR_CHECK(err_code); err_code = nrf_ble_gatt_att_mtu_central_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE); APP_ERROR_CHECK(err_code); } /**@brief Function for handling events from the BSP module. * * @param[in] event Event generated by button press. */ void bsp_event_handler(bsp_event_t event) { // ret_code_t err_code; switch (event) { case BSP_EVENT_SLEEP: nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF); break; case BSP_EVENT_DISCONNECT: /* err_code = sd_ble_gap_disconnect(m_ble_nus_c.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } */ break; default: break; } } /**@brief Handle events from leds timer. * * @note Timer handler does not support returning an error code. * Errors from bsp_led_indication() are not propagated. * * @param[in] p_context parameter registered in timer start function. */ static void uart_timer_handler(void * p_context) { UNUSED_PARAMETER(p_context); uart_rx_leng = uart_rx_index; uart_rx_index = 0; at_received = 1; } /**@brief Function for initializing the UART. */ static void uart_init(void) { ret_code_t err_code; app_uart_comm_params_t const comm_params = { .rx_pin_no = RX_PIN_NUMBER, .tx_pin_no = TX_PIN_NUMBER, .rts_pin_no = RTS_PIN_NUMBER, .cts_pin_no = CTS_PIN_NUMBER, .flow_control = APP_UART_FLOW_CONTROL_DISABLED, .use_parity = false, .baud_rate = UART_BAUDRATE_BAUDRATE_Baud115200 }; APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_event_handle, APP_IRQ_PRIORITY_LOWEST, err_code); APP_ERROR_CHECK(err_code); err_code = app_timer_create(&m_uart_rx_tmr, APP_TIMER_MODE_SINGLE_SHOT, uart_timer_handler); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the Nordic UART Service (NUS) client. */ static void nus_c_init(void) { ret_code_t err_code; ble_nus_c_init_t init; init.evt_handler = ble_nus_c_evt_handler; init.error_handler = nus_error_handler; init.p_gatt_queue = &m_ble_gatt_queue; for (uint32_t i = 0; i < NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++) { err_code = ble_nus_c_init(&m_ble_nus_c[i], &init); APP_ERROR_CHECK(err_code); } } /**@brief Function for initializing leds. */ static void leds_init(void) { ret_code_t err_code; //bsp_event_t startup_event; err_code = bsp_init(BSP_INIT_LEDS, bsp_event_handler); APP_ERROR_CHECK(err_code); //err_code = bsp_btn_ble_init(NULL, &startup_event); //APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the timer. */ static void timer_init(void) { ret_code_t err_code = app_timer_init(); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the nrf log module. */ static void log_init(void) { ret_code_t err_code = NRF_LOG_INIT(NULL); APP_ERROR_CHECK(err_code); NRF_LOG_DEFAULT_BACKENDS_INIT(); } /**@brief Function for initializing power management. */ static void power_management_init(void) { ret_code_t err_code; err_code = nrf_pwr_mgmt_init(); APP_ERROR_CHECK(err_code); } /** @brief Function for initializing the database discovery module. */ static void db_discovery_init(void) { ble_db_discovery_init_t db_init; memset(&db_init, 0, sizeof(ble_db_discovery_init_t)); db_init.evt_handler = db_disc_handler; db_init.p_gatt_queue = &m_ble_gatt_queue; ret_code_t err_code = ble_db_discovery_init(&db_init); APP_ERROR_CHECK(err_code); } /**@brief Function for handling the idle state (main loop). * * @details Handles any pending log operations, then sleeps until the next event occurs. */ static void idle_state_handle(void) { if (NRF_LOG_PROCESS() == false) { //nrf_pwr_mgmt_run(); } } static at_code_typ at_get_code(void *param, uint16_t leng) { at_code_typ code = AT_NULL; uint16_t ok_count; uint16_t cmp_leng; uint8_t *p_at_str; uint8_t *p_param; if (at_received) { at_member_str *p_at_member = (at_member_str *)at_member_array; while (p_at_member->string != NULL) { ok_count = 0; cmp_leng = 0; p_at_str = (uint8_t *)p_at_member->string; p_param = (uint8_t *)param; while ((*p_at_str != '\0') && (cmp_leng < leng)) { cmp_leng++; if (*p_at_str++ == *p_param++) { ok_count++; } else { break; } } if (ok_count == strlen((const char *)p_at_member->string)) { code = p_at_member->code; NRF_LOG_INFO("result=%s, cmp_len=%d, ok_count=%d, leng=%d, at_code=%d", p_at_member->string, cmp_leng, ok_count, leng, code); break; } p_at_member++; } at_received = 0; } return code; } static void uart_puts(uint8_t *p_data, uint16_t data_len) { ret_code_t ret_val; for (uint32_t i = 0; i < data_len; i++) { do { ret_val = app_uart_put(p_data[i]); if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_BUSY)) { NRF_LOG_ERROR("app_uart_put failed for index 0x%04x.", i); APP_ERROR_CHECK(ret_val); } } while (ret_val == NRF_ERROR_BUSY); } } static uint32_t find_adv_name(const ble_gap_evt_adv_report_t *p_adv_report, uint8_t *p_name) { uint8_t i; uint32_t index = 0; uint8_t * p_data; p_data = p_adv_report->data.p_data; while (index < p_adv_report->data.len) { uint8_t field_length = p_data[index]; uint8_t field_type = p_data[index + 1]; if ((field_type == BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME) || (field_type == BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME)) { for(i=0;i<field_length-1;i++) { *p_name++ = p_data[index+2+i]; if (i >= SCAN_NAME_BUFFER_SIZE - 1) break; } return NRF_SUCCESS; } index += field_length + 1; } return NRF_ERROR_NOT_FOUND; } int main(void) { // Initialize. log_init(); timer_init(); uart_init(); leds_init(); db_discovery_init(); power_management_init(); ble_stack_init(); gatt_init(); nus_c_init(); scan_init(false); // Start execution. printf("BLE UART central example started. zsl:%s\r\n", __TIME__); NRF_LOG_INFO("BLE UART central example started. zsl:%s", __TIME__); //scan_start(); // Enter main loop. for (;;) { idle_state_handle(); if (at_process == AT_NULL) { at_process = at_get_code(uart_rx_buf, uart_rx_leng); switch(at_process) { case AT_COMI_CODE: AT_COMI_Handler(uart_rx_buf, uart_rx_leng); break; case AT_COMA_CODE: AT_COMA_Handler(uart_rx_buf, uart_rx_leng); break; case AT_COLA_CODE: AT_COLA_Handler(uart_rx_buf, uart_rx_leng); break; case AT_COSU_CODE: AT_COSU_Handler(uart_rx_buf, uart_rx_leng); break; case AT_SCNT_CODE: AT_SCNT_Handler(uart_rx_buf, uart_rx_leng); break; case AT_SCAN_CODE: AT_SCAN_Handler(uart_rx_buf, uart_rx_leng); break; case AT_CONN_CODE: AT_CONN_Handler(uart_rx_buf, uart_rx_leng); break; case AT_CONC_CODE: AT_CONC_Handler(uart_rx_buf, uart_rx_leng); break; case AT_DISC_CODE: AT_DISC_Handler(uart_rx_buf, uart_rx_leng); break; case AT_DATA_CODE: AT_DATA_Handler(uart_rx_buf, uart_rx_leng); break; case AT_VERS_CODE: AT_VERS_Handler(uart_rx_buf, uart_rx_leng); break; case AT_TEST_CODE: AT_TEST_Handler(uart_rx_buf, uart_rx_leng); break; default:break; } } } } /****************************** AT+SCNT[P] P: [1~ 9] [?] *****************************/ static void AT_SCNT_Handler(uint8_t *p_data, uint16_t data_len) { uint8_t param = *(p_data + sizeof(AT_SCNT) - 1); if (data_len <= (sizeof(AT_SCNT) - 1)) { at_process = AT_NULL; return; } if (param == '?') { printf("OK+Get:%d\r\n", m_scan_param.timeout/100); } else if ((param >= '1') && (param <= '9')) { m_scan_param.timeout = (param - '0')*100; nrf_ble_scan_stop(); scan_init(false); printf("OK+Set:%d\r\n", m_scan_param.timeout/100); } at_process = AT_NULL; } static void AT_SCAN_Handler(uint8_t *p_data, uint16_t data_len) { if ((GET_CHANNEL_ACTIVE(0)) && (GET_CHANNEL_ACTIVE(1))) { at_process = AT_NULL; return; } printf("OK+SCANS\r\n"); if ((GET_CHANNEL_ACTIVE(0)) || (GET_CHANNEL_ACTIVE(1))) { if (GET_CHANNEL_ACTIVE(0)) { bsp_indication_set(BSP_INDICATE_USER_SCANNER_START_ONLY_1); } else { bsp_indication_set(BSP_INDICATE_USER_SCANNER_START_ONLY_0); } } else { bsp_indication_set(BSP_INDICATE_USER_SCANNER_START); } scan_init(false); scan_start(); } static void AT_COMI_Handler(uint8_t *p_data, uint16_t data_len) { int8_t interval = 0; uint8_t param = *(p_data + sizeof(AT_COMI) - 1); if (data_len <= (sizeof(AT_SCNT) - 1)) { at_process = AT_NULL; return; } if (param == '?') { switch (m_conn_param.min_conn_interval) { case (uint16_t)MSEC_TO_UNITS(7.5, UNIT_1_25_MS):interval = 0;break; case (uint16_t)MSEC_TO_UNITS(10, UNIT_1_25_MS):interval = 1;break; case (uint16_t)MSEC_TO_UNITS(15, UNIT_1_25_MS):interval = 2;break; case (uint16_t)MSEC_TO_UNITS(20, UNIT_1_25_MS):interval = 3;break; case (uint16_t)MSEC_TO_UNITS(25, UNIT_1_25_MS):interval = 4;break; case (uint16_t)MSEC_TO_UNITS(30, UNIT_1_25_MS):interval = 5;break; case (uint16_t)MSEC_TO_UNITS(35, UNIT_1_25_MS):interval = 6;break; case (uint16_t)MSEC_TO_UNITS(40, UNIT_1_25_MS):interval = 7;break; case (uint16_t)MSEC_TO_UNITS(45, UNIT_1_25_MS):interval = 8;break; case (uint16_t)MSEC_TO_UNITS(60, UNIT_1_25_MS):interval = 9;break; default:interval = -1;break; } printf("OK+Get:%d\r\n", interval); } else if ((param >= '0') && (param <= '9')) { switch (param) { case '0':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(7.5, UNIT_1_25_MS);break; case '1':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(10, UNIT_1_25_MS);break; case '2':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(15, UNIT_1_25_MS);break; case '3':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(20, UNIT_1_25_MS);break; case '4':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(25, UNIT_1_25_MS);break; case '5':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(30, UNIT_1_25_MS);break; case '6':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(35, UNIT_1_25_MS);break; case '7':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(40, UNIT_1_25_MS);break; case '8':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(45, UNIT_1_25_MS);break; case '9':m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(60, UNIT_1_25_MS);break; default: m_conn_param.min_conn_interval = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL, UNIT_1_25_MS); break; } nrf_ble_scan_stop(); scan_init(false); printf("OK+Set:%d\r\n", param-'0'); } at_process = AT_NULL; } static void AT_COMA_Handler(uint8_t *p_data, uint16_t data_len) { int8_t interval = 0; uint8_t param = *(p_data + sizeof(AT_COMA) - 1); if (data_len <= (sizeof(AT_SCNT) - 1)) { at_process = AT_NULL; return; } if (param == '?') { switch (m_conn_param.max_conn_interval) { case (uint16_t)MSEC_TO_UNITS(7.5, UNIT_1_25_MS):interval = 0;break; case (uint16_t)MSEC_TO_UNITS(10, UNIT_1_25_MS):interval = 1;break; case (uint16_t)MSEC_TO_UNITS(15, UNIT_1_25_MS):interval = 2;break; case (uint16_t)MSEC_TO_UNITS(20, UNIT_1_25_MS):interval = 3;break; case (uint16_t)MSEC_TO_UNITS(25, UNIT_1_25_MS):interval = 4;break; case (uint16_t)MSEC_TO_UNITS(30, UNIT_1_25_MS):interval = 5;break; case (uint16_t)MSEC_TO_UNITS(35, UNIT_1_25_MS):interval = 6;break; case (uint16_t)MSEC_TO_UNITS(40, UNIT_1_25_MS):interval = 7;break; case (uint16_t)MSEC_TO_UNITS(45, UNIT_1_25_MS):interval = 8;break; case (uint16_t)MSEC_TO_UNITS(60, UNIT_1_25_MS):interval = 9;break; default:interval = -1;break; } printf("OK+Get:%d\r\n", interval); } else if ((param >= '0') && (param <= '9')) { switch (param) { case '0':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(7.5, UNIT_1_25_MS);break; case '1':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(10, UNIT_1_25_MS);break; case '2':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(15, UNIT_1_25_MS);break; case '3':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(20, UNIT_1_25_MS);break; case '4':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(25, UNIT_1_25_MS);break; case '5':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(30, UNIT_1_25_MS);break; case '6':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(35, UNIT_1_25_MS);break; case '7':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(40, UNIT_1_25_MS);break; case '8':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(45, UNIT_1_25_MS);break; case '9':m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(60, UNIT_1_25_MS);break; default: m_conn_param.max_conn_interval = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL, UNIT_1_25_MS); break; } nrf_ble_scan_stop(); scan_init(false); printf("OK+Set:%d\r\n", param-'0'); } at_process = AT_NULL; } static void AT_COLA_Handler(uint8_t *p_data, uint16_t data_len) { if (data_len <= (sizeof(AT_SCNT) - 1)) { at_process = AT_NULL; return; } if (*(p_data + sizeof(AT_COLA) - 1) == '?') { printf("OK+Get:%d\r\n", m_conn_param.slave_latency); } else { uint32_t latency; int result; uint8_t buffer[4] = {0,0,0,0}; memcpy(buffer, (p_data + sizeof(AT_COLA) - 1), data_len - sizeof(AT_COLA) + 1); result = sscanf((const char *)buffer, "%d", &latency); if ((latency <= BLE_GAP_CP_SLAVE_LATENCY_MAX) && (result == 1)) { m_conn_param.slave_latency = latency; nrf_ble_scan_stop(); scan_init(false); printf("OK+Set:%d\r\n", m_conn_param.slave_latency); } } at_process = AT_NULL; } static void AT_COSU_Handler(uint8_t *p_data, uint16_t data_len) { int8_t timeout; uint8_t param = *(p_data + sizeof(AT_COSU) - 1); if (data_len <= (sizeof(AT_SCNT) - 1)) { at_process = AT_NULL; return; } if (param == '?') { switch (m_conn_param.conn_sup_timeout) { case (uint16_t)MSEC_TO_UNITS(100, UNIT_10_MS):timeout = 0;break; case (uint16_t)MSEC_TO_UNITS(1000, UNIT_10_MS):timeout = 1;break; case (uint16_t)MSEC_TO_UNITS(2000, UNIT_10_MS):timeout = 2;break; case (uint16_t)MSEC_TO_UNITS(3000, UNIT_10_MS):timeout = 3;break; case (uint16_t)MSEC_TO_UNITS(4000, UNIT_10_MS):timeout = 4;break; case (uint16_t)MSEC_TO_UNITS(5000, UNIT_10_MS):timeout = 5;break; case (uint16_t)MSEC_TO_UNITS(6000, UNIT_10_MS):timeout = 6;break; default:timeout = -1;break; } printf("OK+Get:%d\r\n", timeout); } else if ((param >= '0') && (param <= '6')) { if (param == '0') { m_conn_param.conn_sup_timeout = (uint16_t)MSEC_TO_UNITS(100, UNIT_10_MS); } else if((param >= '1') && (param <= '6')) { m_conn_param.conn_sup_timeout = (uint16_t)MSEC_TO_UNITS((param-'0')*1000, UNIT_10_MS); } nrf_ble_scan_stop(); scan_init(false); printf("OK+Set:%d\r\n", param - '0'); } at_process = AT_NULL; } static void AT_CONN_Handler(uint8_t *p_data, uint16_t data_len) { uint32_t channel; uint32_t address[6]; int result; if (data_len < (sizeof(AT_CONN"0:010203040506") - 1)) { goto flag_error; } //extract result = sscanf((const char *)p_data, "AT+CONN%d:%02X%02X%02X%02X%02X%02X", &channel, &address[0], &address[1], &address[2], &address[3], &address[4], &address[5]); if (result != 7) { goto flag_error; } if (channel == 0) { curr_conn_param.channel = 0; } else if (channel == 1) { curr_conn_param.channel = 1; } else { goto flag_error; } curr_conn_param.filter_address[0] = address[0]; curr_conn_param.filter_address[1] = address[1]; curr_conn_param.filter_address[2] = address[2]; curr_conn_param.filter_address[3] = address[3]; curr_conn_param.filter_address[4] = address[4]; curr_conn_param.filter_address[5] = address[5]; if (m_ble_nus_c[curr_conn_param.channel].conn_handle != BLE_CONN_HANDLE_INVALID) { goto flag_error; } if (curr_conn_param.channel) { bsp_indication_set(BSP_INDICATE_USER_SCANNER_START_ONLY_1); } else { bsp_indication_set(BSP_INDICATE_USER_SCANNER_START_ONLY_0); } // connecting target printf("OK+CONN%dA\r\n", curr_conn_param.channel); //report connecting scan_init(true); scan_start(); return; flag_error: at_process = AT_NULL; } static void AT_CONC_Handler(uint8_t *p_data, uint16_t data_len) { uint8_t channel; if (data_len < (sizeof(AT_CONC"0") - 1)) { goto flag_error; } if (*(p_data + 7) == '0') { channel = 0; } else if(*(p_data + 7) == '1') { channel = 1; } else { goto flag_error; } if (m_ble_nus_c[channel].conn_handle == BLE_CONN_HANDLE_INVALID) { printf("OK+CON0\r\n"); } else { printf("OK+CON1:%02X%02X%02X%02X%02X%02X\r\n", m_ble_nus_c[channel].addr.addr[0], m_ble_nus_c[channel].addr.addr[1], m_ble_nus_c[channel].addr.addr[2], m_ble_nus_c[channel].addr.addr[3], m_ble_nus_c[channel].addr.addr[4], m_ble_nus_c[channel].addr.addr[5]); } flag_error: at_process = AT_NULL; } static void AT_DISC_Handler(uint8_t *p_data, uint16_t data_len) { uint8_t channel; ret_code_t err_code; if (data_len < (sizeof(AT_DISC"0") - 1)) { goto flag_error; } if (*(p_data + 7) == '0') { channel = 0; } else if(*(p_data + 7) == '1') { channel = 1; } else { goto flag_error; } if (m_ble_nus_c[channel].conn_handle == BLE_CONN_HANDLE_INVALID) { goto flag_error; } err_code = sd_ble_gap_disconnect(m_ble_nus_c[channel].conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); goto flag_error; } printf("OK+DISC%d\r\n", channel); flag_error: at_process = AT_NULL; } static void AT_DATA_Handler(uint8_t *p_data, uint16_t data_len) { uint32_t channel; uint32_t length; int result; uint8_t *p_send_data; uint8_t counter = 0; uint32_t ret_val; if (data_len < (sizeof(AT_DATA"0:0:") - 1)) { goto flag_error; } result = sscanf((const char *)p_data, "AT+DATA%d:%d:", &channel, &length); NRF_LOG_INFO("sscanf result:%d, channel:%d, length:%d\r\n", result, channel, length); p_send_data = p_data + sizeof("AT+DATA0:") - 1; while ((*p_send_data++ != ':') && (++counter <= length)); do { ret_val = ble_nus_c_string_send(&m_ble_nus_c[channel], p_send_data, length); if ( (ret_val != NRF_ERROR_INVALID_STATE) && (ret_val != NRF_ERROR_RESOURCES) ) { APP_ERROR_CHECK(ret_val); } } while (ret_val == NRF_ERROR_RESOURCES); flag_error: at_process = AT_NULL; } static void AT_VERS_Handler(uint8_t *p_data, uint16_t data_len) { printf("OK+Get:%s\r\n", VERSION_STRING_APP); at_process = AT_NULL; } static void AT_TEST_Handler(uint8_t *p_data, uint16_t data_len) { uart_puts("OK\r\n", sizeof("OK\r\n")-1); at_process = AT_NULL; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Copyright (c) 2012 - 2021, 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
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
/** * Copyright (c) 2012 - 2021, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "sdk_common.h" #if NRF_MODULE_ENABLED(BLE_NUS_C) #include <stdlib.h> #include "ble.h" #include "ble_nus_c.h" #include "ble_gattc.h" #include "ble_srv_common.h" #include "app_error.h" #define NRF_LOG_MODULE_NAME ble_nus_c #include "nrf_log.h" NRF_LOG_MODULE_REGISTER(); /**@brief Function for intercepting the errors of GATTC and the BLE GATT Queue. * * @param[in] nrf_error Error code. * @param[in] p_ctx Parameter from the event handler. * @param[in] conn_handle Connection handle. */ static void gatt_error_handler(uint32_t nrf_error, void * p_ctx, uint16_t conn_handle) { ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_ctx; NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle); if (p_ble_nus_c->error_handler != NULL) { p_ble_nus_c->error_handler(nrf_error); } } void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt) { ble_nus_c_evt_t nus_c_evt; memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t)); ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics; // Check if the NUS was discovered. if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) && (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE) && (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type)) { for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++) { switch (p_chars[i].characteristic.uuid.uuid) { case BLE_UUID_NUS_RX_CHARACTERISTIC: nus_c_evt.handles.nus_rx_handle = p_chars[i].characteristic.handle_value; p_ble_nus_c->write_cmd = p_chars[i].characteristic.char_props.write_wo_resp; break; case BLE_UUID_NUS_TX_CHARACTERISTIC: nus_c_evt.handles.nus_tx_handle = p_chars[i].characteristic.handle_value; nus_c_evt.handles.nus_tx_cccd_handle = p_chars[i].cccd_handle; break; default: break; } } if (p_ble_nus_c->evt_handler != NULL) { nus_c_evt.conn_handle = p_evt->conn_handle; nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCOVERY_COMPLETE; p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt); } } } /**@brief Function for handling Handle Value Notification received from the SoftDevice. * * @details This function uses the Handle Value Notification received from the SoftDevice * and checks if it is a notification of the NUS TX characteristic from the peer. * If it is, this function decodes the data and sends it to the application. * * @param[in] p_ble_nus_c Pointer to the NUS Client structure. * @param[in] p_ble_evt Pointer to the BLE event received. */ static void on_hvx(ble_nus_c_t * p_ble_nus_c, ble_evt_t const * p_ble_evt) { // HVX can only occur from client sending. if ( (p_ble_nus_c->handles.nus_tx_handle != BLE_GATT_HANDLE_INVALID) && (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_tx_handle) && (p_ble_nus_c->evt_handler != NULL)) { ble_nus_c_evt_t ble_nus_c_evt; ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TX_EVT; ble_nus_c_evt.p_data = (uint8_t *)p_ble_evt->evt.gattc_evt.params.hvx.data; ble_nus_c_evt.data_len = p_ble_evt->evt.gattc_evt.params.hvx.len; p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt); NRF_LOG_DEBUG("Client sending data."); } } uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init) { uint32_t err_code; ble_uuid_t uart_uuid; ble_uuid128_t nus_base_uuid = NUS_BASE_UUID; VERIFY_PARAM_NOT_NULL(p_ble_nus_c); VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init); VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init->p_gatt_queue); err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type); VERIFY_SUCCESS(err_code); uart_uuid.type = p_ble_nus_c->uuid_type; uart_uuid.uuid = BLE_UUID_NUS_SERVICE; p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID; p_ble_nus_c->evt_handler = p_ble_nus_c_init->evt_handler; p_ble_nus_c->error_handler = p_ble_nus_c_init->error_handler; p_ble_nus_c->handles.nus_tx_handle = BLE_GATT_HANDLE_INVALID; p_ble_nus_c->handles.nus_rx_handle = BLE_GATT_HANDLE_INVALID; p_ble_nus_c->p_gatt_queue = p_ble_nus_c_init->p_gatt_queue; return ble_db_discovery_evt_register(&uart_uuid); } void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context) { ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_context; if ((p_ble_nus_c == NULL) || (p_ble_evt == NULL)) { return; } if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID) ||(p_ble_nus_c->conn_handle != p_ble_evt->evt.gap_evt.conn_handle) ) { return; } switch (p_ble_evt->header.evt_id) { case BLE_GATTC_EVT_HVX: on_hvx(p_ble_nus_c, p_ble_evt); break; case BLE_GAP_EVT_DISCONNECTED: if (p_ble_evt->evt.gap_evt.conn_handle == p_ble_nus_c->conn_handle && p_ble_nus_c->evt_handler != NULL) { ble_nus_c_evt_t nus_c_evt; nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCONNECTED; p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID; p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt); } break; default: // No implementation needed. break; } } /**@brief Function for creating a message for writing to the CCCD. */ static uint32_t cccd_configure(ble_nus_c_t * p_ble_nus_c, bool notification_enable) { nrf_ble_gq_req_t cccd_req; uint8_t cccd[BLE_CCCD_VALUE_LEN]; uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : 0; memset(&cccd_req, 0, sizeof(nrf_ble_gq_req_t)); cccd[0] = LSB_16(cccd_val); cccd[1] = MSB_16(cccd_val); cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE; cccd_req.error_handler.cb = gatt_error_handler; cccd_req.error_handler.p_ctx = p_ble_nus_c; cccd_req.params.gattc_write.handle = p_ble_nus_c->handles.nus_tx_cccd_handle; cccd_req.params.gattc_write.len = BLE_CCCD_VALUE_LEN; cccd_req.params.gattc_write.offset = 0; cccd_req.params.gattc_write.p_value = cccd; cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ; cccd_req.params.gattc_write.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE; return nrf_ble_gq_item_add(p_ble_nus_c->p_gatt_queue, &cccd_req, p_ble_nus_c->conn_handle); } uint32_t ble_nus_c_tx_notif_enable(ble_nus_c_t * p_ble_nus_c) { VERIFY_PARAM_NOT_NULL(p_ble_nus_c); if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID) ||(p_ble_nus_c->handles.nus_tx_cccd_handle == BLE_GATT_HANDLE_INVALID) ) { return NRF_ERROR_INVALID_STATE; } return cccd_configure(p_ble_nus_c, true); } uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length) { VERIFY_PARAM_NOT_NULL(p_ble_nus_c); nrf_ble_gq_req_t write_req; memset(&write_req, 0, sizeof(nrf_ble_gq_req_t)); if (length > BLE_NUS_MAX_DATA_LEN) { NRF_LOG_WARNING("Content too long."); return NRF_ERROR_INVALID_PARAM; } if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID) { NRF_LOG_WARNING("Connection handle invalid."); return NRF_ERROR_INVALID_STATE; } write_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE; write_req.error_handler.cb = gatt_error_handler; write_req.error_handler.p_ctx = p_ble_nus_c; write_req.params.gattc_write.handle = p_ble_nus_c->handles.nus_rx_handle; write_req.params.gattc_write.len = length; write_req.params.gattc_write.offset = 0; write_req.params.gattc_write.p_value = p_string; write_req.params.gattc_write.write_op = (p_ble_nus_c->write_cmd)?(BLE_GATT_OP_WRITE_CMD):(BLE_GATT_OP_WRITE_REQ); write_req.params.gattc_write.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE; return nrf_ble_gq_item_add(p_ble_nus_c->p_gatt_queue, &write_req, p_ble_nus_c->conn_handle); } uint32_t ble_nus_c_handles_assign(ble_nus_c_t * p_ble_nus, uint16_t conn_handle, ble_nus_c_handles_t const * p_peer_handles) { VERIFY_PARAM_NOT_NULL(p_ble_nus); p_ble_nus->conn_handle = conn_handle; if (p_peer_handles != NULL) { p_ble_nus->handles.nus_tx_cccd_handle = p_peer_handles->nus_tx_cccd_handle; p_ble_nus->handles.nus_tx_handle = p_peer_handles->nus_tx_handle; p_ble_nus->handles.nus_rx_handle = p_peer_handles->nus_rx_handle; } return nrf_ble_gq_conn_handle_register(p_ble_nus->p_gatt_queue, conn_handle); } #endif // NRF_MODULE_ENABLED(BLE_NUS_C)