mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 08:55:36 +00:00
Merge remote-tracking branch 'upstream/esp8266-wake-loop-any-context' into integration
This commit is contained in:
@@ -633,6 +633,7 @@ class Application {
|
||||
esphome_lwip_wake_main_loop_from_isr(px_higher_priority_task_woken);
|
||||
}
|
||||
|
||||
#ifdef USE_ESP32
|
||||
/// Wake the main event loop from any context (ISR, thread, or main loop).
|
||||
/// Detects the calling context and uses the appropriate FreeRTOS API.
|
||||
static void IRAM_ATTR wake_loop_any_context() { esphome_lwip_wake_main_loop_any_context(); }
|
||||
@@ -642,6 +643,13 @@ class Application {
|
||||
static void IRAM_ATTR wake_loop_any_context() { socket::socket_wake(); }
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_ESP8266) && defined(USE_SOCKET_IMPL_LWIP_TCP)
|
||||
/// Wake the main event loop from any context (ISR, thread, or main loop).
|
||||
/// On ESP8266: sets the socket wake flag and calls esp_schedule() to exit esp_delay() early.
|
||||
static void IRAM_ATTR wake_loop_any_context() { socket::socket_wake(); }
|
||||
#endif
|
||||
|
||||
#if defined(USE_ESP8266) && defined(USE_SOCKET_IMPL_LWIP_TCP)
|
||||
/// Wake the main event loop from any context (ISR, thread, or main loop).
|
||||
|
||||
@@ -328,7 +328,7 @@ void IRAM_ATTR HOT Component::enable_loop_soon_any_context() {
|
||||
// This method is thread and ISR-safe because:
|
||||
// 1. Only performs simple assignments to volatile variables (atomic on all platforms)
|
||||
// 2. No read-modify-write operations that could be interrupted
|
||||
// 3. No memory allocation or object construction; the only call (wake_loop_any_context) is ISR-safe
|
||||
// 3. No memory allocation or object construction; on ESP32 the only call (wake_loop_any_context) is ISR-safe
|
||||
// 4. IRAM_ATTR ensures code is in IRAM, not flash (required for ISR execution)
|
||||
// 5. Components are never destroyed, so no use-after-free concerns
|
||||
// 6. App is guaranteed to be initialized before any ISR could fire
|
||||
@@ -336,11 +336,10 @@ void IRAM_ATTR HOT Component::enable_loop_soon_any_context() {
|
||||
// 8. Race condition with main loop is handled by clearing flag before processing
|
||||
this->pending_enable_loop_ = true;
|
||||
App.has_pending_enable_loop_requests_ = true;
|
||||
#if defined(USE_LWIP_FAST_SELECT) || (defined(USE_ESP8266) && defined(USE_SOCKET_IMPL_LWIP_TCP))
|
||||
#if (defined(USE_LWIP_FAST_SELECT) && defined(USE_ESP32)) || (defined(USE_ESP8266) && defined(USE_SOCKET_IMPL_LWIP_TCP))
|
||||
// Wake the main loop from sleep. Without this, the main loop would not
|
||||
// wake until the select/delay timeout expires (~16ms).
|
||||
// ESP32/LibreTiny: uses platform-specific context detection (xPortInIsrContext
|
||||
// or IPSR register) to choose the correct FreeRTOS notify API.
|
||||
// ESP32: uses xPortInIsrContext() to choose the correct FreeRTOS notify API.
|
||||
// ESP8266: sets socket wake flag and calls esp_schedule() to exit esp_delay() early.
|
||||
Application::wake_loop_any_context();
|
||||
#endif
|
||||
|
||||
@@ -239,26 +239,11 @@ void IRAM_ATTR esphome_lwip_wake_main_loop_from_isr(int *px_higher_priority_task
|
||||
}
|
||||
|
||||
// Wake the main loop from any context (ISR, thread, or main loop).
|
||||
// Detects ISR context and delegates to the appropriate variant:
|
||||
// ESP32 (Xtensa/RISC-V): xPortInIsrContext() — checks interrupt nesting counter
|
||||
// LibreTiny (ARM Cortex-M): IPSR register read via inline asm (0 = task context)
|
||||
#ifdef USE_LIBRETINY
|
||||
// Read the ARM Cortex-M IPSR register directly via inline asm.
|
||||
// Avoids depending on CMSIS __get_IPSR() which may not be declared/available
|
||||
// in all LibreTiny chip family toolchains (e.g. beken-72xx).
|
||||
static inline IRAM_ATTR uint32_t esphome_get_ipsr(void) {
|
||||
uint32_t ipsr = 0;
|
||||
__asm volatile("mrs %0, ipsr" : "=r"(ipsr));
|
||||
return ipsr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void IRAM_ATTR esphome_lwip_wake_main_loop_any_context(void) {
|
||||
// ESP32-only: uses xPortInIsrContext() to detect ISR context.
|
||||
// LibreTiny is excluded because it lacks IRAM_ATTR support needed for ISR-safe paths.
|
||||
#ifdef USE_ESP32
|
||||
void IRAM_ATTR esphome_lwip_wake_main_loop_any_context(void) {
|
||||
if (xPortInIsrContext()) {
|
||||
#else
|
||||
if (esphome_get_ipsr() != 0) {
|
||||
#endif
|
||||
int px_higher_priority_task_woken = 0;
|
||||
esphome_lwip_wake_main_loop_from_isr(&px_higher_priority_task_woken);
|
||||
portYIELD_FROM_ISR(px_higher_priority_task_woken);
|
||||
@@ -266,5 +251,6 @@ void IRAM_ATTR esphome_lwip_wake_main_loop_any_context(void) {
|
||||
esphome_lwip_wake_main_loop();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // USE_LWIP_FAST_SELECT
|
||||
|
||||
@@ -34,8 +34,11 @@ void esphome_lwip_wake_main_loop(void);
|
||||
void esphome_lwip_wake_main_loop_from_isr(int *px_higher_priority_task_woken);
|
||||
|
||||
/// Wake the main loop task from any context (ISR, thread, or main loop).
|
||||
/// Detects the calling context and uses the appropriate FreeRTOS API.
|
||||
/// ESP32-only: uses xPortInIsrContext() to detect ISR context.
|
||||
/// LibreTiny lacks IRAM_ATTR support needed for ISR-safe paths.
|
||||
#ifdef USE_ESP32
|
||||
void esphome_lwip_wake_main_loop_any_context(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user