The lambda in DelayAction::play_complex must be `mutable` so captured
copies of non-const reference arguments (e.g. std::string& from the
http_request on_response trigger) can bind to the non-const reference
parameters of play_next_(const Ts&...). Without `mutable`, the captured
members are const-qualified and cannot bind to `T&`.
Regression from #14968 which replaced std::bind with a lambda.
Fixes https://github.com/esphome/esphome/issues/15808
The idempotency check in _inject_keep returns content unchanged when the
marker is already present, so patched stayed 0 and the fail-hard
RuntimeError fired on every incremental rebuild after the first. Check
for the marker before attempting to patch and count it as success.
IRAM_ATTR is a no-op on BK72xx so there is nothing for the script to
patch or summarize. Guard the extra_scripts registration with a
COMPONENT_BK72XX check and drop the BK72xx variants from
KNOWN_VARIANTS.
Post-link was not registered for RTL8710B (condition was too narrow
after removing it from _PATCHERS_BY_VARIANT). Use a BK72xx exclusion
set instead so all IRAM-active variants get the summary.
Also fall back to TOOLCHAIN_PREFIX-nm when $NM is empty, which fixes
the empty summary on LN882H.
RTL8710B's stock linker already consumes *(.image2.ram.text*) into its
.ram_image2.text output (> BD_RAM), so hal.h can place IRAM_ATTR
functions directly into section(".image2.ram.text") without any linker
patching. RTL8720C already worked this way with section(".sram.text").
The patcher is now only needed for LN882H, whose stock linker has no
glob that catches ".sram.text" — we inject KEEP(*(.sram.text*)) into
.flash_copysection (> RAM0 AT> FLASH).
This removes the _RTL8710B_IMAGE2 regex, the RTL8710B entry from
_PATCHERS_BY_VARIANT, and simplifies the header comments.
Linker-generated interworking veneers (e.g. ___ZN...enable_loop_soon_
any_context_veneer at 0x9b062588) contain the same function name
substrings but live at unrelated addresses, producing a bogus multi-GB
range in the summary. Filter them out.
- ESP8266 in_isr_context() was checking PS.INTLEVEL which gives false
positives when user code masks interrupts. Return false unconditionally
since the ESP8266 wake path is context-agnostic and never calls
in_isr_context().
- Replace brittle mangled C++ symbol names in the post-link fallback
with substring matches on demangled names via nm --demangle. Survives
namespace/signature changes.
Review feedback:
- three comments still referenced the input glob '.image2.ram.text' after
the output section was fixed to '.ram_image2.text' in eae6e6d32b; update
comments in hal.h, libretiny/__init__.py, and patch_linker.py.script so
they match the regex.
- rename the 'dir' local in libretiny.copy_files() to 'script_dir' to
avoid shadowing the Python builtin.
- the 'no linker script patched' RuntimeError now names the per-family
regex constants a maintainer should update when a LibreTiny template
changes shape.
Confused the output section name with the input glob. RTL8710B's linker
template has:
.ram_image2.text : {
KEEP(*(.image2.ram.text*))
} > BD_RAM
so we need to match ".ram_image2.text :" and inject our extra
KEEP(*(.sram.text*)) alongside the existing input glob. CI caught this;
the test_build_components rtl87xx-ard smoke test now exercises the
patcher.
- hal.h: collapse the four-way USE_LIBRETINY_VARIANT_BK72* guard into
USE_BK72XX.
- libretiny/__init__.py: drop the stale reference to growing .itcm from
4.5 kB to 8.5 kB; BK72xx no longer gets any .ld patching.
- patch_linker.py.script: hoist the duplicated "import subprocess" to the
top, pull the fallback IRAM_ATTR symbols out into a module-level
frozenset, and split the ELF scan into a helper so _post_link is just
the print logic.
After confirming via the Beken SDKs (both BK7231T and BK7231N flash.c use
GLOBAL_INT_DISABLE around every erase/program) and searching the libretiny
+ esphome issue trackers, the ISR-during-flash race IRAM_ATTR is designed
to prevent cannot actually occur on any BK72xx variant:
- Beken SDK wraps every flash op in GLOBAL_INT_DISABLE(), masking FIQ +
IRQ at the CPU for the ~0.5-20 ms of the write, so no ISR fires while
flash is stalled.
- Interrupts are delayed (not dropped outright for single-shot sources)
by that mask, but that is an SDK-level design choice and cannot be
reduced from this layer.
- No BK72xx user has reported the crash pattern IRAM_ATTR fixes; the
real reports of that pattern are on RTL8710B (see libretiny#167).
Make IRAM_ATTR a no-op on every BK72xx variant and remove the BK7231N-
specific ITCM shuffling from patch_linker.py.script. The fix now covers
only the families where the race is real: RTL8710B, RTL8720C, LN882H.
BK7231T / BK7231Q / BK7251 share a LibreTiny linker template that only
declares flash + ram, no executable RAM region. Their SDK wraps flash
writes in GLOBAL_INT_DISABLE() which masks both FIQ and IRQ, so no ISR
fires while flash is stalled and the "code in flash while flash is busy"
scenario IRAM_ATTR is guarding against does not occur on those variants.
Map IRAM_ATTR to nothing on them rather than orphan-linking .sram.text
into flash and drop the T/Q/7251 entries from _PATCHERS_BY_VARIANT so
the pre-link hook is not registered for them.
BK7231N still gets the full fix (grown .itcm.code) because its SDK takes
the defense-in-depth route of also placing flash/ISR/FreeRTOS critical
code in ITCM, so our IRAM_ATTR functions need to live there too.
Also make _grow_bk72xx_itcm fail loudly if the tcm/itcm declarations in
the BK7231N template ever change shape, matching the fail-hard stance of
the rest of the script.
The SDK's built-in ISR / flash / FreeRTOS critical-path code already fills
most of the stock 4.5 kB .itcm executable RAM region, leaving under 500
bytes for ESPHome's IRAM_ATTR functions. cb3s overflowed by 248 bytes on
first link. Physically .tcm (rw!x, data) and .itcm (rwx, code) are
contiguous SRAM blocks on ARM968E-S; the template's boundary is just a
linker carve-out. Shift it back 4 kB so .tcm shrinks 60k -> 56k and .itcm
grows 4.5k -> 8.5k. Confirmed fits every ESPHome IRAM_ATTR function on cb3s
with ample headroom.