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

I combined Bonding in the UART example, but after autoconnect, the notification is not enabled.

I applied Bonding to the UART example(ble_app_uart).

Bonding combined with the UART example works well, but there is one problem.

1. I did Bonding first.
2. After that I set Notification Enable.
3. Rebooted the device and reconnected to the application using Auto connect.
4. On the NRF Connect, it is marked as Notification Enable, but the device did not send the notification.

I checked the code point where the problem was occurring.

I found that is_notification_enabled is still false after auto-connect.

uint32_t ble_nus_string_send(ble_nus_t * p_nus, uint8_t * p_string, uint16_t 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 (length > BLE_NUS_MAX_DATA_LEN)
{
return NRF_ERROR_INVALID_PARAM;
}

memset(&hvx_params, 0, sizeof(hvx_params));

hvx_params.handle = p_nus->rx_handles.value_handle;
hvx_params.p_data = p_string;
hvx_params.p_len = &length;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;

return sd_ble_gatts_hvx(p_nus->conn_handle, &hvx_params);
}

I tried to ignore this part of the conditional statement, but then the device didn't work properly.

If possible, please help resolve the problem.

  • /**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the S110 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 * 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 S110 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 * 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 S110 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 * p_ble_evt)
    {
        ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    
        if (
            (p_evt_write->handle == p_nus->rx_handles.cccd_handle)
            &&
            (p_evt_write->len == 2)
           )
        {
            if (ble_srv_is_notification_enabled(p_evt_write->data))
            {
                p_nus->is_notification_enabled = true;
            }
            else
            {
                p_nus->is_notification_enabled = false;
            }
        }
        else if (
                 (p_evt_write->handle == p_nus->rx_handles.value_handle)
                 &&
                 (p_nus->data_handler != NULL)
                )
        {
            p_nus->data_handler(p_nus, p_evt_write->data, p_evt_write->len);
        }
        else
        {
            // Do Nothing. This event is not relevant for this service.
        }
    }
    
    
    /**@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)
    {
        /**@snippet [Adding proprietary characteristic to S110 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.write_perm = p_nus_init->nus_attr_md.cccd_write_perm;
    
        cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    
        memset(&char_md, 0, sizeof(char_md));
    
    	char_md.char_props.write  = 1;
    	char_md.char_props.write_wo_resp = 1;
        char_md.char_props.notify = 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_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  = sizeof(uint8_t);
        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);
        /**@snippet [Adding proprietary characteristic to S110 SoftDevice] */
    }
    
    
    
    void ble_nus_on_ble_evt(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
    {
        if ((p_nus == NULL) || (p_ble_evt == NULL))
        {
            return;
        }
    
        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;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * 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 S110 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 S110 SoftDevice] */
        VERIFY_SUCCESS(err_code);
    
        // Add the RX Characteristic.
        err_code = rx_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 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 (length > BLE_NUS_MAX_DATA_LEN)
        {
            return NRF_ERROR_INVALID_PARAM;
        }
    
        memset(&hvx_params, 0, sizeof(hvx_params));
    
        hvx_params.handle = p_nus->rx_handles.value_handle;
        hvx_params.p_data = p_string;
        hvx_params.p_len  = &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)
    

    This is my code in ble_nus.c

  • What SDK version is this ?

    In the latest SDK versions we read the CCCD value in the function on_connect() with sd_ble_gatts_value_get(), and then we update the variable is_notification_enabled. Some SDKs might have a bug here though, ref this post.

    Snippet:

        /* Check the hosts CCCD value to inform of readiness to send data using the RX characteristic */
        memset(&gatts_val, 0, sizeof(ble_gatts_value_t));
        gatts_val.p_value = cccd_value;
        gatts_val.len     = sizeof(cccd_value);
        gatts_val.offset  = 0;
    
        err_code = sd_ble_gatts_value_get(p_ble_evt->evt.gap_evt.conn_handle,
                                          p_nus->rx_handles.cccd_handle,
                                          &gatts_val);
    
        if ((err_code == NRF_SUCCESS)     &&
            (p_nus->data_handler != NULL) &&
            ble_srv_is_notification_enabled(gatts_val.p_value))
        {
            if (p_client != NULL)
            {
                p_client->is_notification_enabled = true;
            }

  • Ok, then if you want is_notification_enabled to be true after auto-connect, then you need to implement the functionally shown in the snippet. You might also need to bond to the device for it to work.

Related