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

How do I access the "More Data Bit" in data header of a notification received as Central.

We have an NRF52 set up as Central, connecting to a peripheral (not our own) that's sending notifications with Data>20 bytes

I'm trying to differentiate between it sending two seperate sets of bytes 20 then 10, or a single set of 30 bytes, as an example.

I was hoping to use params.offset, but this is only available for writes and reads, not for receiving notifications. (from a quick look through devzone, it does appear to be available when sending a notification as a peripheral though?).

Before digging further into this only to possibly find out that the peripheral is not even sending an offset, I sniffed the communication, as attached.

The interesting difference I see is the "More Data" bit in the Data header

Data Header: 0x1b16
        .... ..10 = LLID: Start of an L2CAP message or a complete L2CAP message with no fragmentation (0x2)
        .... .1.. = Next Expected Sequence Number: 1
        .... 0... = Sequence Number: 0 [OK]
        ...1 .... = More Data: True
        000. .... = RFU: 0

vs

Data Header: 0x110a
        .... ..10 = LLID: Start of an L2CAP message or a complete L2CAP message with no fragmentation (0x2)
        .... .0.. = Next Expected Sequence Number: 0
        .... 1... = Sequence Number: 1 [OK]
        ...0 .... = More Data: False
        000. .... = RFU: 0

how can I access that info (or any derivation of that info), so that if there is more to come, I buffer the first notification, and wait for the rest of the data in the next notification before further processing it?

p_ble_evt->evt.gattc_evt.params.hvx only contains data, handle, len and type - none of which reflects the More Data info.

Thanks already!

No.     Time     Source                PHY        Protocol Length     Delta time (µs end to start) SN         NESN       More Data  Event counter Info
    363 12.471   Slave_0x1376ef35      LE 1M      ATT      27         151                           0          1          True       151           Rcvd Handle Value Notification, Handle: 0x0017 (Unknown: Unknown)

Frame 363: 53 bytes on wire (424 bits), 53 bytes captured (424 bits) on interface 0
Nordic BLE Sniffer
Bluetooth Low Energy Link Layer
    Access Address: 0x1376ef35
    [Master Address: XX:XX:XX:XX:XX:XX (XX:XX:XX:XX:XX:XX)]
    [Slave Address: XX:XX:XX:XX:XX:XX (XX:XX:XX:XX:XX:XX)]
    Data Header: 0x1b16
        .... ..10 = LLID: Start of an L2CAP message or a complete L2CAP message with no fragmentation (0x2)
        .... .1.. = Next Expected Sequence Number: 1
        .... 0... = Sequence Number: 0 [OK]
        ...1 .... = More Data: True
        000. .... = RFU: 0
        Length: 27
    [L2CAP Index: 33]
    CRC: 0x1606b1
Bluetooth L2CAP Protocol
    Length: 23
    CID: Attribute Protocol (0x0004)
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
        0... .... = Authentication Signature: False
        .0.. .... = Command: False
        ..01 1011 = Method: Handle Value Notification (0x1b)
    Handle: 0x0017 (Unknown)
        [UUID: 720330f41db74fd7ae5a87e5bd942880]
    Value: 3132333435363738393031323334353637383930

No.     Time     Source                PHY        Protocol Length     Delta time (µs end to start) SN         NESN       More Data  Event counter Info
    365 12.473   Slave_0x1376ef35      LE 1M      ATT      17         151                           1          0          False      151           Rcvd Handle Value Notification, Handle: 0x0017 (Unknown: Unknown)

Frame 365: 43 bytes on wire (344 bits), 43 bytes captured (344 bits) on interface 0
Nordic BLE Sniffer
Bluetooth Low Energy Link Layer
    Access Address: 0x1376ef35
    [Master Address: XX:XX:XX:XX:XX:XX (XX:XX:XX:XX:XX:XX)]
    [Slave Address: XX:XX:XX:XX:XX:XX (XX:XX:XX:XX:XX:XX)]
    Data Header: 0x110a
        .... ..10 = LLID: Start of an L2CAP message or a complete L2CAP message with no fragmentation (0x2)
        .... .0.. = Next Expected Sequence Number: 0
        .... 1... = Sequence Number: 1 [OK]
        ...0 .... = More Data: False
        000. .... = RFU: 0
        Length: 17
    [L2CAP Index: 34]
    CRC: 0x627f49
Bluetooth L2CAP Protocol
    Length: 13
    CID: Attribute Protocol (0x0004)
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
        0... .... = Authentication Signature: False
        .0.. .... = Command: False
        ..01 1011 = Method: Handle Value Notification (0x1b)
    Handle: 0x0017 (Unknown)
        [UUID: 720330f41db74fd7ae5a87e5bd942880]
    Value: 3132333435363738390d

[EDIT:] I know I could wait for the 0x0d at the end if I'm expecting that, but that's not guaranteed to be sent, so I can't rely on it.

  • Hello,

    The More Data bit is stripped away by the softdevice. 

    What SDK version do you use?

    The reason I ask is that in the later versions, you can send much larger packets than this. Either way, the More Data bit wouldn't necessarily be set to false even though it was the last packet of that specific message (ending with 0x0d). If you have queued more packets, maybe from the next message before the previous packet was sent, the More Data bit will still be set to 1. This bit only indicates whether the device intends to send more packets during the same connection interval or not. It may not even be a notification, but some Link Layer packet. Therefore, you can't rely on this bit to see whether there is more data from your peripheral's service.

    I see that your peripheral is "not your own", so it may be difficult to change the way it behaves, but in short. The notification you get should be the same packet as the peripheral queued. If it splits up a large message into 20 byte chunks, then you have to interpret this in the application layer. 

    Best regards,

    Edvin

  • Right. I read up some more on the More Data Bit after posting my question, and realized that too - it just means there's an other packet following this one in the same Connection Event, not that they belong together. Too bad.

    We're using SDK 15 btw. Yeah, with other connections we can use larger MTU and send more data, but since this peripheral we connect to is not our product, we can't change its behaviour.

    I have implemented a workaround in the application layer, but it's not perfect, so I'm just checking my options.

    So how about this:

    I was hoping to use params.offset, but this is only available for writes and reads, not for receiving notifications.

    It does look like as a peripheral, I do have the option to specify an offset parameter, but as central, I don't

    Peripheral:

    /**@brief GATT HVx parameters. */
    typedef struct
    {
      uint16_t          handle;             /**< Characteristic Value Handle. */
      uint8_t           type;               /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */
      uint16_t          offset;             /**< Offset within the attribute value. */
      uint16_t         *p_len;              /**< Length in bytes to be written, length in bytes written after return. */
      uint8_t const    *p_data;             /**< Actual data content, use NULL to use the current attribute value. */
    } ble_gatts_hvx_params_t;

    Central:

    /**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */
    typedef struct
    {
      uint16_t            handle;         /**< Handle to which the HVx operation applies. */
      uint8_t             type;           /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */
      uint16_t            len;            /**< Attribute data length. */
      uint8_t             data[1];        /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
                                               See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
    } ble_gattc_evt_hvx_t;
    

    I still don't know if the peripheral is actually specifying an offset, (I couldn't make anything out in the sniffed data), but in the SDK, why is there this difference between central and peripheral?

  • Hello,

    This is because the peripheral should be able to use a buffer and specify an offset to where you want to start sending the data. It can be used e.g. if you have already sent a packet of 20 bytes, but you don't want to update the buffer, just send the next part of the buffer. In that case you can set the offset to 20. However, the packet over the air doesn't contain this offset parameter, so that is why it isn't included in the central implementation. On air, it will just look like any other packet.

    Best regards,

    Edvin

  • Ok. Makes sense. too bad though. Thanks for the confirmation!

    I'll find a way to deal with it in the application layer.

Related