This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Not able to write 14 Bytes into Queued Writes module

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

sdk_config.h

/**
 * 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)

nrf_ble_qwr.h

/**
 * 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;
}

nrf_ble_qwrs.h

/**
 * 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;
}

  • Hi Nordic,

    My application do gatt_services_init (ble_wrap_15.c) to init qwr, and qwrs.
    While nrf_connect write 14 Bytes data into qwr, nrf_connect got "[Server callback] Connection state changed with status: 0 and new state: DISCONNECTED (0)"

    Is there any methodology to understand why my application not able to handle 14 Bytes gatt write characteristics ?

    "Log 2020-01-17 11_37_48.txt" [nrf_connect android application log]
    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

    Many thanks.
    Caspar

  • Hi Nordic,
    Wireshark log "0117.pcapng"  attachedfor reference.
    [Wireshark log information]
    [Master Address: 73:e8:6b:a4:9e:9e (73:e8:6b:a4:9e:9e)] <- nrf_connect Android Application
    [Slave Address: e6:e7:6e:cf:b4:c1 (e6:e7:6e:cf:b4:c1)]  <- nrf52832 wtih my application

    1). Master writes 13 Bytes into Slave successfully
    [Write 13 Bytes][OK]
    2). Master not able to write 14 Bytes into Slave, and lost connection
    [Write 14 Bytes][NG]
    [0117.pcapng]
    Many thanks.
    Caspar
  • Hi,

    Your application most likely entered the APP_ERROR_CHECK() with an error code somewhere. You need to debug your application to find the function that returned the error-code, and what error-code that was returned. You should also enable RTT logging(set NRF_LOG_BACKEND_RTT_ENABLED to 1 in sdk_config.h, you might also need to set NRF_FPRINTF_FLAG_AUTOMATIC_CR_ON_LF_ENABLED to 0), and see if you get any output in J-Link RTT Viewer, or Debug Terminal if you are using SES IDE.

    Why are you using Queued write module for NUS? As mentioned in this post, queued writes only make sense if you want to synchronize writes to multiple characteristics, so that the change take effect simultaneously. If you just want to write to a long characteristic and have to split it over multiple writes, then you should write with offset instead. That is simpler and has less overhead.

  • Hi Sigurd,

    Currently, I just want to write a long characteristic in custom ble service.
    I found this for reference. Is https://github.com/bjornspockeli/custom_ble_service_example suitable to integrate  into my application ?
    Would you please give me a reference example code for integration ?

    Many thanks
    Caspar

  • Hi Nordic, 

    I use github.com/.../custom_ble_service_example in my application to act as peripheral-role, and it works.
    However, my application dose not able to connect other peripheral-role device, while my application do  sd_ble_gap_connect to peripheral device.
    1). Did you have any idea how many FLASH/RAM should increase while adding a vendor-specific UUID to the BLE stack results in the RAM requirement of the SoftDevice increasing, which we need to take into account ?
    2). Did you have any suggestion the way to debug sd_ble_gap_connect not able to connect peripheral problem ?

    Now, I'm trying to make RTT logging with J-Link RTT Viewer.

    Many thanks.
    Caspar

Related