Android Ble Bluetoothgatt.Writedescriptor() Return Sometimes False

Android BLE BluetoothGatt.writeDescriptor() return sometimes false

The documentation lacks information. However you can read the source code to find out the rules, which (currently) are the following:

For each BluetoothGatt object, you can only have one outstanding request at a time, including requestMtu, readCharacteristic, writeCharacteristic, readDescriptor, writeDescriptor and executeReliableWrite. So if you issue a read request you need to wait for the read response before you issue a write request. While they implemented the code that returns false if there is an ongoing operation in BluetoothGatt.java, they forgot to do this for requestMtu, so if you have multiple requests at a time where requestMtu is one of them, you will get random errors sooner or later (in the latest versions at the time of this post).

So yes, every developer has to manually serialize the requests. Note that the Bluetooth stack actually has a queue of requests, but it is limited to only one request per client (i.e. BluetoothGatt object). So if two apps on the same phone talk to the same device simultaneously you will never get "busy" errors. The only exception is if you use Write Without Response for which the current data flow implementation is quite buggy (see https://issuetracker.google.com/issues/37121017 which Google seems to have ignored).

You can send notifications at the same time as you write a characteristic, since the server and client roles are separated.

Regarding updating the documentation, you can always try to file an issue at https://issuetracker.google.com (but I get the feeling nobody reads that), or, since Android is open source, send a pull request to https://android-review.googlesource.com/ which updates the Javadoc from which the documentation is generated.

gatt.writeDescriptor() returning false all the time:

I have fixed the issue.

Upon much debugging, I discovered that for some estrange reason (I'm not very experience with Kotlin or Android, so I don't know this reason), the method gatt.writeDescriptor() returns 3 times, (in my case, at least). And only the last time does it return true and the descriptor actually gets written.

So because my code only checked whether it returned true or false the first time, it was obviously failing.

I have now modified my code, to make it wait until it returns true which happens always on the third time it returns.

private suspend fun setNotification(
char: BluetoothGattCharacteristic,
descValue: ByteArray,
enable: Boolean
) {
val desc = char.getDescriptor(UUID_CLIENT_CHAR_CONFIG)
?: throw IOException("missing config descriptor on $char")
val key = Pair(char.uuid, desc.uuid)
if (descWriteCont.containsKey(key))
throw IllegalStateException("last setNotification() not finish")

if (!gatt.setCharacteristicNotification(char, enable))
throw IOException("fail to set notification on $char")

return suspendCoroutine { cont ->
descWriteCont[key] = cont
desc.value = descValue
while (!gatt.writeDescriptor(desc)) {

}

}
}

Now I have successfully subscribed for notifications, and can read data from the BLE Device without much issues.

Thanks to all who helped by offering some input, and I hope this will hopefully help someone in the future facing the same situation.

BluetoothGatt.writeCharacteristic return false half the time

Never use timeouts to try to workaround this issue. The proper way is to wait for the callback and then perform the next request. See Android BLE BluetoothGatt.writeDescriptor() return sometimes false.

BLE Data lost on reading characteristic when the device sends data frequently

Declared those lines before device.connectGatt()

    AdvertiseSettings advertiseSettings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
.setConnectable(true)
.setTimeout(0)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
.build();
AdvertiseData advertiseData = new AdvertiseData.Builder()
.setIncludeDeviceName(true)
.setIncludeTxPowerLevel(false)
.addServiceUuid(new ParcelUuid(FP_SERVICE_UUID))
.build();
mBluetoothAdapter.getBluetoothLeAdvertiser().startAdvertising(advertiseSettings, advertiseData, new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
// Log.d(TAG, "BluetoothLeAdvertiser, onStartSuccess --> $isConnectable : " + settingsInEffect.isConnectable());
}

@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
// Log.d(TAG, "BluetoothLeAdvertiser, onStartSuccess --> errorCode : " + errorCode);
}
});
...

bluetooth ble writecharacteristics return write_empty ondeviceresult

You can't have multiple outstanding GATT requests at a time. Now you call writeDescriptor followed by writeCharacteristic without waiting for onDescriptorWrite.



Related Topics



Leave a reply



Submit