Site icon AranaCorp

Sending long character strings via BLE

Bluetooth Low Energy (BLE) has a known limit of 20Bytes on the length of strings sent. There are ways of overriding this limit.

Hardware

In this tutorial, we’ll send data from an Android application, developed under React Native, to an ESP32. The methods described may be valid for other devices.

BLE 20-byte limit

The application developed under React Native is fully capable of sending long character strings in the form of 20byte packets by default. Without modifying the previous tutorial, here’s the value received on the ESP32 side. Only the last packet is stored in memory.

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

Summary of methods for sending long strings via BLE

Recover multiple packages

If the device sending the messages is capable of handling the sending of strings that exceed the MTU limit, as is the case in our example, all that remains is to configure the receiving module to concatenate the various packets received. To do this, we use an end-of-string character, such as “;”.

In the onWrite function of the ESP32BLE module, we add an end-of-string test and a longMsg variable to act as a 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;
        }
      }
    }
};

Send packets of predefined size

If the device sending the data doesn’t handle messages larger than the MTU, then the string can be split into packets of predefined size (chunksize). This method makes it possible to control the size of packets sent.

In the React Native project, we’re creating a function that will transform the long string into an array of bytes, which we’ll send in packets.

    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.: a delay function can be introduced to allow time for the message to be sent. delay(100)

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

Increase application MTU limit

By default, the react-native-ble-manager library sends 20-byte packets. There is a method for specifying the Maximum Transmission Unit (MTU) size to the BLE module.

In the application code, during connection, before retrieving services, add an MTU request

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

When sending the message, you can specify the maximum message size in bytes, “mtu”, in the BLEManager.write() function.

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

On the ESP32 side, the BLEDevice library provides a method for defining the MTU size.

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

N.B.: In this example (Android+ESP32), the only way to increase the limit is to set the maximum number of bytes in the BLEManager.write() function. We’ll leave the other information that might be useful for another configuration (iOS, HM10, etc.).

Once the code has been modified, when we return the same character string, we receive its full value in the BLE feature

Applications

Sources


Exit mobile version