diff --git a/esphome/components/ld2410/ld2410.cpp b/esphome/components/ld2410/ld2410.cpp index e3b948e4c3a..f10e7ec0aae 100644 --- a/esphome/components/ld2410/ld2410.cpp +++ b/esphome/components/ld2410/ld2410.cpp @@ -359,17 +359,14 @@ void LD2410Component::handle_periodic_data_() { Detect distance: 16~17th bytes */ #ifdef USE_SENSOR - SAFE_PUBLISH_SENSOR( - this->moving_target_distance_sensor_, - ld24xx::two_byte_to_uint16(this->buffer_data_[MOVING_TARGET_LOW], this->buffer_data_[MOVING_TARGET_HIGH])) + SAFE_PUBLISH_SENSOR(this->moving_target_distance_sensor_, + encode_uint16(this->buffer_data_[MOVING_TARGET_HIGH], this->buffer_data_[MOVING_TARGET_LOW])) SAFE_PUBLISH_SENSOR(this->moving_target_energy_sensor_, this->buffer_data_[MOVING_ENERGY]) - SAFE_PUBLISH_SENSOR( - this->still_target_distance_sensor_, - ld24xx::two_byte_to_uint16(this->buffer_data_[STILL_TARGET_LOW], this->buffer_data_[STILL_TARGET_HIGH])); + SAFE_PUBLISH_SENSOR(this->still_target_distance_sensor_, + encode_uint16(this->buffer_data_[STILL_TARGET_HIGH], this->buffer_data_[STILL_TARGET_LOW])); SAFE_PUBLISH_SENSOR(this->still_target_energy_sensor_, this->buffer_data_[STILL_ENERGY]); - SAFE_PUBLISH_SENSOR( - this->detection_distance_sensor_, - ld24xx::two_byte_to_uint16(this->buffer_data_[DETECT_DISTANCE_LOW], this->buffer_data_[DETECT_DISTANCE_HIGH])); + SAFE_PUBLISH_SENSOR(this->detection_distance_sensor_, + encode_uint16(this->buffer_data_[DETECT_DISTANCE_HIGH], this->buffer_data_[DETECT_DISTANCE_LOW])); if (engineering_mode) { /* @@ -576,8 +573,8 @@ bool LD2410Component::handle_ack_data_() { /* None Duration: 33~34th bytes */ - updates.push_back(set_number_value(this->timeout_number_, - ld24xx::two_byte_to_uint16(this->buffer_data_[32], this->buffer_data_[33]))); + updates.push_back( + set_number_value(this->timeout_number_, encode_uint16(this->buffer_data_[33], this->buffer_data_[32]))); for (auto &update : updates) { update(); } diff --git a/esphome/components/ld2412/ld2412.cpp b/esphome/components/ld2412/ld2412.cpp index f5bf42829e2..ef0915d0bc0 100644 --- a/esphome/components/ld2412/ld2412.cpp +++ b/esphome/components/ld2412/ld2412.cpp @@ -396,22 +396,19 @@ void LD2412Component::handle_periodic_data_() { Detect distance: 16~17th bytes */ #ifdef USE_SENSOR - SAFE_PUBLISH_SENSOR( - this->moving_target_distance_sensor_, - ld24xx::two_byte_to_uint16(this->buffer_data_[MOVING_TARGET_LOW], this->buffer_data_[MOVING_TARGET_HIGH])) + SAFE_PUBLISH_SENSOR(this->moving_target_distance_sensor_, + encode_uint16(this->buffer_data_[MOVING_TARGET_HIGH], this->buffer_data_[MOVING_TARGET_LOW])) SAFE_PUBLISH_SENSOR(this->moving_target_energy_sensor_, this->buffer_data_[MOVING_ENERGY]) - SAFE_PUBLISH_SENSOR( - this->still_target_distance_sensor_, - ld24xx::two_byte_to_uint16(this->buffer_data_[STILL_TARGET_LOW], this->buffer_data_[STILL_TARGET_HIGH])) + SAFE_PUBLISH_SENSOR(this->still_target_distance_sensor_, + encode_uint16(this->buffer_data_[STILL_TARGET_HIGH], this->buffer_data_[STILL_TARGET_LOW])) SAFE_PUBLISH_SENSOR(this->still_target_energy_sensor_, this->buffer_data_[STILL_ENERGY]) if (this->detection_distance_sensor_ != nullptr) { int new_detect_distance = 0; if (target_state != 0x00 && (target_state & MOVE_BITMASK)) { new_detect_distance = - ld24xx::two_byte_to_uint16(this->buffer_data_[MOVING_TARGET_LOW], this->buffer_data_[MOVING_TARGET_HIGH]); + encode_uint16(this->buffer_data_[MOVING_TARGET_HIGH], this->buffer_data_[MOVING_TARGET_LOW]); } else if (target_state != 0x00) { - new_detect_distance = - ld24xx::two_byte_to_uint16(this->buffer_data_[STILL_TARGET_LOW], this->buffer_data_[STILL_TARGET_HIGH]); + new_detect_distance = encode_uint16(this->buffer_data_[STILL_TARGET_HIGH], this->buffer_data_[STILL_TARGET_LOW]); } this->detection_distance_sensor_->publish_state_if_not_dup(new_detect_distance); } @@ -635,9 +632,9 @@ bool LD2412Component::handle_ack_data_() { /* None Duration: 11~12th bytes */ - updates.push_back(set_number_value(this->timeout_number_, - ld24xx::two_byte_to_uint16(this->buffer_data_[12], this->buffer_data_[13]))); - ESP_LOGV(TAG, "timeout_number_: %u", ld24xx::two_byte_to_uint16(this->buffer_data_[12], this->buffer_data_[13])); + updates.push_back( + set_number_value(this->timeout_number_, encode_uint16(this->buffer_data_[13], this->buffer_data_[12]))); + ESP_LOGV(TAG, "timeout_number_: %u", encode_uint16(this->buffer_data_[13], this->buffer_data_[12])); /* Output pin configuration: 13th bytes */ diff --git a/esphome/components/socket/__init__.py b/esphome/components/socket/__init__.py index a83648979c7..a1e5d16036f 100644 --- a/esphome/components/socket/__init__.py +++ b/esphome/components/socket/__init__.py @@ -191,7 +191,7 @@ async def to_code(config): # ESP32 and LibreTiny both have LwIP >= 2.1.3 with lwip_socket_dbg_get_socket() # and FreeRTOS task notifications — enable fast select to bypass lwip_select() if CORE.is_esp32 or CORE.is_libretiny: - cg.add_define("USE_LWIP_FAST_SELECT") + cg.add_build_flag("-DUSE_LWIP_FAST_SELECT") def FILTER_SOURCE_FILES() -> list[str]: diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index 4aa8b805648..1507fad4996 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -339,8 +339,9 @@ void IRAM_ATTR HOT Component::enable_loop_soon_any_context() { #ifdef USE_LWIP_FAST_SELECT // Wake the main loop if sleeping in ulTaskNotifyTake(). Without this, // the main loop would not wake until the select timeout expires (~16ms). - // Uses xPortInIsrContext() to pick xTaskNotifyGive (task) or - // vTaskNotifyGiveFromISR (ISR) — safe from any calling context. + // Uses platform-specific context detection to choose the correct notify + // API (task vs ISR), e.g. xPortInIsrContext() on ESP32 or IPSR register + // on LibreTiny — safe from any calling context. Application::wake_loop_any_context(); #endif } diff --git a/esphome/core/component.h b/esphome/core/component.h index 9dc271782ee..6b920da2901 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -301,6 +301,8 @@ class Component { /// Helper to set a status LED flag on both this component and the app. /// Returns true if the flag was newly set, false if it was already set. + /// Note: Callers often use the return value to decide whether to log a warning/error, + /// so once a flag is set, subsequent (potentially different) messages may be suppressed. bool set_status_flag_(uint8_t flag); /** Set an interval function with a unique name. Empty name means no cancelling possible. diff --git a/esphome/core/lwip_fast_select.c b/esphome/core/lwip_fast_select.c index 8c4b26ccacd..370638a8e08 100644 --- a/esphome/core/lwip_fast_select.c +++ b/esphome/core/lwip_fast_select.c @@ -105,10 +105,9 @@ // critical sections). Multiple concurrent xTaskNotifyGive calls are safe — // the notification count simply increments. -// USE_ESP32 and USE_LIBRETINY are compiler -D flags, so they are always visible in this .c file. -// Feature macros like USE_LWIP_FAST_SELECT may come from generated headers that are not included here, -// so this implementation is enabled based on platform flags instead of USE_LWIP_FAST_SELECT. -#if defined(USE_ESP32) || defined(USE_LIBRETINY) +// USE_LWIP_FAST_SELECT is set via -D build flag (not cg.add_define) so it is +// visible in both .c and .cpp translation units. +#ifdef USE_LWIP_FAST_SELECT // LwIP headers must come first — they define netconn_callback, struct lwip_sock, etc. #include @@ -242,17 +241,30 @@ 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): __get_IPSR() — reads IPSR register (0 = task context) +// 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 uint32_t esphome_get_ipsr(void) { + uint32_t ipsr; + __asm volatile("mrs %0, ipsr" : "=r"(ipsr)); + return ipsr; +} +#endif + void IRAM_ATTR esphome_lwip_wake_main_loop_any_context(void) { #ifdef USE_ESP32 if (xPortInIsrContext()) { #else - if (__get_IPSR() != 0) { + if (esphome_get_ipsr() != 0) { #endif - esphome_lwip_wake_main_loop_from_isr(NULL); + 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); } else { esphome_lwip_wake_main_loop(); } } -#endif // defined(USE_ESP32) || defined(USE_LIBRETINY) +#endif // USE_LWIP_FAST_SELECT diff --git a/script/ci-custom.py b/script/ci-custom.py index 85a446ba0dd..f428eb0821b 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -959,7 +959,7 @@ def main(): continue run_checks(LINT_CONTENT_CHECKS, fname, fname, content) - run_checks(LINT_POST_CHECKS, "POST") + run_checks(LINT_POST_CHECKS, Path("POST")) for f, errs in sorted(errors.items()): bold = functools.partial(styled, colorama.Style.BRIGHT)