Added support for Heltec Wireless Stick Lite V3 (WSL V3)#35
Conversation
Add build environment for the HTIT-WSL_V3, which is hardware-identical to the Heltec WiFi LoRa 32 V3 but lacks an OLED display. Uses a NO_DISPLAY build flag to conditionally disable HAS_DISPLAY in the V3 board block. Also adds missing heltec32v3 provisioning case to extra_script.py. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds full support for the Seeed XIAO nRF52840 with the Wio-SX1262 expansion board, including TNC (standalone transport) and HOST (KISS modem) modes. Board support: - Boards.h: BOARD_XIAO_NRF52840 (0x52), pin mapping, TCXO, RF switch, active-low LED, VALIDATE_FIRMWARE disabled (Seeed bootloader incompatibility) - platformio.ini: xiao_nrf52840 and xiao_nrf52840_lowpower environments using Seeed platform (https://github.com/Seeed-Studio/platform-seeedboards.git) - extra_script.py: is_nrf52_platform() helper covers seeedboards; xiao env provisioned with RAK4631 product/model bytes until dedicated ID exists - LowPower.h/cpp: runtime power management (PERFORMANCE / BALANCED / LOW_POWER) - Utilities.h: XIAO LED functions, eeprom_model_valid() XIAO case, written_bytes initialised to 0 (was 4, causing spurious EEPROM flush), eeprom_conf_save() no longer gated on radio_online CSMA bug fixes (affected TNC mode on all SX1262 boards): - RNode_Firmware.ino medium_free(): added update_noise_floor() call alongside update_modem_status(). In TNC mode, queue_height>0 causes medium_free() to run every loop iteration, continuously refreshing last_status_update and starving check_modem_status() — the only previous caller of update_noise_floor(). With noise_floor stuck at -292, interference_detected was always true (any real RSSI > -281 dBm), blocking TX permanently and preventing led_rx_off() from ever being called. - sx126x.cpp dcd(): clear PREAMBLE_DET IRQ bit immediately on detection rather than after a 147 ms timeout. The bit is not routed to DIO1, so it was never cleared by handleDio0Rise(); under high-frequency CSMA polling spurious detections kept dcd=true. Software timer preserves the correct busy window; header detection resets the timer to prevent expiry mid-reception. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Supported Hardware section covering pin mapping, PlatformIO environments, build/flash procedure (DFU bootloader), rnodeconf configuration commands, and known-limitations notes (VALIDATE_FIRMWARE, provisional product ID). Update PlatformIO command line examples to include xiao_nrf52840 environment. Update roadmap to reflect completed power management and new board support. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Errata 15.4: SetPacketParams resets register 0x0736 to an incorrect IQ polarity default. Bit 2 must be SET for standard IQ after every SetPacketParams call, otherwise LoRa RX fails silently while TX works. Errata 15.1: Register 0x0889 bit 2 must be cleared for 500 kHz BW and set for all other bandwidths. The previous implementation was a no-op stub. Ported from markqvist/RNode_Firmware@ae04347 (PR markqvist#132 by GlassOnTin). Applies to all SX1262-based boards in this fork. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Downloads the latest release zip from GitHub, flashes via adafruit-nrfutil DFU, provisions EEPROM, and writes the firmware hash. Requires adafruit-nrfutil and rnodeconf on PATH. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…P, v1.86 - OCP_TUNED raised 0x18 → 0x28 across all boards (T-Beam SX1262, Heltec V2/V3/V4, T-Beam Supreme, global default) to match upstream headroom. - Heltec32 V4: runtime PA model detection (GC1109 vs KCT8103L) by probing LORA_PA_CSD at boot. Each PA gets its own gain table and LNA gain value (GC1109: 17 dB, KCT8103L: 21 dB). Replaces the previous compile-time LORA_PA_GC1109 flag with runtime lora_pa_model checks in begin(), beginPacket(), and receive(). - Heltec T114: turn TFT backlight off when display blanks, on when active. - Version bumped 1.85 → 1.86 to match upstream. Ported from markqvist/RNode_Firmware commits 9fd0ae3, fe594b2, 0c07c1b. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…L_V3 0x43) Hardware is identical to Heltec LoRa32 V3 (ESP32-S3 + SX1262 + TCXO) but without the OLED display. Defined as a proper separate board rather than using BOARD_HELTEC32_V3 + -DNO_DISPLAY, following the same pattern as all other boards in this firmware. Changes: - Boards.h: add BOARD_HELTEC_WSL_V3 constant (0x43) and full board config section with HAS_DISPLAY false and identical pin/modem/TCXO definitions - sx126x.cpp: add BOARD_HELTEC_WSL_V3 to TCXO 3.3V branch in enableTCXO() - Utilities.h: add BOARD_HELTEC_WSL_V3 to LED function definitions - platformio.ini: switch env to -DBOARD_MODEL=BOARD_HELTEC_WSL_V3, remove -DNO_DISPLAY, fix stale DUSTORE_* flags to RNS_PATH_TABLE_* - extra_script.py: add heltec32v3_wsl variant to provisioning (uses same rnodeconf product/model as V3: 0xC1/0xCA — identical hardware) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BOARD_HELTEC_WSL_V3 was missing from several per-board dispatch chains, causing the radio to stay offline: - sx126x.cpp preInit(): WSL V3 fell through to bare SPI.begin() without explicit pin arguments, so SX1262 SPI bus never initialised and the sync word check failed → modem_installed = false - Utilities.h eeprom_model_valid(): no case for WSL V3, so always returned false → "Invalid EEPROM configuration" printed at boot, hw_ready never set - Utilities.h eeprom_model_valid(): combined with BOARD_HELTEC32_V3 since both accept MODEL_C5 / MODEL_CA (identical provisioning bytes) Also add WSL V3 to Power.h battery/PMU init (same pins and ADC scaling as V3: pin_vbat=1, pin_ctrl=37, measurement factor 0.0041). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Adafruit nRF52 BSP hard-codes the LittleFS region to 7 pages (28 KB),
which severely constrains the microReticulum path table and microStore
segments on nRF52840-based boards. This commit lifts that limit to 32
pages (128 KB) for the XIAO nRF52840 envs without touching any other board.
## extra_script.py — pre-build InternalFS patcher
Adds patch_internalfs_for_xiao(env), called from the nRF52 env-setup block
at SCons script-import time (before any source is compiled). For the two
XIAO variants it locates InternalFileSystem.cpp inside the PlatformIO
framework-arduinoadafruitnrf52 package and rewrites two #define lines:
LFS_FLASH_ADDR: 0xED000 → 0xD4000 (region base, nRF52840 branch only)
LFS_FLASH_TOTAL_SIZE: 7 pages → 32 pages (28 KB → 128 KB)
The patch is idempotent (regex-anchored; skips if already applied) and backs
up the original file to InternalFileSystem.cpp.xiao.orig on first run. A
RuntimeError is raised if the regex matches nothing and the file looks
unpatched, so a BSP upstream change fails loudly rather than silently
shipping a 28 KB FS. Region size is overridable per-env via the build flag
-DXIAO_INTERNALFS_PAGES=N (supported: 7, 16, 32, 64).
nRF52840 flash map after the patch (SoftDevice S140 v7.3.0):
0x00000–0x01000 MBR 4 KB
0x01000–0x27000 SoftDevice 152 KB
0x27000–0xD4000 Application 692 KB (was 792 KB; 100 KB donated to FS)
0xD4000–0xF4000 LittleFS 128 KB (was 28 KB)
0xF4000–0x100000 Bootloader 48 KB (Seeed/Adafruit — untouched)
No changes in Utilities.h, RNode_Firmware.ino, Boards.h or microStore;
all InternalFS.* call sites continue to work via the patched _InternalFSConfig.
Also bumps the post-DFU sleep from 5 s to 12 s so the new firmware has time
to mount (or format) the 128 KB FS before rnodeconf connects for provisioning.
## platformio.ini — XIAO env updates (both xiao_nrf52840 and xiao_nrf52840_lowpower)
- upload_port = /dev/ttyACM0
Pins the upload port explicitly, bypassing a crash in PlatformIO's
HWID auto-detection (board_config NoneType bug in platformio/device/finder.py
triggered by the Seeed platform's board JSON lacking hwids for 0x2886:0x0045,
the VID:PID the XIAO presents in normal mode). The board JSON's
use_1200bps_touch=true still fires automatically to trigger DFU.
- -DXIAO_INTERNALFS_PAGES=32 (replaces dead -DURTN_PATH_TABLE_MAX_RECS=25)
Documents the intended FS size explicitly and drives the patcher.
URTN_PATH_TABLE_MAX_RECS was never defined in the microReticulum source;
it was a no-op carried over from the varna9000 fork.
- -DRNS_PATH_TABLE_MAX=100 (replaces the dead flag; makes the cap explicit)
RNS_PATH_TABLE_MAX is the actual define in Transport.cpp (default 100).
128 KB of flash comfortably holds 100 persisted path entries; RAM usage
at boot is ~42 KB (17.6% of 237 KB), leaving ample headroom.
## .gitignore — exclude local tooling files
Adds CLAUDE.md, AGENTS.md, .claude/, implementation.md so that AI assistant
context files and design notes are never accidentally staged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a "Flash storage and RNS persistence" subsection under the XIAO hardware section explaining the 28 KB BSP limitation, the pre-build patcher approach, the resulting flash map, and how to verify the 128 KB region is mounted at runtime. Also documents the upload_port workaround for PlatformIO's HWID auto-detection crash on the Seeed platform. Adds -DXIAO_INTERNALFS_PAGES and -DRNS_PATH_TABLE_MAX to the Build Options section. Updates the Roadmap to mark the storage work done and add Option 2 (QSPI flash) as a future item. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
RNode_Firmware.ino:642 calls Transport::path_table_maxsize(URTN_PATH_TABLE_MAX_RECS) directly at startup, overriding the static initializer that RNS_PATH_TABLE_MAX controls. The previous commit used the wrong define; this corrects both envs (xiao_nrf52840, xiao_nrf52840_lowpower) and the README. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove f-strings and !!! print prefix from patch_internalfs_for_xiao() to match Attermann upstream conventions. Replace !!! with --- WARNING: prefix or raise for fatal paths. Remove hardcoded upload_port from both XIAO envs in platformio.ini — port is workstation-specific. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks for sharing how you enlarged the InternalFS to more than 28 KB! A little hacky, but definitely a workaround for now. This method also works fine on Heltec T114. Maybe this could be added for all nrf52-based boards. Did you have any problems with not having enough space for your program code with 32 pages reserved for InternalFS? PlatformIO still uses default values for its build summary (at least for me), so this info might not help to evaluate if there is enough space. Here is my memory summary from PIO: |
|
Thank you! Yeah it is extremely hacky... so if anyone has a better idea to workaround this limitation, I'd be very thankful! No, so far I haven't run into space issues, but it's extremely tight... Also note that the pio flash numbers are lying to your face: With 32 pages (128KB) InternalFS, you'd end up with roughly 31KB of headroom instead of 131KB! If your firmware.bin is exceeding the I'd suggest, if you're getting too close to the 712,704 bytes ceiling to drop the pages to 16 (XIAO_INTERNALFS_PAGES), so it'll be 64KB (it's still more than the stock 28KB FS size...), just to be safe. That's interesting... the patch should be xiao-specific and not apply to the T114 env, or did you first ran a build for the Xiao and then for the T114? I think a subsequent build would inherit the patch from the previous xiao build 😅 I probably need to put more work into this... |
|
Hi, thanks for your further explanation! And sorry for the confusion – I did not run your exact same script, which is indeed should be specific for xiao, but I used the same approach to extend the InternalFS storage for my T114. |
I´ve been using this on my WSL v3 for a couple of weeks now and it seems to be fine.
I'd appreciate if someone could review my changes. I used Claude Code for help as I was getting very rusty with Arduino based projects.
Thanks! Keep up the great work!