1411 Commits
Author SHA1 Message Date
Kaj SchittecatandClaude Opus 5.5 b85eef6fec touch: beta_95, MeshCore 1.18 via meshcomod v1.18.0.1
About (Build) and the boot log name the meshcomod release the core is:
"on meshcomod v1.18.0.1". release.sh reads it from the pinned core's own
examples/companion_radio/MyMesh.h, keeps the in-tree defaults in step and checks
every staged image carries it. Language store v26 (this build's new texts),
release notes for beta_95.

Bench (T-Deck, 1.18): device and self info, 404-contact sync, the companion CLI
(ver, board, get name/radio/tx/freq, unknown command), 4 packets received and a
zero-hop advert sent in 90 s, correct device time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
beta_95
2026-10-15 18:07:34 +02:00
Kaj SchittecatandClaude Opus 5.5 ef0b27f1e0 core: MeshCore 1.18 (core-v1.18.0 = meshcomod 8aba438f), V4 language table deflated
Pins move from core-v1.17.4 to core-v1.18.0, cut from the main meshcomod
companion-v1.18.0.1 was released from. The companion changes are ported from
meshcomod's rebase into wadamesh's own MyMesh:

- onCLICommandRecv: a contact's remote CLI command runs when the user granted
  that contact remote CLI, and lands in the chat as a CLI message otherwise.
- CMD_RUN_CLI_COMMAND (66) / RESP_CODE_CLI_REPLY (29) and the local companion CLI
  (name, pin, Wi-Fi, radio, af/dutycycle, rxgain, tx, rxdelay, path.hash.mode,
  multi.acks, board, ver), also reachable from the serial CLI. Settings without a
  prefs field answer "unsupported". NodePrefs layout unchanged.
- TXT_TYPE_CLI_COMMAND is accepted for sending; sendCommandData (and our queue-
  preserving wrapper) carry the text type.
- Channel data is delivered to the app (onChannelDataRecv), unsolicited responses
  (pushed telemetry) reach it as PUSH_CODE_BINARY_RESPONSE, and raw-data sends
  decode multi-byte-hash paths.

Clock: 1.18 seeds an unsynced ESP32 clock at 1 Mar 2026, so ClockFloorRTC's
MIN_VALID_EPOCH follows it (a set equal to the seed must stay invalid).
Pager LR1121: the AGC reset re-applies the boosted-gain setting (new core arg).
IDF builds exclude the new CommonRadioPrefs.cpp (needs <target.h>/radio_driver).

The 2 MB Heltec V4 went to 100.0% with the CLI. Its built-in language table is now
one raw-deflated blob per language (895 KB -> 312 KB), inflated into PSRAM by the
S3 ROM on first use (~10 ms, ~75 KB for the active language): 91.7% flash. Checked
on a T-Deck forced onto the table (nl, hu, el) and by the post-link key check.

Builds: all 15 S3 touch envs, Tanmatsu (3,237,024 B), T-Display P4 SX1262 + LR2021.
T-Deck boots and runs on 1.18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 17:50:32 +02:00
Kaj SchittecatandClaude Opus 5.5 d3a9cf1453 touch: radio tools redesign, Music app, Store update badge, triage fixes
Spectrum: stat tiles (peak, floor, our channel, busy), plot and waterfall drawn
at screen size (the lv_chart and zoomed waterfall were the page's render cost),
dark-to-yellow waterfall, peak hold, our-channel marker, Band/Channel and
Live/1 min/10 min chips. RF Monitor 1.4 (tiles, filled chart, typed feed, packet
detail card; the old type table did not match MeshCore payload types) and
Airtime 1.6 (big figure, tiles, duty line, rx/tx split).

Lua SDK: ui.panel, bold labels and a size-24 figure font, colors.warn/border,
app.on_audio (fires with the screen off), read-only wada.sd.list and sd: audio on
the SD_MMC boards (P4, Tanmatsu, Wio L2), caps panel/audio_events/epaper, a
"music" icon and an "audio" Store requirement. button:set() no longer writes
label fields into the button object (heap corruption, every earlier firmware).
The SDK page's input table described events the firmware never sent.

Music 1.0 (Store app): plays MP3/WAV from the card's Music folder, shuffle,
repeat, keeps going through the list with the screen off. Verified on the
T-Display P4 end to end.

Store: the update check also fetches the app catalog and badges the Store tile
with the number of installed apps that have a newer version. Baked Lua apps are
raw-deflated and inflated by the S3 ROM (14.6 KB back on the V4); the V4 language
table keeps only texts of apps it can run.

Fixes: the SD-card notice no longer fires when the card mounts fine (#667); the
Control Center clock keeps time while open (#666); M9 keyboard brightness (#664);
the battery widget's number no longer sits on a ring too small for it (Discord);
M9 shortcuts doc follows #669's composer order. New texts in all 14 languages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 17:07:11 +02:00
Kaj Schittecat 3b0af92044 Merge pull request #665 from Ender436: T-Deck Max audio (chimes, custom sounds and Lua audio through the ES8311) 2026-10-15 15:28:35 +02:00
Kaj Schittecat 833fac8943 Merge pull request #669 from oumike: the composer puts the text box next to Quick Reply, Emoji (and the M9's #) beside Send 2026-10-15 15:17:45 +02:00
Michael A. CojocariandClaude Opus 5.5 d3202fe7fe feat(touch): the composer puts the text box next to Quick Reply, with Emoji (and the M9's #) beside Send
Non-touch M9: Quick Reply | text | Emoji | # | Send. Touch boards: Quick
Reply | text | Emoji | Send. Emoji and # align off Send's slot so they
follow the text box's new width on a rotation; the P4's landscape row
matches. The M9's arrow keys walk the new order: RIGHT from the end of
the text goes to Emoji, then #, then Send; LEFT walks back # → Emoji →
text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Us6CjkLFga9GkFJmmr3rrq
2026-10-15 09:06:21 -04:00
Ender436 3166e4a654 t-deck max audio fix
Notification chimes, custom WAV notification sounds and Lua wada.audio
playback through the ES8311 codec + NS4150B amp, mirroring LilyGo's
examples/ES8311/playWAV bring-up. I2S DOUT is GPIO40, not the header
name's 17 (measured in GlomarGadaffi/tdeck-max-phone#34); the XL9555
amp enable (line 6) is bracketed around playback and the shared-speaker
mux (line 10) held to the ES8311. Reuses the pager's Es8311Codec driver
and enables CAP_SOUND/CAP_SOUND_FILES/CAP_AUDIO_STREAM for the Max.

Signed-off-by: Ender436 <68835715+Ender436@users.noreply.github.com>
2026-10-14 11:37:08 -06:00
Kaj SchittecatandClaude Opus 5.5 75ec6759dd test: the M9 keyboard test follows #628's one-read-per-poll driver and checks its 70 ms repeat filter
#662's test queued three keys and read them all after one poll; #628 (for #625,
keys typing twice) reads one key per poll and drops the same key again within
70 ms. The test now polls per key and also checks that a repeat inside 70 ms is
dropped and one after it is a new press. Host tests: 18 pass, 2 skips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
beta_94
2026-10-14 10:34:12 +02:00
Kaj SchittecatandClaude Opus 5.5 179577ef10 beta_94 notes: CrowPanel 5.0, hashtag links, #628's fixes, the Radio widget line
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:33:33 +02:00
Kaj SchittecatandClaude Opus 5.5 0692775ba5 Merge follow-ups: the confirm X stays on touch boards (#628), link bubbles skip a full-screen layout (#580)
#628 dropped the close X from actions-only confirms on every CAP_KEYPAD_NAV board,
which includes the V4, the T-Deck and the touch-only boards that take a Bluetooth
keyboard. Now only a board without touch drops it; touch boards keep main's X,
skipped by keypad focus.

#580's chatCreateLinkLabel called lv_obj_update_layout on the message label to read
its height, laying out the whole screen for every link bubble as it scrolled in.
The caller already measured the wrapped text; it passes that height in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:17:57 +02:00
Kaj Schittecat 507511fab6 Merge PR #628 (oumike): Touch UI follow-ups 5a: quick fixes (#603, #605, #614, #617, #620, #625, #627, M9, Tanmatsu, Wio)
# Conflicts:
#	src/ui-touch/UITask.cpp
2026-10-14 10:17:19 +02:00
Kaj Schittecat ea4913f117 Merge PR #580 (TerryTel93): feat: add support for hashtag channels links with prefill and open fu… 2026-10-14 10:16:49 +02:00
Kaj Schittecat 806ecb0f71 Merge PR #655 (oumike): Add the Elecrow CrowPanel Advance 5.0 (#651) 2026-10-14 10:16:48 +02:00
Kaj SchittecatandClaude Opus 5.5 9f633d9d6d touch(home): no bottom bar on the Radio widget; a widget's bar never sits on its text
The Radio widget drew its airtime as a 5 px bar pinned to the bottom edge, which
on the usual widget height landed on the detail line (SF / BW) and looked like a
stray purple line through the text. Gone from Radio; and hwCardBuild now leaves
the bar out wherever it would not fit under the text (the Lua app widget's bar).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:15:55 +02:00
Michael A. CojocariandCopilot 31747c5477 Chat composer: name the text box's chrome height once
chatComposerChromeH() is the row padding plus the top row, used for the
text box height, the auto-grow and the one-line radius. A board-specific
inset (the P4's bottom lift in #611) then changes one helper instead of
four expressions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 09:37:44 -04:00
Michael A. CojocariandCopilot 3b58f58433 Review fixes for #628
- M9 shortcuts guide: the function row is Back, Ctrl and Triangle (no Mic).
- The X-last action lists, the bubble-only chat cursor and the lifted
  message-menu X are keypad behaviour, so they follow CAP_KEYPAD_NAV
  (Pager, Tanmatsu, T-Deck, ...) rather than HAS_THINKNODE_M9.
- Actions-only confirms (#603) drop the X on keypad boards only; touch-only
  boards keep it.
- M9 map buttons: focus keeps the accent fill but no local outline, so the
  shared keypad cursor is not outranked.
- M9 chat header: compare the bar's style height, not its stale coords.
- Contacts bulk delete ends with onThreadsChanged() so web clients refetch.
- The contacts selection buffer (~12 KB at MAX_CONTACTS) is allocated when
  select mode opens and freed when it closes, not at boot.
- Boot time sync: disconnect before the saved-network scan, so a first
  attempt still mid-handshake cannot fail it with ESP_ERR_WIFI_STATE.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 09:31:48 -04:00
Michael A. CojocariandClaude Opus 5.5 a5996faa41 M9: the chat header's clock, battery and GPS centre vertically
They sat on the title's line. They now centre on the header's two lines,
level with the back arrow and the avatar, so the whole header is centred
vertically. The step in from the rounded corner stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yt7fNCKmafm9LtRjyuUmS
2026-10-13 09:31:48 -04:00
Michael A. CojocariandClaude Opus 5.5 32c01f0682 M9: one key press enters one character (#625)
The keyboard controller latches a single key. When one was pending,
m9KeyboardPoll read the register up to three times back to back, a
"drain" meant to catch a second key, but with one slot a second read
can only return nothing or the same key again if the controller has not
cleared it yet. Keys came out twice, often and on any key.

- One read per poll, as the Launcher and Meshtastic M9 ports do.
- The same key reported again within 70 ms of the last accepted one is
  dropped as the same press. That covers a stale latch read on the next
  poll and the matrix bouncing on a slow, deliberate press, which the
  report found worse. Nobody presses one key twice that fast on purpose.
  The guard runs from the last accepted key, so bounces cannot stretch it.

Fixes #625

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yt7fNCKmafm9LtRjyuUmS
2026-10-13 09:31:48 -04:00
Michael A. CojocariandClaude Opus 5.5 7f025ffbf5 M9: the conversation header fits its text and lines up (#627)
The M9's UI sizes grow the fonts but not the geometry, so the header's
title and subtitle, centred in a bar of fixed height, clipped the
subtitle ("3 nodes heard today"). The back arrow and avatar sat low, the
clock and battery sat mid-bar while the GPS glyph kept the top row, and
the message list started several px below the header, leaving a strip of
bare background.

- m9ChatHeadH() gives the header's height from its fonts: the two lines
  from 3 px down, 2 px under them. The bar takes that height in a
  conversation, and makeChatDetail starts the list's content at the same
  line. The list is virtualised and places its rows against that padding
  once, so it is set when the list is built.
- The back arrow and avatar centre on the two lines.
- The clock, battery and GPS glyph share the title's line, with the GPS
  just left of the clock. The group steps in from the panel's rounded
  corner, which clipped the battery, and the title stays short of it.
- Leaving the conversation puts the bar's height, the battery and the
  GPS glyph back.

Other boards are unchanged.

Fixes #627

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yt7fNCKmafm9LtRjyuUmS
2026-10-13 09:31:38 -04:00
Michael A. CojocariandClaude Opus 5.5 14589f2c6e Status bar: the smoked-glass shade is not shifted with the icons
In a tall bar, updateGlobalStatusBar shifts each child of the bar up half
a row to put the system icons on the top row. It skipped the full-bar
backdrops (fade, dim) but not the shade drawn over a background picture,
so the shade sat half a row too high. The bottom of the bar showed the
picture unshaded, a strip over the top of the content below it. Measured
on the M9's conversation header: bar y0-38, shade y-11-27.

The shade is skipped like the other backdrops. All boards with a
background picture and a tall bar (conversations, settings pages).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yt7fNCKmafm9LtRjyuUmS
2026-10-13 09:31:38 -04:00
Michael A. CojocariandCopilot b247fa3ace Wio Tracker L2: Clock settings and the cold-boot time sync
The Wio Tracker L2 has no battery-backed clock, so it gets the same
opt-in saved-Wi-Fi time sync at power-on as the T-Deck
(CAP_BOOT_TIME_SYNC / BootTimeSync).

Split out of 4844a9b (Touch UI follow-ups 4).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 09:31:38 -04:00
Michael A. CojocariandCopilot 9d7da2354d M9 chat: # and emoji move left of the message input
The composer reads QR | # | emoji | text | Send. With the caret at the
start of the input, LEFT walks to emoji, then #; RIGHT walks back.

Split out of 4844a9b (Touch UI follow-ups 4).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 09:31:38 -04:00
Michael A. CojocariandClaude Opus 5.5 10e0f84b35 Channel region scope on phone-app channel sends too (#614)
CMD_SEND_CHANNEL_TXT_MSG called sendGroupMessage directly, so a post from
the phone app on a scoped channel went out on the default scope. It now
pushes the channel's scope for the send and pops it afterwards, as the
on-device composer, web remote, terminal and Lua sends do. Touch builds
only, where per-channel scopes are stored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yt7fNCKmafm9LtRjyuUmS
2026-10-13 09:31:38 -04:00
Michael A. CojocariandClaude Opus 5.5 94a7c13ef5 M9: name the 0x88 key by its triangle; it no longer opens chat options
The key is printed with a triangle, not a microphone, so the docs and the
code now call it the triangle key (M9_KEY_TRIANGLE). In an open chat it
used to open the thread's options; keypad navigation reaches the
conversation header for that now (#623), so the key keeps only its other
job, the focused item's hold action. M9_PORT.md no longer calls it
unbound.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yt7fNCKmafm9LtRjyuUmS
2026-10-13 09:31:38 -04:00
Michael A. Cojocari b63b4f3904 M9 and Tanmatsu feedback from #609
- M9: double-press Home opens the launcher settings (what Home opens, icon size)
- M9: "Mark all as read" is the first item in the chats menu
- M9: MIC key opens the chat options in a chat, else the focused item's hold action
- M9: stronger focus on the map overlay buttons
- M9: the at-a-glance card shows even when the message-flash wake lit the screen first
- Tanmatsu: screensaver preview ignores input for its first 1.2 s so it no longer ends at once

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
(cherry picked from commit f479382c9b12070cffae530e3b4789d689c441c5)
2026-10-13 09:31:38 -04:00
Michael A. Cojocari 1700366f3f M9: white tab bar while the map loads, double-press Home for Settings, bubble-only chat cursor
- Map: the transparent tab bar shows white icons from opening the Map tab until
  its first tile render finishes, then returns to its map colours.
- Home: a second press within 450 ms opens Settings. The keyboard controller
  sends no key-up or long-press code for Home, so a hold can't be detected.
- Chat: the keypad cursor surrounds the message bubble only, not the info
  line under it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
(cherry picked from commit 9523475232aa1a73e2c7c3395888407dfd4020c8)
2026-10-13 09:31:38 -04:00
Michael A. Cojocari 7f4d3fd0b6 M9: action menus focus first row (X last); lift message-menu X clear of buttons
The ⋯ / thread action list creates its close X after the rows on the M9, so
keypad focus opens on the first action and reaches the X last. The message
action menu's X moves up into the card padding so the first button row no
longer clips its focus cursor. Other boards unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
(cherry picked from commit 8fdb23ce5f5dbf58514304ab3be7a5dd04c4cdd8)
2026-10-13 09:31:37 -04:00
Michael A. Cojocari 2964ff02e3 fix(time): cold-boot Wi-Fi time sync gets past a slow first join (#620)
The first attempt on the active network brings the radio up from cold and
searches every channel for the AP, inside the same 4 s as every other
attempt. A T-Deck that joins in about 7 s by hand never made it, and the
scan retry then skipped that network as already tried, so a home with one
saved network always ended "no association".

The first attempt now gets 8 s. The scan retry keeps the active network
and joins each candidate on the channel and BSSID the scan found it on,
which skips the all-channel search. The whole session is capped at 16 s
(was 12 s) so the retry and SNTP still fit.

Fixes #620

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yt7fNCKmafm9LtRjyuUmS
(cherry picked from commit 477e0163ccf64d65706737a9558f1ef9ab439539)
2026-10-13 09:31:37 -04:00
Michael A. Cojocari 9bbe0a468b Chat: compact rows fit emoji; composer keeps the newest message in view and its text inside the box (#617)
- Compact rows that carry a colour emoji get its overhang above the text
  line as extra top padding, measured into the row height so the
  virtualizer agrees (chatCompactEmojiLift).
- When the composer grows while the list is at the bottom, the list is
  scrolled back to the newest message instead of being covered.
- The composer's corner radius stays at its one-line size, so a four-line
  box no longer curves through the start and end of its lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkSqsocfpbhCD2AtpskvQo
(cherry picked from commit 867db9917e682ac24f2542ecd77224fcf27f232a)
2026-10-13 09:31:37 -04:00
Michael A. Cojocari 2463bc238b Channel region scope on web remote, terminal and Lua sends (#614)
The chat composer tagged a channel post with the channel's own region scope,
but termDoSend (web remote and terminal) and luaHostMeshSendChannel called
sendGroupMessage directly, so those posts went out on the default scope.
All three now go through sendGroupMessageScoped, which pushes the channel's
scope for the send and pops it afterwards.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
(cherry picked from commit fa1ec9868fdee31922ee57a5ed0a940522bb86c1)
2026-10-13 09:31:37 -04:00
Michael A. Cojocari ae473ee86d Contacts: A-Z sorts by name only; Select all covers every contact (#605)
- Name (A-Z) no longer sinks "?" (never heard) contacts below the heard
  ones; that rule now applies to the Last heard / Last message modes
  only. Favourites with and without a last-heard sort together by name.
- Select all selected at most 128 contacts, in storage order, while the
  list shows the first 128 in sorted order. Past 128 contacts it picked
  mostly rows that were not on screen, so nothing visible was ticked and
  a delete seemed to do nothing. The selection is now sized to
  MAX_CONTACTS and Select all takes every non-favourite that passes the
  filter.
- Bulk delete removes without saving (uiRemoveContactNoSave) and writes
  /contacts3 once at the end, keeps only the public keys for the run,
  and matches the selection by binary search.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkSqsocfpbhCD2AtpskvQo
(cherry picked from commit f30ca794039ff11358903938d70e402019908776)
2026-10-13 09:31:37 -04:00
Michael A. Cojocari 477b7d5981 fix(touch): backup Import dialog opens on Import, loops Import/Cancel, no X (#603)
On the T-LoRa Pager the "Import this backup?" confirm started on the
close X, then stopped on the message text before reaching the buttons:
keypad navigation follows the card's tree order (X, message, Cancel,
Import), and confirmBackupImport() used none of showConfirm()'s options
for that.

- confirmBackupImport() now passes actions_only_nav (the message box is
  not a focus stop) and focus_confirm (focus opens on Import). With two
  stops, the group's wrap loops Import <-> Cancel in both directions.
- showConfirm() no longer creates the X at all for actions_only_nav
  dialogs, rather than only skipping it in navigation. Cancel and the
  Back key already dismiss them. The Purge-discovered dialog uses the
  same flag and loses its X too, which keeps the two consistent.

Fixes #603

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zE15egJdCZ9nRBZmg1YUq
(cherry picked from commit 1df7b93ef91d5ca3790271e3d216409988cabf1c)
(cherry picked from commit 29a842b4a2de8bb2ff8a849b14d57955d17b2729)
2026-10-13 09:31:37 -04:00
Michael A. CojocariandCopilot 1826e0f74c DEVICES.md: the CrowPanel 5 recovers from long flash erases (full install, OTA)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 09:09:54 -04:00
Michael A. CojocariandCopilot 320e5cb93b CrowPanel 5: zero chat_back's shift in the chat header; docs say what was tested
chatHeaderApply now resets chat_back's translate_y, which updateGlobalStatusBar
skips in a chat, so a chat opened from a settings or app page no longer keeps
the half-bar upward shift. DEVICES.md and the site describe the hardware
testing, and the site counts 14 boards.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 09:01:59 -04:00
Michael A. Cojocari b0960cdcf1 Merge remote-tracking branch 'upstream/main' into crowpanel-50
# Conflicts:
#	scripts/build/gen-touch-fonts.sh
#	src/ui-touch/ui_font_18.c
#	src/ui-touch/ui_font_20.c
#	src/ui-touch/ui_font_24.c
2026-10-13 08:59:08 -04:00
Terry Carr 9fc158499b fix: conditionally include bubbleUrlTapCb for TDECK_PRO only 2026-10-13 12:02:39 +01:00
Terry Carr 7e539c3373 Merge branch 'ALLFATHER-BV:main' into hash-channels-links 2026-10-13 11:38:23 +01:00
Terry Carr 5ac174b443 fix: refactor chat link choices management to use dynamic allocation 2026-10-13 11:20:21 +01:00
Kaj SchittecatandClaude Opus 5.5 6b6253c242 storage: the SD-fallback notice opens above the app drawer
It was shown from setupWizardMaybeOpen(), before the drawer (the default Home)
was built on the same top layer, so the drawer covered it. It now opens after
the drawer, in place of the crash-report prompt for that boot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:17:30 +02:00
Terry Carr 7d283c6ae7 fix: adjust label long mode and width in chat link picker 2026-10-13 11:11:16 +01:00
Kaj SchittecatandClaude Opus 5.5 88dc3894e4 i18n: regenerate the V4 table for the new strings
The pre-build hook picked up the track, SD and Reader strings (8 translated keys x 14).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:03:56 +02:00
Kaj SchittecatandClaude Opus 5.5 a99a582bd4 i18n + notes: the track, SD and Reader strings; beta_94 notes for the three features
Short strings in all 14 languages; the long SD-fallback and track-stopped texts
as English placeholders until translated. v25 snapshot kept equal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:49:29 +02:00
Kaj SchittecatandClaude Opus 5.5 bec56ba814 reader: page through big text files, open card documents from Files, and a tool to fill a card
Asked for on Discord (prepper use: books and documentation offline on the card).

- The Reader opens a .txt or .md file on the card as a 16 KB window at an
  offset carried in the URL (sd:/x.txt?o=49152), cut back to a line (or a whole
  UTF-8 character), with Next page / Previous page / Back to the start links and
  the position in percent. A book of any size pages through; Back works as usual.
- Files opens HTML on the card in the Reader (its links work there, so a folder of
  pages browses offline) and text or markdown too big for the 8 KB editor; small
  text files keep the editor.
- scripts/sdpack.py (standard library only): an EPUB becomes /library/<name>/ with
  one page per chapter (long chapters split under 30 KB, linked in order) and a
  contents page; .txt/.md are copied as they are; /home.htm lists everything, so
  the Reader, which opens sd:/home.htm, starts on the library. Tested with a
  generated EPUB.
ZIM (Wikipedia) files are not read on the device: their clusters are zstd/xz
blobs of 1-2 MB and the files run to tens of GB on FAT32; converting on a
computer keeps the device side small.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:48:26 +02:00
Kaj SchittecatandClaude Opus 5.5 d0b1f58024 storage: a failed SD card no longer costs the node its key; the boot says what happened
Reported on Discord: a T-Deck that kept its data on a card that died booted
into first-time setup with a NEW private key, and the next good card was then
given the new key, so the old one was gone for good.

- DataStore keeps a copy of the main identity in NVS (namespace mc_id, 96 B):
  every save writes it, a load with no identity file falls back to it and puts
  it back into the active store, and a successful load seeds it when missing. A
  different copy is never replaced silently; only an explicit save changes it.
  Verified on a T-Deck: one boot with the card seeded mc_id.
- When the SD store was chosen but the card did not mount, the boot is flagged
  (g_sd_fallback_boot) and, instead of the setup wizard (whose done-mark is on
  the card too), a dialog says the card could not be read, that the key is kept
  (or, on a device that never had a copy, that it started with a new one while
  the card keeps the old), and offers Try the card again.
The retry ladder at lower SPI clocks already existed. Not yet done: copying the
data off a card that mounts but refuses writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:44:58 +02:00
Kaj SchittecatandClaude Opus 5.5 fd8a163421 touch(map): record a GPS track to a GPX file (Map options > Record track)
Asked for on Discord. A switch in the map options records where you go into
/meshcomod/tracks/<date-time>.gpx on the SD card, a standard GPX 1.1 track that
other mapping software opens, with elevation and time per point.

- Runs from the UI loop beside the GPS saver, so it keeps recording with the
  screen off; the GPS stays awake while it records (gpsWantedLive).
- A point once we have moved 10 m (GPS jitter stays out of the distance), or
  every five minutes after at least 3 m. Climb counts steps of 3 m or more.
- The file is complete after every point: the closing tags are rewritten behind
  each new one (r+ and seek), so a flat battery still leaves a file that opens.
- The map draws this session's track as a red line (one lv_line, thinned to 256
  points) and the status corner shows the distance and climb while recording.
- Three failed writes in a row stop it with a message; no card, no start.
Boards with an SD card and GPS (CAP_SD or the Pager). The app route was ruled out:
Lua apps stop ticking with the screen off and their files cap at 32 KB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:39:24 +02:00
Kaj SchittecatandClaude Opus 5.5 459be25e34 beta_94 notes: this round; MECP gets the bell icon
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:20:12 +02:00
Kaj SchittecatandClaude Opus 5.5 083d422a2d i18n: the V4 bakes the live translations, trimmed to keys the firmware can show
beta_93 pinned the Heltec V4 to the beta_92 .lang files because the full table
no longer fit. lang_reach.py now works out which keys any source can look up:
a .lang key is kept when it equals a C string literal anywhere in the sources
(every #if branch, adjacent literals joined, LV_SYMBOL_*/UI_ICON_* and other
string macros expanded, escapes decoded as GCC does), or that literal with TR()'s
glyph prefix stripped, or a string in any Lua app. 1818 of 1925 keys survive; the
107 dropped look unused (old dropdown strings, texts the source has reworded).

The trimmed live table is 15.5 KB smaller than the pinned one (V4 4,025,365 B
used, 37.9 KB free) and carries every translation added since beta_92.

Guards: the generator refuses to trim when an input is missing (lv_symbol_def.h,
UITask.cpp, or under 80% kept) and leaves the header alone; after linking the V4,
--check-objects reads the strings the compiler emitted and fails the build if a
translated key among them was dropped (proved by dropping a live one). The
pre-build hook regenerates on source changes too, and the header is only
rewritten when its content changes. The pinned copy is gone (git history).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:20:12 +02:00
Kaj SchittecatandClaude Opus 5.5 6ff2cdedd8 i18n: rows for the Bluetooth failure messages
"The Bluetooth chip is not responding." and "Bluetooth could not start.
Restart the device and try again." in all 14 languages, v25 snapshot kept equal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:20:12 +02:00
Kaj SchittecatandClaude Opus 5.5 cd70c91465 p4: Bluetooth starts from the toggles again; failures say what went wrong (#612)
Since beta_88 (b52c71f) the P4 stored its BLE name and PIN only when BLE was on
at boot and the C6 came up for it. A unit that booted with BLE off (or once had
it off, since that is saved) then failed every enable at once, and the UI read
every refusal as "Not enough free memory for Bluetooth", Wi-Fi off or not.

- main.cpp stores the parameters on every boot; storing them does not touch the C6.
- enableBle() brings the C6's BLE controller up on a runtime cold start
  (hostedInitBLE) before NimBLE, or NimBLE would start against no controller.
- The transport records why a cold start did not happen (no parameters, the
  memory guard, the radio) and the toast says so; only the guard is about memory.

Not run on a P4 yet: the P4 build has both strings in it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:20:12 +02:00
Kaj SchittecatandClaude Opus 5.5 821f9b2c5a apps: a Store app can ship its own files
An app's manifest can list files beside its code as one quoted string,
"files":"beep.wav,track.mp3" (the manifest reader takes strings only). The
Store installs each into /apps/<id>.d/, the folder wada.fs and
wada.audio.play("beep.wav") already read, so an app can carry its sounds. On
the T-Display P4, whose Lua SD API is off, that was the only way to get a sound
there (#lua-app-dev). Files stream to storage through a 4 KB internal buffer
(SD writes from PSRAM come back short), the server must send a length, a
short read deletes the partial file and fails the install. Up to 8 files of
4 MB, names as wada.audio's. No app uses it yet, so existing installs are
unchanged. SDK page documents it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:20:12 +02:00