From 21a588ca091930e7eaa56ebff1562375cd7c82f6 Mon Sep 17 00:00:00 2001 From: mikecarper Date: Mon, 19 Oct 2026 21:11:44 -0700 Subject: [PATCH] Default radio profile crossover to off --- docs/radio_profiles.md | 4 ++-- src/RadioProfiles.h | 2 +- src/helpers/RadioProfileCLI.cpp | 4 ++-- src/helpers/RadioProfileCLI.h | 2 +- test/fixtures/radio_profiles/cli.cpp | 12 +++++++++++- .../test_companion_node_prefs.cpp | 4 ++-- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/docs/radio_profiles.md b/docs/radio_profiles.md index fa24df0a4..f5c87df32 100644 --- a/docs/radio_profiles.md +++ b/docs/radio_profiles.md @@ -20,7 +20,7 @@ Frequencies are MHz; bandwidths are kHz. The driver validates each tuple against Modes are `rx`, `rxtx` and `off`; `rx&tx` aliases `rxtx`. Bare `tempradio ...` remains supported. Temporary durations are 1–10080 minutes. -`cross auto` permits crossover when both profiles are permanent or both are temporary. `on` always permits it; `off` keeps traffic on its originating profile. An RX-only profile never transmits. Replies follow receive affinity and crossover policy; queued packets from replaced sessions are discarded. +Crossover defaults to `off`. `cross auto` permits crossover when both profiles are permanent or both are temporary. `on` always permits it; `off` keeps traffic on its originating profile. An RX-only profile never transmits. Replies follow receive affinity and crossover policy; queued packets from replaced sessions are discarded. ```text set radio2 915,125,8,5,rxtx @@ -60,4 +60,4 @@ SX1262 and LR1110 switches reuse acknowledged RX settings and keep the oscillato Scanning and pending timers keep the MCU awake. One transceiver cannot receive both profiles simultaneously; acquisition still depends on peer preambles, traffic and application delays. -Permanent settings use existing preferences JSON. Missing fields default to secondary off and automatic timing/crossover. Temporary settings and schedules disappear on reboot. Scheduled permanent settings are saved only after application. +Permanent settings use existing preferences JSON. Missing fields default to secondary off, crossover off and automatic timing. Temporary settings and schedules disappear on reboot. Scheduled permanent settings are saved only after application. diff --git a/src/RadioProfiles.h b/src/RadioProfiles.h index 5b277fec7..d9d46e2f9 100644 --- a/src/RadioProfiles.h +++ b/src/RadioProfiles.h @@ -61,7 +61,7 @@ class RadioProfiles { RadioProfileConfig secondary; bool primary_temporary = false; bool secondary_temporary = false; - RadioCrossMode cross = RadioCrossMode::Auto; + RadioCrossMode cross = RadioCrossMode::Off; uint32_t generation[2] = {1, 1}; uint32_t switches = 0; uint32_t rx_packets[2] = {}; diff --git a/src/helpers/RadioProfileCLI.cpp b/src/helpers/RadioProfileCLI.cpp index 46a1a5da8..174616dd3 100644 --- a/src/helpers/RadioProfileCLI.cpp +++ b/src/helpers/RadioProfileCLI.cpp @@ -100,8 +100,8 @@ void RadioProfileCLI::begin(CommonRadioPrefs& prefs, Radio& radio, RTCClock& clo if (primary_preamble_ && (primary_preamble_ < 8 || primary_preamble_ > RadioProfiles::MaxPreamble)) primary_preamble_ = 0; if (uint8_t(saved_.mode) > uint8_t(RadioProfileMode::RxTx) || (saved_.mode != RadioProfileMode::Off && !radio.validateProfile(saved_.params))) saved_ = {}; - if (cross_ > uint8_t(RadioCrossMode::Off)) cross_ = 0; - radio.profiles()->cross = cross_ <= uint8_t(RadioCrossMode::Off) ? RadioCrossMode(cross_) : RadioCrossMode::Auto; + if (cross_ > uint8_t(RadioCrossMode::Off)) cross_ = uint8_t(RadioCrossMode::Off); + radio.profiles()->cross = RadioCrossMode(cross_); RadioProfileConfig primary; primary.params = savedPrimary(); primary.mode = RadioProfileMode::RxTx; queue(0, primary, false, false, uint32_t(millis())); if (uint8_t(saved_.mode) <= uint8_t(RadioProfileMode::RxTx) diff --git a/src/helpers/RadioProfileCLI.h b/src/helpers/RadioProfileCLI.h index 5034bce95..e19f60c5e 100644 --- a/src/helpers/RadioProfileCLI.h +++ b/src/helpers/RadioProfileCLI.h @@ -31,7 +31,7 @@ class RadioProfileCLI : public ConfigSerializer { bool restoring_[2] = {}; RadioProfileConfig saved_; uint16_t primary_preamble_ = 0; - uint8_t cross_ = 0; + uint8_t cross_ = uint8_t(RadioCrossMode::Off); CommonRadioPrefs* prefs_ = nullptr; Radio* radio_ = nullptr; RTCClock* rtc_ = nullptr; diff --git a/test/fixtures/radio_profiles/cli.cpp b/test/fixtures/radio_profiles/cli.cpp index c0ca2e4eb..064660a23 100644 --- a/test/fixtures/radio_profiles/cli.cpp +++ b/test/fixtures/radio_profiles/cli.cpp @@ -60,6 +60,8 @@ public: int main(int argc,char**argv) { assert(argc==2);std::string name=argv[1]; Rig r; if(name=="parse") { + assert(r.cmd("get radio2.cross")=="> off"); + assert(r.radio.state.cross==mesh::RadioCrossMode::Off&&!r.radio.state.canCross()); const char* bad[]={"set radio2 915,125,8,5", "set radio2 nan,125,8,5,rx", "set radio2 1e3,125,8,5,rx", "set radio2 +915,125,8,5,rx", "set radio2 915,124,8,5,rx", "set radio2 915,125,256,5,rx", "set radio2 915,125,8,261,rx", "set radio2 915,125,8,5,both", "set radio2 915,125,8,5,rx,7", @@ -132,7 +134,15 @@ int main(int argc,char**argv) { assert(radio.state.secondary.params.preamble==40&&radio.state.secondary.mode==mesh::RadioProfileMode::RxTx&&radio.state.cross==mesh::RadioCrossMode::Off); char reply[160];loaded.profileCLI().handle("get radio2at",reply);assert(!strcmp(reply,"> off"));loaded.profileCLI().handle("get tempradio",reply);assert(!strcmp(reply,"> off")); Prefs legacy;MemoryStream old("{freq:868.5,bw:125,sf:9,cr:5}");assert(legacy.loadSerial(old));mesh::Radio oldradio;legacy.profileCLI().begin(legacy,oldradio,rtc);legacy.profileCLI().loop(); - assert(!oldradio.state.enabled()&&oldradio.state.primary.preamble==0&&oldradio.state.cross==mesh::RadioCrossMode::Auto); + assert(!oldradio.state.enabled()&&oldradio.state.primary.preamble==0&&oldradio.state.cross==mesh::RadioCrossMode::Off); + const char* saved_cross[]={"{profiles:{cross:0}}","{profiles:{cross:1}}","{profiles:{cross:2}}","{profiles:{cross:255}}","{profiles:{mode:0}}"}; + for(unsigned value=0;value<5;++value) { + Prefs prefs;MemoryStream input(saved_cross[value]);assert(prefs.loadSerial(input));mesh::Radio restored; + prefs.profileCLI().begin(prefs,restored,rtc); + assert(restored.state.cross==(value<3?mesh::RadioCrossMode(value):mesh::RadioCrossMode::Off)); + MemoryStream output;assert(prefs.saveSerial(output)); + assert(output.text.find(value==0?"cross:0":value==1?"cross:1":"cross:2")!=std::string::npos); + } test_millis=UINT32_MAX-500;r.ok("set radio2.cross on");assert(r.cli.saveDue());assert(!r.cli.saveDue()); test_millis+=1000;assert(r.cli.saveDue());r.prefs.clearDirty();assert(!r.cli.saveDue()); } else if(name=="legacy") { diff --git a/test/test_companion_node_prefs/test_companion_node_prefs.cpp b/test/test_companion_node_prefs/test_companion_node_prefs.cpp index 9ce533711..bf808fbd0 100644 --- a/test/test_companion_node_prefs/test_companion_node_prefs.cpp +++ b/test/test_companion_node_prefs/test_companion_node_prefs.cpp @@ -111,7 +111,7 @@ TEST(CompanionNodePrefs, RadioProfilesRoundTripInExistingPrefs) { EXPECT_NE(std::string::npos, output.text().find("cross:2")); } -TEST(CompanionNodePrefs, LegacyPrefsDefaultToOneProfileAndAutomaticPreamble) { +TEST(CompanionNodePrefs, LegacyPrefsDefaultToOneProfileNoCrossoverAndAutomaticPreamble) { NodePrefs prefs; ReplayStream input("{radio:{freq:869.525,bw:125,sf:8,cr:5}}"); ASSERT_TRUE(prefs.loadSerial(input)); @@ -121,7 +121,7 @@ TEST(CompanionNodePrefs, LegacyPrefsDefaultToOneProfileAndAutomaticPreamble) { EXPECT_EQ(0, profiles.savedPrimary().preamble); CaptureStream output; ASSERT_TRUE(prefs.saveSerial(output)); - EXPECT_NE(std::string::npos, output.text().find("cross:0")); + EXPECT_NE(std::string::npos, output.text().find("cross:2")); } int main(int argc, char** argv) {