Add Heltec Mesh Node T114 support (nRF52840 + SX1262) - #107
Open
Giak88 wants to merge 11 commits into
Open
Conversation
Add LXMF-based GPIO control for RNode hardware
- Add battery telemetry in Sideband Telemeter format (SID_TIME + SID_BATTERY) attached to every LXMF reply, so Sideband natively displays battery data - Add BATTERY and ANNOUNCE commands, remove GPIO pin control from XIAO build - Fix XIAO nRF52840 battery: correct voltage divider (2.957x), hardware charging detection via BQ25101 /CHG pin + NRF_POWER USB register - Add LittleFS corruption guard for nRF52840 InternalFS - Change default LXMF node name to RTransport-XXXX (random per compile) - Make transport announce interval runtime-configurable - Fix flash script: auto-activate venv, relaxed device check for RNS transport - Add msgpack helpers (pack_bool, pack_nil, pack_fixint, pack_float32, pack_uint32) - Enable HAS_GPIO_CONTROL for xiao_nrf52840 in platformio.ini
Board support for Seeed XIAO ESP32-S3 + Wio-SX1262 Meshtastic Kit
(B2B connector variant):
- New board definition BOARD_XIAO_ESP32S3 (0x53) with B2B pin mapping
(CS=GPIO41, RST=GPIO42, DIO1=GPIO39, BUSY=GPIO40, RXEN=GPIO38)
- Product code PRODUCT_XIAO_ESP32S3 (0x12), model MODEL_13 (0x13)
- PlatformIO env with 8MB flash, default_8MB partition table
- Custom SPI init in sx126x.cpp for ESP32-S3 pin assignment
- TCXO 1.8V configuration for Wio-SX1262
- Flash script with esptool USB reset, erase, provision, TNC config
- LED functions and EEPROM validation entries for the new board
- IS_ESP32S3 flag used for WDT header selection (hal/wdt_hal.h)
Fix LittleFS filename length causing transport cache failures:
- ESP32 LittleFS has an effective filename limit well below the
configured CONFIG_LITTLEFS_OBJ_NAME_LEN=64. Cache filenames
(SHA256 hex hashes, 64 chars) exceeded this limit, causing all
packet cache writes to silently fail with "no permits for creation".
- Set FS_NAME_MAX=32 to truncate cache filenames to 32 chars (128-bit
hash prefix), which is still collision-proof for cache purposes.
- This was the root cause of transport nodes failing to forward
non-announce packets: without cached announce data, the transport
node couldn't resolve paths or answer path requests from peers.
- Added FS.mkdir("/cache") call during init to ensure the cache
directory exists on fresh filesystems.
Debug transport mode (compile-time flag):
- Added DEBUG_TRANSPORT flag that forces RNS logs to serial even
when a KISS client is connected, and sets log level to TRACE.
- Enables full visibility into transport forwarding decisions.
Test tooling:
- test_transport.py: Python script that injects a forced transport
path and sends a HEADER_2 link request through the transport node
to verify forwarding works end-to-end.
The PlatformIO mklittlefs tool is compiled with LFS_NAME_MAX=32, so any filesystem image it creates has name_max=32 baked into the superblock. When the ESP32 runtime mounts this filesystem, it reads the superblock and downgrades its own name_max from 255 to 32, even though the runtime library supports 255-char filenames. This caused all cache file writes to fail silently because the SHA256 hex hash filenames are 64 characters long. Fix: on boot, test if a 64-char filename can be created. If not, reformat the filesystem (which creates a new superblock with name_max=255 from the runtime default), then restore identity files from the pre-reformat read. Raise FS_NAME_MAX from 32 to 64 to use full SHA256 hashes without truncation.
A brownout during a flash write could corrupt LittleFS metadata at a level below the superblock. Adafruit_LittleFS::begin()'s auto-format recovered only mount failures, so subsequent file ops tripped an assertion in lfs.c:1144 (head block pointer out of range) and abort()ed into a permanent ~3s reboot loop. Recovery now layered: - Build with -DLFS_NO_ASSERT so LFS returns LFS_ERR_CORRUPT instead of abort()ing on internal sanity checks - eeprom_begin() split into mount + eeprom_open_files() steps; either failing triggers InternalFS.format() + retry, with all file handles closed on the failure path so eeprom_read() is a safe no-op - FileSystem::init() (RNS side) mirrors the format-and-retry on the InternalFS mount path - RNS startup, identity-restore, and /destination_table read are gated on fs_ready from filesystem.init() - Serial.flush() after each early boot print so a future failure is pinpointable from the serial log - Identity keys preserved via the existing raw-flash backup at 0xEC000, outside the LittleFS region Also includes accumulated pre-existing changes: no-activity watchdog, GPIO control over LXMF, XIAO ESP32-S3 board support tweaks, local microReticulum library copy under lib/, telemetry destination removal, and CUSTOM_BOARDS.md updates.
…ial) Without this, the T114 hung forever in setup() waiting for a USB host that never arrives when running on battery alone. RAK4631, RNode NG22 and XIAO nRF52840 were already excluded for the same reason.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds support for the Heltec Mesh Node T114 (nRF52840 + SX1262), tested
standalone as a Reticulum transport node — both via USB and running on
battery alone.
Verified on hardware
or receive usably without it (
enableTCXO()in sx126x.cpp)excluding the board from the unconditional
while (!Serial);inRNode_Firmware.ino (same fix already applied to RAK4631, RNode NG22,
XIAO nRF52840)
non-zero
paths/pin/poutin periodic statsNot independently verified
EEPROM_SIZE 296, inherited from the XIAO block by analogy, notmeasured against T114's actual InternalFS constraints
as a workaround — the T114 has no dedicated model identity yet
Known limitation (not board-specific)
Direct LXMF message reception over a Link currently fails — links
establish correctly (~180ms) and Resource chunks arrive at the radio
layer, but the receive-side Resource protocol (
Resource::accept(),proof generation) is not implemented in the underlying microReticulum
library. Filed upstream as attermann/microReticulum#77. Transport and
forwarding are unaffected and fully functional.
Also fixes (unrelated to T114, hit while building from clean checkout)
CryptoandArduinoJsonlib_deps declarations