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; } } } };
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); } }
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
Aplicações
- Aumentar o tamanho das mensagens enviadas para o módulo BLE
- Imitar o funcionamento do Bluetooth clássico numa base pontual