mirror of
https://github.com/meshtastic/firmware.git
synced 2026-09-17 18:45:37 -04:00
fix rfswitch_table cross-file merge; drop now-stale checker warning
Three CodeRabbit findings on 09e0d390c, addressed together since #2
and #3 are the same root cause:
1. PortduinoGlue.cpp: require an exact "DIO<n>" match when parsing
rfswitch_table.pins. sscanf's %d stops at the first non-digit, so
"DIO5invalid" silently parsed as DIO5 at runtime even though
ConfigCheck.cpp's static validator (exact match against
kRfSwitchPins) already rejected it - checker and loader disagreed.
2. PortduinoGlue.cpp: reset all 5 pin slots and all 8 mode rows before
applying a table, rather than only overwriting what the new table
mentions. A later config.d file that omitted a mode a prior file
had set (e.g. only redefining MODE_TX) let the earlier file's
MODE_RX leak through, contradicting "last file wins" - the rule
every other Lora: key already follows.
3. ConfigCheck.cpp: with #2 fixed, rfswitch_table behaves like any
other cross-file key, so removed the special-cased ERROR in
checkCrossFileOverlap ("These do NOT override each other... OR of
every table") - it described the pre-fix OR-accumulation bug and
is no longer accurate. Falls through to the generic "last file
wins" INFO now. Renamed/repurposed the rfswitch-sticky fixture to
rfswitch-last-wins and updated its assertion (was rc=1 asserting
the old error text, now rc=0 asserting the generic info) and the
fixtures README.
Verified: bin/test-config-check.sh GREEN 69/69 against an isolated
native build, including the renamed assertion.
This commit is contained in:
1 parent
09e0d390c7
commit
ee9b5b81ee
9 files changed
+33
-40
No files matched your search
@@ -402,12 +402,12 @@ assert "config.d overrides are reported" 0 configd-conflict/config.yaml check \
|
||||
"files define a 'Lora:' section" \
|
||||
"The file loaded last wins" \
|
||||
"Result: 0 errors,"
|
||||
# Switch tables are the one place "last wins" is false: the loader only ever writes
|
||||
# HIGH, so the effective table is the OR of every file. Proven with --output-yaml.
|
||||
assert "switch tables across files do not override" 1 rfswitch-sticky/config.yaml check \
|
||||
"These do NOT override each other" \
|
||||
"a HIGH from an earlier file survives a later file that sets LOW" \
|
||||
"Enable exactly one"
|
||||
# rfswitch_table follows "last file wins" like every other Lora: key: no special-cased
|
||||
# error, just the standard cross-file-overlap info.
|
||||
assert "rfswitch tables across files: last one wins" 0 rfswitch-last-wins/config.yaml check \
|
||||
"'Lora.rfswitch_table' is set in 2 files" \
|
||||
"The file loaded last wins" \
|
||||
"Result: 0 errors,"
|
||||
|
||||
echo
|
||||
echo "--check takes precedence over --output-yaml:"
|
||||
|
||||
@@ -915,18 +915,6 @@ void checkCrossFileOverlap(const PathIndex &paths, const std::map<std::string, s
|
||||
if (coveredByAncestor)
|
||||
continue;
|
||||
|
||||
// The one place "last wins" is untrue: the loader only ever writes HIGH, so the effective
|
||||
// table is the OR of every table loaded -- a switch state belonging to none of them.
|
||||
if (entry.first == "Lora.rfswitch_table") {
|
||||
findings.push_back({kError, across, 0,
|
||||
"'Lora.rfswitch_table' is set in " + std::to_string(entry.second.size()) + " files (" +
|
||||
describeOwners(entry.second) +
|
||||
"). These do NOT override each other: the loader only ever writes HIGH, so a HIGH "
|
||||
"from an earlier file survives a later file that sets LOW there, and the radio ends "
|
||||
"up driving the OR of every table. Enable exactly one"});
|
||||
continue;
|
||||
}
|
||||
|
||||
findings.push_back({kInfo, across, 0,
|
||||
"'" + entry.first + "' is set in " + std::to_string(entry.second.size()) + " files (" +
|
||||
describeOwners(entry.second) + "). The file loaded last wins"});
|
||||
|
||||
@@ -1095,14 +1095,23 @@ bool loadConfig(const char *configPath)
|
||||
}
|
||||
if (yamlConfig["Lora"]["rfswitch_table"]) {
|
||||
portduino_config.has_rfswitch_table = true;
|
||||
// A later file's table fully replaces an earlier one, matching "last file wins"
|
||||
// for every other Lora: key, rather than leaving omitted pins/modes as carryover.
|
||||
for (int i = 0; i < 5; i++)
|
||||
portduino_config.rfswitch_dio_num[i] = -1;
|
||||
for (int m = 0; m < RFSW_MODE_COUNT; m++) {
|
||||
portduino_config.rfswitch_mode_present[m] = false;
|
||||
portduino_config.rfswitch_mode_high[m] = 0;
|
||||
}
|
||||
const YAML::Node table = yamlConfig["Lora"]["rfswitch_table"];
|
||||
|
||||
// Store the DIO number as written; the slot it maps to is per-radio. Anything
|
||||
// not spelled "DIO<n>" leaves the slot unused.
|
||||
// not spelled exactly "DIO<n>" (trailing junk included) leaves the slot unused.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
const std::string name = table["pins"][i].as<std::string>("");
|
||||
int dioNum = 0;
|
||||
if (sscanf(name.c_str(), "DIO%d", &dioNum) == 1 && dioNum >= 0 && dioNum <= INT8_MAX)
|
||||
if (sscanf(name.c_str(), "DIO%d", &dioNum) == 1 && dioNum >= 0 && dioNum <= INT8_MAX &&
|
||||
name == "DIO" + std::to_string(dioNum))
|
||||
portduino_config.rfswitch_dio_num[i] = (int8_t)dioNum;
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -182,13 +182,11 @@ the last-loaded file is reset to its default - here `config.yaml` sets
|
||||
The load order within `config.d/` comes from the filesystem, so the report warns
|
||||
rather than assuming alphabetical order.
|
||||
|
||||
`rfswitch-sticky/` covers the one place where "the file loaded last wins" is false,
|
||||
and it documents a firmware bug rather than a configuration mistake. Its `config.d/`
|
||||
holds two switch tables; the last one loaded sets `MODE_RX` LOW on both pins, but the
|
||||
loader only ever writes HIGH and never writes LOW back, so the HIGH from the earlier
|
||||
file survives and the effective table is the OR of both. Verified with
|
||||
`meshtasticd --output-yaml`. Until the loader is fixed, `--check` reports this as an
|
||||
error and tells you to enable exactly one.
|
||||
`rfswitch-last-wins/` covers `Lora.rfswitch_table` across two `config.d/` files. It
|
||||
follows the same "last file loaded wins" rule as every other `Lora:` key - the loader
|
||||
resets a table's pins and mode rows before applying a replacement, so an earlier
|
||||
file's `MODE_RX` setting cannot leak through a later file that omits it. `--check`
|
||||
reports this as the standard cross-file-overlap info, not a special-cased error.
|
||||
|
||||
## Running these as a normal boot
|
||||
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,7 @@
|
||||
# Sets MODE_RX LOW on both pins. Whichever of this file and a-first.yaml the filesystem
|
||||
# returns last should fully replace the other's table, per "last file wins".
|
||||
Lora:
|
||||
Module: lr1121
|
||||
rfswitch_table:
|
||||
pins: [DIO5, DIO6]
|
||||
MODE_RX: [LOW, LOW]
|
||||
@@ -0,0 +1,4 @@
|
||||
# Primary config for the rfswitch_table last-wins case. The two files in config.d/
|
||||
# each define a Lora.rfswitch_table; the one loaded last should fully replace it.
|
||||
General:
|
||||
ConfigDirectory: config.d/
|
||||
@@ -1,9 +0,0 @@
|
||||
# FAULT, and it is a firmware bug rather than a typo. This file is loaded LAST and says
|
||||
# MODE_RX is LOW on both pins, but the loader only ever writes HIGH and never writes
|
||||
# LOW back, so the HIGH from a-first.yaml survives. The effective table is the OR of
|
||||
# both files -- a switch state that neither file asked for. Verified with --output-yaml.
|
||||
Lora:
|
||||
Module: lr1121
|
||||
rfswitch_table:
|
||||
pins: [DIO5, DIO6]
|
||||
MODE_RX: [LOW, LOW]
|
||||
@@ -1,4 +0,0 @@
|
||||
# Primary config for the sticky-switch-table case. The two files in config.d/ each
|
||||
# define a Lora.rfswitch_table.
|
||||
General:
|
||||
ConfigDirectory: config.d/
|
||||
Reference in new issue
Block a user