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

Automatically start notification upon connection event (manually write cccd?) - Short tutorial on notifications


I want to implement a Peripheral (GATT Server) that automatically starts notification once a Central connects. No bonding is provided in our system (connection is between arbitrary devices).

I have read several times that notifications must be initiated by the GATT Client. But when a bonding exists between the devices, the former configuration (e.g. notification) is restored upon connection. It sounds like the device manager is able to restore the notification state (cccd) at the moment a connection is established.

Can this be done manually / in my own code, e.g. by writing to cccd? I couldn't find any SD interface function that enables notifications. Manually writing to cccd results in error code 15 (NRF_ERROR_FORBIDDEN).

My code looks something like this...

static void on_connect(ble_myservice_t* p_service, ble_evt_t* p_event)
    uint32_t result;
    ble_gatts_value_t value;
    uint16_t data;

    p_service->conn_handle = p_event->evt.gap_evt.conn_handle;

    // Seems we need this, otherwise sd_ble_gatts_hvx() fails
    result = sd_ble_gatts_sys_attr_set(p_service->conn_handle, NULL, 0, 0);

    // Just for robustness, check for valid cccd handle
    if (p_service->mydata_handles.cccd_handle)
        data = 1;  // 1 = Enable notifications
        value.len = 2;
        value.offset = 0;
        value.p_value = (uint8_t*)(&data);
        result = sd_ble_gatts_value_set(p_service->conn_handle, p_service->mydata_handles.cccd_handle, &value);
        // Here we get error 15 (NRF_ERROR_FORBIDDEN)

Any suggestions? Or is the only way to write to cccd from the Central / GATT Client each time (which will cause additional latency that I would like to avoid)?

Update: I tried to update cccd after connection establishment by directly using the handle (which fails). After some research, it seems like ´sd_ble_gatts_sys_attr_set()´is used for setting cccd values. But I can nowhere find any specification about the buffer content that is handed over to ´sd_ble_gatts_sys_attr_set()´... shouldn't this be in the documentation at

  • The cccd handle value in my case was 14. So it seems we need to calculate the CRC value in the application itself as it may vary.  CRC value can be calculated using crc16_compute( ) API. This API is provided by Nordic. 

    buffer[0] = p_nus->tx_handles.cccd_handle;                  // cccd handle
    buffer[1] = 2;                                              // cccd attribute size = 2
    buffer[2] = 1;                                              // 1 = enable notifications
    buffer[3] = crc16_compute((uint8_t const *)buffer,  6, NULL); // calculate CRC-CCITT (0xFFFF);

    This will also take care of any change in the cccd handle value

  • Hi, 

    I try to enable notification of CCCD to send data over Bluetooth from my device to my phone. So in the function on_connect, I enable notifications with this code

        uint16_t buffer[4];
        buffer[0] = p_nus->rx_handles.cccd_handle;                     //cccd handle
        buffer[1] = 2;                                                 //cccd attribute size = 2
        buffer[2] = 1;                                                  //1 = enable notifications
        buffer[3] = crc16_compute((uint8_t const*)buffer, 6, NULL);    //CR-CCITT 
        sd_ble_gatts_sys_attr_set(p_ble_evt->evt.gap_evt.conn_handle, (uint8_t*)(buffer), 8, 0);   //initialize cccd attribute

    but I still have the same mistake: NRF_ERROR_INVALID_STATE which means notification disabled. So why there are no enabled?