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

How to know if the Notification/Indication of a Characteristic is enabled?

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.

Parents
  • Hi Ole,

    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
        if (p_bas->is_notification_supported)
        {
            memset(&cccd_md, 0, sizeof(cccd_md));
        
            // According to BAS_SPEC_V10, the read operation on cccd should be possible without
            // authentication.
            BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
            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;
        
        BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BATTERY_LEVEL_CHAR);
        
        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,
                                                   &attr_char_value,
                                                   &p_bas->battery_level_handles);
    

    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?

Reply
  • Hi Ole,

    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
        if (p_bas->is_notification_supported)
        {
            memset(&cccd_md, 0, sizeof(cccd_md));
        
            // According to BAS_SPEC_V10, the read operation on cccd should be possible without
            // authentication.
            BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
            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;
        
        BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BATTERY_LEVEL_CHAR);
        
        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,
                                                   &attr_char_value,
                                                   &p_bas->battery_level_handles);
    

    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?

Children
  • 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.

Related