0

I am using RxAndroidBle library for handling BLE connection and reading/writing to GATT server from my android gatt client app. I have followed the sample application provided on 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' . I have tried Custom read operation example which is supposed to read 5 times every 250 ms.

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. So there might be an easy way to do this, But any suggestion or help will good.

This is my 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.

4

1 回答 1

1

您没有显示它connectionObservable是如何创建的,我不知道在执行上述代码之前是否对该连接进行了任何其他操作。

我的猜测是,如果您查看应用程序的日志,您会看到无线电处理队列开始执行您CustomReadOperation作为连接后的第一个操作。在您正在调用的自定义操作中,RxBleConnection.getCharacteristic(UUID)它会尝试执行(在无线电队列上.discoverServices()安排 a )。RxBleRadioOperationDiscoverServices问题是无线电队列已经在执行您的CustomReadOperation并且在完成之前不会发现服务。

RxBleConnection没有传递给是有原因的RxBleRadioOperationCustom.asObservable()——当时大部分功能都不起作用。

您可以做的是RxBleConnection.discoverServices()在调度之前执行CustomReadOperation并传递BluetoothGattCharacteristicRxBleDeviceServices构造函数中检索到的内容。所以不要这样:

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

你会有类似的东西:

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

编辑(澄清):

你的构造函数CustomReadOperation应该是这样的:

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

这样你就不用在this.rxBleConnection.getCharacteristic(UUID)你的里面CustomReadOperation直接使用了bluetoothGatt.readCharacteristic(this.characteristic)

编辑2:更改这两行:

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

对此(其余相同):

    return readAndObserve(this.characteristic, bluetoothGatt, rxBleGattCallback)
于 2017-07-28T10:59:57.907 回答