mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-11-03 20:02:24 +01:00
fix(config): name the radios[] entry with a stray sync word
build_radio_stack pops _radio_id before building each radio, so the warning never named the entry on a real node. A _radio_label survives the pop, and the warning now points at radios[<id>].radio, saying the value is inherited only when it is. config.yaml.example documents sync_word.
This commit is contained in:
1 parent
0ed70f4d1b
commit
d5e4bd754c
3 files changed
+86
-6
No files matched your search
@@ -599,6 +599,11 @@ radio:
|
||||
# Preamble length in symbols
|
||||
preamble_length: 32
|
||||
|
||||
# LoRa sync word, used by modem_tcp/modem_usb radios (the SX1262 driver
|
||||
# ignores it). MeshCore uses 0x12; a modem on any other value hears nothing.
|
||||
# radios[] entries inherit this value unless they set their own.
|
||||
# sync_word: 0x12
|
||||
|
||||
# Use implicit header mode
|
||||
implicit_header: false
|
||||
|
||||
|
||||
+16
-5
@@ -517,19 +517,26 @@ def _checked_modem_sync_word(sync_word: int, board_config: dict, radio_type: str
|
||||
These are the drivers that actually push the value to the radio, and a
|
||||
modem on another sync word connects, answers pings and transmits, yet hears
|
||||
no MeshCore traffic -- a silent failure. A radios[] entry inherits the
|
||||
top-level ``radio.sync_word``, which the SX1262 driver ignores, so a stray
|
||||
top-level value is harmless until a modem entry picks it up.
|
||||
top-level ``radio.sync_word``, which the SX1262 driver ignores (SX1262Radio
|
||||
stores it but never calls setSyncWord), so a stray top-level value is
|
||||
harmless until a modem entry picks it up.
|
||||
"""
|
||||
if sync_word != MESHCORE_SYNC_WORD:
|
||||
radio_id = board_config.get("_radio_id")
|
||||
radio_id = board_config.get("_radio_label") or board_config.get("_radio_id")
|
||||
if radio_id:
|
||||
where = f"radios[{radio_id}].radio"
|
||||
if board_config.get("_sync_word_inherited"):
|
||||
where += " (it inherits the top-level radio.sync_word)"
|
||||
else:
|
||||
where = "its radio section"
|
||||
logger.warning(
|
||||
"%s sync_word is 0x%X, not MeshCore's 0x%02X: the modem will not hear "
|
||||
"MeshCore traffic. Set sync_word: 0x%02X in its radio section%s.",
|
||||
"MeshCore traffic. Set sync_word: 0x%02X in %s.",
|
||||
f"Radio {radio_id!r} ({radio_type})" if radio_id else f"{radio_type} radio",
|
||||
sync_word,
|
||||
MESHCORE_SYNC_WORD,
|
||||
MESHCORE_SYNC_WORD,
|
||||
" (radios[] entries inherit the top-level radio.sync_word)" if radio_id else "",
|
||||
where,
|
||||
)
|
||||
return sync_word
|
||||
|
||||
@@ -920,6 +927,10 @@ def _merge_radio_entry(global_config: dict, entry: dict) -> dict:
|
||||
raise ValueError(f"radios[] entry {radio_id!r} missing radio_type")
|
||||
|
||||
merged["_radio_id"] = str(radio_id)
|
||||
# build_radio_stack pops _radio_id; this survives it, to name the radio in logs.
|
||||
merged["_radio_label"] = str(radio_id)
|
||||
own_radio = entry.get("radio") if isinstance(entry.get("radio"), dict) else {}
|
||||
merged["_sync_word_inherited"] = "sync_word" not in own_radio
|
||||
# Hint for CH341 path: do not install process-global SPI/GPIO defaults.
|
||||
merged["_ch341_per_instance"] = True
|
||||
return merged
|
||||
|
||||
@@ -364,7 +364,7 @@ def test_a_radios_entry_inheriting_a_stray_top_level_sync_word_is_named(monkeypa
|
||||
|
||||
assert captured["sync_word"] == 0x3444
|
||||
assert "Radio 'narrow' (modem_tcp) sync_word is 0x3444" in caplog.text
|
||||
assert "inherit the top-level radio.sync_word" in caplog.text
|
||||
assert "inherits the top-level radio.sync_word" in caplog.text
|
||||
|
||||
|
||||
def test_a_radios_entry_overriding_the_stray_sync_word_is_not_warned_about(monkeypatch, caplog):
|
||||
@@ -398,3 +398,67 @@ def test_an_explicit_null_sync_word_means_the_default(monkeypatch, caplog, radio
|
||||
|
||||
assert captured["sync_word"] == 0x12
|
||||
assert "sync_word" not in caplog.text
|
||||
|
||||
|
||||
def test_build_radio_stack_names_the_radios_entry_with_the_stray_sync_word(monkeypatch, caplog):
|
||||
"""The real path: build_radio_stack pops _radio_id before building the
|
||||
radio, so the warning must still name the entry."""
|
||||
from repeater.config import build_radio_stack
|
||||
|
||||
captured = _capture_modem(monkeypatch, "modem_tcp")
|
||||
config = {
|
||||
"radio_type": "sx1262",
|
||||
"radio": {**_modem_radio_cfg(), "sync_word": 13380},
|
||||
"radios": [
|
||||
{
|
||||
"id": "narrow",
|
||||
"radio_type": "modem_tcp",
|
||||
"radio": {"frequency": 910525000},
|
||||
"modem_tcp": {"host": "192.168.50.154"},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
with caplog.at_level("WARNING", logger="Config"):
|
||||
build_radio_stack(config)
|
||||
|
||||
assert captured["sync_word"] == 0x3444
|
||||
assert "Radio 'narrow' (modem_tcp) sync_word is 0x3444" in caplog.text
|
||||
assert "inherits the top-level radio.sync_word" in caplog.text
|
||||
|
||||
|
||||
def test_each_modem_entry_gets_its_own_sync_word_and_warning(monkeypatch, caplog):
|
||||
from repeater.config import build_radio_stack
|
||||
|
||||
pytest.importorskip("openhop_core.hardware.tcp_radio")
|
||||
built = []
|
||||
|
||||
class _Dummy(_DummyRadio):
|
||||
def __init__(self, **kwargs):
|
||||
built.append(kwargs)
|
||||
|
||||
monkeypatch.setattr("openhop_core.hardware.tcp_radio.TCPLoRaRadio", _Dummy)
|
||||
config = {
|
||||
"radio_type": "sx1262",
|
||||
"radio": {**_modem_radio_cfg(), "sync_word": 13380},
|
||||
"radios": [
|
||||
{"id": "local", "radio_type": "modem_tcp", "modem_tcp": {"host": "10.0.0.1"}},
|
||||
{
|
||||
"id": "narrow",
|
||||
"radio_type": "modem_tcp",
|
||||
"radio": {"sync_word": 0x34},
|
||||
"modem_tcp": {"host": "10.0.0.2"},
|
||||
},
|
||||
],
|
||||
"fabric": {"default_radio": "local"},
|
||||
}
|
||||
|
||||
with caplog.at_level("WARNING", logger="Config"):
|
||||
build_radio_stack(config)
|
||||
|
||||
assert [b["sync_word"] for b in built] == [0x3444, 0x34]
|
||||
lines = [r.getMessage() for r in caplog.records]
|
||||
local = next(m for m in lines if "Radio 'local'" in m)
|
||||
narrow = next(m for m in lines if "Radio 'narrow'" in m)
|
||||
assert "radios[local].radio (it inherits" in local
|
||||
assert "radios[narrow].radio." in narrow and "inherits" not in narrow
|
||||
Reference in new issue
Block a user