mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-23 21:33:53 +00:00
Default radio profile crossover to off
This commit is contained in:
1 parent
b18bd79da2
commit
44ba5b4f18
13 files changed
+70
-17
No files matched your search
@@ -2145,11 +2145,11 @@
|
||||
section("Companion tempradio2: transmit on both", [
|
||||
{ label: "Transmit on both", commands: ["set radio2.cross on"],
|
||||
text: "After setting tempradio2 to rxtx, run this to send new messages on both radio and tempradio2. rxtx enables transmission on the second profile; cross on enables copying between the two profiles." },
|
||||
{ label: "Default isolation", commands: ["set radio2.cross auto"],
|
||||
text: "Keep ordinary local messages on radio and local LoRa OTA traffic on tempradio2. With auto, a permanent and a temporary profile remain isolated." },
|
||||
{ label: "Default isolation", commands: ["set radio2.cross off"],
|
||||
text: "Keep ordinary local messages on radio and local LoRa OTA traffic on tempradio2. Off disables copying between profiles, including two permanent profiles." },
|
||||
{ label: "Check", commands: ["get tempradio2", "get radio2.cross", "get radio2.status"],
|
||||
text: "Confirm tempradio2 is active in rxtx mode. TX=a,b reports primary and secondary transmit counts." },
|
||||
], "radio2.cross is saved and stays set after tempradio2 expires or the node reboots. Turning it on also allows OTA traffic to cross profiles. RX-only mode still prevents transmission on the second profile. Use Default isolation to restore auto when needed.");
|
||||
], "radio2.cross is saved and stays set after tempradio2 expires or the node reboots. Turning it on also allows OTA traffic to cross profiles. RX-only mode still prevents transmission on the second profile. Use Default isolation to restore off when needed.");
|
||||
}
|
||||
if (full || infrastructure) {
|
||||
toggle("Device power saving", "set powersaving", "get powersaving",
|
||||
|
||||
@@ -431,8 +431,8 @@
|
||||
primaryCancel:
|
||||
"get tempradioat\ndel tempradioat all",
|
||||
companionCancelBefore:
|
||||
"get tempradioat2\ndel tempradioat2 all\nset radio2.cross auto",
|
||||
companionCancelDuring: "set tempradio2 off\nset radio2.cross auto",
|
||||
"get tempradioat2\ndel tempradioat2 all\nset radio2.cross off",
|
||||
companionCancelDuring: "set tempradio2 off\nset radio2.cross off",
|
||||
companionLeaveIn30:
|
||||
"set radio2.cross on\ndel tempradioat2 all\nset tempradio2 " +
|
||||
tuple + ",rxtx,30",
|
||||
|
||||
@@ -438,7 +438,7 @@ set radio2.cross on
|
||||
|
||||
This copies new messages to both `radio` and `tempradio2`. The setting is saved,
|
||||
outlasts the temporary session and reboot, and also allows OTA traffic to cross
|
||||
profiles. **Default isolation** copies `set radio2.cross auto`; **Check** shows
|
||||
profiles. **Default isolation** copies `set radio2.cross off`; **Check** shows
|
||||
the temporary profile, crossing policy and per-profile transmit counters.
|
||||
See the [two-profile setup guide](radio_profiles.md#companion-messages-on-both-profiles).
|
||||
|
||||
|
||||
+3
-3
@@ -293,7 +293,7 @@ clock</code></pre>
|
||||
<p class="preset-test-note">
|
||||
Crossing is saved independently and remains <code>on</code> after the
|
||||
temporary second profile ends. Restore its previous value after the
|
||||
test; <code>auto</code> is the normal default.
|
||||
test; <code>off</code> is the normal default.
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
@@ -342,7 +342,7 @@ clock</code></pre>
|
||||
<pre><code data-command="companion-cancel-during"></code></pre>
|
||||
<button type="button" data-copy-command="companion-cancel-during">Copy restore commands</button>
|
||||
<p class="preset-test-note">
|
||||
If <code>get radio2.cross</code> was not <code>auto</code> before the
|
||||
If <code>get radio2.cross</code> was not <code>off</code> before the
|
||||
test, restore that recorded value instead.
|
||||
</p>
|
||||
<h4>Leave in 30 minutes</h4>
|
||||
@@ -352,7 +352,7 @@ clock</code></pre>
|
||||
These commands clear any absolute second-profile schedule and give
|
||||
the test profile a fresh 30-minute lease. The saved second profile
|
||||
returns at expiry, but crossing remains <code>on</code>; afterward,
|
||||
restore the value you recorded before the test (<code>auto</code> is
|
||||
restore the value you recorded before the test (<code>off</code> is
|
||||
the normal default).
|
||||
</p>
|
||||
</article>
|
||||
|
||||
@@ -189,8 +189,8 @@ messages between the two profiles. `TX=a,b` reports primary and secondary
|
||||
transmit counts. Crossing also applies to OTA traffic.
|
||||
|
||||
The crossing setting is saved and remains enabled after the temporary session
|
||||
ends or the node reboots. Run `set radio2.cross auto` to restore the default
|
||||
isolation between permanent and temporary profiles. The firmware picker's
|
||||
ends or the node reboots. Run `set radio2.cross off` to restore the default
|
||||
isolation between profiles. The firmware picker's
|
||||
Companion tempradio2 instructions include both choices and the status commands.
|
||||
|
||||
## Companion TX routing by contact or channel
|
||||
@@ -806,7 +806,7 @@ set radio2.cross on
|
||||
set radio2.cross off
|
||||
```
|
||||
|
||||
| Active primary | Active secondary | `auto` (default) | `on` | `off` |
|
||||
| Active primary | Active secondary | `auto` | `on` | `off` (default) |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `radio` | `radio2` | Cross | Cross | Isolated |
|
||||
| `tempradio` | `tempradio2` | Cross | Cross | Isolated |
|
||||
@@ -816,6 +816,9 @@ set radio2.cross off
|
||||
This table describes MeshCore profiles. A Meshtext secondary profile is
|
||||
always isolated, including with `radio2.cross on`.
|
||||
|
||||
New configurations default to `off`. An explicitly saved `auto`, `on`, or `off`
|
||||
setting is preserved across firmware updates and reboots.
|
||||
|
||||
These are the global rules used by Companion targets set to `auto`; an explicit
|
||||
contact/channel choice above overrides crossing for its own outbound packets.
|
||||
Ordinary crossing respects `rx`. The infrastructure-only `tx.reply ... force`
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ class RadioProfiles {
|
||||
RadioProfileConfig secondary;
|
||||
bool primary_temporary = false;
|
||||
bool secondary_temporary = false;
|
||||
RadioCrossMode cross = RadioCrossMode::Auto;
|
||||
RadioCrossMode cross = RadioCrossMode::Off;
|
||||
// Infrastructure opts into BOTH at startup; Companions keep their own
|
||||
// contact/channel policy. Force applies only to locally generated replies.
|
||||
uint8_t reply_tx = RADIO_TX_AUTO;
|
||||
|
||||
@@ -213,6 +213,7 @@ bool RadioProfileCLI::commitSavedImage(const char* path) {
|
||||
void RadioProfileCLI::begin(FILESYSTEM* fs, Radio* radio, RTCClock* rtc, bool infrastructure_replies) {
|
||||
fs_ = fs; radio_ = radio; rtc_ = rtc; last_ms_ = millis();
|
||||
hold_ = false;
|
||||
cross_ = RadioCrossMode::Off;
|
||||
recoverable_corrupt_store_ = false;
|
||||
manual_secondary_ = false;
|
||||
secondary_intent_generation_ = 0;
|
||||
@@ -222,6 +223,7 @@ void RadioProfileCLI::begin(FILESYSTEM* fs, Radio* radio, RTCClock* rtc, bool in
|
||||
#endif
|
||||
infrastructure_replies_ = infrastructure_replies;
|
||||
if (radio_ && radio_->profiles()) {
|
||||
radio_->profiles()->cross = cross_;
|
||||
radio_->profiles()->reply_tx = infrastructure_replies ? RADIO_TX_BOTH : RADIO_TX_AUTO;
|
||||
radio_->profiles()->reply_force = false;
|
||||
}
|
||||
@@ -270,7 +272,7 @@ void RadioProfileCLI::begin(FILESYSTEM* fs, Radio* radio, RTCClock* rtc, bool in
|
||||
// structurally valid backup exists; that backup is the last known-good
|
||||
// radio-profile image and must remain available for manual recovery.
|
||||
const ImageReadResult backup_image = readImage(BackupPath, bytes, sizeof(bytes));
|
||||
hold_ = true; saved_ = {}; primary_preamble_ = 0; cross_ = RadioCrossMode::Auto;
|
||||
hold_ = true; saved_ = {}; primary_preamble_ = 0; cross_ = RadioCrossMode::Off;
|
||||
recoverable_corrupt_store_ = backup_image != ImageReadResult::Valid
|
||||
&& backup_image != ImageReadResult::Unreadable;
|
||||
reply_setting_ = 0; // reject the entire image, including its reply override
|
||||
|
||||
@@ -26,7 +26,7 @@ class RadioProfileCLI {
|
||||
RadioProfileConfig temporary_;
|
||||
RadioProfileConfig pending_temporary_;
|
||||
uint16_t primary_preamble_ = 0;
|
||||
RadioCrossMode cross_ = RadioCrossMode::Auto;
|
||||
RadioCrossMode cross_ = RadioCrossMode::Off;
|
||||
uint8_t reply_setting_ = 0; // reserved image byte: 0 = role default
|
||||
bool infrastructure_replies_ = false;
|
||||
// Saved Off can be an explicit veto, rather than an unused secondary slot.
|
||||
|
||||
@@ -24,7 +24,7 @@ struct RadioProfileSystemStatus {
|
||||
bool dual_radio_enabled = false;
|
||||
bool secondary_temporary = false;
|
||||
RadioProfileMode secondary_mode = RadioProfileMode::Rx;
|
||||
RadioCrossMode cross = RadioCrossMode::Auto;
|
||||
RadioCrossMode cross = RadioCrossMode::Off;
|
||||
float noise_floor_1 = 0.0f;
|
||||
float noise_floor_2 = 0.0f;
|
||||
float noise_floor_1_seconds = 0.0f;
|
||||
|
||||
+2
@@ -22,6 +22,8 @@ static void checkSafePreamble(unsigned sf, float bw, uint16_t symbols) {
|
||||
assert(Profiles::safePreamble(p, symbols) == originalSafePreamble(p, symbols));
|
||||
}
|
||||
int main() {
|
||||
Profiles fresh;
|
||||
assert(fresh.cross==mesh::RadioCrossMode::Off && !fresh.canCross());
|
||||
// Sharing the read-only validation table must preserve every supported
|
||||
// value and the strict float tolerance on both sides of its boundary.
|
||||
for (float bw : {7.8f, 10.4f, 15.6f, 20.8f, 31.25f, 41.7f,
|
||||
|
||||
+36
-1
@@ -503,6 +503,41 @@ static void spectrumOverlap() {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
static_assert(uint8_t(mesh::RadioCrossMode::Auto)==0 && uint8_t(mesh::RadioCrossMode::On)==1
|
||||
&& uint8_t(mesh::RadioCrossMode::Off)==2, "saved crossover encoding must remain compatible");
|
||||
{
|
||||
Fixture fresh;
|
||||
assert(fresh.radio.p.cross==mesh::RadioCrossMode::Off && !fresh.radio.p.canCross());
|
||||
assert(!strcmp(fresh.cmd("get radio2.cross"),"> off") && fresh.fs.files.empty());
|
||||
for(const char* mode:{"auto","on","off"}) {
|
||||
char command[40];snprintf(command,sizeof(command),"set radio2.cross %s",mode);fresh.cmd(command);
|
||||
const auto expected=!strcmp(mode,"auto")?mesh::RadioCrossMode::Auto
|
||||
: !strcmp(mode,"on")?mesh::RadioCrossMode::On:mesh::RadioCrossMode::Off;
|
||||
assert(fresh.fs.files["/radio_profiles"][18]==uint8_t(expected));
|
||||
Radio reboot;mesh::RadioProfileCLI restored;restored.begin(&fresh.fs,&reboot,&fresh.clock);
|
||||
assert(reboot.p.cross==expected);
|
||||
restored.handle("get radio2.cross",fresh.reply);
|
||||
char reply[16];snprintf(reply,sizeof(reply),"> %s",mode);assert(!strcmp(fresh.reply,reply));
|
||||
}
|
||||
fresh.cmd("set radio2.cross on");fresh.fs.files.clear();
|
||||
fresh.cli.begin(&fresh.fs,&fresh.radio,&fresh.clock);
|
||||
assert(fresh.radio.p.cross==mesh::RadioCrossMode::Off);
|
||||
assert(!strcmp(fresh.cmd("get radio2.cross"),"> off"));
|
||||
}
|
||||
for(bool semantic:{false,true}) {
|
||||
Fixture invalid;invalid.cmd("set radio2.cross auto");
|
||||
auto& image=invalid.fs.files["/radio_profiles"];
|
||||
if(semantic) {
|
||||
image[18]=255;
|
||||
uint32_t crc=0xffffffffU;
|
||||
for(size_t i=0;i<20;++i) {crc^=image[i];for(unsigned bit=0;bit<8;++bit)crc=(crc>>1)^((crc&1)?0xedb88320U:0);}
|
||||
memcpy(image.data()+20,&crc,4);
|
||||
} else image[0]^=1;
|
||||
Radio radio;radio.p.cross=mesh::RadioCrossMode::On;
|
||||
mesh::RadioProfileCLI restored;restored.begin(&invalid.fs,&radio,&invalid.clock);
|
||||
assert(radio.p.cross==mesh::RadioCrossMode::Off);
|
||||
restored.handle("get radio2.cross",invalid.reply);assert(!strcmp(invalid.reply,"> off"));
|
||||
}
|
||||
if (argc == 2) {
|
||||
if (!strcmp(argv[1], "permanent_order")) permanentScheduleOrder();
|
||||
else if (!strcmp(argv[1], "temporary_boundary")) adjacentTemporarySchedules();
|
||||
@@ -647,7 +682,7 @@ int main(int argc, char** argv) {
|
||||
{
|
||||
Fixture f;
|
||||
assert(!strcmp(f.cmd("get radio2"),"> off"));
|
||||
assert(!strcmp(f.cmd("get radio2.cross"),"> auto"));
|
||||
assert(!strcmp(f.cmd("get radio2.cross"),"> off"));
|
||||
assert(strstr(f.cmd("set radio2 910.5,500,7,5,rxtx"),"timing self-test pending"));
|
||||
assert(!f.radio.p.enabled()); f.advance(2000); assert(f.radio.p.enabled());
|
||||
assert(strstr(f.cmd("get radio2.timing"),"self-test pending"));
|
||||
|
||||
@@ -1118,6 +1118,13 @@ assert.strictEqual(rakCommands.find(s => s.title.startsWith('RS232')).actions[0]
|
||||
assert(commands(rakCommands).includes('set gps on'));
|
||||
assert(!rakCommands.some(s => s.title === 'MQTT broker connections'));
|
||||
const indicator = picker.runtimeDirections(findControlled('SenseCapIndicator-LoRa_companion_radio_full'), {});
|
||||
const isolation = picker.runtimeDirections(Object.assign({},
|
||||
findControlled('SenseCapIndicator-LoRa_companion_radio_full'),
|
||||
{releaseFamily: 'v1.17.1.6-halo-keymind-cascade-dev-test'}), {})
|
||||
.find(section => section.title === 'Companion tempradio2: transmit on both');
|
||||
assert(isolation);
|
||||
assert.deepStrictEqual(isolation.actions.find(action => action.label === 'Default isolation').commands,
|
||||
['set radio2.cross off']);
|
||||
assert(commands(indicator).includes('set companion.transport ble'));
|
||||
assert(!indicator.some(s => s.title.startsWith('MQTT')));
|
||||
// Never apply old hardware capabilities to another release, or to an unknown
|
||||
|
||||
@@ -265,6 +265,10 @@ assert.strictEqual(
|
||||
"set tempradioat 910.1,500,8,7,+1,+2880\nget tempradioat"
|
||||
);
|
||||
assert.strictEqual(commands.primaryCancel, "get tempradioat\ndel tempradioat all");
|
||||
assert.strictEqual(commands.companionCancelBefore,
|
||||
"get tempradioat2\ndel tempradioat2 all\nset radio2.cross off");
|
||||
assert.strictEqual(commands.companionCancelDuring,
|
||||
"set tempradio2 off\nset radio2.cross off");
|
||||
assert.strictEqual(
|
||||
commands.companionNow,
|
||||
"set radio2.cross on\nset tempradio2 910.1,500,8,7,rxtx,2880"
|
||||
|
||||
Reference in new issue
Block a user