The Bluetooth-page PIN prompt was gated on hasConnection(), which is fed by
the serial interface's isConnected(). DualSerialInterface::isConnected()
always returns true (USB always "connected"), so waiting_for_pair was always
false and the PIN was never drawn — on every dual build, i.e. the published
OLED + e-ink firmware. Pure-BLE builds were unaffected (there isConnected()
reflects bond state).
Gate the PIN on actual BLE-bonded state instead: add
AbstractUITask::isBLEConnected() (forwards to BaseSerialInterface::
isBLEConnected(), which DualSerialInterface overrides with the real BLE state
and pure-BLE inherits as its bond-aware isConnected()). The PIN now shows on
the Bluetooth page while BLE is on and not yet bonded.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Settings › Sound gains an "AD sound" row, and Auto-Advert notes the audible
"in range" heartbeat: the device chirps on every received advert (any node),
melody chosen by AD sound; there's no off, so silence it via the Buzzer
setting. built-in still chirps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a navigation tagline to the intro and a dedicated "GPS navigation"
feature-highlights block (waypoints, compass, navigate-to-anything,
location sharing, trail, global units); note location nav in the Messages
entry and expand the Tools entry to cover waypoints/compass/navigate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release notes covering the navigation suite (waypoints, GPS compass,
navigate-to-point, mesh location share, waypoints in GPX), the global
metric/imperial Units setting, the long-message buffer fix, plus the
existing v1.14 items, under docs/releases/solo-v1.14.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- geo::parseLatLon now rounds lat/lon in double (matching the Add-by-coords
form) instead of through a float cast that lost ~1 m near 1e8.
- NearbyScreen: preserve the ping menu's selected row across a rebuild
instead of snapping back to "Send" when a result line arrives.
- NearbyScreen: guard the ping-menu input path so a vanished contact
(selectedStoredPubKey == false) closes the popup rather than acting on an
uninitialised pub-key buffer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When a trail exists but the framed box collapses to one point (e.g. a
single recorded point, or all points coincident, with no GPS fix), the
degenerate branch was drawing waypoint[0] at the centre — but waypoints
aren't folded into the box in trail-priority mode, so a possibly-distant
waypoint appeared at the trail's location. Only centre a waypoint in the
genuine "lone waypoint, no trail" case.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GPX dumps previously contained only the <trk>. Emit saved waypoints as
<wpt> elements (label → <name>, plus <time> when the RTC was set) before
the track, per GPX 1.1 ordering, in both live and saved-file exports. The
emitter is duck-typed over the waypoint store so Trail.h stays decoupled
from Waypoint.h; labels are XML-escaped. They now import as pins in OsmAnd /
Garmin / GPX Studio alongside the track.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture the plan to multiply battery life via radio power technique (the
dominant draw is continuous RX, not the framework): CAD-based RX windowing
(~10-15mA → ~3-5mA, behind a setting due to the latency tradeoff) and
Adaptive Power Control, inspired by the ZephCore Zephyr port but stayable in
this Arduino tree. GPS power gating explicitly excluded — the device is a
live navigator/trail recorder. Deferred until trail polishing is done; prefer
adopting upstream nRF52 powersaving work.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The form's keyboard is the full alphanumeric one, and atof() silently read
a non-numeric entry as 0.0 — so typing letters created a waypoint at
(0, 0). Validate each coordinate with strtod and require the whole field to
be numeric; bad input now reports "Lat/Lon invalid" and saves nothing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Waypoints list header now reads "WAYPOINTS <n>/<cap>" (e.g. 3/16) so
it's clear at a glance how many waypoints are stored and how much room is
left before the table is full.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add-by-coords sat in the top-level Trail action popup alongside Mark here.
Move it into the Waypoints view as a trailing "+ Add by coords" row, so the
popup stays focused on trail/marking actions and waypoint management lives
in one place. "Waypoints" is now always shown in the action menu (it hosts
the list, backtrack and the add entry), so the first waypoint can be added
by coordinates even with no trail or saved points yet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The on-screen keyboard has no comma or minus, so a single "lat,lon" entry
was unworkable. Replace it with a WP_ADD form: separate Lat / Lon / Label
rows plus Save. Lat/Lon take a magnitude from the keyboard and a hemisphere
(N/S, E/W) toggled with LEFT/RIGHT, so negative coordinates need no minus
key. Save validates the range, auto-names a blank label, and stores the
point via the normal waypoint path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New Trail action "Add by coords" creates a waypoint without a GPS fix: the
keyboard takes a "lat,lon" string (decimal degrees), parsed by the shared
geo::parseLatLon; on success it falls through to the normal label keyboard
(blank → auto WP<n>). Useful for a meeting point or a spot read off a map.
Invalid input reports "Bad coordinates".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Range test → ✅: shipped as the Nearby Nodes ping (RTT + SNR, repeatable);
the dedicated continuous-ping/sparkline screen was not built (kept as future).
- Lock-screen unread count → ✅: total "<n> unread" badge on the lock screen.
- Mark-read at type level → ✅ pointer to the implemented priority entry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Waypoints/nav, GPS trail, Backtrack, Compass-to-contact flipped to ✅ with a
consolidated "shipped" summary noting deltas from the original spec
(two-char labels, heading tape compass, global Units, mesh location sharing,
trail-priority map framing, shared geo/gfx helpers).
- New backlog item: heading-up (track-up) map orientation, with the COG-only /
jitter / fit / grid / e-ink caveats and a lightweight rotate-the-fit plan.
- Audit: record the message-buffer length fix (history/compose sized to
MAX_TEXT_LEN) as ✅.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
While a trail exists the map now fits the recorded route (plus the live
position) and no longer folds waypoints into the bounding box, so a far-off
waypoint can't zoom the view out and squash the trail. Waypoints that
project outside the framed area are clamped to the nearest edge (marker +
label) instead of being lost off-screen. With no trail, the view still
auto-fits to the waypoints as before.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The label was always drawn up-and-right of the marker (wx+4, wy-3) and was
dropped entirely if it would clip the right edge — so waypoints near the
top/bottom (and left) edges had their label spill off the map or vanish.
Add an edge-aware placement helper: prefer upper-right, flip to the left
when it would clip the right edge, and clamp vertically so edge/corner
waypoints keep a visible label. Used by both the normal and degenerate
single-point map paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
After widening the history buffers, the compose side was still the
bottleneck: the keyboard capped input at 139 bytes and the quick-message
expand buffers were 140. Raise KB_MAX_LEN to 160 (MeshCore's MAX_TEXT_LEN)
and size the expand/compose buffers to MSG_TEXT_BUF, so a message can be
typed, expanded, sent, stored and displayed at the full protocol length on
every path.
The custom-message editor now passes an explicit max bound to its 140-byte
store, so the wider keyboard buffer can't overflow it; the bot editor
already passed per-field maxima.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Message history buffers were smaller than the over-the-air maximum, so long
messages lost their tail on display. Channel messages carry the sender
embedded as "Name: body" in the payload (up to MAX_TEXT_LEN = 160 B), but
ChHistEntry::text was only 140 B; DmHistEntry::text was just 80 B — and with
Polish text each accented char is two UTF-8 bytes, so the effective limit was
roughly half the visible characters.
Size both history buffers (and the fullscreen/preview split copies) to
MAX_TEXT_LEN + 1 so a full-length message is stored and shown intact. Sender
split buffers widened to the 32-char name limit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Previously a shared location was only actionable after opening the message
fullscreen; Hold Enter on a history row only ever offered Reply. Route the
DM and channel list context menus through the same buildFsMenu /
dispatchFsAction path as the fullscreen view, so Navigate / Save waypoint
appear directly on the list row when the selected message carries a
location (Navigate returns to the list on Back).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Waypoints list → Hold Enter → Send hands the point to the Messages screen
as "[WAY]<lat>,<lon> <label>" (same text format geo::parseLatLon already
reads). The user picks a contact or channel, the text lands prefilled in
the keyboard to confirm/edit, then sends — closing the loop with the
Navigate / Save waypoint actions on the receiving end.
- QuickMsgScreen: share-compose mode (startShare/beginShareCompose). Picking
a recipient jumps straight to the prefilled keyboard; cancel returns home;
afterSend clears the mode.
- UITask::shareToMessage hands off from TrailScreen to the Messages screen.
- TrailScreen: "Send" added to the waypoint Rename/Delete popup; builds the
[WAY] payload at the {loc} precision (5 dp).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Locations already travel as plain text ({loc} expands to "lat,lon"), so any
message carrying coordinates can now be acted on. In the fullscreen message
view, the context-menu (Hold Enter) gains Navigate and Save waypoint
entries whenever the message contains a coordinate — alongside Reply.
- geo::parseLatLon: shared scanner for an embedded "lat,lon" (the {loc}
format), with an optional [WAY] tag that supplies a label. Range-checked,
requires a decimal point to avoid matching plain integer pairs. Will also
back the waypoint-share feature later.
- QuickMsgScreen: Navigate opens NavView inline (To/Hdg/distance, honouring
the global Units setting) over the message, back returns to it; Save
waypoint stores the point (label from [WAY], else auto-named). Works in
both DM and channel histories, and on incoming or outgoing messages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The shrunken ring left only a few-pixel needle in the OLED's short vertical
space. Switch to a linear heading tape: a fixed travel-direction pointer at
centre over a scrolling N..E..S..W scale (30° ticks, N/E/S/W labelled),
with the large degrees+cardinal readout below. The tape is purely linear
(no trig) and uses the available width, so it stays readable on the small
panel. Update the Compass docs to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The N/E/S/W letters rode on the ring radius, so they overlapped the circle
as the card rotated. Place the letters on an outer radius and draw the ring
a glyph-height smaller, leaving a clear gap between them. The forward index
now sits in that gap, just outside the ring.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The no-heading hint was centred on the compass circle, overlapping the
ring. Draw it in the bottom readout band instead so the ring stays clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow the global Units preference in the two remaining Trail distance
spots that were still metric-only:
- Min dist gate: the index is now a unit-agnostic level (0=finest..3).
Metric stays 5/10/25/100 m; imperial uses round 15/30/75/300 ft (applied
as their metre equivalents in the sampling gate).
- Map scale grid: imperial mode uses round ft/mi steps (10 ft … 100 mi)
instead of metric steps with a converted label. Step storage moved to
float metres so sub-metre imperial steps keep their geometry; labels come
from a parallel table so the scale bar reads an exact round value.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the Settings › System "Units" (Metric/Imperial) row and update the
Trail action-menu entry from the old four-way km/h·mph·min/km·min/mi
"Units" cycle to a Speed/Pace "Readout" toggle within the global system.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a single "Units" choice (Settings › System: Metric / Imperial) that
governs every distance and speed shown in Tools — Nearby Nodes, the Trail
views, and the navigate-to-point screen.
- NodePrefs: units_imperial (global) + trail_show_pace (Trail readout mode),
schema bumped 0xC0DE0005 → 0006. The old combined trail_units_idx is kept
for file-layout stability but no longer drives anything; upgraders default
to metric + speed.
- geo::fmtDist gains an imperial mode (ft below ~1000 ft, then miles).
- NavView / Nearby / Trail (waypoint list, Summary distance, List deltas,
map scale-bar label) all format through the global preference.
- Trail's action-menu "Units" row becomes a Speed/Pace readout toggle; the
km-vs-mi unit now follows the global setting instead of being one of four
combined options.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The last stray getLocationProvider/isValid duplicate (with its own
ENV_INCLUDE_GPS guard). Fold it into ownPos so every GPS lookup in the
nav screens goes through UITask::currentLocation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>