【问题标题】:gatt.writeDescriptor() returning false all the time:gatt.writeDescriptor() 一直返回 false:
【发布时间】:2021-10-05 07:02:44
【问题描述】:

抱歉,如果之前有人问过我的问题,但是尽管进行了很多搜索,但我仍然无法找到任何可能的解释来解决我遇到的问题。

我正在开发一个与 BLE 设备 (CC2541) 通信的 Android 应用程序。我能够毫无问题地将数据从 Android 写入 BLE 设备。但是,当尝试从 Android 中的 BLE 设备读取数据时会出现问题。

我正在使用 Kotlin,并且我正在尝试为我想要读取的特定 GATT 特征“启用”通知,我通过将描述符设置为以下 UUID 来做到这一点

00002902-0000-1000-8000-00805f9b34fb

为此,我有以下代码:

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"))
    }
}

然而恰好下面的方法总是返回 false:

gatt.writeDescriptor(desc)

有没有人知道是什么导致了这个问题?如果这是一个我忽略了答案的愚蠢问题,请提前道歉。我是 Kotlin 和协程的新手,实际上我怀疑这个问题与我使用挂起函数的方式有关。

【问题讨论】:

  • @mightyWOZ 非常感谢您抽出宝贵时间发表评论。但是我以前见过这种情况,为了完全确定一次只执行一个请求,我确实将所有函数调用放在同一个后台线程中,并使用 runBlocking {} 来执行请求(考虑到我也实现了一个队列)。可悲的是,它没有任何区别。此外,与您发布的线程不同,在我的情况下,它始终返回 false。我还没有看到它成功。
  • 如果通过在该行设置断点来调试程序,然后单步执行 Android sdk,您将看到该方法返回 false 的确切原因。

标签: java android kotlin bluetooth-lowenergy kotlin-coroutines


【解决方案1】:

我已经解决了这个问题。

经过多次调试,我发现由于某种陌生的原因(我对 Kotlin 或 Android 不是很熟悉,所以我不知道这个原因),方法 gatt.writeDescriptor() 返回 3 次,(在我的情况下,至少)。只有最后一次它返回 true 并且 descriptor 实际被写入。

所以因为我的代码第一次只检查是返回true还是false,显然是失败了。

我现在修改了我的代码,让它等到它返回true,这总是在它第三次返回时发生。

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)) {

        }

    }
}

现在我已经成功订阅了通知,并且可以毫无问题地从 BLE 设备读取数据。

感谢所有提供意见的人,我希望这能帮助将来面临同样情况的人。

【讨论】:

  • 这似乎是一个不正确的解决方案,它会将您的 CPU 使用率最大化到 100%。我相信您还有另一个尚未完成的待处理 GATT 操作(操作完成时您将收到回调)。您必须等待一个操作完成,然后才能执行另一个操作。
  • @Emil Negative,我什至注释掉了任何其他 GATT 操作(读/写)。除了像我说的那样我实现了一个队列,队列中没有任何东西可以解释为什么前两次它总是返回 false :(
  • 如果您调试程序,您应该看到android.googlesource.com/platform/frameworks/base/+/… 中返回false 的行。如果发生的是if (mDeviceBusy) return false; 行,那么您有一个尚未完成的挂起操作。另一个return false 可能在对象关闭、没有这样的可写描述符或类似情况下发生。
  • @Emil 在代码的最后一部分返回 false。 1276 号线
  • 第 1276 行不是函数的一部分?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-07
  • 2021-11-14
相关资源
最近更新 更多