The 4.2" build's 9x15 font (EINK_LARGE_FONT=2) at 2x -- 18x30 cells,
~44 characters x 16 lines -- instead of the 6x9 at 4x, which goes blocky.
Compared side by side on the panel, as suggested in review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
setRamArea() and fastWrite() follow GxEPD2 1.6.2's private
_setPartialRamArea() and _writeImage() for the GDEQ0426T82; say so, so
whoever bumps the library knows to re-check them.
- 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>
- 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>
The Watch13 env still compiled with -Ofast and had run out of flash
after the map, calendar and QR commits. -Os brings it to 70.7%.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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
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
GxEPD2 sends the panel RAM a byte at a time; on the nRF52's SPIM the
per-call overhead dominates, and an 800x480 partial refresh writes the
whole 48 KB several times. GxEPD2_426_GDEQ0426T82_Fast overrides the three
image writes to send each row in one transfer() call, falling back to the
stock path for the cases it doesn't cover (first write, mirror_y, PROGMEM).
Byte-for-byte the same data as the stock driver.
Opt-in per env: -D EINK_FAST_WRITES=1, and EINK_SPI_HZ (default 4 MHz,
8 MHz here, SPIM2's ceiling).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxAZVAbhhYr18Dd4guTQM1
New solo env WioTrackerL1_GDEQ0426T82_companion_solo_dual: the Wio Tracker
L1 (Lite) with a Good Display GDEQ0426T82 (SSD1677) on the board's 24-pin
e-ink FPC. Build config only. Extends WioTrackerL1Eink with its own full
build_flags list so the stock panel's model and rotation never reach the
compiler.
RAM: the 800x480 framebuffer is 48 KB, so OFFLINE_QUEUE_SIZE is 32 and
MAX_CONTACTS 250 -- with the stock limits UiCore's heap allocations fail
at boot and it loops.
Tested on hardware: Wio Tracker L1 Lite + GDEQ0426T82.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxAZVAbhhYr18Dd4guTQM1
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>
- 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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
Chart.h draws Diagnostics > History, the noise sweep and the trail's height
profile: round values up the left, labels along the bottom, a solid fill
(no transparency) and, under a finger, the sample's value and when / where.
Sim: sim_open("histdemo") / ("profdemo") fill them with made-up data.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Home and the lock screen draw HH:MM in ui-core/Lettering.h's block digits,
the seconds smaller on the same baseline, leaning smoothly per screen row.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ACCENT_DIM (the accent mixed toward black) came out brown on selected
tabs, chips, segments and own bubbles. They take the accent with dark
text now, as primary actions and the quick panel tiles do:
styleSelected() sets the fill, the pressed shade and every label under
it. Own bubbles: dark text, age and delivery mark (green or red can't be
read on amber); the melody editor's selected note is outlined, the
sounding one filled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>