Подписка на уведомления BLE получает 133

1 телефон Android (N5X 6.0.1) работает под управлением сервера BLE, другой (N5X O) подписывается. Уведомление о характеристиках может быть включено, однако в части дескриптора записи я постоянно получаю 133.

Server.java

private void createServer() {
    bluetoothGattServer = bluetoothManager.openGattServer(this, serverCallback);
    BluetoothGattService service = new BluetoothGattService(Constants.SERVICE,
        BluetoothGattService.SERVICE_TYPE_PRIMARY);

    characteristic =
        new BluetoothGattCharacteristic(Constants.CHARACTERISTIC,
                BluetoothGattCharacteristic.PROPERTY_NOTIFY,
                BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);

    // public static UUID DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    characteristic.addDescriptor(new BluetoothGattDescriptor(Constants.DESCRIPTOR,
                BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE));

    characteristic.setWriteType(
        BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);

    service.addCharacteristic(characteristic);
    bluetoothGattServer.addService(service);
}

private BluetoothGattServerCallback serverCallback = new BluetoothGattServerCallback() {
    @Override
    public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
        super.onConnectionStateChange(device, status, newState);
        Log.d(TAG, "onConnectionStateChange " + device.getName() + " " + status + " " + newState);
        if (newState == BluetoothGatt.STATE_CONNECTED) {
            bluetoothDevice = device;
        } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
            bluetoothGattServer.cancelConnection(bluetoothDevice);
            bluetoothGattServer.close();
        }
    }
};

private void sendData(String message) {
    characteristic.setValue(message);
    bluetoothGattServer.notifyCharacteristicChanged(bluetoothDevice, characteristic, true);
}

Все остальные UUID были созданы здесь.

Client.java

device.establishConnection(false)
        .flatMap(bleConnection -> bleConnection.setupNotification(Constants.CHARACTERISTIC))
        .flatMap(onNotificationReceived -> onNotificationReceived)
        .subscribe(data -> {
            Log.d(TAG, "data: " + data);
        }, throwable -> {
            Log.d(TAG, "data error " + throwable);
        });

logcat

05-15 15:26:50.097 D/BluetoothGatt: setCharacteristicNotification() - uuid: 8d7dda32-3759-11e7-a919-92ebcb67fe33 enable: true
05-15 15:26:50.105 D/RxBle#Radio:   QUEUED RxBleRadioOperationDescriptorWrite(60042487)
05-15 15:26:50.110 D/RxBle#Radio: FINISHED RxBleRadioOperationServicesDiscover(231218312)
05-15 15:26:50.112 D/RxBle#Radio:  STARTED RxBleRadioOperationDescriptorWrite(60042487)
05-15 15:27:20.119 D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(60042487)
05-15 15:27:20.121 D/BluetoothGatt: setCharacteristicNotification() - uuid: 8d7dda32-3759-11e7-a919-92ebcb67fe33 enable: false
05-15 15:27:20.126 D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=133
05-15 15:27:20.129 D/BLE: data error BleGattDescriptorException{macAddress=42:EE:5A:C6:C1:F0, status=133 (0x85 -> https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h), bleGattOperationType=BleGattOperation{description='DESCRIPTOR_WRITE'}}

Примечание: если я использую собственный Android API, я могу подписаться и получать уведомления без необходимости записи в дескриптор.

update: интересная вещь, но пока идет процесс дескриптора записи (требуется около 30 секунд, прежде чем он вернется с ошибкой), я могу получить onCharacteristicChanged.

update2: добавлен обратный вызов и запись в код характеристики


person mbmc    schedule 15.05.2017    source источник


Ответы (1)


В спецификации ядра Bluetooth говорится, что если характеристика поддерживает уведомления, она должна содержать дескриптор конфигурации характеристик клиента и начинать уведомление только тогда, когда дескриптор CCC будет записан с правильным значением.

Похоже, что в вашей конфигурации есть проблема, которая проявляется как status = 133. Похоже, вы могли ошибиться при установке свойств в characteristic. Я предполагаю, что вы хотите иметь характеристику, позволяющую читать, писать и устанавливать уведомления - в этой ситуации это будет выглядеть так:

characteristic =
    new BluetoothGattCharacteristic(Constants.CHARACTERISTIC,
            BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);

Изменить. Помните, что если центральный сервер запрашивает включение уведомлений, он пытается записать дескриптор конфигурации характеристик клиента. Если это не запрос с настройкой NO_RESPONSE, центральный сервер ожидает ответа.

Правильное решение - добавить обратный вызов к onDescriptorWriteRequest и отправить ответ в центральный:

BluetoothGattServerCallback serverCallback = new BluetoothGattServerCallback() {
    // (...)

    @Override
    public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor,
                                         boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
        super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);

        // validate if the request is exactly what you expect if needed
        bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
    }

    // (...)
};

Возможное решение

Некоторые китайские производители не соответствуют спецификации Bluetooth Core и не имеют дескриптора CCC в характеристиках, отправляющих уведомления. Если вы можете получать уведомления без настройки CCC, вы можете использовать режим совместимости RxBleConnection.setupNotifications(characteristic, NotificationSetupMode.COMPAT), хотя это не рекомендуется, и необходимо внести правильное исправление в конфигурацию.

person Dariusz Seweryn    schedule 16.05.2017
comment
Предлагаемое исправление не устранило проблему, но помогло обходное решение. - person mbmc; 16.05.2017
comment
Должна быть другая проблема с настройкой BluetoothGattServer. Я ожидал, что обе ОС Android будут хорошо работать друг с другом, и обходной путь - это просто обходной путь. Может, завтра у меня будет минутка поиграть с Андроидом в качестве сервера. Спасибо за правку - мне было рано. - person Dariusz Seweryn; 16.05.2017
comment
@mbmc Не могли бы вы поделиться своим BluetoothGattServerCallback кодом? Я думаю, что вы неправильно управляете ответами на централь. - person Dariusz Seweryn; 17.05.2017
comment
Еще не было возможности попробовать, но буду держать вас в курсе. - person mbmc; 19.05.2017
comment
Вот и все! Благодаря тонну. - person mbmc; 21.05.2017