Description
Background Info
I am using a Nano 33 IoT 33. In this scenario, my Arduino plays a peripheral role.
What I refer to as "BLE cycle" is the process of using BLE.begin()
... up until the BLE.end()
, with all the setup and config functions in between.
Problem Description
During my first BLE cycle, everything goes as planned and I can communicate perfectly fine. However, upon ending BLE and doing other stuff, then coming back to it in another step, there will usually be one of these errors:
- Option 1: The BLEService is totally missing. The advertised UUID may be there, but the service does not get exposed.
- Option 2: The BLEService is there, but with no characteristics. Yes, I've made sure that I add the characteristics - the same code that adds them in the first time is triggered the second time.
Thus this completely interrupts my device setup flow and I have to resort to resetting the device. Thankfully I have a state machine implementation but I don't believe this is a solution.
What I've Tried
- Keeping the same characteristics + service throughout BLE cycles, but made sure to reset their values after every relaunch of BLE. In this approach I usually end up with Option 2.
- Creating new characteristics + service for each BLE cycle. This sometimes works, but I have not been able to keep it working consistently. See section below for more details.
Solution 2
In this solution, as described above, I opt to create a new characteristic and service for every BLE cycle. I have found that this sometimes works, specifically in these cases:
- When you do not write to any characteristic.
- When I write to the service through the LightBlue app by PunchThrough, it doesn't seem to mind multiple writes and restarts correctly.
- When I write to the service through the app I have developed, which is using this plugin, it almost always breaks - UNLESS I only write to one characteristic. I'm not doing anything special there, but you can view it for context in the case that I've failed to realize any errors.
I'm all out of ideas at the moment. There's clearly something going wrong in the library level. I haven't been able to pinpoint exactly what causes this. Is there a way to enable some form of verbose logging in your library?
Minimal Reproducible Example
#include <ArduinoBLE.h>
char BLE_NAME[] = "proto_01";
char SERVICE_UUID[] = "11111111-1111-1111-1111-111111111110";
char SERIAL_UUID[] = "11111111-1111-1111-1111-11111111111A";
char SSID_UUID[] = "11111111-1111-1111-1111-11111111111B";
char PASS_UUID[] = "11111111-1111-1111-1111-11111111111C";
char JWT_UUID[] = "11111111-1111-1111-1111-11111111111D";
static const int MAX_JWT_CHARACTERISTIC_BUFFER_SIZE = 512;
static const int MAX_CHARACTERISTIC_BUFFER_SIZE = 64;
// ---- Advertisement ----
BLEService* bleService;
BLEStringCharacteristic* bleSerialChar;
BLEStringCharacteristic* bleSsidChar;
BLEStringCharacteristic* blePassChar;
BLEStringCharacteristic* bleJwtChar;
void newCharacteristics()
{
bleService = new BLEService(SERVICE_UUID);
bleSerialChar = new BLEStringCharacteristic(SERIAL_UUID, BLERead, MAX_CHARACTERISTIC_BUFFER_SIZE);
bleSsidChar = new BLEStringCharacteristic(SSID_UUID, BLEWrite, MAX_CHARACTERISTIC_BUFFER_SIZE);
blePassChar = new BLEStringCharacteristic(PASS_UUID, BLEWrite, MAX_CHARACTERISTIC_BUFFER_SIZE);
bleJwtChar = new BLEStringCharacteristic(JWT_UUID, BLEWrite, MAX_JWT_CHARACTERISTIC_BUFFER_SIZE);
}
void freeCharacteristics()
{
bleService->clear();
delete bleSerialChar;
delete bleSsidChar;
delete blePassChar;
delete bleJwtChar;
delete bleService;
}
void setup() {
Serial.begin(9600);
while (!Serial);
}
void loop() {
setupBle();
long startClock = millis(); // Sample time
while (millis() - startClock < 60000)
{
BLE.poll();
// Write to the SSID char (ends in B) to trigger the bug
if (bleSsidChar->written())
{
Serial.println("Wrote SSID");
break;
}
}
endBle();
}
void setupBle() {
newCharacteristics();
// Add characteristics
bleService->addCharacteristic(*bleSerialChar);
bleService->addCharacteristic(*bleSsidChar);
bleService->addCharacteristic(*blePassChar);
bleService->addCharacteristic(*bleJwtChar);
// Write the serial to the characteristic to be readable
bleSerialChar->writeValue(String(4));
// begin initialization
if (!BLE.begin()) {
Serial.println("starting Bluetooth® Low Energy module failed!");
while (1);
}
BLE.setAdvertisedService(*bleService);
BLE.addService(*bleService);
// start advertising
BLE.advertise();
Serial.println("Bluetooth® device active, waiting for connections...");
}
void endBle() {
BLE.central().disconnect();
BLE.stopAdvertise();
BLE.end();
freeCharacteristics();
}