Payloads of 166 or 167 bytes previously passed the frame-sized bound
(MAX_CHANNEL_DATA_LENGTH = 167) but were rejected by sendGroupData
against MAX_GROUP_DATA_LENGTH (165), causing ERR_CODE_TABLE_FULL (retry
later) to be returned instead of ERR_CODE_ILLEGAL_ARG.
Fixes#3345
'custom:{}' (a DynamicConfigSerializer with nothing set) hits EXPECT_KEY
with a '}' and returns TOK_ERROR, so loadSerial stops there and silently
drops every property after it. Nothing follows 'custom' in NodePrefs
today, so it goes unnoticed until you add one.
Also include stdlib.h, which Arduino.h was providing on-device but not
in the native test build.
- scope the serial config CLI to RP2040; it was exposing the rescue CLI
(cat/rm/erase) on every ESP32 WiFi build, which gates it behind a
physical long-press
- bound and space out RP2040 rejoins: the core's join busy-waits, so cap
it at 5s and retry every 30s instead of every 10s
- stamp the reconnect timer in setup(), so the first loop() doesn't tear
down an association that is still finishing DHCP
- treat stored credentials as a pair, and pass NULL (not "") for an open
network
- teach build_as_lib.py where SerialWifiInterface moved
arduino-pico's WiFi.begin() blocks for up to 2x its 15s timeout, which
stalled the mesh loop on every reconnect attempt; use beginNoBlock().
Log the IP when the link comes up, and the status code when retrying.
Store ssid/pwd in NodePrefs and set them with 'set wifi.ssid' /
'set wifi.pwd' over USB serial; build-time WIFI_SSID/WIFI_PWD stay as
the fallback. Headless WiFi builds get the config CLI on Serial, which
is otherwise unused there.
SerialWifiInterface has no ESP32-specific code, so move it to
helpers/wifi and reuse it on RP2040. Guard the ESP32-only WiFi
event/auto-reconnect calls and poll link state on RP2040 instead.
Lets applications know whether a GPS was actually detected
(EnvironmentSensorManager reports its gps_detected state), e.g. to
hide GPS-dependent UI when no receiver is attached.
The serial command buffers must stay NUL-terminated within their
bounds: if they ever aren't, strlen() can return >= sizeof(command)
and the read loop would index past the buffer. Additionally, a full
buffer now becomes a completed line (end-of-line marker placed
inside the buffer, NUL terminator kept) instead of overwriting the
terminator and silently corrupting the buffer for the next pass.
Applies to the serial CLI readers of the repeater, room server,
sensor and secure chat examples, and to the CLI rescue reader of
the companion example.
The project moved to meshcore-dev/meshcore, but two links still pointed at
ripplebiz/MeshCore: the GitHub Issues link in README and the git clone in the
FAQ build instructions.
Also fixes the FAQ build recipe:
- `pio run -e RAK_4631_Repeater` does not exist; the env is spelled
RAK_4631_repeater (variants/rak4631/platformio.ini:40).
- LORA_FREQ was given as 867.5; the default in [arduino_base] is 869.618
(platformio.ini:29). Reworded to point at the flag rather than a value that
drifts with the default preset.
- Renamed the venv so it no longer collides with the cloned directory name.
And one more env-name casing slip in the Raspberry Pi flashing instructions:
`Heltec_V3_companion_radio_ble` should be `Heltec_v3_...`. Release artifacts are
named directly from the env name (build.sh:147), and the two neighbouring
examples in the same block already use the lowercase spelling.
f6338430 added get/set dutycycle to CommonCLI and updated both CLI docs, but
Terminal Chat does not use CommonCLI -- simple_secure_chat/main.cpp:479-507 has
its own `set` handler supporting only af, name, lat, lon, tx and freq. Typing
`set dutycycle` there returns "ERROR: unknown config".
Restores `set af` as the documented command, points readers at cli_commands.md
for the roles that do have dutycycle, and documents `help`
(simple_secure_chat/main.cpp:510), which the client implements but the doc
never listed.
The doc claimed every pwrmgt command except `get pwrmgt.support` returns
"ERROR: Power management not supported" when NRF52_POWER_MANAGEMENT is not
defined. `get pwrmgt.bootreason` is not inside the #ifdef (CommonCLI.cpp:787)
and answers on all boards; only pwrmgt.source and pwrmgt.bootmv are gated.
Three factual errors in companion_protocol.md:
- The channel-datagram payload cap was given as 163 (MAX_FRAME_SIZE - 9 when
MAX_FRAME_SIZE was still 172). It went 172 -> 176 in 62f1b11d, but simply
updating the arithmetic to 167 would be worse than the stale value: 167 is
only the host-frame bound (MyMesh.cpp:1265). The radio-side bound is
MAX_GROUP_DATA_LENGTH = 184 - 16 - 3 = 165 (MeshCore.h:21, enforced at
BaseChatMesh.cpp:544). A 166- or 167-byte payload passes the frame check,
fails the radio check, and comes back as ERR_CODE_TABLE_FULL -- which this
same doc describes as "retry later", so a conforming client would retry a
permanently failing send forever. Documents 165 as the limit to enforce and
calls out the 166-167 band explicitly.
- Channel index was documented as 0-7 throughout. The bound is
MAX_GROUP_CHANNELS (BaseChatMesh.cpp:927,936), which is 40 on most current
variants, 8 on some and 1 on others. Clients should read max_channels from
byte 3 of PACKET_DEVICE_INFO instead. Index 0 is pre-populated with the
built-in Public channel but is not reserved.
- The secret field was documented as "all zeros" for public channels. The
firmware always hashes a real 16-byte key; the public channel ships with
izOH6cXN6mrJ5e26oRXNcg== (companion_radio/MyMesh.cpp:111,1040). An all-zero
secret is not a private channel and not an inert one: SHA256 over 16 zero
bytes is a fixed global constant, giving a well-known channel with an
all-zero AES key. searchChannelsByHash skips unnamed slots for exactly this
reason (BaseChatMesh.cpp:392-401), but a named slot with a zero secret is
not skipped and will absorb null-key group traffic from any node. Now
documented as something not to do.
Five "Default:" values in cli_commands.md no longer matched the firmware:
- radio / freq: the default preset moved to EU/UK (Narrow) in b777a7c6,
changing LORA_FREQ/BW/SF from 869.525/250/11 to 869.618/62.5/8
(platformio.ini:29-31). No variant overrides these, and LORA_CR is 5
on every path, so the full preset is 869.618,62.5,8,5.
- flood.advert.interval: raised to 47 hours in 40180b8f for both repeater
and room server; sensor leaves it disabled.
- advert.interval: prefs store minutes/2 and the getter doubles on read, so a
factory-fresh node reports 2, not 0. But savePrefs() zeroes any interval
below the 60 minute minimum (CommonCLI.cpp:162-165), and it is called from
every `set` handler -- so the value becomes 0 as soon as the node is
configured. Documented both states, since neither alone is the whole story.
- direct.txdelay: repeater defaults to 0.3, room server and sensor to 0.2.
Sources: platformio.ini:29-31, simple_repeater/MyMesh.cpp:893,903-904,
simple_room_server/MyMesh.cpp:650,661-662, simple_sensor/SensorMesh.cpp:716,
726-727, CommonCLI.cpp:162-165,680-681.