Icono del sitio AranaCorp

Envío de cadenas largas de caracteres a través de BLE

Bluetooth Low Energy (BLE) tiene un límite conocido de 20Bytes en la longitud de las cadenas enviadas. Hay formas de anular este límite.

Hardware

En este tutorial, enviaremos datos desde una aplicación Android, desarrollada con React Native, a un ESP32. Los métodos descritos también pueden ser válidos para otros dispositivos.

BLE limitado a 20 bytes

La aplicación desarrollada bajo React Native es perfectamente capaz de enviar cadenas de caracteres largas en forma de paquete de 20bytes por defecto. Sin modificar el tutorial anterior, este es el valor recibido en el lado del ESP32. Sólo se almacena en memoria el último paquete.

01:48:39.734 -> ESP32BLE server ready
01:48:40.493 -> Server address:3c:61:05:31:5f:12
01:48:41.672 -> Client connected
01:48:48.169 -> Charac value: Helloworldthisisalon
01:48:48.253 -> Charac value: gstringletseewhatcom
01:48:48.374 -> Charac value: esout;
01:48:48.374 -> this is the last packet

Resumen de métodos para enviar cadenas largas a través de BLE

Recuperar varios paquetes

Si el dispositivo que envía los mensajes es capaz de gestionar el envío de cadenas de caracteres que superan el límite de la MTU, como es el caso de nuestro ejemplo, sólo queda configurar el módulo receptor para que concatene los distintos paquetes recibidos. Para ello, utilizaremos un carácter de fin de cadena, como «;».

En la función onWrite de la característica del módulo ESP32BLE, añadimos un test de fin de cadena y una variable longMsg para que actúe como buffer.

std::string longMsg;
class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();

      if (value.length() > 0) {
        Serial.print("Charac value: ");
        for (int i = 0; i < value.length(); i++)
          Serial.print(value[i]);

        Serial.println();
        if(value.find(";") != -1){
          //Serial.println("this is the last packet");
          longMsg = longMsg + value;
          Serial.print("longMsg: ");
          for (int i = 0; i < longMsg.length(); i++)
            Serial.print(longMsg[i]);
          Serial.println();
          //do whatever you want with longMsg then erase
          longMsg = "";
        }else{
          longMsg = longMsg + value;
        }
      }
    }
};

Envío de paquetes de tamaño predefinido

Si el dispositivo que envía los datos no gestiona mensajes de tamaño superior a la MTU, es posible dividir la cadena de caracteres en paquetes de tamaño predefinido (chunksize). Este método permite controlar el tamaño de los paquetes enviados.

En el proyecto React Native, estamos creando una función que transformará la cadena de caracteres largos en un array de bytes que enviaremos en paquetes.

    const sendLongMessage = async (data: string, chunksize: number) => {
      console.log("data : ",data)
      var bytes = convertStringToByteArray(data)
      var times = Math.ceil(bytes.length/chunksize);
        var packets = [];
  
        console.log("split data ",times," times");
        //console.log("bytes: ",bytes)
        var i=0
        for(var time=0;time<times;time++){
          var packet = bytes.slice(time*chunksize, (time+1)*chunksize)
          packets.push(packet)
          console.log(time," : ",byteArrayToString(packet))
          sendMessage(byteArrayToString(packet));
          await delay(100);
        }
    }

N.B.: se puede introducir una función de retardo para dar tiempo a que se envíe el mensaje. delay(100)

const delay = (ms: number) => new Promise(
  resolve => setTimeout(resolve, ms)
);

Aumentar el límite de MTU de la aplicación

Por defecto, la librería react-native-ble-manager envía paquetes de 20bytes. Existe un método para especificar que el módulo BLE debe modificar el tamaño de la Unidad Máxima de Transmisión (MTU)

En el código de la aplicación, durante la conexión, antes de recuperar los servicios, añada una solicitud de MTU

BleManager.requestMTU(device.id, 512).then(
        (mtu) => {
          setMTU(mtu);
        }
      ) //request the MTU size in bytes

Al enviar el mensaje, puedes especificar el tamaño máximo del mensaje en bytes, «mtu», en la función BLEManager.write().

     BleManager.write(
       selectedDevice.id,
       serviceid,
       caracid,
       buffer.toJSON().data,
       mtu // or 512
     ).then(() => {
       // Success code
       console.log("Write: " + buffer.toJSON().data);
     })

En el lado ESP32, hay un método en la biblioteca BLEDevice para definir el tamaño de MTU.

BLEDevice::setMTU(512); //between 23 and 517 (bluetooth 4.2)

N.B.: En este ejemplo (Android+ESP32), la única forma de aumentar el límite es definir el número máximo de bytes en la función BLEManager.write(). Dejaremos el resto de información que pueda ser útil para otra configuración (iOS, HM10, etc.).

Una vez modificado el código, cuando devolvamos la misma cadena de caracteres, recibiremos su valor completo en la función BLE

Aplicaciones

Fuentes

Salir de la versión móvil