T-Deck LXMF Messenger v1.1.0
T-Deck LXMF Messenger v1.1.0
Single-flash firmware image for the LilyGO T-Deck v1. Everything is in the one file — no additional uploads needed.
Forty commits since v1.0.0. The headline additions are two entirely new tabs, voice messaging, and a run of µReticulum transport fixes that made opportunistic delivery work for the first time.
New
- NomadNet page browser (NET tab) — fetch and render micron (
.mu) pages from NomadNet nodes over LoRa or TCP, with colours, headings and clickable links. - rnsh shell client (SSH tab) — interactive shell against rnsh listeners over Reticulum Link + Channel. The terminal composites rows into a framebuf rather than issuing an SPI transaction per glyph, giving up to 80×32 on a 320px panel and still repainting faster than the 40×12 screen it replaced.
- Voice messages — record with the mic key, encoded Codec2 3200 bps and sent as LXMF
FIELD_AUDIO, interoperable with MeshChat and Sideband. Getting Codec2 encoding to work on ESP32 needed a full double-precision LPC/LSP pipeline — single-precision finds 0 of 10 LSP roots and outputs silence. - Cyrillic display support — CP866-layout font with glyph transcoding.
- Mesh clock, per-peer routes, ping, and a live radio/mesh stats page in settings.
- Keyboard backlight toggle (needs keyboard MCU firmware from 2024-12-25 or newer).
Fixed
- Opportunistic (single-packet) messaging never worked between direct-range nodes. The packet builder wrapped direct sends in a transport header addressed "via" the destination itself, so every correct receiver silently discarded them as another relay's traffic. Link-based delivery worked throughout, which disguised this as RF trouble for weeks.
- Attachments arrived looking like plain text. An image sent with a caption showed no marker and no clue the row was clickable; a JPEG from MeshChat was dropped outright, because MeshChat labels images by MIME subtype (
"jpeg") and the receive path only accepted"jpg". Format now comes from the payload's magic bytes, markers lead the caption, file attachments are listed and playable/viewable where possible, and anything undecodable still says what it is rather than vanishing. - Message identity under history trim. Messages were tracked by list position, so once a chat hit its 30-message cap every later message collapsed onto the same index: delivery ticks landed on the wrong row and image clicks opened the wrong picture.
- Half-duplex link establishment (LRRTT resend + DIRECT delivery retry) and outgoing-resource watchdog — unanswered advertisements retry, stalled transfers fail cleanly instead of wedging the link.
- WiFi failures surface in the UI, and a failed scan can no longer take LoRa down with it.
Changed
- Firmware layout. The five natmods (ed25519, bz2, codec2, tjpgd, webp) are now built into the app image as C modules, executing from flash instead of competing for internal IRAM. The factory partition grew 2 MB → 3 MB and the filesystem shrank 6 MB → 5 MB, so this is not an in-place upgrade from v1.0.0 — the partition table moved.
- The system font is Spleen 8×16 (BSD-2) rather than the 1981 VGA ROM font.
- WiFi/LWIP buffers moved to PSRAM.
First boot
The image carries no identity or configuration of its own — just main.py, tdeck_config.py and logo.jpg. On first boot each device creates /rns, generates its own X25519 + Ed25519 keypair, and names itself T-Deck-XXXX from the last four hex digits of its WiFi MAC, so a batch of freshly flashed devices are distinguishable in each other's node lists instead of all announcing as "T-Deck". Rename it from Settings at any time; that persists and overrides the default.
Serial logging is off by default (DEBUG = 0 in tdeck_config.py). Set it to 1 for app messages or 2 for the full Reticulum debug log when something needs investigating.
What's included
- MicroPython v1.24.1 for ESP32-S3 with Octal SPIRAM
- ST7789 C display driver (DMA-accelerated, Russ Hughes st7789_mpy)
- Frozen in ROM: UI, sound, ES7210 mic driver, NomadNet browser, rnsh client, fonts, full µReticulum stack
- Built into the app image: ed25519, bz2, codec2, tjpgd, webp
- On the filesystem:
main.py,tdeck_config.py,logo.jpg
Flashing
Requirements: esptool (pip install esptool)
1. Enter download mode:
Short GPIO0 to GND while pressing the reset button on the T-Deck, then release both. On the T-Deck, GPIO0 is the trackball click — hold the trackball down, tap reset, release.
2. Flash:
esptool --chip esp32s3 --port PORT erase-flash
esptool --chip esp32s3 --port PORT write-flash 0x0 tdeck_firmware.binReplace PORT with your serial port:
- macOS:
/dev/cu.usbmodem* - Linux:
/dev/ttyACM0or/dev/ttyUSB0 - Windows:
COM3(check Device Manager)
Upgrading from v1.0.0: this rewrites the whole flash, including the filesystem — your node identity at /rns/identity goes with it and your LXMF address will change. Back it up first (mpremote cp -r :rns ./rns-backup) and copy it back after flashing if you want to keep your address.
Building it yourself
pip install esptool littlefs-python
cd tools && bash build_firmware.shProduces tools/firmware_build/tdeck_firmware.bin. First build takes ~20 minutes (clones ESP-IDF v5.2.3, MicroPython v1.24.1 and st7789_mpy, installs the Xtensa toolchain); rebuilds take ~30 seconds.