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

Write Queued Characteristic with Less than 20 bytes

Good afternoon,

Following up my previous case, to which I got no reply, how can I use a queued write characteristic to write less than 20 bytes of data?

I'm using it to mainly write more than 20 bytes of data but when I write less than 20 bytes it just halts the application. How can I overcome it?

Thank you,

João

  • Hi João, 

    please find the QWR and QWRS source and header files with the necessary changes to receive less than 20bytes and propagating this to the application. The only changes in main.c should be the addition of NRF_LOG_HEXDUMP_INFO(&p_evt->rcvd_data,p_evt->rcv_length) to the BLE_QWRS_NEW_DATA_RCVD case in queued_write_example_service_evt_handler, i.e. 

         case BLE_QWRS_NEW_DATA_RCVD:
                NRF_LOG_INFO("BLE_QWRS_NEW_DATA_RCVD");
                NRF_LOG_HEXDUMP_INFO(&p_evt->rcvd_data,p_evt->rcv_length);
                // This is where the data is actually received and has been accepted.
                break;//BLE_QWRS_NEW_DATA_RCVD

    Attachments:

    /**
     * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    #include "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. */
    
    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)
    {
        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
                 {
    
                    NRF_LOG_ERROR("sd_ble_gatts_value_get failed.");
                 }
            }
            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)
                {
                    NRF_LOG_ERROR("nrf_ble_qwr_value_get failed.");
                    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);
        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);
        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.write_access     = SEC_OPEN;
        add_char_params.is_defered_write = true;
    
        err_code = characteristic_add(p_qwrs->service_handle,
                                  &add_char_params,
                                  &p_qwrs->long_charact_handles);
        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);
            VERIFY_SUCCESS(err_code);
        }
        return err_code;
    }
    
    nrf_ble_qwrs.hnrf_ble_qwr.h
    /**
     * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    #include "sdk_common.h"
    #if NRF_MODULE_ENABLED(NRF_BLE_QWR)
    #include <stdlib.h>
    #include "nrf_ble_qwr.h"
    #include "ble.h"
    #include "ble_srv_common.h"
    #include "nrf_log.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"
    
    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;
    
        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)
    {
        VERIFY_PARAM_NOT_NULL_VOID(p_context);
        VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
    
        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:
                NRF_LOG_INFO("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:
                NRF_LOG_INFO("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:
                NRF_LOG_INFO("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)
    

  • Hi Bjørn,

    Thank you for your reply.

    Just updated the QWR and QWRS files and now the queued write is working like a charm for less than 20bytes.

    As a last question, is there a way to write more than 510bytes to a characteristic, with QWR or by any other means?

    Thank you,

    João

  • Hi again Bjørn,

    For writing more than 510bytes to a characteristic I mean writing up to 1024bytes.

    Thank you again,

    João

  • Hi,

    Unfortunately, the Softdevice limits this:

    #define  BLE_GATTS_FIX_ATTR_LEN_MAX   (510)
     
    #define  BLE_GATTS_VAR_ATTR_LEN_MAX   (512)
  • Dear Runar,

    But is there any other means besides QWR to write more than 510bytes through a characteristic?

    Thank you,

    João

Related