Gate rsDeck opportunistic LXMF sends by the final packed Reticulum raw size when the next hop is LoRa, instead of using the pre-encryption LXMF payload size as the 254-byte limit.
Keep TCP paths on the normal Reticulum MDU, route LoRa packets that would exceed one RNode RF frame into link delivery, and log payload/raw/lora_raw sizing for field diagnosis.
Tested with rsDeck/Ratdeck T-Deck and Heltec V3 RNode attached over USB to a MacBook Pro running Ratspeak, using the medium-fast LoRa preset. Short 1-5 character opportunistic sends worked bidirectionally. Direct link delivery worked from T-Deck to Ratspeak/Heltec; Ratspeak-to-T-Deck link delivery later queued during link establishment while opportunistic still worked.
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.
Input events otherwise wait up to a full 33ms frame interval before
LVGL renders, which is noticeable when the loop body is loaded.
When the input poll reports activity, run lv_timer_handler()
immediately and let the next idle frame fall back to the 30 FPS cadence.
037af2a left the backlight at 0 in Display::begin() to avoid exposing an
unpainted framebuffer, but powerMgr.setBrightness() at step 24 only runs
at the end of boot, so the whole boot sequence rendered onto a dark panel.
Set PWM 128 right after the first lvBootScreen.setProgress(), once LVGL
has flushed the boot screen. powerMgr at step 24 still overrides with the
user's configured brightness.
The handler had no aspect filter, so it captured every announce from
every aspect of a peer (lxmf.delivery, lxmf.propagation, NomadNet
node, etc.). Each aspect has a different destination hash, so the
same Sideband/Columba peer appeared multiple times in the nodes list
— once with the display name (lxmf.delivery's app_data carries it)
and once or more as raw hex (other aspects had no/different name).
Restrict to lxmf.delivery: that's the only destination we ever route
LXMF messages to. Propagation/NomadNet visibility can come back later
behind an opt-in toggle if needed.
Note: existing saved contacts captured under other aspects will still
appear after this change since they're loaded from disk. They can be
removed manually via the contacts UI.
Two pocket-carry quality-of-life additions:
1. Long-press (1.2s) trackball click blanks the screen if no LVGL
screen consumes the long-press. InputManager captures the power
state at click DOWN (_clickFromScreenOn) and only emits the
long-press if the screen was already on, so a long-press from
SCREEN_OFF wakes without immediately re-blanking.
2. Touch events are ignored entirely while screen is off, preventing
accidental wakes from pressure on the panel in a pocket/bag.
Trackball click and keyboard keys still wake normally.
InputManager now holds a Power* injected via setPowerMgr() in setup.
encodeAnnounceName now emits msgpack fixarray(3):
[display_name(bin), stamp_cost=0, supported_functionality=[]]
Empty supported_functionality list = SF_COMPRESSION (=0x00) absent,
so Python LXMF disables auto_compress for our destinations and stops
shipping bz2-compressed Resources we can't decode. Always emit the
3-element form even when the name is empty — Python defaults to
auto_compress=True for legacy <3-element app_data.
Pairs with microReticulum 290a133 which removed bz2 entirely.
CORE_DEBUG_LEVEL=0 drops Arduino core noise on expected-missing files, LittleFSFileSystem::open_file now actually works so path_table persists across reboots.
Link proof signature, TCP proof routing, and split-packet handling
were causing intermittent message failures with Python LXMF clients.
Route >254B messages through link delivery, add proof retry for LoRa.
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"
LoRaInterface: Implement RNode-compatible split-packet framing so the
full Reticulum MTU (500 bytes) works over LoRa. Packets >254 bytes are
transparently split into two LoRa frames with matching sequence numbers
and reassembled on the receiver. Also adds a 4-deep TX queue instead of
dropping packets when the radio is busy — critical for link handshakes.
LXMFManager: Large messages (>MDU) now queue pending link establishment
and retry via resource transfer instead of failing immediately. Stale
link-pending state is detected and reset. Speculative background link
establishment removed to avoid LoRa collisions.
AnnounceManager: Add app_data hex diagnostics on announce RX for
debugging name extraction issues.
main.cpp: Centralize all announce paths through announceWithName() so
display name and app_data are always logged.
Outbound (Ratdeck→Python) was broken because Identity::recall() could
never find the recipient. Root cause: OS::time() returns seconds since
boot on ESP32, but persisted known_destinations entries carried timestamps
from the previous session. New announces got timestamp ~31s while persisted
entries had ~5000s, so the LRU cull immediately removed the new entry.
The microReticulum Identity.cpp fix (timestamp normalization on load) is
in .pio/libdeps and must be upstreamed to ratspeak/microReticulum separately.
Changes:
- known_destinations cap 256→512 (PSRAM pool was 1% used, plenty of room)
- Fix link delivery destHash: onLinkEstablished callback was passing link_id
instead of LXMF destination hash, corrupting conversation routing
- Add diagnostic logging: [LXMF-DIAG], [TCP-DIAG], [HEART-DIAG], [DIAG-PROOF]
for tracing link establishment, proof routing, and interface status
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.