mirror of
https://github.com/esphome/esphome.git
synced 2026-08-17 02:47:52 +08:00
[rp2040_ble] Add scan arbitration and GATT client hooks (#18155)
This commit is contained in:
@@ -57,6 +57,17 @@ void RP2040BLE::enable() {
|
||||
l2cap_init();
|
||||
sm_init();
|
||||
|
||||
#ifdef USE_BLE_GATT_CLIENT
|
||||
gatt_client_init();
|
||||
// The GATT engine kicks the MTU exchange explicitly right after a
|
||||
// connection completes (auto negotiation would only run on the first
|
||||
// query, which a with-cache connection never issues).
|
||||
gatt_client_mtu_enable_auto_negotiation(0);
|
||||
// Just-works security for peripheral-initiated pairing.
|
||||
sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);
|
||||
sm_set_authentication_requirements(SM_AUTHREQ_BONDING);
|
||||
#endif
|
||||
|
||||
this->hci_event_callback_registration_.callback = &RP2040BLE::packet_handler;
|
||||
hci_add_event_handler(&this->hci_event_callback_registration_);
|
||||
|
||||
@@ -215,6 +226,18 @@ bool RP2040BLE::scan_start(uint16_t interval, uint16_t window, bool active) {
|
||||
// the moment a tracker retries. Callers retry until the stack is up.
|
||||
return false;
|
||||
}
|
||||
#ifdef USE_BLE_GATT_CLIENT
|
||||
this->scan_interval_ = interval;
|
||||
this->scan_window_ = window;
|
||||
this->scan_active_mode_ = active;
|
||||
this->scan_desired_ = true;
|
||||
if (this->scan_inhibit_count_ > 0) {
|
||||
// A connect attempt owns the radio; the scan starts physically when the
|
||||
// inhibit is released. Report success — the controller will run it.
|
||||
ESP_LOGV(TAG, "Scan start deferred (connect in progress)");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
// Serialize with the BTstack background worker (arduino-pico's BluetoothHCI
|
||||
// takes the same lock around its gap_* calls).
|
||||
BluetoothLock lock;
|
||||
@@ -224,6 +247,9 @@ bool RP2040BLE::scan_start(uint16_t interval, uint16_t window, bool active) {
|
||||
}
|
||||
|
||||
void RP2040BLE::scan_stop() {
|
||||
#ifdef USE_BLE_GATT_CLIENT
|
||||
this->scan_desired_ = false;
|
||||
#endif
|
||||
if (!this->is_active()) {
|
||||
return; // nothing can be scanning on a stack that is not up
|
||||
}
|
||||
@@ -231,6 +257,32 @@ void RP2040BLE::scan_stop() {
|
||||
gap_stop_scan();
|
||||
}
|
||||
|
||||
#ifdef USE_BLE_GATT_CLIENT
|
||||
void RP2040BLE::inhibit_scan() {
|
||||
if (this->scan_inhibit_count_++ != 0) {
|
||||
return; // another connect attempt already owns the radio
|
||||
}
|
||||
if (this->scan_desired_ && this->is_active()) {
|
||||
BluetoothLock lock;
|
||||
gap_stop_scan();
|
||||
}
|
||||
}
|
||||
|
||||
void RP2040BLE::release_scan_inhibit() {
|
||||
if (this->scan_inhibit_count_ == 0) {
|
||||
return;
|
||||
}
|
||||
this->scan_inhibit_count_--;
|
||||
if (this->scan_inhibit_count_ != 0) {
|
||||
return;
|
||||
}
|
||||
if (this->scan_desired_) {
|
||||
// One physical-start path: scan_start re-applies the remembered params.
|
||||
this->scan_start(this->scan_interval_, this->scan_window_, this->scan_active_mode_);
|
||||
}
|
||||
}
|
||||
#endif // USE_BLE_GATT_CLIENT
|
||||
|
||||
} // namespace esphome::rp2040_ble
|
||||
|
||||
#endif // USE_RP2040_BLE
|
||||
|
||||
@@ -91,13 +91,25 @@ class RP2040BLE final : public Component {
|
||||
/// (0.625 ms). Returns false until the stack is ACTIVE (callers retry — the
|
||||
/// tracker's rate-limited retry loop); powering the stack on stays with the
|
||||
/// user (enable_on_boot or an explicit enable() call). The controller keeps
|
||||
/// no scan state: a disable()/enable() power cycle ends the scan, and the
|
||||
/// caller must call scan_start() again once the stack is back to ACTIVE
|
||||
/// (the tracker's loop() reconciliation does exactly that).
|
||||
/// no scan state across power cycles: a disable()/enable() cycle ends the
|
||||
/// scan, and the caller must call scan_start() again once the stack is back
|
||||
/// to ACTIVE (the tracker's loop() reconciliation does exactly that).
|
||||
/// While a GATT connect attempt has the scan inhibited, the desired scan is
|
||||
/// remembered and started physically when the inhibit is released.
|
||||
bool scan_start(uint16_t interval, uint16_t window, bool active);
|
||||
/// Stop the controller scan (no-op when not scanning).
|
||||
void scan_stop();
|
||||
|
||||
#ifdef USE_BLE_GATT_CLIENT
|
||||
/// Pause the physical scan for the duration of a GATT connect attempt
|
||||
/// (initiating and scanning contend for the radio). The desired scan state
|
||||
/// set through scan_start()/scan_stop() is remembered and reconciled by
|
||||
/// release_scan_inhibit(). Holders must guarantee the release on every
|
||||
/// abort path (the GATT engine reclaims via its connect timeout).
|
||||
void inhibit_scan();
|
||||
void release_scan_inhibit();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static void packet_handler(uint8_t type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
|
||||
@@ -128,6 +140,16 @@ class RP2040BLE final : public Component {
|
||||
bool enable_on_boot_{true};
|
||||
bool btstack_initialized_{false};
|
||||
bool active_logged_{false};
|
||||
#ifdef USE_BLE_GATT_CLIENT
|
||||
// Remembered scan intent, so connect attempts can pause the physical scan
|
||||
// and restore it afterwards without involving the tracker. Counted so
|
||||
// overlapping connect attempts compose once multiple slots exist.
|
||||
uint16_t scan_interval_{0};
|
||||
uint16_t scan_window_{0};
|
||||
uint8_t scan_inhibit_count_{0};
|
||||
bool scan_active_mode_{false};
|
||||
bool scan_desired_{false};
|
||||
#endif
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
Reference in New Issue
Block a user