Commit Graph
27813 Commits
Author SHA1 Message Date
Clyde Stubbs b018ac67bc [image] Fix byte order handling (#15800) 2026-04-17 22:11:05 +10:00
Clyde Stubbs 1a529a62aa [mipi_spi] Drawing fixes for native display (#15802) 2026-04-17 21:17:16 +10:00
Edvard FilistovičandJonathan Swoboda 6a46437a5f [wifi] Guard retry_phase_to_log_string with log level check to fix warning (#15801)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-04-17 10:58:39 +00:00
Diorcet Yann cfe8c0eeee [wireguard] Bump esp_wireguard to 0.4.5 for ESP-IDF v6 (#15804) 2026-04-17 06:20:55 -04:00
J. Nick Koston 71636ba8a1 [core] coerce set_interval(0) to 1ms to prevent scheduler spin
Users (notably PollingComponents with update_interval: 0ms) have
historically relied on set_interval(0) as a pseudo-loop() mechanism. A
literal interval=0 causes Scheduler::call() to spin — the item is
always 'due now' after re-scheduling, so the scheduler loop never
returns, starves the main loop, and triggers a WDT reset in the field.

Coerce interval=0 to 1ms at creation so existing code keeps working at
~1kHz instead of spinning, while still emitting the warning pointing
authors at HighFrequencyLoopRequester (the intended mechanism for
running fast in the main loop). Zero-delay timeouts (defer/set_timeout)
remain legitimate one-shots and are unaffected — defer is a one-shot,
not a spin risk.
2026-04-16 17:34:05 -10:00
J. Nick Koston a0ac226e6c [core] decouple main loop cadence from scheduler wake timing
Restructures Application::loop() into two independent phases to stop the
scheduler from silently pulling the component loop cadence forward.

Before: Application::loop() bounded its sleep by
  min(loop_interval_ - elapsed, next_schedule_in())
with a delay_time/2 floor. Any scheduler item due sooner than
loop_interval_/2 dragged the whole component phase with it. On a typical
ESP32 config with default loop_interval_=16ms, combined scheduler
activity from api / esp32_ble / esp32_ble_tracker / debug was keeping
every component's loop() running at ~128 Hz instead of the documented
~62 Hz.

This has become more visible recently as more components convert to
PollingComponent (which uses set_interval internally) and more in-tree
code uses set_interval / set_timeout directly. Adding or removing any
scheduled item silently changed every other component's loop cadence.
App.set_loop_interval() for power savings was also silently defeated.

After:
- Phase A (every tick): drain wake notifications, run scheduler.call(),
  feed WDT
- Phase B (gated by loop_interval_ or HighFrequencyLoopRequester):
  iterate registered components and update last_loop_

Sleep = min(time-until-next-component-phase, next_schedule_in()). When
a scheduler event wakes us early, Phase A services it and the component
phase stays gated independently. loop_interval_ is now a true minimum
interval between component phases.

The delay_time/2 floor is removed. Any legitimate need to wake faster
than loop_interval_ has proper mechanisms:
- HighFrequencyLoopRequester for sustained fast-loop needs
- Application::wake_loop_threadsafe() from any context (new in 2026.4.0)
  for one-shot wake-on-event

Also guards against set_interval(0) misuse — it asks the main loop to
spin forever, which was never the intended API. Warns at creation time
pointing authors at HighFrequencyLoopRequester. set_timeout(0)/defer()
is unaffected; zero-delay one-shots remain legitimate.

Runtime stats: process_pending_stats is now called on every tick (not
just when the component phase runs) so log_interval_ isn't quantized to
the component-phase cadence. Added an inline fast-path gate in
runtime_stats.h that early-outs unless now >= next_log_time_, keeping
Application::loop() slim; the log_stats_ work stays out-of-line.

Ordering constraints preserved:
- defer() callbacks still FIFO before components same-tick (Phase A
  runs before Phase B)
- Scheduled items still execute before components when both due
- Scheduled callbacks still run on main thread only
- loop_component_start_time_ is still set fresh at each component's loop
- WDT is still fed at least once per tick
2026-04-16 14:27:39 -10:00
J. Nick Koston b232fc91ab [runtime_stats] Track main loop active time and report overhead (#15743) 2026-04-16 14:07:26 -10:00
Yves Fischer ac50f33388 Fix typo in devcontainer.json (#15791) 2026-04-16 18:27:50 -04:00
Jonathan Swoboda ff52bb3029 [lvgl] Guard lv_image_set_src wrapper with LV_USE_IMAGE (#15789) 2026-04-16 18:16:58 -04:00
J. Nick Koston 627e440bd6 [libretiny] Make IRAM_ATTR functional on RTL87xx and LN882H (#15766) 2026-04-16 19:38:49 +00:00
Jonathan Swoboda 6bb90a1268 [esp32] Accept unquoted minimum_chip_revision values (#15785) 2026-04-16 19:07:04 +00:00
J. Nick Koston 7d8add70a7 [ili9xxx] Guard against null buffer in display_() when allocation fails (#15786) 2026-04-16 09:01:55 -10:00
9094392870 [gpio] Keep interrupts enabled for gpio binary_sensor shared with deep_sleep wakeup pin (#15020)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-04-16 09:01:32 -10:00
J. Nick Koston c6ad23fbc0 [bundle] Force-resolve nested IncludeFile during file discovery (#15762) 2026-04-16 08:45:33 -10:00
Jonathan Swoboda 6af7a9ed8f [qmc5883l] Move per-update log line from DEBUG to VERBOSE (#15781) 2026-04-16 14:36:06 -04:00
0b051289f5 [core] Add missing exception chaining (raise from) across codebase (#15648)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-04-16 15:19:33 +00:00
Clyde Stubbs d8329dba22 [mipi_spi] Add Waveshare C6 LCD 1.47 (#15776) 2026-04-16 11:17:51 -04:00
guillempagesandJ. Nick Koston ee70a4aa72 [tm1637] Add set_brightness method (#15322)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-04-16 09:46:27 -04:00
04a58159d0 [zephyr_ble_server] add support for on_numeric_comparison_request (#14400)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-04-16 09:43:03 -04:00
J. Nick Koston 4c758fa1da [time] Fix RTC is_valid() rejecting valid times after day_of_year cleanup (#15763) 2026-04-16 09:40:22 -04:00
J. Nick Koston c8e21802db [core] Diagnose missing cg.templatable in codegen for TEMPLATABLE_VALUE fields (#15758) 2026-04-16 09:36:55 -04:00
Boris Krivonog b40ffacb8d [mitsubishi_cn105] use HEAT_COOL mode to enable temperature slider (#15748) 2026-04-16 09:35:24 -04:00
Clyde Stubbs e0118dd8eb [lvgl] Clean the build if lv_conf.h changes (#15777) 2026-04-16 09:19:42 -04:00
J. Nick Koston 0300163162 Merge remote-tracking branch 'upstream/libretiny-iram-attr' into integration 2026-04-15 19:46:32 -10:00
J. Nick Koston fd42f43da0 Merge remote-tracking branch 'upstream/dev' into integration 2026-04-15 19:46:17 -10:00
J. Nick Koston e7194dce75 [core] Deduplicate entity type boilerplate with X-macro pattern (#15618) 2026-04-15 17:45:01 -10:00
J. Nick Koston 01b5bef37f [status_led] Disable loop when idle (#15642) 2026-04-15 17:44:42 -10:00
J. Nick Koston 849463b8a5 libretiny: treat already-patched .ld as success on incremental rebuilds
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.
2026-04-15 16:47:44 -10:00
J. Nick Koston 21c32966ee libretiny: fix hal.h intro comment — only LN882H uses the patcher 2026-04-15 16:11:50 -10:00
J. Nick Koston f296a86675 libretiny: drop unnecessary CC-derived nm fallback 2026-04-15 16:10:29 -10:00
J. Nick Koston 1aeb04b4dc libretiny: log nm failure reason instead of silently swallowing 2026-04-15 16:09:55 -10:00
J. Nick Koston 384f8f6870 libretiny: derive nm from CC path when $NM is unset 2026-04-15 16:08:58 -10:00
J. Nick Koston 1cc0ae5443 libretiny: skip patch_linker.py entirely on BK72xx
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.
2026-04-15 16:07:43 -10:00
J. Nick Koston f961f9bfb3 libretiny: fix post-link summary for RTL8710B + LN882H
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.
2026-04-15 16:06:48 -10:00
J. Nick Koston 9fc54d30e5 libretiny: use native section names for RTL8710B; patcher now LN882H-only
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.
2026-04-15 16:05:12 -10:00
J. Nick Koston 853782b251 libretiny: exclude veneer symbols from post-link IRAM fallback
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.
2026-04-15 15:59:26 -10:00
J. Nick Koston 35cafd52a5 libretiny: inline _collect_iram_symbols into _post_link 2026-04-15 15:54:02 -10:00
J. Nick Koston 3b0ac8ebed libretiny: simplify _pre_link, inline _patch_build_dir 2026-04-15 15:50:34 -10:00
J. Nick Koston 22781aff74 libretiny: reference _PATCHERS_BY_VARIANT instead of individual regex names in error 2026-04-15 15:47:45 -10:00
J. Nick Koston f9c4ed65ff libretiny: fix ESP8266 in_isr_context; use demangled names for fallback
- 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.
2026-04-15 15:47:06 -10:00
J. Nick Koston 663c1784b7 libretiny: use walrus operator for variant/patchers assignment 2026-04-15 15:44:29 -10:00
J. Nick Koston 65f10feee4 libretiny: fix stale .image2.ram.text comments; rename dir -> script_dir; link regex from error
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.
2026-04-15 15:36:13 -10:00
J. Nick Koston eae6e6d32b libretiny: fix RTL8710B linker regex — output is .ram_image2.text not .image2.ram.text
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.
2026-04-15 15:28:46 -10:00
J. Nick Koston f0944a944a libretiny: clean up stale comments and tighten patch_linker script
- 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.
2026-04-15 15:26:36 -10:00
J. Nick Koston 8a7de40f40 libretiny: KNOWN_VARIANTS -> frozenset for O(1) membership 2026-04-15 15:22:12 -10:00
J. Nick Koston 05df654a3e libretiny: drop BK72xx from IRAM_ATTR coverage
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.
2026-04-15 15:17:41 -10:00
J. Nick Koston bc672d358b libretiny: scope BK72xx IRAM_ATTR to BK7231N; T/Q/7251 stay no-op
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.
2026-04-15 14:34:16 -10:00
J. Nick Koston 85d1ab7303 libretiny: grow BK72xx .itcm region from 4.5 kB to 8.5 kB
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.
2026-04-15 14:24:57 -10:00
J. Nick Koston 365ff86bac libretiny: target BK72xx .itcm.code instead of .data for IRAM_ATTR
cb3s flashed firmware crashed after logger init. Main SRAM on ARM968E-S
is not instruction-fetchable: the stock linker marks it (rw!x) because
the bus does not allow instruction fetches from that region, so putting
IRAM_ATTR code in .data landed the bytes in RAM but triggered a prefetch
abort when the first IRAM function was called.

The ARM968 design has a separate tightly-coupled instruction memory
("itcm", 4.5 kB, rwx) where the SDK already routes its own ISR, flash,
and FreeRTOS critical-path code via the .itcm.code output section.
Inject KEEP(*(.sram.text*)) into .itcm.code so our IRAM_ATTR functions
share that executable RAM region. No (rw!x) flip is needed since we no
longer touch the main SRAM layout.
2026-04-15 14:18:39 -10:00
J. Nick Koston a1970737c6 libretiny: dedupe per-variant patchers into a shared injector and dict lookup 2026-04-15 14:10:39 -10:00