package cat import ( "testing" "hamlog/internal/cat/civ" ) // The Xiegu mode table is SHORTER than Icom's: LSB, USB, AM, CW, CWR and // nothing else. The interesting cases are the ones with no equivalent — a // digital mode must land on plain sideband rather than be refused, because // refusing it would leave the rig on whatever it was and silently log the wrong // mode. func TestXieguModeByte(t *testing.T) { cases := []struct { mode string hz int64 want byte ok bool }{ {"SSB", 7150000, 0x00, true}, // LSB below 10 MHz {"SSB", 14250000, 0x01, true}, // USB above {"LSB", 14250000, 0x00, true}, // explicit beats the convention {"USB", 7150000, 0x01, true}, {"AM", 7150000, 0x02, true}, {"CW", 7030000, 0x03, true}, {"CWR", 7030000, 0x07, true}, {"FT8", 7074000, 0x00, true}, // no data mode on this rig → LSB {"FT8", 14074000, 0x01, true}, // → USB {"RTTY", 14080000, 0x01, true}, {"FM", 145000000, 0x01, true}, // no FM either; sideband is the honest fallback {"", 14074000, 0x00, false}, } for _, c := range cases { got, ok := xieguModeByte(c.mode, c.hz) if got != c.want || ok != c.ok { t.Errorf("xieguModeByte(%q, %d) = 0x%02X,%v — want 0x%02X,%v", c.mode, c.hz, got, ok, c.want, c.ok) } } } // The Xiegu mode bytes must decode through the shared Icom table, since that is // the whole reason this backend reuses internal/cat/civ instead of its own // codec. If the two ever disagree, the radio would be set to one mode and read // back as another. func TestXieguModesRoundTripThroughCIV(t *testing.T) { cases := []struct { mode string adif string }{ // ADIF has no LSB/USB distinction — both sidebands ARE the SSB mode, and // that is what gets logged. The sideband still matters to the radio, which // is why xieguModeByte picks it from the frequency. {"LSB", "SSB"}, {"USB", "SSB"}, {"AM", "AM"}, {"CW", "CW"}, } for _, c := range cases { b, ok := xieguModeByte(c.mode, 14200000) if !ok { t.Fatalf("xieguModeByte(%q) refused", c.mode) } if got := civ.ModeToADIF(b, false); got != c.adif { t.Errorf("%s → 0x%02X → %q, want %q", c.mode, b, got, c.adif) } } } // Frequency encoding is shared with Icom, and it is the one field where a byte // out of place mistunes the radio silently. Pinned here at the boundaries a // Xiegu actually covers (it is an HF rig, so the 5-byte BCD upper bytes are 0). func TestXieguFrequencyEncoding(t *testing.T) { for _, hz := range []int64{1840000, 7074000, 14074000, 28500000, 50313000} { b := civ.FreqToBCD(hz) if len(b) != 5 { t.Fatalf("FreqToBCD(%d) produced %d bytes, want 5", hz, len(b)) } if got := civ.BCDToFreq(b); got != hz { t.Errorf("round trip %d → % X → %d", hz, b, got) } } }