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

unable to enable Notifications using sd_ble_gattc_write (SDK 15.2)

Hi there,

I am migrating my central project from SDK 13 to SDK 15.2, almost all the project is already migrated, but I am having an issue with sd_ble_gattc_write() it is not enabling the notifications when I start a connection and skip ble_db_discovery_start()

so, the first thing I do in my central when it has established a connection with a peripheral is enable the CCCD using sd_ble_gattc_write(), I do it to avoid extra consumption discovering every time the same attribute table for the same Peripheral that already known 

SDK 13 code: it works fine

case BLE_GAP_EVT_CONNECTED:
		{
			NRF_LOG_INFO("Connected\r\n");
			
			(void) sd_ble_gap_scan_stop();

			uint32_t err_code;	
			ble_gattc_write_params_t write_params;
			uint8_t	EnableNotification[2] = {0x01, 0x00};		

			write_params.write_op = BLE_GATT_OP_WRITE_REQ;						
			write_params.handle   = 0x0011;  			
			write_params.offset   = 0;															
			write_params.len      = 2;																
			write_params.p_value  = EnableNotification;													
			
			err_code = sd_ble_gattc_write(0x0000 , &write_params);
			APP_ERROR_CHECK(err_code);

			bsp_board_led_on(LED_CONNECTED);
		} break;

since then I am using it Bypass or skip the discovery service nRF52 SDK 12.2

I am trying to use the same code for the SDK 15.2, it is writing on the peripheral 0x01 0x00 but it is still not enabling the notification (I am writting it on the CCCD handle like when the discovery service is performed) the only way I can make it work is after a ble_db_discovery_start() and event BLE_LBS_C_EVT_DISCOVERY_COMPLETE, but it no makes sense to me if I want to avoid performing a discovery service each time for the same device

as a reference, I am using the BLE Blinky peripheral and central projects to replicate the issue

any suggestion?

Regards,

Arepa

  • Hi Arepa.

     

    so, the first thing I do in my central when it has established a connection with a peripheral is enable the CCCD using sd_ble_gattc_write(), I do it to avoid extra consumption discovering every time the same attribute table for the same Peripheral that already known 

     You could take a look at nRF5_SDK_15.2.0_9412b96\examples\ble_central_and_peripheral\experimental\ble_app_interactive\cli_m.c and the function static void cccd_set(nrf_cli_t const * p_cli, uint16_t cccd, char * p_addr, char * p_uuid), and make sure that you set up CCCD correct.

    /**@brief Function for setting the CCCD Descriptor value.
     *
     * @param[in] p_cli          Instance of the command line.
     * @param[in] cccd           New CCCD value.
     * @param[in] addr           Device address in string format.
     * @param[in] uuid           Characteristic UUID in string format.
     */
    static void cccd_set(nrf_cli_t const * p_cli, uint16_t cccd, char * p_addr, char * p_uuid)
    {
        uint16_t                 conn_handle;
        uint16_t                 desc_handle;
        ret_code_t               err_code;
        ble_gattc_write_params_t write_params;
    
        // Search for connection handle.
        conn_handle = addr_string_to_conn_handle(p_addr);
    
        if(!conn_handle_is_valid(conn_handle, p_cli))
        {
            return;
        }
    
        memset(&write_params, 0, sizeof(write_params));
    
        desc_handle = cccd_descriptors_handle_get(p_uuid);
    
        if (desc_handle == BLE_GATT_HANDLE_INVALID)
        {
            nrf_cli_fprintf(p_cli,
                            NRF_CLI_ERROR,
                            "Wrong characteristic UUID or the CCCD descriptor has not been found yet\r\n");
            return;
        }
    
        uint16_t cccd_val    = cccd;
        uint8_t  data_buf[2] = {LSB_16(cccd_val), MSB_16(cccd_val)};
        uint8_t  data_len    = sizeof(data_buf);
    
        write_params.write_op = BLE_GATT_OP_WRITE_REQ;
        write_params.handle   = desc_handle;
        write_params.len      = data_len;
        write_params.p_value  = data_buf;
        write_params.offset   = 0;
        write_params.flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
    
        // Set CCCD descriptor value.
        err_code = sd_ble_gattc_write(conn_handle, &write_params);
    
        if (err_code != NRF_SUCCESS)
        {
            nrf_cli_fprintf(p_cli,
                            NRF_CLI_ERROR,
                            "wrong characteristic UUID or the CCCD descriptor has not been found yet\r\n");
        }
    }
    

    - Andreas

  • Hi Arepa.

     

    so, the first thing I do in my central when it has established a connection with a peripheral is enable the CCCD using sd_ble_gattc_write(), I do it to avoid extra consumption discovering every time the same attribute table for the same Peripheral that already known 

    Could you try this code:

    case BLE_GAP_EVT_CONNECTED:
    		{
    			NRF_LOG_INFO("Connected\r\n");
    			
    			(void) sd_ble_gap_scan_stop();
    
    			uint32_t err_code;
    			
    			ble_gattc_write_params_t write_params;
    		    memset(&write_params, 0, sizeof(write_params));
    		    
    			uint8_t	EnableNotification[2] = {LSB_16(0x01), MSB_16(0x00)};
    
    			write_params.write_op = BLE_GATT_OP_WRITE_REQ;						
    			write_params.handle   = 0x0015;  			
    			write_params.offset   = 0;															
    			write_params.len      = 2;																
    			write_params.p_value  = EnableNotification;
    			write_params.flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
    			
    			err_code = sd_ble_gattc_write(0x0000 , &write_params);
    			APP_ERROR_CHECK(err_code);
    
                if (err_code != NRF_SUCCESS)
                {
                    NRF_LOG_INFO("wrong characteristic UUID or the CCCD descriptor has not been found yet\r\n");
                }
    
    
    			bsp_board_led_on(LED_CONNECTED);
    		} break;

    I've looked at the function static void cccd_set(nrf_cli_t const * p_cli, uint16_t cccd, char * p_addr, char * p_uuid), in nRF5_SDK_15.2.0_9412b96\examples\ble_central_and_peripheral\experimental\ble_app_interactive\cli_m.c, which is used to enable CCCD.

    There is a good tutorial on custom BLE service which also sets up CCCD.

    - Andreas

  • Hi @AndreasF thanks for the suggestions, I double checked my CCCD set up using the custom BLE service and it seems good. l added the code you suggested above, at the moment I am using the BLE blinky project Peripheral and Client without major modification just skipping the discovery service, but my central is not enabling the notification on the peripheral side when I am using sd_ble_gattc_write, it only works after performed a discovery service, It concerns me because I have been using the same routine almost 2 years with no issue with the SDK13, and it is not working when I am running the SDK15.2

    note: I am using the RTT output with J-Link RTT Viewer instead of Putty or any UART terminal

    I have attached the project I am using blinky peripheral and central (with some modifications),

    Inside the central code you can find Skip_discovery flag and Enable_CCCD_write() I added to enable the notification to my peripheral,

    ble_app_blinky_c_Original_skiping_discovery.rar

    ble_app_blinky_original.rar

    #update:

    I also tried adding manually the values for conn handle and button_cccd_handle inside ble_lbs_c_button_notif_enable() commenting out the verification if the value is null or invalid, it works fine only if the client performs a discovery service otherwise it does not enable the CCCD (it does not return any error)

    The curious about this issue is that when I am not performing a discovery service in the client, I am also receiving  p_evt_write->data[0],p_evt_write->data[1] = 0x01 0x00 on the peripheral inside on_write() event, but the notification is not being enabled

  • Hi.

    I'm a bit confused at why you would like to skip the discovery service?

    If you do not do a discovery service the CCCD will not be enabled, because the central does not know what the different services has as handles.

    For example:

    If you have a central (C1) and a peripheral (P1), and a temperature sensor (T1)  is connected to the peripheral (P1)

    If you do not do a discovery service and only connect to the peripheral (P1) from the central (C1), then the central (C1) is only connected. If the temperature sensor (T1) registers a new temperature to a service at the peripheral (P1) the peripheral will not notify the central (C1) because:

    1) The central does not know what different services that are available at the peripheral (P1)

    2) It does not know the service handle which relates to the temperatur sensor (T1) .

    3) The central (C1) has not made the peripheral (P1) aware that this particular service should do a notify when it has a change in value

    Hope this helps.


    Best regards.

    - Andreas

  • Hi Andreas,

    I want to skip the discovey service for two reasons:

    1) I am going to connect to only one Peripheral wheres I know the handle for each service and I am adding it manually to the Central

    2) I want to save battery, each time a discovery service is performed it takes 140-200ms + connection time, skipping it my connections usually takes 40-60ms It makes a big different for a long term run.

    On my setup I have the sensors on the Central and it is my sleepy device, I did it configuration because it fits better to my application

    In the example above I am adding the handle(0), service handle(0x13) and CCCD handle(0x11) manually to the central code,  but it only enables the notifications when peforms a discovery service still the central is using the handles I added manually that does not makes sense for me

    I dont get why I cant do it using the SDK 15.2 if I was doing it since a while using the SDK13

Related