Commit Graph
3 Commits
Author SHA1 Message Date
Kaj SchittecatandClaude Opus 5 5fc4608c37 touch: contacts cursor across a list rebuild (#467), idle-saver blocker breakdown (#465)
#467 (Buko84): leaving a page stashes the focused row so the cursor can go back
where it was, and it stashed it as a raw pointer. Reading a channel's unread
messages clears its badge, which rebuilds every thread row -- so on the way out
that pointer is either dead or, worse, recycled by the allocator onto a
DIFFERENT row, which is how the cursor lands on an unrelated channel. With no
unread messages nothing rebuilds and it works, which is exactly the split he
identified.

Identify the row by the slot it occupied instead. A list rebuilt in place keeps
its order, so the slot is reliable where the address is not; the pointer is only
consulted when the number of targets actually changed. The restore also scrolls
that row back into view now: the rest of the rebuild deliberately runs with
focus-scroll suppressed, which is right for the transient focus during
recollect, but it left the restored cursor off-screen whenever the rebuild had
also reset the list's scroll position.

#465 (jrote1): his follow-up screenshot shows the gate passing (178406 cycles,
last wake timer) but only 15% asleep. 178406 parks at the 50 ms throttle is
~2.5 h, which against 15% puts uptime near 16.5 h -- so every park runs its full
length and the parks are not the problem. The device simply was not ELIGIBLE
for the other 85%, and nothing reported which of the six gate conditions was
holding it shut.

So charge the wall time between checks to whichever condition was blocking at
that moment, and surface the biggest one ("held by mesh busy 62%") on the
Battery page and the live Lock-settings diag. gatePasses() becomes gateBlocker()
returning the condition rather than a bool. Gaps over 5 s are dropped rather
than blamed on a condition, and the clock is stamped AFTER a park so a completed
park is never mis-attributed to the next blocker.

Also: device_caps.h computed CAP_SOUND from HAS_UI_SOUND, which UITask.cpp does
not define until ~1400 lines AFTER that header is included -- so CAP_SOUND was 0
on every board. Nothing consumed it, so it was silent rather than broken, but
any future `#if CAP_SOUND` would have compiled notification sound out
everywhere. The board list moves into device_caps.h (every macro involved is a
-D on the command line, so all of them are genuinely visible there) and
HAS_UI_SOUND now derives from CAP_SOUND. Verified per board: on for T-Deck,
V4-TFT, V4-R8, M9, Pager and P4; off for RAK Tap, Wio L2 and Attaky, which is
the pre-existing behaviour, unchanged.

Reported-by: Buko84, jrote1
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 20:28:34 +02:00
mikecarper 04d5f33575 Retry messages until an echo is heard 2026-08-01 17:13:03 -07:00
Dan Vybiral 11b31e1cdd touch: idle power-save — loop-throttle + downclock when parked (#19)
Opt-in Idle power-save for the T-Deck: when parked (screen off, on battery, no
companion client, Wi-Fi+BLE off, mesh idle) the main loop is throttled with
vTaskDelay so the FreeRTOS idle task can halt the CPU between ticks, on top of the
existing 80 MHz screen-off downclock — without ever stopping mesh RX. Default OFF
(Settings -> Lock, persisted TouchCfg v8 sleep_idle); status-bar moon indicator +
idle stats. Heltec V4 compiles (gate never passes there). A plain scheduler throttle
rather than esp_light_sleep_start(), which trips INT_WDT in this build.

Co-authored-by: Dan Vybiral <dan.vybiral@greencode.cz>
2026-06-21 22:39:59 +02:00