- SEARCH_CMPL honors the event's own status: a failed discovery leaves
an empty cached database that the count calls read as a clean zero,
which would have become an authoritative empty service list
- The loop stays enabled while a link exists and settles only at IDLE -
the stack-down recovery needs a tick to run in ESTABLISHED, which the
settle-on-established optimization was silently blocking
- The pre-started search uses the OPEN_EVT conn id (replaced-class
parity)
- A refused MTU request no longer wedges the connection: OPEN_EVT
reports with the default MTU so the consumer proceeds (previously no
CFG_MTU_EVT meant no connected report and a slot that never freed)
- Disabling the BLE stack settles a live link with a connected=false
report before forgetting it, so the consumer frees its slot instead of
holding a phantom connection
- A refused security response answers the pairing request with the
failure instead of hanging it
- The service-table walk mismatch logs its reason before discarding
- The shared streamer's two bounds-check aborts use abort_service_stream
with an ATT Unlikely Error cause (new shared GATT_ERR_UNLIKELY)
The three coordinated flags become one SearchState (NONE / PRESTARTED /
PRESTART_DONE / CLAIMED / REPORT_PENDING): illegal combinations are
unrepresentable, delivery and the two reset sites collapse to single
assignments, and the requested-meets-done subtlety becomes a named
state. A second discover_services() while one is in flight now returns 0
instead of issuing a duplicate search (one completion is already owed).
Same RAM: the enum sits in a 4-bit bitfield in the same flags byte.
The latches were cleared only in set_idle_(), but the stack-down branch
in loop() reaches IDLE through set_state() without it, so after a
ble.disable/enable cycle the next connection's discover_services() would
complete immediately from the previous connection's latched result and
HA would cache an authoritative empty service list. tracker_connect_()
now resets the latch alongside the two per-attempt flags it already
clears, and delivery consumes the whole latch so a re-discovery on a
live link issues a real search instead of re-reporting the first
result.
- abort_service_stream() on the wrapper (which owns the latch discipline)
replaces five identical field-poke sequences in the streamer
- The pre-start reuses check_and_log_error_ like the serialized path
- discover_services() sets the requested flag where it sticks instead of
set-then-rollback; deliver_pending_search_() returns void (no caller
reads it); loop()'s IDLE arm folds into the settle arm
- SEARCH_CMPL during a teardown skips the param/count work whose result
is never delivered
- frameworks_for_platforms() in config_helpers derives framework sets
from platform lists; the hub.cpp filter entry is now a named map pinned
by a test against the proxy's platform list
The split serialized service discovery behind the MTU exchange: the
backend reported connected only at CFG_MTU_EVT and the wrapper started
discovery on that report, costing one ATT round trip per uncached
connection. The backend now pre-starts the search at OPEN_EVT (it knows
the connection type) and completes the consumer's discover_services()
from it: SEARCH_CMPL latches silently until requested, the flush after
the connected report delivers in the same event drain, and a refused
pre-start falls back to the serialized path. Net RAM cost is zero (the
flags pack into one bitfield byte plus a status byte, replacing the two
existing bools).
Also from review: SEARCH_CMPL no longer clobbers a teardown in progress
with ESTABLISHED, the five streamer abort sites latch pending_error_ so
HA sees the real Bluedroid status instead of a generic HCI reason, and a
completed re-discovery frees a materialized service table before the
counts its offsets derive from move.
The hub wrapper serves the proxy's API surface, but its gate keyed on the
backend define alone while the backend guarded its own proxy pieces on
USE_BLUETOOTH_PROXY. Narrow BLUETOOTH_CONNECTION_HAS_GATT to require both
so a future backend-only consumer build agrees with the backend's guards.
No change to any build this PR can produce (only the proxy emits
USE_BLE_GATT_CLIENT here).
- Fold the one-line event-handler forwarders, the state accessor renames,
and the report helper into direct calls; drop the dead forward
declaration and the tracker_client() accessor (the backend is the
tracker client)
- Hoist DEFAULT_ATT_MTU next to the other shared GATT constants and use
it in all three engines
- Emit BLUETOOTH_PROXY_MAX_CONNECTIONS once, in _connections_to_code
- Drop the unused esp_gatt_common_api.h include and DOMAIN constant
- Comment accuracy: stale shim/esp32-parity wording, registry roles,
request_gatt_client() caller