es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Enviar datos a través del aire y, una vez finalizada la operación, finalizarla utilizando RxAndroidBLE.

Estoy tratando de enviar los 128 bytes del bloque al controlador BLE usando la biblioteca RxAndroidBle. El flujo para enviar datos desde el móvil al controlador BLE es el siguiente:

  1. Conectar con el controlador BLE
  2. Iniciar OTA (enviar 1)
  3. Enviar CRC (del bloque de datos)
  4. Enviar bloque de datos
  5. Esperar 2 segundos
  6. Repetir paso 3
  7. FINALIZAR OTA (enviar 2)

Aquí hay una captura de código:

.flatMap(rxBleConnection -> prepareWriting())
.flatMapIterable(otaMetaData -> otaMetaData)
.zipWith(Observable.interval(2, TimeUnit.SECONDS), (item, interval) -> item)
.doOnNext(metaData -> {
    otaMetaData = metaData;
})
.map(otaMetaData -> {
    return mRxBleConnection.writeCharacteristic(OTA_CHECKSUM, otaMetaData.getCrcBlock()).toObservable();
})

.doOnNext(otaMetaData -> {
    Log.e(TAG, "Escribiendo CRC " + Arrays.toString(BLEUtils.toHex(otaMetaData.getCrcBlock())));
})

.map(bytes -> {
    return mRxBleConnection.writeCharacteristic(OTA_DATA, otaMetaData.getDataBlock()).toObservable();
})
.doOnNext(otaMetaData -> {
    Log.e(TAG, "Escribiendo Datos " + Arrays.toString(BLEUtils.toHex(otaMetaData.getDataBlock())));
})

.flatMap(bytes -> mRxBleConnection.writeCharacteristic(OTA_CONTROL,OTA_DATA_END).toObservable())

El problema ocurre al enviar el comando FINALIZAR OTA debido a que, al retornar 20 elementos, .flatMap(bytes -> mRxBleConnection.writeCharacteristic(OTA_CONTROL,OTA_DATA_END) se llama 20 veces.

Por lo tanto, no estoy seguro de cómo puedo enviar el comando OTA_DATA_END cuando todos los 20 elementos se procesen. Además, cualquier sugerencia para mejorar el código existente es bienvenida.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Para enviar el comando OTA_DATA_END después de que se hayan procesado los 20 elementos, puedes usar el operador toList() después de flatMapIterable() para convertir los elementos emitidos en una sola lista. Luego, puedes usar el operador doOnSuccess() para activar una acción después de que se complete la lista, y finalmente llamar mRxBleConnection.writeCharacteristic(OTA_CONTROL, OTA_DATA_END) para enviar el comando OTA_DATA_END.

    Aquí tienes un fragmento de código actualizado:

    .flatMap(rxBleConnection -> prepareWriting())
    .flatMapIterable(otaMetaData -> otaMetaData)
    .zipWith(Observable.interval(2, TimeUnit.SECONDS), (item, interval) -> item)
    .doOnNext(metaData -> {
        otaMetaData = metaData;
    })
    .map(otaMetaData -> {
        return mRxBleConnection.writeCharacteristic(OTA_CHECKSUM, otaMetaData.getCrcBlock()).toObservable();
    })
    .doOnNext(otaMetaData -> {
        Log.e(TAG, "Writing CRC " + Arrays.toString(BLEUtils.toHex(otaMetaData.getCrcBlock())));
    })
    .map(bytes -> {
        return mRxBleConnection.writeCharacteristic(OTA_DATA, otaMetaData.getDataBlock()).toObservable();
    })
    .doOnNext(otaMetaData -> {
        Log.e(TAG, "Writing Data " + Arrays.toString(BLEUtils.toHex(otaMetaData.getDataBlock())));
    })
    .toList()
    .doOnSuccess(otaMetaDataList -> {
        // Se han procesado los 20 elementos, así que envía el comando OTA_DATA_END
        mRxBleConnection.writeCharacteristic(OTA_CONTROL, OTA_DATA_END).subscribe();
    })
    .flatMapObservable(bytes -> Observable.empty()); // Reemplaza el último flatMap() con esto para evitar emitir más elementos
    

    En cuanto a mejorar el código existente, aquí hay algunas sugerencias:

    1. Usa compose() para extraer la lógica común en operadores reutilizables. Por ejemplo, podrías crear un operador que maneje las llamadas a writeCharacteristic() y el registro de eventos, y aplicarlo tanto a las escrituras de checksum como a las de bloque de datos.
    2. Reemplaza las llamadas a doOnNext() con operadores que puedan modificar los elementos emitidos en línea, como map(), flatMap(), o flatMapSingle(). Esto hará que el código sea más componible y más fácil de entender.

    3. Usa constantes o enums para los valores de OTA_CHECKSUM, OTA_DATA y OTA_CONTROL, para que puedan modificarse fácilmente si es necesario.

    4. Considera dividir el método prepareWriting() en métodos u operadores más pequeños, para mejorar la legibilidad y testabilidad. Por ejemplo, podrías crear un operador que lea los datos del firmware desde un archivo y los convierta en una lista de objetos OtaMetaData.

    En general, el código se ve bien y sigue el patrón recomendado de utilizar streams reactivos para manejar eventos asíncronos de manera limpia y componible. ¡Buen trabajo!

Comments are closed.