Bitfield component_source_index_ (9 bits) and warn_if_blocking_over_
(7 bits) into the same 16 bits. This doubles the max unique component
source names from 255 to 511 without increasing Component size.
The blocking warn threshold max drops from 2550ms to 1270ms which is
more than sufficient since it starts at 50ms and ratchets up.
Fixes test warnings when many components are compiled together:
WARNING Too many unique component source names (max 255)
Replace virtual handler interfaces (GAPEventHandler, GAPScanEventHandler,
GATTcEventHandler, GATTsEventHandler, BLEStatusEventHandler) with
StaticCallbackManager-based dispatch using lambda callbacks.
This eliminates vtable lookups and MI this-pointer adjustment thunks
on every BLE event dispatch in the hot path. Each lambda captures a
single pointer (fits in Callback inline storage, no heap allocation)
and the StaticCallbackManager avoids std::vector template bloat.
Breaking change: external components inheriting from the virtual handler
classes need to switch to add_*_callback() registration instead.
When OTA starts, stop_scan() is called which clears the scan_continuous_
flag. If OTA fails or aborts, the scan was never restarted because
scan_continuous_ was already false. This left the device without BLE
scanning until reboot.
Save the scan_continuous_ state before stopping and restore it on
OTA_ERROR or OTA_ABORT to resume scanning.
Replace the FreeRTOS xQueue (xQueueCreate/xQueueSend/xQueueReceive)
used for WiFi event passing with a lock-free SPSC queue. This avoids
the FreeRTOS kernel spinlock overhead on every loop iteration when
checking for events — the common case is an empty queue.
The LockFreeQueue::pop() fast path is just two atomic loads and a
comparison, vs xQueueReceive which takes a spinlock, checks the
queue, and releases the spinlock even when empty.
WiFi events are rare (connect/disconnect/scan) so heap allocation
for event data is retained — no EventPool needed unlike the BLE
path which processes hundreds of events per second.
This matches the lock-free pattern already used by esp32_ble.
Replace the FreeRTOS xQueue (xQueueCreate/xQueueSend/xQueueReceive)
used for WiFi event passing with a lock-free SPSC queue. This avoids
the FreeRTOS kernel spinlock overhead on every loop iteration when
checking for events — the common case is an empty queue.
The LockFreeQueue::pop() fast path is just two atomic loads and a
comparison, vs xQueueReceive which takes a spinlock, checks the
queue, and releases the spinlock even when empty.
WiFi events are rare (connect/disconnect/scan) so heap allocation
for event data is retained — no EventPool needed unlike the BLE
path which processes hundreds of events per second.
This matches the lock-free pattern already used by esp32_ble.
Replace the FreeRTOS xQueue (xQueueCreate/xQueueSend/xQueueReceive)
used for WiFi event passing with a lock-free SPSC queue. This avoids
the FreeRTOS kernel spinlock overhead on every loop iteration when
checking for events — the common case is an empty queue.
The LockFreeQueue::pop() fast path is just two atomic loads and a
comparison, vs xQueueReceive which takes a spinlock, checks the
queue, and releases the spinlock even when empty.
WiFi events are rare (connect/disconnect/scan) so heap allocation
for event data is retained — no EventPool needed unlike the BLE
path which processes hundreds of events per second.
This matches the lock-free pattern already used by esp32_ble.
The flag is just a hint — xQueueReceive with its own internal
synchronization is the source of truth. Relaxed ordering avoids
unnecessary fence cost on ESP targets. Worst case is missing an
event for one loop iteration.