Data loss during data transfer

Hello everyone,

at the moment I am working on a BLE program which collects data from various sensors and passes it to a Central device.
For the transmission the BLE NUS service is used. When the peripheral device collects data from sensor, the advertising is started
and tries to connect to the central device. If this connection is successful, the data from the peripheral device is sent to the central device using the ble_nus_data_send() function. After each call of ble_nus_data_send() the event BLE_NUS_EVT_TX_RDY is waited for and only then the next data is transferred. If I send 300 to 400 records, 1-2 records will be lost.

Is it ensured, if I wait for the event BLE_NUS_EVT_TX_RDY, that these data really arrived at the central device?

Or is it better that the central device confirms every single data record from the peripheral device?

Central device:

-> SoftDevice version: 7.0.1 (S132)

-> Hardware: nRF52810

Peripheral device:

-> SoftDevice version: 7.0.1 (S113)

-> Hardware: nRF52805

Thanks for your help!

Parents
  • Hello,

    If I send 300 to 400 records, 1-2 records will be lost.

    Are you checking the returned error code from your call to ble_nus_data_send? Is it always NRF_SUCCESS?
    Are you passing the returned error code to an APP_ERROR_CHECK, for instance?
    If so, please make sure to have DEBUG defined in your preprocessor defines, like shown in the included image:


    This will make your logger output a detailed error message whenever a non-NRF_SUCCESS error code is passed to an APP_ERROR_CHECK.

    Or is it better that the central device confirms every single data record from the peripheral device?

    This happens as part of the BLE protocol - each packet will either be acknowledged by the peer, or retried by the sender.
    BLE is lossless; data is never lost in the BLE Link - once it has been queued for transfer it will either be transferred, or the link will be terminated. That is to say; if the transmissions fail for whatever reason, the device will keep trying to send the same data until it receives acknowledgement that it was successfully received, or the link will be terminated with the connection supervision timeout.
    There is however no guarantee against the application itself loosing data, such as if the ble_nus_data_send function returns with a non-NRF_SUCCESS error code, while the application keeps going as if it was successful. Could this be the case in your application?

    Best regards,
    Karl

  • Thanks for your answer Karl   

        Are you checking the returned error code from your call to ble_nus_data_send? Is it always NRF_SUCCESS?  Are you        passing the returned error code to an APP_ERROR_CHECK, for instance?

    With each call to ble_nus_data_send() the return code is evaluated. If the return code is NRF_SUCCESS, then the program waits for the event BLE_NUS_EVT_TX_RDY, otherwise it waits a short time and repeats the send operation.  The function APP_ERROR_CHECK is not called, because the call of these functions leads to a reboot of the system. In this case, the counters of the dataset would be reset, which I actually want to avoid. 

    Best regards,

    Ron

  • Hello Ron,

    Ron Weber said:
    Thanks for your answer

    No problem at all, I am happy to help! :) 

    Ron Weber said:
    The function APP_ERROR_CHECK is not called, because the call of these functions leads to a reboot of the system. In this case, the counters of the dataset would be reset, which I actually want to avoid. 

    I understand. Could you at least print out the error code, so we could know if it just fails due to resources (too many notifications queued) or if there is something else?

    You should use the BLE_GATTS_EVT_HVN_TX_COMPLETE event to monitor when you can queue new notifications, as this will tell you when and how many notifications that have been sent in the previous connection event.

    Best regards,
    Karl

Reply
  • Hello Ron,

    Ron Weber said:
    Thanks for your answer

    No problem at all, I am happy to help! :) 

    Ron Weber said:
    The function APP_ERROR_CHECK is not called, because the call of these functions leads to a reboot of the system. In this case, the counters of the dataset would be reset, which I actually want to avoid. 

    I understand. Could you at least print out the error code, so we could know if it just fails due to resources (too many notifications queued) or if there is something else?

    You should use the BLE_GATTS_EVT_HVN_TX_COMPLETE event to monitor when you can queue new notifications, as this will tell you when and how many notifications that have been sent in the previous connection event.

    Best regards,
    Karl

Children
  • Hello Karl,

    today I did some tests to find out the cause of the problem.

    When the peripheral wants to send data to the central, first a connection is established via
    Advertising and the data is transferred. If all data has been transferred, a timer is started which
    calls the sd_ble_gap_disconnect(m_conn_handle,BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION) function to terminate the connection after the time has expired. However, the process of disconnecting takes some time. In my case the function ble_nus_data_send() was called during the connection termination. This constellation led to the fact that the function ble_nus_data_send() returned the return code NRF_ERROR_INVALID_STATE. My program recognized this and stored this data record in a buffer to repeat it later. After the BLE connection was successfully terminated, the peripheral device started advertising to establish a new connection to the central device.

    After the successful connection establishment the peripheral device calls the ble_nus_data_send() function and also receives the return code NRF_SUCCESS. After a further time the event BLE_NUS_EVT_TX_RDY also appears, but this data set does not arrive at the Central device. But all following data sets are received again from the Central.

    Problem solution:

    The problem can be eliminated by preventing all subsequent function calls to ble_nus_data_send()
    after calling the sd_ble_gap_disconnect(m_conn_handle,BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION) function until the ble connection is fully disconnected.


    What I don't understand is why is the following call to the ble_nus_data_send() function unsuccessful when it previously returned an error code?

    Is there any other situation within the ble stack in which the connection can be terminated?

    Is there a function which can be used to detect the upcoming state?

    Is there perhaps a way to reset the internal states of ble_nus in this situation?

    Best regards,

    Ron

  • Hello Ron,

    Thank you for the update and detailed description of what you have observed.

    If you are transferring very important data, and you can not afford that this could possibly happen, you could instead use Indications (instead of notifications). Indications goes a step further, and not only requires an acknowledgement from the BLE Stack of the peer that the package was received, but it also requires an acknowledgement from the application of the peer, that the package was received. This adds a lot of overhead to your transmission and thus makes it take longer, but with this approach you would always know whether each packet of data was successfully received by the application on the peer.

    Ron Weber said:
    What I don't understand is why is the following call to the ble_nus_data_send() function unsuccessful when it previously returned an error code?

    The calls to ble_nus_data_send() will continue to return an error code so long as the condition for the error code is still fulfilled - in the INVALID_STATE case this condition is fulfilled so long as there is no non-zero connection handles to send to.

    Ron Weber said:
    Is there any other situation within the ble stack in which the connection can be terminated?

    Yes, the connection can be terminated for a number of reasons - The most common ones (apart from the peripheral itself terminating the link) is that the peer can terminate the link, or the link can time out if nothing is heard from the connected peer for the duration of the configured Connection Supervision Timeout.

    Ron Weber said:
    Is there a function which can be used to detect the upcoming state?

    Could you elaborate what you mean by this? Do you mean whether or not you already have staged the link for termination on your peripheral device?
    If so, you could just look at the connection handle, as this will be reset to 0 when you terminate the link.

    Ron Weber said:
    Is there perhaps a way to reset the internal states of ble_nus in this situation?

    Please elaborate what you mean by this as well. What internal states are you here referring to?
    The nus service uses the connection handle to know whether it is in a connection or not, but there are no other states that it takes into consideration - perhaps I did not understand your question correctly.

    Best regards,
    Karl

Related