BLE notify for several characteristics

I seem to be struggling getting several characteristics to notify on my nrf52840 - peripheral device.

I can get ONE to notify, but when I add more then notifications stop. The reads work perfectly well, but I need several characteristics to actively notify.

This is my working "pseudo" code:

________________________________

BT_GATT_SERVICE_DEFINE(atlas_sensors_srv,
    BT_GATT_PRIMARY_SERVICE(BT_UUID_ATLAS_SLAVE_SENSORS),
    BT_GATT_CHARACTERISTIC(BT_UUID_TEMPERATURE_CHRC,  BT_GATT_CHRC_READ,
                           BT_GATT_PERM_READ, my_read_temperature_function, NULL, NULL),
    BT_GATT_CHARACTERISTIC(BT_UUID_WEIGHT_CHRC, BT_GATT_CHRC_NOTIFY,
                           BT_GATT_PERM_NONE, NULL, NULL, NULL),
                               BT_GATT_CCC(weight_ccc_cfg_changed,
                BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
    BT_GATT_CHARACTERISTIC(BT_UUID_LOCATION_CHRC, BT_GATT_CHRC_READ,
                           BT_GATT_PERM_READ, my_read_location_function, NULL, NULL),
    BT_GATT_CHARACTERISTIC(BT_UUID_BATTERY_CHRC, BT_GATT_CHRC_READ,
                           BT_GATT_PERM_READ, my_read_battery_function, NULL, NULL)
);
// CCCD configuration changed callback
void weight_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
    bool notify_enabled = (value == BT_GATT_CCC_NOTIFY);
    printk("Notifications weight %s\n", notify_enabled ? "enabled" : "disabled");
}
void temp_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
    bool notify_enabled = (value == BT_GATT_CCC_NOTIFY);
    printk("Notifications temperature %s\n", notify_enabled ? "enabled" : "disabled");
}

int err = bt_gatt_notify(NULL, &atlas_sensors_srv.attrs[3], &weight_custom ,sizeof(weight_custom));

int err = bt_gatt_notify(NULL, &atlas_sensors_srv.attrs[2], &temperature_custom ,sizeof(temperature_custom));

________________________________

(in the example above temperature does not notify, and the bt_gatt_notify for this will of course not work. I know that. But I can read it (my_read_temperature_function is not shown, but works). When I connect to my device (using nfr Connect) and subscribe - all is well. I get the updates. 

However I activate notify for the temperaure:

_________________________________

BT_GATT_SERVICE_DEFINE(atlas_sensors_srv,
    BT_GATT_PRIMARY_SERVICE(BT_UUID_ATLAS_SLAVE_SENSORS),
    BT_GATT_CHARACTERISTIC(BT_UUID_TEMPERATURE_CHRC,  BT_GATT_CHRC_NOTIFY,
                           BT_GATT_PERM_NONE, NULL, NULL, NULL),
                               BT_GATT_CCC(temp_ccc_cfg_changed,
                BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
    BT_GATT_CHARACTERISTIC(BT_UUID_WEIGHT_CHRC, BT_GATT_CHRC_NOTIFY,
                           BT_GATT_PERM_NONE, NULL, NULL, NULL),
                               BT_GATT_CCC(weight_ccc_cfg_changed,
                BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
    BT_GATT_CHARACTERISTIC(BT_UUID_LOCATION_CHRC, BT_GATT_CHRC_READ,
                           BT_GATT_PERM_READ, my_read_location_function, NULL, NULL),
    BT_GATT_CHARACTERISTIC(BT_UUID_BATTERY_CHRC, BT_GATT_CHRC_READ,
                           BT_GATT_PERM_READ, my_read_battery_function, NULL, NULL)
);
_________________________________ 

The both characteristics show up, and I can subscribe to both. But ONLY the temperature actually updates.

Somehow the notifications for the weigh stops when I also add temperature.

I only have this problem with a custom service. The problem is with CCCD - but I cannot see what!
Do I need to limit it to one notify per custom service? that seems a bit strange.
Sorry for the newbie question - but Im getting there!


here is my prj.conf
__________________________________

# BLE
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Altlas FR"
CONFIG_BT_DEVICE_APPEARANCE=0
__________________________________
  • I only have this problem with a custom service. The problem is with CCCD - but I cannot see what!
    Do I need to limit it to one notify per custom service? that seems a bit strange.
    Sorry for the newbie question - but Im getting there!

    No, you can have as many notifications as the memory allows in the controller.  Not sure why you are not able to get notifications from both. Can you give me your simplistic project, so that I can test it on the DK and see why you are not able to get the notifications on both? 

  • one_notify.ziptwo_notify.zip

    OK. I have now stripped this down to be bone. The problem still presists. 

    I have one custom service, and 4 characteristics. There are two threads each updating one characteristic.
    "one_nofity" works, while "two_notify" does not. I am using nrf52840dk, but I guess it should compile under any nrf52

    Bjorn

  • The index for the attributes you were using was wrong.

    Use these indexes instead 

    void update_weight(int32_t new_weight) {
    
    int err;
    
        if (new_weight > INT16_MAX) {
            // Handle overflow, clamp to max value
            weight_custom = INT16_MAX;
        } else if (new_weight < INT16_MIN) {
            // Handle underflow, clamp to min value
            weight_custom = INT16_MIN;
        } else {
            // Safe conversion to int16_t
            weight_custom = (int16_t)new_weight;
        }
        bt_gatt_notify(NULL, &atlas_sensors_srv.attrs[4], &weight_custom ,sizeof(weight_custom));
    
        if (err) {
            LOG_ERR("update_weight: Failed to send data over BT: %d", err);
        }
    
    }
    
    void update_temperature(int32_t new_temperature) {
        int err;
    
        if (new_temperature > INT16_MAX) {
            // Handle overflow, clamp to max value
            temperature_custom = INT16_MAX;
        } else if (new_temperature < INT16_MIN) {
            // Handle underflow, clamp to min value
            temperature_custom = INT16_MIN;
        } else {
            // Safe conversion to int16_t
            temperature_custom = (int16_t)new_temperature;
        }
        printk("temperature sent %i",temperature_custom);
        err = bt_gatt_notify(NULL, &atlas_sensors_srv.attrs[1], &temperature_custom ,sizeof(temperature_custom));
    
        if (err) {
            LOG_ERR("update_temperature: Failed to send data over BT: %d", err);
        }
    }

    notice that I changed 

    &atlas_sensors_srv.attrs index for notifying temperature and weight

  • Thank you.
    I would believe that temperature should be "2" since the service itself is "1" (2 also works).
    is weight "4" because BT_GATT_CCC adds another index? the weight characteristics immediately follows the temperature.

    2 and 4 works (as well does 1 and 4) 

  • Yes, you need to understand the attribute table to be able to send the notification on the right characteristic. The characteristic comprises of two attributes, so giving the index of any one of the two attributes within the characteristic seems to work.

Related