package cat import "testing" // WSJT-X "Fake It" against the transmit-window cache. // // Fake It keeps the radio on one dial frequency and shifts it only for the // duration of each over: set the transmit frequency, key, transmit, unkey, set // it back. The restore is not unconditional — WSJT-X reads the frequency back // and puts the dial where it believes it should be. // // That read lands inside the window where this backend deliberately stops // polling, because a Kenwood answers "?;" to IF; while it is transmitting and // treating that as a fault used to drop the whole shared link. The cache // answers instead. So the cache has to account for frequency SETS made during // the window, or it describes the dial as it was before the over — and WSJT-X, // told the radio is already on the receive frequency, has nothing to restore. // // This reproduces the sequence from a reported session: the dial stayed on the // transmit frequency after the first over and every later one started there. func TestKenwoodFakeItRestoresAfterTransmit(t *testing.T) { const ( rxHz = 7074000 // where the operator is listening txHz = 7075500 // where Fake It moves the dial to transmit ) rig := &ts2000{vfoA: rxHz, mode: '2'} k := NewKenwood("COM-TEST", 9600, "FT8") k.dialPort = dialTo(rig) if err := k.Connect(); err != nil { t.Fatalf("connect: %v", err) } defer k.Disconnect() if s, err := k.ReadState(); err != nil || s.FreqHz != rxHz { t.Fatalf("before the over: %d (err %v) — want %d", s.FreqHz, err, rxHz) } // The over: shift the dial, then key. if err := k.SetFrequency(txHz); err != nil { t.Fatalf("set transmit frequency: %v", err) } if err := k.SetPTT(true); err != nil { t.Fatalf("ptt on: %v", err) } // WSJT-X reads back mid-over. The wire is not polled here — this is the // cache talking, and it must not still be saying rxHz. s, err := k.ReadState() if err != nil { t.Fatalf("read during the over: %v", err) } if s.FreqHz != txHz { t.Errorf("during the over the backend reported %d, want %d — "+ "reporting the pre-over frequency is what stops Fake It restoring the dial", s.FreqHz, txHz) } if err := k.SetPTT(false); err != nil { t.Fatalf("ptt off: %v", err) } // The restore, once the over is done. if err := k.SetFrequency(rxHz); err != nil { t.Fatalf("restore: %v", err) } if rig.vfoA != rxHz { t.Errorf("dial left on %d after the over, want %d", rig.vfoA, rxHz) } if s, err := k.ReadState(); err != nil || s.FreqHz != rxHz { t.Errorf("after the over: %d (err %v) — want %d", s.FreqHz, err, rxHz) } } // Under split the same write must NOT touch the cache: FreqHz means the // transmit frequency while the write lands on whichever VFO the operator is on, // so guessing which side moved would put a wrong number in front of the // operator. A stale one survives only until the next poll. func TestKenwoodSplitCacheLeftToThePoll(t *testing.T) { rig := &ts2000{vfoA: 14025000, vfoB: 14030000, mode: '3', split: true} k := NewKenwood("COM-TEST", 9600, "CW") k.dialPort = dialTo(rig) if err := k.Connect(); err != nil { t.Fatalf("connect: %v", err) } defer k.Disconnect() s, err := k.ReadState() if err != nil || !s.Split { t.Fatalf("split not seen: %+v (err %v)", s, err) } before := s.FreqHz if err := k.SetFrequency(14026000); err != nil { t.Fatalf("set: %v", err) } if k.lastState.FreqHz != before { t.Errorf("split cache moved to %d on a VFO write, want it left at %d for the poll", k.lastState.FreqHz, before) } }