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

Detect which handle needs to be notified to the BLE Client

I have custom service, where I have declared 2 handles inside BLE Service structure, one for button action and the other for custom battery ADC measurement, each identified by its characteristic's UUID:

ble_gatts_char_handles_t    button_char_handles; /**< Handles related to the Button Characteristic. */
ble_gatts_char_handles_t    battery_char_handles; /**< Handles related to the LiPo Characteristic. */

I successfully initialize both handles and add them to my service. Now I like to send regular updates only to battery characteristic after BLE client (=my phone) connects, therefore I added app_timer, which repeatedly fires each n seconds:

err_code = app_timer_start(m_start_sending_data_timer_id, START_SENDING_DATA_DELAY, NULL);
APP_ERROR_CHECK(err_code);

...and sends 4-byte long float inside BLE_GATT_HVX_NOTIFICATION:

uint32_t ble_send_on_battery_level_change(ble_skiwatt_t * p_skiwatt, float voltage)
{
    ble_gatts_hvx_params_t params;
    uint16_t len = sizeof(voltage);

    memset(&params, 0, sizeof(params));
    params.type = BLE_GATT_HVX_NOTIFICATION;
    params.handle = p_skiwatt->battery_char_handles.value_handle;
    params.p_data = (uint8_t*)&voltage;
    params.p_len = &len;

    return (sd_ble_gatts_hvx(p_skiwatt->conn_handle, &params));
}

Whatsoever, if I connect my board with "Android nRF Connect APP" on my phone, I get NRF ERROR 0x3401 in case I do not set gatt.setCharacteristicNotification() for this characteristic on my phone BEFORE first notification takes place. Therefore, I wait for GATT Client Event BLE_GATTC_EVT_CHAR_DISC_RSP (0x50) in main.c inside function static void on_ble_evt(ble_evt_t * p_ble_evt), before start sending notification packets.

Now I wonder:

how can I detect for which handle (button_char_handles or battery_char_handles) the notification status was changed?

  • I'm assuming that you meant BLE_GATTS_EVT_WRITE, which is 0x50, not BLE_GATTC_EVT_CHAR_DISC_RSP.

    You need to compare the attribute handle in the write event with the attribute handles of the CCCDs.

    The attribute handle in the write event can be found at

    p_ble_evt->evt.gatts_evt.params.write.handle

    The attribute handles of the CCCDs will be available in the ble_gatts_char_handles_t struct after you have called sd_ble_gatts_characteristic_add().

  • Wow, thanks Petter, it works out of the box! I ended up at with this piece of code, where I catch ble events inside function static void on_ble_evt(ble_evt_t * p_ble_evt):

    case BLE_GATTS_EVT_WRITE:
            { // <-- this is necessary, since in C there isn't any clause that allows for a "labeled declaration" in lines below.
            	uint16_t handle_received = p_ble_evt->evt.gatts_evt.params.write.handle;
            	uint16_t batt_cccd = m_skiwatt.battery_char_handles.cccd_handle;
            	uint16_t button_cccd = m_skiwatt.button_char_handles.cccd_handle;
    
            	NRF_LOG_DEBUG("Write handle: %08x\r\n", handle_received);
            	if (handle_received == batt_cccd)
            	{
            		curr_cccd = CCCD_IS_BATTERY_1_LEVEL;
            		NRF_LOG_DEBUG("User ask for battery notifications\r\n");
            	}
            	if (handle_received == button_cccd)
    			{
            		curr_cccd = CCCD_IS_BUTTON;
    				NRF_LOG_DEBUG("User ask for button notifications\r\n");
    			}
            } break;
    

    Hope someone will find it useful.

Related