ESPHome 2026.5.0-dev
Loading...
Searching...
No Matches
helpers.cpp
Go to the documentation of this file.
3
4#ifdef USE_RP2040
5
6#include "esphome/core/hal.h"
7
8#if defined(USE_WIFI)
9#include <WiFi.h>
10#include <pico/cyw43_arch.h> // For cyw43_arch_lwip_begin/end (LwIPLock)
11#elif defined(USE_ETHERNET)
12#include <lwip_wrap.h> // For LWIPMutex — LwIPLock mirrors its semantics (see below)
14#endif
15#include <hardware/structs/rosc.h>
16#include <hardware/sync.h>
17
18namespace esphome {
19
20bool random_bytes(uint8_t *data, size_t len) {
21 while (len-- != 0) {
22 uint8_t result = 0;
23 for (uint8_t i = 0; i < 8; i++) {
24 result <<= 1;
25 result |= rosc_hw->randombit;
26 }
27 *data++ = result;
28 }
29 return true;
30}
31
32// RP2040 Mutex is defined inline in helpers.h for RP2040/ESP8266 builds.
33
34IRAM_ATTR InterruptLock::InterruptLock() { state_ = save_and_disable_interrupts(); }
35IRAM_ATTR InterruptLock::~InterruptLock() { restore_interrupts(state_); }
36
37// On RP2040, lwip callbacks run from a low-priority user IRQ context, not the
38// main loop (see low_priority_irq_handler() in pico-sdk
39// async_context_threadsafe_background.c). This applies to both WiFi (CYW43) and
40// Ethernet (W5500) — both use async_context_threadsafe_background.
41//
42// Without locking, recv_fn() from IRQ context races with read_locked_() on the
43// main loop, corrupting the shared rx_buf_ pbuf chain (use-after-free, pbuf_cat
44// assertion failures). See esphome#10681.
45//
46// WiFi uses cyw43_arch_lwip_begin/end.
47//
48// For wired Ethernet, taking only the async_context lock is NOT enough. The
49// W5500 GPIO IRQ path (LwipIntfDev::_irq) checks arduino-pico's `__inLWIP`
50// counter to decide whether to defer packet processing. If we hold the
51// async_context lock without bumping `__inLWIP`, an interrupt-driven packet
52// arrival re-enters lwIP from IRQ context and corrupts pbufs (the `pbuf_cat`
53// assertion crash on wiznet-w5500-evb-pico). We mirror arduino-pico's
54// LWIPMutex (cores/rp2040/lwip_wrap.h) exactly: bump `__inLWIP`, take the
55// lock, and on release re-unmask any GPIO IRQs that were deferred while we
56// held it. We can't `using LwIPLock = LWIPMutex;` in helpers.h because
57// pulling lwip_wrap.h there poisons many TUs with lwIP types.
58//
59// When neither WiFi nor Ethernet is configured, this is a no-op since
60// there's no network stack and no lwip callbacks to race with.
61#if defined(USE_WIFI)
62LwIPLock::LwIPLock() { cyw43_arch_lwip_begin(); }
63LwIPLock::~LwIPLock() { cyw43_arch_lwip_end(); }
64#elif defined(USE_ETHERNET)
66 __inLWIP++;
67 ethernet_arch_lwip_begin();
68}
70 ethernet_arch_lwip_end();
71 __inLWIP--;
72 if (__needsIRQEN && !__inLWIP) {
73 __needsIRQEN = false;
74 ethernet_arch_lwip_gpio_unmask();
75 }
76}
77#else
80#endif
81
82void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter)
83#ifdef USE_WIFI
84 WiFi.macAddress(mac);
85#elif defined(USE_ETHERNET)
87#endif
88}
89
90} // namespace esphome
91
92#endif // USE_RP2040
EthernetComponent * global_eth_component
const std::vector< uint8_t > & data
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
bool random_bytes(uint8_t *data, size_t len)
Generate len random bytes using the platform's secure RNG (hardware RNG or OS CSPRNG).
Definition helpers.cpp:20
std::string size_t len
Definition helpers.h:1045
void get_mac_address_raw(uint8_t *mac)
Get the device MAC address as raw bytes, written into the provided byte array (6 bytes).
Definition helpers.cpp:74