This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Sending multiple bluetooth notifications in quick succession (nRF Connect SDK 1.6.1)

Hey all,

I've run into an interesting situation where writing multiple notifications to successively to a multi-characteristic (custom) service causes data loss. Look like it may be similar to the case here: https://devzone.nordicsemi.com/f/nordic-q-a/77381/sending-multiple-notify-packets-per-connection-interval

The service is defined here. All characteristics have unique UUIDs (See below)

#define BT_UUID_ENV_TEMPERATURE_VAL \
    BT_UUID_128_ENCODE(0x12340002, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e)
#define BT_UUID_ENV_HUMIDITY_VAL \
    BT_UUID_128_ENCODE(0x12340003, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e)
#define BT_UUID_ENV_C02_VAL \
    BT_UUID_128_ENCODE(0x12340004, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e)
#define BT_UUID_ENV_PRESURE_VAL \
    BT_UUID_128_ENCODE(0x12340005, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e)

Here's how they're defined (along with some other characteristics)

BT_GATT_SERVICE_DEFINE(env_service,
                       BT_GATT_PRIMARY_SERVICE(BT_UUID_ENV_SERVICE),
                       BT_GATT_CHARACTERISTIC(BT_UUID_ENV_TEMPERATURE, BT_GATT_CHRC_NOTIFY,
                                              BT_GATT_PERM_NONE, NULL, NULL, NULL),
                       BT_GATT_CCC(env_ccc_cfg_changed,
                                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
                       BT_GATT_CHARACTERISTIC(BT_UUID_ENV_HUMIDITY, BT_GATT_CHRC_NOTIFY,
                                              BT_GATT_PERM_NONE, NULL, NULL, NULL),
                       BT_GATT_CCC(env_ccc_cfg_changed,
                                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
                       BT_GATT_CHARACTERISTIC(BT_UUID_ENV_C02, BT_GATT_CHRC_NOTIFY,
                                              BT_GATT_PERM_NONE, NULL, NULL, NULL),
                       BT_GATT_CCC(env_ccc_cfg_changed,
                                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
                       BT_GATT_CHARACTERISTIC(BT_UUID_ENV_PRESSURE, BT_GATT_CHRC_NOTIFY,
                                              BT_GATT_PERM_NONE, NULL, NULL, NULL),
                       BT_GATT_CCC(env_ccc_cfg_changed,
                                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
                       BT_GATT_CHARACTERISTIC(BT_UUID_ENV_AQ, BT_GATT_CHRC_NOTIFY,
                                              BT_GATT_PERM_NONE, NULL, NULL, NULL),
                       BT_GATT_CCC(env_ccc_cfg_changed,
                                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
                       BT_GATT_CHARACTERISTIC(BT_UUID_ENV_PH, BT_GATT_CHRC_NOTIFY,
                                              BT_GATT_PERM_NONE, NULL, NULL, NULL),
                       BT_GATT_CCC(env_ccc_cfg_changed,
                                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
                       BT_GATT_CHARACTERISTIC(BT_UUID_ENV_EC, BT_GATT_CHRC_NOTIFY,
                                              BT_GATT_PERM_NONE, NULL, NULL, NULL),
                       BT_GATT_CCC(env_ccc_cfg_changed,
                                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
                       BT_GATT_CHARACTERISTIC(BT_UUID_ENV_WT, BT_GATT_CHRC_NOTIFY,
                                              BT_GATT_PERM_NONE, NULL, NULL, NULL),
                       BT_GATT_CCC(env_ccc_cfg_changed,
                                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
                                   );

I get no errors when sending and the data shows up ok in the console:

[00:00:16.136,016] <inf> app_ble_service_env: Env service notifications enabled
[00:00:17.208,557] <inf> app_ble_service_env: Env service notifications enabled
[00:00:18.281,066] <inf> app_ble_service_env: Env service notifications enabled
[00:00:19.841,094] <inf> app_ble_service_env: Env service notifications enabled
[00:00:36.554,168] <inf> fluidd_sensors: Fetching Sensor Data Now
[00:00:36.556,335] <inf> fluidd_sensors: Temp: 28.190000
[00:00:36.556,335] <inf> fluidd_sensors: raw hex: 
                                         1c 00 00 00 30 e6 02 00                          |....0...         
[00:00:36.558,532] <inf> fluidd_sensors: Humidity: 51.497000
[00:00:36.558,532] <inf> fluidd_sensors: raw hex: 
                                         33 00 00 00 68 95 07 00                          |3...h...         
[00:00:36.559,387] <inf> fluidd_sensors: C02: 993.0
[00:00:36.559,387] <inf> fluidd_sensors: raw hex: 
                                         e1 03 00 00 00 00 00 00                          |........         
[00:00:36.561,553] <inf> fluidd_sensors: Pressure: 101.5000
[00:00:36.561,645] <inf> fluidd_sensors: raw hex: 
                                         65 00 00 00 88 13 00 00                          |e.......  

When received on the phone side, the first two characteristics usually show up correctly (right data). But the last subscribed characteristic receives the wrong data. I'm assuming there are some limits here (max notifications per interval?) If there's a way to work around this that'd be fantastic.

Here's the data on the phone side using nRF Connect on iOS:

Thanks!

  • Hello,

    Yes, this seems to be the same issue as in this thread. That is currently ongoing, but a workaround has been suggested in this post.

  • Thanks!

    I increase SDC_DEFAULT_TX_PACKET_COUNT but still am having the issue. I'm using a nRF52840 not and nRF53. (not sure if that makes a difference here). 

    The value for the characteristic 12340005 still shows up in characteristic 12340004's value. 12340005 still shows up N/A like the above screenshot.

  • Hi,

    Jared said:
    I increase SDC_DEFAULT_TX_PACKET_COUNT but still am having the issue. I'm using an nRF52840 not and nRF53. (not sure if that makes a difference here). 

    Ah, I see. Adjusting SDC_DEFAULT_TX_PACKET_COUNT should only make a difference on the nRF53.

    Jared said:
    The value for the characteristic 12340005 still shows up in characteristic 12340004's value. 12340005 still shows up N/A like the above screenshot.

    That is odd. Do you have a sniffer trace of this so that we can verify if the issue here is on the nRF side or the mobile side? Also, can you share the relevant part of your code where you send the notifications? Do you check return values from bt_gatt_notify_cb() / bt_gatt_notify() for instance?

  • Values got to an event manager. Data is allocated on the heap. app_ble_publish_sensor_data is called

            case APP_EVENT_SENSOR_DATA:
    
                /* Publish sensor data to BLE */
                err = app_ble_publish_sensor_data(evt.sensor_data);
                if (err)
                    LOG_WRN("Publish err: %i", err);
    
                k_free(evt.sensor_data);
    
                break;

    app_ble_publish_sensor_data looks like this

    /* TODO: handle other data? */
    int app_ble_publish_sensor_data(env_sensor_data_t *data)
    {
        /* Publish env data*/
        return app_ble_environment_publish(NULL, data);
    }

    and the final function looks like this:

    int app_ble_environment_publish(struct bt_conn *conn, const env_sensor_data_t *data)
    {
        struct bt_gatt_notify_params params = {0};
        const struct bt_gatt_attr *attr = NULL;
    
        switch (data->type)
        {
        case ENV_SENSOR_TEMPERATURE:
            attr = &env_service.attrs[ENV_TEMP_ATTR_POS];
            break;
        case ENV_SENSOR_HUMIDITY:
            attr = &env_service.attrs[ENV_HUMIDITY_ATTR_POS];
            break;
        case ENV_SENSOR_CO2:
            attr = &env_service.attrs[ENV_C02_ATTR_POS];
            break;
        case ENV_SENSOR_AIR_PRESSURE:
            attr = &env_service.attrs[ENV_PRESSURE_ATTR_POS];
            break;
        case ENV_SENSOR_AIR_QUALITY:
            attr = &env_service.attrs[ENV_AQ_ATTR_POS];
            break;
        case ENV_SENSOR_FLUIDDPHEC_CHAN_PH:
            attr = &env_service.attrs[ENV_PH_ATTR_POS];
            break;
        case ENV_SENSOR_FLUIDDPHEC_CHAN_EC:
            attr = &env_service.attrs[ENV_EC_ATTR_POS];
            break;
        case ENV_SENSOR_FLUIDDPHEC_CHAN_WT:
            attr = &env_service.attrs[ENV_WT_ATTR_POS];
            break;
        default:
            /* Return invalid input error */
            return -EINVAL;
        }
    
        /* Return error if not valid or handled */
        if (attr == NULL)
        {
            LOG_ERR("Unknown data type: %i", data->type);
            return -EINVAL;
        }
    
        params.attr = attr;
        params.data = &data->value;
        params.len = sizeof(data->value);
        params.func = NULL;
    
        if (!conn)
        {
            LOG_DBG("Notification send to all connected peers");
            return bt_gatt_notify_cb(NULL, &params);
        }
        else if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY))
        {
            return bt_gatt_notify_cb(conn, &params);
        }
        else
        {
            return -EINVAL;
        }
    }

    I seem to remember that some BT functions are async. I tried statically allocating the values earlier but didn't have much luck.

    Here are the attribute position values btw:

    /* Make sure this is updated to match BT_GATT_SERVICE_DEFINE below */
    enum app_ble_environment_char_position
    {
        ENV_TEMP_ATTR_POS = 2,
        ENV_HUMIDITY_ATTR_POS = 4,
        ENV_C02_ATTR_POS = 6,
        ENV_PRESSURE_ATTR_POS = 8,
        ENV_AQ_ATTR_POS = 10,
        ENV_PH_ATTR_POS = 12,
        ENV_EC_ATTR_POS = 14,
        ENV_WT_ATTR_POS = 16,
    };

  • I'm trying to get a sniffer trace as well but not sure if I'm getting the full connection details. So far I can see the advertising and connection request. After that nothing. I'm using just works pairing no bonding etc.

    Here's my filter:

    (btle.advertising_address == e7:60:41:d9:f2:72) || (btle.initiator_address == 55:44:8b:f6:98:3e)

    If there's a better way to filter please let me know:

    1401.capture.pcapng

Related