package cat import "testing" // In split, OpsLog stays on the RECEIVE slice. // // SmartSDR moves its "active" flag onto the TX slice as soon as the transmit // frequency is touched. Following it hands the operator the S-meter, audio // level, filter and DSP of a receiver they are not listening to — while the DX // they are working is on the other slice. func TestMainSliceStaysOnRXInSplit(t *testing.T) { mk := func(hz int64, mode string, active, tx bool) *flexSlice { return &flexSlice{freqHz: hz, mode: mode, active: active, tx: tx, inUse: true} } // Working a DX on 14.100, transmitting up on 14.200. The radio has focused // the transmitter. f := &Flex{pinnedSlice: -1, slices: map[int]*flexSlice{ 0: mk(14_100_000, "USB", false, false), // where the DX is heard 1: mk(14_200_000, "USB", true, true), // where we transmit, radio-focused }} idx, s := f.mainSliceLocked() if idx != 0 || s == nil || s.freqHz != 14_100_000 { t.Errorf("main slice = %d (%v Hz) — want slice 0, the RX side on 14.100", idx, s.freqHz) } // Simplex: the radio's focus is authoritative again, nothing to prefer. f2 := &Flex{pinnedSlice: -1, slices: map[int]*flexSlice{ 0: mk(14_100_000, "USB", false, false), 1: mk(14_200_000, "USB", true, true), }} f2.slices[0].inUse = false // only the TX slice is in use → simplex if idx, _ := f2.mainSliceLocked(); idx != 1 { t.Errorf("simplex main slice = %d, want 1 — the only slice in use", idx) } // Two same-band slices in DIFFERENT classes are not a split (SSB + FT8), so // there is nothing to prefer and the radio's focus stands. f3 := &Flex{pinnedSlice: -1, slices: map[int]*flexSlice{ 0: mk(14_074_000, "DIGU", false, false), 1: mk(14_200_000, "USB", true, true), }} if idx, _ := f3.mainSliceLocked(); idx != 1 { t.Errorf("SSB+FT8 main slice = %d, want 1 — that is not a split", idx) } } // A slice picked IN OPSLOG wins over everything, including the split rule and // the radio's own focus. Picking one on the radio does not move OpsLog. func TestPinnedSliceWins(t *testing.T) { mk := func(hz int64, mode string, active, tx bool) *flexSlice { return &flexSlice{freqHz: hz, mode: mode, active: active, tx: tx, inUse: true} } f := &Flex{pinnedSlice: 1, slices: map[int]*flexSlice{ 0: mk(14_100_000, "USB", true, false), // radio-focused 1: mk(14_200_000, "USB", false, true), // chosen in OpsLog }} if idx, _ := f.mainSliceLocked(); idx != 1 { t.Errorf("main slice = %d — an explicit choice in OpsLog must win", idx) } // A pin on a slice that is no longer in use is not a choice any more: it // must not strand OpsLog on a receiver that has been closed. f.slices[1].inUse = false if idx, _ := f.mainSliceLocked(); idx != 0 { t.Errorf("main slice = %d — a closed slice cannot stay pinned", idx) } }