Olivier Brand
Olivier Brand

Reputation: 121

Making READ, WRITE and NOTIFY working on Android BLE (version 21 and above)

In my application, I got the READ and WRITE to work on specific BluetoothGattCharacteristic objects. The BluetoothGattCallback onCharacteristicWrite and onCharacteristicRead are properly called. I have then tried to setup the NOTIFY option so my Android app gets notified when a specific characteristic on the device changes. I have set this up via the following code:

// Local notifications
mGatt.setCharacteristicNotification(statusTypeCharacteristic, notify);

// Remote notifications
BluetoothGattDescriptor desc = statusTypeCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));

Log.d("Descriptor", desc.toString());

boolean test;
test = desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);  // return value = true
test = mGatt.writeDescriptor(desc);  // return value = true

When the characteristic changes, the callback: onCharacteristicChanged is being called as expected

However, now all READ and WRITE operations do not work anymore. When I comment the lines dealing with the descriptor, the READ and WRITE work again.

A part I am very unclear is around the UUID used to get the descriptor. Is it correct? Should I scan instead all descriptors from the characteristic and enable notification on one? How do I know which one to set as I have multiple ones coming back?

Upvotes: 3

Views: 3580

Answers (1)

Olivier Brand
Olivier Brand

Reputation: 121

Ok, so I have figured out the issue. At the beginning of my application, I am configuring (i.e. writing) to lots of descriptors. 2 issues with it: 1- A descriptor can only be written one at a time 2- No read/write operations can happen when a descriptor is being written to

The fix is to create a queue of write descriptor operations and perform the next descriptor write in the onDescriptorWrite callback.

private void writeGattDescriptor(BluetoothGattDescriptor d) {
    //put the descriptor into the write queue
    descriptorWriteQueue.add(d);
    //if there is only 1 item in the queue, then write it. If more than 1, we handle asynchronously in the
    // callback
    if(descriptorWriteQueue.size() == 1) {
        mGatt.writeDescriptor(d);
    }
}

And then in the callback:

@Override
    public void onDescriptorWrite (BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        // Called when the descriptor is updated for notification
        Log.d("onDescriptorWrite", descriptor.getUuid().toString());

        // pop the item that we just finishing writing
        descriptorWriteQueue.remove();

        // if there is more to write, do it!
        if(descriptorWriteQueue.size() > 0) {
            mGatt.writeDescriptor(descriptorWriteQueue.element());
        }

        // Inform the framework that the scope has connected, configured and ready to process commands
        if(descriptorWriteQueue.size() == 0) {
            // Do something else, such as reads and writes
        }
    }

Upvotes: 1

Related Questions