PATH_CONTACTS / PATH_MESSAGES / SD_PATH_CONTACTS / SD_PATH_MESSAGES
all ended in '/'. The FATFS layer used by the SD library and LittleFS
won't reliably enumerate when given a path ending in slash — opendir
returns a valid handle but readdir yields nothing. Direct file reads
(SD.open with FILE_READ for a known path) still work, which is why
settings/identity persisted but contacts and conversations vanished
on reboot.
Drop the trailing slash from the constants and add explicit "/" at
all concat sites: saveContact, removeContact, conversationDir,
sdConversationDir, and the migrateTruncatedDirs path builders.
Sideband/Columba and other LXMF clients commonly include "/" in display
names (e.g. handle/path conventions). The allowlist in sanitizeName
stripped it, mangling "alice/columba" into "alicecolumba". Saved
contacts get re-sanitized on each load (line 393), so existing names
also lose the slash on next boot.
CORE_DEBUG_LEVEL=0 drops Arduino core noise on expected-missing files, LittleFSFileSystem::open_file now actually works so path_table persists across reboots.
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
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.
Guard AnnounceManager::received_announce() against null Identity
objects — Identity::recall() can fail when known_destinations table
is full and cull removes the entry. Also removes dead-code
needs_transport_headers() override from TCPClientInterface.
4-layer defense against 100+ node announce storms from rns.ratspeak.org:
- Transport-level rate limiter (5/sec) via filter_packet callback, before Ed25519 verify
- TCP frame processing time-boxed to 15ms per loop iteration
- Global announce rate limit (3/sec) in AnnounceManager
- UI rebuild throttled to once per 2 seconds
Also fixes message status not persisting to disk on queue drain.
- Evict highest-hop unsaved nodes first when peer list is full (nearby peers survive)
- Add first-boot SD data cleanup screen before name input
- Conversation summaries cache for faster message list rendering
- Optimize message view refresh with summary-based change detection
- Streamline unread tracking through MessageStore instead of LXMFManager
- Fix LXMF wire format: standardize on opportunistic [src:16][sig:64][content]
- Fix LXMF signature: sign(dest||src||packed) per spec, remove message_hash
- Fix MsgPack interop: handle both str and bin types for title/content
- Radio defaults changed to Balanced preset (SF9/BW250k/CR5/TX14)
- Messages screen: sorted by most recent, preview with You:/Them:, green unread dot, timestamps
- Status bar: replace LoRa/BLE/WiFi text with signal bars (green=connected, red=offline)
- Home screen: remove Unread info (shown in Messages tab)
- Contacts screen added (Friends tab)
- Identity manager: multi-slot identity support with per-slot display names
- Message store: fix peer hash truncation, SD directory creation, .bak file leak
- Settings: check for updates, active identity display, info diagnostics
- Migrate all screens to LVGL v8.4 widget system
- Non-blocking radio TX (async endPacket via LoRaInterface)
- Live TCP server switching with transient node cleanup
- Fix UI freeze during radio transmit
- Trackball long-press delete, deferred click with debounce
- Pin microReticulum to 392363c, fix list_directory API
- Fix CI build: portable include path, remove hardcoded local path
- Remove boot display test (color bars + 1.5s delay)
- Show identity hashes on NodesScreen (colon-formatted, matching own identity display)
- Show node names in MessagesScreen and MessageView instead of raw hex
- Add message status indicators in chat (*/!/~ for sent/failed/queued)
- Fix LXMF send: retry Identity::recall() up to 5 times before failing
- Add LXMF logging throughout send/receive/queue drain
- Remove Alt+IJML arrow key mapping (obsolete with trackball)
- Filter own node from discovered nodes list
- Update troubleshooting docs with SetModulationParams STDBY fix