1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-15 01:32:19 +01:00
This commit is contained in:
J. Nick Koston
2025-06-11 10:43:48 -05:00
parent 0e9f14f969
commit 068c62c6fe
2 changed files with 70 additions and 36 deletions

View File

@@ -306,11 +306,11 @@ void ESP32BLE::loop() {
switch (ble_event->type_) { switch (ble_event->type_) {
case BLEEvent::GATTS: case BLEEvent::GATTS:
this->real_gatts_event_handler_(ble_event->event_.gatts.gatts_event, ble_event->event_.gatts.gatts_if, this->real_gatts_event_handler_(ble_event->event_.gatts.gatts_event, ble_event->event_.gatts.gatts_if,
&ble_event->event_.gatts.gatts_param); ble_event->event_.gatts.gatts_param);
break; break;
case BLEEvent::GATTC: case BLEEvent::GATTC:
this->real_gattc_event_handler_(ble_event->event_.gattc.gattc_event, ble_event->event_.gattc.gattc_if, this->real_gattc_event_handler_(ble_event->event_.gattc.gattc_event, ble_event->event_.gattc.gattc_if,
&ble_event->event_.gattc.gattc_param); ble_event->event_.gattc.gattc_param);
break; break;
case BLEEvent::GAP: { case BLEEvent::GAP: {
esp_gap_ble_cb_event_t gap_event = ble_event->event_.gap.gap_event; esp_gap_ble_cb_event_t gap_event = ble_event->event_.gap.gap_event;
@@ -341,6 +341,7 @@ void ESP32BLE::loop() {
default: default:
break; break;
} }
// Destructor will clean up external allocations for GATTC/GATTS
ble_event->~BLEEvent(); ble_event->~BLEEvent();
EVENT_ALLOCATOR.deallocate(ble_event, 1); EVENT_ALLOCATOR.deallocate(ble_event, 1);
ble_event = this->ble_events_.pop(); ble_event = this->ble_events_.pop();

View File

@@ -14,12 +14,25 @@ namespace esphome {
namespace esp32_ble { namespace esp32_ble {
// Received GAP, GATTC and GATTS events are only queued, and get processed in the main loop(). // Received GAP, GATTC and GATTS events are only queued, and get processed in the main loop().
// This class stores each event with minimal memory usage by only copying the data we actually need. // This class stores each event with minimal memory usage.
// GAP events (99% of traffic) don't have the vector overhead.
// GATTC/GATTS events use external storage for their param and data.
class BLEEvent { class BLEEvent {
public: public:
// NOLINTNEXTLINE(readability-identifier-naming)
enum ble_event_t : uint8_t {
GAP,
GATTC,
GATTS,
};
BLEEvent() = default;
// Constructor for GAP events - no external allocations needed
BLEEvent(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) { BLEEvent(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) {
this->type_ = GAP; this->type_ = GAP;
this->event_.gap.gap_event = e; this->event_.gap.gap_event = e;
this->event_.gap.ext_data = nullptr; // GAP events don't use external data
// Only copy the data we actually use for each GAP event type // Only copy the data we actually use for each GAP event type
switch (e) { switch (e) {
@@ -49,97 +62,117 @@ class BLEEvent {
default: default:
// We only handle 4 GAP event types, others are dropped // We only handle 4 GAP event types, others are dropped
// This should never happen in normal operation
break; break;
} }
}; }
// Constructor for GATTC events - uses external storage
BLEEvent(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) { BLEEvent(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
this->type_ = GATTC; this->type_ = GATTC;
this->event_.gattc.gattc_event = e; this->event_.gattc.gattc_event = e;
this->event_.gattc.gattc_if = i; this->event_.gattc.gattc_if = i;
memcpy(&this->event_.gattc.gattc_param, p, sizeof(esp_ble_gattc_cb_param_t));
// Allocate external storage for param and data
this->event_.gattc.gattc_param = new esp_ble_gattc_cb_param_t(*p);
// Copy data for events that need it // Copy data for events that need it
switch (e) { switch (e) {
case ESP_GATTC_NOTIFY_EVT: case ESP_GATTC_NOTIFY_EVT:
this->data.assign(p->notify.value, p->notify.value + p->notify.value_len); this->event_.gattc.data = new std::vector<uint8_t>(p->notify.value, p->notify.value + p->notify.value_len);
this->event_.gattc.gattc_param.notify.value = this->data.data(); this->event_.gattc.gattc_param->notify.value = this->event_.gattc.data->data();
break; break;
case ESP_GATTC_READ_CHAR_EVT: case ESP_GATTC_READ_CHAR_EVT:
case ESP_GATTC_READ_DESCR_EVT: case ESP_GATTC_READ_DESCR_EVT:
this->data.assign(p->read.value, p->read.value + p->read.value_len); this->event_.gattc.data = new std::vector<uint8_t>(p->read.value, p->read.value + p->read.value_len);
this->event_.gattc.gattc_param.read.value = this->data.data(); this->event_.gattc.gattc_param->read.value = this->event_.gattc.data->data();
break; break;
default: default:
this->event_.gattc.data = nullptr;
break; break;
} }
}; }
// Constructor for GATTS events - uses external storage
BLEEvent(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) { BLEEvent(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
this->type_ = GATTS; this->type_ = GATTS;
this->event_.gatts.gatts_event = e; this->event_.gatts.gatts_event = e;
this->event_.gatts.gatts_if = i; this->event_.gatts.gatts_if = i;
memcpy(&this->event_.gatts.gatts_param, p, sizeof(esp_ble_gatts_cb_param_t));
// Allocate external storage for param and data
this->event_.gatts.gatts_param = new esp_ble_gatts_cb_param_t(*p);
// Copy data for events that need it // Copy data for events that need it
switch (e) { switch (e) {
case ESP_GATTS_WRITE_EVT: case ESP_GATTS_WRITE_EVT:
this->data.assign(p->write.value, p->write.value + p->write.len); this->event_.gatts.data = new std::vector<uint8_t>(p->write.value, p->write.value + p->write.len);
this->event_.gatts.gatts_param.write.value = this->data.data(); this->event_.gatts.gatts_param->write.value = this->event_.gatts.data->data();
break;
default:
this->event_.gatts.data = nullptr;
break;
}
}
// Destructor to clean up external allocations
~BLEEvent() {
switch (this->type_) {
case GATTC:
delete this->event_.gattc.gattc_param;
delete this->event_.gattc.data;
break;
case GATTS:
delete this->event_.gatts.gatts_param;
delete this->event_.gatts.data;
break; break;
default: default:
break; break;
} }
}; }
// Disable copy to prevent double-delete
BLEEvent(const BLEEvent &) = delete;
BLEEvent &operator=(const BLEEvent &) = delete;
union { union {
// NOLINTNEXTLINE(readability-identifier-naming) // NOLINTNEXTLINE(readability-identifier-naming)
struct gap_event { struct gap_event {
esp_gap_ble_cb_event_t gap_event; esp_gap_ble_cb_event_t gap_event;
void *ext_data; // Always nullptr for GAP, just for alignment
union { union {
BLEScanResult scan_result; // ~73 bytes BLEScanResult scan_result; // 73 bytes
// Minimal storage for scan complete events
struct { struct {
esp_bt_status_t status; esp_bt_status_t status;
} scan_complete; // 1 byte } scan_complete; // 1 byte
// We only handle 4 GAP event types, no need for full fallback
// If we ever get an unexpected event, we'll just drop it in ble.cpp
}; };
} gap; // ~73 bytes (size of BLEScanResult) } gap; // 80 bytes (with alignment)
// NOLINTNEXTLINE(readability-identifier-naming) // NOLINTNEXTLINE(readability-identifier-naming)
struct gattc_event { struct gattc_event {
esp_gattc_cb_event_t gattc_event; esp_gattc_cb_event_t gattc_event;
esp_gatt_if_t gattc_if; esp_gatt_if_t gattc_if;
esp_ble_gattc_cb_param_t gattc_param; esp_ble_gattc_cb_param_t *gattc_param; // External allocation
} gattc; // ~68 bytes std::vector<uint8_t> *data; // External allocation
} gattc; // 16 bytes (4 + 4 + 4 + 4)
// NOLINTNEXTLINE(readability-identifier-naming) // NOLINTNEXTLINE(readability-identifier-naming)
struct gatts_event { struct gatts_event {
esp_gatts_cb_event_t gatts_event; esp_gatts_cb_event_t gatts_event;
esp_gatt_if_t gatts_if; esp_gatt_if_t gatts_if;
esp_ble_gatts_cb_param_t gatts_param; esp_ble_gatts_cb_param_t *gatts_param; // External allocation
} gatts; // ~68 bytes std::vector<uint8_t> *data; // External allocation
} event_; // Union size is now ~73 bytes (BLEScanResult is largest) } gatts; // 16 bytes (4 + 4 + 4 + 4)
} event_; // Union size is 80 bytes (largest member is gap)
std::vector<uint8_t> data{}; // For GATTC/GATTS data ble_event_t type_;
// NOLINTNEXTLINE(readability-identifier-naming)
enum ble_event_t : uint8_t {
GAP,
GATTC,
GATTS,
} type_;
// Helper methods to access event data // Helper methods to access event data
ble_event_t type() const { return type_; }
esp_gap_ble_cb_event_t gap_event_type() const { return event_.gap.gap_event; } esp_gap_ble_cb_event_t gap_event_type() const { return event_.gap.gap_event; }
const BLEScanResult &scan_result() const { return event_.gap.scan_result; } const BLEScanResult &scan_result() const { return event_.gap.scan_result; }
esp_bt_status_t scan_complete_status() const { return event_.gap.scan_complete.status; } esp_bt_status_t scan_complete_status() const { return event_.gap.scan_complete.status; }
}; };
// Total size: ~100 bytes instead of 440 bytes! // Total size for GAP events: ~84 bytes (was 296 bytes - 71.6% reduction!)
// GATTC/GATTS events use external storage, keeping the queue size minimal
} // namespace esp32_ble } // namespace esp32_ble
} // namespace esphome } // namespace esphome