ArduinoBLE
ArduinoBLE copied to clipboard
Event Handling Mix-up in ArduinoBLE with Multiple Peripherals
While developing our software which needs to receive input from several Bluetooth devices, we have run into a strange problem. Any help would be very appreciated.
Problem Description:
An ESP32-S3-DevKitC-1-N32R8V connects to two peripheral devices (A and B). After detecting a device, its peripheral
object is stored in a global std::unordered_map
. Once both devices are detected, the std::unordered_map
contains two elements, each representing an instance of the PeripheralDevice
class.
The PeripheralDevice
constructor performs the following actions:
- Stores the passed
peripheral
object fromBLE.available()
. - Connects to the device.
- Connects to a service and subscribes to a characteristic.
- Sets up an event handler of type
BLEUpdated
using thesetEventHandler
method.
Upon successful connection, event handlers for each characteristic are set. The BLE devices send data arrays of 60 bytes approximately 60 times per second.
Expected Behavior:
- The event handler
Handler_A
in instanceA
should receive data only from Device A. - The event handler
Handler_B
in instanceB
should receive data only from Device B.
Actual Problem:
When changes occurs on Device A (e.g., a button press), the Handler_B
of instance B
also sometimes receives events and data originating from Device A, in an undefined order. This remains consistent with different numbers of devices (three or more) as well.
Additional Observations:
The issue persists even if polling the devices directly instead of subscribing to BLE notifications. When using direct functions like valueUpdated()
and canRead()
to read data in each instance (A
and B
), reading data via Instance B still appears to receive data from Device B and vice versa. Each instance uses its own reading functions, which are expected to operate independently.
Code Overview:
Connection Description:
Two identical peripheral devices (A and B) connect to the Arduino board, which retrieves data from them.
After scanning, peripherals are stored in:
std::unordered_map<std::string, PeripheralDevice *> devices;
loop() {
BLEDevice.poll();
BLEDevice peripheral = BLE.available();
if (peripheral) {
String deviceName = peripheral.localName();
if (strstr(deviceName.c_str(), "Controller") != NULL) {
PeripheralDevice *device = new PeripheralDevice(peripheral);
devices[peripheral.address().c_str()] = device;
}
}
}
PeripheralDevice
Constructor:
-
Store
peripheral
in the instance:PeripheralDevice::PeripheralDevice(BLEDevice &_peripheral) { peripheral = _peripheral; }
-
Connect to the device:
peripheral.connect();
-
Discover and connect to a service:
if (peripheral.discoverService(UUID_CUSTOM_SERVICE) && (service = peripheral.service(UUID_CUSTOM_SERVICE))) { ... }
-
Connect to a characteristic:
serviceNotify = service.characteristic(UUID_CUSTOM_SERVICE_NOTIFY);
-
Subscribe to the characteristic:
if (!serviceNotify.canSubscribe() && !serviceNotify.subscribe()) { return; }
-
Set up an event handler:
serviceNotify.setEventHandler(BLEUpdated, [](BLEDevice bleDevice, BLECharacteristic characteristic) { uint8_t value[60] = {}; if (characteristic.readValue(value, sizeof(value)) == sizeof(value)) { if (value[58] != 0x40) { Log.notice("%s: %x <-> ", bleDevice.address().c_str(), value[58]); for (size_t i = 0; i < 60; ++i) { char byteBuffer[3]; sprintf(byteBuffer, "%02X", value[i]); Log.notice("%s ", byteBuffer); } Log.noticeln(""); } } });
Steps to Reproduce:
- Connect the Arduino board to two BLE devices with identical configurations (in our case, two Samsung GearVR Controllers).
- Use the
PeripheralDevice
class to manage each connection and subscribe to their characteristics. - Trigger an event (e.g., button press) on Device A.
- Observe the event handler of Device B receiving data intended for Device A.
Environment:
- Hardware: ESP32-S3-DevKitC-1-N32R8V board which embeds a WROOM-2 BLE connectivity module
- Library: ArduinoBLE
- Peripheral Devices: Two identical BLE devices (Samsung GearVR Controller)
- Data Rate: 60 bytes/frame, ~60 frames/second