fix: ground-truth CI-V offset/tone on live ID-5100

- offset amount (0x0D) is REJECTED (NG) by the radio -> removed the offset
  codec + set_offset/get_offset; tune_repeater now sets only duplex direction
  (radio applies its configured auto-offset)
- repeater tone (0x1B/00) uses a 3-byte field (00 + 2-byte BCD); set_tone
  prepends the pad, get_tone strips it
- duplex (0x0F) and tone-switch (0x16/42) verified working
- added get_duplex; verified full tune_repeater on a live repeater (all steps OK)
This commit is contained in:
2026-06-14 16:22:19 -04:00
parent 66b368fb87
commit 69710e362a
3 changed files with 29 additions and 55 deletions
+2 -15
View File
@@ -73,23 +73,10 @@ class TestParseFrames(unittest.TestCase):
self.assertEqual(civ.parse_frames(b""), [])
class TestOffsetCodec(unittest.TestCase):
# PROVISIONAL: 3-byte little-endian BCD in units of 100 Hz.
# Round-trip validated until pinned to a real capture (plan Task 6).
def test_offset_roundtrip(self):
for hz in (600_000, 5_000_000, 1_600_000, 0):
self.assertEqual(civ.bcd_to_offset(civ.offset_to_bcd(hz)), hz)
def test_offset_is_three_bytes(self):
self.assertEqual(len(civ.offset_to_bcd(600_000)), 3)
def test_offset_rejects_negative(self):
with self.assertRaises(ValueError):
civ.offset_to_bcd(-1)
class TestToneCodec(unittest.TestCase):
# ICOM convention: CTCSS tone as 2-byte BCD of tone*10. 131.8 -> "13 18".
# Verified on the live ID-5100: cmd 0x1B/0x00 returned `00 08 85` for 88.5 Hz
# (a 0x00 pad byte precedes these two; radio.py handles the pad).
def test_tone_to_bcd_known(self):
self.assertEqual(civ.tone_to_bcd(88.5), b"\x08\x85")
self.assertEqual(civ.tone_to_bcd(131.8), b"\x13\x18")