diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index 1de223ce1..1d5dcd6de 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -409,9 +409,10 @@ mesh::RadioParamApplyResult RadioLibWrapper::prepareTransmitProfile(uint8_t prof mesh::RadioParamApplyResult RadioLibWrapper::tryRestoreCodingRate(uint8_t cr) { const uint8_t resume_rx = beginReconfigure(); if (resume_rx > 1) return mesh::RadioParamApplyResult::BUSY; - const bool applied = setCodingRate(cr); - if (!applied) _profile_refresh_required = true; + bool applied = setCodingRate(cr); endReconfigure(resume_rx); + applied = applied && (!resume_rx || isInRecvMode()); + if (!applied) _profile_refresh_required = true; return applied ? mesh::RadioParamApplyResult::APPLIED : mesh::RadioParamApplyResult::FAILED; } @@ -552,7 +553,11 @@ mesh::RadioParamApplyResult RadioLibWrapper::trySetPrimaryParams(const mesh::Rad _profiles.primary_temporary = was_temp; _profiles.generation[0] = generation; } else { - _profiles.generation[0] = generation + (previous != p || was_temp != temporary); + const bool changed = previous != p || was_temp != temporary; + _profiles.generation[0] = generation + changed; + // Preamble and lease flags are staged before trySetParams(), so its + // setPrimary() cannot detect a change limited to those fields. + if (changed) _profiles.resetSwitchTest(); _profile_generation = _profiles.generation[0]; } return result; diff --git a/test/test_radio_profile_scan.py b/test/test_radio_profile_scan.py index 116ff5811..ed3242f4c 100644 --- a/test/test_radio_profile_scan.py +++ b/test/test_radio_profile_scan.py @@ -153,6 +153,22 @@ int main() { assert(w.coding_writes==1 && state==STATE_RX); assert(w._profile_refresh_required==!success); } + { + RadioLibWrapper w; state=STATE_IDLE; + assert(w.tryRestoreCodingRate(5)==Result::APPLIED); + assert(w.coding_writes==1 && state==STATE_IDLE && !w._profile_refresh_required); + } + { + RadioLibWrapper w; w.failRxStarts=1; + assert(w.tryRestoreCodingRate(5)==Result::FAILED); + assert(w.coding_writes==1 && state==STATE_IDLE && w._profile_refresh_required); + // The normal receive re-arm and profile refresh can recover after a + // transient restart failure; a later coding-rate restore then succeeds. + w.startRecv(); w.serviceProfileScan(); + assert(w.isInRecvMode() && !w._profile_refresh_required); + assert(w.tryRestoreCodingRate(5)==Result::APPLIED); + assert(w.coding_writes==2 && w.isInRecvMode() && !w._profile_refresh_required); + } { // Force only admits a reply on an active RX-only profile. It cannot // enable a disabled profile or erase an in-progress reception. @@ -329,6 +345,47 @@ int main() { assert(w.chip.standbyXOSC && !w._profile_standby_held && !w._rx_ps_enabled); w.setProfileStandbyWarm(false); assert(w.chip.standbyXOSC); } + for (bool preamble_only : {false,true}) { + RadioLibWrapper w; w.enable(); + const auto original=w._profiles; + auto requested=original.primary; + if (preamble_only) requested.preamble=64; + assert(w.trySetPrimaryParams(requested,!preamble_only)==Result::APPLIED); + assert(w._profiles.primary==requested && w._profiles.primary_temporary==!preamble_only); + assert(w._profiles.generation[0]==original.generation[0]+1); + assert(!w._profiles.switchTestReady() && w._profiles.switchBudgetUs()==0); + assert(w._profiles.switch_test_samples[0]==0 && w._profiles.switch_test_samples[1]==0); + w.serviceProfileScan(); assert(w._profiles.switchTestReady()); + } + { + RadioLibWrapper w; w.enable(); + const auto original=w._profiles; + assert(w.trySetPrimaryParams(original.primary,false)==Result::APPLIED); + assert(w._profiles.generation[0]==original.generation[0]); + assert(w._profiles.switchTestReady() && w._profiles.switchBudgetUs()==original.switchBudgetUs()); + for (unsigned i=0;i<2;++i) { + assert(w._profiles.switch_test_samples[i]==original.switch_test_samples[i]); + assert(w._profiles.switch_test_max_us[i]==original.switch_test_max_us[i]); + } + } + for (bool preamble_only : {false,true}) for (bool busy : {false,true}) { + RadioLibWrapper w; w.enable(); + const auto original=w._profiles; + const auto original_preamble=w._physical_preamble; + auto requested=original.primary; + if (preamble_only) requested.preamble=64; + w.packet=busy; + if (!busy) w.failRxStarts=1; + assert(w.trySetPrimaryParams(requested,!preamble_only)==(busy?Result::BUSY:Result::FAILED)); + assert(w._profiles.primary==original.primary && !w._profiles.primary_temporary); + assert(w._profiles.generation[0]==original.generation[0]); + assert(w._physical_preamble==original_preamble); + assert(w._profiles.switchTestReady() && w._profiles.switchBudgetUs()==original.switchBudgetUs()); + for (unsigned i=0;i<2;++i) { + assert(w._profiles.switch_test_samples[i]==original.switch_test_samples[i]); + assert(w._profiles.switch_test_max_us[i]==original.switch_test_max_us[i]); + } + } for (int reason=0;reason<4;++reason) { RadioLibWrapper w; if (reason==0) w.busy=true;