Make parse_characteristics and parse_descriptors lazy to reduce memory pressure (#4063)

This commit is contained in:
J. Nick Koston 2022-11-27 14:28:02 -10:00 committed by GitHub
parent c5f59fad62
commit 53e0af18fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 30 additions and 2 deletions

View file

@ -72,11 +72,15 @@ void BluetoothProxy::loop() {
api::BluetoothGATTService service_resp; api::BluetoothGATTService service_resp;
service_resp.uuid = {service->uuid.get_128bit_high(), service->uuid.get_128bit_low()}; service_resp.uuid = {service->uuid.get_128bit_high(), service->uuid.get_128bit_low()};
service_resp.handle = service->start_handle; service_resp.handle = service->start_handle;
if (!service->parsed)
service->parse_characteristics();
for (auto &characteristic : service->characteristics) { for (auto &characteristic : service->characteristics) {
api::BluetoothGATTCharacteristic characteristic_resp; api::BluetoothGATTCharacteristic characteristic_resp;
characteristic_resp.uuid = {characteristic->uuid.get_128bit_high(), characteristic->uuid.get_128bit_low()}; characteristic_resp.uuid = {characteristic->uuid.get_128bit_high(), characteristic->uuid.get_128bit_low()};
characteristic_resp.handle = characteristic->handle; characteristic_resp.handle = characteristic->handle;
characteristic_resp.properties = characteristic->properties; characteristic_resp.properties = characteristic->properties;
if (!characteristic->parsed)
characteristic->parse_descriptors();
for (auto &descriptor : characteristic->descriptors) { for (auto &descriptor : characteristic->descriptors) {
api::BluetoothGATTDescriptor descriptor_resp; api::BluetoothGATTDescriptor descriptor_resp;
descriptor_resp.uuid = {descriptor->uuid.get_128bit_high(), descriptor->uuid.get_128bit_low()}; descriptor_resp.uuid = {descriptor->uuid.get_128bit_high(), descriptor->uuid.get_128bit_low()};
@ -87,6 +91,13 @@ void BluetoothProxy::loop() {
} }
resp.services.push_back(std::move(service_resp)); resp.services.push_back(std::move(service_resp));
api::global_api_server->send_bluetooth_gatt_services(resp); api::global_api_server->send_bluetooth_gatt_services(resp);
// Descriptors are rarely used and can be quite large so we clear them
// after sending them to save memory. If something actually needs them
// it can parse them again.
for (auto &characteristic : service->characteristics) {
characteristic->parsed = false;
characteristic->descriptors.clear();
}
connection->send_service_++; connection->send_service_++;
} }
} }

View file

@ -17,6 +17,7 @@ BLECharacteristic::~BLECharacteristic() {
} }
void BLECharacteristic::parse_descriptors() { void BLECharacteristic::parse_descriptors() {
this->parsed = true;
uint16_t offset = 0; uint16_t offset = 0;
esp_gattc_descr_elem_t result; esp_gattc_descr_elem_t result;
@ -49,6 +50,8 @@ void BLECharacteristic::parse_descriptors() {
} }
BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) { BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) {
if (!this->parsed)
this->parse_descriptors();
for (auto &desc : this->descriptors) { for (auto &desc : this->descriptors) {
if (desc->uuid == uuid) if (desc->uuid == uuid)
return desc; return desc;
@ -59,6 +62,8 @@ BLEDescriptor *BLECharacteristic::get_descriptor(uint16_t uuid) {
return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid)); return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid));
} }
BLEDescriptor *BLECharacteristic::get_descriptor_by_handle(uint16_t handle) { BLEDescriptor *BLECharacteristic::get_descriptor_by_handle(uint16_t handle) {
if (!this->parsed)
this->parse_descriptors();
for (auto &desc : this->descriptors) { for (auto &desc : this->descriptors) {
if (desc->handle == handle) if (desc->handle == handle)
return desc; return desc;

View file

@ -18,6 +18,7 @@ class BLEService;
class BLECharacteristic { class BLECharacteristic {
public: public:
~BLECharacteristic(); ~BLECharacteristic();
bool parsed = false;
espbt::ESPBTUUID uuid; espbt::ESPBTUUID uuid;
uint16_t handle; uint16_t handle;
esp_gatt_char_prop_t properties; esp_gatt_char_prop_t properties;

View file

@ -135,6 +135,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
for (auto &svc : this->services_) for (auto &svc : this->services_)
delete svc; // NOLINT(cppcoreguidelines-owning-memory) delete svc; // NOLINT(cppcoreguidelines-owning-memory)
this->services_.clear(); this->services_.clear();
esp_ble_gattc_cache_clean(this->remote_bda_);
this->set_state(espbt::ClientState::IDLE); this->set_state(espbt::ClientState::IDLE);
break; break;
} }
@ -154,7 +155,6 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
svc->uuid.to_string().c_str()); svc->uuid.to_string().c_str());
ESP_LOGI(TAG, "[%d] [%s] start_handle: 0x%x end_handle: 0x%x", this->connection_index_, ESP_LOGI(TAG, "[%d] [%s] start_handle: 0x%x end_handle: 0x%x", this->connection_index_,
this->address_str_.c_str(), svc->start_handle, svc->end_handle); this->address_str_.c_str(), svc->start_handle, svc->end_handle);
svc->parse_characteristics();
} }
this->set_state(espbt::ClientState::CONNECTED); this->set_state(espbt::ClientState::CONNECTED);
this->state_ = espbt::ClientState::ESTABLISHED; this->state_ = espbt::ClientState::ESTABLISHED;
@ -287,6 +287,8 @@ BLECharacteristic *BLEClientBase::get_characteristic(uint16_t service, uint16_t
BLECharacteristic *BLEClientBase::get_characteristic(uint16_t handle) { BLECharacteristic *BLEClientBase::get_characteristic(uint16_t handle) {
for (auto *svc : this->services_) { for (auto *svc : this->services_) {
if (!svc->parsed)
svc->parse_characteristics();
for (auto *chr : svc->characteristics) { for (auto *chr : svc->characteristics) {
if (chr->handle == handle) if (chr->handle == handle)
return chr; return chr;
@ -298,6 +300,8 @@ BLECharacteristic *BLEClientBase::get_characteristic(uint16_t handle) {
BLEDescriptor *BLEClientBase::get_config_descriptor(uint16_t handle) { BLEDescriptor *BLEClientBase::get_config_descriptor(uint16_t handle) {
auto *chr = this->get_characteristic(handle); auto *chr = this->get_characteristic(handle);
if (chr != nullptr) { if (chr != nullptr) {
if (!chr->parsed)
chr->parse_descriptors();
for (auto &desc : chr->descriptors) { for (auto &desc : chr->descriptors) {
if (desc->uuid.get_uuid().uuid.uuid16 == 0x2902) if (desc->uuid.get_uuid().uuid.uuid16 == 0x2902)
return desc; return desc;
@ -323,7 +327,11 @@ BLEDescriptor *BLEClientBase::get_descriptor(uint16_t service, uint16_t chr, uin
BLEDescriptor *BLEClientBase::get_descriptor(uint16_t handle) { BLEDescriptor *BLEClientBase::get_descriptor(uint16_t handle) {
for (auto *svc : this->services_) { for (auto *svc : this->services_) {
if (!svc->parsed)
svc->parse_characteristics();
for (auto *chr : svc->characteristics) { for (auto *chr : svc->characteristics) {
if (!chr->parsed)
chr->parse_descriptors();
for (auto *desc : chr->descriptors) { for (auto *desc : chr->descriptors) {
if (desc->handle == handle) if (desc->handle == handle)
return desc; return desc;

View file

@ -11,6 +11,8 @@ namespace esp32_ble_client {
static const char *const TAG = "esp32_ble_client"; static const char *const TAG = "esp32_ble_client";
BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) { BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) {
if (!this->parsed)
this->parse_characteristics();
for (auto &chr : this->characteristics) { for (auto &chr : this->characteristics) {
if (chr->uuid == uuid) if (chr->uuid == uuid)
return chr; return chr;
@ -28,6 +30,7 @@ BLEService::~BLEService() {
} }
void BLEService::parse_characteristics() { void BLEService::parse_characteristics() {
this->parsed = true;
uint16_t offset = 0; uint16_t offset = 0;
esp_gattc_char_elem_t result; esp_gattc_char_elem_t result;
@ -57,7 +60,6 @@ void BLEService::parse_characteristics() {
ESP_LOGI(TAG, "[%d] [%s] characteristic %s, handle 0x%x, properties 0x%x", this->client->get_connection_index(), ESP_LOGI(TAG, "[%d] [%s] characteristic %s, handle 0x%x, properties 0x%x", this->client->get_connection_index(),
this->client->address_str().c_str(), characteristic->uuid.to_string().c_str(), characteristic->handle, this->client->address_str().c_str(), characteristic->uuid.to_string().c_str(), characteristic->handle,
characteristic->properties); characteristic->properties);
characteristic->parse_descriptors();
offset++; offset++;
} }
} }

View file

@ -18,6 +18,7 @@ class BLEClientBase;
class BLEService { class BLEService {
public: public:
~BLEService(); ~BLEService();
bool parsed = false;
espbt::ESPBTUUID uuid; espbt::ESPBTUUID uuid;
uint16_t start_handle; uint16_t start_handle;
uint16_t end_handle; uint16_t end_handle;