The RP2040's LEAmDNS library relies on LwipIntf::stateUpCB() to
restart mDNS when the network interface reconnects. However, this
callback is stubbed out in arduino-pico because the original ESP8266
implementation used schedule_function() which doesn't exist in
arduino-pico, and the callback can't safely run directly since netif
status callbacks fire from IRQ context while _restart() allocates
UDP sockets.
The previous workaround blocked all component setup via can_proceed()
until WiFi connected, which only helped on initial boot but did not
handle reconnects.
Replace with a proper fix: detect WiFi reconnection from the existing
50ms mDNS update interval (main loop context) and call
MDNS.notifyAPChange() to restart mDNS probing and announcing.
The RP2040's LEAmDNS library relies on LwipIntf::stateUpCB() to
restart mDNS when the network interface reconnects. However, this
callback is stubbed out in arduino-pico because the original ESP8266
implementation used schedule_function() which doesn't exist in
arduino-pico, and the callback can't safely run directly since netif
status callbacks fire from IRQ context while _restart() allocates
UDP sockets.
The previous workaround blocked all component setup via can_proceed()
until WiFi connected, which only helped on initial boot but did not
handle reconnects.
Replace with a proper fix: detect WiFi reconnection from the existing
50ms mDNS update interval (main loop context) and call
MDNS.notifyAPChange() to restart mDNS probing and announcing.
Add FixedRingBuffer<T, MAX_CAPACITY> to helpers.h as the runtime-sized
equivalent of StaticRingBuffer. Uses std::conditional_t to auto-select
uint8_t/uint16_t/uint32_t index types based on MAX_CAPACITY.
Convert SlidingWindowFilter from manual ring buffer logic on FixedVector
to FixedRingBuffer<float>, eliminating window_head_, window_count_,
and window_size_ fields.
When calling set_effect("None") from a lambda, the compiler cannot
choose between set_effect(optional<std::string>) and
set_effect(const std::string&) since both require one implicit
conversion from const char*. Add explicit const char* overload to
resolve the ambiguity.
Fixes https://github.com/esphome/esphome/issues/14728
readv() holds LWIP_LOCK for the entire scatter-gather operation and
previously called read() internally, which would call wait_for_data_()
→ socket_delay() while the lock was held — blocking recv_fn() on RP2040.
Extract read_locked_() with the state checks and copy logic. Both
read() and readv() call wait_for_data_() before acquiring the lock,
then use read_locked_() under the lock.
Remove the redundant s_socket_woke = false between the early-return
check and the while loop. If an IRQ fires in that window (recv_fn
sets s_socket_woke = true), clearing the flag would lose the wake
and sleep until the timer fires. Now the while loop sees the flag
immediately and exits. The flag is cleared after the loop instead.
Replace read_locked_() approach with a simpler wait_for_data_() called
at the top of both read() and readv(), keeping the original read/readv
structure intact.
- Extract read_locked_() to avoid holding LWIP_LOCK during socket_delay(),
which would block recv_fn() on RP2040 (needs async_context lock)
- Loop around socket_delay() for remaining time on spurious wakes from
other sockets, ensuring SO_RCVTIMEO semantics are correct
- Fix readv() to use read_locked_() directly instead of calling read(),
avoiding recursive locking and unintended socket_delay() waits
When rx_buf_ is empty during the client hello phase of the noise
handshake, rx_buf_.data() can return nullptr. Passing nullptr to
std::memcpy as the source argument is undefined behavior even when
the size is 0. Guard the memcpy with a size check.
Found by UndefinedBehaviorSanitizer in #14718.
StringRef fields decoded from protobuf point into the receive buffer
and are NOT null-terminated. DumpBuffer::append(const char*) calls
strlen() which reads past the buffer. Use the (const char*, size_t)
overload instead.
Found by AddressSanitizer in #14718.
Version the crash data by encoding the version in the magic value
(upper 16 bits = 0xDEAD sentinel, lower 16 bits = version). This
allows safely changing the scratch register layout in future firmware
without misinterpreting old crash data, and costs zero scratch
registers (we only have 8).
Add USE_RP2040_CRASH_HANDLER define and guard all call sites so
the crash handler can be conditionally compiled, matching the ESP32
crash handler pattern.
Add crash_handler_has_data() so callers can check for crash data
without triggering log output.
Log crash data when the API client subscribes to logs so dashboard
and HA users see crash reports even when connecting after boot,
matching the ESP32 crash handler behavior.