feat: radio duplex/offset/tone control + tune_repeater

This commit is contained in:
2026-06-14 16:12:50 -04:00
parent 24afa04a4c
commit 08fd5dbb40
+48
View File
@@ -156,3 +156,51 @@ class Radio:
def squelch_open(self): def squelch_open(self):
data = self.transact(civ.CMD_METER, bytes([civ.SUB_SQL_STATUS])).data data = self.transact(civ.CMD_METER, bytes([civ.SUB_SQL_STATUS])).data
return bool(data[1]) if len(data) > 1 else False return bool(data[1]) if len(data) > 1 else False
# ---- repeater config (candidate commands; verify live) ----------------
def set_duplex(self, direction):
"""direction: '+', '-', or 'simplex'."""
code = {"+": civ.DUP_PLUS, "-": civ.DUP_MINUS,
"simplex": civ.DUP_SIMPLEX}.get(direction)
if code is None:
raise ValueError(f"bad duplex {direction!r}")
return self._command(civ.CMD_DUPLEX, bytes([code]))
def set_offset(self, hz):
return self._command(civ.CMD_OFFSET, civ.offset_to_bcd(hz))
def get_offset(self):
return civ.bcd_to_offset(self.transact(civ.CMD_OFFSET).data)
def set_tone(self, hz):
return self._command(civ.CMD_TONE_PARAM,
bytes([civ.SUB_RPT_TONE]) + civ.tone_to_bcd(hz))
def get_tone(self):
return civ.bcd_to_tone(self.transact(civ.CMD_TONE_PARAM,
bytes([civ.SUB_RPT_TONE])).data[1:])
def set_tone_on(self, on):
return self._command(civ.CMD_TONE_SWITCH,
bytes([civ.SUB_TONE_ENC, 0x01 if on else 0x00]))
def tune_repeater(self, rec):
"""Apply a normalized record: freq -> duplex/offset -> tone.
Returns (steps, errors): each step True/False; errors keyed by step."""
steps, errors = {}, {}
def attempt(name, fn):
try:
fn(); steps[name] = True
except (CIVError, ValueError, OSError) as e:
steps[name] = False; errors[name] = str(e)
attempt("freq", lambda: self.set_frequency(int(round(rec["output_mhz"] * 1e6))))
duplex = rec.get("duplex", "simplex")
attempt("duplex", lambda: self.set_duplex(duplex))
if duplex != "simplex":
attempt("offset", lambda: self.set_offset(int(round(rec.get("offset_mhz", 0) * 1e6))))
if rec.get("tone_mode") == "ctcss" and rec.get("tone_hz"):
attempt("tone_freq", lambda: self.set_tone(rec["tone_hz"]))
attempt("tone_on", lambda: self.set_tone_on(True))
return steps, errors