mirror of
https://github.com/esphome/esphome.git
synced 2026-02-25 21:43:14 -07:00
[esp32_ble_client] Defer IDLE transition from DISCONNECT_EVT to CLOSE_EVT
ESP_GATTC_DISCONNECT_EVT only indicates that the link-layer disconnection has started, not that the controller has fully freed resources (L2CAP channels, ATT resources, HCI connection handle). Transitioning to IDLE immediately allowed reconnection attempts before cleanup was complete, causing the controller to reject new connections with status=133 (ESP_GATT_CONN_FAIL_ESTABLISH) or crash with ASSERT_PARAM in lld_evt.c. This applies the same fix that was made for bluetooth_proxy in #10303 to the base BLEClientBase class, which is used by the ble_client component. Changes: - DISCONNECT_EVT now transitions to DISCONNECTING instead of IDLE - CLOSE_EVT (already existing) handles the final IDLE transition - connect() now blocks while in DISCONNECTING state - OPEN_EVT ignores events received during DISCONNECTING state
This commit is contained in:
@@ -101,9 +101,9 @@ bool BLEClientBase::parse_device(const espbt::ESPBTDevice &device) {
|
||||
#endif
|
||||
|
||||
void BLEClientBase::connect() {
|
||||
// Prevent duplicate connection attempts
|
||||
// Prevent duplicate connection attempts or connecting while still disconnecting
|
||||
if (this->state() == espbt::ClientState::CONNECTING || this->state() == espbt::ClientState::CONNECTED ||
|
||||
this->state() == espbt::ClientState::ESTABLISHED) {
|
||||
this->state() == espbt::ClientState::ESTABLISHED || this->state() == espbt::ClientState::DISCONNECTING) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection already in progress, state=%s", this->connection_index_, this->address_str_,
|
||||
espbt::client_state_to_string(this->state()));
|
||||
return;
|
||||
@@ -295,9 +295,10 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
// ESP-IDF's BLE stack may send ESP_GATTC_OPEN_EVT after esp_ble_gattc_open() returns an
|
||||
// error, if the error occurred at the BTA/GATT layer. This can result in the event
|
||||
// arriving after we've already transitioned to IDLE state.
|
||||
if (this->state() == espbt::ClientState::IDLE) {
|
||||
ESP_LOGD(TAG, "[%d] [%s] ESP_GATTC_OPEN_EVT in IDLE state (status=%d), ignoring", this->connection_index_,
|
||||
this->address_str_, param->open.status);
|
||||
// It may also arrive during DISCONNECTING if the controller is still cleaning up.
|
||||
if (this->state() == espbt::ClientState::IDLE || this->state() == espbt::ClientState::DISCONNECTING) {
|
||||
ESP_LOGD(TAG, "[%d] [%s] ESP_GATTC_OPEN_EVT in %s state (status=%d), ignoring", this->connection_index_,
|
||||
this->address_str_, espbt::client_state_to_string(this->state()), param->open.status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -362,8 +363,13 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
ESP_LOGD(TAG, "[%d] [%s] ESP_GATTC_DISCONNECT_EVT, reason 0x%02x", this->connection_index_, this->address_str_,
|
||||
param->disconnect.reason);
|
||||
}
|
||||
// Don't transition to IDLE yet - wait for CLOSE_EVT to ensure the controller has
|
||||
// fully freed resources (L2CAP channels, ATT resources, HCI connection handle).
|
||||
// Transitioning to IDLE here would allow reconnection before cleanup is complete,
|
||||
// causing the controller to reject the new connection (status=133) or crash
|
||||
// with ASSERT_PARAM in lld_evt.c.
|
||||
this->release_services();
|
||||
this->set_state(espbt::ClientState::IDLE);
|
||||
this->set_state(espbt::ClientState::DISCONNECTING);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user