-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Description
Hardware:
Board: Sparkfun ESP32 Thing
Core Installation/update date: No different as of today (28/1/2018) from origin/master of https://github.com/espressif/arduino-esp32.git
IDE name: Arduino IDE 1.8.5
Flash Frequency: 80Mhz
Upload Speed: 921600
Description:
Side Note: In my opinion, the BLE library for ESP32 with the Arduino IDE is an excellent piece of work. The API is well-structured and clearly written from from the ground up, uses meaningful classes, consistent naming, etc. etc. I have found it and presumably therefore the underlying esp-idf code to be robust.
I have encountered what appears to be an incorrect (and hopefully unnecessary) constraint in the implementation of the BLECharacteristic::addDescriptor method. If multiple descriptors with the same UUID are added to a characteristic, only the first one gets a valid handle allocated during the BLEService start() method and, in my tests, is the only one seen by a BLE GATT client using service discovery.
As I understand the BLE spec's, a characteristic's descriptors are not required to have distinct UUIDs and it is intended that in some cases they do not. For example, if Characteristic Presentation Format descriptors (UUID 0x2904) are being used, there are multiple of them for a characteristic with multiple data elements in its payload. (The Characteristic Aggregate Format descriptor (0x2905) can then be used to define the order of multiple Characteristic Presentation Format descriptors within that payload.)
In this library, the association of descriptors with a characteristic is implemented using a std::map and addDescriptor uses setByUUID method to update that map with a UUID as the key. Since std::map requires keys to be unique, that would appear to be at least one cause of this issue. I do not know whether the underlying software or firmware also imposes such a constraint and hence do not know whether it can be fixed in this library alone.
Can anyone with knowledge of the underlying BLE software/firmware comment on whether characteristics with duplicate descriptor UUIDs are supported further down the stack?
Sketch:
//Change the code below by your sketch
/*
Test sketch to demonstrate isse with multiple descriptors with the same UUID not working with the ESP32 BLE Arduino library.
Based on examples/BLE_server ...
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
Ported to Arduino ESP32 by Evandro Copercini
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
// Logically, our characteristic value consists of two fields, the first an unsigned 8 bit integer, the second an unsigned 16 bit integer.
// Physically, that is just three octets.
uint8_t characteristicValue1[] = {
0x11,
0x22, 0x33,
};
// The logical structure of the above is described by two Characteristic Presentation Format descriptors, one for each field. See:
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
// With more than one Characteristic Presentation Format descriptors, we should also have a Characteristic Aggregate Format descriptor,
// however that would need the handles of the Characteristic Presentation Format descriptors but we don't get a valid handle for the second one.
uint8_t presentationFormat1[] = {
0x04, // Format = 4 = "unsigned 8-bit integer"
0x00, // Exponent = 0
0x00, // Unit = 0x2700 = "unitless" (low byte)
0x27, // ditto (high byte)
0x01, // Namespace = 1 = "Bluetooth SIG Assigned Numbers"
0x00, // Description = 0 = "unknown" (low byte)
0x00, // ditto (high byte)
};
uint8_t presentationFormat2[] = {
0x04, // Format = 6 = "unsigned 16-bit integer"
0x00, // Exponent = 0
0x00, // Unit = 0x2700 = "unitless" (low byte)
0x27, // ditto (high byte)
0x01, // Namespace = 1 = "Bluetooth SIG Assigned Numbers"
0x00, // Description = 0 = "unknown" (low byte)
0x00, // ditto (high byte)
};
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\r\nStarting BLE work!");
BLEDevice::init("MyESP32");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
// create two descriptors with the same UUID
BLEDescriptor *pDescriptor1 = new BLEDescriptor((uint16_t)0x2904); // Characteristic Presentation Format
BLEDescriptor *pDescriptor2 = new BLEDescriptor((uint16_t)0x2904); // ditto
// and one with a different UUID
BLEDescriptor *pDescriptor3 = new BLEDescriptor((uint16_t)0x2901); // Characteristic User Description
// confirm that the second descriptor was created despite its duplicate UUID
if (pDescriptor2)
Serial.println("pDescriptor2 created OK");
else
Serial.println("!pDescriptor2");
// attach all three descriptors to our one characteristic
pCharacteristic->addDescriptor(pDescriptor1);
pCharacteristic->addDescriptor(pDescriptor2);
pCharacteristic->addDescriptor(pDescriptor3);
// give the characteristic a value and start the service
pCharacteristic->setValue(characteristicValue1, sizeof characteristicValue1);
pService->start();
// set the descriptors' values
pDescriptor1->setValue(presentationFormat1, sizeof presentationFormat1);
pDescriptor2->setValue(presentationFormat2, sizeof presentationFormat2);
pDescriptor3->setValue("My Test Characteristic");
// enable advertising so that this device can be easily found
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->start();
// have valid handles been allocated for the descriptors?
Serial.print("pDescriptor1->getHandle()=0x"); Serial.println(pDescriptor1->getHandle(), HEX);
Serial.print("pDescriptor2->getHandle()=0x"); Serial.println(pDescriptor2->getHandle(), HEX);
Serial.print("pDescriptor3->getHandle()=0x"); Serial.println(pDescriptor3->getHandle(), HEX);
Serial.println("Look for MyESP32 and do service discovery with your favourite BLE scanner.");
Serial.println("I used \"BLE Scanner 4.0\" (Version 2.0.1) from \"bluepixel technologies\" on iOS");
}
void loop() {
// put your main code here, to run repeatedly:
delay(2000);
}
Debug Messages:
pDescriptor1->getHandle()=0x2C
pDescriptor2->getHandle()=0xFFFF
pDescriptor3->getHandle()=0x2B