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.
Replace atomic counter with a simple flag to avoid underflow race
where consumer could decrement before producer increments. Use
uint8_t instead of bool to avoid GCC Xtensa indirect call issue.
Clear flag before draining — if a new event arrives between clear
and xQueueReceive, the flag is set again and caught next iteration.
Replace atomic counter with a simple flag to avoid underflow race
where consumer could decrement before producer increments. Use
uint8_t instead of bool to avoid GCC Xtensa indirect call issue.
Clear flag before draining — if a new event arrives between clear
and xQueueReceive, the flag is set again and caught next iteration.
Add an atomic counter incremented when events are enqueued and
decremented when dequeued. wifi_loop_() checks this counter before
calling xQueueReceive, avoiding the FreeRTOS kernel call on every
loop iteration when no events are pending (the common case).
This matches the fast-path pattern used by the scheduler to avoid
lock overhead when there is nothing to process.
Replace the file-static s_sta_state with the shared sta_state_
member variable on WiFiComponent, matching the ESP8266 change.
All accesses are in member functions so no global_wifi_component
indirection is needed.
Replace the file-static s_sta_state with the shared sta_state_
member variable on WiFiComponent, matching the ESP8266 change.
All accesses are in member functions so no global_wifi_component
indirection is needed.
Keep the enum definition private to wifi_component_esp8266.cpp and
store as uint8_t in the class to avoid leaking platform-specific
types into the shared header.
Move these small methods to the header so the compiler can inline
them into loop(), eliminating two function call/return pairs from
every loop iteration on all platforms.
Replace the file-static s_sta_state with a member variable sta_state_
on WiFiComponent, consistent with error_from_callback_ and pending_
which are also written from the static callback via global_wifi_component.
Replace five separate boolean state variables in the ESP8266 WiFi
implementation with a single enum state machine, matching the pattern
already used by LibreTiny. This eliminates the per-loop call to
wifi_station_get_connect_status() by reading cached state from the
existing event callback instead.
Also use the cached connected_ field (set unconditionally at the top
of loop()) in the STA_CONNECTED branch instead of calling
is_connected_() a second time. This applies to all platforms.