Skip to content

refactor(radiolib): one template for LR1110 and LR1121 (step 9d, not for merge) - #36

Merged
marcelverdult merged 24 commits into
devfrom
refactor/9d-lr11x0-template
Oct 26, 2026
Merged

marcelverdult merged 24 commits into
devfrom
refactor/9d-lr11x0-template

Conversation

@marcelverdult

Copy link
Copy Markdown
Owner

CI only, not for merge into integration. Based on integration at 07fa9c5c (steps 1 to 4, 9a to 9c, 10a to 10c, 11 cuts A to D), so the diff against dev also shows the earlier steps. This PR's own commits are the last four (cec4fd2e, 683a8d51, 8bbf8caa, 67877a7f).

Step 9d of note 0009: CustomLR1110 and CustomLR1121 were copies. The inventory script (tools/refactoring/scripts/sx126x_inventory.py . lr11x0, now with a family argument) shows every member of LR1110 identical in LR1121 (begin() on DC-DC, getPacketLength() with the standby after a header error, receive detection, boosted gain, getters); the only hidden difference is the chip name in one debug line. LR1121 adds its band dependent power handling (setOutputPower() clipping to the active PA, setFrequency() applying the power again, LR1121_FORCE_HP_PA). Now one template CustomLR11x0<Base, Traits> in the shape of 9b's CustomSX126x; the traits hold only name() for the debug line (printed through %s, same text). CustomLR1110 is a thin subclass; CustomLR1121 is a subclass that keeps the power handling in its original text, the macro keeps its name and acts only there. Both stay real classes with the same names and non explicit constructors (RADIO_CLASS radio = new Module(...)). In src: 129 lines out, 92 in.

Evidence:

  • Host tests first (683a8d51) in native_radio_chips: a typed suite over both chips (begin arguments and defaults, DC-DC only after success, regulator error returned, standby only for length 0 with the header error bit, getters are the members, boosted gain flag stored before the chip answers) and 8 power tests (LR1110 straight to RadioLib; LR1121 clipping, requested power remembered only on success, re-applied after a successful frequency change), plus 5 in test_radio_chips_init with MESH_DEBUG and LR1121_FORCE_HP_PA (the debug line per chip, the forced high power PA). native_radio_chips 251 cases (218 before, 33 new) on the test and the code commit; all 22 native environments 818 cases, one skipped, on the code commit. 17 mutations caught, among them the power handling pulled into the template (M17, fails only for LR1110) and LR1121_FORCE_HP_PA ignored (M13).
  • Builds of all 48 environments with CustomLR1110/CustomLR1121 plus 7 controls (nRF52, ESP32, RP2040, STM32; SX1262, STM32WLx, SX1276, LR2021), before and after in the same worktree, every build with SOURCE_DATE_EPOCH set and ELF files kept. All 55 build on both sides; RAM unchanged in all; the 7 control images are byte identical. Flash: nRF52 LR1110/LR1121 and ESP32 LR1121 +0; ESP32 LR1110 (ThinkNode M7/M9) -16 to +8. nm -S -C of all 48 pairs: 35 have no symbol of another size (all nRF52, all Waveshare_S3_LR1121_* which set LR1121_FORCE_HP_PA); in the 13 ESP32 LR1110 builds the changed functions were disassembled: same instructions, differences are branch target padding, narrow/wide encodings and one register choice in the static initializer.
  • No board test (no hardware claimed).

Upstream collisions (checked 22 October 2026, all 493 open PRs): meshcore-dev#3638 is heavy textually but lands in the thin CustomLR1110 subclass (its standby() override is still reached from the template's getPacketLength() through the vtable); meshcore-dev#3261 changes getPacketLength() for LR1110 only, so on rebase it chooses between a subclass override and the template (which would also give LR1121 the fix); meshcore-dev#3496 becomes one edit instead of two; meshcore-dev#2682, meshcore-dev#2999, meshcore-dev#2696, meshcore-dev#2198 create CustomLR1121.h as a new file and already conflict. Details in the note.

…the board description

Inventory of the radio blocks in the 89 target.cpp (tools/refactoring/
variant_target_globals.py), why objects cannot be weak, the opt-in macro
RADIOLIB_TARGET_GLOBALS in target.h, the split into D1 (31 nRF52) and
D2 (22 ESP32 with the shared radio_init()), rejected alternatives and the
open upstream pull requests that touch the same lines.
…riants

A new host suite (native_variant_target_globals) builds the shared variant
code against the target.h of a variant with the real AutoDiscoverRTCClock,
with the radio block of the 31 nRF52 variants of cut C copied verbatim: the
radio is built from a Module on the board pins in SX126x order with SPI
passed, radio_driver wraps it and the board, rtc_clock falls back to and
ticks fallback_clock, and the shared radio_init() starts that radio. The
variant stand-ins move into variant_stubs.h and gain a Module stand-in.
… variants

RadioLibTarget.cpp defines radio, radio_driver, fallback_clock and
rtc_clock for the variants whose target.h defines the new opt-in macro
RADIOLIB_TARGET_GLOBALS, built from the P_LORA_* pins: on nRF52 the radio
is a Module on SPI, the fallback clock a VolatileRTCClock. Not weak: a weak
object would still be constructed into a variant's own one. Other platforms
and the SX1276 pin order stop the build with an #error until described.

The 31 nRF52 variants of cut C delete their block from target.cpp
(deletions only) and add the macro line to target.h (additions only).
The host suite now runs its cases against the shared globals.
…riants

A host suite in four environments, one per board description that occurs
among the 22 ESP32 variants of cut D2 (SX1262 on an own bus on the default
host, without P_LORA_SCLK, SX1276, own bus on another host), with their
blocks and radio_init() bodies copied verbatim: the Module's pins in the
chip's order, its bus (own, on which host, or none), what radio_driver
wraps, the fallback clock, and that radio_init() starts the fallback clock,
the RTC and then the radio on its bus, passing the result through. The SPI
stand-in gets bus numbers, the radio stand-in tells the module's bus apart.
…r 22 ESP32 variants

RadioLibTarget.cpp describes the radio globals for ESP32 as well: the pins
in the chip's order (SX1276: DIO0, RESET, DIO1), an own SPIClass where the
board names P_LORA_SCLK, on P_LORA_SPI_HOST if set, otherwise no bus so that
RadioLib starts its default one, and an ESP32RTCClock as fallback clock. For
those variants with an SX126x or SX1276 it adds a weak radio_init(): start
the fallback clock and the RTC, then the radio on its bus.

The 22 ESP32 variants left by cut C delete their block and radio_init()
from target.cpp (deletions only) and add the opt-in, and five of them
P_LORA_SPI_HOST (FSPI, or 0 on the C6), to target.h (additions only).
@marcelverdult
marcelverdult merged commit 140bf82 into dev Oct 26, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant