esp-rs / esp-idf-svc

Type-Safe Rust Wrappers for various ESP-IDF services (WiFi, Network, Httpd, Logging, etc.)
https://docs.esp-rs.org/esp-idf-svc/
Apache License 2.0
309 stars 175 forks source link

Adding a descriptor to the Characteristic sequence is problematic #460

Open yexiyue opened 2 months ago

yexiyue commented 2 months ago

Adding a descriptor to the Characteristic sequence is problematic

https://github.com/esp-rs/esp-idf-svc/blob/ac98266a07309e1b9e0885711fb2282b301bc78a/examples/bt_gatt_server.rs#L427-L449

When I swapped the order of adding these two characteristics, I found that CCCD was added to the last characteristic and not to the characteristic with Property Indicator

https://github.com/esp-rs/esp-idf-svc/blob/ac98266a07309e1b9e0885711fb2282b301bc78a/examples/bt_gatt_server.rs#L482-L488

Vollbrecht commented 1 week ago

The underlying problem here is the esp-idf descriptor api. Essentially as you build the service up on the fly from the overall service, to its corresponding characteristics and there added descriptors you get a complete service description.

This service description needs to follow a fixed form and you cannot reallocate space in between the handles once you given them out. So its essentially building the stack up from each call you make, in the specific order you call either esp_ble_gatts_add_cha or esp_ble_gatts_add_char_descr.

So in its current form the correct way is to add characteristics and then directly follow the next calls with the descriptors you want to add the that specific characteristic, and then again calling the next characteristic you want to add and so forth.

You don't need to wait in the eventloop for char A to be created to be able to call adding descriptor A or char B. The eventloop will only help you here to get the actual handle for everything you added without manually traversing the complete service database.

So after you created the service you can have one place where you describe all char/descriptors like the following

self.gatts.add_characteristic(..)?;
self.gatts.add_descriptor(..)?;
self.gatts.add_descriptor(..)?;
self.gatts.add_characteristic()?;

With using esp_ble_gatts_add_char_descr there is no other way as the api itself doesn't accept a parameter to what char the descriptor actually should be added, it only wants to know to which overall service its gets added.