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.
This commit is contained in:
James L
2026-02-27 16:38:10 -05:00
parent 8184000d17
commit 59784a34fd
8 changed files with 3680 additions and 3 deletions

275
MICRORETICULUM_BUGS.md Normal file
View File

@@ -0,0 +1,275 @@
# microReticulum Bug Report
## 1. Copy-vs-Reference Bugs in Transport.cpp
### Summary
Several locations in `Transport.cpp` retrieve `LinkEntry` or `DestinationEntry` values from `std::map` containers **by copy** instead of **by reference**. Subsequent mutations (setting `_validated`, updating `_timestamp`) only affect the local copy — the actual map entry is never updated.
This is a Python→C++ porting issue: in Python, `dict[key]` returns a reference to the value, so `transport.link_table[link_id][0] = time.time()` mutates the dict entry in place. In C++, `(*iter).second` returns a copy when assigned to a non-reference variable.
### Bug 1a — LRPROOF handler: `_validated` never set on map entry (CRITICAL)
**File:** `Transport.cpp`, LRPROOF handling section
**Code (before fix):**
```cpp
LinkEntry link_entry = (*_link_table.find(packet.destination_hash())).second; // COPY
// ... later:
link_entry._validated = true; // Only updates local copy
```
**Impact:** The link_table entry's `_validated` stays `false`. The culling code in `jobs()` checks:
```cpp
if (link_entry._validated) {
if (OS::time() > (link_entry._timestamp + LINK_TIMEOUT)) { ... } // 15 minutes
} else {
if (OS::time() > link_entry._proof_timeout) { ... } // 6-18 seconds
}
```
Since `_validated` is never set to `true`, the entry is culled at `proof_timeout` (6 × hops = **618 seconds**) instead of `LINK_TIMEOUT` (15 minutes). All subsequent link data packets (resource chunks, keepalives, etc.) are silently dropped once the entry is removed.
**Symptom:** Resource transfers start successfully but fail after a few seconds. Link establishes, some data transfers, then all traffic stops. Affects both directions.
**Fix:** Change to reference:
```cpp
LinkEntry& link_entry = (*_link_table.find(packet.destination_hash())).second;
```
### Bug 1b — Link transport handler: `_timestamp` never refreshed (CRITICAL)
**File:** `Transport.cpp`, link transport handling section
**Code (before fix):**
```cpp
LinkEntry link_entry = (*link_iter).second; // COPY
// ... later:
link_entry._timestamp = OS::time(); // Only updates local copy
```
**Impact:** Even with Bug 1a fixed, the link_table entry's `_timestamp` is set once (at LINKREQUEST time) and never refreshed during ongoing link data forwarding. For long-running transfers exceeding `LINK_TIMEOUT` (KEEPALIVE=360s, STALE_TIME=720s, LINK_TIMEOUT=900s = 15 minutes), the entry is eventually culled and the transfer fails.
**Fix:** Change to reference:
```cpp
LinkEntry& link_entry = (*link_iter).second;
```
### Bug 1c — Standard inbound transport forwarding: `_timestamp` never refreshed
**File:** `Transport.cpp`, inbound transport forwarding (HEADER_2 packets where we are the designated next-hop)
**Code (before fix):**
```cpp
DestinationEntry destination_entry = (*destination_iter).second; // COPY
// ... later:
destination_entry._timestamp = OS::time(); // Only updates local copy
```
**Impact:** Path timestamps are never refreshed when packets are actively being forwarded along that path. Paths could be culled while still in active use, though the timeout is typically long enough (DESTINATION_TIMEOUT) that this is less likely to cause issues than the link_table bugs.
**Fix:** Change to reference:
```cpp
DestinationEntry& destination_entry = (*destination_iter).second;
```
### Bug 1d — Outbound transport forwarding: `_timestamp` never refreshed
**File:** `Transport.cpp`, `outbound()` method
**Code (before fix):**
```cpp
DestinationEntry destination_entry = (*_destination_table.find(packet.destination_hash())).second; // COPY
// ... later:
destination_entry._timestamp = OS::time(); // Only updates local copy
```
**Impact:** Same as 1c — outbound path forwarding never refreshes the path timestamp.
**Fix:** Change to reference:
```cpp
DestinationEntry& destination_entry = (*_destination_table.find(packet.destination_hash())).second;
```
### How to audit for more
Search for the pattern: assignments from map iterators without `&`:
```
grep -n "Entry [a-z_]* = " Transport.cpp
```
Any line matching `SomeEntry variable_name = (*iter).second;` (without `&` after the type) that later mutates a field of `variable_name` is a bug.
---
## 2. Potential additional copy-vs-reference instances (non-mutating — safe but wasteful)
The following locations also copy entries but only read from them (no mutation). They are not bugs but are unnecessarily copying large structs:
- `for_local_client` check: `LinkEntry link_entry = (*link_iter).second;` — read-only, safe
- `for_local_client` check: `DestinationEntry destination_entry = (*destination_iter).second;` — read-only, safe
- `proof_for_local_client` check: `ReverseEntry reverse_entry = (*reverse_iter).second;` — read-only, safe
- Several `DestinationEntry` copies in `has_path()`, `hops_to()`, `next_hop()`, `next_hop_interface()` — read-only, safe
These could be changed to `const auto&` for efficiency but are not correctness bugs.
---
## 3. `std::map::insert()` silently fails on existing keys
### Summary
In Python, `dict[key] = value` always overwrites. In C++, `std::map::insert({key, value})` is a **no-op** if the key already exists — it silently discards the new value and returns the old entry.
### Bug 3a — `_destination_table` path updates silently ignored
**File:** `Transport.cpp`, path table update code
**Code (before fix):**
```cpp
_destination_table.insert({destination_hash, new_destination_entry});
// If destination_hash already exists, the insert does NOTHING.
// The old (stale) path entry remains.
```
**Impact:** When a destination announces a new path (e.g. it roamed to a different transport node), the path table keeps the old stale entry. Packets continue to be routed to the old path, which may no longer work.
**Fix:** Erase before insert:
```cpp
_destination_table.erase(destination_hash);
_destination_table.insert({destination_hash, new_destination_entry});
```
**Note:** This same pattern (`insert` without `erase`) should be audited across ALL map insertions in the codebase. Any map that might receive updated entries for existing keys needs the erase-before-insert pattern, or should use `operator[]` or `insert_or_assign()`.
---
## 4. Memory Leaks — Unbounded Data Structures
### Bug 4a — `_boundary_local_addresses`: no cap, no eviction (HIGH RISK)
**File:** `Transport.cpp`
The `_boundary_local_addresses` set accumulates every local device address seen via LoRa announces. There is no size cap and no eviction mechanism. On a long-running boundary node that sees many transient devices, this grows without bound.
**Impact:** Slow heap exhaustion over days/weeks of operation. Particularly problematic on ESP32 with limited RAM.
**Fix needed:** Add a size cap (e.g. 200) with timestamp-based or LRU eviction, similar to how `_boundary_mentioned_addresses` is capped.
### Bug 4b — `_held_announces`: no cap, can orphan
**File:** `Transport.cpp`
The `_held_announces` map stores announces waiting to be retransmitted. There is no size cap. If the retransmit never triggers (e.g. the outbound interface disappears), entries can be orphaned and accumulate indefinitely.
**Impact:** Slow memory leak, exacerbated on busy networks with many announces.
**Fix needed:** Add a size cap or timeout-based eviction.
### Bug 4c — `_pending_local_path_requests`: entries never erased
**File:** `Transport.cpp`
**Status:** Fixed (added `.erase(iter)` call)
Entries in `_pending_local_path_requests` were inserted but never removed after the path request was fulfilled. Over time the map grew without bound.
### Bug 4d — `_path_requests`: entries never culled
**File:** `Transport.cpp`
**Status:** Fixed (added `DESTINATION_TIMEOUT`-based culling in `jobs()`)
The `_path_requests` map recorded timestamps of path requests but entries were never removed. Each unique destination hash that triggered a path request stayed in the map forever.
---
## 5. Spurious Path Request Broadcasts
### Bug 5a — Boundary Path A sends PATH REQUEST for every link data packet
**File:** `Transport.cpp`, boundary mode local→backbone forwarding
**Code (before fix):**
```cpp
// Boundary Path A: local device packet, no path in _destination_table
else {
DEBUG("BOUNDARY: No path to " + packet.destination_hash().toHex() + " for local packet. Requesting path.");
request_path(packet.destination_hash());
}
```
**Impact:** Link data packets are addressed to a `link_id` (the link's unique identifier), not a destination hash. The `link_id` will never be found in `_destination_table` — it's only in `_link_table`. So **every** link data packet from a local device triggers a `request_path(link_id)` call, which broadcasts a PATH REQUEST for a hash that is not any destination.
For a resource transfer with 100 chunks, this sends 100 useless PATH REQUEST broadcasts over LoRa (with no deduplication — `request_path()` always sends). This wastes radio airtime and can cause congestion-related timeouts on slow LoRa links.
**Fix:** Check if the destination is a known link_id before requesting a path:
```cpp
else {
if (_link_table.find(packet.destination_hash()) == _link_table.end()) {
DEBUG("BOUNDARY: No path to " + packet.destination_hash().toHex() + " for local packet. Requesting path.");
request_path(packet.destination_hash());
}
}
```
### Bug 5b — Same issue in standard transport HEADER_2 fallback path
**File:** `Transport.cpp`, inbound transport forwarding (where we are designated next-hop but destination_table lookup fails)
Same pattern: for link data packets with HEADER_2/TRANSPORT headers where the transport_id matches us, if the destination_hash (which is a link_id) isn't in the destination table, the code requests a path for the link_id — another spurious broadcast.
**Fix:** Same guard — check `_link_table` before calling `request_path()`.
---
## 6. General Audit Recommendations
### 6a — Systematic `insert()` audit
Every `std::map::insert()` call in the codebase should be reviewed. The ones that are intentional "insert-if-not-exists" semantics are fine. The ones ported from Python `dict[key] = value` (which overwrites) need to use erase+insert or `insert_or_assign()`.
### 6b — Systematic copy-vs-reference audit
Run:
```bash
grep -n "Entry [a-z_]* = .*\.second" Transport.cpp
```
Any match where the variable is later mutated (assigned to `._timestamp`, `._validated`, etc.) is a bug.
### 6c — Data structure caps
Every `std::map` and `std::set` in Transport that accumulates entries over time needs:
1. A size cap appropriate for ESP32 memory constraints
2. An eviction strategy (timestamp-based, LRU, or lexicographic)
3. Culling in the `jobs()` periodic task
---
## 7. Packet Hashlist Timing Bug — Link Transport Breakage on Shared Media
### Bug 7a — Premature packet hash insertion breaks link transport (FIXED)
**File:** `Transport.cpp`, inbound() after packet_filter
**Bug:** The C++ code unconditionally added every accepted packet's hash to
`_packet_hashlist` immediately (line ~1505), before link transport or proof
handling ran:
```cpp
_packet_hashlist.insert(packet.packet_hash()); // Always, immediately
```
The Python reference implementation (`Transport.py` lines 1362-1373)
**defers** insertion for two cases:
1. Packets whose `destination_hash` is in `link_table` (link data packets)
2. LRPROOF packets (type=PROOF, context=LRPROOF)
For link data: the hash is added later, **inside** the link transport
forwarding block, only after a valid outbound direction is confirmed
(`Transport.py` line 1544).
For LRPROOF: the hash is **never** added (allowing duplicate proofs to be
processed on multiple interfaces).
**Impact:** On shared-medium interfaces (e.g. LoRa), a packet belonging to a
link that transports through this node may arrive on the "wrong" interface
first (e.g. received on LoRa before it arrives via TCP backbone). The
premature hash insertion causes the correct arrival to be filtered as a
duplicate for non-resource contexts (DATA ctx=0, LINKIDENTIFY, LRRTT,
LINKCLOSE). Resource contexts (RESOURCE, RESOURCE_REQ, RESOURCE_PRF)
are unaffected because they bypass the hashlist check in `packet_filter`.
**Fix:** Defer hash insertion for link-table and LRPROOF packets, matching
the Python reference implementation. Add `_packet_hashlist.insert()` inside
the link transport forwarding block after direction is confirmed.

View File

@@ -693,7 +693,11 @@ void setup() {
HEAD("Boundary Mode: TCP backbone DISABLED", RNS::LOG_TRACE);
}
// Register local TCP server if enabled (MODE_ACCESS_POINT — no announce forwarding)
// Register local TCP server if enabled
// MODE_GATEWAY allows announce rebroadcasts so local TCP clients
// can discover each other and receive backbone announces.
// (MODE_ACCESS_POINT blocks all announce broadcasts in outbound(),
// which prevented local clients from finding paths to each other.)
if (boundary_state.wifi_enabled && boundary_state.ap_tcp_enabled) {
local_tcp_interface_ptr = new TcpInterface(
TCP_IF_MODE_SERVER,
@@ -706,12 +710,12 @@ void setup() {
// to prevent unnecessary reconnection cycles that leak lwIP memory
local_tcp_interface_ptr->setReadTimeout(600000);
local_tcp_rns_interface = local_tcp_interface_ptr;
local_tcp_rns_interface.mode(RNS::Type::Interface::MODE_ACCESS_POINT);
local_tcp_rns_interface.mode(RNS::Type::Interface::MODE_GATEWAY);
RNS::Transport::register_interface(local_tcp_rns_interface);
{
char _bm_msg[128];
snprintf(_bm_msg, sizeof(_bm_msg), "Local TCP server: port %d (ACCESS_POINT mode)",
snprintf(_bm_msg, sizeof(_bm_msg), "Local TCP server: port %d (GATEWAY mode)",
boundary_state.ap_tcp_port);
HEAD(_bm_msg, RNS::LOG_TRACE);
}

BIN
Release/bootloader.bin Normal file

Binary file not shown.

BIN
Release/partitions.bin Normal file

Binary file not shown.

Binary file not shown.

557
platformio.ini.bak Executable file
View File

@@ -0,0 +1,557 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
; Change source and include directories to root of project since RNode places them here
include_dir = .
src_dir = .
[env]
framework = arduino
monitor_speed = 115200
upload_speed = 460800
build_flags =
-Wall
;-Wextra
-Wno-missing-field-initializers
-Wno-format
-I.
; CBA Define following to disable DEBUG build
;-DNDEBUG
; CBA Define following to include RNS stack
-DHAS_RNS
-DRNS_USE_FS
-DRNS_PERSIST_PATHS
-DMSGPACK_USE_BOOST=OFF
; CBA Define following to disable LFS asserts
;-DLFS_NO_ASSERT
; ???
;-DLFS_YES_TRACE
; ???
;-DCORE_DEBUG_LEVEL=5
; ??? NO
;-DLOG_LOCAL_LEVEL=5
;-DCONFIG_LOG_DEFAULT_LEVEL=5
lib_deps =
ArduinoJson@^7.4.2
MsgPack@^0.4.2
adafruit/Adafruit SSD1306@^2.5.9
https://github.com/attermann/Crypto.git
; Exclude directories in root from sources
build_src_filter = +<*> -<variants/>
extra_scripts = pre:extra_script.py
[env:rnode-ng-20]
platform = espressif32
board = ttgo-lora32-v2
custom_variant = ng20
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_RNODE_NG_20
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
adafruit/Adafruit NeoPixel@^1.12.0
attermann/microReticulum
[env:rnode-ng-21]
platform = espressif32
board = ttgo-lora32-v21
custom_variant = ng21
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_RNODE_NG_21
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
adafruit/Adafruit NeoPixel@^1.12.0
attermann/microReticulum
[env:ttgo-t-beam]
platform = espressif32
board = ttgo-t-beam
custom_variant = tbeam
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_TBEAM
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:ttgo-t-beam-sx1262]
platform = espressif32
board = ttgo-t-beam
custom_variant = tbeam_sx1262
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_TBEAM
-DMODEM=SX1262
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:ttgo-t-beam-supreme]
platform = espressif32
board = ttgo-t-beam
custom_variant = tbeam_supreme
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_TBEAM_S_V1
-DMODEM=SX1262
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
Adafruit_SH110X
adafruit/Adafruit SH110X@^2.1.14
attermann/microReticulum
[env:lilygo-t3-s3]
platform = espressif32
board = lilygo-t3-s3
custom_variant = t3s3
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_T3S3
-DMODEM=SX1262
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:lilygo-t3-s3-sx127x]
platform = espressif32
board = lilygo-t3-s3
custom_variant = t3s3_sx127x
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_T3S3
-DMODEM=SX1276
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:lilygo-t3-s3-sx1280-pa]
platform = espressif32
board = lilygo-t3-s3
custom_variant = t3s3_sx1280_pa
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_T3S3
-DMODEM=SX1280
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:lilygo-t-deck]
platform = espressif32
board = esp32-s3-devkitc-1
custom_variant = tdeck
board_build.filesystem = littlefs
; Flash / memory layout
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = default_16MB.csv
; Enable PSRAM + correct flash mode
board_build.flash_mode = qio
board_build.psram_type = opi
board_build.arduino.memory_type = qio_opi
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_TDECK
-DBOARD_HAS_PSRAM=1
-DARDUINO_USB_MODE=1
-DCORE_DEBUG_LEVEL=1
; Enable UARDUINO_ USB_ CDC_ ON_ BOOT will start printing and wait for terminal access during startup
-DARDUINO_USB_CDC_ON_BOOT=1
; Enable UARDUINO_USB_CDC_ON_BOOT will turn off printing and will not block when using the battery
; -UARDUINO_USB_CDC_ON_BOOT
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:ttgo-lora32-v1]
platform = espressif32
board = ttgo-lora32-v1
custom_variant = lora32v10
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_LORA32_V1_0
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:ttgo-lora32-v2]
platform = espressif32
board = ttgo-lora32-v2
custom_variant = lora32v20
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_LORA32_V2_0
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:ttgo-lora32-v2-extled]
platform = espressif32
board = ttgo-lora32-v2
custom_variant = lora32v20_extled
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_LORA32_V1_0
-DEXTERNAL_LEDS=true
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:ttgo-lora32-v21]
platform = espressif32
board = ttgo-lora32-v21
custom_variant = lora32v21
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_LORA32_V2_1
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:ttgo-lora32-v21-extled]
platform = espressif32
board = ttgo-lora32-v21
custom_variant = lora32v21_extled
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_LORA32_V2_1
-DEXTERNAL_LEDS=true
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:ttgo-lora32-v21-tcxo]
platform = espressif32
board = ttgo-lora32-v21
custom_variant = lora32v21_extled
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_LORA32_V2_1
-DENABLE_TCXO=true
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:heltec_wifi_lora_32_V2]
platform = espressif32
board = heltec_wifi_lora_32_V2
custom_variant = heltec32v2
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_LORA32_V2_1
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:heltec_wifi_lora_32_V2-extled]
platform = espressif32
board = heltec_wifi_lora_32_V2
custom_variant = heltec32v2_extled
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_LORA32_V2_1
-DEXTERNAL_LEDS=true
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:heltec_wifi_lora_32_V3]
platform = espressif32
board = heltec_wifi_lora_32_V3
custom_variant = heltec32v3
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_HELTEC32_V3
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:heltec_wifi_lora_32_V4]
platform = espressif32
board = esp32-s3-devkitc-1
custom_variant = heltec32v4
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_HELTEC32_V4
-DARDUINO_USB_CDC_ON_BOOT=1
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:heltec_V4_boundary]
platform = espressif32
board = esp32-s3-devkitc-1
custom_variant = heltec32v4_boundary
board_build.filesystem = littlefs
; Flash / memory layout for 16MB flash + 2MB PSRAM
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = default_16MB.csv
board_build.flash_mode = qio
board_build.psram_type = qio
board_build.arduino.memory_type = qio_qspi
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_HELTEC32_V4
-DARDUINO_USB_CDC_ON_BOOT=1
-DBOARD_HAS_PSRAM=1
-DBOUNDARY_MODE
; --- Boundary mode defaults (override via EEPROM at runtime) ---
; TCP server mode (0=server, 1=client)
-DBOUNDARY_TCP_MODE=0
; TCP listen/connect port
-DBOUNDARY_TCP_PORT=4242
; Backbone host for client mode (empty = server mode)
; -DBOUNDARY_BACKBONE_HOST=\"192.168.1.100\"
; -DBOUNDARY_BACKBONE_PORT=4242
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
monitor_filters = esp32_exception_decoder
[env:heltec_V4_boundary-local]
platform = espressif32
board = esp32-s3-devkitc-1
custom_variant = heltec32v4_boundary_local
board_build.filesystem = littlefs
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = default_16MB.csv
board_build.flash_mode = qio
board_build.psram_type = qio
board_build.arduino.memory_type = qio_qspi
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_HELTEC32_V4
-DARDUINO_USB_CDC_ON_BOOT=1
-DBOARD_HAS_PSRAM=1
-DBOUNDARY_MODE
-DBOUNDARY_TCP_MODE=0
-DBOUNDARY_TCP_PORT=4242
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
microReticulum=symlink://../microReticulum
monitor_filters = esp32_exception_decoder
[env:featheresp32]
platform = espressif32
board = featheresp32
custom_variant = featheresp32
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_HUZZAH32
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:seeed_xiao_esp32s3]
platform = espressif32
board = seeed_xiao_esp32s3
custom_variant = xiao_esp32s3
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_XIAO_S3
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:generic-esp32]
platform = espressif32
board = esp32dev
custom_variant = esp32_generic
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_GENERIC_ESP32
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
attermann/microReticulum
[env:wiscore_rak4631]
platform = nordicnrf52
board = rak4630
custom_variant = rak4631
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_src_filter = ${env.build_src_filter} +<variants/rak4630>
build_flags =
${env.build_flags}
-I variants/rak4630
-fexceptions
-DBOARD_MODEL=BOARD_RAK4631
-DRNS_USE_TLSF=1
-DRNS_USE_ALLOCATOR=1
lib_deps =
${env.lib_deps}
attermann/microReticulum
[env:ttgo-t-beam-local]
platform = espressif32
board = ttgo-t-beam
upload_speed = 460800
custom_variant = tbeam_local
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-fexceptions
-DBOARD_MODEL=BOARD_TBEAM
; CBA TEST
;-DUSE_FLASHFS=1
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
microReticulum=symlink://../microReticulum
Adafruit_SPIFlash=symlink://../Adafruit_SPIFlash
monitor_filters = esp32_exception_decoder
[env:ttgo-lora32-v21-local]
platform = espressif32
board = ttgo-lora32-v21
upload_speed = 460800
custom_variant = lora32v21_local
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_LORA32_V2_1
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
microReticulum=symlink://../microReticulum
monitor_filters = esp32_exception_decoder
[env:heltec_wifi_lora_32_V4-local]
platform = espressif32
board = esp32-s3-devkitc-1
custom_variant = heltec32v4_local
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-DBOARD_MODEL=BOARD_HELTEC32_V4
-DARDUINO_USB_CDC_ON_BOOT=1
lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
microReticulum=symlink://../microReticulum
monitor_filters = esp32_exception_decoder
[env:wiscore_rak4631-local]
platform = nordicnrf52
board = rak4630
custom_variant = rak4631_local
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_src_filter = ${env.build_src_filter} +<variants/rak4630>
build_flags =
${env.build_flags}
-I variants/rak4630
-fexceptions
-DBOARD_MODEL=BOARD_RAK4631
; CBA TEST
-DRNS_USE_TLSF=1
-DRNS_USE_ALLOCATOR=1
;-DUSE_FLASHFS=1
build_unflags = -fno-exceptions
lib_deps =
${env.lib_deps}
microReticulum=symlink://../microReticulum
Adafruit_SPIFlash=symlink://../Adafruit_SPIFlash
[env:heltec_t114_local]
;upload_port = /dev/cu.usbmodem1101
platform = nordicnrf52
board = nrf52840_dk_adafruit
custom_variant = heltec_t114_local
board_build.partitions = no_ota.csv
board_build.filesystem = littlefs
build_flags =
${env.build_flags}
-fexceptions
-DBOARD_MODEL=BOARD_HELTEC_T114
; CBA TEST
-DRNS_USE_TLSF=1
-DRNS_USE_ALLOCATOR=1
build_unflags = -fno-exceptions
lib_deps =
${env.lib_deps}
https://github.com/liamcottle/esp8266-oled-ssd1306#e16cee124fe26490cb14880c679321ad8ac89c95
adafruit/Adafruit NeoPixel@^1.12.0
microReticulum=symlink://../microReticulum

2841
rnodethv3.log Normal file

File diff suppressed because it is too large Load Diff

BIN
rnodethv3_firmware.bin Executable file

Binary file not shown.