Writing to Multiple BluetoothGatt objects on Android 4.4.4 Nexus 4

790 views Asked by At

I know this has been discussed at length, but I have not found an answer that seems to solve the issue I am facing with Android Bluetooth LE.

The system we have designed allows connections to multiple devices. Discovery and connection to multiple devices works great. Each BluetoothGatt object instance is saved based on the MAC address of the device and each of these instances is assigned a unique callback object (this is based off information from Nordic Semiconductor's website regarding multiple device connections in Android).

The issue comes about when I try to write the same data to multiple devices. Typically, each individual write is the same data on the same characteristic UUID but on different BluetoothGatt instances. All writes are queued in the app to ensure only one write request is pending at a given time with the BT Stack on Android. I am well aware of the perils of doing otherwise as there is a plethora of information about it.

The behavior I am seeing is that one of the devices, usually the first one to which I connect, always receives the data. The other devices never receive the data. However, the BT stack returns onCharacteristicWrite for every write I send. So, the BT stack seems to think it wrote the data to all devices, but instead, it seems to queue it up. If, after some time has passed (unknown amount of time), I send a command only to one of the devices that was not receiving data, the BT stack seems to push all unsent data to the device and then whatever command I last sent as if it was sent a flush() command. Here is a logcat of the behavior:

11-18 01:58:55.571 E/testapp( 1110): writeDataToCharacteristic(characteristic. Value: [111, -1, 95])

11-18 01:58:55.571 D/testapp( 1110): Characteristic WriteType: 1

11-18 01:58:55.571 I/testapp( 1110): writeCharacteristic for CF:9E:D0:9A:98:90 with value - [-1, -102, -112]

11-18 01:58:55.571 D/BluetoothGatt( 1110): writeCharacteristic() - uuid: 9a143cb6-d775-4cfb-9eca-6e3a9b0f966b

11-18 01:58:55.571 D/BtGatt.GattService( 1204): writeCharacteristic() - address=CF:9E:D0:9A:98:90

11-18 01:58:55.571 D/BtGatt.btif( 1204): btif_gattc_write_char

11-18 01:58:55.571 D/BtGatt.btif( 1204): btgattc_handle_event: Event 1015

11-18 01:58:55.571 D/BtGatt.btif( 1204): btif_gattc_upstreams_evt: Event 4

11-18 01:58:55.571 D/BtGatt.GattService( 1204): onWriteCharacteristic() - address=CF:9E:D0:9A:98:90, status=0

11-18 01:58:55.571 D/BluetoothGatt( 1110): onCharacteristicWrite() - Device=CF:9E:D0:9A:98:90 UUID=9a143cb6-d775-4cfb-9eca-6e3a9b0f966b Status=0

11-18 01:58:55.571 I/testapp( 1110): onCharacterisiticWrite

11-18 01:58:55.571 E/testapp( 1110): writeDataToCharacteristic(characteristic. Value: [111, -1, 95])

11-18 01:58:55.581 D/testapp( 1110): Characteristic WriteType: 1

11-18 01:58:55.581 I/testapp( 1110): writeCharacteristic for DB:7B:3E:47:AF:1A with value - [-1, -102, -112]

11-18 01:58:55.581 D/BluetoothGatt( 1110): writeCharacteristic() - uuid: 9a143cb6-d775-4cfb-9eca-6e3a9b0f966b

11-18 01:58:55.581 D/BtGatt.GattService( 1204): writeCharacteristic() - address=DB:7B:3E:47:AF:1A

11-18 01:58:55.581 D/BtGatt.btif( 1204): btif_gattc_write_char

11-18 01:58:55.581 D/BtGatt.btif( 1204): btgattc_handle_event: Event 1015

11-18 01:58:55.581 D/BtGatt.btif( 1204): btif_gattc_upstreams_evt: Event 4

11-18 01:58:55.581 D/BtGatt.GattService( 1204): onWriteCharacteristic() - address=DB:7B:3E:47:AF:1A, status=0 Stack claims write success, but the data is never received on device and the characteristic value remains unchanged

11-18 01:58:55.581 D/BluetoothGatt( 1110): onCharacteristicWrite() - Device=DB:7B:3E:47:AF:1A UUID=9a143cb6-d775-4cfb-9eca-6e3a9b0f966b Status=0

11-18 01:58:55.581 I/testapp( 1110): onCharacterisiticWrite

In the above, there are two characteristic writes to the same characteristic UUID on two different devices. The main difference being the device address which I have bolded for clarity. The stack claims to have performed both writes, but it in fact did not. I have not found a solution to this issue as it seems the stack is caching the write to the second device but not actually writing it out. Note that I have a delay between each set of writes but each individual write is delayed only by waiting for the onCharacteristicWrite callback from the stack.

Some pseudo code to show how the data is being sent to all connected devices. I will add more if necessary for this discussion:

if(canWrite) {
    for (BTDevice device : deviceList) {
        /* Each write is queued at a lower level. */
        device.sendData(data);
    }

    nextChangeAllowed = System.currentTimeMillis() + 100;
    canWrite = false;
}

if(nextChangeAllowed < System.currentTimeMillis()) {
    canWrite = true;
}

Has anyone else run in to this issue and solved it?

1

There are 1 answers

2
Álvaro Pérez Soria On

I faced a similar problem as yours. I needed to write the same characteristic to two devices, and what I did is implement an algorithm that wrote the characteristic to the second device, only when the first one was written and read (when onCharacteristicRead was called).

So that canWrite flag (on your pseudocode), should be changed inside the callback onCharacteristicRead when the previous characteristic written has been completed written and read.

Hope this helps.