1

我正在使用 RxAndroidBle 库将值从我的 BLE 设备读取到我的 android 应用程序。应用程序在 BLE 外围设备上进行多次读取,如下面的代码所示。

public void longRead()
{
   // if (isConnected())
    {
        longReadSubscription =  connectionObservable
                .flatMap(RxBleConnection::discoverServices, (rxBleConnection, services) ->
                        services.getCharacteristic(UUID_READ_CHARACTERISTIC)
                                .flatMap(characteristic -> rxBleConnection.queue(new CustomReadOperation(characteristic)))
                )
                .flatMap(observable -> observable)
                .first() // Bug fix for not disconnecting after read.
                .observeOn(AndroidSchedulers.mainThread())
                .compose(this.bindToLifecycle())
                .subscribe(bytes -> {
                    configureWifiMvpView.showList(bytes);
                }, this::onLongReadFailure);
    }
}

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

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

    /**
     * Reads a characteristic until a special charcter has been found.. 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 readAndObserve(this.characteristic, bluetoothGatt, rxBleGattCallback)
                .subscribeOn(scheduler)
                .takeFirst(readResponseForMatchingCharacteristic())
                .map(byteAssociation -> byteAssociation.second)

                .repeatWhen(completed -> completed.delay(200, TimeUnit.MILLISECONDS))
                .takeUntil(result -> getSpecialCharacter(result) == true);

    }

    public boolean getSpecialCharacter(byte[] s) {
        boolean result = false;
       try {
           String str = new String(s, "UTF-8");
           if (str == null || str.trim().isEmpty()) {
               // System.out.println("Incorrect format of string");
               return true;
           }
           System.out.println(s);
           Pattern p = Pattern.compile("]");
           Matcher m = p.matcher(str);
           result = m.find();
     }
       }catch(Exception e)
       {
           System.out.println("exception #####");
       }
        return result;

    }

    @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(UUID_READ_CHARACTERISTIC);
    }
}

}

现在这一切工作正常,但偶尔如果从 BLE 设备读取的数据超过 600 字节,那么我会在读取完整数据之前调用 Subscribe(bytes->) ,之后我会调用 takeUntil 来检查它字符串末尾的特殊字符并终止,丢失第二块中的所有数据。看起来 RxAndrodiBLE 库维护一个内部缓冲区并继续写入该缓冲区中的所有数据,一旦缓冲区已满,订阅 observable 就会被调用。当读取的数据大小大于缓冲区大小时,这会导致问题。我们如何处理它,这样我们就不会以块的形式获取数据。我们还可以增加缓冲区的大小,以便在调用订阅之前将接收到的所有数据存储在那里。

4

0 回答 0