How to receive all notifications in RxAndroidBle

蓝咒 提交于 2019-12-05 21:45:05

Most actions that one can do over BLE are asynchronous and take some time to finish. Setting up the notifications is no exception—it is a two-step procedure:

  1. setup a local notification
  2. write a Client Characteristic Configuration Descriptor of the characteristic one wants to get notifications from

If your peripheral is first set to send notifications before the notifications are ready to be received by the central then some of the data may get lost during the notifications setup procedure.

Is there maybe some way to do setupNotification(), and then write the characteristics to tell the device to start sending notifications?

Of course (this is how usually similar scenarios are handled)—there are multiple possible implementations. One of them could look like this:

device.establishConnection(false) // establish the connection
        .flatMap(rxBleConnection -> rxBleConnection.setupNotification(log_uuid) // once the connection is available setup the notification
                .flatMap(logDataObservable -> Observable.merge( // when the notification is setup start doing three things at once
                        rxBleConnection.writeCharacteristic(pword_uuid, pword).ignoreElements(), // writing the `pword` but ignore the result so the output of this .merge() will contain only log data
                        rxBleConnection.writeCharacteristic(mode_uuid, mode).ignoreElements(), // same as the line above but for `mode`
                        logDataObservable // observing the log data notifications
                ))
        )
        .subscribe(
                bytes -> System.out.println(">>> data from device " + bytesToHex(bytes)),
                throwable -> {
                    System.out.println("error");
                    System.out.println(throwable);
                }
        );

Edit:

As it was mentioned in the comments below—the peripheral does not allow for any BLE interactions before setting the mode and writing the password. As I have written above setting the notifications is a two step-step procedure with a local step and remote (executed on peripheral) one which is executed before the mode/password in the above code snippet. It is possible to separate those two steps by using the NotificationSetupMode.COMPAT mode and writing the Client Characteristic Configuration Descriptor manually later:

UUID clientCharacteristicConfigDescriptorUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
device.establishConnection(false) // establish the connection
        .flatMap(
                RxBleConnection::discoverServices,  // once the connection is available discover the services of the peripheral
                (rxBleConnection, rxBleDeviceServices) -> // and when we have the connection and services
                        rxBleDeviceServices.getCharacteristic(log_uuid) // we get the log characteristic (on which we will setup the notification and write the descriptor)
                                .flatMap(logDataCharacteristic -> // once the log characteristic is retrieved
                                        rxBleConnection.setupNotification(logDataCharacteristic, NotificationSetupMode.COMPAT) // we setup the notification on it in the COMPAT mode (without writing the CCC descriptor)
                                                .flatMap(logDataObservable -> Observable.merge( // when the notification is setup start doing four things at once
                                                        rxBleConnection.writeCharacteristic(pword_uuid, pword).ignoreElements(), // writing the `pword` but ignore the result so the output of this .merge() will contain only log data
                                                        rxBleConnection.writeCharacteristic(mode_uuid, mode).ignoreElements(), // same as the line above but for `mode`
                                                        rxBleConnection.writeDescriptor(logDataCharacteristic.getDescriptor(clientCharacteristicConfigDescriptorUuid), BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE).ignoreElements(), // and we write the CCC descriptor manually
                                                        logDataObservable // observing the log data notifications
                                                ))
                                )
        )
        .flatMap(observable -> observable) // flatMap to get the raw byte[]
        .subscribe(
                bytes -> System.out.println(">>> data from device " + bytesToHex(bytes)),
                throwable -> {
                    System.out.println("error");
                    System.out.println(throwable);
                }
        );

rxBleConnection.discoverServices() call may be omitted if we would know the Log Characteristic Service UUID and use rxBleConnection.writeDescriptor(UUID serviceUuid, UUID characteristicUuid, UUID descriptorUuid function.

UUID clientCharacteristicConfigDescriptorUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
device.establishConnection(false) // establish the connection
        .flatMap(rxBleConnection -> rxBleConnection.setupNotification(log_uuid, NotificationSetupMode.COMPAT) // once the connection is available setup the notification w/o setting Client Characteristic Config Descriptor
                .flatMap(logDataObservable -> Observable.merge( // when the notification is setup start doing three things at once
                        rxBleConnection.writeCharacteristic(pword_uuid, pword).ignoreElements(), // writing the `pword` but ignore the result so the output of this .merge() will contain only log data
                        rxBleConnection.writeCharacteristic(mode_uuid, mode).ignoreElements(), // same as the line above but for `mode`
                        rxBleConnection.writeDescriptor(log_service_uuid, log_uuid, clientCharacteristicConfigDescriptorUuid).ignoreElements(), // same as the above line but for writing the CCC descriptor
                        logDataObservable // observing the log data notifications
                ))
        )
        .subscribe(
                bytes -> System.out.println(">>> data from device " + bytesToHex(bytes)),
                throwable -> {
                    System.out.println("error");
                    System.out.println(throwable);
                }
        );
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!