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

How to enable indication and get CCCD value to check

Hi All,

I want to use DFU to update the firmware from master to peripheral over BLE ,  both master and peripheral are nrf52840. My purpose is that the master sends a command to make the peripheral enter bootloader.Therefore I need enable indication and write 0x01 to peripheral. "nrf connect" can do it.

But the problem is that I don't kown if the indication is enable on peripheral.I referred to other answers but failed becuase I can't excuess sd_ble_gatts_value_get() and  sd_ble_gatts_hvx() correctly, my programs are below.

 

//enable indication
static uint32_t cccd_configure(ble_hrs_c_t * p_ble_hrs_c, bool enable)
{
    NRF_LOG_INFO("Configuring CCCD. CCCD Handle = %x, Connection Handle = %x",
                  p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle,
                  p_ble_hrs_c->conn_handle);

    nrf_ble_gq_req_t hrs_c_req;
    uint8_t          cccd[BLE_CCCD_VALUE_LEN];
    uint16_t         cccd_val = enable ? BLE_GATT_HVX_INDICATION : 0;

    cccd[0] = LSB_16(cccd_val);
    cccd[1] = MSB_16(cccd_val);

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

    hrs_c_req.type                        = NRF_BLE_GQ_REQ_GATTC_WRITE;
    hrs_c_req.error_handler.cb            = gatt_error_handler;
    hrs_c_req.error_handler.p_ctx         = p_ble_hrs_c;
    hrs_c_req.params.gattc_write.handle   = p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle;
    hrs_c_req.params.gattc_write.len      = BLE_CCCD_VALUE_LEN;
	hrs_c_req.params.gattc_write.offset   = 0;
    hrs_c_req.params.gattc_write.p_value  = cccd;
    hrs_c_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
	hrs_c_req.params.gattc_write.flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
    return nrf_ble_gq_item_add(p_ble_hrs_c->p_gatt_queue, &hrs_c_req, p_ble_hrs_c->conn_handle);
}

ble_hrs_c_handles_assign

uint32_t ble_hrs_c_handles_assign(ble_hrs_c_t    * p_ble_hrs_c,
                                  uint16_t         conn_handle,
                                  const hrs_db_t * p_peer_hrs_handles)
{
    VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);

    p_ble_hrs_c->conn_handle = conn_handle;
    if (p_peer_hrs_handles != NULL)
    {
        //p_ble_hrs_c->peer_hrs_db = *p_peer_hrs_handles;
		NRF_LOG_INFO("In handles assign");
		p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle = p_peer_hrs_handles->hrm_cccd_handle;
		p_ble_hrs_c->peer_hrs_db.hrm_handle = p_peer_hrs_handles->hrm_handle;
    }

    return nrf_ble_gq_conn_handle_register(p_ble_hrs_c->p_gatt_queue, conn_handle);
}

when find the service and characteristics

 

static void hrs_c_evt_handler(ble_hrs_c_t * p_hrs_c, ble_hrs_c_evt_t * p_hrs_c_evt)
{
	
    ret_code_t err_code;
	bool       is_indication_enabled = true;
    switch (p_hrs_c_evt->evt_type)
    {
        case BLE_HRS_C_EVT_DISCOVERY_COMPLETE:
        {
            NRF_LOG_INFO("dfu service discovered.");

            err_code = ble_hrs_c_handles_assign(p_hrs_c,
                                                p_hrs_c_evt->conn_handle,
                                                &p_hrs_c_evt->params.peer_db);
            APP_ERROR_CHECK(err_code);

			err_code = cccd_configure(p_hrs_c,true);
            APP_ERROR_CHECK(err_code);
			ble_gatts_value_t gatt_value;
			uint8_t cccd_value;
			gatt_value.len = 2;
			gatt_value.p_value = &cccd_value;
			gatt_value.offset = 0;
			err_code = sd_ble_gatts_value_get(p_hrs_c_evt->conn_handle, p_hrs_c->peer_hrs_db.hrm_cccd_handle, &gatt_value);
			APP_ERROR_CHECK(err_code);
        } break;
        default:
            break;
    }
}

connection handle : 0, characteristics handle:0x16, cccd handle:0x17

sd_ble_gatts_value_get() returned error 5 

I have no idea where is wrong , please give me some advice

Thanks,

Steven

Parents
  • I am not sure I understand you. In your screenshot, you have highlighted the buttonless DFU service, but your snippets looks like they are using the bl_app_hrs_c (which is a central) service.

    Are you trying to enable indications from a central, or are you trying to check whether a central have enabled indications?

    And is there a particular reason why you are using indications and not notifications?

    the sd_ble_gatts_value_get() is a gatt server call, which is intended for the peripheral to check the value of the characteristic. You can't use this on the central.

    If you want to check how to enable notifications, please check the unmodified ble_app_hrs_c (download and unzip a new SDK if you have changed a lot in the service's files).

    Look at how it uses ble_hrs_c_hrm_notif_enable(). It uses cccd_configure from ble_hrs_c.c. Please note the line:

    uint16_t         cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;

    If you want to use indications instead of notifications, please change BLE_GATT_HVX_NOTIFICATION to BLE_GATT_HVX_INDICATION, but please check whether the peripheral supports indications at all before you do so. The ble_app_hrs example does not support indications by default (and if you change it, it no longer complies with the HRS service, which is determined by Bluetooth).

    Best regards,

    Edvin

  • Hi Edvin 

    Thanks for your quick reply.

    but your snippets looks like they are using the bl_app_hrs_c (which is a central) service.

    I just use the example of bl_app_hrs_c and changed UUIDs because I didn't find any example of DFU  in master(based on nrf52840). My purpose is that the master sends a command to make the peripheral enter bootloader. I would rewrite the codes when I understand more.

    The peripheral has bootloader(based on Buttonless Secure DFU Service) and I can use "nRF connect" to enter bootloader of peripheral (enable indication and write 0x01).My ultimate goal is to enable the master to control the  peripheral upgrade just like "nrf connect".

    Are you trying to enable indications from a central, or are you trying to check whether a central have enabled indications?

    And is there a particular reason why you are using indications and not notifications?

    Yes, I am trying to enable indications from a central, but I don't know if it works. Therefore I try to confirm it.

    I refer to the infomation(Subscribe for indications and write 0x01 into the characteristic) here.

    If you want to use indications instead of notifications, please change BLE_GATT_HVX_NOTIFICATION to BLE_GATT_HVX_INDICATION, but please check whether the peripheral supports indications at all before you do so.

    I think the peripheral supports indications because I can use "nrf connect" to enable indications and enter bootloader.

    All in all, I have found the service(0xfe59) and its characteristic(Buttonless DFU without bonds:0x03) but failed to write 0x01 to the peripheral. Therefore,I tried to check whether indications aren't enable or failed to write 0x01 into the characteristic.

    Best regards,

    Steven

  • Try to copy the ble_hrs_c_hrm_norif_enable() function and change it from notification to indication, as I described in the previous reply.

    If you want to test whether indications are already enabled, please try to read the characteristic description. The HRS example doesn't do this, and I don't think we have any central examples that does this, really. (Probably because it is easier to just enable the indication/notification again, which I recommend).

    What you need to do to read is to use the implementation from cccd_configure() in ble_hrs_c.c and change NRF_BLE_GQ_REQ_GATTC_WRITE to NRF_BLE_GX_REQ_GATTC_READ, and change all instances of:

    hrs_c_req.params.gattc_write. ...

    with 

    hrs_c_req.params.gattc_read. ...

    This will probably generate an event at a later point in time in your ble_evt_handler:

    case BLE_GATTC_EVT_READ_RSP:

    Look at the p_ble_evt->evt.gattc_evt.params.read_rsp struct (ble_gattc_evt_read_rsp_t) to implement this handler.

    BR,

    Edvin

  • Hi Edvin 

    Thanks for your reply.

    I still have two questions.

    Try to copy the ble_hrs_c_hrm_norif_enable() function and change it from notification to indication, as I described in the previous reply.

    1. To enable indications, the changes in cccd_configure() are:

    1. cccd_val = enable ? BLE_GATT_HVX_INDICATION : 0;
    
    // use my cccd handle
    2.hrs_c_req.params.gattc_write.handle = p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle;
    
    // use my connection handle
    3. return nrf_ble_gq_item_add(p_ble_hrs_c->p_gatt_queue, &hrs_c_req, p_ble_hrs_c->conn_handle);

    Is that right?

    2.If I want to write 0x01 to the characteristic(Buttonless DFU without bonds:0x03) ,where can I get examples.

    Best regards,

    Steven

  • lolifrog said:
    Is that right?

     Yes. Does it return NRF_SUCCESS (0x00)? And do you see the callback later?

     

    lolifrog said:
    2.If I want to write 0x01 to the characteristic(Buttonless DFU without bonds:0x03) ,where can I get examples.

     Look at how the ble_app_uart_c writes to a characteristic using ble_nus_c_string_send().

    Best regards,

    Edvin

Reply Children
  • Yes. Does it return NRF_SUCCESS (0x00)? And do you see the callback later?

    Yes, the return is NRF_SUCCESS(0x00). I read the value of cccd(0x0002) as you said.

    However,I met another question:

    I failed to write 0x01 to the characteristic based on ble_nus_c_string_send() because the peripheral didn't have any logs.But I can read the characteristic (Buttonless DFU without bonds:0x03) :

     

    BLE_GATTC_EVT_READ_RSP,len:3
    value[0]:20
    value[1]:1
    value[2]:1

    and I change the array from {0x01} to {0x04} , the peripheral has logs as below:

    <error> app : Request to send a response to client failed.
    <error> app : Request to enter bootloader mode failed asynchroneously.

    I can also read the characteristic (Buttonless DFU without bonds:0x03) :

    BLE_GATTC_EVT_READ_RSP,len:3
    value[0]:20
    value[1]:4
    value[2]:2

    Bluetooth master connects to the peripheral periodically(if I don't write a byte to the characteristic, the master will not be disconnected). Logs are below:

    Disconnected. conn_handle: 0x0, reason: 0x13

    When reconnected and written 0x04(if the written byte is 0x01,there is no logs below) ,the peripheral show logs:

    Request to enter bootloader mode failed asynchroneously

    I wonder where is wrong?

    More details:

    write characteristic:

    uint32_t ble_dfu_c_string_send(ble_hrs_c_t * p_ble_dfu_c, uint8_t * p_string, uint16_t length)
    {
    
        VERIFY_PARAM_NOT_NULL(p_ble_dfu_c);
        nrf_ble_gq_req_t write_req;
        memset(&write_req, 0, sizeof(nrf_ble_gq_req_t));
        if (length > NRF_SDH_BLE_GATT_MAX_MTU_SIZE - 3)
        {
            NRF_LOG_WARNING("Content too long.");
            return NRF_ERROR_INVALID_PARAM;
        }
        if (p_ble_dfu_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_WARNING("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
     
        write_req.type                        = NRF_BLE_GQ_REQ_GATTC_WRITE;
        write_req.error_handler.cb            = gatt_error_handler;
        write_req.error_handler.p_ctx         = p_ble_dfu_c;
        write_req.params.gattc_write.handle   = p_ble_dfu_c->peer_hrs_db.hrm_handle;
        write_req.params.gattc_write.len      = length;
        write_req.params.gattc_write.offset   = 0;
        write_req.params.gattc_write.p_value  = p_string;
        write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_CMD;
    	NRF_LOG_INFO("ble_dfu_c_string_send write.handle:%x",p_ble_dfu_c->peer_hrs_db.hrm_handle);
        return nrf_ble_gq_item_add(p_ble_dfu_c->p_gatt_queue, &write_req, p_ble_dfu_c->conn_handle);
    }

    read characteristic:

    uint32_t ble_dfu_ch_read(ble_hrs_c_t * p_ble_dfu_c,uint16_t chara_handle)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_dfu_c);
    
        nrf_ble_gq_req_t read_req;
    
        memset(&read_req, 0, sizeof(nrf_ble_gq_req_t));
    
        if (p_ble_dfu_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_INFO("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
    	NRF_LOG_INFO("In ch_read.handle:%x.",chara_handle);
        read_req.type                        = NRF_BLE_GQ_REQ_GATTC_READ;
        read_req.error_handler.cb            = gatt_error_handler;
        read_req.error_handler.p_ctx         = p_ble_dfu_c;
        read_req.params.gattc_read.handle   = chara_handle;
        read_req.params.gattc_read.offset   = 0;
        return nrf_ble_gq_item_add(p_ble_dfu_c->p_gatt_queue, &read_req, p_ble_dfu_c->conn_handle);
    }

    main

    //uint8_t arr={0x01}, and can be changed by uart
    err_code = ble_dfu_c_string_send(&m_hrs_c, arr, 1);
    APP_ERROR_CHECK(err_code);
    err_code = ble_dfu_ch_read(&m_hrs_c,m_hrs_c.peer_hrs_db.hrm_handle);
    APP_ERROR_CHECK(err_code);

    Best regards,

    Steven

  • Hello,

    It looks like you are reading the CCCD of the characteristic, which is 0x0200 (indication enabled). Try reading the value handle instead.

     

    lolifrog said:
    Bluetooth master connects to the peripheral periodically(if I don't write a byte to the characteristic, the master will not be disconnected). Logs are below:

     It is expected that they will disconnect. When you write 0x01 to the buttonless DFU characteristic, the device should reboot in bootloader mode. 

    It looks, based on your log message "Request to enter bootloader mode failed asynchroneously" that it failed to do so. Have you tried to debug to figure out why the BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED event was generated?

    Best regards,

    Edvin

  • Hello Edvin,

    I tried to debug the peripheral and found that BLE_GATTS_EVT_HVC event was not generated in ble_dfu_buttonless_on_ble_evt().

    In "nrf_connect" app, if I enable indications and write 0x01 to the characteristic(Buttonless DFU without bonds:0x03), BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST and BLE_GATTS_EVT_HVC will be generated.

    The result is that I can only recieve {0x20,0x01,0x01}  when writing 0x01 to the characteristic(Buttonless DFU without bonds:0x03) and the peripheral can not enter bootloarder.

    I wonder if I need to do something else after writing 0x01 to the characteristc?

    Best regards,

    Steven

  • I have not tried to write to this application from an application running on the nRF (only with a phone or nRF Connect for Desktop). Can you please zip the project folder and upload it here, so that I can have a look at what you are doing? It is very hard to say whats wrong based on this discussion only.

    If you do upload the zipped project folder, please specify what SDK version and IDE you are using.

    Best regards,

    Edvin

  • Hello Edvin,

    Thanks for your patient replies this week, I figured out  why BLE_GATTS_EVT_HVC event was not generated.

    Because the peripheral is responding to the Enter Bootloader request with a handle value indication which should be confirmed by the master. This confirmation will generate the BLE_GATTS_EVT_HVC event.

    I add the code to send a Handle Value Confirmation to the GATT Server in the master side before on_hvx():

    void ble_hrs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ble_hrs_c_t * p_ble_hrs_c = (ble_hrs_c_t *)p_context;
    
        if ((p_ble_hrs_c == NULL) || (p_ble_evt == NULL))
        {
            return;
        }
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GATTC_EVT_HVX:
    			//Send a Handle Value Confirmation to the GATT Server
    			sd_ble_gattc_hv_confirm(p_ble_evt->evt.common_evt.conn_handle,p_ble_evt->evt.gattc_evt.params.hvx.handle);
                on_hvx(p_ble_hrs_c, p_ble_evt);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                on_disconnected(p_ble_hrs_c, p_ble_evt);
                break;
    
            default:
                break;
        }
    }

    Reference:

    https://devzone.nordicsemi.com/f/nordic-q-a/52470/create-ble_dfu_c---triggering-enter-bootloader-doesn-t-work/211297#211297

    https://devzone.nordicsemi.com/f/nordic-q-a/22743/no-ble_gatts_evt_hvc-event-generating-when-using-s140-for-bluetooth-5

    Best regards,

    Steven

Related