Commit Graph
4628 Commits
Author SHA1 Message Date
MUSTARDTIGERFPV 4bbcb5270a Support boards that move the radio output alongside the PA gain
Not every external-PA board parks its radio at a fixed drive level. Where
the amplifier is driven somewhere other than its floor, the radio's own
output steps with the requested power as well, and the board describes that
with a second table paired to the first. ExpressLRS layouts call this
"power_values2"; it is independent of dual-band operation, and appears on
single-band modules such as the Radiomaster Bandit.

An optional radio_dbm array supplies one radio output level per entry in the
level table. When present the fixed drive level is unused, and each power
change sets the radio before moving the amplifier so the PA is never asked
to pass a level the radio has already exceeded.

Values go to the SX1276 on the PA_BOOST path. A board wired to RFO_HF would
need RadioLib's useRfo argument plumbed through, which this does not do.
2026-09-09 01:24:38 -07:00
MUSTARDTIGERFPV c430ac130e Add GEPRC LINKFLOW 900M TX variant
An ExpressLRS 900 MHz transmitter module: ESP32-D0WDQ6, 4 MB flash, SX1276
driving an external PA through a DAC gain input on GPIO26.

Pin values come from the ExpressLRS hardware layout for this target
(Unified_ESP32_900_TX). The board brings out only RX_EN, so RadioLib's
single-pin RF switch handling covers it. Note GPIO12 is both RX_EN and the
MTDI flash-voltage strapping pin, so it must stay low through reset.

Verified on hardware: boots, radio initialises, TX power changes take
effect and are rejected outside the configured range, and the node repeats
flood traffic.

Uses dual_ota_1536k.csv, and 115200 for upload because the CH340 on this
board corrupts transfers above 230400.
2026-09-09 01:24:38 -07:00
MUSTARDTIGERFPV 83371a10f3 Add shared board class for ExpressLRS ESP32 TX modules
ExpressLRS transmitter modules share a common shape: powered from the
handset bay or USB rather than a battery, a fan over the amplifier, and an
ESP8285 "backpack" on a second UART that MeshCore has no use for.

ELRSTxBoard handles those from optional defines (PIN_FAN_EN,
PIN_BACKPACK_EN, PIN_BACKPACK_BOOT, MANUFACTURER_NAME) so a variant only
has to supply pin numbers. It also returns DIO0 from getIRQGpio(), since
the ESP32Board default is the SX126x pin.
2026-09-09 01:24:38 -07:00
MUSTARDTIGERFPV ae3ddcd215 Add SX1276 wrapper for DAC-controlled external PA gain
Some SX1276 boards do not drive the antenna from the radio. They feed an
external power amplifier whose gain is set by an analog control voltage on
the PA's gain input (APC/APC1/APC2/VAPC depending on the module), driven
from an MCU DAC. The radio sits at a fixed drive level and all power
control happens on that pin, so setOutputPower() alone does not describe
what the board can do.

DacPaSX1276Wrapper overrides applyCachedTxPower() and translates the
requested dBm, measured at the antenna, into a gain-control code using a
per-board calibration table.

The table defines the legal range, so out-of-range requests are refused
rather than saturated at the nearest entry. An optional max_dbm argument
caps the board below its top entry for thermal or regulatory headroom, and
can only ever reduce the ceiling. The gain write goes through a virtual so
a PA driven by PWM or an external DAC can reuse the rest.
2026-09-09 01:24:38 -07:00
MUSTARDTIGERFPV c6d71b969a Enable the on-demand mOTA context for every classic ESP32 build
Move OTA_HEAP_CONTEXT from two hand-edited envs to a pre-script gated on
build.mcu == "esp32", so every classic ESP32 image gets it and none can drift.
S2/S3/C-series and nRF52 keep the .bss singleton: they have no equivalent
static-DRAM ceiling, so there a guaranteed-present workspace is the better
trade for what is ultimately a recovery path. It has to be a build flag rather
than a header default, because OTA_HEAP_CONTEXT must hold the same value in
every translation unit that sees OtaContext.h - OtaContext.cpp included - and a
header test on CONFIG_IDF_TARGET_ESP32 would depend on include order relative
to sdkconfig.h. The script defers to OTA_SHARED_COMPANION_QUEUE where a Full
Companion recipe already owns the storage.

Fix a gap this exposes in the roles that now use it. Only CLI entry points
acquire the context, so once it was released, a repeater with the temporary
radio profile up would no longer serve or announce its own firmware - LoRa OTA
would look enabled and silently do nothing. ota_service_temp_radio_context()
holds the workspace for exactly the temp-radio window and hands it back
outside it, which is where the saving was coming from anyway. Wired into the
repeater, room server and sensor loops; the Companion keeps its own
acquire-on-host-demand policy, since its context is borrowed from the offline
message queue and must not be taken speculatively.

Static DRAM, classic ESP32 (bytes occupied of a 124,580 region):
  Heltec_v2_repeater                   108,332 -> 70,732
  Heltec_v2_room_server                 83,716 -> 68,300
  Heltec_v2_companion_radio_ble        123,236 -> 107,772  (was failing on main)
  Tbeam_SX1262_repeater                 86,932 -> 71,468
  Tbeam_SX1262_repeater_observer_mqtt  121,132 -> 83,532   (was failing)
2026-09-09 01:24:00 -07:00
MUSTARDTIGERFPV 1257ea4dc5 Free OtaContext-owned buffers when the context is torn down
OtaContext owns serve_buf, serve_self_leaves and serve_self_proof as raw
malloc'd pointers, and nothing freed them on teardown: self-serve only frees
them when it re-allocates, and reset_session() does not touch them. That was
harmless while the context was a permanent .bss singleton, but both dynamic
storage modes destroy it between operations - OTA_HEAP_CONTEXT deletes it,
and the Companion's borrowed queue runs ~OtaContext() in place. A self-serving
node reaches release with both self-serve buffers populated, so every
acquire/release cycle leaked them.

Give OtaContext a destructor that releases what it owns, and delete the copy
operations so the raw pointers cannot be double-freed.
2026-09-09 01:24:00 -07:00
MUSTARDTIGERFPV 0d42d3c8e1 Move large repeater tables off classic ESP32 static DRAM
Classic ESP32 links into a dram0_0_seg of only 124,580 bytes: memory.ld
carves the BT controller's 0xdb5c (56,156) reservation off the 0x2c200
window before the application gets any. Three large objects dominated what
was left, and Tbeam_SX1262_repeater_observer_mqtt overran the build's 8 KiB
static reserve by 4,744 bytes.

Heap-allocate them instead, each with a defined behaviour when the
allocation fails:

- OtaContext: generalize the Companion's borrowed-storage path behind
  OTA_DYNAMIC_CONTEXT and add OTA_HEAP_CONTEXT, which allocates the context
  on first use and frees it once no transfer, apply or folder link needs it.
  A repeater is idle nearly all the time, so the workspace is usually absent.
  Exhaustion is reported to the caller and the operation declines.
- ClientACL: the client table becomes a pointer with a live capacity;
  capacity 0 refuses new clients rather than writing through a null table.
- MyMesh flood packet filters: likewise, with flood_packet_filter_slots as
  the live bound for every rule loop. At capacity 0 the node forwards
  unfiltered, and both save paths refuse to write so a stored ruleset is
  never replaced by an empty file.

Also override the Arduino SDK's weak btInUse() in simple_repeater so
initArduino() releases the BT controller memory to the heap. That grows the
runtime heap these tables now come from; it cannot recover the same
reservation from the linker's static window.

Static DRAM, classic ESP32:
  Heltec_v2_repeater                   108,332 -> 70,732
  Tbeam_SX1262_repeater_observer_mqtt  121,132 -> 83,532  (was failing)
2026-09-09 01:24:00 -07:00
mikecarper f778d14c76 Add multi-tap channel navigation for messages 2026-09-08 22:47:15 -07:00
mikecarper c690f65376 Allow frequency changes over authorized LoRa CLI 2026-09-08 22:07:30 -07:00
mikecarper b9138c13b2 Allow local CLI maintenance across direct connections 2026-09-08 21:44:57 -07:00
mikecarper 99ff7bd693 Allow explicit contact imports with discovery filters enabled 2026-09-08 20:07:25 -07:00
mikecarper 5e6a74be50 Enable the shared terminal on WiFi-only Companions 2026-09-08 19:56:12 -07:00
mikecarper d178cf1474 Share the Companion terminal with the WiFi console 2026-09-08 19:48:15 -07:00
mikecarper cb79dcd4e3 Preserve MQTT settings across slot changes 2026-09-08 18:55:00 -07:00
mikecarper aa8caa4ed2 Unify device controls and restore the WiFi console 2026-09-08 18:36:23 -07:00
mikecarper 30d58d8e5b cleanup 2026-09-08 17:46:37 -07:00
mikecarper b2ce8a8c0a Add spacing to reader button hints 2026-09-08 17:38:45 -07:00
mikecarper 1b3e5daa02 Add button navigation hints to the hidden John reader 2026-09-08 17:31:18 -07:00
mikecarper 05fd0a4794 Merge origin/keymindCascade with companion button hints 2026-09-08 17:24:27 -07:00
mikecarper 74d87c8d13 Show button controls on companion home and message screens 2026-09-08 17:11:43 -07:00
mikecarper ac694d536e Place setup AP status below the WiFi address 2026-09-08 16:56:10 -07:00
mikecarper 42a8795db6 Show connected WiFi address on the V4 setup screen 2026-09-08 16:47:19 -07:00
mikecarper 4c1ed2593a Fix bootloader version discovery and tolerate legacy OTA probes 2026-09-08 16:17:43 -07:00
mikecarper 846282adf4 Use native display resolution and adaptive typography 2026-09-08 16:02:16 -07:00
mikecarper 0058f72192 Offer verified OTA source contact import with explicit approval 2026-09-08 15:33:19 -07:00
mikecarper 8f5614c958 Merge remote-tracking branch 'origin/keymindCascade' into keymindCascade 2026-09-08 14:33:02 -07:00
mikecarper 0651e1cdb8 Record 6px font build and V4 hardware results 2026-09-08 14:31:36 -07:00
mikecarper 4112671a75 Read Full Companion source identity from USB and TCP banners 2026-09-08 14:29:02 -07:00
mikecarper 469b47d190 Use readable 6px message font and keep 5px on tiny panels 2026-09-08 14:23:39 -07:00
mikecarper b40fcd37ef Check OTA build toolchains and bind sources by public key 2026-09-08 14:13:38 -07:00
mikecarper 03e42830b0 Avoid Python nesting limit in LoRa OTA preflight test 2026-09-08 13:51:20 -07:00
mikecarper 26aa8118c3 Merge remote-tracking branch 'origin/keymindCascade' into keymindCascade 2026-09-08 13:49:00 -07:00
mikecarper 4f97084126 Record small-screen font build and V4 hardware results 2026-09-08 13:46:18 -07:00
mikecarper eeea15ef01 Use compact message text and sender lines on all small displays 2026-09-08 13:36:40 -07:00
mikecarper f6fba1da91 Offer private cryptography repair before bootloader OTA staging 2026-09-08 13:35:57 -07:00
mikecarper a7f088290b Add a V4 Picopixel message font trial with longer previews 2026-09-08 13:22:53 -07:00
mikecarper e0bf7ae979 Document contact-cache RAM and hardware qualification results 2026-09-08 13:08:28 -07:00
mikecarper b68aa1c685 Enable dual WiFi OTA slots for the smaller 4 MiB NimBLE trials 2026-09-08 12:36:43 -07:00
mikecarper f2f93c4660 Support bootloader mOTA staging and guided host tool repair 2026-09-08 12:36:06 -07:00
mikecarper 468cc3cf56 Reset RX recovery deadline after successful transmissions 2026-09-08 12:35:37 -07:00
mikecarper be41d9dd79 Cache Full Companion paths and shared secrets to recover RAM 2026-09-08 12:21:30 -07:00
mikecarper b041fc7f4f Record V4 and XIAO NimBLE hardware trial results 2026-09-08 10:17:31 -07:00
mikecarper 9dbab4317d Avoid nested MQTT preference copies on the Companion loop stack 2026-09-08 10:05:59 -07:00
mikecarper 966ab823f0 Add standalone raw TCP CLI fallback for OTA scripts 2026-09-08 10:03:43 -07:00
mikecarper 7f1bd8b1d2 Add opt-in NimBLE Full Companion trials for V4 and XIAO S3 2026-09-08 09:30:31 -07:00
mikecarper 7ff11a2d64 Restore the V4 WiFi setup QR with a one-pixel border 2026-09-08 09:30:31 -07:00
mikecarper 626ead5433 Point Wireless Paper release catalogs to the 350-contact update 2026-09-08 08:17:28 -07:00
mikecarper 1e4d1e167a Restore Wireless Paper Full capacity with shared mOTA queue storage 2026-09-08 08:09:42 -07:00
mikecarper e0a229fb91 Publish memory-corrected 1.17.1.5 catalogs and picker directions 2026-09-08 02:53:48 -07:00
mikecarper aa20e9278e Gate every firmware build on runtime RAM and share nRF52 mOTA storage 2026-09-08 02:09:26 -07:00