feat(rigctld): split that actually reaches the radio, or an honest refusal
set_split_vfo and set_split_freq both answered RPRT 0 and did nothing. WSJT-X and JTDX in "Split Operating: Rig" send exactly that pair, believed both, and transmitted on the RECEIVE frequency — on a pileup, straight onto the DX, while showing the operator precisely what they had asked for. A lie that leaves no trace in any log is the worst kind of bug this program can have. The two commands are honoured as a PAIR. Arming alone does nothing on the radio, because WSJT-X sends the frequency second and split armed on whatever the transmit VFO happened to hold is worse than no split at all: it transmits somewhere the operator never chose. The request is remembered and set_split_freq does the work. Kenwood gains SetSplit — FB to place the dial, then FR0/FT1 to arm, in that order for the same reason. It writes what State() already knows how to read. Everything else REFUSES, and that is the feature, not a shortfall. Only Flex and Icom could even toggle split before, neither could set the transmit frequency, and Yaesu, TCI and OmniRig have nothing at all. A refusal WSJT-X can report — and act on, by falling back to Fake It — is worth far more than a success it has no way to check. Both paths are pinned: split reaching the rig as one armed call with the right frequency, and a backend that cannot do it producing an error rather than RPRT 0.
This commit is contained in:
@@ -200,6 +200,31 @@ func (m *Manager) SetPTT(on bool) error {
|
||||
return m.exec(func(b Backend) error { return b.SetPTT(on) })
|
||||
}
|
||||
|
||||
// splitSetter is implemented by the backends that can arm split AND place the
|
||||
// transmit frequency. Both together: arming without setting the dial transmits
|
||||
// on whatever the transmit VFO happened to hold, which is worse than refusing.
|
||||
type splitSetter interface {
|
||||
SetSplit(on bool, txHz int64) error
|
||||
}
|
||||
|
||||
// SetSplit arms or clears split on the rig, with the transmit frequency.
|
||||
//
|
||||
// Returns a plain error on a backend that cannot do it, and that is the point.
|
||||
// The shared-CAT server used to answer "done" to WSJT-X's split commands while
|
||||
// doing nothing at all — the software then believed it was transmitting up the
|
||||
// band when it was transmitting on the DX's own frequency. A refusal WSJT-X can
|
||||
// report is worth far more than a success it cannot check.
|
||||
func (m *Manager) SetSplit(on bool, txHz int64) error {
|
||||
return m.exec(func(b Backend) error {
|
||||
s, ok := b.(splitSetter)
|
||||
if !ok {
|
||||
return fmt.Errorf("cat: this radio's backend cannot set split from software — " +
|
||||
"use Split Operating: Fake It in WSJT-X/JTDX, or set split on the radio itself")
|
||||
}
|
||||
return s.SetSplit(on, txHz)
|
||||
})
|
||||
}
|
||||
|
||||
// SpotInfo is one cluster spot to render on a backend that supports a spot
|
||||
// overlay (the FlexRadio panadapter). Color is an optional "#AARRGGBB" string;
|
||||
// the backend picks a default when it's empty. (Status-based colouring can be
|
||||
|
||||
Reference in New Issue
Block a user