BleGattCharacteristicException: статус исключения GATT 129 при попытке указать- ›запись-› уведомить глюкометр BLE

Я пытаюсь прочитать все записи, хранящиеся в глюкометре, с помощью библиотеки rxAndroidBle. Согласно нескольким источникам, которые я обнаружил, процесс состоит из трех основных шагов после сопряжения / связывания и подключения к устройству:

  1. Индикация установки в характеристике точки управления доступом к записи (RACP)
  2. Настройка уведомлений по характеристике измерения уровня глюкозы
  3. Запишите в характеристику RACP два байта 0x01, 0x01.

Затем должны поступать уведомления, если есть какие-то записи.

Этот процесс несколько раз работал нормально в LG G5 с Android 7.0, но на других телефонах, к которым у меня есть доступ, он просто не будет работать. Он выдаст ужасный GATT_INTERNAL_ERROR (статус 129), что несколько неоднозначно. Я нашел эта статья, в которой описывается, с чем я могу столкнуться.

Меня беспокоит, что это работает, но это может быть связано с прошивкой, что странно, потому что я видел, что это безупречно работает в другом приложении, которое без проблем подключается к глюкометру на любом устройстве.

Вот как сейчас выглядит мой тестовый код для этого:

fun loadRecords(rxBleDevice: RxBleDevice){
...
...
rxBleDevice.establishConnection(false)
   .flatMap { rxBleConnection: RxBleConnection ->
        rxBleConnection.setupIndication(racpUUID)
            .flatMapSingle {
                Single.just(rxBleConnection)
            }
    }
    .flatMap { rxBleConnection ->
        writeAndReadOnNotification(racpUUID, 
                                   glucoseUUID, 
                                   byteArrayOf(0x01, 0x01), 
                                   false, 
                                   rxBleConnection)
    }
    .subscribe(
        { it:ByteArray ->
            decodeReading(it)
        },Logger::logException)
}

private fun writeAndReadOnNotification(writeTo: UUID, readOn: UUID,
                                           bytes: ByteArray,
                                           isIndication: Boolean,
                                    rxBleConnection:RxBleConnection)
: Observable<ByteArray> {
    val notifObservable = if (isIndication)
            rxBleConnection.setupIndication(readOn)
        else
            rxBleConnection.setupNotification(readOn)
    return notifObservable.flatMap { notificationObservable ->
            Observable.combineLatest(
                    notificationObservable,
                    rxBleConnection.writeCharacteristic(writeTo, bytes).toObservable(),
                    BiFunction { readBytes: ByteArray, writeBytes: ByteArray -> readBytes })
        }
    }

и вот как выглядит журнал для этого фрагмента кода:

18:28:58.058 D/BluetoothGatt: connect() - device: E0:7D:EA:FF:38:AB, auto: false
18:28:58.058 D/BluetoothGatt: registerApp()
18:28:58.058 D/BluetoothGatt: registerApp() - UUID=cca42db0-a88f-4b1c-acd0-f7fbe7be536d
18:28:58.065 D/BluetoothGatt: onClientRegistered() - status=0 clientIf=7
18:28:58.518 D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=7 device=E0:7D:EA:FF:38:AB
18:28:58.527 D/BluetoothGatt: discoverServices() - device: E0:7D:EA:FF:38:AB
18:28:58.532 D/BluetoothGatt: onSearchComplete() = Device=E0:7D:EA:FF:38:AB Status=0
18:28:58.873 D/BluetoothGatt: setCharacteristicNotification() - uuid: 00002a52-0000-1000-8000-00805f9b34fb enable: true
18:28:58.965 D/BluetoothGatt: setCharacteristicNotification() - uuid: 00002a18-0000-1000-8000-00805f9b34fb enable: true
18:28:59.057 D/BluetoothGatt: setCharacteristicNotification() - uuid: 00002a18-0000-1000-8000-00805f9b34fb enable: false
18:28:59.061 D/BluetoothGatt: setCharacteristicNotification() - uuid: 00002a52-0000-1000-8000-00805f9b34fb enable: false
18:28:59.066 E/None: com.polidea.rxandroidble2.exceptions.BleGattCharacteristicException: GATT exception from MAC='XX:XX:XX:XX:XX:XX', status 129 (GATT_INTERNAL_ERROR), type BleGattOperation{description='CHARACTERISTIC_WRITE'}. (Look up status 0x81 here https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h)
        at com.polidea.rxandroidble2.internal.connection.RxBleGattCallback.propagateErrorIfOccurred(RxBleGattCallback.java:243)
        at com.polidea.rxandroidble2.internal.connection.RxBleGattCallback.access$800(RxBleGattCallback.java:35)
        at com.polidea.rxandroidble2.internal.connection.RxBleGattCallback$2.onCharacteristicWrite(RxBleGattCallback.java:125)
        at android.bluetooth.BluetoothGatt$1$7.run(BluetoothGatt.java:438)
        at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:770)
        at android.bluetooth.BluetoothGatt.access$200(BluetoothGatt.java:39)
        at android.bluetooth.BluetoothGatt$1.onCharacteristicWrite(BluetoothGatt.java:433)
        at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:137)
        at android.os.Binder.execTransact(Binder.java:731)
18:28:59.067 D/BluetoothManager: getConnectionState()
18:28:59.067 D/BluetoothManager: getConnectedDevices
18:28:59.074 D/BluetoothGatt: cancelOpen() - device: E0:7D:EA:FF:38:AB
18:28:59.080 D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=7 device=E0:7D:EA:FF:38:AB
18:28:59.083 D/BluetoothGatt: close()
18:28:59.084 D/BluetoothGatt: unregisterApp() - mClientIf=7
18:28:59.507 V/FA: Inactivity, disconnecting from the service

Я что-то пропустил в своем коде? Почему на некоторых телефонах работает?


person Danlos    schedule 25.07.2019    source источник


Ответы (1)


Мне самому удалось это решить. Заглянув в журналы, которые я опубликовал ранее, я увидел, что и индикации, и уведомления были отключены сразу после их настройки, поэтому я глубоко исследовал библиотеку, чтобы увидеть, почему это происходит. Оказывается, не следует устанавливать индикаторы перед настройкой уведомлений по какой-либо характеристике (даже если это две разные характеристики). Итак, основные шаги для чтения должны быть в следующем порядке:

  1. Настройте уведомления о характеристиках глюкозы и продолжайте наблюдение.
  2. Настройте показания на RACP.
  3. Запишите 0x01, 0x01 в RACP.
  4. Выгода

Также я нашел эту заметку в коде библиотеки:

/*
*NOTE: due to stateful nature of characteristics if one will setupIndication() before setupNotification()
* the notification will not be set up and will emit an BleCharacteristicNotificationOfOtherTypeAlreadySetException
*/

что заставило меня переместить часть уведомления перед частью индикации. Вот как это выглядит сейчас:

fun loadRecords(rxBleDevice: RxBleDevice){
...
//Do stuff
...
    rxBleDevice.establishConnection(false)
        .flatMap { rxBleConnection: RxBleConnection ->

    rxBleConnection.setupNotification(glucoseUUID,
                                      NotificationSetupMode.QUICK_SETUP)
        .flatMapSingle {
            Single.just(Pair(it, rxBleConnection))
        }
    }
    .flatMap { (observable, rxBleConnection)  ->
        writeAndReadOnNotification(racpUUID, 
                                   racpUUID, 
                                   byteArrayOf(0x01, 0x01),
                                   true, 
                                   rxBleConnection).subscribe()
        observable
    }
    .subscribe(
        {
            decodeReading(it)
        },Logger::logException)
}

Я знаю, что это выглядит некрасиво и нуждается в полировке.

person Danlos    schedule 26.07.2019