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

Reading a characteristic does not generate a BLE event

Hi,

I think I have properly configured my application to authorize reads on characteristic, yet I do not see an event generated. I get write events, but I don't get read events. Can anyone see what I'm doing wrong, or not doing at all? Here are some code snippets from my application. 

I create custom services as follows:

ret_code_t ble_vpe_init(ble_vpe_t * p_vpe, ble_vpe_init_t * p_vpe_init)
{
    ret_code_t          err_code;
    ble_uuid_t          ble_uuid;
    ble_uuid128_t       vpe_base_uuid = VECTOR_PUMP_BASE_UUID;

    VERIFY_PARAM_NOT_NULL(p_vpe);
    VERIFY_PARAM_NOT_NULL(p_vpe_init);

    /**@snippet [Adding proprietary Service to the SoftDevice] */
    // Add a custom base UUID.
    err_code = sd_ble_uuid_vs_add(&vpe_base_uuid, &p_vpe->uuid_type);
    VERIFY_SUCCESS(err_code);

    ble_uuid.type = p_vpe->uuid_type;
    ble_uuid.uuid = BLE_UUID_VECTOR_PUMP;

    // Add service
    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                            &ble_uuid,
                            &p_vpe->service_handle);
    VERIFY_SUCCESS(err_code);

    // Add the characteristics
    err_code = vpe_command_char_add(p_vpe);

    return err_code;
}

I add the custom characteristic to the service as follows:

static ret_code_t vpe_command_char_add(ble_vpe_t *p_vpe)
{
    ret_code_t              err_code;
    uint8_t                 init_value = 0;
    ble_uuid_t              char_uuid;
    ble_uuid128_t           base_uuid = COMMAND_BASE_UUID;
    ble_add_char_user_desc_t user_desc;
    ble_gatts_attr_md_t     attr_md;
    ble_gatts_char_md_t     char_md;
    ble_gatts_attr_t        attr_char_value;

    // Add a custom base UUID.
    err_code = sd_ble_uuid_vs_add(&base_uuid, &char_uuid.type);
    VERIFY_SUCCESS(err_code);

    memset(&char_md, 0, sizeof(char_md));
    char_md.char_props.read = 1;
    char_md.char_props.write = 1;

    ble_gatts_attr_md_t cccd_md;
    memset(&cccd_md, 0, sizeof(cccd_md));
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
    cccd_md.vloc                = BLE_GATTS_VLOC_STACK;    
    char_md.p_cccd_md           = &cccd_md;
    char_md.char_props.notify   = 1;


    memset(&attr_md, 0, sizeof(attr_md));
    attr_md.rd_auth = 1;
    attr_md.wr_auth = 0;
    attr_md.vlen = 0;
    attr_md.vloc = BLE_GATTS_VLOC_STACK;
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);


    memset(&attr_char_value, 0, sizeof(attr_char_value));
    char_uuid.uuid = BLE_UUID_VECTOR_PUMP;
    attr_char_value.p_uuid = &char_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len = BLE_COMMAND_CHAR_LEN;
    attr_char_value.init_offs = 0;
    attr_char_value.max_len = BLE_COMMAND_CHAR_LEN;
    attr_char_value.p_value = &init_value;

    err_code = sd_ble_gatts_characteristic_add(p_vpe->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_vpe->command_char_handle);
    VERIFY_SUCCESS(err_code);
    return err_code;

}


I get write events, but I don't get any read events. My event handler is as follows:

void ble_vpe_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
    if ((p_context == NULL) || (p_ble_evt == NULL))
    {
        return;
    }

    ble_vpe_t * p_vpe = (ble_vpe_t *)p_context;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
          on_connect(p_vpe, p_ble_evt);
          break;

        case BLE_GATTS_EVT_WRITE:
            on_write(p_vpe, p_ble_evt);
            break;

        case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            if((p_ble_evt->evt.gatts_evt.params.authorize_request.type) == BLE_GATTS_AUTHORIZE_TYPE_READ){
                NRF_LOG_INFO(0,"BLE Read request. \n");
                on_read(p_vpe, p_ble_evt);
            }
            //If there is a write request
            else if((p_ble_evt->evt.gatts_evt.params.authorize_request.type) == BLE_GATTS_AUTHORIZE_TYPE_WRITE){
                NRF_LOG_INFO(0,"BLE Write request. \n");
                on_write(p_vpe, p_ble_evt);
            }
            break;

        default:
            // No implementation needed.
            break;
    }
}
Parents
  • Hi Only1chi, 

    Could you let me know which SDK version you are using and with which Softdevice ? 

    I did a quick test here with the NUS service in SDK v14.2 and it worked fine for me. 

    When you don't see the read event, can you actually get the characteristic's value on the peer's side ? 

    /**
     * Copyright (c) 2012 - 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, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    #include "sdk_common.h"
    #if NRF_MODULE_ENABLED(BLE_NUS)
    #include "ble.h"
    #include "ble_nus.h"
    #include "ble_srv_common.h"
    
    
    #define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003                      /**< The UUID of the TX Characteristic. */
    #define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002                      /**< The UUID of the RX Characteristic. */
    
    #define BLE_NUS_MAX_RX_CHAR_LEN        BLE_NUS_MAX_DATA_LEN        /**< Maximum length of the RX Characteristic (in bytes). */
    #define BLE_NUS_MAX_TX_CHAR_LEN        BLE_NUS_MAX_DATA_LEN        /**< Maximum length of the TX Characteristic (in bytes). */
    
    #define NUS_BASE_UUID                  {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
    
    
    /**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the SoftDevice.
     *
     * @param[in] p_nus     Nordic UART Service structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static void on_connect(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
    {
        p_nus->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
    }
    
    
    /**@brief Function for handling the @ref BLE_GAP_EVT_DISCONNECTED event from the SoftDevice.
     *
     * @param[in] p_nus     Nordic UART Service structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static void on_disconnect(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
    {
        UNUSED_PARAMETER(p_ble_evt);
        p_nus->conn_handle = BLE_CONN_HANDLE_INVALID;
    }
    
    
    /**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the SoftDevice.
     *
     * @param[in] p_nus     Nordic UART Service structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
    {
        ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
        ble_nus_evt_t evt;
        evt.p_nus = p_nus;
        if (   (p_evt_write->handle == p_nus->tx_handles.cccd_handle)
            && (p_evt_write->len == 2))
        {
            if (ble_srv_is_notification_enabled(p_evt_write->data))
            {
                p_nus->is_notification_enabled = true;
                evt.type = BLE_NUS_EVT_COMM_STARTED;
            }
            else
            {
                p_nus->is_notification_enabled = false;
                evt.type = BLE_NUS_EVT_COMM_STOPPED;
            }
            p_nus->data_handler(&evt);
        }
        else if (   (p_evt_write->handle == p_nus->rx_handles.value_handle)
                 && (p_nus->data_handler != NULL))
        {
            evt.params.rx_data.p_data = p_evt_write->data;
            evt.params.rx_data.length = p_evt_write->len;
            evt.type = BLE_NUS_EVT_RX_DATA;
            p_nus->data_handler(&evt);
        }
        else
        {
            // Do Nothing. This event is not relevant for this service.
        }
    }
    
    
    /**@brief Function for adding TX characteristic.
     *
     * @param[in] p_nus       Nordic UART Service structure.
     * @param[in] p_nus_init  Information needed to initialize the service.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static uint32_t tx_char_add(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
    {
        /**@snippet [Adding proprietary characteristic to the SoftDevice] */
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_md_t cccd_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
    
        cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.notify = 1;
        char_md.char_props.read = 1;
        char_md.p_char_user_desc  = NULL;
        char_md.p_char_pf         = NULL;
        char_md.p_user_desc_md    = NULL;
        char_md.p_cccd_md         = &cccd_md;
        char_md.p_sccd_md         = NULL;
    
        ble_uuid.type = p_nus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC;
    
        memset(&attr_md, 0, sizeof(attr_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
    
        attr_md.vloc    = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth = 1;
        attr_md.wr_auth = 0;
        attr_md.vlen    = 1;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = sizeof(uint8_t);
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = BLE_NUS_MAX_TX_CHAR_LEN;
    
        return sd_ble_gatts_characteristic_add(p_nus->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_nus->tx_handles);
        /**@snippet [Adding proprietary characteristic to the SoftDevice] */
    }
    
    
    /**@brief Function for adding RX characteristic.
     *
     * @param[in] p_nus       Nordic UART Service structure.
     * @param[in] p_nus_init  Information needed to initialize the service.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static uint32_t rx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
    {
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.write         = 1;
        char_md.char_props.write_wo_resp = 1;
        char_md.p_char_user_desc         = NULL;
        char_md.p_char_pf                = NULL;
        char_md.p_user_desc_md           = NULL;
        char_md.p_cccd_md                = NULL;
        char_md.p_sccd_md                = NULL;
    
        ble_uuid.type = p_nus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
    
        memset(&attr_md, 0, sizeof(attr_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
    
        attr_md.vloc    = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth = 0;
        attr_md.wr_auth = 0;
        attr_md.vlen    = 1;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = 1;
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = BLE_NUS_MAX_RX_CHAR_LEN;
    
        return sd_ble_gatts_characteristic_add(p_nus->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_nus->rx_handles);
    }
    
    
    void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        if ((p_context == NULL) || (p_ble_evt == NULL))
        {
            return;
        }
    
        ble_nus_t * p_nus = (ble_nus_t *)p_context;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                on_connect(p_nus, p_ble_evt);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                on_disconnect(p_nus, p_ble_evt);
                break;
    
            case BLE_GATTS_EVT_WRITE:
                on_write(p_nus, p_ble_evt);
                break;
    
            case BLE_GATTS_EVT_HVN_TX_COMPLETE:
            {
                //notify with empty data that some tx was completed.
                ble_nus_evt_t evt = {
                        .type = BLE_NUS_EVT_TX_RDY,
                        .p_nus = p_nus
                };
                p_nus->data_handler(&evt);
                break;
            }
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
    {
        uint32_t      err_code;
        ble_uuid_t    ble_uuid;
        ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
    
        VERIFY_PARAM_NOT_NULL(p_nus);
        VERIFY_PARAM_NOT_NULL(p_nus_init);
    
        // Initialize the service structure.
        p_nus->conn_handle             = BLE_CONN_HANDLE_INVALID;
        p_nus->data_handler            = p_nus_init->data_handler;
        p_nus->is_notification_enabled = false;
    
        /**@snippet [Adding proprietary Service to the SoftDevice] */
        // Add a custom base UUID.
        err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        ble_uuid.type = p_nus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
    
        // Add the service.
        err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                            &ble_uuid,
                                            &p_nus->service_handle);
        /**@snippet [Adding proprietary Service to the SoftDevice] */
        VERIFY_SUCCESS(err_code);
    
        // Add the RX Characteristic.
        err_code = rx_char_add(p_nus, p_nus_init);
        VERIFY_SUCCESS(err_code);
    
        // Add the TX Characteristic.
        err_code = tx_char_add(p_nus, p_nus_init);
        VERIFY_SUCCESS(err_code);
    
        return NRF_SUCCESS;
    }
    
    
    uint32_t ble_nus_string_send(ble_nus_t * p_nus, uint8_t * p_string, uint16_t * p_length)
    {
        ble_gatts_hvx_params_t hvx_params;
    
        VERIFY_PARAM_NOT_NULL(p_nus);
    
        if ((p_nus->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_nus->is_notification_enabled))
        {
            return NRF_ERROR_INVALID_STATE;
        }
    
        if (*p_length > BLE_NUS_MAX_DATA_LEN)
        {
            return NRF_ERROR_INVALID_PARAM;
        }
    
        memset(&hvx_params, 0, sizeof(hvx_params));
    
        hvx_params.handle = p_nus->tx_handles.value_handle;
        hvx_params.p_data = p_string;
        hvx_params.p_len  = p_length;
        hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
    
        return sd_ble_gatts_hvx(p_nus->conn_handle, &hvx_params);
    }
    
    #endif // NRF_MODULE_ENABLED(BLE_NUS)
    

  • Hi Hug,

    I'm using SDK v17. 
    The events do not appear on peer's side. 

  • Hi Only1chi, 

    Could you send your full project so we can test here ? Or if you can create a minimum project that I can run on nRF52 DK here it would be great. 
    When you don't get a read event, what do you see on the phone's side ? 

  • It seems a little bit different from the initial code you quoted in the original question. In the project in the .zip you sent you used the ble_srv library to initialize the characteristic. 
    I noticed that you used :     add_char_params.p_user_descr->is_defered_read   = 1; This is the property for the user descriptor, not the characteristic value itself. You should use : 

    add_char_params.is_defered_read=1;
     instead.

    After changing that, i can see the read event in the log:  ble_vpe: Read Event. conn_handle: 0 

    It doesn't seem you have handle the reply/confirmation for the read. You would need to implement sd_ble_gatts_rw_authorize_reply() in on_read()

  • Hi Hung,

    Thanks for your answer. I had done the exact same thing before, but I haven't seen the event.
    Where in the application would I see the event? Which of the handlers?

    Also in the file vpe_ble.c, there is an event handler which looks for 

    BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST 

    I never see that event get triggered.

    Could you point me to the event handler you're referring to? 

  • I figured it out. I understand now what you're saying. 
    I was using  sd_ble_gatts_value_set() function to handle the event when I should have been using sd_ble_gatts_rw_authorize_reply()

    Thanks



Reply Children
No Data
Related