Merge PR #7 with reviewed ExpressLRS power and memory fixes
Integrate ExpressLRS TX module support and its stacked ESP32 heap changes. Use the approved Linkflow calibration (17-30 dBm), preserve the PA drive and output path after radio recovery, and keep LoRa OTA enabled. Preserve stored ACLs and filters on allocation failure, release owned client/filter buffers, service heap OTA contexts on Companions, release self-serving workspaces after TempRadio, and reset staged-resume state when a context is released. Keep manual staging and active operations alive. Account for all moved allocations in the runtime RAM gate. Validation: 1,393 native cases; radio-power, heap-context, ACL persistence, shared-queue transfer, display/inbox, radio receive, and memory regressions. Firmware builds passed for Linkflow, Heltec V2 Companion, T-Beam MQTT repeater, Heltec V4 R8 MQTT repeater, RAK4631 repeater, and Indicator Full. Physical verification awaits access to the currently offline lab Pi.
This commit is contained in:
commit
fa010196b1
26 files changed
+1072
-74
No files matched your search
@@ -0,0 +1,114 @@
|
||||
; GEPRC LINKFLOW 900M TX - an ExpressLRS 900 MHz transmitter module.
|
||||
;
|
||||
; ESP32-D0WDQ6, 4 MB flash, SX1276 driving an external PA whose gain is set
|
||||
; from a DAC pin. The board itself is a plain ExpressLRS TX module, so the
|
||||
; two classes it uses are shared:
|
||||
;
|
||||
; helpers/esp32/ELRSTxBoard.h fan + backpack + no battery
|
||||
; helpers/radiolib/DacPaSX1276Wrapper.h DAC-controlled amplifier gain
|
||||
;
|
||||
; Every pin below is the value from the ExpressLRS hardware layout for this
|
||||
; module - ExpressLRS target "GEPRC LINKFLOW 900M TX", firmware
|
||||
; Unified_ESP32_900_TX. The current approved power calibration is cited in
|
||||
; target.cpp. Two entries in that layout are deliberately unused:
|
||||
; serial_rx/serial_tx (both GPIO13, the inverted half-duplex CRSF link to the
|
||||
; handset) and the backpack UART on GPIO16/17.
|
||||
|
||||
[GEPRC_Linkflow_900]
|
||||
extends = esp32_base
|
||||
board = esp32dev
|
||||
board_build.partitions = variants/dual_ota_1536k.csv
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-I variants/geprc_linkflow_900
|
||||
-D GEPRC_LINKFLOW_900
|
||||
-D MANUFACTURER_NAME='"GEPRC LINKFLOW 900M TX"'
|
||||
|
||||
; ---- radio ----
|
||||
-D RADIO_CLASS=CustomSX1276
|
||||
-D WRAPPER_CLASS=DacPaSX1276Wrapper
|
||||
-D P_LORA_SCLK=18
|
||||
-D P_LORA_MISO=19
|
||||
-D P_LORA_MOSI=23
|
||||
-D P_LORA_NSS=5
|
||||
-D P_LORA_RESET=14
|
||||
-D P_LORA_DIO_0=4
|
||||
-D P_LORA_DIO_1=21
|
||||
-D SX127X_CURRENT_LIMIT=120
|
||||
|
||||
; ---- RF switch ----
|
||||
; The board only brings out RX_EN (hardware.json "power_rxen"); there is no
|
||||
; TX_EN pin. Leaving SX127X_TXEN undefined makes RadioLib drive this pin
|
||||
; HIGH for RX and LOW for TX, which is what a single-pin switch wants.
|
||||
; NOTE: GPIO12 is also the MTDI flash-voltage strapping pin, so it has to
|
||||
; stay low through reset. Do not add a pull-up here.
|
||||
-D SX127X_RXEN=12
|
||||
|
||||
; ---- frequency ----
|
||||
; This module's own ExpressLRS options blob had "domain": 1, which is
|
||||
; FCC915 in FHSS.cpp (903.5 - 926.9 MHz). So it is a US 915 MHz unit, and
|
||||
; the 869.618 inherited from arduino_base is wrong for it. build_unflags
|
||||
; below drops the inherited one so this is the only definition.
|
||||
-D LORA_FREQ=910.525
|
||||
|
||||
; ---- TX power ----
|
||||
; ExpressLRS layout "power_apc2". The dBm-to-DAC table lives in target.cpp.
|
||||
-D PIN_PA_APC2=26
|
||||
|
||||
; These numbers are dBm at the antenna, i.e. after the amplifier. The
|
||||
; SX1276 itself sits at a fixed +2 dBm; see DacPaSX1276Wrapper.h.
|
||||
; 17 dBm (50 mW) is the stock ExpressLRS "power_default" for this board.
|
||||
;
|
||||
; LORA_TX_POWER must stay within 2..17. CustomSX1276::std_init() passes it
|
||||
; straight to RadioLib's begin(), and PA_BOOST rejects anything outside that
|
||||
; range, which would fail radio_init(). It only sets the startup level;
|
||||
; MIN/MAX below are what bound the range at runtime, and those go through
|
||||
; the DAC, so they are free to be higher.
|
||||
;
|
||||
; MAX_LORA_TX_POWER is defined once and used twice: the CLI validates
|
||||
; against it, and target.cpp hands the same value to the wrapper, which
|
||||
; enforces it in applyCachedTxPower(). The wrapper also refuses anything
|
||||
; outside its own table regardless, so a board that omits these flags is
|
||||
; still bounded by what the amplifier table actually describes.
|
||||
;
|
||||
; The amplifier will do 33 dBm (2 W), but ExpressLRS only ever asks for that
|
||||
; in short packet bursts. MeshCore transmits for far longer, so the ceiling
|
||||
; here is one table entry lower. Raise it to 33 only with cooling you
|
||||
; trust, and check your local duty-cycle and EIRP limits first.
|
||||
-D LORA_TX_POWER=17
|
||||
-D MIN_LORA_TX_POWER=17
|
||||
-D MAX_LORA_TX_POWER=30
|
||||
|
||||
; ---- board ----
|
||||
-D PIN_FAN_EN=32 ; hardware.json "misc_fan_en"
|
||||
-D PIN_BACKPACK_EN=25 ; hardware.json "backpack_en"
|
||||
-D PIN_BACKPACK_BOOT=15 ; hardware.json "backpack_boot"
|
||||
|
||||
; WS2812 on GPIO27. hardware.json says GRB ordering, which is what
|
||||
; neopixelWrite() emits.
|
||||
-D P_LORA_TX_NEOPIXEL_LED=27
|
||||
|
||||
; The CH340 on this board is not reliable above 230400 for flash access;
|
||||
; 460800 and 921600 both corrupt mid-transfer.
|
||||
upload_speed = 115200
|
||||
build_unflags =
|
||||
-D LORA_FREQ=869.618
|
||||
build_src_filter = ${esp32_base.build_src_filter}
|
||||
+<../variants/geprc_linkflow_900>
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
|
||||
[env:GEPRC_Linkflow_900_repeater]
|
||||
extends = GEPRC_Linkflow_900
|
||||
build_flags =
|
||||
${GEPRC_Linkflow_900.build_flags}
|
||||
-D ADVERT_NAME='"Linkflow Repeater"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
build_src_filter = ${GEPRC_Linkflow_900.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${GEPRC_Linkflow_900.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <Arduino.h>
|
||||
#include "target.h"
|
||||
|
||||
ELRSTxBoard board;
|
||||
|
||||
static SPIClass spi;
|
||||
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
|
||||
|
||||
// The "power_values" array from the ExpressLRS hardware layout for this
|
||||
// module (ExpressLRS target "GEPRC LINKFLOW 900M TX", firmware
|
||||
// Unified_ESP32_900_TX), paired with the PowerLevels_e step each index maps
|
||||
// to. power_min is 2, so index 0 is PWR_50mW. Approved measured calibration:
|
||||
// https://github.com/ExpressLRS/Targets/blob/504178dcfa469ee32f4290d6ae9ba02e2f2f365e/TX/GEPRC%20900%20Linkflow.json
|
||||
// The older eight-step table overdrives the PA at its lower settings.
|
||||
static const DacPaLevel POWER_LEVELS[] = {
|
||||
{ 17, 0 }, // 50 mW <- ExpressLRS minimum and default
|
||||
{ 20, 22 }, // 100 mW
|
||||
{ 24, 50 }, // 250 mW
|
||||
{ 27, 75 }, // 500 mW
|
||||
{ 30, 130 }, // 1000 mW
|
||||
{ 33, 225 }, // 2000 mW <- above MAX_LORA_TX_POWER, see platformio.ini
|
||||
};
|
||||
|
||||
// MAX_LORA_TX_POWER is the single definition of this board's ceiling: the CLI
|
||||
// validates against it, and the wrapper enforces it independently so a request
|
||||
// that gets past the CLI cannot saturate the amplifier at its top table entry.
|
||||
WRAPPER_CLASS radio_driver(radio, board, PIN_PA_APC2,
|
||||
POWER_LEVELS,
|
||||
sizeof(POWER_LEVELS) / sizeof(POWER_LEVELS[0]),
|
||||
MAX_LORA_TX_POWER);
|
||||
|
||||
ESP32RTCClock fallback_clock;
|
||||
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||
SensorManager sensors;
|
||||
|
||||
bool radio_init() {
|
||||
fallback_clock.begin();
|
||||
rtc_clock.begin(Wire);
|
||||
|
||||
if (!radio.std_init(&spi)) return false;
|
||||
|
||||
// std_init() left the SX1276 at LORA_TX_POWER, which on this board is a
|
||||
// post-amplifier number. Hand power control over to the amplifier instead.
|
||||
return radio_driver.beginPowerControl(LORA_TX_POWER);
|
||||
}
|
||||
|
||||
mesh::LocalIdentity radio_new_identity() {
|
||||
RadioNoiseListener rng(radio);
|
||||
return mesh::LocalIdentity(&rng); // create new random identity
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#define RADIOLIB_STATIC_ONLY 1
|
||||
#include <RadioLib.h>
|
||||
#include <helpers/radiolib/RadioLibWrappers.h>
|
||||
#include <helpers/esp32/ELRSTxBoard.h>
|
||||
#include <helpers/radiolib/DacPaSX1276Wrapper.h>
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <helpers/SensorManager.h>
|
||||
|
||||
extern ELRSTxBoard board;
|
||||
extern WRAPPER_CLASS radio_driver;
|
||||
extern AutoDiscoverRTCClock rtc_clock;
|
||||
extern SensorManager sensors;
|
||||
|
||||
bool radio_init();
|
||||
mesh::LocalIdentity radio_new_identity();
|
||||
Reference in new issue
Block a user