How to create robust BLE transmission and messages between an embedded device and mobile app for large amounts of data? (General design question)

This is a higher-level question because I'm having difficulty finding concise and clear practices for this sort of thing. I don't want to go implementing something subpar.

I have a mobile application which pairs to my embedded device. The device has characteristics for states, commands, and data. The app periodically reads states to determine what the device is doing. It writes commands, which the device handles and runs. When executing a command, the device then steams data notifications during it's measurement.

Each point is sent as an individual notification and consists of 6 bytes. There are typically several thousand points and the app receives every notification. This is clearly not something that will work in a real-world product.

There are several points of concern

  • What if the app disconnects during the measurement?

The device will still be running the measurement but all data after disconnection will be lost. The firmware should store unsent data in flash. Should I allow partial transmission during measurement or first store all data then send it all?

  • Packet formatting

Based on the agreed upon MTU, I should transmit data chunks rather than each individual point. Is there an optimal method to do this or is this typically application-dependent?

  • Acknowledgement

My understanding is that I can use indications which have built-in acknowledgement. However, should I also add an application-layer acknowledgement message? The packet would be retransmitted if no ACK was received after some time and that associated sequence number would be used to rebuild the data.

  • Error checking and handling

BLE has it's own error checking built into the protocol so no application CRC is needed.

  • Data reconstruction

The app needs to know which packet chunk goes in which order to decode and reconstruct the data. Therefore, should a sequence number be added to each chunk? This would also be used for the acknowledgement characteristic before the device sends the next packet to the app.

This is my overall thought for how I would implement a service with the above points in mind:

Characteristics:
    Device Status      (read only, int)
        - Idle, Measuring, Sending
    Control            (write only, int)
        - Start, Stop
    Command Parameters (read and write, packet)
        - How to run the measurement
    Data               (read only, packet)
        - Measurement points
    CCCD               (read and write, bool)
        - Indications for Data
    Data Send          (write only, bool)
        - Initiate the device to start data send procedure
    Data Ack           (write only, int)
        - Sequence number acknowledgement
    Data Remaining     (read only, int)
        - How many packets are left to read

It would then have the following flow chart:

I'm thinking it would be best to store all data in flash first then transmit at the end once the app requests it. A timer and sequence number acknowledgements are then used to transmit data until it's all been sent successfully.

Each packet would have the sequence number for reconstruction as well as the number of points within the packet for decoding. The last sequence number would be determined by the app reading the Data Remaining characteristic before writing to Data Send to put the device in send mode.

Does this seems like a decent plan? Please let me know a better or easier way to do this.

Parents
  • Hello,

    I am sorry for the late reply.

    Ok, let us try to figure this out. Just in case we want to point at some API, what SDK do you intend to use? The nRF5 SDK (which is the "old" SDK used while the nRF52 series was launched. It works, but is in maintenance mode), or do you want to use the new nRF Connect SDK ("NCS", which is our "current" SDK). Regardless of what SDK you are using, the BLE stack and protocol is the same, so let's try to answer your questions:

    What if the app disconnects during the measurement?

    Let us save this for later.

    Packet formatting

    This depends on your needs. How much data are we talking in a total measurement? And how often is this being sent? If you need a high throughput, chunking the samples together in bigger packets and using a large MTU is preferable, as it gives a larger payload/header ratio. This allows for up to the 1.3MBPS payload throughput, which is the maximum allowed by the current BLE specification.

    Acknowledgement

    All packets in BLE are acknowledged, or retransmitted until they are. So this is not really the intention for indications. Notifications should be more than fine for data transfer. Indications, which are application controlled acknowledgment, as you said, are intended for other mechanisms, such as in a doorlock, you can confirm that the door is locked (and not for example jammed) before you send the application acknowledgement back to the central. Using indications instead of notifications gives a significant decrease in throughput.

    Error checking and handling

    That is correct. The CRC is checked by the BLE stack before the AKC is sent, so you can know that all data that is acked is also correct. 

    Data reconstruction

    You are guaranteed that the packets will enter the receiver's application the same order that they were queued in the transmitter's application. However, if you'd like, you can add some sequence numbering if you want to know how much data is left. I imagine this can replace the need for a "more data" characteristic, which may take up bandwidth, e.g. by saying that the first byte or two describes how much data is left of the transfer. 

    What if the app disconnects during the measurement?

    So back to this. I chose to save it for last since it is the question that complicates all of the questions, really. In general, BLE is a lossless protocol. This doesn't mean that you don't have packet loss, because you certainly do. But the protocol guarantees that all queued packets are transmitted, "and it will die trying". So in this case, "die" means disconnect. As long as you queue a packet, and the link is still connected after the supervision timeout period, the packet has been delivered. If the packet was not received within this period, it means that the devices has not received a packet with the correct CRC within this period, and the link is considered disconnected. 

    So what is the source of your disconnect? Dead battery? The devices are moving too far apart? An increase in RF noise? Depending on the reason, you may or may not want to introduce saving data to flash. If you don't think power loss is a likely issue, then I wouldn't bother saving data to flash, as long as you are able to store a large enough buffer in RAM. However, if you experience a disconnect, you may want to keep track of what data that is actually sent and ACKed. For this, we have callbacks that you can use to determine what packets that was successfully ACKed (what API and callbacks depends on your SDK). If the issue is that they have a poor connection, I would try to increase the supervision timeout, since this will make them try to communicate for longer before disconnecting the link. The disadvantage of this is that it takes longer for the disconnection to happen and your app to "know", but the advantage is that all your queued packets are still queued, and you don't have to deal with the disconnect/connect handling, and figure out what packets that wasn't ACKed. 

    Really, it depends on the consequences of your partially transmitted measurements. What is the impact of a disconnect? Can you do another measurement, and throw away the old one? 

    Hopefully this gives the answer to some of your questions. Perhaps you can elaborate a bit more on the consequences of a partially received measurement? It is possible to store the data in flash, but if the consequences aren't that high, the application structure is way easier if you don't need to think about this. 

    Best regards,

    Edvin

Reply
  • Hello,

    I am sorry for the late reply.

    Ok, let us try to figure this out. Just in case we want to point at some API, what SDK do you intend to use? The nRF5 SDK (which is the "old" SDK used while the nRF52 series was launched. It works, but is in maintenance mode), or do you want to use the new nRF Connect SDK ("NCS", which is our "current" SDK). Regardless of what SDK you are using, the BLE stack and protocol is the same, so let's try to answer your questions:

    What if the app disconnects during the measurement?

    Let us save this for later.

    Packet formatting

    This depends on your needs. How much data are we talking in a total measurement? And how often is this being sent? If you need a high throughput, chunking the samples together in bigger packets and using a large MTU is preferable, as it gives a larger payload/header ratio. This allows for up to the 1.3MBPS payload throughput, which is the maximum allowed by the current BLE specification.

    Acknowledgement

    All packets in BLE are acknowledged, or retransmitted until they are. So this is not really the intention for indications. Notifications should be more than fine for data transfer. Indications, which are application controlled acknowledgment, as you said, are intended for other mechanisms, such as in a doorlock, you can confirm that the door is locked (and not for example jammed) before you send the application acknowledgement back to the central. Using indications instead of notifications gives a significant decrease in throughput.

    Error checking and handling

    That is correct. The CRC is checked by the BLE stack before the AKC is sent, so you can know that all data that is acked is also correct. 

    Data reconstruction

    You are guaranteed that the packets will enter the receiver's application the same order that they were queued in the transmitter's application. However, if you'd like, you can add some sequence numbering if you want to know how much data is left. I imagine this can replace the need for a "more data" characteristic, which may take up bandwidth, e.g. by saying that the first byte or two describes how much data is left of the transfer. 

    What if the app disconnects during the measurement?

    So back to this. I chose to save it for last since it is the question that complicates all of the questions, really. In general, BLE is a lossless protocol. This doesn't mean that you don't have packet loss, because you certainly do. But the protocol guarantees that all queued packets are transmitted, "and it will die trying". So in this case, "die" means disconnect. As long as you queue a packet, and the link is still connected after the supervision timeout period, the packet has been delivered. If the packet was not received within this period, it means that the devices has not received a packet with the correct CRC within this period, and the link is considered disconnected. 

    So what is the source of your disconnect? Dead battery? The devices are moving too far apart? An increase in RF noise? Depending on the reason, you may or may not want to introduce saving data to flash. If you don't think power loss is a likely issue, then I wouldn't bother saving data to flash, as long as you are able to store a large enough buffer in RAM. However, if you experience a disconnect, you may want to keep track of what data that is actually sent and ACKed. For this, we have callbacks that you can use to determine what packets that was successfully ACKed (what API and callbacks depends on your SDK). If the issue is that they have a poor connection, I would try to increase the supervision timeout, since this will make them try to communicate for longer before disconnecting the link. The disadvantage of this is that it takes longer for the disconnection to happen and your app to "know", but the advantage is that all your queued packets are still queued, and you don't have to deal with the disconnect/connect handling, and figure out what packets that wasn't ACKed. 

    Really, it depends on the consequences of your partially transmitted measurements. What is the impact of a disconnect? Can you do another measurement, and throw away the old one? 

    Hopefully this gives the answer to some of your questions. Perhaps you can elaborate a bit more on the consequences of a partially received measurement? It is possible to store the data in flash, but if the consequences aren't that high, the application structure is way easier if you don't need to think about this. 

    Best regards,

    Edvin

Children
No Data
Related