//go:build windows package cat import "fmt" // TCIAudioController is the receive-audio capability of the TCI backend, kept // as an interface for the same reason as the Flex and Yaesu ones: the host asks // the manager, and a station running something else gets a clear "this backend // does not do that" instead of a nil dereference. type TCIAudioController interface { StartTCIAudio(rx, rate int) error StopTCIAudio() error TCIAudioStatus() TCIAudioStatus } // TCIAudioState returns the stream's state, or (zero, false) when the active // backend is not a TCI radio. func (m *Manager) TCIAudioState() (TCIAudioStatus, bool) { m.mu.RLock() b := m.backend m.mu.RUnlock() if tc, ok := b.(TCIAudioController); ok { return tc.TCIAudioStatus(), true } return TCIAudioStatus{}, false } // TCIAudioDo dispatches an audio command onto the CAT goroutine, like every // other backend-specific control. func (m *Manager) TCIAudioDo(fn func(TCIAudioController) error) error { return m.exec(func(b Backend) error { tc, ok := b.(TCIAudioController) if !ok { return fmt.Errorf("active CAT backend is not a TCI radio") } return fn(tc) }) } // TCIPanelController is the control console of a TCI radio — everything the // panel reads and everything it sets. // // Listed one by one rather than accepted as *TCI, for the same reason the audio // controller is: the manager hands out capabilities, not backends, and a // station on OmniRig asking for the TCI console gets a sentence instead of a // crash. type TCIPanelController interface { TCIPanel() TCIPanelState SetDrive(v int) error SetTuneDrive(v int) error SetMicLevel(v int) error SetVolume(db int) error SetMute(on bool) error SetAGC(mode string) error SetSquelch(on bool) error SetSquelchLevel(v int) error SetNB(on bool) error SetNR(on bool) error SetANF(on bool) error SetAPF(on bool) error SetFilter(lo, hi int) error SetRIT(on bool) error SetXIT(on bool) error SetRITOffset(hz int) error SetXITOffset(hz int) error SetLock(on bool) error SetTune(on bool) error } // TCIPanelState returns the console snapshot, or (zero, false) when the active // backend is not a TCI radio. // // Read WITHOUT going through the CAT goroutine: the state is a cached copy of // what the radio pushed, guarded by its own lock, and the panel polls it several // times a second. Queueing that behind whatever the poll loop is doing would put // the console's smoothness at the mercy of a rig command's timeout. func (m *Manager) TCIPanelState() (TCIPanelState, bool) { m.mu.RLock() b := m.backend m.mu.RUnlock() if tc, ok := b.(TCIPanelController); ok { return tc.TCIPanel(), true } return TCIPanelState{}, false } // TCIPanelDo dispatches one console command onto the CAT goroutine, where every // other write to the radio goes. func (m *Manager) TCIPanelDo(fn func(TCIPanelController) error) error { return m.exec(func(b Backend) error { tc, ok := b.(TCIPanelController) if !ok { return fmt.Errorf("the active CAT backend is not a TCI radio") } return fn(tc) }) }