I would like to know if the Notification/Indication of a Characteristic is enabled. I suppose this data is stored in a CCCD on the stack. I have not found any SVC instruction to read this info from the BLE stack.
Where can I access this info?
Thanks for your help.
There are basically 3 ways you can handle this:
A GATT Server has an attribute table, and a characteristic is one type of attribute, others being service declarations, descriptors or actual characteristic values. An attribute have a set of properties…
Of these, I'd recommend using method 1 or method 2. If you only need to send a notification once in a while, it might be ok to just ignore the error with method 1, but you should most definitely not busy-loop on this error. If you need to transfer lots of data, you should be certain that the CCCD has been enabled before starting the transfer.
Edit: Clarify recommendations, and when they don't apply.
Thanks for your quick reply. I am looking at this issue from the peripheral side. I still have few questions about the 3rd way taht you commented above. As an example, I will use part of the code from the battery service. This part is when we are add the Battery Level Characteristic:
// Add Battery Level characteristic
memset(&cccd_md, 0, sizeof(cccd_md));
// According to BAS_SPEC_V10, the read operation on cccd should be possible without
cccd_md.write_perm = p_bas_init->battery_level_char_attr_md.cccd_write_perm;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.char_props.notify = (p_bas->is_notification_supported) ? 1 : 0;
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 = (p_bas->is_notification_supported) ? &cccd_md : NULL;
char_md.p_sccd_md = NULL;
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_bas_init->battery_level_char_attr_md.read_perm;
attr_md.write_perm = p_bas_init->battery_level_char_attr_md.write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
initial_battery_level = p_bas_init->initial_batt_level;
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 = sizeof(uint8_t);
attr_char_value.p_value = &initial_battery_level;
err_code = sd_ble_gatts_characteristic_add(p_bas->service_handle, &char_md,
From my understanding in the we are flagging the client that notification is supported (char_md.char_props.notify = (p_bas->is_notification_supported) ? 1 : 0; ). The characteristic can either support notification or indication. Is that right?
Also, I would like to know if both this information(notification supported flag) and the notification enabled flag are stored in the CCCD attribute. If this is the case, what is the bit order of the CCCD? Where is this info explained?
Finally, is the CCCD handle normally next to the attribute value. For example if the Battery Level attribute value handle is 0x000A we should be expecting the CCCD have the 0x000B handle. Is this right?
A GATT Server has an attribute table, and a characteristic is one type of attribute, others being service declarations, descriptors or actual characteristic values. An attribute have a set of properties, which defines what kind of operations can be done with this attribute. Notifications/indication are two of those operations.
The existence of one of those properties also promises the existence of a CCCD, which is used by the GATT Client to control whether it currently receives Notifications/Indications or not.
I believe that the spec doesn't make a promise the CCCD will be next to the value attribute, but in practice it often is.
For further details, I'd recommend you to read chapter 2.2 of nAN-36, if you haven't already done so: https://www.nordicsemi.com/eng/content/download/34055/573345/file/nAN-36.zip
For even more details, you should refer to the Core Specification itself, Volume 3, Part G and the underlying Part F.
A characteristic can actually support both at once.