fix: Yaesu mode commands always addressed the main receiver
Reported, and reasoned out from the half that already worked: a spot click now tunes the right VFO, but it set the mode with MD0 — main — whatever VFO the operator was on. Working from SUB, the spot changed the mode of the VFO NOT in use and left the one in use as it was. The author inferred the sub half from seeing main change, and was right. The read had the same fault, so the console displayed main's mode while showing the sub VFO's frequency. Mode now addresses the receiver in use — MD0 for main, MD1 for sub — in the poll read, in SetMode, and in the console's raw-mode setter. A rig without a sub receiver never sees MD1: curVFO only becomes B where the rig reports its receive VFO in the first place.
This commit is contained in:
+21
-3
@@ -17,7 +17,7 @@ package cat
|
||||
//
|
||||
// FA; → FA014074000; VFO A frequency, 9 digits, Hz
|
||||
// FB; → FB014100000; VFO B frequency
|
||||
// MD0; → MD02; operating mode of the main receiver
|
||||
// MD0;/MD1; → MD02; operating mode — 0 = main receiver, 1 = sub
|
||||
// FR; → FR1; RECEIVE VFO (0=main/A, 1=sub/B)
|
||||
// VS; → VS0; selected VFO, on models without FR
|
||||
// ST; → ST1; split (FTDX10/FTDX101)
|
||||
@@ -304,7 +304,7 @@ func (y *Yaesu) ReadState() (RigState, error) {
|
||||
y.curRXFreq = s.RxFreqHz
|
||||
}
|
||||
|
||||
if r, err := y.ask("MD0;"); err == nil && len(r) >= 4 {
|
||||
if r, err := y.ask("MD" + y.modeVFOSuffix() + ";"); err == nil && len(r) >= 4 {
|
||||
// Keep the RAW mode too: ADIF folds CW-U/CW-L and DATA-U/DATA-L together,
|
||||
// but the panel has to show which sideband the rig is actually on.
|
||||
y.panel.RawMode = yaesuRawModeName(r[3])
|
||||
@@ -351,7 +351,25 @@ func (y *Yaesu) SetMode(mode string) error {
|
||||
if d == 0 {
|
||||
return fmt.Errorf("yaesu: no CAT mode for %q", mode)
|
||||
}
|
||||
return y.write(fmt.Sprintf("MD0%c;", d))
|
||||
return y.write(fmt.Sprintf("MD%s%c;", y.modeVFOSuffix(), d))
|
||||
}
|
||||
|
||||
// modeVFOSuffix picks which receiver the mode commands address: "0" is main,
|
||||
// "1" is sub.
|
||||
//
|
||||
// Both the read and the write used 0 unconditionally. A spot click already tuned
|
||||
// the right VFO — that part was fixed — but then set the MODE on main, so an
|
||||
// operator working from the sub receiver had a spot change the mode of the VFO
|
||||
// they were not using and leave the one they were on untouched (F4NBZ,
|
||||
// 2026-07-29). The rig reads the same way, so the panel showed main's mode too.
|
||||
//
|
||||
// Rigs without a sub receiver simply never see "1": curVFO only becomes B on a
|
||||
// rig that reports its receive VFO.
|
||||
func (y *Yaesu) modeVFOSuffix() string {
|
||||
if y.curVFO == "B" {
|
||||
return "1"
|
||||
}
|
||||
return "0"
|
||||
}
|
||||
|
||||
func (y *Yaesu) SetPTT(on bool) error {
|
||||
|
||||
@@ -430,7 +430,9 @@ func (y *Yaesu) SetYaesuModeRaw(name string) error {
|
||||
if !ok {
|
||||
return fmt.Errorf("yaesu: unknown rig mode %q", name)
|
||||
}
|
||||
return y.setAndRefresh(fmt.Sprintf("MD0%c;", d))
|
||||
// Same receiver as everywhere else — the console must not set main's mode
|
||||
// while the operator is working the sub VFO.
|
||||
return y.setAndRefresh(fmt.Sprintf("MD%s%c;", y.modeVFOSuffix(), d))
|
||||
}
|
||||
|
||||
// yaesuRawModeDigit maps a rig-mode name to its MD digit.
|
||||
|
||||
@@ -347,3 +347,36 @@ func TestYaesuSplitProbeOrder(t *testing.T) {
|
||||
t.Error("ST1 is a flag and reads as split whatever the VFO — that is the trap")
|
||||
}
|
||||
}
|
||||
|
||||
// The mode commands address the receiver the operator is ON.
|
||||
//
|
||||
// Reported on an FTDX101 (F4NBZ, 2026-07-29): once a spot click tuned the right
|
||||
// VFO, it still changed the mode of MAIN while the operator worked from SUB — so
|
||||
// the VFO in use kept its old mode and the idle one was altered. The read had the
|
||||
// same fault, so the panel showed main's mode as well.
|
||||
func TestYaesuModeVFOSuffix(t *testing.T) {
|
||||
cases := []struct{ vfo, want string }{
|
||||
{"A", "0"}, // main
|
||||
{"", "0"}, // not yet read — main is the safe assumption
|
||||
{"B", "1"}, // sub
|
||||
{"AB", "0"}, // pair enums start with the receive VFO
|
||||
}
|
||||
for _, c := range cases {
|
||||
y := &Yaesu{}
|
||||
y.curVFO = c.vfo
|
||||
if got := y.modeVFOSuffix(); got != c.want {
|
||||
t.Errorf("curVFO=%q → MD%s, want MD%s", c.vfo, got, c.want)
|
||||
}
|
||||
}
|
||||
|
||||
// Spelled out as the commands actually sent, which is what the rig sees.
|
||||
y := &Yaesu{}
|
||||
y.curVFO = "B"
|
||||
if cmd := "MD" + y.modeVFOSuffix() + "3;"; cmd != "MD13;" {
|
||||
t.Errorf("setting CW on the sub receiver sends %q, want MD13;", cmd)
|
||||
}
|
||||
y.curVFO = "A"
|
||||
if cmd := "MD" + y.modeVFOSuffix() + "3;"; cmd != "MD03;" {
|
||||
t.Errorf("setting CW on main sends %q, want MD03;", cmd)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user