Adds an lxma://<hash>:<pubkey> QR overlay reachable from Settings and
from a new header row at the top of the Contacts tab. Including the
public key lets Columba/Sideband skip the PENDING_IDENTITY round-trip.
Contacts list stays visible even with no saved contacts so the header
row is always reachable; the empty-state floats above it.
Both the LXMF Addr and Identity readonly entries truncated to the
first 16 hex chars, which made it impossible to type or read the
real address into another client (Sideband, Columba, etc) for adding
ratdeck as a contact. Drop the substring(0, 16) calls and show the
full 32-char hex. Wraps inside the row at the existing font; legible
and copyable.
Previously a single ASCII glyph collapsed SENT and DELIVERED. Wire
PacketReceipt delivery callbacks through to sideband-style single
and double checks.
LXMFManager tracks outstanding receipts (opportunistic + link
single-packet) by hash. On delivery: persist DELIVERED and fire
_statusCb. On 60s timeout: drop the entry, leave at SENT — lack
of proof over LoRa isn't proof of failure. Resource transfers stay
at SENT; microReticulum's Transport skips receipts for resource
packets and Link::start_resource_transfer exposes no concluded
callback to hook.
LvMessageView renders the glyph via applyStatusGlyph (Montserrat 12):
REFRESH for in-flight, single OK for SENT, double OK for DELIVERED,
WARNING for FAILED. Status callback matches by timestamp (~1s
tolerance) so DELIVERED lands on the right bubble after later
messages have already moved past QUEUED.
The timestamp label was positioned via lv_obj_align_to below the
message box, but the bubble container's LV_SIZE_CONTENT height was
driven entirely by the box, so the time rendered below the bubble's
allocated row in the flex scroll — visibly hanging into the gap.
Add pad_bottom=14 to the bubble so its outer height includes the
timestamp row, and anchor the box at TOP_LEFT/TOP_RIGHT (was
LEFT_MID/RIGHT_MID) so the layout stacks cleanly: box on top,
timestamp tucked under it inside the bubble's bbox.
Contacts/Messages/Nodes screens consumed long-press as soon as they
loaded, which surfaced delete/menu dialogs instead of blanking the
display. Gate per-screen long-press consumption on _focusActive so the
delete affordance only fires after the user has navigated into the
list with up/down/enter. From the resting tab view, long-press falls
through to main.cpp and powers the screen off — same behaviour as the
home screen.
CORE_DEBUG_LEVEL=0 drops Arduino core noise on expected-missing files, LittleFSFileSystem::open_file now actually works so path_table persists across reboots.
Regenerated Montserrat 10/12/14 with Cyrillic and Latin Extended
Unicode ranges so messages in Russian, Ukrainian, Bulgarian, and
accented European languages render properly instead of rectangles.
Scroll: scrollToSelected() was defined but never called — LVGL didn't
know which pool row to show after viewport updates. Nodes at the
bottom of long lists were invisible. Now called after every sync.
Modal: Replace lv_obj_center() with explicit pixel positioning so
the action modal renders centered regardless of list scroll state.
Trackball: Click now sets character='\n' matching keyboard Enter for
complete event parity.
Timestamps: Incoming messages with invalid sender timestamps
(< Nov 2023 epoch) are now stamped with the receiver's local time
if available. Previously, messages from devices without NTP/GPS
showed no timestamp at all.
Frequency editor: Replace raw 9-digit Hz accumulator with a
radio-style digit cursor. Display shows NNN.NNN.NNN format with
bracket cursor on active digit (e.g., "920.[6]50.500"). Trackball
left/right moves cursor, digit keys replace at cursor and advance.
Esc restores original value. Matches amateur radio transceiver UX.
Status bar: Cache last displayed hour/minute, skip LVGL label
update when minute hasn't changed (eliminates 59/60 redundant
invalidations per minute).
RNS tables: Increase ANNOUNCE_TABLE_MAX 32→48 (prevents premature
eviction on networks >32 nodes). Increase RATE_TIMESTAMPS_MAX
16→32 (prevents false rate-limit rejects on busy networks).
BLE: Add 5-minute idle timeout. Stale connections now get
disconnected to free the single NimBLE connection slot for new
devices. Activity tracked on connect, RX, and TX events.
Message view: Extract appendMessage() from rebuildMessages(). New
messages are now incrementally appended (O(delta) widget ops) instead
of destroying and recreating all bubbles (O(N)). Full rebuild only
on initial load or message count decrease.
WiFi TX: Buffer HDLC frame in PSRAM then send with single write()
call. Previously sent per-byte (200+ syscalls per packet), now 1
syscall. Reduces CPU overhead and TCP fragmentation.
Font: Disable unused LV_FONT_UNSCII_8 (compiled but never referenced).
Previously, "Reboot Required!" fired on every applyAndSave() once
any WiFi setting changed — showing 3 times during a single STA
setup (mode + SSID + password). Now the toast only shows on first
detection with a gentler message: "WiFi changes apply on reboot".
Subsequent saves show "Saved" normally.
refreshUI() detected and displayed new messages but never called
markRead() or updated the tab badge. Now marks conversation as read
and refreshes the badge whenever new messages are loaded while the
user is actively viewing the conversation.
Replace direct-message-on-Enter with a 3-option modal overlay:
- "Add Contact" prompts for a nickname (pre-filled with announce
name, falls back to hex hash if left empty), then saves contact
- "Message" opens conversation (previous Enter behavior)
- "Back" closes modal (also Esc at any point)
Long press on unsaved nodes now also shows the modal instead of
silently adding. Long press on saved contacts keeps the existing
delete confirmation flow.
Backend:
- LoRaInterface captures packet RSSI/SNR immediately after every RX,
removing redundant SPI re-reads from log statements
- AnnounceManager populates DiscoveredNode.rssi/snr from LoRaInterface
on every announce (fields existed but were never wired up)
Frontend:
- Nodes screen shows RSSI appended to hops/age when dev mode is on
- Node name label uses smaller font (montserrat_12) to reduce truncation
- Normal users see no change
Screen idle:
- Remove powerMgr.activity() from radio yield callback — screen no
longer wakes on LoRa RX, auto-announce, or RSSI polls
- Add [POWER] state transition logging for on-device diagnostics
Radio regions:
- Add 4-region system: Americas (915), Europe (868), Australia (915),
Asia (923) with timezone-to-region mapping
- Region picker in Radio settings (always visible)
- Presets now apply region-appropriate frequency + modulation params
- Timezone change warns if it suggests a different radio region
Frequency input (developer mode):
- Hz-precision input (9 digits) displayed as MHz with trimmed decimals
- Left/right arrows step by 125 kHz, digit keys for direct entry
- Inspired by @strijar in https://github.com/ratspeak/ratdeck/pull/12
- GPS time sync via UBlox MIA-M10Q (38400 baud auto-detect)
- Custom zero-dependency NMEA parser with XOR checksum validation
- Only trust GPS time when satellites > 0 (no stale RTC cache)
- DST-aware timezone picker at first boot (21 cities, POSIX TZ strings)
- Timezone also configurable in Settings > GPS/Time
- GPS Time on by default, GPS Location off by default (opt-in)
- Status bar: clock (top-left), Ratspeak.org (center), battery (right)
- 12h time default (no AM/PM), configurable 24h in settings
- NVS persistence of GPS time for approximate timestamps across reboots
- Fix factory reset Enter key bleed-through (600ms input guard)
- Fix hardcoded UTC-5 NTP timezone (now uses DST-aware POSIX TZ)
- Enable UBlox MIA-M10Q GPS on T-Deck Plus (HAS_GPS true)
- Custom zero-dependency NMEA parser (NMEAParser.h) with XOR checksum
- GPSManager: baud auto-detect (115200/38400/9600, 10s timeout),
settimeofday() sync every 60s, NVS time/position persistence
- GPS Time enabled by default, GPS Location disabled by default
(user must explicitly opt in via Settings)
- Replace status bar connectivity bars with clock display (top-left)
- Default 12h format without AM/PM, configurable 24h in Settings
- Add GPS/Time settings category: GPS Time, GPS Location,
UTC Offset (-12 to +14), 24h Time toggle
- Fix hardcoded UTC-5 NTP timezone to use configurable utcOffset
- Change status bar brand text to "Ratspeak.org"
PlatformIO Build / release (push) Has been skipped
Apply bin8 fix to the duplicate announce encoding in LvSettingsScreen
(Send Announce action). Replace inline copy with shared function from
main.cpp. Follows up on PR #5.
- Fix TCP port input: allow direct digit entry instead of scroll-only
- Fix flash status always showing "Error" (was checking SD path on flash)
- Flash now shows used/total KB instead of just Mounted/Error
- Audio buffers use PSRAM (ps_malloc) with internal heap fallback
- Bump version to 1.6.1