mirror of
https://github.com/esphome/esphome.git
synced 2026-05-23 20:05:32 +08:00
[esp32_ble] Devirtualize BLE event handler dispatch (#15310)
This commit is contained in:
@@ -134,10 +134,38 @@ class HandlerCounts:
|
||||
_handler_counts = HandlerCounts()
|
||||
|
||||
|
||||
def _add_callback(
|
||||
parent_var: cg.MockObj,
|
||||
method: str,
|
||||
handler_var: cg.MockObj,
|
||||
params: str,
|
||||
call_args: str,
|
||||
) -> None:
|
||||
"""Generate a lambda callback that forwards to a handler method.
|
||||
|
||||
Uses a braced scope with a local pointer variable so the generated C++
|
||||
lambda captures only that pointer, avoiding GCC warnings about capturing
|
||||
variables with static storage duration.
|
||||
"""
|
||||
cg.add(
|
||||
cg.RawStatement(
|
||||
f"{{ auto *h = {handler_var}; "
|
||||
f"{parent_var}->{method}("
|
||||
f"[h]({params}) {{ h->{call_args}; }}); }}"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def register_gap_event_handler(parent_var: cg.MockObj, handler_var: cg.MockObj) -> None:
|
||||
"""Register a GAP event handler and track the count."""
|
||||
_handler_counts.gap_event += 1
|
||||
cg.add(parent_var.register_gap_event_handler(handler_var))
|
||||
_add_callback(
|
||||
parent_var,
|
||||
"add_gap_event_callback",
|
||||
handler_var,
|
||||
"esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param",
|
||||
"gap_event_handler(event, param)",
|
||||
)
|
||||
|
||||
|
||||
def register_gap_scan_event_handler(
|
||||
@@ -145,7 +173,13 @@ def register_gap_scan_event_handler(
|
||||
) -> None:
|
||||
"""Register a GAP scan event handler and track the count."""
|
||||
_handler_counts.gap_scan_event += 1
|
||||
cg.add(parent_var.register_gap_scan_event_handler(handler_var))
|
||||
_add_callback(
|
||||
parent_var,
|
||||
"add_gap_scan_event_callback",
|
||||
handler_var,
|
||||
"const esphome::esp32_ble::BLEScanResult &scan_result",
|
||||
"gap_scan_event_handler(scan_result)",
|
||||
)
|
||||
|
||||
|
||||
def register_gattc_event_handler(
|
||||
@@ -153,7 +187,13 @@ def register_gattc_event_handler(
|
||||
) -> None:
|
||||
"""Register a GATTc event handler and track the count."""
|
||||
_handler_counts.gattc_event += 1
|
||||
cg.add(parent_var.register_gattc_event_handler(handler_var))
|
||||
_add_callback(
|
||||
parent_var,
|
||||
"add_gattc_event_callback",
|
||||
handler_var,
|
||||
"esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param",
|
||||
"gattc_event_handler(event, gattc_if, param)",
|
||||
)
|
||||
|
||||
|
||||
def register_gatts_event_handler(
|
||||
@@ -161,7 +201,13 @@ def register_gatts_event_handler(
|
||||
) -> None:
|
||||
"""Register a GATTs event handler and track the count."""
|
||||
_handler_counts.gatts_event += 1
|
||||
cg.add(parent_var.register_gatts_event_handler(handler_var))
|
||||
_add_callback(
|
||||
parent_var,
|
||||
"add_gatts_event_callback",
|
||||
handler_var,
|
||||
"esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param",
|
||||
"gatts_event_handler(event, gatts_if, param)",
|
||||
)
|
||||
|
||||
|
||||
def register_ble_status_event_handler(
|
||||
@@ -169,7 +215,13 @@ def register_ble_status_event_handler(
|
||||
) -> None:
|
||||
"""Register a BLE status event handler and track the count."""
|
||||
_handler_counts.ble_status_event += 1
|
||||
cg.add(parent_var.register_ble_status_event_handler(handler_var))
|
||||
_add_callback(
|
||||
parent_var,
|
||||
"add_ble_status_event_callback",
|
||||
handler_var,
|
||||
"",
|
||||
"ble_before_disabled_event_handler()",
|
||||
)
|
||||
|
||||
|
||||
def register_bt_logger(*loggers: BTLoggers) -> None:
|
||||
@@ -225,10 +277,6 @@ NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2]
|
||||
esp32_ble_ns = cg.esphome_ns.namespace("esp32_ble")
|
||||
ESP32BLE = esp32_ble_ns.class_("ESP32BLE", cg.Component)
|
||||
|
||||
GAPEventHandler = esp32_ble_ns.class_("GAPEventHandler")
|
||||
GATTcEventHandler = esp32_ble_ns.class_("GATTcEventHandler")
|
||||
GATTsEventHandler = esp32_ble_ns.class_("GATTsEventHandler")
|
||||
|
||||
BLEEnabledCondition = esp32_ble_ns.class_("BLEEnabledCondition", automation.Condition)
|
||||
BLEEnableAction = esp32_ble_ns.class_("BLEEnableAction", automation.Action)
|
||||
BLEDisableAction = esp32_ble_ns.class_("BLEDisableAction", automation.Action)
|
||||
|
||||
@@ -408,9 +408,7 @@ void ESP32BLE::loop() {
|
||||
esp_gatt_if_t gatts_if = ble_event->event_.gatts.gatts_if;
|
||||
esp_ble_gatts_cb_param_t *param = &ble_event->event_.gatts.gatts_param;
|
||||
ESP_LOGV(TAG, "gatts_event [esp_gatt_if: %d] - %d", gatts_if, event);
|
||||
for (auto *gatts_handler : this->gatts_event_handlers_) {
|
||||
gatts_handler->gatts_event_handler(event, gatts_if, param);
|
||||
}
|
||||
this->gatts_event_callbacks_.call(event, gatts_if, param);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -420,9 +418,7 @@ void ESP32BLE::loop() {
|
||||
esp_gatt_if_t gattc_if = ble_event->event_.gattc.gattc_if;
|
||||
esp_ble_gattc_cb_param_t *param = &ble_event->event_.gattc.gattc_param;
|
||||
ESP_LOGV(TAG, "gattc_event [esp_gatt_if: %d] - %d", gattc_if, event);
|
||||
for (auto *gattc_handler : this->gattc_event_handlers_) {
|
||||
gattc_handler->gattc_event_handler(event, gattc_if, param);
|
||||
}
|
||||
this->gattc_event_callbacks_.call(event, gattc_if, param);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -431,10 +427,7 @@ void ESP32BLE::loop() {
|
||||
switch (gap_event) {
|
||||
case ESP_GAP_BLE_SCAN_RESULT_EVT:
|
||||
#ifdef ESPHOME_ESP32_BLE_GAP_SCAN_EVENT_HANDLER_COUNT
|
||||
// Use the new scan event handler - no memcpy!
|
||||
for (auto *scan_handler : this->gap_scan_event_handlers_) {
|
||||
scan_handler->gap_scan_event_handler(ble_event->scan_result());
|
||||
}
|
||||
this->gap_scan_event_callbacks_.call(ble_event->scan_result());
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -478,9 +471,7 @@ void ESP32BLE::loop() {
|
||||
}
|
||||
// clang-format on
|
||||
// Dispatch to all registered handlers
|
||||
for (auto *gap_handler : this->gap_event_handlers_) {
|
||||
gap_handler->gap_event_handler(gap_event, param);
|
||||
}
|
||||
this->gap_event_callbacks_.call(gap_event, param);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@@ -518,9 +509,7 @@ void ESP32BLE::loop_handle_state_transition_not_active_() {
|
||||
ESP_LOGD(TAG, "Disabling");
|
||||
|
||||
#ifdef ESPHOME_ESP32_BLE_BLE_STATUS_EVENT_HANDLER_COUNT
|
||||
for (auto *ble_event_handler : this->ble_status_event_handlers_) {
|
||||
ble_event_handler->ble_before_disabled_event_handler();
|
||||
}
|
||||
this->ble_status_event_callbacks_.call();
|
||||
#endif
|
||||
|
||||
if (!ble_dismantle_()) {
|
||||
|
||||
@@ -87,37 +87,6 @@ enum BLEComponentState : uint8_t {
|
||||
BLE_COMPONENT_STATE_ACTIVE,
|
||||
};
|
||||
|
||||
class GAPEventHandler {
|
||||
public:
|
||||
virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) = 0;
|
||||
};
|
||||
|
||||
class GAPScanEventHandler {
|
||||
public:
|
||||
virtual void gap_scan_event_handler(const BLEScanResult &scan_result) = 0;
|
||||
};
|
||||
|
||||
#ifdef USE_ESP32_BLE_CLIENT
|
||||
class GATTcEventHandler {
|
||||
public:
|
||||
virtual void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_ESP32_BLE_SERVER
|
||||
class GATTsEventHandler {
|
||||
public:
|
||||
virtual void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t *param) = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
class BLEStatusEventHandler {
|
||||
public:
|
||||
virtual void ble_before_disabled_event_handler() = 0;
|
||||
};
|
||||
|
||||
class ESP32BLE : public Component {
|
||||
public:
|
||||
void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; }
|
||||
@@ -154,22 +123,28 @@ class ESP32BLE : public Component {
|
||||
#endif
|
||||
|
||||
#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT
|
||||
void register_gap_event_handler(GAPEventHandler *handler) { this->gap_event_handlers_.push_back(handler); }
|
||||
template<typename F> void add_gap_event_callback(F &&callback) {
|
||||
this->gap_event_callbacks_.add(std::forward<F>(callback));
|
||||
}
|
||||
#endif
|
||||
#ifdef ESPHOME_ESP32_BLE_GAP_SCAN_EVENT_HANDLER_COUNT
|
||||
void register_gap_scan_event_handler(GAPScanEventHandler *handler) {
|
||||
this->gap_scan_event_handlers_.push_back(handler);
|
||||
template<typename F> void add_gap_scan_event_callback(F &&callback) {
|
||||
this->gap_scan_event_callbacks_.add(std::forward<F>(callback));
|
||||
}
|
||||
#endif
|
||||
#if defined(USE_ESP32_BLE_CLIENT) && defined(ESPHOME_ESP32_BLE_GATTC_EVENT_HANDLER_COUNT)
|
||||
void register_gattc_event_handler(GATTcEventHandler *handler) { this->gattc_event_handlers_.push_back(handler); }
|
||||
template<typename F> void add_gattc_event_callback(F &&callback) {
|
||||
this->gattc_event_callbacks_.add(std::forward<F>(callback));
|
||||
}
|
||||
#endif
|
||||
#if defined(USE_ESP32_BLE_SERVER) && defined(ESPHOME_ESP32_BLE_GATTS_EVENT_HANDLER_COUNT)
|
||||
void register_gatts_event_handler(GATTsEventHandler *handler) { this->gatts_event_handlers_.push_back(handler); }
|
||||
template<typename F> void add_gatts_event_callback(F &&callback) {
|
||||
this->gatts_event_callbacks_.add(std::forward<F>(callback));
|
||||
}
|
||||
#endif
|
||||
#ifdef ESPHOME_ESP32_BLE_BLE_STATUS_EVENT_HANDLER_COUNT
|
||||
void register_ble_status_event_handler(BLEStatusEventHandler *handler) {
|
||||
this->ble_status_event_handlers_.push_back(handler);
|
||||
template<typename F> void add_ble_status_event_callback(F &&callback) {
|
||||
this->ble_status_event_callbacks_.add(std::forward<F>(callback));
|
||||
}
|
||||
#endif
|
||||
void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
|
||||
@@ -202,21 +177,27 @@ class ESP32BLE : public Component {
|
||||
private:
|
||||
template<typename... Args> friend void enqueue_ble_event(Args... args);
|
||||
|
||||
// Handler vectors - use StaticVector when counts are known at compile time
|
||||
#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT
|
||||
StaticVector<GAPEventHandler *, ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT> gap_event_handlers_;
|
||||
StaticCallbackManager<ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT,
|
||||
void(esp_gap_ble_cb_event_t, esp_ble_gap_cb_param_t *)>
|
||||
gap_event_callbacks_;
|
||||
#endif
|
||||
#ifdef ESPHOME_ESP32_BLE_GAP_SCAN_EVENT_HANDLER_COUNT
|
||||
StaticVector<GAPScanEventHandler *, ESPHOME_ESP32_BLE_GAP_SCAN_EVENT_HANDLER_COUNT> gap_scan_event_handlers_;
|
||||
StaticCallbackManager<ESPHOME_ESP32_BLE_GAP_SCAN_EVENT_HANDLER_COUNT, void(const BLEScanResult &)>
|
||||
gap_scan_event_callbacks_;
|
||||
#endif
|
||||
#if defined(USE_ESP32_BLE_CLIENT) && defined(ESPHOME_ESP32_BLE_GATTC_EVENT_HANDLER_COUNT)
|
||||
StaticVector<GATTcEventHandler *, ESPHOME_ESP32_BLE_GATTC_EVENT_HANDLER_COUNT> gattc_event_handlers_;
|
||||
StaticCallbackManager<ESPHOME_ESP32_BLE_GATTC_EVENT_HANDLER_COUNT,
|
||||
void(esp_gattc_cb_event_t, esp_gatt_if_t, esp_ble_gattc_cb_param_t *)>
|
||||
gattc_event_callbacks_;
|
||||
#endif
|
||||
#if defined(USE_ESP32_BLE_SERVER) && defined(ESPHOME_ESP32_BLE_GATTS_EVENT_HANDLER_COUNT)
|
||||
StaticVector<GATTsEventHandler *, ESPHOME_ESP32_BLE_GATTS_EVENT_HANDLER_COUNT> gatts_event_handlers_;
|
||||
StaticCallbackManager<ESPHOME_ESP32_BLE_GATTS_EVENT_HANDLER_COUNT,
|
||||
void(esp_gatts_cb_event_t, esp_gatt_if_t, esp_ble_gatts_cb_param_t *)>
|
||||
gatts_event_callbacks_;
|
||||
#endif
|
||||
#ifdef ESPHOME_ESP32_BLE_BLE_STATUS_EVENT_HANDLER_COUNT
|
||||
StaticVector<BLEStatusEventHandler *, ESPHOME_ESP32_BLE_BLE_STATUS_EVENT_HANDLER_COUNT> ble_status_event_handlers_;
|
||||
StaticCallbackManager<ESPHOME_ESP32_BLE_BLE_STATUS_EVENT_HANDLER_COUNT, void()> ble_status_event_callbacks_;
|
||||
#endif
|
||||
|
||||
// Large objects (size depends on template parameters, but typically aligned to 4 bytes)
|
||||
|
||||
@@ -13,7 +13,6 @@ esp32_ble_beacon_ns = cg.esphome_ns.namespace("esp32_ble_beacon")
|
||||
ESP32BLEBeacon = esp32_ble_beacon_ns.class_(
|
||||
"ESP32BLEBeacon",
|
||||
cg.Component,
|
||||
esp32_ble.GAPEventHandler,
|
||||
cg.Parented.template(esp32_ble.ESP32BLE),
|
||||
)
|
||||
CONF_MAJOR = "major"
|
||||
|
||||
@@ -35,7 +35,7 @@ using esp_ble_ibeacon_t = struct {
|
||||
|
||||
using namespace esp32_ble;
|
||||
|
||||
class ESP32BLEBeacon : public Component, public GAPEventHandler, public Parented<ESP32BLE> {
|
||||
class ESP32BLEBeacon : public Component, public Parented<ESP32BLE> {
|
||||
public:
|
||||
explicit ESP32BLEBeacon(const std::array<uint8_t, 16> &uuid) : uuid_(uuid) {}
|
||||
|
||||
@@ -51,7 +51,7 @@ class ESP32BLEBeacon : public Component, public GAPEventHandler, public Parented
|
||||
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
|
||||
void set_tx_power(esp_power_level_t val) { this->tx_power_ = val; }
|
||||
#endif
|
||||
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
|
||||
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
|
||||
|
||||
protected:
|
||||
void on_advertise_();
|
||||
|
||||
@@ -72,7 +72,6 @@ BLECharacteristic_ns = esp32_ble_server_ns.namespace("BLECharacteristic")
|
||||
BLEServer = esp32_ble_server_ns.class_(
|
||||
"BLEServer",
|
||||
cg.Component,
|
||||
esp32_ble.GATTsEventHandler,
|
||||
cg.Parented.template(esp32_ble.ESP32BLE),
|
||||
)
|
||||
esp32_ble_server_automations_ns = esp32_ble_server_ns.namespace(
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace esp32_ble_server {
|
||||
using namespace esp32_ble;
|
||||
using namespace bytebuffer;
|
||||
|
||||
class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented<ESP32BLE> {
|
||||
class BLEServer : public Component, public Parented<ESP32BLE> {
|
||||
public:
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
@@ -53,10 +53,9 @@ class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEv
|
||||
const uint16_t *get_clients() const { return this->clients_; }
|
||||
uint8_t get_client_count() const { return this->client_count_; }
|
||||
|
||||
void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t *param) override;
|
||||
void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
|
||||
|
||||
void ble_before_disabled_event_handler() override;
|
||||
void ble_before_disabled_event_handler();
|
||||
|
||||
// Direct callback registration - supports multiple callbacks
|
||||
void on_connect(std::function<void(uint16_t)> &&callback) {
|
||||
|
||||
@@ -90,8 +90,6 @@ esp32_ble_tracker_ns = cg.esphome_ns.namespace("esp32_ble_tracker")
|
||||
ESP32BLETracker = esp32_ble_tracker_ns.class_(
|
||||
"ESP32BLETracker",
|
||||
cg.Component,
|
||||
esp32_ble.GAPEventHandler,
|
||||
esp32_ble.GATTcEventHandler,
|
||||
cg.Parented.template(esp32_ble.ESP32BLE),
|
||||
)
|
||||
ESPBTClient = esp32_ble_tracker_ns.class_("ESPBTClient")
|
||||
|
||||
@@ -291,10 +291,6 @@ class ESPBTClient : public ESPBTDeviceListener {
|
||||
};
|
||||
|
||||
class ESP32BLETracker : public Component,
|
||||
public GAPEventHandler,
|
||||
public GAPScanEventHandler,
|
||||
public GATTcEventHandler,
|
||||
public BLEStatusEventHandler,
|
||||
#ifdef USE_OTA_STATE_LISTENER
|
||||
public ota::OTAGlobalStateListener,
|
||||
#endif
|
||||
@@ -325,11 +321,10 @@ class ESP32BLETracker : public Component,
|
||||
void start_scan();
|
||||
void stop_scan();
|
||||
|
||||
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) override;
|
||||
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
|
||||
void gap_scan_event_handler(const BLEScanResult &scan_result) override;
|
||||
void ble_before_disabled_event_handler() override;
|
||||
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param);
|
||||
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
|
||||
void gap_scan_event_handler(const BLEScanResult &scan_result);
|
||||
void ble_before_disabled_event_handler();
|
||||
|
||||
#ifdef USE_OTA_STATE_LISTENER
|
||||
void on_ota_global_state(ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) override;
|
||||
|
||||
@@ -1830,6 +1830,38 @@ template<typename... Ts> class CallbackManager<void(Ts...)> {
|
||||
std::vector<Callback<void(Ts...)>> callbacks_;
|
||||
};
|
||||
|
||||
/** CallbackManager backed by StaticVector for compile-time-known callback counts.
|
||||
*
|
||||
* Drop-in replacement for CallbackManager that avoids std::vector template bloat
|
||||
* (_M_realloc_insert, etc.) when the maximum number of callbacks is known at compile time.
|
||||
*
|
||||
* @tparam N Maximum number of callbacks (compile-time constant, typically from cg.add_define())
|
||||
* @tparam Ts The arguments for the callbacks, wrapped in void().
|
||||
*/
|
||||
template<size_t N, typename... X> class StaticCallbackManager;
|
||||
|
||||
template<size_t N, typename... Ts> class StaticCallbackManager<N, void(Ts...)> {
|
||||
public:
|
||||
/// Add any callable. Small trivially-copyable callables (like [this] lambdas)
|
||||
/// are stored inline without heap allocation.
|
||||
template<typename F> void add(F &&callback) { this->add_(Callback<void(Ts...)>::create(std::forward<F>(callback))); }
|
||||
|
||||
/// Call all callbacks in this manager.
|
||||
void call(Ts... args) {
|
||||
for (auto &cb : this->callbacks_)
|
||||
cb.call(args...);
|
||||
}
|
||||
size_t size() const { return this->callbacks_.size(); }
|
||||
|
||||
/// Call all callbacks in this manager.
|
||||
void operator()(Ts... args) { call(args...); }
|
||||
|
||||
protected:
|
||||
/// Non-template core to avoid code duplication per lambda type.
|
||||
void add_(Callback<void(Ts...)> cb) { this->callbacks_.push_back(cb); }
|
||||
StaticVector<Callback<void(Ts...)>, N> callbacks_;
|
||||
};
|
||||
|
||||
template<typename... X> class LazyCallbackManager;
|
||||
|
||||
/** Lazy-allocating callback manager that only allocates memory when callbacks are registered.
|
||||
|
||||
Reference in New Issue
Block a user