Every message send on the device was deterministically rebooting it: send_message() ran the full pipeline (identity recall, message construction, RouterLock-scoped router admission, and LittleFS persistence) synchronously on LVGL's 8 KiB task while holding the LVGL mutex. On this device's degraded filesystem a single save takes ~7s of 400ms-2s per-op gaps, tripping the 5s LVGL deadlock guard and asserting at LVGLLock.h:45 (assert failed: LVGL mutex timeout (5s)). The receive path already carries the fix pattern for exactly this failure class (see on_message_received); the send path never got it. Restructure the send path as a mailbox handoff, following the existing CallStartMailbox / LocationShareCommandMailbox precedent: - send_message() (LVGL task) now only validates and publishes (destination, content, source) into a mutex-guarded single-slot OutgoingSendMailbox. No router lock, no I/O, no message construction. - update() services the mailbox in service_pending_sends() on the main loop, before the big LVGL_LOCK() — the only place in the send path that may take the router lock, block on admission, or wait on LittleFS. - On acceptance, a brief LVGL_LOCK in apply_outbound_result() commits the UI (add_message / clear_composer / compose->chat navigation, route-guarded). The admitted packed form is unpacked for display with incoming/state flags restored. - On rejection (storage error, router busy, queue full) the user's input is retained for retry, matching the old behavior. The 500-char UI cap bounds the mailbox payload. Build tdeck SUCCESS, 170/170 contract tests pass.
Pyxis
An LXMF and LXST client firmware for T-Deck, built on a highly modified fork of microReticulum
Very much WIP, don't expect stability :)
Features
Reticulum transport over:
- RNode-compatible LoRa
- AutoInterface (local wifi)
- TCP Client
- BLE Interface (barely working if at all)
Other features:
- GPS-synced time
- One really annoying beep when you get a new message (user toggle)
- View the announce stream
- Choose a propagation node (and sync with it) (fixed in v0.2.1)
- Set auto announce timer
- Light up keyboard (user toggle)
Will crash in about 5 minutes of normal use (sorry)I had 5d uptime on v0.2.0 with BLE disabled- Make LXST voice calls (codec2 only, quality sounds horrible coming out the other end in Columba, needs work)
Flashing
The easiest way to get Pyxis running is the web flasher, which downloads release firmware from this repository's releases and verifies each image's SHA-256 digest against the release metadata.
For esptool (or any other tool that writes raw flash), each release also publishes a merged binary (pyxis-<tag>-merged.bin) that contains the bootloader, partition table, OTA selector, and application at their fixed offsets. Provision a T-Deck Plus (8 MB flash) with:
esptool.py --chip esp32s3 erase_flash
esptool.py --chip esp32s3 write_flash 0x0 pyxis-<tag>-merged.bin
Merged binaries are for first install / provisioning. Flashing one overwrites every flash region, including NVS (settings, identity) and the LittleFS partition (messages, paths, maps). To update an existing device without losing data, flash firmware.bin to 0x10000 only, or use the Columba-compatible pyxis-<tag>.pyxis.zip update package.
Why "Pyxis"
Pyxis, latin for "compass," is a constellation in the southern sky depicting a mariner's compass. Small but essential, the compass ensures every message finds its destination - even when the path is uncertain.