Etiquetas: , , ,

O Bluetooth Low Energy (BLE) tem um limite conhecido de 20 Bytes para o comprimento das cadeias de caracteres enviadas. Existem formas de ultrapassar este limite.

Hardware

Neste tutorial, vamos enviar dados de uma aplicação Android, desenvolvida com React Native, para um ESP32. Os métodos descritos também podem ser válidos para outros dispositivos.

  • Dispositivo Android
  • ESP32 BLE

BLE limitado a 20 bytes

A aplicação desenvolvida em React Native é perfeitamente capaz de enviar cadeias de caracteres longas sob a forma de um pacote de 20 bytes por defeito. Sem modificar o tutorial anterior, aqui está o valor recebido no lado do ESP32. Apenas o último pacote é armazenado na memória.

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

Resumo dos métodos de envio de cadeias longas via BLE

  • Recuperar vários pacotes (no lado do recetor)
  • Enviar a cadeia longa sob a forma de pequenos pacotes (lado do remetente)
  • Aumentar o limite de MTU de 23 bytes para 512 bytes

Recuperação de vários pacotes

Se o dispositivo que envia as mensagens for capaz de suportar o envio de cadeias de caracteres que excedam o limite do MTU, como é o caso do nosso exemplo, resta apenas configurar o módulo recetor para concatenar os vários pacotes recebidos. Para isso, utilizamos um carácter de fim de cadeia, como “;”.

Na função onWrite na caraterística do módulo ESP32BLE, adicionamos um teste de fim de cadeia e uma variável longMsg para atuar como um 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;
        }
      }
    }
};
esp32-ble-long-string-receive-packets Envio de cadeias longas de caracteres através de BLE

Envio de tamanhos de pacotes predefinidos

Se o dispositivo que envia os dados não gere mensagens maiores do que a MTU, é possível dividir a cadeia de caracteres em pacotes de tamanho predefinido (chunksize). Este método permite controlar o tamanho dos pacotes enviados.

No projeto React Native, estamos a criar uma função que transformará a cadeia de caracteres longa num array de bytes que enviaremos em pacotes.

    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);
        }
    }
esp32-ble-long-string-custom-size-packets Envio de cadeias longas de caracteres através de BLE

N.B.: pode ser introduzida uma função de atraso para dar tempo ao envio da mensagem. delay(100)

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

Aumentar o limite de MTU da aplicação

Por defeito, a biblioteca react-native-ble-manager envia pacotes de 20 bytes. Existe um método para especificar que o módulo BLE deve modificar o tamanho da unidade máxima de transmissão (MTU)

No código da aplicação, durante a ligação, antes de obter os serviços, adicionar um pedido de MTU

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

Ao enviar a mensagem, pode especificar o tamanho máximo da mensagem em bytes, “mtu”, na função BLEManager.write().

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

No lado do ESP32, existe um método na biblioteca BLEDevice para definir o tamanho do MTU.

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

Nota: neste exemplo (Android+ESP32), a única forma de aumentar o limite é definir o número máximo de bytes na função BLEManager.write(). Deixamos as outras informações que podem ser úteis para outra configuração (iOS, HM10, etc.).

Depois de o código ter sido modificado, quando devolvemos a mesma cadeia de caracteres, recebemos o seu valor total na funcionalidade BLE

esp32-ble-long-string-increase-mtu Envio de cadeias longas de caracteres através de BLE

Aplicações

  • Aumentar o tamanho das mensagens enviadas para o módulo BLE
  • Imitar o funcionamento do Bluetooth clássico numa base pontual

Fontes