I have a program that I previously wrote on ESP32 with the ESP32 BLE library that I am porting to ArduinoBLE to run on a Nano 33 IoT. Because I already wrote the previous program, I have a pretty good understanding of how BLE works, but am struggling with the ArduinoBLE library, which is limited compared to the ESP32 library.
The nano is a central device, connecting to a peripheral using read with notifications. (I think, it seems I can't explicitly set notifications vs indications when I subscribe). The data I am reading comes in blocks (responses to data I write) that range from 7 bytes to about 40 bytes. When I process the notification, I add it to a circular buffer, so that I can deal with the data being broken up into multiple notifications, and I put it back together. This worked on the ESP32.
With shorter responses, less than about 16 bytes, it works fine. With longer responses I only get the last part of the data, and the first 2 bytes of that last part are zeros. I am only receiving a single notification, that which contains the second half of data, or else the data is changing before I have a chance to read it.
The most obvious fix for me would be to change the MTU to about 40 bytes. But ArduinoBLE doesn't seem to allow that. Or, if I used an indication instead of a notification, then maybe that would slow the data until I was ready for it. But that doesn't seem supported either. Or, on ESP32 notifications are handled by a blocking callback function, and include the data with the notification, so I don't have to follow up with a readValue. This handles them right away so no data is lost. But the Arduino doesn't support that either, and notifications are handled in the main loop.
My code is quite long, but here are snippets:
Connected already then subscribe in main loop.
// retrieve the characteristic
BLECharacteristic readCharacteristic = peripheral.characteristic(BLE_RX_UUID);
BLECharacteristic writeCharacteristic = peripheral.characteristic(BLE_TX_UUID);
if (!readCharacteristic) {
Serial.println("Peripheral does not have Read characteristic!");
peripheral.disconnect();
return;
} else if (!readCharacteristic.canSubscribe()) {
Serial.println("Peripheral does not have a subscribe characteristic!");
peripheral.disconnect();
return;
} else if (!readCharacteristic.subscribe()) {
Serial.println("subscription failed!");
peripheral.disconnect();
return;
}
if (!writeCharacteristic) {
Serial.println("Peripheral does not have Write characteristic!");
peripheral.disconnect();
return;
}
Handle the notification. This is in a separate function with characteristics passed via pointers. It is called repeatedly as fast as I can from the main loop. Testing, I even call this every other line of code. But, I additionally call it immediately after I write a value, since that is when I expect a response. It doesn't seem to matter how fast I call this, I only get one notification, and only read the second half of the data.
if (myReadCharacteristic->valueUpdated()) {
int length = myReadCharacteristic->valueLength();
Serial.print("Bytes Received: ");Serial.println(length);
myReadCharacteristic->readValue(pData, length );
for (int i = 0; i < length; i++){
Serial.print(pData[i], HEX);Serial.print(" ");
receiveBuffer.add(pData[i]);
}
Serial.println();
Serial.print("rx Buffer Length: ");Serial.println(receiveBuffer.getLength());
}