feat: new example which tests sync word setting
This commit is contained in:
1 file changed
+104
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify the dongle applies ``LoRaConfig.sync_word`` to the radio.
|
||||
|
||||
Two roles. Run on TWO SEPARATE PHYSICAL DONGLES (not the same dongle
|
||||
shared via donglora-mux — a single chip can only hold one sync word at
|
||||
a time, and the mux delivers local TX back to other sessions as
|
||||
LOCAL_LOOPBACK events that bypass the chip's sync filter). Pass an
|
||||
explicit port path to each invocation so neither side discovers the
|
||||
mux socket:
|
||||
|
||||
# Dongle A — pin to one sync word, listen:
|
||||
python examples/sync_word_test.py --role rx /dev/ttyACM0 [--sync 0x5464]
|
||||
|
||||
# Dongle B — rotate through several sync words, transmitting on each:
|
||||
python examples/sync_word_test.py --role tx /dev/ttyACM1
|
||||
|
||||
Expected behavior with the firmware fix:
|
||||
RX hears ONLY the cycles whose sync word matches its own
|
||||
(one packet per rotation pass through SYNC_WORDS), and packets
|
||||
have realistic RSSI / SNR (not 0.0 / 0.0).
|
||||
|
||||
Without the fix:
|
||||
RX hears every transmission regardless of which sync word the TX
|
||||
side configured — the firmware was silently ignoring the field
|
||||
and leaving the SX126x on the boot-time default 0x1424.
|
||||
|
||||
The default RX sync word (0x5464) is deliberately off the MeshCore
|
||||
(0x1424) and LoRaWAN-public (0x3444) values so the test isn't polluted
|
||||
by ambient mesh traffic. The RX role drops `LOCAL_LOOPBACK` events
|
||||
defensively so accidental mux sharing fails loud (zero packets) rather
|
||||
than printing misleading "all sync words received" output.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import dataclasses
|
||||
import time
|
||||
|
||||
import donglora as dl
|
||||
from _common import MESHCORE_US
|
||||
|
||||
# SX126x register-encoded sync words. Each is (hi << 8) | lo where
|
||||
# [hi, lo] = convert_sync_word(byte) for the listed underlying byte:
|
||||
# byte 0x12 → 0x1424 (LoRa "private" — MeshCore default)
|
||||
# byte 0x34 → 0x3444 (LoRaWAN "public")
|
||||
# byte 0x56 → 0x5464
|
||||
# byte 0x78 → 0x7484
|
||||
# byte 0xAB → 0xA4B4
|
||||
# byte 0xCD → 0xC4D4
|
||||
SYNC_WORDS = [0x1424, 0x3444, 0x5464, 0x7484, 0xA4B4, 0xC4D4]
|
||||
TX_PAUSE_S = 1.5
|
||||
|
||||
parser = argparse.ArgumentParser(description="Sync-word verification test")
|
||||
parser.add_argument("--role", choices=["tx", "rx"], required=True)
|
||||
parser.add_argument(
|
||||
"--sync",
|
||||
type=lambda x: int(x, 0),
|
||||
default=0x5464,
|
||||
help="(rx) sync word to pin to, e.g. 0x5464 (default; avoids MeshCore noise)",
|
||||
)
|
||||
parser.add_argument("port", nargs="?", help="Serial port (auto-detect if omitted)")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.role == "tx":
|
||||
with dl.connect(args.port, config=MESHCORE_US) as d:
|
||||
print(
|
||||
f"TX: rotating {len(SYNC_WORDS)} sync words, "
|
||||
f"{TX_PAUSE_S}s between (Ctrl+C to stop)\n"
|
||||
)
|
||||
try:
|
||||
cycle = 0
|
||||
while True:
|
||||
for sw in SYNC_WORDS:
|
||||
cfg = dataclasses.replace(MESHCORE_US, sync_word=sw)
|
||||
d.set_config(cfg)
|
||||
msg = f"cycle={cycle} sync=0x{sw:04X}"
|
||||
td = d.tx(msg.encode())
|
||||
print(
|
||||
f" TX sync=0x{sw:04X} {msg!r} ({td.airtime_us} µs)"
|
||||
)
|
||||
time.sleep(TX_PAUSE_S)
|
||||
cycle += 1
|
||||
except KeyboardInterrupt:
|
||||
print("\nDone.")
|
||||
else:
|
||||
sw = args.sync
|
||||
cfg = dataclasses.replace(MESHCORE_US, sync_word=sw)
|
||||
with dl.connect(args.port, config=cfg) as d:
|
||||
print(f"RX: pinned to sync=0x{sw:04X} (Ctrl+C to stop)")
|
||||
print("Only matching-sync-word transmissions should arrive.\n")
|
||||
try:
|
||||
for pkt in d.rx():
|
||||
if pkt.origin != dl.RxOrigin.OTA:
|
||||
# Drop mux-injected local-loopback events. They
|
||||
# arrive without going through the chip's sync
|
||||
# filter and would falsely "match" every sync
|
||||
# word the TX side rotates through.
|
||||
continue
|
||||
text = pkt.data.decode("utf-8", errors="replace")
|
||||
print(
|
||||
f" RX: {text!r} RSSI:{pkt.rssi_dbm:.1f}dBm "
|
||||
f"SNR:{pkt.snr_db:.1f}dB"
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
print("\nDone.")
|
||||
Reference in new issue
Block a user