How to solve the overflow phenomenon in Bluetooth high speed transmission?

HI! I tried to transmit at the rate of 36000 bytes(Send the notify of the device continuously), but win10 bluetooth receiver has packet loss phenomenon, although there is no lack of comma or period, Win10 received Bluetooth packet string is relatively complete, but missing more than a dozen complete packets, as shown below:

BLE: ESP32 DEVKIT V1
PC: NOTEBOOK COMPUTER

Win10 Code:

import sys
import time
import platform
import asyncio
import logging

from bleak import BleakClient

logger = logging.getLogger(__name__)

ADDRESS = (
    "24:71:89:cc:09:05"
)
CHARACTERISTIC_UUID = f"ca73b3ba-39f6-4ab3-91ae-186dc9577d99"


async def run_ble_client(address: str, char_uuid: str, queue: asyncio.Queue):
    async def callback_handler(sender, data):
        await queue.put((time.time(), data))

    async with BleakClient(address) as client:
        logger.info(f"Connected: {client.is_connected}")
        await client.start_notify(char_uuid, callback_handler)
        while True:
                await asyncio.sleep(10.0)
        # await client.stop_notify(char_uuid)
        # Send an "exit command to the consumer"
        await queue.put((time.time(), None))


async def run_queue_consumer(queue: asyncio.Queue):
    while True:
        # Use await asyncio.wait_for(queue.get(), timeout=1.0) if you want a timeout for getting data.
        epoch, data = await queue.get()
        if data is None:
            logger.info(
                "Got message from client about disconnection. Exiting consumer loop..."
            )
            break
        else:
            logger.info(f"Received callback data via async queue at {epoch}: {data}")


async def main(address: str, char_uuid: str):
    queue = asyncio.Queue()
    client_task = run_ble_client(address, char_uuid, queue)
    consumer_task = run_queue_consumer(queue)
    await asyncio.gather(client_task, consumer_task)
    logger.info("Main method done.")


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    asyncio.run(
        main(
            sys.argv[1] if len(sys.argv) > 1 else ADDRESS,
            sys.argv[2] if len(sys.argv) > 2 else CHARACTERISTIC_UUID,
        )
    )

ESP32 ino Code:

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
// #include <periph_ctr
#define SERIAL_RX_BUFFER_SIZE 2048
BLEServer *pServer = NULL;
BLECharacteristic *pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
boolean newData = false;

const byte numChars = 36;
uint8_t txValue = 0;
char receivedChars[numChars];

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "f78ebbff-c8b7-4107-93de-889a6a06d408"
#define CHARACTERISTIC_UUID_TX "ca73b3ba-39f6-4ab3-91ae-186dc9577d99"

class MyServerCallbacks : public BLEServerCallbacks
{
  void onConnect(BLEServer *pServer)
  {
    deviceConnected = true;
  };

  void onDisconnect(BLEServer *pServer)
  {
    deviceConnected = false;
  }
};

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

    if (rxValue.length() > 0)
    {
      Serial2.println("*********");
      Serial2.print("Received Value: ");
      for (int i = 0; i < rxValue.length(); i++)
        Serial2.print(rxValue[i]);

      Serial2.println();
      Serial2.println("*********");
    }
  }
};
void setup()
{
  Serial1.begin(500000, SERIAL_8N1, 3, 1);
  Serial2.begin(500000, SERIAL_8N1, 16, 17);

  // Create the BLE Device
  BLEDevice::init("UART Service");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pTxCharacteristic = pService->createCharacteristic(
      CHARACTERISTIC_UUID_TX,
      BLECharacteristic::PROPERTY_NOTIFY);

  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
      CHARACTERISTIC_UUID_RX,
      BLECharacteristic::PROPERTY_WRITE);

  pRxCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();

  // // 确定传感器的连接状态
  // // 缓冲区没有字符时,每半秒发送1次
  // while (true)
  // {
  //   if (Serial1.available() <= 0)
  //   {
  //     Serial1.print('A');
  //     delay(500);
  //   }
  //   else
  //   {
  //     while (Serial1.available()>=0)
  //     {
  //       Serial1.read();
  //     }
  //     break;
  //   }
  // }
  Serial2.println("\nSet Serial1 ok!");
  Serial2.println("Waiting a client connection to notify...");
}

// void loop()
// {
//   recvWithEndMarker();
//   showNewData();
// }

// 接收串口数据,并
void recvWithEndMarker()
{
  static byte ndx = 0;
  static boolean recvInProgress = false;
  char startMaker = '<';
  char endMarker = '>';
  char rc;

  // if (Serial1.available() > 0) {
  while (Serial1.available() > 0 && newData == false)
  {
    rc = Serial1.read();
    if (recvInProgress == true)
    {
      if (rc != endMarker)
      {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars)
        {
          ndx = numChars - 1;
        }
      }
      else
      {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }
    else if (rc == startMaker)
    {
      recvInProgress = true;
    }
  }
}

// 输出数据
void showNewData()
{
  if (newData == true)
  {
    Serial2.println(receivedChars);
    pTxCharacteristic->setValue(receivedChars);
    pTxCharacteristic->notify();
    newData = false;
  }
}
void loop()
{
  // disconnecting
  if (!deviceConnected && oldDeviceConnected)
  {
    delay(500);                  // 让蓝牙堆栈有机会做好准备
    pServer->startAdvertising(); // 重启广播
    Serial2.println("disconnecting start advertising");
    oldDeviceConnected = deviceConnected;
    ESP.restart();
  }
  // connecting
  if (deviceConnected && !oldDeviceConnected)
  {
    // do stuff here on connecting在连接上做点事情
    oldDeviceConnected = deviceConnected;
    Serial2.println("connecting start advertising");
  }
  if (deviceConnected)
  {

    recvWithEndMarker();
    showNewData();

    // long time = millis();
    // for (int i = 0; i < 7000; i++)
    // {
			// recvWithEndMarker();
			// showNewData();
    // }
    // float a = 1000 / ((millis() - time) / 1000);
    // Serial2.println();
    // Serial2.println();
    // Serial2.println();
    // Serial2.println();
    // Serial2.println();
    // Serial2.println();
    // Serial2.println(xiao.data());
    // delay(100000);
  }
}

BLE typically has a connection interval of about 30 to 50 milliseconds, so it can only send 20 to 30 packets per second. HID devices can have the fastest interval of 15 milliseconds (depending on the configuration) which would be 66 packets per second. The maximum MTU is for most devices is 512 bytes, so this would give 66 * 512 = approx 34000 bytes per second. So perhaps the buffer on the ESP32 is overflowing from trying to send data faster than what is possible.

I tried to reduce the speed to 8000-10000 bytes, but it still lost packets.

I have no experience in bluetooth debugging. I need to ensure a high rate of data transmission and avoid packet loss.What is the solution for ESP32 sending buffer overflow?

Thank you for reading this question.:grinning:

I tried to use classic Bluetooth, but got frustrated along the develop. I had the same problem from the url: https://forum.arduino.cc/t/bluetooth-not-working-with-windows-10-and-not-working-with-android/920136

To solve this problem, use the Python third-party library Bleak to detect the upper limit of the MTU value of Bluetooth to maximize throughput and thus reduce packet loss rates.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.