Android receiving multiple BLE packets per connect

2019-07-24 04:24发布

问题:

I have a device that transmits data to my Android (4.4.2) over a BLE GATT characteristic. The device sends multiple 20byte packets per connection interval, where each packet has a sequence number. Lets say the device is sending 4 packets per connection interval, as shown... |sq1,sq2,sq3,sq4|sq5,sq6,sq7,sq8|..

I notice at the Android end, may calls to onCharacteristicChanged() are coming in like... |sq4,sq4,sq4,sq4|sq8,sq8,sq8,sq8|...

Does Android support sending multiple packets per connection interval?

Michael

回答1:

Yes, it supports multiple packets per connection interval, but the API is badly designed, and the characteristic value is a shared object, which may be updated by multiple threads. Each notification may be handled in a different thread and they then call onCharacteristicChanged on one thread (either set in connectGatt(...), or some unspecified thread for older Android versions. If the connection interval is very small, or the device sends many packets in a single interval, it may happen that before you receive the callback with the first notification it will be overwritten by another.

There are 2 advices I may give:

  1. The reference to the value should be obtained as soon as possible, at the beginning of onCharacteristicChanged method, as it may soon be changed (by another notification, or write operation). Ref: https://github.com/NordicSemiconductor/Android-BLE-Library/issues/54
  2. Don't use connectGatt(..., Handler) method, but rather rely on the default handler. If you set a handler, this will add additional time before you receive the callback, so more opportunity for the data to be overwritten. Ref: https://github.com/NordicSemiconductor/Android-BLE-Library/issues/54

The above advices do not guarantee 100% of success, however, but lower the chance of loosing data.

Also, when you write and listen to notification, I recommend splitting that into 2+ characteristics as the characteristic's value is then shared between write and notify operations. Value may be updated before it's sent, and you'll end up sending what was received. Ref: https://github.com/NordicSemiconductor/Android-BLE-Library/issues/60

The iOS API is much better, as the data are set as a parameter to the writeValue(...) and received as value in peripheralDidUpdateValueFor(...). They are not shared.