Rewrite all scripts against the DongLoRa Protocol v2 async Dongle surface, and extract the shared MeshCore US preset into a single module. * _common.py: MESHCORE_US preset (910.525 MHz / BW 62.5 / SF 7 / CR 4/5 / sync 0x1424 / 20 dBm) plus small helpers, imported by every example. * New: explore.py, which prints the device capabilities and runs a single TX + RX roundtrip for quick hardware validation. * simple_rx.py, simple_tx.py, ping_pong.py, lora_bridge.py all switch to donglora.Dongle and the new Modulation / LoRaConfig types. * all_commands.py removed; it was an index of the old v0.1 command enum that no longer exists after the Protocol v2 split. * justfile: drop stale recipes that referenced removed scripts.
73 lines
2.3 KiB
Python
73 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Probe a DongLoRa device: print capabilities, then TX + RX once.
|
|
|
|
Configures the radio for the MeshCore US/Canada channel so the TX
|
|
probe is audible to other MeshCore nodes on the same band.
|
|
|
|
Usage:
|
|
python examples/explore.py [PORT]
|
|
"""
|
|
|
|
import sys
|
|
import time
|
|
|
|
import donglora as dl
|
|
from _common import MESHCORE_US
|
|
|
|
|
|
def describe_info(info: dl.Info) -> None:
|
|
chip = info.chip.name if isinstance(info.chip, dl.RadioChipId) else f"0x{info.chip:04X}"
|
|
print(f" Protocol: DongLoRa Protocol v{info.proto_major}.{info.proto_minor}")
|
|
print(f" Firmware: v{info.fw_major}.{info.fw_minor}.{info.fw_patch}")
|
|
print(f" Chip: {chip}")
|
|
print(f" Freq: {info.freq_min_hz / 1e6:.1f} - {info.freq_max_hz / 1e6:.1f} MHz")
|
|
print(f" TX power: {info.tx_power_min_dbm}..{info.tx_power_max_dbm} dBm")
|
|
print(f" Max pkt: {info.max_payload_bytes} bytes")
|
|
print(f" SF range: {info.supported_sf()}")
|
|
print(f" MCU UID: {info.mcu_uid.hex()}")
|
|
caps = []
|
|
if info.supports(dl.Capability.LORA):
|
|
caps.append("LoRa")
|
|
if info.supports(dl.Capability.FSK):
|
|
caps.append("FSK")
|
|
if info.supports(dl.Capability.CAD_BEFORE_TX):
|
|
caps.append("CAD")
|
|
print(f" Features: {', '.join(caps) or 'none advertised'}")
|
|
|
|
|
|
port = sys.argv[1] if len(sys.argv) > 1 else None
|
|
|
|
with dl.connect(port, config=MESHCORE_US) as d:
|
|
print("── GET_INFO ──")
|
|
describe_info(d.info)
|
|
|
|
cfg = d.config
|
|
print(
|
|
f"\n── Radio configured: {cfg.freq_hz / 1e6:.3f} MHz "
|
|
f"SF{cfg.sf} BW{cfg.bw.khz:g}kHz "
|
|
f"sync=0x{cfg.sync_word:04X} {cfg.tx_power_dbm} dBm ──"
|
|
)
|
|
|
|
print("\n── TX ──")
|
|
td = d.tx(b"hello from explore.py")
|
|
print(
|
|
f" result={td.result.name} airtime_us={td.airtime_us} "
|
|
f"(~{td.airtime_us / 1000:.1f} ms on air)"
|
|
)
|
|
|
|
print("\n── RX (5 s window) ──")
|
|
start = time.monotonic()
|
|
any_rx = False
|
|
for pkt in d.rx(timeout=0.25):
|
|
any_rx = True
|
|
print(
|
|
f" pkt: rssi={pkt.rssi_dbm:.1f}dBm snr={pkt.snr_db:.1f}dB "
|
|
f"len={len(pkt.data)} origin={pkt.origin.name}"
|
|
)
|
|
if time.monotonic() - start > 5:
|
|
break
|
|
if not any_rx:
|
|
print(" (no packets received — try pairing with ping_pong.py --role tx)")
|
|
|
|
print("\nDone.")
|