Search code examples
javaandroidkotlinbluetooth-lowenergykotlin-coroutines

gatt.writeDescriptor() returning false all the time:


Apologies if what I am asking has been asked before, however despite much searching I have not been able to find any possible explanation to the issue I am experiencing.

I am developing an Android application, which communicates with a BLE Device (CC2541). I am able to write data from Android to BLE device without issues. However issues start when trying to read data from the BLE device in the Android.

I am using Kotlin, and I am trying to "enable" notifications for the particular GATT Characteristic which I want to read, and I do so by setting the descriptor to the following UUID

00002902-0000-1000-8000-00805f9b34fb

And for doing so I have the following code:

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 not finished yet")

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

    return suspendCoroutine { cont ->
        descWriteCont[key] = cont
        desc.value = descValue
        if (!gatt.writeDescriptor(desc))
            cont.resumeWithException(IOException("fail to config descriptor $this"))
    }
}

However it just so happens that the following method returns false all the time:

gatt.writeDescriptor(desc)

Does anyone have any idea what could be causing this issue? Apologies in advance if it's a silly question whose answer I have overlooked. I am new to Kotlin and coroutines, and in fact I suspect this issue has to do with how I am using suspend functions.


Solution

  • 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.