- A restart between commitTempFile()'s remove and rename left only the .tmp;
loads now recover it (prefs, contacts, channels, scopes).
- CustomLR1121Wrapper lacked readLiveRSSI/readLiveSNR: LR1121 boards didn't
compile.
- The repeater and room server sims gain DynamicConfigSerializer.cpp and
CommonRadioPrefs.cpp (broken since the v1.18 merge).
- Comments still describing the removed DualSerialInterface.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- DisplayDriver takes ColorVal; each driver's .cpp defines the UIColor roles
(window_bkg, primary_txt, ...) in its own values. ui-new draws in two:
window_bkg and primary_txt. OLED and e-ink look as before (sim screens
pixel-identical).
- E213, E290, LGFX, Null, ST7735, ST7789LCD, U8g2 taken whole from upstream
(with them the rewritten ST7735 driver and the Heltec V4 R8 TFT display).
- SH1106, SSD1306, ST7789, EinkGfxDisplay and the sim drivers converted.
- ui-orig, ui-tiny, simple_* get upstream's colour roles; the repeater's UI
taken from upstream (its power-off screen).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Bluetooth + USB (+ WiFi/Ethernet/UART per build) in one interface_manager,
as upstream; frames go to every enabled link, USB is read while BT is
connected. DUAL_SERIAL now means ENABLE_USB_INTERFACE.
- WiFi interface with upstream's wifi_* prefs and set/get wifi.* CLI.
- isClientConnected moved into ArduinoSerialInterface (DTR on nRF52 and
ESP32 native CDC).
- UI uses isBluetoothEnabled/enableBluetooth/disableBluetooth; turning BT
off leaves USB and the other links on.
- DualSerialInterface removed.
- Sim build gains DynamicConfigSerializer.cpp (broken since bd64c203).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NodePrefs is now NodePrefsFields (the fields) plus how they're saved: one
JSON key per field, upstream's keys under "radio", "gps", "repeat", "comp"
and "custom" (so either firmware reads what the other wrote of them),
ours under "solo". Saved atomically (temp file, then renamed), through a
buffer. 2.0-rc's binary /prefs is removed, not converted: 2.0 starts from
the defaults; /new_prefs from before 2.0 is still imported.
From upstream with it: txdelay / direct.txdelay / agc.reset.interval
(prefs and CLI), and the board's own settings through getCustom()
(Board::attachDynamicPrefs) in place of the merge's stopgap adapter.
ConfigSerializer reads values up to 191 characters (was 127): 140-byte
texts, an 80-byte table in hex.
Test: every field round-trips through the JSON byte for byte; the alarm
label tests expect "Once" (the label changed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes and features from upstream: MACThenDecrypt / command buffer
overflow fixes, ACK forwarding delay, transport code 0 as unscoped,
hidden nodes don't answer DISCOVER, LR2021/LR1121 fixes, GPS cold-start
detection and waitFor()/drain(), NMEA fix-age counters, ESP32 RTC after a
crash, remote CLI by text message (TXT_TYPE_CLI_COMMAND),
PUSH_CODE_BINARY_RESPONSE, board.loop(), new boards (Wio Tracker L1 1W,
ThinkNode M4/M8, Muzi Base, Waveshare LR1121, Pico W).
Kept ours: NodePrefs, main.cpp, every UI, GxEPDDisplay. The companion CLI
stays MyMeshCli.h's handleCliCommand(); upstream's handleCommand() calls
it. The board's FEM gains go through attachDynamicPrefs() with an adapter
over our NodePrefs fields. Upstream's JSON prefs and MultiSerialInterface
come as their own stages.
Also: the display defaults were inside RADIO_FEM_TXGAIN's #else (a
missing #endif).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The panel froze and dimmed the screen as the finger started: a snapshot of
the whole screen (slow on the map) and a full-screen flush, so it stalled,
jumped and tore top to bottom. Now it slides opaque over the live screen
(a clear layer under it still takes the tap that closes it), built at start.
Its slide is timed by its own frames, at most 30 ms a frame: a slow frame
ended the 160 ms lv_anim and the panel just appeared.
The sky plot on GPS > Sky was a fixed 168 px, taller than what is left
under the title bar and tabs: now it takes that height.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The light theme read as the dark one inverted. Now something selected (a
tab, a segment, a tile, Fav) is a tint of the accent with the accent's text
(SEL_*), the full accent fill stays for the primary action; setting values
read in grey (VALUE); popups, the banner and the toast have a quiet grey edge
(EDGE), the toast is a dark pill; neutral greys the RGB565 panel keeps
neutral; the big clock graphite.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Settings > Display > Theme: Dark / Light (NVS mc_ui/light). The colour
tokens are set once before anything is built, so a change restarts the
device. Text on an accent fill is the new ON_ACCENT (it was BG, white
in the light theme); each accent has a deeper hand-picked light variant
that reads on white and takes white text. The map's empty-tile fill and
grid and the areas' outlines follow the theme too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
L2: a Flashlight app on Home (a lightbulb icon added to the fonts): a
white layer over everything, the backlight at 100 %, no auto-off; a tap,
the side or the top button puts it away and the brightness back.
L1: Tools > System > Flashlight, the whole OLED lit at full contrast
until a key. Not on e-ink.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The panel starts a radius up, under the status bar, so its top corners
are hidden there instead of cut out over the frozen screen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Map tools > Layers > Map picks what the map is drawn from:
- Topo: OpenTopoMap, as before.
- Light and Dark: Esri's grey canvases, no labels, up to z16.
- Satellite: Esri World Imagery.
- Esri Topo.
Each layer has its own folder for downloaded areas (/sdcard/maps-light,
-dark, -sat, -esritopo; Topo stays in /sdcard/maps) and its own live-tile
cache. Live-cache records carry the layer.
Esri serves JPEG: decoded with LVGL's tjpgd (LV_USE_TJPGD), whatever the
file name says. The layer is kept in NVS (mc_ui/layer); switching waits
while a download or a deletion runs in the current folder.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Every packet heard is drawn, by kind in fixed colours: advert, DM,
channel, request, ack, other, sent. One that can't be placed on the map
is a ring at your own position.
- A legend pill at the top counts each kind over the last minute.
- On a map without node markers, a flow brings its own nodes (a dot and
the name), fading with it.
- Copies of one packet (the same packet hash) share one fade, so a path
goes out as a whole, not segment by segment.
- 32 flows kept on ESP32 (12 on nRF).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WiFi starts and joins on internal RAM: ~42 KB the first time, ~25 KB after,
more for WPA. Free internal RAM had shrunk to ~20 KB after opening the map
(the tile decoder's 12 KB stack, the 32 KB I-cache, the DMA draw buffers,
UI statics), so a scan failed at once (esp_wifi_init: no memory) and a join
during a tile download timed out (AUTH_EXPIRE).
- ESP-IDF: CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY, and the esp_timer
task stack 8 -> 4 KB (it uses ~0.4 KB). Rebuild the framework libs:
pio run -e Wio_Tracker_L2_idf_libs.
- PSRAM_BSS (EXT_RAM_BSS_ATTR) on the UI's big statics: QR codes, map
state, charts, lists. .dram0.bss 115 -> 66 KB.
- The tile decoder's and fetcher's task stacks in PSRAM.
Free internal RAM, idle: 48 -> 105 KB; WiFi up: 57 KB, 29 KB at the
lowest while downloading tiles.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With two thumbs the second lands before the first lifts; the panel's
first point then jumped to it and LVGL saw one press sliding from key to
key, losing the first letter (or starting a scroll). A new GT911 track id
is now a release, then a press. The keyboard no longer hands a rolling
finger to a scroll or gesture up the tree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Density from less chrome instead of smaller rows (ROW_H stays 44):
- titled screens drop the status bar; the title bar (APPBAR_H) holds back,
the title, the screen's actions and the time/battery on a pill; the status
bar returns for Home, the map, typing, the quick panel and the lock
- one radius (RADIUS) for everything tapped: buttons, tabs, choices, chips
- tabs are all segmented at TAB_H in the body (GPS, Clock converted)
- Nodes: chips row + sort + status line become one toolbar row with
Show / Order choices; Messages' All/Favourites is the same choice
- nav map: the target bar only while there is a target; the pin opens one
"Places" popup; back from a map options page restores the map and Map
tools as left, without a jump
- node detail actions at the top of the scroll; Home tiles fill the page
- rowsFit() leaves growing labels to the flex (a screen title cut to one
letter after Messages' filter changed)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every packet heard runs from its origin through the repeaters with a
position to this device; a packet sent is a ring. ui-core/PacketFlow.h
resolves them (UiCore::flow, MyMesh logRx/logTx -> Listener). ui-lvgl
draws them on the map's marker layer and repaints only their area while
they move; ui-new draws the last minute on the Nodes map ("Flow" in its
options). Setting: Map options > On the map > Packet flow, CLI map.flow.
Off by default. Sim-checked only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core: PathEditor results are links (node k hearing k-1 and back); toNode()
off traces only the repeaters (a companion answers only with repeat on);
probe() traces to each repeater in turn after no reply; failures carry a
reason; an empty list saves "direct". PingEngine takes over a slot left past
its timeout. A kept route: the dropped heard path isn't announced to the app
nor bumps lastmod; an app update keeps the flag only if it leaves the route.
Marker boxes sized for every dot and name (overflow).
ui-lvgl Route: one line per node with out / back dB coloured by quality, tap
a hop to move / remove, tap the node to include it, Keep in the header, Find
where beside a no-reply status. ui-new Path: To node / Find break rows,
result alerts, cursor kept on its action.
Channels: ui-new re-sorts the list on entering it, cursor on the same channel.
Docs: Path and trace, Channel order. Sim hooks: open route, add channel,
open messages.
Checked in the browser sim (L2 + ui-new peer + repeater); not on hardware.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shared chanctl::order() builds the channel list for ui-new and the L2:
favourites first, then by ch_sort. New ch_sort pref at the end of NodePrefs,
Settings > Contacts row and contacts.channel.order CLI key.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Core: PathEditor (UiCore::route) loads, edits, traces and saves the route to
a contact; MyMesh::sendTrace over an explicit route with per-hop SNRs,
setContactPath / setContactPinned. A route can be kept
(CONTACT_FLAG_ROUTE_PINNED, ContactInfo::flags bit 4): a path heard from the
node doesn't replace it and the last DM resend doesn't drop it.
ui-lvgl: Route screen (node detail), repeater picker by distance, picking
hops by tapping the nodes map (numbered badges, line, Undo / Done). The
map's markers are one drawn layer with hit-testing and name decluttering
instead of three objects per node.
ui-new: Path / trace view in the Nodes action menu; Add reuses the list
filtered to repeaters.
First cut: built for L2 LVGL, L1 OLED and L1 e-ink, tried on L2 only.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
PREFS_VERSION 2: settings saved by 2.0-rc1..rc3 are not read, the device
starts from the defaults (v1.x /new_prefs is still imported as before).
The fields appended at the end during the rc cycle move into their
sections (BLE off, battery curve, text/icon size, message alert, advert
position precision, lock screen look). ch_scope_follow and its rc1
conversion and the unused use_lemon_font are removed. Stale comments in
NodePrefs.h and Trail.h fixed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 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>
- 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>
- 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>
- 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>
- 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>
MicroNMEA's valid flag survives a power cycle, so the duty cycle saw the
old fix right after waking the receiver and stopped it again a tick
later: with GPS power saving on the position never updated. begin() now
clears the parser.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the phone not connected, every frame (each packet heard, each advert)
went to the USB port. With nobody holding it open the core either drops the
bytes or lets its buffer fill, and streamWriteUntil() then spun out its whole
timeout. Skip the write when the native USB Serial has no host.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
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>
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>
WioTrackerL1Eink426_solo_dual extends eink_solo like the 4.2" build and
sets only what differs: the panel, rotation, the 9x15 at 2x with Text and
Icon size, bulk writes at 8 MHz, 250 contacts and a 32-message queue.
Replaces the full copy of the flags in solo/wio-tracker-l1-gdeq0426/.
Docs: advert precision, text and icon size, the 4.26" in the feature matrix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
- 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>
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>
build_unflags runs after build_flags, so unflagging the board's
-D DISPLAY_ROTATION=1 in [eink_solo] also removed the landscape env's
identical flag: the panel came up portrait (GxEPDDisplay's default 0) and
UITask::applyRotation's restore was compiled out, so the rotation setting
didn't stick. Only the portrait env unflags it now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Quick panel: the screen under it is frozen and dimmed in one snapshot
(freeze::early), so the slide redraws an image and the panel; a tap or
swipe up under it closes it and nothing under it takes a touch. Tiles are
two pages of four with dots; tiles restyle only when their state changes.
- Home: a touch that starts on the top layer (the quick panel, the status
bar) is not a page swipe -- a sideways drag of the brightness slider over
Home ended the drag and turned the page under it.
- Keyboard: OK and hide don't put the cursor back on a field whose keyboard
is gone.
- BotScreen: adminRowBox -> centerRow (the sim build broke in 3293ac09).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The quick panel, as a phone's: pulled down from the status bar (or a tap
on it). Bluetooth, WiFi, GPS, sound, trail and live share switch at a
tap; Advert opens the advert popup (moved here from the Nodes header);
Lock locks the screen; a brightness slider. Holding a tile opens its
settings. Lock and sun glyphs added to the fonts.
Fixes from rc1 testing on the L2:
- GPS status icon: none when GPS is off (the module kept its last fix
valid, so it stayed green); grey on, green with a fix. ensureGps()
turns GPS on before trusting that stale fix.
- Screen wake: the panel wakes dark, a frame is drawn, then the
backlight fades in -- no white flash. Off fades out first.
- Power off / flat battery: the chip wakes every 30 s to look for USB
power and starts when plugged in (it slept with no wake source before,
until the reset button). Plugged in when switched off: stays off until
re-plugged.
- Message ages in a conversation refresh every 2 s, as on ui-new; the
message popup keeps its age, repeaters heard and delivery up to date.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
versionNum() read "v2.0-rc1" as plain 2.0, so a device on a release
candidate never offered the release itself (nor a later candidate). A
"-rcN" suffix now orders before the bare version: v2.0-rc1 < v2.0-rc2 <
v2.0 < v2.0.1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/prefs holds a header (magic, format version, size, CRC-32), the node's
position and NodePrefs as it is in memory, in place of /new_prefs' two
hand-kept field lists and 0xC0DE00xx schema bumps. A new field goes at the
end of the struct; moving one bumps PREFS_VERSION. sanitize() keeps every
value in range.
The first boot after an update from before 2.0 imports only the first
block of the old file, laid out the same in upstream MeshCore and Solo
(name, position, radio, BLE PIN, scope), then deletes it; everything else
starts from the defaults. Contacts, channels, scopes, waypoints and trails
are untouched.
Gone: the page-order and GPS-interval migrations, the unused
trail_interval_idx / trail_units_idx / repeat_extra_scopes; fav_sort_off
and msg_wake_screen_off become fav_sort and msg_wake (on by default).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Node detail: a card with a compass rose and the hop chain over the info;
the bar keeps Message / Admin / Add, Ping and Navigate, the rest goes to a
"More" group under the info (favourite toggled in place, delete by a second
tap). Nodes: an arrow by each distance. A trail's height profile in Map
tools and a saved trail's popup. Diagnostics > History: battery, noise,
SNR and traffic charts. Clock > Calendar: today, the weekend and alarm days.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The OLED gets the arrows towards nodes in Nodes and the Path row with its
hop rings in a stored node's detail (its position on one line to make the
room); no compass rose. Trail gets a height-profile view on both. The
Status history, trail profile and calendar come from ui-core. A sim hook
turns on the advert's position for tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The history of the noise floor, battery, traffic and SNR, a trail's height
profile (with a sampler for trails read point by point off the card) and a
month's calendar, moved out of ui-new so ui-lvgl can draw the same.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Docs: the E-ink section describes the landscape and portrait builds, what
the tall screens add, and the settings, with three screenshots; the e-ink
build flags; the release file names. Sim: each orientation gets its own
factory, so a page can load both, and simEinkScale 0 leaves the canvas'
CSS size to the page. CI builds both into solo-sim-wasm.zip (wasm/eink/).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The landscape build's 8x13 digits stand 9 px, so its status, page and
check glyphs and the row-heading map markers come in a 7 px set instead
of 5. The battery outline, in the header and on the Status tile, leaves
its corner pixels out.
The page icons go back to a row of their own under the header: beside
them on the header line only three status icons fitted, and the rest
went missing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Message ages, the GPS search time and the sky plot changed every second,
and each change is a panel refresh. On e-ink an age under a minute reads
"<1m", the search time counts minutes, and the sky redraws every 15 s
(at once after a key).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tall screens stack the Sky view and the map over their rows, show more
recent chats, give favourite cards the heard age and distance, and put
the trail map under the trail summary. Wide screens put the page icons
on the header line.
E-ink only (Features::IS_EINK):
- a month calendar under the clock and on the portrait lock screen, with
the alarm's days marked; the lock screen also lists unread messages,
the alarm and the clock fields
- 8-hour charts in Status: battery, noise and SNR, mesh traffic
- an elevation profile under the trail map, with the climb and the top
- a compass rose and the path's hops on a contact's detail, arrows by
the distance in Nodes rows and on favourite cards
- an ordered-dither fade under chart lines
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>