Commit Graph
1697 Commits
Author SHA1 Message Date
JakubandClaude Opus 5.5 2b9e013071 fix(l2): no remount while the card is a USB drive, vector packs locked across cores, time zone list, noise sweep restore
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:30:46 +02:00
JakubandClaude Opus 5.5 57db27512d fix(companion): pack and history files from the card checked, contact loops skip the reserved slots, small UI fixes
- L2 vector packs: a damaged count can't wrap the index size, and an
  entry pointing past the file is refused.
- L2 map share-target list: sized for 40 long channel names and 16
  favourites (it could overflow), off the stack.
- L2 SD history: a file with an unreadable header is set aside as .bad
  instead of written over; Delete message history takes those too.
- Contact lookups by key or hash start after the reserved anon slots (an
  empty one matched a 00 hop hash with a blank name); MessagesScreen uses
  contactctl::hopName().
- Nearby keeps its selection by public key: deleting a contact shifts
  the table.
- ui-new Live Share target cycle holds every channel and favourite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:31:35 +02:00
JakubandClaude Opus 5.5 4eee794a17 fix(companion): hashtag join trims like the app, prefs survive a downgrade, a sender named Me
- Joining #topic drops surrounding spaces and keeps the case, as
  meshcore-open's derivePskFromHashtag() does.
- /prefs written by a newer build (bigger NodePrefs, same version): the
  extra bytes are read through the CRC and skipped instead of resetting
  every setting.
- A channel post from someone named "Me" is filed as "\"Me\": ...", so
  the views don't take it for our own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:14:08 +02:00
JakubandClaude Opus 5.5 01a068be7d refactor(companion): shared shutdown steps, SD channel key by secret, fetch race, small UI fixes
- UITaskBase holds what both UIs' shutdown() and low-battery check share:
  the saves before the goodbye sound, the power-down (GPS through its
  provider) and the battery EMA and threshold.
- L2 SD archive: a channel's file is keyed by its secret only, so renaming
  keeps the history; old files are renamed once at boot.
- L2 fetch: abandoning a request and the task finishing it are one critical
  section (it could stay DONE for good); TileCache gets the read-side barrier.
- Text from a repeater or sensor no longer rings on the device (nothing to
  open); a settings switch reads any non-zero value as on; the message
  toast never cuts a letter in half; ui-new's GPS helpers ask UiCore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:08:31 +02:00
JakubandClaude Opus 5.5 28d8291e33 fix(companion): CLI NaN, APC on TX changes, tz-aware alarm, late ACKs, ping timeout and widths, TX limits
- set af / dutycycle / rxdelay reject nan.
- A TX power change from the app or CLI re-baselines APC.
- CMD_SET_RADIO_PARAMS stores repeat as 0/1.
- The alarm reschedules itself when the time zone changes.
- A late ACK for an earlier DM attempt marks it delivered.
- A new auto-advert interval counts from the last advert.
- Both UIs take the TX power range from radioctl, up to MAX_LORA_TX_POWER
  (30 dBm on the GAT562 30S).
- The ping timeout comes from the airtime; 3-byte path hash mode pings with
  4-byte trace hashes, and trace flags are right for width 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:00:49 +02:00
JakubandClaude Opus 5.5 cd294613ea fix(companion): scopes, room bot backlog, DM flood fallback, atomic trail saves
- Removing a scope moves the channels that used it to the default, not to
  unscoped.
- The room bot ignores posts older than 5 minutes: the backlog a room
  replays after login no longer gets answers.
- Adverts take the default scope from the scope list, as messages do; the
  legacy fields always mirror it, and CMD_SET_DEFAULT_FLOOD_SCOPE with a
  full list answers TABLE_FULL.
- The last DM resend drops the direct path and floods.
- /trail and /waypoints are written through a temp file.
- An admin login timeout keeps the saved password.
- History records read from the SD card are sanitised.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:54:38 +02:00
JakubandClaude Opus 5.5 7ad11b6f02 build(solo): drop the L2 bring-up and Arduino 2.0.17 envs
Neither is published or used any more: the LVGL firmware on Arduino-ESP32
3.x is the only L2 build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:41:39 +02:00
JakubandClaude Opus 5.5 b393732b90 refactor(companion): our MyMesh additions in their own headers
Contacts and rooms, the scope list, discovery and ping, APC and
screenshots move out of MyMesh.cpp to headers included at its bottom,
as MyMeshBot.h and MyMeshCli.h are, so upstream merges meet less of our
code. The feature matrix gains the 4.26" in its layout tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:26:59 +02:00
JakubandClaude Opus 5.5 4e95647c0d refactor(ui-lvgl): widgets, the virtual list, chats, nodes, thread and settings out of UITask.cpp
A pure move: each section now sits in its own header, included where its
code was, so the order of definitions is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:26:59 +02:00
JakubandClaude Opus 5.5 e896e6af60 refactor(ui-new): Home, splash, CardKB and the perf walk out of UITask.cpp
A pure move: each block now sits in its own header, included where its
code was, so the order of definitions is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:26:58 +02:00
Jakub 1b318af15b Merge pull request #46 from pmow/feature/eink-ui-scale
GDEQ0426T82 4.26" panel (#42), bulk SPI writes (#43), Text size and Icon size for big panels

# Conflicts:
#	examples/companion_radio/DataStore.cpp
#	examples/companion_radio/NodePrefs.h
2026-10-11 10:41:29 +02:00
Jakub d749633b04 Merge pull request #44 from pmow/feature/advert-loc-precision
feat(companion): advert position precision (privacy)
2026-10-11 10:41:15 +02:00
JakubandClaude Opus 5.5 beef9edf5a fix(cli): keys pages counted as they are printed
A page break counted a space before every key, printing put none before
the first, so the skipped pages broke one key early and the next page
began with the previous page's last key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:41:05 +02:00
pmowandClaude Opus 5.5 13531dd2ce refactor(eink): Text size and Icon size as schema settings, on opt-in builds only
Review follow-up:

- The rows exist only where the build asks for them: Text size with
  EINK_FONT_SCALE, Icon size with STATUS_ICON_SCALE. The stock 2.13", the
  portrait builds and the L2 don't get them -- their screens are laid out
  for one cell size. The text override also applies in landscape only.
- Stored in NodePrefs (ui_text_scale, ui_icon_scale) instead of a
  /ui_scale file, as rows in the schema's Display section: the usual row,
  save path and factory reset, and console keys display.text.size /
  display.icon.size. The hand-written Settings rows and the load/save code
  are gone; UITask::applyUiScale() applies the prefs at boot and on change
  (applyDisplayPrefs). On opt-in builds ui_text_scale starts at the
  build's EINK_FONT_SCALE (DataStore sanitize), so the row shows the scale
  in use.
- EINK_FONT_SCALE, when set, now scales whichever landscape font the build
  picks (the 6x9, or the EINK_LARGE_FONT one); unset, it is stock as before.
- setUiScale() skips the re-layout and full redraw when nothing changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:36:39 -10:00
pmowandClaude Opus 5.5 a25df3ceec feat(companion): advert position precision (privacy)
Settings > Privacy > Precision: Exact / ~100 m / ~500 m / ~1 km, beside
"Position in adverts", which stays the on/off. With the position shared,
it is snapped to a fixed grid (0.0009 / 0.0045 / 0.009 degrees) rather
than jittered, so repeated adverts from one spot send the same value and
can't be averaged back to the exact fix.

A schema row (NodePrefs::advert_loc_prec), so both UIs show it, factory
reset clears it and the console has it as advert.loc.precision.

Every self-advert -- manual, flood, auto, the phone app's and contact
export -- now goes through MyMesh::createOwnAdvert(), so the precision
applies everywhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:22:16 -10:00
pmow c06b394144 Merge dev into feature/eink-ui-scale 2026-10-10 16:19:17 -10:00
JakubandGitHub 2820c36b1c Merge pull request #45 from pmow/fix/cardkb-during-refresh
fix(ui-new): keep CardKB key presses during an e-ink refresh
2026-10-10 10:20:03 +02:00
JakubandClaude Opus 5.5 c5bb4752d0 feat: per-contact actions, device settings, a companion CLI and your contact's QR code
- Nodes: telemetry permissions per contact, reset path, share nearby
  (L1 options menu; L2 node card with "Can ask for" switches)
- Settings > Privacy: fixed position (typed in, from a waypoint, cleared)
  and the Bluetooth PIN; Settings > System: factory reset, asked twice
- Companion CLI (CMD_RUN_CLI_COMMAND 66 / RESP_CODE_CLI_REPLY 29, as
  upstream; FIRMWARE_VER_CODE 14): upstream's command names plus a key for
  every schema setting (get / set / keys)
- Screenshots move to 0x7E; tools/screenshot.py falls back to 66 / 29
- Your contact as a QR code (meshcore://contact/add): Status > System on
  ui-new, Settings > About on the L2; Nayuki's qrcodegen made header-only

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:59:35 +02:00
JakubandClaude Opus 5.5 6fba3dfca7 feat: app-only settings on the device: privacy, adding contacts, advanced radio
- Settings schema gains Privacy (position in adverts, who can ask for
  status / location / sensors), Adding contacts (all or by type, max
  hops, replace oldest) and Advanced radio (path hash size, double ACK,
  listen before talk, interference threshold, RX boost, RX delay,
  airtime factor); both UIs build their rows from it
- Auto-advert carries position only when Position in adverts is on
- ui-new accordion holds 16 sections and 128 rows
- docs: settings, tools, feature matrix

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:47:03 +02:00
pmowandClaude Opus 5.5 2c1e1fa930 feat(eink): Text size and Icon size settings for big panels
On an 800x480 panel the doubled 6x9 font and the status bar's icons are
tiny. Two opt-in build flags, each also a setting under Settings > Display:

- EINK_FONT_SCALE=<n>: the landscape font's pixel multiplier (stock 2).
  Settings > Display > Text size (1x-5x) overrides it at run time
  (DisplayDriver::setUiScale -> EinkGfxDisplay re-lays out).
- STATUS_ICON_SCALE=<n>: Home's status icons, battery and page-icon row
  drawn at n x their pixel grid, the bar growing to fit. 0 = Auto, 1.5x
  the text's pixel scale. Settings > Display > Icon size (Auto, 1x-8x).

Both live in their own /ui_scale file, so NodePrefs is untouched. Icon size
appears only where STATUS_ICON_SCALE is set; Text size appears on every
e-ink build with the full-refresh setting, and builds that set neither
flag draw as before until it is changed. The GDEQ0426T82 env defaults to
4x text with Auto icons.

Tested in the native sim at 800x480.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxAZVAbhhYr18Dd4guTQM1
2026-10-09 11:57:29 -10:00
pmowandClaude Opus 5.5 06e741b310 fix(ui-new): keep CardKB key presses during an e-ink refresh
While the loop task is inside a display refresh (seconds on a big e-ink
panel) the CardKB isn't polled, and the keyboard's own one-key buffer
drops every press but the last.

A small FreeRTOS task polls the CardKB every 10 ms while a refresh is in
progress, into a 16-entry queue that the loop drains afterwards. A mutex
guards the shared Wire1 bus against querySensors(). The task is created
after the screens so its stack doesn't starve their allocations, and the
loop falls back to the old direct polling if it can't be created.

Tested on hardware: Wio Tracker L1 + CardKB, several quick presses during
an 800x480 refresh all arrive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxAZVAbhhYr18Dd4guTQM1
2026-10-09 08:48:03 -10:00
JakubandClaude Opus 5.5 c9877e0ab1 feat: a QR code of the Solo manual on every screen
ui-new: Status › System, Enter shows it full screen. L2: Settings › About.
One precomputed 25 x 25 matrix (ui-core/SiteQr.h) for both, so no QR
library; the URL in upper case keeps it at version 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:38:29 +02:00
JakubandClaude Opus 5.5 57cf58424d feat: a node map and a calendar on ui-new, a banner switch on the L2
- Nearby › Map (ui-new): the positioned nodes and you on one view, scaled
  to fit, with north, a scale bar and the selected node's name and
  distance; Left / Right picks a node, Up / Down zooms on it, Enter opens it.
- Clock tools › Calendar (ui-new): the month with today and the alarm's
  days; a tight grid on small screens, Left / Right pages the months.
- L2 Settings: a Message banner switch (on / off) in place of ui-new's
  three-way alert setting.
- Simulator: sim_nodes() puts eight positioned contacts around Kraków.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:38:29 +02:00
JakubandClaude Opus 5.5 d901a58424 refactor: one place each for "in view" and the keyboard's backspace
ui-new's messagesInView() and ui-lvgl's threadInView() hold the
lit-and-unlocked test the viewing checks repeated; the keyboard's three
copies of the backspace call deleteBeforeCursor(). A stale comment on the
cursor-mode hint goes, onDisplayOn() sits after the view helpers it calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:58:52 +02:00
JakubandClaude Opus 5.5 9e24abcbeb feat(ui-new): a cursor mode that keeps the keyboard in view
The cursor marks the character it stands before instead of pushing the
text apart: underlined while typing, an inverted block while moving it.
The grid stays on screen with the special row turned into the key hints;
Up/Down move a word, Hold-Enter deletes before the cursor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:41:40 +02:00
JakubandClaude Opus 5.5 e09a90b325 fix: messages that arrive while asleep or locked stay unread
A conversation left open under the lock screen or a dark display no longer
counts as read: the counters and the lock screen's tally go up, and on
waking (L2: on unlocking) the conversation reopens on its first unread
under the "New" line, a typed draft kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:41:40 +02:00
JakubandClaude Opus 5.5 92e379e05c fix(ui-new): one '#' on a hashtag channel's favourite tile and slot list
Hashtag channel names already start with '#'; the tiles added another
("##test"). chanctl::bareName() is now the one place that strips it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:41:40 +02:00
JakubandClaude Opus 5.5 9ef7d5d981 fix: no flash writes while typing, and a clock that survives a power loss
Contacts and paths are saved a while after the change and never while the
user is active, so a send no longer stutters on the 53 KB contact rewrite
(a path that came back unchanged isn't written at all). The clock is saved
every 30 minutes and restored no earlier than the firmware's build day.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:41:32 +02:00
JakubandClaude Opus 5.5 aaf35351d7 feat: open a conversation on its first unread message, under a "New" line
Both UIs: a channel, DM or room with unread messages opens on the oldest of
them (MessageHistory::firstUnreadChannel / firstUnreadDm, own messages not
counted), a "New" line above it, so it reads down to the newest. Nothing
unread: the newest, as before.

L1: the first unread is selected and scrolled up top with the line in view;
the channel's unread count now counts down as you read towards the newest.
L2: the page holding it, scrolled to the line; an incoming message scrolls
down only when the list is already at its end. Sim hooks: sim_unread (L1),
sim_open("unread") (L2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:20:04 +02:00
JakubandClaude Opus 5.5 38925dde65 fix(l2): a dot per DM send, lists that notice every change, the LED lit only on TX
- A pending DM shows a dot per send, as on the L1. The thread is read from
  the SD archive, which a resend never updated: it does now, and the
  thread's signature and patch state count the attempt.
- Nearby redraws when a node goes live, changes type or the units change;
  the scan popup when a name or the remote SNR arrives.
- The user LED is active high: it was lit all the time and went dark
  while transmitting.
- Sim hooks "dm" and "send" for testing a DM thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:32:54 +02:00
JakubandClaude Opus 5.5 8324d0c6d1 feat(ui-new): message alert setting -- banner, corner envelope or none
Display > Message alert: Normal keeps the sliding banner; Compact shows an
envelope with the unread count beside the battery (in the header line where
there's no status row), blinking for 2 s; Off shows nothing. The blink only
ever brings the next frame earlier, so it no longer holds back the UI's
animations while it runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:32:54 +02:00
JakubandClaude Opus 5.5 6c9186dc54 feat: a message's bytes left, counted as it will be sent, on every screen
The limit is what the send leaves of MAX_TEXT_LEN: a channel post carries
"<node name>: ", a direct message resent more than three times keeps two
bytes spare, and placeholders count as they expand (msgtext::limit/sentLen).
Bytes, not characters. The path and packet header sit outside the payload;
static_asserts keep a full message within the radio frame on the longest path.

From 40 bytes left the count shows: on the L2 as a tag on the field's top
edge, on OLED/e-ink at the right of the preview's last line with the text
wrapped short of it. Input stops at the limit; a send still over (a
placeholder grew) is held. Sim hooks to open a compose with text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:58:01 +02:00
JakubandClaude Sonnet 5.5 f396882768 fix(ui-new): the screen redraws when USB power comes or goes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 21:49:59 +02:00
JakubandClaude Sonnet 5.5 6e13ad59ae feat(ui-new): a bolt beside the battery while USB power is connected
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 18:39:58 +02:00
JakubandClaude Sonnet 5.5 643dc09615 feat(ui-new): alerts as a banner sliding down from the top, a message's for 2 s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 16:35:45 +02:00
JakubandClaude Sonnet 5.5 ca6c2021d8 feat: the loading mark is three dots mid-screen, whatever the rotation
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 22:47:26 +02:00
JakubandClaude Sonnet 5.5 39d29383ac feat(ui-new): the boot splash grows with the panel, as the clock does
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 22:47:26 +02:00
JakubandClaude Sonnet 5.5 cf086678aa fix(ui-lvgl): the USB drive offer waits for the lock screen to go, PIN or not
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 22:47:26 +02:00
JakubandClaude Opus 5.5 b63af9fee1 fix(ui-lvgl): GPS signal chart spans the box from the first bar
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 21:25:27 +02:00
JakubandClaude Opus 5.5 2a9f900fff fix(ui-new): a Settings change is saved on the way to a screen opened from it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:52:20 +02:00
JakubandClaude Opus 5.5 0460249579 feat(ui-new): Home's panels list "All ..." first, shortcuts after
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:52:20 +02:00
JakubandClaude Opus 5.5 7c568d6153 fix: a leftover /prefs folder (Meshtastic) no longer blocks every settings save
Our /prefs file can't be read from a folder of that name, and the rename
that commits each save can't replace one, so on a device moved over from
Meshtastic without erasing the flash no setting survived a restart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:52:20 +02:00
JakubandClaude Opus 5.5 608c5b7dad fix(ui-new): on/off written On / Off everywhere, as every other value
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:12:27 +02:00
JakubandClaude Opus 5.5 c4217d8632 feat: a channel's scope can follow the default -- Default is the new start value
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:09:22 +02:00
JakubandClaude Opus 5.5 5a92d36509 fix: Bluetooth switched off stays off over a reboot or hibernate
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:09:22 +02:00
JakubandClaude Opus 5.5 50d0d5577b fix(ui-new): a tool opened from Home's Tools page goes back to Home
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:09:22 +02:00
JakubandClaude Opus 5.5 1af8ce1a85 fix(ui-new): on/off as the words ON / OFF -- the pill switch read as a battery
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:09:22 +02:00
JakubandClaude Opus 5.5 3326881dc1 feat(eink): screens laid out for the 4.2" -- tiles, Nodes pane, charts, Sky, nav, clock tools
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 13:44:11 +02:00
JakubandClaude Opus 5.5 cea102c152 feat(eink): 9px icon set, 5x10 hop digits and roomier bubbles on the 4.2"
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 13:44:11 +02:00
JakubandClaude Opus 5.5 44ccd47a12 feat(ui-lvgl): GPS on three tabs -- Sky, Signal, Details
Each tab a screenful: the sky plot beside the fix; the bars with a fixed
dB-Hz scale and the constellations; and Details with whatever else the
receiver reports (correction, locator, course, DOPs with their rating,
signal averages, NMEA counts). Sim: sim_open("gps").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:22:44 +02:00