Search code examples
androidnotificationsbluetooth-lowenergyesp32gatt

Many empty PDUs in ESP32 Upgrade over BLE


I am doing a firmware upgrade of a BLE peripheral device based on ESP32 from an Android central. The firmware file is sent in parts of 512 bytes each. The ESP32 device (the GATT server) sends a notification to the central (GATT client) and the central sends the next part, followed by a write command to the peripheral. Then the next notification is sent and so on.

The upgrade works, however, it takes a long time to complete (~10-12 min for a 600kB file). I sniffed the traffic with Wireshark and it turned out there are 15-20 empty PDUs between the sending of each notification by the peripheral and the start of sending the part by the central. I searched what may be the problem on the server side but could not find anything relevant.

Maybe something is happening on the Android central that delays the sending process? Or maybe I am missing something with the ESP32? Here is a Wireshark capture (I’ve underlined in red where the sending should start):

enter image description here

EDIT: I haven't added extra sleep on server and if I had, there would be no empty server PDUs, correct?

I tried what you suggested, to use just android's internal mechanism for confirmation and the download is now about 3x faster. Thank you! However, in the captures there are some strange (to me) things like a lot of 26-byte response packets from the server to the master (captures below). Why is that and is it possible to combine them into 3 packets, the way they were sent from the master?

Also, about he explanation in the link you gave:

The Bluetooth controller sends a "number of packets complete" event back to Android's Bluetooth stack over HCI which indicates that the Link Layer of the remote's device has acknowledged a packet.

I didn't quite get that. If its a Write_No_Response from the master, how does the remote device acknowledge receiving a packet? And is this Android flow control mechanism a possible explanation of my original problem with the empty packets?

enter image description here

enter image description here


Solution

  • Seems like the Android device is not fast enough, or you have added an extra sleep.

    Assuming the peripheral can handle the data, you can quite reliably send write commands without using a notification acknowledging scheme. See onCharacteristicWrite and onNotificationSent are being called too fast - how to acquire real outgoing data rates?. Basically just wait for onCharacteristicWrite before sending the next one.