Hi ~ Now I'm trying to make a BLE project using esp32.
But I have some error about this line.
pServer->getAdvertising()->start(); <- not working
create service, characteristic is fine..
I'd like to create 1 server that has 7 services
each service has char below
A service -> 2 char
B service -> 6 char
C service -> 1 char
D service -> 2 char
E service -> 7 char
F service -> 2 char
G service -> 2 char
So, I tried to make a code using example project
Have it limit to create service or characteristic?
If I created 7 services, It couldn't start advertising
Is it limited number of services and characteristics?
Hi,
i remember there was issue here claiming that someone has server with 10 services or so and about 80 characteristics (maybe numbers are not accurate, but something like that).
Recently i found issue on forum about creating some amount of characteristics and i tested it. There is problem somewhere for sure, maybe menuconfig and number of handles.
My suggestion is to create services with this function:
https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLEServer.h#L67
and adjust handles value.
you need 2 handles per characteristic and 1 per descriptor.
@chegewara Thank you for suggestion!
Now I'm using arduino Ide, I tried to adjust handle value each service. But I still have same problem.
Did you tried to any change sdkconfig file?
No, nothing changed in sdkconfig.
@chegewara
the handle value jump 0x0061 to 0xb33f
it's has limited handle values?
```
14:25:00.007 -> [D][BLECharacteristic.cpp:90] executeCreate(): Registering characteristic (esp_ble_gatts_add_char): uuid: 0000ffc3-0000-1000-8000-00805f9b34fb, service: UUID: 0000ffe2-0000-1000-8000-00805f9b34fb, handle: 0x0061
14:25:00.042 -> [D][FreeRTOS.cpp:189] take(): Semaphore taking: name: CreateEvt (0x3ffe77f0), owner:
14:25:00.042 -> [D][FreeRTOS.cpp:198] take(): Semaphore taken: name: CreateEvt (0x3ffe77f0), owner: executeCreate
14:25:00.076 -> [D][BLEDevice.cpp:102] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 4] ... Unknown
14:25:00.076 -> [D][FreeRTOS.cpp:189] take(): Semaphore taking: name: CreateEvt (0x3ffe7a3c), owner:
14:25:00.076 -> [D][FreeRTOS.cpp:198] take(): Semaphore taken: name: CreateEvt (0x3ffe7a3c), owner: executeCreate
14:25:00.076 -> [D][BLEDevice.cpp:102] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 4] ... Unknown
14:25:00.111 -> [D][FreeRTOS.cpp:189] take(): Semaphore taking: name: StartEvt (0x3ffe262c), owner:
14:25:00.111 -> [D][FreeRTOS.cpp:198] take(): Semaphore taken: name: StartEvt (0x3ffe262c), owner: start
14:25:00.111 -> [D][BLEDevice.cpp:102] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 4] ... Unknown
14:25:00.111 -> start pService service
14:25:00.212 -> [D][BLECharacteristic.cpp:90] executeCreate(): Registering characteristic (esp_ble_gatts_add_char): uuid: 0000ff01-0000-1000-8000-00805f9b34fb, service: UUID: 0000ffe3-0000-1000-8000-00805f9b34fb, handle: 0xb33f
14:25:00.246 -> [D][FreeRTOS.cpp:189] take(): Semaphore taking: name: CreateEvt (0x3ffe7cac), owner:
14:25:00.246 -> [D][FreeRTOS.cpp:198] take(): Semaphore taken: name: CreateEvt (0x3ffe7cac), owner: executeCreate
Its either some bug/error or peripheral device has programmed handle 0xb33f.
I do have the same issue. All is well until I try to start the seventh service. Totally freezes at that point - no crash report, just freezes. I simplified my code the bare minimum if anyone wants it to recreate the error.
Could you share code, i am too lazy to build app with so many services/characteristics, but i can test and try to find problem.
// Arduino IDE version: 1.8.12 Board: WEMOS LOLIN32
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#define NUM_SERVICES 7
#define NUM_SERVICES_TO_START 7 // Make this 6 or fewer it works fine
#define NUM_CHARACTERISTICS 1
#define SERVICE_ADVERTISING services[0]
BLEUUID services[NUM_SERVICES];
BLEUUID characteristics[NUM_SERVICES][NUM_CHARACTERISTICS];
BLEServer* pServer;
BLEService* pService[NUM_SERVICES];
BLECharacteristic* pCharacteristics[NUM_SERVICES][NUM_CHARACTERISTICS];
void setup() {
Serial.begin(115200);
Serial.println("Starting");
services[0] = BLEUUID("ab529100-5310-483a-b4d3-7f1eaa8134a0");
characteristics[0][0] = BLEUUID("ab529101-5310-483a-b4d3-7f1eaa8134a0");
services[1] = BLEUUID("ab529200-5310-483a-b4d3-7f1eaa8134a0");
characteristics[1][0] = BLEUUID("ab529201-5310-483a-b4d3-7f1eaa8134a0");
services[2] = BLEUUID("ab529300-5310-483a-b4d3-7f1eaa8134a0");
characteristics[2][0] = BLEUUID("ab529301-5310-483a-b4d3-7f1eaa8134a0");
services[3] = BLEUUID("ab529400-5310-483a-b4d3-7f1eaa8134a0");
characteristics[3][0] = BLEUUID("ab529401-5310-483a-b4d3-7f1eaa8134a0");
services[4] = BLEUUID("ab529500-5310-483a-b4d3-7f1eaa8134a0");
characteristics[4][0] = BLEUUID("ab529501-5310-483a-b4d3-7f1eaa8134a0");
services[5] = BLEUUID("ab529600-5310-483a-b4d3-7f1eaa8134a0");
characteristics[5][0] = BLEUUID("ab529601-5310-483a-b4d3-7f1eaa8134a0");
services[6] = BLEUUID("ab529700-5310-483a-b4d3-7f1eaa8134a0");
characteristics[6][0] = BLEUUID("ab529701-5310-483a-b4d3-7f1eaa8134a0");
BLEDevice::init("S-Test");
pServer = BLEDevice::createServer();
//-------------------------------------------------------
// Define the services with one read characteristic each
//-------------------------------------------------------
for(int i = 0; i < NUM_SERVICES; i++) {
pService[i] = pServer->createService(services[i]);
if(pService[i] == nullptr) {
Serial.println("service not created - ABORT");
while(true);
}
pCharacteristics[i][0] = pService[i]->createCharacteristic(characteristics[i][0], BLECharacteristic::PROPERTY_READ);
if(pCharacteristics[i][0] == nullptr) {
Serial.println("characteristic not created - ABORT");
while(true);
}
pCharacteristics[i][0]->setValue("abc123");
Serial.print("Service "); Serial.print(i); Serial.println(" defined");
}
Serial.println("All Services defined");
//----------------------------
// Now start all the services
//----------------------------
for(int i = 0; i < NUM_SERVICES_TO_START; i++) {
pService[i]->start(); // if NUM_SERVICES_TO_START is > 6 this call hangs
Serial.print("Service "); Serial.print(i); Serial.println(" started");
}
Serial.println("All Services started");
//-----------------------------
// Advertise the first service
//-----------------------------
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_ADVERTISING);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
Serial.println("Advertising Service");
}
uint32_t tickMillis = millis();
void loop() {
// put your main code here, to run repeatedly:
if(millis() - tickMillis > 60000) {
Serial.println("tick");
tickMillis = millis();
}
}
Ok, i tested it and i have the same observations like @JAICHANGPARK
@chegewara
the handle value jump 0x0061 to 0xb33f
it's has limited handle values?
Just in my case its even higher value:
[V][BLEService.cpp:134] start(): >> start(): Starting service (esp_ble_gatts_start_service): UUID: ab529700-5310-483a-b4d3-7f1eaa8134a0, handle: 0x3ffc
I will try to test it with esp-idf, but i am suspecting it is bug in idf.
This is log from esp-idf:
W (1411) my_gatts_event_handler: custom gatts event handler, event: 0
W (1411) my_gatts_event_handler: custom gatts event handler, event: 7
I (1411) : Service 0 defined
W (1421) my_gatts_event_handler: custom gatts event handler, event: 7
I (1421) : Service 1 defined
W (1431) my_gatts_event_handler: custom gatts event handler, event: 7
I (1431) : Service 2 defined
W (1441) my_gatts_event_handler: custom gatts event handler, event: 7
I (1441) : Service 3 defined
W (1451) my_gatts_event_handler: custom gatts event handler, event: 7
I (1451) : Service 4 defined
W (1461) my_gatts_event_handler: custom gatts event handler, event: 7
I (1461) : Service 5 defined
E (1471) BT_GATT: GATTS_ReserveHandles: no free handle blocks
E (1471) BT_APPL: service creation failed.
W (1481) my_gatts_event_handler: custom gatts event handler, event: 7
I (1481) : Service 6 defined
I (1491) : All Services defined
W (1491) my_gatts_event_handler: custom gatts event handler, event: 12
I (1491) : Service 0 started
W (1501) my_gatts_event_handler: custom gatts event handler, event: 12
I (1501) : Service 1 started
I (1521) : Service 2 started
W (1521) my_gatts_event_handler: custom gatts event handler, event: 12
W (1531) my_gatts_event_handler: custom gatts event handler, event: 12
I (1531) : Service 3 started
W (1541) my_gatts_event_handler: custom gatts event handler, event: 12
I (1541) : Service 4 started
W (1551) my_gatts_event_handler: custom gatts event handler, event: 12
I (1551) : Service 5 started
E (1561) BT_APPL: service not created
I think those lines explain everything:
E (1471) BT_GATT: GATTS_ReserveHandles: no free handle blocks
E (1471) BT_APPL: service creation failed.
ok interesting. Saw your comment that it makes no difference how many handles are consumed in each service. So not running out of space for handles.
I assume the error could be given back to the caller as a nullptr so we can at least know the call failed?
It is esp-idf issue, because there is no error returned from esp_ble_gatts_create_service.
There is also few bugs related to semaphores in this library, like in this function which is causing stuck:
void BLEService::start() {
// We ask the BLE runtime to start the service and then create each of the characteristics.
// We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event
// obtained as a result of calling esp_ble_gatts_create_service().
//
ESP_LOGD(LOG_TAG, ">> start(): Starting service (esp_ble_gatts_start_service): %s", toString().c_str());
if (m_handle == NULL_HANDLE) {
ESP_LOGE(LOG_TAG, "<< !!! We attempted to start a service but don't know its handle!");
return;
}
BLECharacteristic *pCharacteristic = m_characteristicMap.getFirst();
while (pCharacteristic != nullptr) {
m_lastCreatedCharacteristic = pCharacteristic;
pCharacteristic->executeCreate(this);
pCharacteristic = m_characteristicMap.getNext();
}
// Start each of the characteristics ... these are found in the m_characteristicMap.
m_semaphoreStartEvt.take("start");
esp_err_t errRc = ::esp_ble_gatts_start_service(m_handle);
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_start_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
m_semaphoreStartEvt.give(); // add this line and should no longer stuck
return;
}
m_semaphoreStartEvt.wait("start");
ESP_LOGD(LOG_TAG, "<< start()");
} // start
I see there is few more places where semaphore is not not give/released upon error.
Here is answer:
https://github.com/espressif/esp-idf/issues/5495#issuecomment-651047331
Espressif seems to not take responsibility for returning ESP_OK when new service cant be created due to lack of handles, so we have to keep in mind that we are limited to 6 services in our app.
@chegewara Super Cool
Thank you for supporting
Ok, i think i see the problem in this library now. This code is missing one important check, status:
// ESP_GATTS_CREATE_EVT
// Called when a new service is registered as having been created.
//
// create:
// * esp_gatt_status_t status
// * uint16_t service_handle
// * esp_gatt_srvc_id_t service_id
// * - esp_gatt_id id
// * - esp_bt_uuid uuid
// * - uint8_t inst_id
// * - bool is_primary
//
case ESP_GATTS_CREATE_EVT: {
if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid)) && m_instId == param->create.service_id.id.inst_id) {
setHandle(param->create.service_handle);
m_semaphoreCreateEvt.give();
}
break;
} // ESP_GATTS_CREATE_EVT
I am assuming that status is giving us info if service is created or not.
Ok so we are restricted to 6 services. Luckily I managed to make my project work by picking and choosing which 6 services to start.
Sounds like waiting on the event will at least give a way to pass back a failure code on the seventh attempt. Interesting to see if programmatically stopping and starting services within the 6 limit works.
UPDATE: I used a hack to recognize a bad handle and used pServer->removeService(pService) to remove a service and keep at total of 6 - that works fine:
```
Starting
service 0 handle 28
Service 0 defined
service 1 handle 37
Service 1 defined
service 2 handle 46
Service 2 defined
service 3 handle 55
Service 3 defined
service 4 handle 64
Service 4 defined
service 5 handle 73
Service 5 defined
service 6 handle B33F
Bad handle - throw Service 1 away to make room
service 6 handle 82
Service 6 defined
service 7 handle B33F
Bad handle - throw Service 2 away to make room
service 7 handle 91
Service 7 defined
All Services defined
Service 0 started
Service 3 started
Service 4 started
Service 5 started
Service 6 started
Service 7 started
All Services started
Advertising Service