- DisplayDriver takes ColorVal; each driver's .cpp defines the UIColor roles
(window_bkg, primary_txt, ...) in its own values. ui-new draws in two:
window_bkg and primary_txt. OLED and e-ink look as before (sim screens
pixel-identical).
- E213, E290, LGFX, Null, ST7735, ST7789LCD, U8g2 taken whole from upstream
(with them the rewritten ST7735 driver and the Heltec V4 R8 TFT display).
- SH1106, SSD1306, ST7789, EinkGfxDisplay and the sim drivers converted.
- ui-orig, ui-tiny, simple_* get upstream's colour roles; the repeater's UI
taken from upstream (its power-off screen).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes and features from upstream: MACThenDecrypt / command buffer
overflow fixes, ACK forwarding delay, transport code 0 as unscoped,
hidden nodes don't answer DISCOVER, LR2021/LR1121 fixes, GPS cold-start
detection and waitFor()/drain(), NMEA fix-age counters, ESP32 RTC after a
crash, remote CLI by text message (TXT_TYPE_CLI_COMMAND),
PUSH_CODE_BINARY_RESPONSE, board.loop(), new boards (Wio Tracker L1 1W,
ThinkNode M4/M8, Muzi Base, Waveshare LR1121, Pico W).
Kept ours: NodePrefs, main.cpp, every UI, GxEPDDisplay. The companion CLI
stays MyMeshCli.h's handleCliCommand(); upstream's handleCommand() calls
it. The board's FEM gains go through attachDynamicPrefs() with an adapter
over our NodePrefs fields. Upstream's JSON prefs and MultiSerialInterface
come as their own stages.
Also: the display defaults were inside RADIO_FEM_TXGAIN's #else (a
missing #endif).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gat562_30s_mesh_kit has an always-on external PA rated at +30dBm, but the
firmware wrote tx_power_dbm straight to the SX1262 register (capped at 22),
so the app/CLI/UI never matched the real radiated power and couldn't ask
for more than 22 even though the hardware supports it.
Add a generic, macro-gated PA gain-curve resolution in
RadioLibWrapper::setTxPower() (the single choke point every TX-power path
already funnels through), reusable by any future board with a similar PA.
For this board, reuse the vendor-measured 869MHz curve from the open
upstream Meshtastic PR that added it for the same physical module
(meshtastic/firmware#11212): pick the lowest SX1262 setting whose measured
output reaches the requested dBm, clamped at the PA's saturation knee.
Bump LORA_TX_POWER/MAX_LORA_TX_POWER to 30 for this variant only -- the
other three GAT562 boards use the SX1262's own PA_BOOST (22dBm, no
external PA) and are unaffected.
Since a request below the PA's floor gain (14dBm) still radiates at that
floor, also make CommonCLICallbacks::setTxPower() return what was actually
applied, and have every setter (BLE CMD_SET_RADIO_TX_POWER, CLI "tx",
simple_repeater/room_server/sensor) persist and report that value instead
of the raw request -- so tx_power_dbm never silently disagrees with the
physical output in either direction.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
sim_buzzer_toggle_quiet()/sim_buzzer_get_quiet() (UITask.cpp) call the
literal UITask::toggleBuzzer() the real on-device Settings > Buzzer mute
toggle already calls -- persists into NodePrefs.buzzer_quiet, clears
buzzer_auto, saves prefs, shows the real "Buzzer: ON/OFF" alert. Not a
re-implementation, not a host-side Web Audio mute layered on top.
Every simple_repeater instance advertised the literal ADVERT_NAME
("repeater") -- across meshcore-solo-site's cross-visitor relay bridge
every hop in every path/relay list was an indistinguishable wall of
"repeater"s. A SIM_PLATFORM/__EMSCRIPTEN__-only default now picks a
random "<adjective> <geographic feature>" pair from
sim_instance_entropy() (real crypto.getRandomValues()-sourced entropy,
already used for RNG seeding) at first boot -- matches the real,
common ham-radio convention of naming a repeater after the hill it
sits on. Persists normally across reboots via the existing prefs
load/save path, same as a real operator-set name would.
sim_repeater_get_name() added alongside the existing
sim_repeater_get_relay_count() for host-page/test access to the
result.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018iubftDmKNWmkNnhJRz8UH
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.
advert_interval defaulted to 1 (the field is minutes/2, so 2 minutes) --
too chatty for a repeater sitting on a desk being demoed/deployed. Field
only stores even minute counts, so 6 (value 3) is the closest step down
from "beeps too often" without landing under-target at 4.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018iubftDmKNWmkNnhJRz8UH
- Turn on ENV_INCLUDE_GPS/UI_SENSORS_PAGE for the sim build (both were
compiled out entirely, so the GPS and Sensors home-page carousel
entries didn't exist regardless of home_pages_mask) -- SimSensorManager
already fed a real JS-settable GPS fix and a temperature/battery
channel with nothing to display them.
- Add sim_test_advert_flood() to the repeater build too, mirroring
companion_radio's hook: MyMesh::updateAdvertTimer() otherwise leaves
the repeater's first self-advert 2 minutes out, so a host page
couldn't make it discoverable as a contact (needed for admin login)
right away.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018iubftDmKNWmkNnhJRz8UH
Ports examples/simple_repeater to variants/sim/ (new sim_simple_repeater
native env + build_wasm_repeater.sh) and adds a JS "ether"
(variants/sim/web/mesh.html) that bridges two real companion_radio WASM
instances through a real simple_repeater instance in a strict A<->R<->B
topology (no direct A-B link), proving genuine relay routing rather than
a shortcut.
Also fixes multi-instance issues Phase 2's single-instance design never
surfaced: SimDisplayDriver's canvas context/id caching was keyed on a
single global instead of per-instance, and both wasm builds were missing
_malloc/_free/HEAPU8 runtime exports needed for the ether to poke bytes
into an instance's memory.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
MAX_CLIENTS is defined in both src/helpers/ClientACL.h and examples/simple_repeater/MyMesh.h. Appears it was centralised in the former header file some time ago. Both are included in some places and, depending on which order they're in, either value can win.
This change drops the duplicate entry from the repeater firmware and bumps the central limit up to 32 (per the original repeater firmware value).
Changes:
- Remove MAX_CLIENTS from repeater MyMesh.h
- Increase MAX_CLIENTS limit in ClientACL.h to 32
Adopts hardware Channel Activity Detection (wired into
RadioLibWrapper::isChannelActive() alongside our RSSI-threshold check
and RX duty-cycle power-save), MCU temperature telemetry, LR2021
standby workaround, DISPLAY_SCALE/FLIP overrides, NRF52Board
shutdownPeripherals() refactor, and misc upstream fixes.
Declines upstream's ConfigSerializer-based NodePrefs rewrite,
MultiSerialInterface/interface_manager, and UIColor palette system —
each would have broken large parts of the Solo-specific feature set
(NodePrefs fields, per-variant single serial_interface, enum-based
DisplayDriver::Color). Flagged as candidate follow-up migrations, not
permanent no's.
Also fixes several pre-existing bugs surfaced while chasing silent
merge breaks (stale newMsg() override signature in ui-tiny/ui-orig,
dead UIEventType::newContactMessage case, missing ContactsIterator
init), bumps FIRMWARE_VERSION/MESHCORE_VERSION to 1.17, and fixes a
missing <cstdlib> include that broke the native ConfigSerializer unit
tests.
Verified via 13+ pio run builds across ESP32/nRF52, all 3 companion UI
variants, and 7 display drivers, plus the full native unit test suite
(33/33 passing).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The `recv_pkt_region` is set when processing a flood packet in `filterRecvFloodPacket`
but direct/non-flood packets would never pass through that function, so the pointer was
not cleared for them.
`sendFloodReply` would then later use it blindly, which meant that the response would
either inherit the region from the last flood packet, or refer to a non-initialised pointer
if no region floods had been received yet.