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.

Related