简体   繁体   English

如何使用RxAndroidBLE从GATT服务器读取块中的BLE GATT特征

[英]How to Read BLE GATT characterstics in chunks form GATT server using RxAndroidBLE

I am using RxAndroidBle library for handling BLE connection and reading/writing to GATT server from my android gatt client app. 我正在使用RxAndroidBle库来处理BLE连接以及从我的android gatt客户端应用读取/写入GATT服务器。 I have followed the sample application provided on github . 我遵循了github提供的示例应用程序。

The problem I am facing is my GATT server is running on Intel Edison and it is supporting MTU size of 80 only .It sends data in chunks, I am supposed to read the charcterstics value multiple time until i encounter a special character, something like '/END' . 我面临的问题是我的GATT服务器在Intel Edison上运行,并且仅支持80的MTU大小。它以块的形式发送数据,我应该多次读取特征值,直到遇到特殊字符,例如`` /结束' 。 I have tried Custom read operation example which is supposed to read 5 times every 250 ms. 我尝试了“自定义读取”操作示例,该示例应该每250毫秒读取5次。

private static class CustomReadOperation implements RxBleRadioOperationCustom<byte[]> {

    private RxBleConnection connection;
    private UUID characteristicUuid;

    CustomReadOperation(RxBleConnection connection, UUID characteristicUuid) {
        this.connection = connection;
        this.characteristicUuid = characteristicUuid;
    }

    /**
     * Reads a characteristic 5 times with a 250ms delay between each. This is easily achieve without
     * a custom operation. The gain here is that only one operation goes into the RxBleRadio queue
     * eliminating the overhead of going on & out of the operation queue.
     */
    @NonNull
    @Override
    public Observable<byte[]> asObservable(BluetoothGatt bluetoothGatt,
                                           RxBleGattCallback rxBleGattCallback,
                                           Scheduler scheduler) throws Throwable {
        return connection.getCharacteristic(characteristicUuid)
                .flatMap(characteristic -> readAndObserve(characteristic, bluetoothGatt, rxBleGattCallback))
                .subscribeOn(scheduler)
                .takeFirst(readResponseForMatchingCharacteristic())
                .map(byteAssociation -> byteAssociation.second)
                .repeatWhen(notificationHandler -> notificationHandler.take(5).delay(250, TimeUnit.MILLISECONDS));
    }

    @NonNull
    private Observable<ByteAssociation<UUID>> readAndObserve(BluetoothGattCharacteristic characteristic,
                                                             BluetoothGatt bluetoothGatt,
                                                             RxBleGattCallback rxBleGattCallback) {
        Observable<ByteAssociation<UUID>> onCharacteristicRead = rxBleGattCallback.getOnCharacteristicRead();

        return Observable.create(emitter -> {
            Subscription subscription = onCharacteristicRead.subscribe(emitter);
            emitter.setCancellation(subscription::unsubscribe);

            try {
                final boolean success = bluetoothGatt.readCharacteristic(characteristic);
                if (!success) {
                    throw new BleGattCannotStartException(bluetoothGatt, BleGattOperationType.CHARACTERISTIC_READ);
                }
            } catch (Throwable throwable) {
                emitter.onError(throwable);
            }
        }, Emitter.BackpressureMode.BUFFER);
    }

    private Func1<ByteAssociation<UUID>, Boolean> readResponseForMatchingCharacteristic() {
        return uuidByteAssociation -> uuidByteAssociation.first.equals(characteristicUuid);
    }
}

and i am calling it like this 我这样称呼它

public void customRead()
{
    if (isConnected()) {
        connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection.queue(new CustomReadOperation(rxBleConnection, UUID_READ_CHARACTERISTIC)))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(bytes -> {
                    configureMvpView.showList(bytes);
                }, this::onRunCustomFailure);
    }
}

and i am not getting any data from the server using this code. 而且我没有使用此代码从服务器获取任何数据。 However if i try simple read operation like this 但是,如果我尝试这样的简单读取操作

public void readInfo() {

    if (isConnected()) {
        connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(UUID_READ_CHARACTERISTIC))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(bytes -> {
                    // parse data
                    configureMvpView.showWifiList(bytes);

                }, this::onReadFailure);
    }

}

I get the first chunk of data, but i need to read rest of data. 我得到了第一批数据,但是我需要读取其余数据。
I am not very well versed with RxJava. 我对RxJava不太了解。 So there might be an easy way to do this, But any suggestion or help will good. 因此,可能有一种简单的方法来执行此操作,但是任何建议或帮助都会很好。

This is my prepareConnectionObservable 这是我的prepareConnectionObservable

private Observable<RxBleConnection> prepareConnectionObservable() {
    return bleDevice
            .establishConnection(false)
            .takeUntil(disconnectTriggerSubject)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnUnsubscribe(this::clearSubscription)
            .compose(this.bindToLifecycle())
            .compose(new ConnectionSharingAdapter());


}

I call 我打电话

 connectionObservable.subscribe(this::onConnectionReceived, this::onConnectionFailure);

and onConnectionReceived i call CustomRead. 和onConnectionReceived我叫CustomRead。

You do not show how the connectionObservable is created and I do not know if anything else is done on that connection before the above code is executed. 您没有显示如何创建connectionObservable ,并且我不知道在执行上述代码之前对该连接是否进行了其他操作。

My guess is that if you would look into the logs of the application you would see that the radio processing queue starts executing your CustomReadOperation as the first operation after the connection. 我的猜测是,如果您查看应用程序的日志,您会看到无线电处理队列在连接后的第一个操作中开始执行CustomReadOperation In your custom operation you are calling RxBleConnection.getCharacteristic(UUID) which tries to execute .discoverServices() (schedule a RxBleRadioOperationDiscoverServices on the radio queue). 在自定义操作中,您正在调用RxBleConnection.getCharacteristic(UUID) ,该尝试尝试执行.discoverServices() (在无线电队列上安排RxBleRadioOperationDiscoverServices )。 The problem is that the radio queue is already executing your CustomReadOperation and will not discover services until it will finish. 问题在于,无线电队列已经在执行CustomReadOperation并且在完成之前不会发现服务。

There is a reason why RxBleConnection is not passed to the RxBleRadioOperationCustom.asObservable() — most of the functionality will not work at that time. 还有就是为什么一个原因RxBleConnection没有传递到RxBleRadioOperationCustom.asObservable() -大部分的功能将不会在那个时候工作。

What you can do is to perform RxBleConnection.discoverServices() before scheduling your CustomReadOperation and pass the BluetoothGattCharacteristic retrieved from RxBleDeviceServices in the constructor. 您可以做的是在安排CustomReadOperation之前执行RxBleConnection.discoverServices()并在构造函数中传递从RxBleDeviceServices检索到的BluetoothGattCharacteristic So instead of having this: 所以不要这样:

public void customRead()
{
    if (isConnected()) {
        connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection.queue(new CustomReadOperation(rxBleConnection, UUID_READ_CHARACTERISTIC)))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(bytes -> {
                    configureMvpView.showList(bytes);
                }, this::onRunCustomFailure);
    }
}

You would have something like: 您将有类似以下内容:

public void customRead()
{
    if (isConnected()) {
        connectionObservable
                .flatMap(RxBleConnection::discoverServices, (rxBleConnection, services) -> 
                    services.getCharacteristic(UUID_READ_CHARACTERISTIC)
                        .flatMap(characteristic -> rxBleConnection.queue(new CustomReadOperation(characteristic)))
                )
                .flatMap(observable -> observable)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(bytes -> {
                    configureMvpView.showList(bytes);
                }, this::onRunCustomFailure);
    }
}

Edit (clarification): 编辑(说明):

And the constructor of your CustomReadOperation should look like this: 而且CustomReadOperation的构造函数应如下所示:

CustomReadOperation(BluetoothGattCharacteristic characteristic) {
    this.characteristic = characteristic;
}

So you will not have to use the this.rxBleConnection.getCharacteristic(UUID) inside of your CustomReadOperation and use directly bluetoothGatt.readCharacteristic(this.characteristic) . 因此,您不必在CustomReadOperation内部使用this.rxBleConnection.getCharacteristic(UUID)并直接使用bluetoothGatt.readCharacteristic(this.characteristic)

Edit 2: Change these two lines: 编辑2:更改这两行:

    return connection.getCharacteristic(characteristicUuid)
            .flatMap(characteristic -> readAndObserve(characteristic, bluetoothGatt, rxBleGattCallback))

To this (the rest is the same): 对此(其余部分相同):

    return readAndObserve(this.characteristic, bluetoothGatt, rxBleGattCallback)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM