Commit Graph

52 Commits

Author SHA1 Message Date
17a99ddd54 Pinned espressif32 platform to 6.5.0 as a workaround for compilation issues 2026-04-26 15:11:43 +03:00
eb827f5a60 Added Heltec V4.3 support/FEM autodetection 2026-04-26 15:10:54 +03:00
bc60028852 Added Heltec V4.3 support/FEM autodetection 2026-04-26 14:08:23 +03:00
0ef379595f Updated version 2026-04-26 14:07:17 +03:00
185d15cbaf Removed log 2026-04-26 13:30:38 +03:00
b728ca3c75 Add TXEN pin control 2026-04-26 13:29:54 +03:00
c15afa9819 Add TXEN pin control 2026-04-26 13:29:54 +03:00
192a008150 I2C pin change for beta board 2026-04-26 13:29:54 +03:00
c827989f43 Ignore built firmware binaries 2026-04-26 13:29:54 +03:00
6115cd6b84 Merge stashed changes; use upstream flash.py 2026-04-26 13:29:50 +03:00
James LaFarge
c84006da8a chore: checkpoint current changes 2026-04-16 12:01:05 -04:00
James L
3157b8e4a8 v1.0.23: Show node public hash in WiFi config portal
Add Reticulum destination hash indicator at the top of the captive-portal
config page so users can identify the device.

- Store the 32-char hex destination hash in RTC_NOINIT memory after RNS
  starts on a normal boot (survives software reboots into config mode)
- BoundaryConfig.h reads the RTC value and renders a styled hash box at
  the top of the HTML page, above the config form
- Falls back to a friendly placeholder if the device has never completed
  a normal boot (hash not yet assigned)
- Rebuild precompiled firmware for Heltec V3 and V4 boundary variants
2026-03-20 23:08:03 -04:00
James L
b3b6cd4302 Fix flash utility compatibility and rebuild firmware binaries 2026-03-15 19:57:17 -04:00
James L
7e56611fe6 Add AI development note to README 2026-03-15 17:54:11 -04:00
James L
56c1a6b881 Normalize release binary file modes 2026-03-14 12:19:11 -04:00
James L
79cb2d49e8 Add transport mode notes and config updates 2026-03-14 12:18:37 -04:00
James L
d8c925769d v1.0.22: Update precompiled firmware binaries for V3 and V4 2026-03-11 21:43:25 -04:00
James L
300676e5ae Add SF=5 option to config portal spreading factor dropdown 2026-03-11 21:42:24 -04:00
James L
d49c55a843 v1.0.21: Update precompiled firmware binaries for V3 and V4 2026-03-11 21:35:56 -04:00
James L
85d8fc7f78 Set default screen blank time to 5 minutes and added SF=5 as an option 2026-03-11 21:14:25 -04:00
James L
949c13c7b1 feat: add LED indicators and headless mode support for V3/V4
- Detect missing OLED at boot, set headless_mode flag
- LED solid: normal operation (radio online)
- LED fast blink: button held >5s (entering WCC config mode)
- LED slow breathe: WiFi Captive Configure portal active
- Allow 1-3s button press in WCC mode to power off
- Next boot after WCC power-off skips config portal (unless unconfigured)
- LED indicators active on both V3 and V4, with or without display
- Clean up LED PWM on deep sleep
2026-03-08 13:59:25 -04:00
jrl290
8db47d4d01 Clarify support for Heltec WiFi LoRa 32 V4 and V3
Updated README to clarify support for Heltec V4 and V3.
2026-03-06 14:50:50 -05:00
James L
ed36e792f2 Default display blanking to 10 minutes (enabled) 2026-03-05 23:38:39 -05:00
James L
42f0eec7b1 Rename to RTNode-HeltecV4, replace 'boundary' with 'transport' in docs
- Rename project from RNodeTHV4 to RTNode-HeltecV4
- Update GitHub repo URL, firmware binary names (rtnode_heltec_v4.bin, rtnode_heltec_v3.bin)
- Replace 'boundary node' with 'transport node' in README and flash.py descriptions
- Update OLED title bar to 'RTNode'
- Bump version to v1.0.18
2026-03-05 23:33:18 -05:00
James L
e33008cf86 fix: V4 also uses DIO, boot monitor on all full flashes, find ~/.local/bin/esptool 2026-03-01 19:49:25 -05:00
James L
8ce5ba2d06 remove temp commit msg file 2026-03-01 19:27:52 -05:00
James L
c2119edc40 Fix V3 bootloop: DIO flash mode, auto-verify, boot monitoring
- V3 board profile defaults to DIO flash mode (QIO fails on some flash chips)
- flash.py: auto-verify on --erase/--full, post-flash boot monitoring with
  auto-DIO retry on bootloop detection
- flash.py: erase keeps device in download mode (--after no_reset) to prevent
  race condition on re-entry
- flash.py: remove --dio/--verify flags (now automatic), hidden --flash-mode
  for power users
- RNode_Firmware.ino: release BT memory (~70KB) on V3 boundary where BT is
  compile-time disabled
- RNode_Firmware.ino: add WDT resets throughout setup() to prevent timeout
  during long init sequences
- RNode_Firmware.ino: fix while-not-Serial blocking on V3 (no USB-CDC)
- RNode_Firmware.ino: init bt_devname from WiFi MAC when BT disabled
- RNode_Firmware.ino: bootloop detection via RTC_NOINIT_ATTR -- forces config
  portal after 5 rapid reboots
2026-03-01 19:27:22 -05:00
James L
7b71181378 v1.0.17: flash.py - app detection + clean flash flow
- Add check_app_on_device(): reads 256 bytes from APP_ADDR (0x10000),
  if all 0xFF (blank flash) forces full flash automatically
- Restructure flash decision flow:
  1. Detect board (reboot + flash_id)
  2. Check if app exists on device -> no app = full flash
  3. Check partition table matches -> mismatch = full flash
  4. Ask 'Erase flash before writing?' -> Y = full flash
  5. Full flash: merged binary at 0x0000
  6. Normal update: extract app from merged, flash at 0x10000
- Remove old confusing erase/partition prompts
- Settings (NVS/EEPROM) preserved on normal updates, never accidentally wiped
2026-02-28 16:12:02 -05:00
James L
4b28c657e3 v1.0.16: Auto-detect partition table mismatch before flashing
- Read device partition table via esptool read_flash before app-only flash
- Compare against expected partitions.bin from PIO build
- On mismatch, automatically upgrade to full flash (mandatory)
- Prevents bricked devices when flashing over different firmware
2026-02-28 15:30:01 -05:00
James L
3a511e8a11 v1.0.15: Default TX power to board PA_MAX_OUTPUT
- Add PA_MAX_OUTPUT define: V3=22, V4=28, default=20
- Captive portal TX power field now defaults to board max
2026-02-28 15:21:34 -05:00
James L
a3ea18b4a7 v1.0.14: Display blanking config in captive portal
- Add Options section to captive portal with display blanking dropdown
- Options: Never, 1, 5, 10, 30, 60 minutes
- Change EEPROM blanking value from seconds to minutes (supports up to 255 min)
- Update Display.h and Utilities.h to interpret stored value as minutes
- Default blanking timeout changed from 15s to 1 minute
2026-02-28 15:15:21 -05:00
James L
5c153e56dc flash.py: Auto-download from GitHub with cache, add --release/--offline flags
Default behavior now checks GitHub for the latest release and downloads
firmware if the cache is empty or outdated. Cached binaries are stored
in .firmware_cache/{board}/ with SHA-256 integrity verification.

New flags:
  --release TAG  Flash a specific release version
  --offline      Skip online check, use cached/local firmware only

Removed --download flag (downloading is now the default).
Added .firmware_cache/ and rnodethv3_firmware.bin to .gitignore.
2026-02-28 15:00:40 -05:00
James L
f042dd5f71 v1.0.13: Fix path discovery starvation and remove redundant announce echo blocking
Immediate PATH_RESPONSE for local clients: On ESP32, continuous TCP
backbone data can starve the jobs() loop for many seconds, causing
path discovery timeouts for local TCP clients. When a local client's
path request is satisfied by a cached announce, send the PATH_RESPONSE
immediately rather than queuing it for the next jobs() cycle.

Remove boundary-mode announce echo blocking: The boundary-specific
code that prevented backbone announces from overwriting LoRa paths
was redundant (the standard random_blob check already prevents echoes)
and harmful (it blocked TCP clients from learning backbone paths and
prevented correct transport routing for LINKREQUESTs).
2026-02-28 15:00:40 -05:00
James L
1122e9a0ee v1.0.12: Fix link MTU clamping, echo-back prevention, oversized frame detection
MTU Clamping (Bug 8a): Clamp link MTU signalling in LINKREQUEST packets
when forwarding through transport node, matching Python reference impl.
Without this, TCP endpoints negotiate 8192-byte segments that exceed the
V3's 1064-byte HDLC buffer, causing silent truncation and permanent
resource transfer stalls at ~70%.

Fixed MTU declaration (Bug 8b): Set FIXED_MTU=true on TcpInterface so
Transport uses HW_MTU for clamping decisions.

Oversized frame detection (Bug 8c): Track truncated HDLC frames and
drop them with a diagnostic log instead of silently delivering corrupt
data to Transport.

Echo-back prevention (v1.0.10): Track which TCP client originated each
inbound frame and skip that client in send_outgoing() to prevent
flooding TCP buffers.

Register local client interface: Enable Transport forwarding of
announces, link packets, and proofs to TCP clients.

Document all discovered microReticulum bugs in MICRORETICULUM_BUGS.md.
2026-02-28 15:00:40 -05:00
James L
4e5d4ee8ad v1.0.8: Fix heap exhaustion from unbounded random_blobs
Root cause: Python Reticulum trims random_blobs per destination entry
(MAX_RANDOM_BLOBS=64 in-memory, PERSIST_RANDOM_BLOBS=32 on disk).
The C++ firmware had these constants defined but NEVER enforced them,
causing unbounded growth. With 21 paths x 60+ blobs x ~90 bytes each,
the destination table alone consumed ~57KB of the ESP32 324KB heap.

Fixes:
- Trim random_blobs after insert (matching Python behavior)
- Trim random_blobs on deserialization from flash
- Trim random_blobs to PERSIST_RANDOM_BLOBS on serialization
- Enforce _path_table_maxpersist when writing path table (was declared
  but never used - write_path_table saved everything)
- Reduce MCU constants: MAX_RANDOM_BLOBS 64->16, PERSIST_RANDOM_BLOBS 32->8
- Reduce path_table_maxsize 128->24, maxpersist 32->12
- Add memory diagnostic after path table load
- Trim loaded paths to maxsize on startup via cull_path_table()

Results: destination_table 21KB->5.8KB, free heap 63K(22%)->156K(49%)
2026-02-28 15:00:40 -05:00
James L
59784a34fd v1.0.7: Fix LocalTcpInterface mode — AP→GATEWAY to allow announce rebroadcasts
MODE_ACCESS_POINT unconditionally blocks announce broadcasts in
Transport::outbound(), preventing local TCP clients from discovering
each other. Changing to MODE_GATEWAY allows announces to flow through
send_outgoing() which broadcasts to all connected clients.

Root cause: receiver's announce was stored in announce_table but never
rebroadcast on LocalTcpInterface, so sender could never find a path.
2026-02-28 15:00:40 -05:00
James L
8184000d17 v1.0.6: Fix link establishment through boundary node
Bug fixes:
- Fix path_request_handler hops: use DestinationEntry._hops instead of
  stale cached announce_packet.hops(). The cached packet retains its
  original wire hops (pre-increment), but Python Transport.py explicitly
  overwrites packet.hops from path_table after retrieval (line 2736).
  This caused PATH_RESPONSE to report fewer hops than actual, making
  the sender's expected_hops too low, which caused LRPROOF hop-count
  validation to silently fail. (ROOT CAUSE of link timeout)

- Fix std::map::insert() no-op: erase before insert at 3 locations in
  _announce_table. Unlike Python dict assignment, C++ map::insert()
  does not overwrite existing keys. This prevented announce table
  updates from taking effect. (Caused PATH-RESP delivery failure)

- Defer packet hash filtering for link table entries and LRPROOF
  packets. Matching Python Transport behavior (line 1544), packets
  belonging to active links are not added to the filter hashlist
  until link transport processing determines it is our turn to
  forward them. Prevents premature filtering that breaks link transport.

- Pass DestinationEntry and LinkEntry by reference instead of by value
  to avoid stale copies and unnecessary allocations.

- Add link_table check before requesting paths for link_id destinations.
  Link data packets are handled by link transport, not standard path
  lookup, so spurious path requests are avoided.

- Add culling for _held_announces (60s timeout, cap 32) and
  _boundary_local_addresses to prevent unbounded memory growth.

- TcpInterface: detect and log partial writes.
2026-02-28 15:00:40 -05:00
jrl290
888e6ef313 Update README.md 2026-02-26 14:35:40 -05:00
jrl290
41a9e5bc94 Fix formatting in README.md diagram 2026-02-26 14:35:08 -05:00
James L
5e0e3f538a v1.0.5: Heltec V3 support, heap stability fix, TCP reconnection improvements
- Add Heltec WiFi LoRa 32 V3 board support (8MB flash, 8MB PSRAM)
  - New heltec_V3_boundary build environment in platformio.ini
  - Board auto-detection in flash.py (8MB=V3, 16MB=V4)
  - V3 board definition in Boards.h
- Fix heap exhaustion causing watchdog reboots every ~70 min
  - Lower boundary_mentioned_addresses cap from 512 to 200
  - Heap now stable at ~38KB free (was draining to 0)
- TCP reconnection improvements in TcpInterface.h
  - SO_LINGER(0) for clean socket teardown
  - 10-minute read timeout prevents zombie connections
  - Defensive client cleanup on accept
- Add heap telemetry instrumentation (HEAP-TEL) for monitoring
- Add level guards on TRACE/DEBUG macros in Log.h
- Update README for dual V3/V4 board support
2026-02-26 14:32:18 -05:00
James L
990649d810 Fix heap exhaustion: enable PSRAM allocator + bound all tables + auto-reboot watchdog
Root cause: heltec_V4_boundary build was missing -DRNS_USE_TLSF=1 and
-DRNS_USE_ALLOCATOR=1 flags, causing ALL C++ new/delete to use internal
SRAM (239KB) instead of the PSRAM-backed TLSF pool (~1.6MB). Transport
data structures consumed internal heap until WiFi driver could not
allocate RX buffers (ESP_ERR_NO_MEM).

Changes:
- platformio.ini: Add TLSF/allocator flags to heltec_V4_boundary env,
  re-enable NDEBUG
- Transport.cpp: Add periodic culling of _path_requests (was unbounded,
  grew one entry per unique destination forever). Cull entries older than
  DESTINATION_TIMEOUT. Also cull _pending_local_path_requests for removed
  interfaces, and fix missing .erase() (Python .pop() equivalent).
- RNode_Firmware.ino: Replace WiFi watchdog halt-serial with auto-reboot.
  Add heap pressure check (reboot if free heap < 20KB). Increase WiFi
  grace period from 5s to 15s. Remove orphaned boundary_done label.
2026-02-25 13:48:10 -05:00
James L
8ee8e86563 Add WiFi disconnect watchdog + re-enable debug logging
- Remove -DNDEBUG to get LOG_TRACE output for WiFi disconnect investigation
- Add WiFi watchdog in main loop: detects WiFi loss, prints diagnostics
  (WiFi status, RSSI, heap, TCP state, bridge stats), then halts serial
  output after 5s grace period so operator can read the last log lines
- Device keeps running as LoRa repeater even when serial is frozen
- Reboot required to resume serial output
2026-02-25 10:23:36 -05:00
James L
50e392c45b flash.py: default to app-only flash, preserving settings 2026-02-23 22:49:45 -05:00
James L
5077aa3829 Boundary mode: performance optimizations + boundary filter
Performance optimizations:
- Move TLSF allocator pool to PSRAM (frees ~170KB internal SRAM)
- Raise TCP_IF_MAX_CLIENTS from 4 to 8 in BOUNDARY_MODE
- Raise path_table_maxsize from 48 to 128, persist from 16 to 32
- Add -DNDEBUG to boundary build: compiles out TRACE/DEBUG macros
- Log level defaults to LOG_VERBOSE when NDEBUG defined
- Serial baud 115200 -> 921600 in BOUNDARY_MODE (reduces CPU blocking)

Previous changes included in this commit:
- Comprehensive boundary filter with transitive whitelisting (7 checks)
- destination_table erase+insert fix (std::map::insert no-overwrite bug)
- Backbone-to-backbone routing guard in next-hop forwarding
- KISS serial output disabled for boundary mode
- flash.py updates for boundary mode support
2026-02-23 22:43:54 -05:00
James L
5ed70dcca9 v1.0.0: Boundary mode with bidirectional LoRa↔TCP transport
Vendor microReticulum library with boundary mode transport fixes:
- Two-whitelist system gates backbone traffic (local addresses +
  mentioned addresses from local devices)
- Allow control_hashes and local destinations through boundary filter
  (fixes backbone→LoRa path discovery)
- Fix get_cached_packet() to call unpack() instead of update_hash()
  (fixes empty destination_hash in path responses)
- LRPROOF Identity::recall null guard
- remaining_hops HEADER_1/BROADCAST fix for final-hop delivery
- PROOF packets excluded from boundary wrapping
- Iterator invalidation fix in transport table cleanup
- is_backbone flag replaces string matching for interface identification

Firmware changes:
- Set is_backbone(true) on backbone TCP interface
- Rename default TcpInterface name to BackboneInterface
- Update comments for dual-use TcpInterface (backbone + local AP)
- Use vendored lib/microReticulum instead of PlatformIO registry
2026-02-23 18:08:29 -05:00
James L
e741d1cd64 feat: add interactive erase prompt and 1200 baud bootloader reset option
- Erase flash prompt: asks user before flashing (in addition to --erase flag)
- 1200 baud reset: opens port at 1200 baud with DTR toggle to force
  ESP32-S3 into download mode when device is stuck/unresponsive
- Re-scans serial ports after reset since port name may change
2026-02-22 21:54:28 -05:00
James L
adc330dc15 fix: flash.py binary detection, boot_app0 discovery, add --erase flag
- Fix merged binary detection: check partition table magic (0xAA50) at
  offset 0x8000 instead of bootloader magic (0xE9) at offset 0 — both
  merged and app-only binaries start with 0xE9, causing app-only
  binaries to be flashed at wrong address
- Fix boot_app0.bin discovery: handle versioned PlatformIO package
  directories (e.g. framework-arduinoespressif32@3.20009.0)
- Add --erase flag: full flash erase before writing (recommended for
  recovery from corrupted flash)
2026-02-22 21:47:00 -05:00
James L
760e92f186 Fix flash address detection: use bootloader magic byte, not file size
The merged binary (1,257,328 bytes) was below the 1.5MB size threshold,
causing it to be misidentified as app-only and flashed at 0x10000 instead
of 0x0. This corrupted the flash layout and bricked the device.

Now checks for ESP32 bootloader magic byte (0xE9) at offset 0 to reliably
distinguish merged binaries from app-only binaries, regardless of size.
2026-02-22 21:24:06 -05:00
James L
8561e9d5ba Fix esptool discovery: prefer pip-installed over bundled
Bundled esptool.py runs via sys.executable, which may be a Python
that lacks pyserial (e.g. miniconda). Reorder find_esptool() to
prefer pip-installed esptool first (handles its own deps), and
only fall back to bundled/PlatformIO scripts if pyserial is
importable. Give a clear error message if neither works.
2026-02-22 21:19:59 -05:00
James L
840f51da16 Add flash utility, display fixes, and comprehensive README
- flash.py: standalone flash utility with serial port listing, merge-bin,
  GitHub Releases download, and esptool flash support
- Display.h: hide LAN row when Local TCP disabled, show local TCP port
  instead of backbone port
- README.md: comprehensive documentation — Quick Start with 3 flash options,
  OLED display layout, interface modes, routing customizations, path table
  fix, interface name uniqueness, hardware rationale (PSRAM/flash)
- Release/boot_app0.bin: bundled for flash.py standalone use
- .gitignore: exclude merged firmware binary build artifact
2026-02-22 20:58:44 -05:00