radiolib: bring LinuxSX1262 to parity with CustomSX1262 - #3
Open
mmmorks wants to merge 1 commit into
Open
Conversation
LinuxSX1262 carried its own copy of the SX126x RX watchdog -- the preamble/header deadline state, startReceive(), isReceiving(), the millis setters and getRxBoostedGainMode() -- and that copy had drifted: upstream's RX-IRQ-timeout work (bounding a latched PREAMBLE_DETECTED that never becomes a packet) landed in every Custom*Wrapper but not here, so the Linux repeater kept an unbounded isReceiving() that reported busy forever after a preamble that went nowhere, deferring every transmit until getCADFailMaxDuration(). None of that logic is Linux-specific, and upstream keeps fixing it. Derive from CustomSX1262 instead. std_init() stays, shadowing the non-virtual base, because that part genuinely differs: the MCU variants pick regulator, RF switch and gain per board at compile time, while one binary here serves every HAT and reads all of it from meshcored.ini. Two of those compile-time knobs had no Linux equivalent at all, so they become keys: use_regulator_ldo (SX126X_USE_REGULATOR_LDO, begin()'s useRegulatorLDO) rx_register_patch (SX126X_REGISTER_PATCH, bit 0 of register 0x8B5) Both default to the compile-time defaults (DC-DC, no patch), so existing installs are unaffected. The wrapper gains the doResetAGC() override every other SX126x board has. Without it Linux fell through to RadioLibWrapper's fallback -- a bare sleep() -- so `set agc_int` was quietly a weaker knob here than anywhere else. The full reset (warm sleep, Calibrate(0x7F), calibrateImage() for the band) drops DIO2-as-RF-switch, RX boosted gain and the 0x8B5 patch, and the shared sx126xResetAGC() restores them from SX126X_* build flags that this variant does not define. So SX126xReset.h gains a second entry point that takes the settings as a struct, with the recalibration and the settings re-application each factored into one helper; the MCU overload keeps its #ifdef path and its behaviour. sx126xApplyRegisterPatch() replaces the register-poke that had grown to three verbatim copies. powerOff() comes along for parity (cold sleep rather than the base class's warm one); nothing on Linux calls it today. Also names the downcast once: _radio is held as the base mesh::Radio, and the wrapper repeated ((LinuxSX1262 *)_radio)-> seventeen times. Verified: clean linux_repeater build in the arm64 container. Neither new key is exercised on hardware -- that needs a module that wants them -- and the reset path is untested on hardware. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXSCjgNEbJfHwLjD2WSHW4
mmmorks
force-pushed
the
pr/02-config-validation
branch
from
September 8, 2026 04:11
b61c48c to
037b93f
Compare
mmmorks
force-pushed
the
pr/03-sx1262-parity
branch
from
September 8, 2026 04:11
d1082d7 to
294f8c5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LinuxSX1262carried a hand-copied subset ofCustomSX1262(the RX watchdog, the millis setters, the boosted-gain readback) and had drifted from it. This derives it fromCustomSX1262instead, keeps only the genuinely Linux-specific part (astd_init()that reads its settings frommeshcored.iniat runtime), and closes the two gaps that drift had opened: two SX126x build-flag knobs with no Linux equivalent, and an AGC reset that was a baresleep()on Linux.What changed
src/helpers/radiolib/LinuxSX1262.h:class LinuxSX1262 : public CustomSX1262. Upstream's RX-IRQ-timeout state machine (bounding a latchedPREAMBLE_DETECTEDthat never becomes a packet) now applies on Linux too; before this,isReceiving()here could report busy forever after a preamble that went nowhere, deferring every transmit untilgetCADFailMaxDuration().std_init()shadows the non-virtual base and takesLinuxConfigby reference.meshcored.inikeys, mirroring the compile-time flags the MCU variants use, defaulting to the compile-time defaults (DC-DC, no patch) so existing installs are unaffected:use_regulator_ldo(SX126X_USE_REGULATOR_LDO,begin()'suseRegulatorLDO)rx_register_patch(SX126X_REGISTER_PATCH, bit 0 of register0x8B5)LinuxSX1262Wrapper:doResetAGC()override running the full SX126x reset (warm sleep,Calibrate(0x7F),calibrateImage()for the configured band), like every other SX126x board. Without it,set agc_intfell through toRadioLibWrapper's baresleep()fallback.powerOff()for parity withCustomSX1262Wrapper(cold sleep). Nothing calls it on Linux today.((LinuxSX1262 *)_radio)->casts become oner()accessor.src/helpers/radiolib/SX126xReset.h: recalibration drops DIO2-as-RF-switch, RX boosted gain and the0x8B5patch, and the existingsx126xResetAGC(radio, bool)restores them fromSX126X_*build flags. A runtime-configured target has none of those, so this adds a second overload taking anSX126xRxSettingsstruct, factors the recalibration and the settings re-application intosx126xRecalibrate()/sx126xApplyRxSettings(), and replaces the three verbatim copies of the register poke withsx126xApplyRegisterPatch(). The MCU overload keeps its#ifdefpath and behaviour.CustomSX1262.h: usessx126xApplyRegisterPatch()(no behaviour change).Why
Everything in the copied code is shared SX126x logic that upstream keeps fixing (the RX timeout handling, which IRQ flag a timeout clears, the setters themselves all changed this year). Keeping a fork of it meant re-applying each fix by hand and silently missing the ones nobody noticed; the missed RX-timeout port above is the concrete example.
How it was tested
linux_repeaterbuild for arm64 in the container (build-docker.sh).Dependencies
Stacked on
pr/02-config-validation(uses itsparse_bool()for the two new keys). Review the last commit only until that merges.Shared code touched
src/helpers/radiolib/SX126xReset.h(additive: struct, two helpers, a secondsx126xResetAGCoverload; the existing overload's behaviour is unchanged)src/helpers/radiolib/CustomSX1262.h(register poke replaced by the helper; no behaviour change)src/helpers/radiolib/LinuxSX1262.h,LinuxSX1262Wrapper.h(Linux-only)Noticed in passing, not changed here:
CustomLLCC68Wrapper.hcallssx126xResetAGC((SX126x *)_radio)with one argument, which does not match either overload's signature. That is pre-existing in this tree.