Hi Nordic,
Please provide the way to debug not able to write 14 Bytes data into Queued Writes module, my application not get any nrf_ble_qwr_on_ble_evt.
[Project Informaiton]
nrf52832 (S132 SoftDevice v6.1.1) + MCU (CXD5602), UART interface to connect between each other.
[Design description]
My application designs both ble_peripheral, and ble_central in one.
I integrate "write-queued-characteristic-with-less-than-20-bytes" solutions into my application.
[sdk_config.h]
#define NRF_BLE_QWR_ENABLED 1
#define NRF_BLE_QWR_MAX_ATTR 1
[Issue description]
Not able write more than 13 Bytes data (while write 14 Bytes, My application stuck) into My applcation with nrf_connect android application
In nrf_connect android application shows log in "Log 2020-01-17 11_37_48.txt"
[Central][Log in nrf_connect android application]
1). write 13 Bytes, result: PASS
V 11:37:05.688 Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D 11:37:05.688 gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x31323334353637383930313233)
I 11:37:06.088 Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 31-32-33-34-35-36-37-38-39-30-31-32-33, "1234567890123"
A 11:37:06.088 "1234567890123" sent
2). write 14 Bytes, result: NG
V 11:37:28.334 Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D 11:37:28.334 gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x3132333435363738393031323334)
D 11:37:32.522 [Server callback] Connection state changed with status: 0 and new state: DISCONNECTED (0)
I 11:37:32.522 [Server] Device disconnected
E 11:37:32.538 Error 133 (0x85): GATT ERROR
[Peripheral][Log in my application with nrf52832]
1). write 13 Bytes, result: PASS
[2020-01-17 11:36:49] ble_spresense_handler_on_le_connect_status_change, ble_state_s.ble_connect_handle = 0x0001
[2020-01-17 11:36:49] [BLE_GATT] Connect status ADDR:6D:E1:DE:BF:A7:C3, status:Connected, ble_state->ble_connect_handle = 0x0001
[2020-01-17 11:36:49] Debug : RESP_OK => nrf_ble_qwr_on_ble_evt, p_ble_evt->header.evt_id = 16
[2020-01-17 11:36:49] Debug : RESP_OK => nrf_ble_qwr_on_ble_evt, p_ble_evt->header.evt_id = 35
[2020-01-17 11:36:49] Debug : RESP_OK => nrf_ble_qwr_on_ble_evt, p_ble_evt->header.evt_id = 36
[2020-01-17 11:36:49] Debug : RESP_OK => PHY update request.
[2020-01-17 11:36:49] Debug : RESP_OK => nrf_ble_qwr_on_ble_evt, p_ble_evt->header.evt_id = 33
[2020-01-17 11:36:50] Debug : RESP_OK => nrf_ble_qwr_on_ble_evt, p_ble_evt->header.evt_id = 34
[2020-01-17 11:36:50] Debug : RESP_OK => nrf_ble_qwr_on_ble_evt, p_ble_evt->header.evt_id = 18
[2020-01-17 11:36:51] Debug : RESP_OK => nrf_ble_qwr_on_ble_evt, p_ble_evt->header.evt_id = 18
[2020-01-17 11:36:55] Debug : RESP_OK => nrf_ble_qwr_on_ble_evt, p_ble_evt->header.evt_id = 18
[2020-01-17 11:37:07] Debug : RESP_OK => nrf_ble_qwr_on_ble_evt, p_ble_evt->header.evt_id = 81
[2020-01-17 11:37:07] Debug : RESP_OK => BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST
[2020-01-17 11:37:07] Debug : RESP_OK => on_rw_authorize_request, p_auth_req->request.write.op = 0x1
[2020-01-17 11:37:07] Debug : RESP_OK => nrf_ble_qwrs_on_qwr_evt, p_evt->evt_type = 2
[2020-01-17 11:37:07] Debug : RESP_OK => BLE_QWRS_NEW_DATA_RCVD
[2020-01-17 11:37:07] Debug : RESP_OK => 31323334353637383930313233
2). write 14 Bytes, result: NG
My application not show any evt in nrf_ble_qwr_on_ble_evt fuction, I guess while handle 14 Bytes data write request in softdevice has exception.
Please Nordic help to provide me the way to do next debug
[Attached files]
sdk_config.h (#define NRF_BLE_QWR_ENABLED 1 #define NRF_BLE_QWR_MAX_ATTR 1)
nrf_ble_qwr.c
nrf_ble_qwr.h
nrf_ble_qwrs.c
nrf_ble_qwrs.h
ble_wrap_15.c (my application)
Many thanks.
Caspar
nRF Connect, 2020-01-17 SONY_BLE (E6:E7:6E:CF:B4:C1) I 11:36:46.645 [Server] Server started V 11:36:46.669 Heart Rate (0x180D) - Heart Rate Measurement [N] (0x2A37) Client Characteristic Configuration (0x2902) - Body Sensor Location [R] (0x2A38) - Heart Rate Control Point [W] (0x2A39) Unknown Service (00003802-0000-1000-8000-00805f9b34fb) - Unknown Characteristic [I N R W] (00004a02-0000-1000-8000-00805f9b34fb) Client Characteristic Configuration (0x2902) Unknown Descriptor (0000aab0-0000-1000-8000-aabbccddeeff) Characteristic Presentation Format (0x2904) - Unknown Characteristic [I R W WNR] (0000aaa2-0000-1000-8000-aabbccddeeff) Client Characteristic Configuration (0x2902) User Data (0x181C) - First Name [R W] (0x2A8A) - Last Name [R W] (0x2A90) - Gender [R W] (0x2A8C) Current Time Service (0x1805) - Current Time [N R] (0x2A2B) Client Characteristic Configuration (0x2902) - Local Time Information [R] (0x2A0F) V 11:36:47.020 Connecting to E6:E7:6E:CF:B4:C1... D 11:36:47.021 gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M) D 11:36:48.538 [Server callback] Connection state changed with status: 0 and new state: CONNECTED (2) I 11:36:48.538 [Server] Device with address E6:E7:6E:CF:B4:C1 connected D 11:36:48.544 [Callback] Connection state changed with status: 0 and new state: CONNECTED (2) I 11:36:48.544 Connected to E6:E7:6E:CF:B4:C1 D 11:36:48.578 [Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED V 11:36:48.578 Discovering services... D 11:36:48.578 gatt.discoverServices() I 11:36:48.988 Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms) D 11:36:49.124 [Callback] Services discovered with status: 0 I 11:36:49.124 Services discovered V 11:36:49.130 Generic Access (0x1800) - Device Name [R W] (0x2A00) - Appearance [R] (0x2A01) - Peripheral Preferred Connection Parameters [R] (0x2A04) - Central Address Resolution [R] (0x2AA6) Generic Attribute (0x1801) Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e) - RX Characteristic [N R W] (6e400002-b5a3-f393-e0a9-e50e24dcca9e) Client Characteristic Configuration (0x2902) D 11:36:49.130 gatt.setCharacteristicNotification(6e400002-b5a3-f393-e0a9-e50e24dcca9e, true) I 11:36:49.211 Connection parameters updated (interval: 45.0ms, latency: 0, timeout: 5000ms) I 11:36:53.218 Connection parameters updated (interval: 195.0ms, latency: 0, timeout: 4000ms) V 11:37:05.688 Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e D 11:37:05.688 gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x31323334353637383930313233) I 11:37:06.088 Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 31-32-33-34-35-36-37-38-39-30-31-32-33, "1234567890123" A 11:37:06.088 "1234567890123" sent V 11:37:28.334 Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e D 11:37:28.334 gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x3132333435363738393031323334) D 11:37:32.522 [Server callback] Connection state changed with status: 0 and new state: DISCONNECTED (0) I 11:37:32.522 [Server] Device disconnected E 11:37:32.538 Error 133 (0x85): GATT ERROR D 11:37:32.539 [Callback] Connection state changed with status: 8 and new state: DISCONNECTED (0) E 11:37:32.552 Error 8 (0x8): GATT CONN TIMEOUT I 11:37:32.553 Disconnected D 11:37:32.568 [Broadcast] Action received: android.bluetooth.device.action.ACL_DISCONNECTED
/** * Copyright (c) 2016 - 2019, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "sdk_common.h" #if NRF_MODULE_ENABLED(NRF_BLE_QWR) #include <stdlib.h> #include "nrf_ble_qwr.h" #include "ble.h" #include "ble_srv_common.h" #define NRF_BLE_QWR_INITIALIZED 0xDE // Non-zero value used to make sure the given structure has been initialized by the module. #define MODULE_INITIALIZED (p_qwr->initialized == NRF_BLE_QWR_INITIALIZED) #include "sdk_macros.h" #include <stdio.h> // Response output macros #define RESP(_form, ...) do { printf(_form "\n", ##__VA_ARGS__); } while(0) #define RESP_ASYNC(form, ...) RESP("#" form, ##__VA_ARGS__) #define RESP_ERROR(form, ...) RESP("*" form, ##__VA_ARGS__) #define RESP_OK(form, ...) RESP("=" form, ##__VA_ARGS__) ret_code_t nrf_ble_qwr_init(nrf_ble_qwr_t * p_qwr, nrf_ble_qwr_init_t const * p_qwr_init) { VERIFY_PARAM_NOT_NULL(p_qwr); VERIFY_PARAM_NOT_NULL(p_qwr_init); if (MODULE_INITIALIZED) { return NRF_ERROR_INVALID_STATE; } p_qwr->error_handler = p_qwr_init->error_handler; p_qwr->initialized = NRF_BLE_QWR_INITIALIZED; p_qwr->conn_handle = BLE_CONN_HANDLE_INVALID; #if (NRF_BLE_QWR_MAX_ATTR > 0) memset(p_qwr->attr_handles, 0, sizeof(p_qwr->attr_handles)); p_qwr->nb_registered_attr = 0; p_qwr->is_user_mem_reply_pending = false; p_qwr->mem_buffer = p_qwr_init->mem_buffer; p_qwr->callback = p_qwr_init->callback; p_qwr->nb_written_handles = 0; #endif return NRF_SUCCESS; } #if (NRF_BLE_QWR_MAX_ATTR > 0) ret_code_t nrf_ble_qwr_attr_register(nrf_ble_qwr_t * p_qwr, uint16_t attr_handle) { VERIFY_PARAM_NOT_NULL(p_qwr); VERIFY_MODULE_INITIALIZED(); if ((p_qwr->nb_registered_attr == NRF_BLE_QWR_MAX_ATTR) || (p_qwr->mem_buffer.p_mem == NULL) || (p_qwr->mem_buffer.len == 0)) { return (NRF_ERROR_NO_MEM); } if (attr_handle == BLE_GATT_HANDLE_INVALID) { return NRF_ERROR_INVALID_PARAM; } p_qwr->attr_handles[p_qwr->nb_registered_attr] = attr_handle; p_qwr->nb_registered_attr++; return NRF_SUCCESS; } ret_code_t nrf_ble_qwr_value_get(nrf_ble_qwr_t * p_qwr, uint16_t attr_handle, uint8_t * p_mem, uint16_t * p_len) { VERIFY_PARAM_NOT_NULL(p_qwr); VERIFY_PARAM_NOT_NULL(p_mem); VERIFY_PARAM_NOT_NULL(p_len); VERIFY_MODULE_INITIALIZED(); uint16_t i = 0; uint16_t handle = BLE_GATT_HANDLE_INVALID; uint16_t val_len = 0; uint16_t val_offset = 0; uint16_t cur_len = 0; do { handle = uint16_decode(&(p_qwr->mem_buffer.p_mem[i])); if (handle == BLE_GATT_HANDLE_INVALID) { break; } i += sizeof(uint16_t); val_offset = uint16_decode(&(p_qwr->mem_buffer.p_mem[i])); i += sizeof(uint16_t); val_len = uint16_decode(&(p_qwr->mem_buffer.p_mem[i])); i += sizeof(uint16_t); if (handle == attr_handle) { cur_len = val_offset + val_len; if (cur_len <= *p_len) { memcpy((p_mem + val_offset), &(p_qwr->mem_buffer.p_mem[i]), val_len); } else { return NRF_ERROR_NO_MEM; } } i += val_len; } while (i < p_qwr->mem_buffer.len); *p_len = cur_len; return NRF_SUCCESS; } #endif ret_code_t nrf_ble_qwr_conn_handle_assign(nrf_ble_qwr_t * p_qwr, uint16_t conn_handle) { VERIFY_PARAM_NOT_NULL(p_qwr); VERIFY_MODULE_INITIALIZED(); p_qwr->conn_handle = conn_handle; return NRF_SUCCESS; } /**@brief checks if a user_mem_reply is pending, if so attempts to send it. * * @param[in] p_qwr QWR structure. */ static void user_mem_reply(nrf_ble_qwr_t * p_qwr) { if (p_qwr->is_user_mem_reply_pending) { ret_code_t err_code; #if (NRF_BLE_QWR_MAX_ATTR == 0) err_code = sd_ble_user_mem_reply(p_qwr->conn_handle, NULL); #else err_code = sd_ble_user_mem_reply(p_qwr->conn_handle, &p_qwr->mem_buffer); #endif if (err_code == NRF_SUCCESS) { p_qwr->is_user_mem_reply_pending = false; } else if (err_code == NRF_ERROR_BUSY) { p_qwr->is_user_mem_reply_pending = true; } else { p_qwr->error_handler(err_code); } } } /**@brief Handle a user memory request event. * * @param[in] p_qwr QWR structure. * @param[in] p_common_evt User_mem_request event to be handled. */ static void on_user_mem_request(nrf_ble_qwr_t * p_qwr, ble_common_evt_t const * p_common_evt) { if ((p_common_evt->params.user_mem_request.type == BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES) && (p_common_evt->conn_handle == p_qwr->conn_handle)) { p_qwr->is_user_mem_reply_pending = true; user_mem_reply(p_qwr); } } /**@brief Handle a user memory release event. * * @param[in] p_qwr QWR structure. * @param[in] p_common_evt User_mem_release event to be handled. */ static void on_user_mem_release(nrf_ble_qwr_t * p_qwr, ble_common_evt_t const * p_common_evt) { #if (NRF_BLE_QWR_MAX_ATTR > 0) if ((p_common_evt->params.user_mem_release.type == BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES) && (p_common_evt->conn_handle == p_qwr->conn_handle)) { // Cancel the current operation. p_qwr->nb_written_handles = 0; } #endif } #if (NRF_BLE_QWR_MAX_ATTR > 0) /**@brief Handle a prepare write event. * * @param[in] p_qwr QWR structure. * @param[in] p_evt_write WRITE event to be handled. */ static void on_prepare_write(nrf_ble_qwr_t * p_qwr, ble_gatts_evt_write_t const * p_evt_write) { uint32_t err_code; ble_gatts_rw_authorize_reply_params_t auth_reply; memset(&auth_reply, 0, sizeof(auth_reply)); auth_reply.params.write.gatt_status = NRF_BLE_QWR_REJ_REQUEST_ERR_CODE; auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; uint32_t i; for (i = 0; i < p_qwr->nb_written_handles; i++) { if (p_qwr->written_attr_handles[i] == p_evt_write->handle) { auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; break; } } if (auth_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS) { for (i = 0; i < p_qwr->nb_registered_attr; i++) { if (p_qwr->attr_handles[i] == p_evt_write->handle) { auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; p_qwr->written_attr_handles[p_qwr->nb_written_handles++] = p_evt_write->handle; break; } } } err_code = sd_ble_gatts_rw_authorize_reply(p_qwr->conn_handle, &auth_reply); if (err_code != NRF_SUCCESS) { // Cancel the current operation. p_qwr->nb_written_handles = 0; // Report error to application. p_qwr->error_handler(err_code); } } /**@brief Handle an execute write event. * * @param[in] p_qwr QWR structure. * @param[in] p_evt_write EXEC WRITE event to be handled. */ static void on_execute_write(nrf_ble_qwr_t * p_qwr, ble_gatts_evt_write_t const * p_evt_write) { uint32_t err_code; ble_gatts_rw_authorize_reply_params_t auth_reply; memset(&auth_reply, 0, sizeof(auth_reply)); auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; if (p_qwr->nb_written_handles == 0) { auth_reply.params.write.gatt_status = NRF_BLE_QWR_REJ_REQUEST_ERR_CODE; err_code = sd_ble_gatts_rw_authorize_reply(p_qwr->conn_handle, &auth_reply); if (err_code != NRF_SUCCESS) { // Report error to application. p_qwr->error_handler(err_code); } return; } for (uint16_t i = 0; i < p_qwr->nb_written_handles; i++) { nrf_ble_qwr_evt_t evt; uint16_t ret_val; evt.evt_type = NRF_BLE_QWR_EVT_AUTH_REQUEST; evt.attr_handle = p_qwr->written_attr_handles[i]; ret_val = p_qwr->callback(p_qwr, &evt); if (ret_val != BLE_GATT_STATUS_SUCCESS) { auth_reply.params.write.gatt_status = ret_val; } } err_code = sd_ble_gatts_rw_authorize_reply(p_qwr->conn_handle, &auth_reply); if (err_code != NRF_SUCCESS) { // Report error to application. p_qwr->error_handler(err_code); } // If the execute has not been rejected by any of the registered applications, propagate execute write event to all written handles. */ if (auth_reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) { for (uint16_t i = 0; i < p_qwr->nb_written_handles; i++) { nrf_ble_qwr_evt_t evt; evt.evt_type = NRF_BLE_QWR_EVT_EXECUTE_WRITE; evt.attr_handle = p_qwr->written_attr_handles[i]; /*lint -e534 -save "Ignoring return value of function" */ p_qwr->callback(p_qwr, &evt); /*lint -restore*/ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; } } p_qwr->nb_written_handles = 0; } /**@brief Handle a cancel write event. * * @param[in] p_qwr QWR structure. * @param[in] p_evt_write EXEC WRITE event to be handled. */ static void on_cancel_write(nrf_ble_qwr_t * p_qwr, ble_gatts_evt_write_t const * p_evt_write) { uint32_t err_code; ble_gatts_rw_authorize_reply_params_t auth_reply; memset(&auth_reply, 0, sizeof(auth_reply)); auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; err_code = sd_ble_gatts_rw_authorize_reply(p_qwr->conn_handle, &auth_reply); if (err_code != NRF_SUCCESS) { // Report error to application. p_qwr->error_handler(err_code); } p_qwr->nb_written_handles = 0; } #endif /**@brief Handle a rw_authorize_request event. * * @param[in] p_qwr QWR structure. * @param[in] p_gatts_evt RW_authorize_request event to be handled. */ static void on_rw_authorize_request(nrf_ble_qwr_t * p_qwr, ble_gatts_evt_t const * p_gatts_evt) { if (p_gatts_evt->conn_handle != p_qwr->conn_handle) { return; } ble_gatts_evt_rw_authorize_request_t const * p_auth_req = &p_gatts_evt->params.authorize_request; if (p_auth_req->type != BLE_GATTS_AUTHORIZE_TYPE_WRITE) { return; } #if (NRF_BLE_QWR_MAX_ATTR == 0) // Handle only queued write related operations. if ((p_auth_req->request.write.op != BLE_GATTS_OP_PREP_WRITE_REQ) && (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) && (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) { return; } // Prepare the response. ble_gatts_rw_authorize_reply_params_t auth_reply = {0}; auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; auth_reply.params.write.gatt_status = NRF_BLE_QWR_REJ_REQUEST_ERR_CODE; if (p_auth_req->request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL) { auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; } ret_code_t err_code = sd_ble_gatts_rw_authorize_reply(p_gatts_evt->conn_handle, &auth_reply); if (err_code != NRF_SUCCESS) { // Report error to application. p_qwr->error_handler(err_code); } #else ble_gatts_rw_authorize_reply_params_t auth_reply = {0}; nrf_ble_qwr_evt_t evt; RESP_OK("%s, p_auth_req->request.write.op = 0x%x", __func__, p_auth_req->request.write.op); switch (p_auth_req->request.write.op) { case BLE_GATTS_OP_WRITE_REQ: auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; auth_reply.params.write.update = 1; auth_reply.params.write.p_data = p_auth_req->request.write.data; auth_reply.params.write.len = p_auth_req->request.write.len; ret_code_t err_code = sd_ble_gatts_rw_authorize_reply(p_qwr->conn_handle,&auth_reply); if (err_code != NRF_SUCCESS) { // Report error to application. p_qwr->error_handler(err_code); } evt.evt_type = NRF_BLE_QWR_EVT_WRITE; evt.attr_handle = p_gatts_evt->params.authorize_request.request.write.handle; evt.write_len = p_auth_req->request.write.len; p_qwr->callback(p_qwr, &evt); break; case BLE_GATTS_OP_PREP_WRITE_REQ: on_prepare_write(p_qwr, &p_auth_req->request.write); break; // BLE_GATTS_OP_PREP_WRITE_REQ case BLE_GATTS_OP_EXEC_WRITE_REQ_NOW: on_execute_write(p_qwr, &p_auth_req->request.write); break; // BLE_GATTS_OP_EXEC_WRITE_REQ_NOW case BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL: on_cancel_write(p_qwr, &p_auth_req->request.write); break; // BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL default: // No implementation needed. break; } #endif } void nrf_ble_qwr_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context) { RESP_OK("%s", __func__); VERIFY_PARAM_NOT_NULL_VOID(p_context); VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt); RESP_OK("%s, p_ble_evt->header.evt_id = %d", __func__, p_ble_evt->header.evt_id); nrf_ble_qwr_t * p_qwr = (nrf_ble_qwr_t *)p_context; VERIFY_MODULE_INITIALIZED_VOID(); if (p_ble_evt->evt.common_evt.conn_handle == p_qwr->conn_handle) { user_mem_reply(p_qwr); } switch (p_ble_evt->header.evt_id) { case BLE_EVT_USER_MEM_REQUEST: RESP_OK("BLE_EVT_USER_MEM_REQUEST"); on_user_mem_request(p_qwr, &p_ble_evt->evt.common_evt); break; // BLE_EVT_USER_MEM_REQUEST case BLE_EVT_USER_MEM_RELEASE: RESP_OK("BLE_EVT_USER_MEM_RELEASE"); on_user_mem_release(p_qwr, &p_ble_evt->evt.common_evt); break; // BLE_EVT_USER_MEM_REQUEST case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: RESP_OK("BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST"); on_rw_authorize_request(p_qwr, &p_ble_evt->evt.gatts_evt); break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST case BLE_GAP_EVT_DISCONNECTED: if (p_ble_evt->evt.gap_evt.conn_handle == p_qwr->conn_handle) { p_qwr->conn_handle = BLE_CONN_HANDLE_INVALID; #if (NRF_BLE_QWR_MAX_ATTR > 0) p_qwr->nb_written_handles = 0; #endif } break; // BLE_GAP_EVT_DISCONNECTED default: break; } } #endif // NRF_MODULE_ENABLED(NRF_BLE_QWR)
/** * Copyright (c) 2016 - 2019, 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 "nrf_ble_qwrs.h" #include <string.h> #include "ble_srv_common.h" #include "nrf_ble_qwr.h" #define NRF_LOG_MODULE_NAME BLE_QWRS #include "nrf_log.h" NRF_LOG_MODULE_REGISTER(); #define BLE_UUID_QWRS_SERVICE 0x0001 /**< The UUID of the QWRS Service. */ #define BLE_UUID_QWRS_LONG_CHARACTERISTIC 0x0002 /**< The UUID of the QWRS Long Characteristic. */ #define BLE_QWRS_MAX_LONG_CHAR_LEN NRF_BLE_QWRS_MAX_RCV_SIZE /**< Maximum length of the QWRS Long Characteristic (in bytes). */ #define BLE_QWRS_MAX_CHAR_LEN 20 /**< Maximum length of the QWRS Characteristic (in bytes). */ #define QWRS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */ // Response output macros #define RESP(_form, ...) do { printf(_form "\n", ##__VA_ARGS__); } while(0) #define RESP_ASYNC(form, ...) RESP("#" form, ##__VA_ARGS__) #define RESP_ERROR(form, ...) RESP("*" form, ##__VA_ARGS__) #define RESP_OK(form, ...) RESP("=" form, ##__VA_ARGS__) uint16_t nrf_ble_qwrs_on_qwr_evt(nrf_ble_qwrs_t *p_qwrs, nrf_ble_qwr_t * p_qwr, nrf_ble_qwr_evt_t * p_evt) { RESP_OK("%s, p_evt->evt_type = %d", __func__, p_evt->evt_type); if (p_qwrs->evt_handler != NULL) { nrf_ble_qwrs_evt_t cur_evt; ret_code_t err_code; if(p_evt->evt_type == NRF_BLE_QWR_EVT_WRITE) { uint8_t recv_data[BLE_QWRS_MAX_CHAR_LEN]; memset(recv_data,0,BLE_QWRS_MAX_CHAR_LEN); ble_gatts_value_t gatt_value = {0}; gatt_value.p_value = recv_data; gatt_value.len = p_evt->write_len; err_code = sd_ble_gatts_value_get(p_qwr->conn_handle,p_evt->attr_handle,&gatt_value); if (err_code == NRF_SUCCESS) { cur_evt.evt_type = BLE_QWRS_NEW_DATA_RCVD; memcpy(&cur_evt.rcvd_data, recv_data, p_evt->write_len); cur_evt.rcv_length = p_evt->write_len; return p_qwrs->evt_handler(p_qwrs, &(cur_evt)); } else { RESP_ERROR("%s, sd_ble_gatts_value_get failed.", __func__); } } else { cur_evt.rcv_length = NRF_BLE_QWRS_MAX_RCV_SIZE; err_code = nrf_ble_qwr_value_get(p_qwr, p_evt->attr_handle, cur_evt.rcvd_data, &cur_evt.rcv_length); if (err_code != NRF_SUCCESS) { RESP_ERROR("%s, nrf_ble_qwr_value_get failed.", __func__); return BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION; } if (p_evt->evt_type == NRF_BLE_QWR_EVT_AUTH_REQUEST) { cur_evt.evt_type = BLE_QWRS_CHECK_RCVD_DATA; return p_qwrs->evt_handler(p_qwrs, &(cur_evt)); } else if (p_evt->evt_type == NRF_BLE_QWR_EVT_EXECUTE_WRITE) { if (p_qwrs->evt_handler != NULL) { cur_evt.evt_type = BLE_QWRS_NEW_DATA_RCVD; return p_qwrs->evt_handler(p_qwrs, &(cur_evt)); } } } } return BLE_GATT_STATUS_SUCCESS; } uint32_t nrf_ble_qwrs_init(nrf_ble_qwrs_init_t *p_qwrs_init, nrf_ble_qwrs_t *p_qwrs) { ret_code_t err_code; ble_uuid_t ble_uuid; // Initialize service structure. p_qwrs->evt_handler = p_qwrs_init->evt_handler; p_qwrs->error_handler = p_qwrs_init->error_handler; p_qwrs->conn_handle = BLE_CONN_HANDLE_INVALID; // Add service. ble_uuid128_t base_uuid = QWRS_BASE_UUID; err_code = sd_ble_uuid_vs_add(&base_uuid, &p_qwrs->uuid_type); RESP_OK("%s, sd_ble_uuid_vs_add, err_code = %lu", __func__, err_code); VERIFY_SUCCESS(err_code); ble_uuid.type = p_qwrs->uuid_type; ble_uuid.uuid = BLE_UUID_QWRS_SERVICE; err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_qwrs->service_handle); RESP_OK("%s, sd_ble_gatts_service_add, err_code = %lu", __func__, err_code); VERIFY_SUCCESS(err_code); //Add Long characteristic ble_add_char_params_t add_char_params; memset(&add_char_params, 0, sizeof(add_char_params)); add_char_params.uuid = BLE_UUID_QWRS_LONG_CHARACTERISTIC; add_char_params.uuid_type = p_qwrs->uuid_type; add_char_params.max_len = BLE_QWRS_MAX_LONG_CHAR_LEN; add_char_params.init_len = 0; add_char_params.char_props.write = true; add_char_params.char_props.read = true; add_char_params.char_props.notify= true; add_char_params.cccd_write_access= true; add_char_params.read_access = SEC_OPEN; add_char_params.write_access = SEC_OPEN; add_char_params.is_defered_read = true; add_char_params.is_defered_write = true; err_code = characteristic_add(p_qwrs->service_handle, &add_char_params, &p_qwrs->long_charact_handles); RESP_OK("%s, characteristic_add, err_code = %lu", __func__, err_code); VERIFY_SUCCESS(err_code); if (p_qwrs_init->p_qwr_ctx != NULL) { err_code = nrf_ble_qwr_attr_register(p_qwrs_init->p_qwr_ctx, p_qwrs->long_charact_handles.value_handle); RESP_OK("%s, nrf_ble_qwr_attr_register, err_code = %lu", __func__, err_code); VERIFY_SUCCESS(err_code); } return err_code; }
/** * Copyright (c) 2014 - 2017, 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, O * 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 <utils.h> // ============================= ble_app_queued_writes ============================= #include "nrf_ble_qwr.h" #include "nrf_ble_qwrs.h" // ============================= ble_app_queued_writes ============================= #define APP_FEATURE_NOT_SUPPORTED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2 /**< Reply when unsupported features are requested. */ #define APP_BLE_OBSERVER_PRIO 1 /**< Application's BLE observer priority. You shouldn't need to modify this value. */ #define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */ #define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000) /**< Time from initiating event (connect or start of notification) to 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 /**< Number of attempts before giving up the connection parameter negotiation. */ #define CONFIG_BLUETOOTH_LE_NAME "BLE-CLASSIC" #define SEND_DISCOVERY_RESULT_DELAY APP_TIMER_TICKS(10000) /**< Discovery notification delay time. */ #define APP_ADV_INTERVAL 300 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 187.5 ms). */ #define APP_ADV_DURATION 18000 /**< The advertising duration (180 seconds) in units of 10 milliseconds. */ // ============================= ble_app_queued_writes ============================= #define MEM_BUFF_SIZE 512 // ============================= ble_app_queued_writes ============================= // Global variables //#define BLE_WRAP_NO_NUS 1 //CEI // ============================= ble_app_queued_writes ============================= NRF_BLE_QWR_DEF(m_qwr); /**< Queued Writes structure.*/ // ============================= ble_app_queued_writes ============================= NRF_BLE_GATT_DEF(m_gatt); /** GATT module instance*/ BLE_ADVERTISING_DEF(m_advertising); /** Advertising module instance*/ #ifndef BLE_WRAP_NO_NUS BLE_NUS_DEF(m_nus, NRF_SDH_BLE_TOTAL_LINK_COUNT); /** Structure to identify the Nordic UART Service*/ #endif #define IS_CENTRAL (m_ble_role == eBLE_Central) // Response output macros #define RESP(_form, ...) do { printf(_form "\n", ##__VA_ARGS__); } while(0) #define RESP_ASYNC(form, ...) RESP("#" form, ##__VA_ARGS__) #define RESP_ERROR(form, ...) RESP("*" form, ##__VA_ARGS__) #define RESP_OK(form, ...) RESP("=" form, ##__VA_ARGS__) // ============================= Code copied from Nordic template ============================= extern uint8_t m_enc_advdata[]; extern uint8_t m_adv_handle; extern ble_gap_adv_data_t m_adv_data; extern ble_gap_adv_params_t m_adv_params; extern ble_gap_scan_params_t m_scan_params; extern ble_gap_conn_params_t m_connection_param; // ============================= ble_app_queued_writes, Start ============================= static uint8_t m_buffer[MEM_BUFF_SIZE]; static nrf_ble_qwrs_t m_qwrs; // ============================= ble_app_queued_writes, End ============================= static char const m_target_periph_name[] = "GATTTool"; /**< Name of the device we try to connect to. This name is searched in the scan report data*/ //Todo 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); break; default: break; } } //From v15 nrf_ble_scan static void scan_init(void) { ret_code_t err_code; nrf_ble_scan_init_t init_scan; memset(&init_scan, 0, sizeof(init_scan)); init_scan.connect_if_match = true; init_scan.conn_cfg_tag = BLE_CONN_CFG_TAG_DEFAULT;//APP_BLE_CONN_CFG_TAG; init_scan.p_scan_param = &m_scan_params; init_scan.p_conn_param = &m_connection_param; err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler); APP_ERROR_CHECK(err_code); // Setting filters for scanning. 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_NAME_FILTER, m_target_periph_name); APP_ERROR_CHECK(err_code); } // ================================================================================= // ============================= Code copied from Nordic template ============================= /**@brief Function for handling Peer Manager events. * * @param[in] p_evt Peer Manager event. */ __WEAK void pm_evt_handler(pm_evt_t const * p_evt) { ret_code_t err_code; switch (p_evt->evt_id) { case PM_EVT_BONDED_PEER_CONNECTED: { NRF_LOG_INFO("Connected to a previously bonded device."); } break; case PM_EVT_CONN_SEC_SUCCEEDED: { NRF_LOG_INFO("Connection secured: role: %d, conn_handle: 0x%x, procedure: %d.", ble_conn_state_role(p_evt->conn_handle), p_evt->conn_handle, p_evt->params.conn_sec_succeeded.procedure); } break; case PM_EVT_CONN_SEC_FAILED: { /* Often, when securing fails, it shouldn't be restarted, for security reasons. * Other times, it can be restarted directly. * Sometimes it can be restarted, but only after changing some Security Parameters. * Sometimes, it cannot be restarted until the link is disconnected and reconnected. * Sometimes it is impossible, to secure the link, or the peer device does not support it. * How to handle this error is highly application dependent. */ } break; case PM_EVT_CONN_SEC_CONFIG_REQ: { // Reject pairing request from an already bonded peer. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false}; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); } break; case PM_EVT_STORAGE_FULL: { // Run garbage collection on the flash. err_code = fds_gc(); if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) { // Retry. } else { APP_ERROR_CHECK(err_code); } } break; case PM_EVT_PEERS_DELETE_SUCCEEDED: { //advertising_start(false); } break; case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED: { // The local database has likely changed, send service changed indications. pm_local_database_has_changed(); } break; case PM_EVT_PEER_DATA_UPDATE_FAILED: { // Assert. APP_ERROR_CHECK(p_evt->params.peer_data_update_failed.error); } break; case PM_EVT_PEER_DELETE_FAILED: { // Assert. APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error); } break; case PM_EVT_PEERS_DELETE_FAILED: { // Assert. APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error); } break; case PM_EVT_ERROR_UNEXPECTED: { // Assert. APP_ERROR_CHECK(p_evt->params.error_unexpected.error); } break; case PM_EVT_CONN_SEC_START: case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: case PM_EVT_PEER_DELETE_SUCCEEDED: case PM_EVT_LOCAL_DB_CACHE_APPLIED: case PM_EVT_SERVICE_CHANGED_IND_SENT: case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED: default: break; } } /**@brief Function for the Timer initialization. * * @details Initializes the timer module. This creates and starts application timers. */ __WEAK void timers_init(void) { // Initialize timer module. ret_code_t err_code = app_timer_init(); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the GATT module. */ static void gatt_init(void) { ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL); //RESP_OK("%s, error_code = %ld", __func__, err_code); APP_ERROR_CHECK(err_code); } #ifndef BLE_WRAP_NO_NUS __WEAK void nus_string_received(const char *str) { } /**@brief Function for handling the data from the Nordic UART Service. * * @details This function will process the data received from the Nordic UART BLE Service and send * it to the UART module. * * @param[in] p_nus Nordic UART Service structure. * @param[in] p_data Data to be send to UART module. * @param[in] length Length of the data. */ /**@snippet [Handling the data received over BLE] */ __WEAK void nus_data_handler(ble_nus_evt_t * p_evt) { if (p_evt->type == BLE_NUS_EVT_RX_DATA) { uint16_t length = MIN(sizeof(m_nus_input)-1, p_evt->params.rx_data.length); strncpy(m_nus_input, (char*)p_evt->params.rx_data.p_data, length); m_nus_input[length] = 0; if (strstr(m_nus_input, "DFUStart")) { // Catch this command here in case application doesn't call ble_wrap_handle_pending ble_wrap_enter_ota_mode(); } } } #endif // ============================= ble_app_queued_writes, Start ============================= /**@brief Function for handling Service errors. * * @details A pointer to this function will be passed to each service which may need to inform the * application about an error. * * @param[in] nrf_error Error code containing information about what went wrong. */ static void service_error_handler(uint32_t nrf_error) { APP_ERROR_HANDLER(nrf_error); } /**@brief Function for handling the Queued Write Example Service events. * * @details This function will be called for all Queued Write Example Service events which are passed to * the application. * * @param[in] p_qwrs Queued Write Example Service structure. * @param[in] p_evt Event received from the Queued Write Example Service. * */ static uint16_t queued_write_example_service_evt_handler(nrf_ble_qwrs_t * p_qwrs, nrf_ble_qwrs_evt_t * p_evt) { uint16_t ret_val = BLE_GATT_STATUS_SUCCESS; switch (p_evt->evt_type) { case BLE_QWRS_CHECK_RCVD_DATA: // This is where your application can check the received value before accepting the write. if (p_evt->rcvd_data[0] == 0) { RESP_ERROR("First byte is 0, reject the operation"); ret_val = BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION; } else { RESP_OK("First byte is not 0, accept the operation"); ret_val = BLE_GATT_STATUS_SUCCESS; } break;//BLE_QWRS_CHECK_RCVD_DATA case BLE_QWRS_NEW_DATA_RCVD: RESP_OK("BLE_QWRS_NEW_DATA_RCVD"); /** * Write Queued Characteristic with Less than 20 bytes * https://devzone.nordicsemi.com/f/nordic-q-a/37970/write-queued-characteristic-with-less-than-20-bytes/151680#151680 **/ if (p_evt->rcv_length > 0) { uint8_t buff[p_evt->rcv_length]; memset(buff, 0x00, p_evt->rcv_length); bytes_to_hex(p_evt->rcvd_data, p_evt->rcv_length, (char*)buff); RESP_OK("%s", buff); } // This is where the data is actually received and has been accepted. break;//BLE_QWRS_NEW_DATA_RCVD default: // No implementation needed. break; } return ret_val; } /**@brief Function for handling events from the Queued Write module. */ uint16_t queued_write_handler(nrf_ble_qwr_t * p_qwr, nrf_ble_qwr_evt_t * p_evt) { return nrf_ble_qwrs_on_qwr_evt(&m_qwrs, p_qwr, p_evt); } // ============================= ble_app_queued_writes, End ============================= /**@brief Function for initializing services that will be used by the application. */ __WEAK void services_init(void) { #ifndef BLE_WRAP_NO_NUS uint32_t err_code; ble_nus_init_t nus_init; memset(&nus_init, 0, sizeof(nus_init)); nus_init.data_handler = nus_data_handler; err_code = ble_nus_init(&m_nus, &nus_init); APP_ERROR_CHECK(err_code); #endif } // ============================= ble_app_queued_writes, Start ============================= /**@brief Function for initializing gatt services that will be used by the application. */ __WEAK ret_code_t gatt_services_init(void) { ret_code_t err_code; nrf_ble_qwr_init_t qwr_init; nrf_ble_qwrs_init_t qwrs_init; memset(&qwr_init,0x00,sizeof(qwr_init)); // Initialize Queued Write Module qwr_init.mem_buffer.len = MEM_BUFF_SIZE; qwr_init.mem_buffer.p_mem = m_buffer; qwr_init.error_handler = service_error_handler; qwr_init.callback = queued_write_handler; err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init); RESP_OK("%s, nrf_ble_qwr_init, err_code = %lu\n", __func__, err_code); //APP_ERROR_CHECK(err_code); //initialize the Queued Writes Example Service memset(&qwrs_init, 0, sizeof(qwrs_init)); qwrs_init.evt_handler = queued_write_example_service_evt_handler; qwrs_init.error_handler = service_error_handler; qwrs_init.p_qwr_ctx = &m_qwr; err_code = nrf_ble_qwrs_init(&qwrs_init, &m_qwrs); RESP_OK("%s, nrf_ble_qwrs_init, err_code = %lu\n", __func__, err_code); //APP_ERROR_CHECK(err_code); return err_code; } // ============================= ble_app_queued_writes, End ============================= /**@brief Function for initializing the Connection Parameters module. */ __WEAK void conn_params_init(void) { uint32_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_GATT_HANDLE_INVALID; cp_init.disconnect_on_fail = false; 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); } /**@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 = NRF_SUCCESS; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_DISCONNECTED: RESP_OK("Disconnected."); m_is_connected = false; m_conn_handle = BLE_CONN_HANDLE_INVALID; break; case BLE_GAP_EVT_CONNECTED: RESP_OK("Connected."); m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; m_is_connected = true; RESP_OK("%s, p_ble_evt->header.evt_id = %d, IS_CENTRAL = %d, m_conn_handle = %04X, p_ble_evt->evt.gap_evt.conn_handle = %04X", __func__, p_ble_evt->header.evt_id, IS_CENTRAL, m_conn_handle, p_ble_evt->evt.gap_evt.conn_handle); // ============================= ble_app_queued_writes, Start ============================= m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle); RESP_OK("%s, err_code = %lu", __func__, err_code); // ============================= ble_app_queued_writes, End ============================= #ifndef PERIPHERAL_ONLY #if 0 //CEI //not Start service discovery at this time, it should trigger by spresense/examples/bluetooth_le_central/bluetooth_le_central_main.c if (IS_CENTRAL) { // Start service discovery //APP_ERROR_CHECK(ble_db_discovery_start(&m_ble_db_discovery, p_ble_evt->evt.gap_evt.conn_handle)); memset(&m_ble_db_discovery, 0x00, sizeof(m_ble_db_discovery)); err_code = ble_db_discovery_start(&m_ble_db_discovery, p_ble_evt->evt.gap_evt.conn_handle); } #endif #endif break; #if defined(S132) case BLE_GAP_EVT_PHY_UPDATE_REQUEST: { RESP_OK("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; #endif case BLE_GATTC_EVT_TIMEOUT: // Disconnect on GATT Client timeout event. RESP_OK("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. RESP_OK("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; case BLE_EVT_USER_MEM_REQUEST: err_code = sd_ble_user_mem_reply(p_ble_evt->evt.gattc_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_GATTS_EVT_HVN_TX_COMPLETE: m_buffer_available = true; break; #ifndef PERIPHERAL_ONLY case BLE_GAP_EVT_ADV_REPORT: { ble_evt_t *p = (ble_evt_t*)p_ble_evt; ble_gap_evt_t *p_gap_evt = &p->evt.gap_evt; if (m_adv_report_cb) m_adv_report_cb(&p_gap_evt->params.adv_report); break; } #endif case BLE_GAP_EVT_TIMEOUT: { const ble_gap_evt_t *p_gap_evt = &p_ble_evt->evt.gap_evt; if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN) { RESP_ERROR("Scan timed out"); } else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { RESP_ERROR("Connection Request timed out"); } break; } default: // No implementation needed. break; } #ifndef PERIPHERAL_ONLY if (IS_CENTRAL) { ble_db_discovery_on_ble_evt(p_ble_evt, &m_ble_db_discovery); #ifndef BLE_WRAP_NO_NUS ble_nus_c_on_ble_evt(p_ble_evt, &m_ble_nus_c); #endif } #endif on_ble_evt((ble_evt_t*)p_ble_evt); } /**@brief Function for initializing the BLE stack. * * @details Initializes the SoftDevice and the BLE event interrupt. */ __WEAK void ble_stack_init() { 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); //RESP_OK("%s, nrf_sdh_ble_default_cfg_set() = %lX", __func__, err_code); // Enable BLE stack. err_code = nrf_sdh_ble_enable(&ram_start); APP_ERROR_CHECK(err_code); //RESP_OK("%s, nrf_sdh_ble_enable() = %lX", __func__, err_code); // Enabling and populating the DC/DC converter, err_code = sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE); //RESP_OK("%s, sd_power_dcdc_mode_set() = %lX", __func__, 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 the Peer Manager initialization. */ __WEAK void peer_manager_init(void) { ble_gap_sec_params_t sec_param; ret_code_t err_code; err_code = pm_init(); APP_ERROR_CHECK(err_code); memset(&sec_param, 0, sizeof(ble_gap_sec_params_t)); // Security parameters to be used for all security procedures. sec_param.bond = SEC_PARAM_BOND; sec_param.mitm = SEC_PARAM_MITM; sec_param.lesc = SEC_PARAM_LESC; sec_param.keypress = SEC_PARAM_KEYPRESS; sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES; sec_param.oob = SEC_PARAM_OOB; sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE; sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE; sec_param.kdist_own.enc = 1; sec_param.kdist_own.id = 1; sec_param.kdist_peer.enc = 1; sec_param.kdist_peer.id = 1; err_code = pm_sec_params_set(&sec_param); APP_ERROR_CHECK(err_code); err_code = pm_register(pm_evt_handler); APP_ERROR_CHECK(err_code); } /**@brief Clear bond information from persistent storage. */ static void delete_bonds(void) { ret_code_t err_code; NRF_LOG_INFO("Erase bonds!"); err_code = pm_peers_delete(); APP_ERROR_CHECK(err_code); } // ============================= End of Nordic template code ============================= void ble_wrap_erase_bonds() { delete_bonds(); } uint32_t _millis() { return (uint32_t)((uint64_t)NRF_RTC0->COUNTER*1000/APP_TIMER_CLOCK_FREQ); } __WEAK void ble_log_init() { static bool done = false; if (done) return; ret_code_t err_code = NRF_LOG_INIT(_millis); APP_ERROR_CHECK(err_code); NRF_LOG_DEFAULT_BACKENDS_INIT(); done = true; } #if !defined(PERIPHERAL_ONLY) && !defined(BLE_WRAP_NO_NUS) static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, const ble_nus_c_evt_t * p_ble_nus_evt) { uint32_t err_code; switch (p_ble_nus_evt->evt_type) { case BLE_NUS_C_EVT_DISCOVERY_COMPLETE: // UART service detected 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); LOG_DEBUG("Service detected"); if (m_nus_c_rx_cb) m_nus_c_rx_cb(NULL, 1); break; case BLE_NUS_C_EVT_NUS_TX_EVT: // UART response received if (m_nus_c_rx_cb) m_nus_c_rx_cb(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len); break; case BLE_NUS_C_EVT_DISCONNECTED: if (m_nus_c_rx_cb) m_nus_c_rx_cb(NULL, 0); break; } } static void nus_c_init(void) { ble_nus_c_init_t nus_c_init_t; nus_c_init_t.evt_handler = ble_nus_c_evt_handler; APP_ERROR_CHECK(ble_nus_c_init(&m_ble_nus_c, &nus_c_init_t)); } #endif #ifndef PERIPHERAL_ONLY __WEAK void discovery_handler(ble_db_discovery_evt_t *p_evt) {} static void db_disc_handler(ble_db_discovery_evt_t * p_evt) { #ifndef BLE_WRAP_NO_NUS ble_nus_c_on_db_disc_evt(&m_ble_nus_c, p_evt); #endif discovery_handler(p_evt); } #endif //-------------------------------------------------------------------------- void ble_wrap_init(const char *device_name) { if (strlen(device_name) == 0) m_ble_role = eBLE_Central; //printf("%s, %d\n", __func__, __LINE__); #ifndef PERIPHERAL_ONLY if (IS_CENTRAL) { APP_ERROR_CHECK(ble_db_discovery_init(db_disc_handler)); } #endif ble_log_init(); timers_init(); ble_stack_init(); gap_params_init(CONFIG_BLUETOOTH_LE_NAME); gatt_init(); services_init(); conn_params_init(); peer_manager_init(); scan_init(); #ifdef INCLUDE_BATT_MEAS init_battery_measurement(); #endif #if !defined(PERIPHERAL_ONLY) && !defined(BLE_WRAP_NO_NUS) if (IS_CENTRAL) { nus_c_init(); } #endif check_set_pub_mac_addr(); ble_gap_addr_t bt_addr; sd_ble_gap_addr_get(&bt_addr); LOG_INFO("Mac address: %s", ble_wrap_addr2str(&bt_addr)); RESP_OK("%s, bt_addr = %02X:%02X:%02X:%02X:%02X:%02X, m_ble_role = %02X", __func__, bt_addr.addr[5], bt_addr.addr[4], bt_addr.addr[3], bt_addr.addr[2], bt_addr.addr[1], bt_addr.addr[0], m_ble_role); //nrf_delay_ms(1000); } void ble_wrap_teardown() { m_is_connected = false; nrf_sdh_disable_request(); } static bool m_is_connectable = true; void ble_wrap_set_connectable(bool on) { m_is_connectable = on; } bool ble_wrap_advertise(uint16_t company_id, ble_advdata_name_type_t type, uint8_t *p_data, uint8_t size, uint32_t interval_ms, uint32_t timeout_s) { RESP_OK("%s, m_is_connected = %d, m_is_advertising = %d, interval_ms = %lu, m_is_connectable = %d", __func__, m_is_connected, m_is_advertising, interval_ms, m_is_connectable); if (m_is_connected) return false; if (m_is_advertising && sd_ble_gap_adv_stop(m_advertising.adv_handle) != NRF_SUCCESS) return false; if (!interval_ms) { m_is_advertising = false; return true; } if (m_is_connectable) { ble_advertising_init_t init; memset(&init, 0, sizeof(init)); init.advdata.name_type = type; init.advdata.include_appearance = true; // extra add, 2019/12/16 init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; ble_advdata_manuf_data_t manuf_specific_data; if (p_data != NULL) { manuf_specific_data.company_identifier = company_id; manuf_specific_data.data.p_data = p_data; manuf_specific_data.data.size = size; init.advdata.p_manuf_specific_data = &manuf_specific_data; } #ifdef ADVERTISE_SERVICE_UUIDS init.advdata.uuids_complete.uuid_cnt = SERVICE_UUID_CNT; init.advdata.uuids_complete.p_uuids = m_adv_uuids; #endif init.config.ble_adv_fast_enabled = true; init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;// MSEC_TO_UNITS(interval_ms, UNIT_0_625_MS); init.config.ble_adv_fast_timeout = APP_ADV_DURATION;// timeout_s; init.evt_handler = ble_wrap_on_adv_evt; APP_ERROR_CHECK(ble_advertising_init(&m_advertising, &init)); ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST); } else { static ble_gap_adv_params_t m_adv_params; ble_advdata_t advdata; memset(&advdata, 0, sizeof(advdata)); ble_advdata_manuf_data_t manuf_specific_data; if (p_data != NULL) { manuf_specific_data.company_identifier = company_id; manuf_specific_data.data.p_data = p_data; manuf_specific_data.data.size = size; advdata.p_manuf_specific_data = &manuf_specific_data; } advdata.name_type = type; advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; #if NRF_SDK_VERSION == 15 ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len); //APP_ERROR_CHECK(err_code); memset(&m_adv_params, 0, sizeof(m_adv_params)); m_adv_params.p_peer_addr = NULL; m_adv_params.filter_policy = BLE_GAP_ADV_FP_ANY; m_adv_params.interval = MSEC_TO_UNITS(interval_ms, UNIT_0_625_MS); m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED; m_adv_params.filter_policy = BLE_GAP_ADV_FP_ANY; m_adv_params.duration = timeout_s; sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params); sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG); #else ble_advdata_set(&advdata, NULL); memset(&m_adv_params, 0, sizeof(m_adv_params)); m_adv_params.p_peer_addr = NULL; m_adv_params.filter_policy = BLE_GAP_ADV_FP_ANY; m_adv_params.interval = MSEC_TO_UNITS(interval_ms, UNIT_0_625_MS); m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_NONCONN_IND; m_adv_params.fp = BLE_GAP_ADV_FP_ANY; m_adv_params.timeout = timeout_s; sd_ble_gap_adv_start(&m_adv_params, APP_BLE_CONN_CFG_TAG); #endif m_is_advertising = true; } // For now, api above return invalid state after first call... return true; } uint32_t ble_wrap_stop_advertise() { RESP_OK("%s, m_is_connected = %d, m_is_advertising = %d, m_is_connectable = %d, m_advertising.adv_handle = %X", __func__, m_is_connected, m_is_advertising, m_is_connectable, m_advertising.adv_handle); (void) sd_ble_gap_adv_stop(m_advertising.adv_handle); m_advertising.adv_modes_config.ble_adv_fast_timeout = 1;// timeout_s; ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST); return NRF_SUCCESS; }