Fix LR2021 occasionally stopping reception after a TX power change - #3218
Open
fkallay1 wants to merge 1 commit into
Open
Fix LR2021 occasionally stopping reception after a TX power change#3218fkallay1 wants to merge 1 commit into
fkallay1 wants to merge 1 commit into
Conversation
RadioLibWrapper::setTxPower() called setOutputPower() and nothing else. On
LR2021 that writes the PA config and TxParams, which are standby-only commands,
and it never re-arms the receiver.
This only affects LR2021 boards. recvRaw() has:
#if defined(USE_LR2021)
state = STATE_RX; // LR2021 stays in Rx after readData
#else
state = STATE_IDLE; // need another startReceive()
#endif
so on SX126x the next recvRaw() re-arms Rx anyway and the write is harmless,
while on LR2021 startReceive() is never called again on its own. A 'set tx'
issued while the radio was listening could therefore stop reception until the
next reboot. Observed a few times on an LR2021 repeater; recovery required a
power cycle.
Dispatcher's stuck-radio check does not catch it: isInRecvMode() reports the
wrapper's own `state` flag rather than the chip's actual mode, so it still
believes the radio is in Rx, and it only raises ERR_EVENT_STARTRX_TIMEOUT
without attempting recovery.
Fix: on LR2021, drop to standby via idle() before writing the PA config and let
checkRecv() re-arm Rx - the same pattern resetAGC() and
applySideDetectorConfig() already use. Other radios are left untouched.
Affects meshtracker_x1 and meshnology_w12 (both USE_LR2021).
Tested on hardware with an LR2021 repeater: six consecutive 'set tx' changes
(15/18/21/14/19/14), after which the radio kept receiving and forwarding
traffic (rawrx/rxpkts increasing, no missed IRQs). Noise-floor sampling also
kept updating, which only happens while state == STATE_RX.
fkallay1
added a commit
to fkallay1/MeshCore
that referenced
this pull request
Aug 15, 2026
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.
Type: bug
Symptom
On an LR2021 board, changing the transmit power at runtime (
set tx <dbm>)could stop the radio from receiving. Nothing recovered it — the node kept
running and still transmitted its own adverts, but never received another
packet until it was rebooted. It happened only occasionally, a few times over
several hours of use.
Cause
RadioLibWrapper::setTxPower()callssetOutputPower()and nothing else:On LR2021 that writes the PA config and TxParams, which are standby-only
commands, and the receiver is never re-armed afterwards.
This only bites on LR2021 because of the platform split in
recvRaw():On SX126x the state falls back to
STATE_IDLE, so the nextrecvRaw()callsstartReceive()regardless and the write is harmless. On LR2021 the wrapperkeeps
STATE_RXforever, so nothing callsstartReceive()on its own. If thePA config write knocks the receiver down, it stays down.
setTxPower()is the only setter in the wrapper that does not do this —idle(),resetAGC()andapplySideDetectorConfig()all setstate = STATE_IDLEto trigger a freshstartReceive().The stuck-radio check in
Dispatcher::loop()cannot catch this either:isInRecvMode()reports the wrapper's ownstateflag rather than the chip'sactual mode, so it still believes the radio is in Rx. And even when it does
trip, it only raises
ERR_EVENT_STARTRX_TIMEOUTwithout attempting recovery.Fix
On LR2021, drop to standby via
idle()before writing the PA config, and letcheckRecv()re-arm Rx — the same pattern the other setters already use.Other radios are left untouched, since they re-arm on their own.
Affected boards
meshtracker_x1andmeshnology_w12(both build withUSE_LR2021).Testing
Verified on hardware with an LR2021 repeater (Seeed XIAO nRF52840 with a NiceRF
LoRa2021F33-2G4 module, 869.618 MHz, SF7, BW 62.5):
set tx, with noway back other than a reboot.
radio fully functional: it kept receiving and forwarding mesh traffic
(
rawrx/rxpktsincreasing, no missed IRQs). Noise-floor sampling also keptupdating, which is an independent confirmation that Rx was re-armed, since
that sampling only runs while
state == STATE_RX.MeshTracker_X1_repeaterbuilds clean.