mirror of
https://github.com/esphome/esphome.git
synced 2025-08-04 09:27:47 +00:00
[esp32_ble_tracker] Remove unnecessary STOPPED scanner state to reduce latency (#10055)
This commit is contained in:
parent
bb3ebaf955
commit
7c297366c7
@ -185,9 +185,6 @@ void ESP32BLETracker::loop() {
|
|||||||
ESP_LOGW(TAG, "Dropped %zu BLE scan results due to buffer overflow", dropped);
|
ESP_LOGW(TAG, "Dropped %zu BLE scan results due to buffer overflow", dropped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this->scanner_state_ == ScannerState::STOPPED) {
|
|
||||||
this->end_of_scan_(); // Change state to IDLE
|
|
||||||
}
|
|
||||||
if (this->scanner_state_ == ScannerState::FAILED ||
|
if (this->scanner_state_ == ScannerState::FAILED ||
|
||||||
(this->scan_set_param_failed_ && this->scanner_state_ == ScannerState::RUNNING)) {
|
(this->scan_set_param_failed_ && this->scanner_state_ == ScannerState::RUNNING)) {
|
||||||
this->stop_scan_();
|
this->stop_scan_();
|
||||||
@ -278,8 +275,6 @@ void ESP32BLETracker::stop_scan_() {
|
|||||||
ESP_LOGE(TAG, "Scan is starting while trying to stop.");
|
ESP_LOGE(TAG, "Scan is starting while trying to stop.");
|
||||||
} else if (this->scanner_state_ == ScannerState::STOPPING) {
|
} else if (this->scanner_state_ == ScannerState::STOPPING) {
|
||||||
ESP_LOGE(TAG, "Scan is already stopping while trying to stop.");
|
ESP_LOGE(TAG, "Scan is already stopping while trying to stop.");
|
||||||
} else if (this->scanner_state_ == ScannerState::STOPPED) {
|
|
||||||
ESP_LOGE(TAG, "Scan is already stopped while trying to stop.");
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -306,8 +301,6 @@ void ESP32BLETracker::start_scan_(bool first) {
|
|||||||
ESP_LOGE(TAG, "Cannot start scan while already stopping.");
|
ESP_LOGE(TAG, "Cannot start scan while already stopping.");
|
||||||
} else if (this->scanner_state_ == ScannerState::FAILED) {
|
} else if (this->scanner_state_ == ScannerState::FAILED) {
|
||||||
ESP_LOGE(TAG, "Cannot start scan while already failed.");
|
ESP_LOGE(TAG, "Cannot start scan while already failed.");
|
||||||
} else if (this->scanner_state_ == ScannerState::STOPPED) {
|
|
||||||
ESP_LOGE(TAG, "Cannot start scan while already stopped.");
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -342,21 +335,6 @@ void ESP32BLETracker::start_scan_(bool first) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP32BLETracker::end_of_scan_() {
|
|
||||||
// The lock must be held when calling this function.
|
|
||||||
if (this->scanner_state_ != ScannerState::STOPPED) {
|
|
||||||
ESP_LOGE(TAG, "end_of_scan_ called while scanner is not stopped.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ESP_LOGD(TAG, "End of scan, set scanner state to IDLE.");
|
|
||||||
this->already_discovered_.clear();
|
|
||||||
this->cancel_timeout("scan");
|
|
||||||
|
|
||||||
for (auto *listener : this->listeners_)
|
|
||||||
listener->on_scan_end();
|
|
||||||
this->set_scanner_state_(ScannerState::IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ESP32BLETracker::register_client(ESPBTClient *client) {
|
void ESP32BLETracker::register_client(ESPBTClient *client) {
|
||||||
client->app_id = ++this->app_id_;
|
client->app_id = ++this->app_id_;
|
||||||
this->clients_.push_back(client);
|
this->clients_.push_back(client);
|
||||||
@ -389,6 +367,8 @@ void ESP32BLETracker::recalculate_advertisement_parser_types() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
void ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
||||||
|
// Note: This handler is called from the main loop context, not directly from the BT task.
|
||||||
|
// The esp32_ble component queues events via enqueue_ble_event() and processes them in loop().
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
|
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
|
||||||
this->gap_scan_set_param_complete_(param->scan_param_cmpl);
|
this->gap_scan_set_param_complete_(param->scan_param_cmpl);
|
||||||
@ -409,11 +389,13 @@ void ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_ga
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ESP32BLETracker::gap_scan_event_handler(const BLEScanResult &scan_result) {
|
void ESP32BLETracker::gap_scan_event_handler(const BLEScanResult &scan_result) {
|
||||||
|
// Note: This handler is called from the main loop context via esp32_ble's event queue.
|
||||||
|
// However, we still use a lock-free ring buffer to batch results efficiently.
|
||||||
ESP_LOGV(TAG, "gap_scan_result - event %d", scan_result.search_evt);
|
ESP_LOGV(TAG, "gap_scan_result - event %d", scan_result.search_evt);
|
||||||
|
|
||||||
if (scan_result.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {
|
if (scan_result.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {
|
||||||
// Lock-free SPSC ring buffer write (Producer side)
|
// Ring buffer write (Producer side)
|
||||||
// This runs in the ESP-IDF Bluetooth stack callback thread
|
// Even though we're in the main loop, the ring buffer design allows efficient batching
|
||||||
// IMPORTANT: Only this thread writes to ring_write_index_
|
// IMPORTANT: Only this thread writes to ring_write_index_
|
||||||
|
|
||||||
// Load our own index with relaxed ordering (we're the only writer)
|
// Load our own index with relaxed ordering (we're the only writer)
|
||||||
@ -445,15 +427,15 @@ void ESP32BLETracker::gap_scan_event_handler(const BLEScanResult &scan_result) {
|
|||||||
ESP_LOGE(TAG, "Scan was in failed state when scan completed.");
|
ESP_LOGE(TAG, "Scan was in failed state when scan completed.");
|
||||||
} else if (this->scanner_state_ == ScannerState::IDLE) {
|
} else if (this->scanner_state_ == ScannerState::IDLE) {
|
||||||
ESP_LOGE(TAG, "Scan was idle when scan completed.");
|
ESP_LOGE(TAG, "Scan was idle when scan completed.");
|
||||||
} else if (this->scanner_state_ == ScannerState::STOPPED) {
|
|
||||||
ESP_LOGE(TAG, "Scan was stopped when scan completed.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->set_scanner_state_(ScannerState::STOPPED);
|
// Scan completed naturally, perform cleanup and transition to IDLE
|
||||||
|
this->cleanup_scan_state_(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP32BLETracker::gap_scan_set_param_complete_(const esp_ble_gap_cb_param_t::ble_scan_param_cmpl_evt_param ¶m) {
|
void ESP32BLETracker::gap_scan_set_param_complete_(const esp_ble_gap_cb_param_t::ble_scan_param_cmpl_evt_param ¶m) {
|
||||||
|
// Called from main loop context via gap_event_handler after being queued from BT task
|
||||||
ESP_LOGV(TAG, "gap_scan_set_param_complete - status %d", param.status);
|
ESP_LOGV(TAG, "gap_scan_set_param_complete - status %d", param.status);
|
||||||
if (param.status == ESP_BT_STATUS_DONE) {
|
if (param.status == ESP_BT_STATUS_DONE) {
|
||||||
this->scan_set_param_failed_ = ESP_BT_STATUS_SUCCESS;
|
this->scan_set_param_failed_ = ESP_BT_STATUS_SUCCESS;
|
||||||
@ -463,6 +445,7 @@ void ESP32BLETracker::gap_scan_set_param_complete_(const esp_ble_gap_cb_param_t:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ESP32BLETracker::gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param ¶m) {
|
void ESP32BLETracker::gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param ¶m) {
|
||||||
|
// Called from main loop context via gap_event_handler after being queued from BT task
|
||||||
ESP_LOGV(TAG, "gap_scan_start_complete - status %d", param.status);
|
ESP_LOGV(TAG, "gap_scan_start_complete - status %d", param.status);
|
||||||
this->scan_start_failed_ = param.status;
|
this->scan_start_failed_ = param.status;
|
||||||
if (this->scanner_state_ != ScannerState::STARTING) {
|
if (this->scanner_state_ != ScannerState::STARTING) {
|
||||||
@ -474,8 +457,6 @@ void ESP32BLETracker::gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble
|
|||||||
ESP_LOGE(TAG, "Scan was in failed state when start complete.");
|
ESP_LOGE(TAG, "Scan was in failed state when start complete.");
|
||||||
} else if (this->scanner_state_ == ScannerState::IDLE) {
|
} else if (this->scanner_state_ == ScannerState::IDLE) {
|
||||||
ESP_LOGE(TAG, "Scan was idle when start complete.");
|
ESP_LOGE(TAG, "Scan was idle when start complete.");
|
||||||
} else if (this->scanner_state_ == ScannerState::STOPPED) {
|
|
||||||
ESP_LOGE(TAG, "Scan was stopped when start complete.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (param.status == ESP_BT_STATUS_SUCCESS) {
|
if (param.status == ESP_BT_STATUS_SUCCESS) {
|
||||||
@ -490,6 +471,8 @@ void ESP32BLETracker::gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ESP32BLETracker::gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param ¶m) {
|
void ESP32BLETracker::gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param ¶m) {
|
||||||
|
// Called from main loop context via gap_event_handler after being queued from BT task
|
||||||
|
// This allows us to safely transition to IDLE state and perform cleanup without race conditions
|
||||||
ESP_LOGV(TAG, "gap_scan_stop_complete - status %d", param.status);
|
ESP_LOGV(TAG, "gap_scan_stop_complete - status %d", param.status);
|
||||||
if (this->scanner_state_ != ScannerState::STOPPING) {
|
if (this->scanner_state_ != ScannerState::STOPPING) {
|
||||||
if (this->scanner_state_ == ScannerState::RUNNING) {
|
if (this->scanner_state_ == ScannerState::RUNNING) {
|
||||||
@ -500,11 +483,11 @@ void ESP32BLETracker::gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_
|
|||||||
ESP_LOGE(TAG, "Scan was in failed state when stop complete.");
|
ESP_LOGE(TAG, "Scan was in failed state when stop complete.");
|
||||||
} else if (this->scanner_state_ == ScannerState::IDLE) {
|
} else if (this->scanner_state_ == ScannerState::IDLE) {
|
||||||
ESP_LOGE(TAG, "Scan was idle when stop complete.");
|
ESP_LOGE(TAG, "Scan was idle when stop complete.");
|
||||||
} else if (this->scanner_state_ == ScannerState::STOPPED) {
|
|
||||||
ESP_LOGE(TAG, "Scan was stopped when stop complete.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->set_scanner_state_(ScannerState::STOPPED);
|
|
||||||
|
// Perform cleanup and transition to IDLE
|
||||||
|
this->cleanup_scan_state_(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP32BLETracker::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
void ESP32BLETracker::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||||
@ -794,9 +777,6 @@ void ESP32BLETracker::dump_config() {
|
|||||||
case ScannerState::STOPPING:
|
case ScannerState::STOPPING:
|
||||||
ESP_LOGCONFIG(TAG, " Scanner State: STOPPING");
|
ESP_LOGCONFIG(TAG, " Scanner State: STOPPING");
|
||||||
break;
|
break;
|
||||||
case ScannerState::STOPPED:
|
|
||||||
ESP_LOGCONFIG(TAG, " Scanner State: STOPPED");
|
|
||||||
break;
|
|
||||||
case ScannerState::FAILED:
|
case ScannerState::FAILED:
|
||||||
ESP_LOGCONFIG(TAG, " Scanner State: FAILED");
|
ESP_LOGCONFIG(TAG, " Scanner State: FAILED");
|
||||||
break;
|
break;
|
||||||
@ -881,6 +861,17 @@ bool ESPBTDevice::resolve_irk(const uint8_t *irk) const {
|
|||||||
}
|
}
|
||||||
#endif // USE_ESP32_BLE_DEVICE
|
#endif // USE_ESP32_BLE_DEVICE
|
||||||
|
|
||||||
|
void ESP32BLETracker::cleanup_scan_state_(bool is_stop_complete) {
|
||||||
|
ESP_LOGD(TAG, "Scan %scomplete, set scanner state to IDLE.", is_stop_complete ? "stop " : "");
|
||||||
|
this->already_discovered_.clear();
|
||||||
|
this->cancel_timeout("scan");
|
||||||
|
|
||||||
|
for (auto *listener : this->listeners_)
|
||||||
|
listener->on_scan_end();
|
||||||
|
|
||||||
|
this->set_scanner_state_(ScannerState::IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace esphome::esp32_ble_tracker
|
} // namespace esphome::esp32_ble_tracker
|
||||||
|
|
||||||
#endif // USE_ESP32
|
#endif // USE_ESP32
|
||||||
|
@ -158,18 +158,16 @@ enum class ClientState : uint8_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum class ScannerState {
|
enum class ScannerState {
|
||||||
// Scanner is idle, init state, set from the main loop when processing STOPPED
|
// Scanner is idle, init state
|
||||||
IDLE,
|
IDLE,
|
||||||
// Scanner is starting, set from the main loop only
|
// Scanner is starting
|
||||||
STARTING,
|
STARTING,
|
||||||
// Scanner is running, set from the ESP callback only
|
// Scanner is running
|
||||||
RUNNING,
|
RUNNING,
|
||||||
// Scanner failed to start, set from the ESP callback only
|
// Scanner failed to start
|
||||||
FAILED,
|
FAILED,
|
||||||
// Scanner is stopping, set from the main loop only
|
// Scanner is stopping
|
||||||
STOPPING,
|
STOPPING,
|
||||||
// Scanner is stopped, set from the ESP callback only
|
|
||||||
STOPPED,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ConnectionType : uint8_t {
|
enum class ConnectionType : uint8_t {
|
||||||
@ -262,8 +260,6 @@ class ESP32BLETracker : public Component,
|
|||||||
void stop_scan_();
|
void stop_scan_();
|
||||||
/// Start a single scan by setting up the parameters and doing some esp-idf calls.
|
/// Start a single scan by setting up the parameters and doing some esp-idf calls.
|
||||||
void start_scan_(bool first);
|
void start_scan_(bool first);
|
||||||
/// Called when a scan ends
|
|
||||||
void end_of_scan_();
|
|
||||||
/// Called when a `ESP_GAP_BLE_SCAN_RESULT_EVT` event is received.
|
/// Called when a `ESP_GAP_BLE_SCAN_RESULT_EVT` event is received.
|
||||||
void gap_scan_result_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m);
|
void gap_scan_result_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m);
|
||||||
/// Called when a `ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT` event is received.
|
/// Called when a `ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT` event is received.
|
||||||
@ -274,6 +270,8 @@ class ESP32BLETracker : public Component,
|
|||||||
void gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param ¶m);
|
void gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param ¶m);
|
||||||
/// Called to set the scanner state. Will also call callbacks to let listeners know when state is changed.
|
/// Called to set the scanner state. Will also call callbacks to let listeners know when state is changed.
|
||||||
void set_scanner_state_(ScannerState state);
|
void set_scanner_state_(ScannerState state);
|
||||||
|
/// Common cleanup logic when transitioning scanner to IDLE state
|
||||||
|
void cleanup_scan_state_(bool is_stop_complete);
|
||||||
|
|
||||||
uint8_t app_id_{0};
|
uint8_t app_id_{0};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user