fix: split read (and set) backwards on a Yaesu reporting the TX VFO
Reported on an FTDX101: the panel showed split ON with the radio OFF, and the reverse — while the same model behaved correctly for another operator, and an FTDX10 was fine throughout. That pattern is the clue: one operator was on MAIN, the other on SUB. The two commands say different things and were read alike: ST is a split FLAG — ST1 means split, whatever VFO is in use. FT names the TX VFO — FT0 = transmit on A, FT1 = transmit on B. Split is on when the rig transmits on a DIFFERENT VFO from the one it listens to. Reading FT1 as "split" is therefore correct only on VFO A, and exactly inverted on SUB. It is now compared with the current VFO. Writing had the identical fault, and it was worse: sending FT1 for "split on" while the operator listened on SUB CLEARED the split it was asked to set. Both directions are pinned by tests over each VFO state.
This commit is contained in:
+69
-13
@@ -54,24 +54,46 @@ func TestResolveYaesuVFOs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// ST and FT say different things and must not be read the same way — see the
|
||||
// comment on yaesuSplitOn.
|
||||
// ST and FT say different things, and reading them alike inverted the split
|
||||
// display on an FTDX101 (F4NBZ, 2026-07-29): the panel showed split ON with the
|
||||
// radio OFF and the reverse.
|
||||
//
|
||||
// ST is a split FLAG — ST1 means split, whatever VFO is in use.
|
||||
// FT names the TX VFO — FT0 = transmit on A, FT1 = transmit on B.
|
||||
//
|
||||
// Split is on when the rig transmits on a DIFFERENT VFO from the one it listens
|
||||
// to, so FT has to be compared with the current VFO. That is why the same model
|
||||
// behaved correctly for one operator and backwards for another: one was on MAIN,
|
||||
// the other on SUB.
|
||||
func TestYaesuSplitReply(t *testing.T) {
|
||||
cases := []struct {
|
||||
reply, cmd string
|
||||
want bool
|
||||
reply, cmd, vfo string
|
||||
want bool
|
||||
}{
|
||||
{"ST1;", "ST", true},
|
||||
{"ST0;", "ST", false},
|
||||
{"FT1;", "FT", true},
|
||||
{"FT0;", "FT", false},
|
||||
{"ST1;", "FT", false}, // reply for the other command — not accepted
|
||||
{"ST", "ST", false}, // truncated
|
||||
{"", "ST", false},
|
||||
// The flag is absolute.
|
||||
{"ST1;", "ST", "A", true},
|
||||
{"ST0;", "ST", "A", false},
|
||||
{"ST1;", "ST", "B", true},
|
||||
{"ST0;", "ST", "B", false},
|
||||
|
||||
// Listening on A: transmit on B is split, transmit on A is not.
|
||||
{"FT1;", "FT", "A", true},
|
||||
{"FT0;", "FT", "A", false},
|
||||
// Listening on B: exactly the opposite — the reported inversion.
|
||||
{"FT0;", "FT", "B", true},
|
||||
{"FT1;", "FT", "B", false},
|
||||
// The pair enums the Yaesus also report start with the listening VFO.
|
||||
{"FT0;", "FT", "BA", true},
|
||||
{"FT1;", "FT", "AB", true},
|
||||
|
||||
{"ST1;", "FT", "A", false}, // reply for the other command — not accepted
|
||||
{"ST", "ST", "A", false}, // truncated
|
||||
{"", "ST", "A", false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := yaesuSplitOn(c.reply, c.cmd); got != c.want {
|
||||
t.Errorf("yaesuSplitOn(%q,%q) = %v, want %v", c.reply, c.cmd, got, c.want)
|
||||
if got := yaesuSplitFromReply(c.reply, c.cmd, c.vfo); got != c.want {
|
||||
t.Errorf("yaesuSplitFromReply(%q, %q, vfo=%q) = %v, want %v",
|
||||
c.reply, c.cmd, c.vfo, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,3 +152,37 @@ func TestYaesuCmdPrefix(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Writing split is as asymmetric as reading it.
|
||||
//
|
||||
// ST takes the state directly. FT sets which VFO TRANSMITS, so "split on" means
|
||||
// transmit on the OTHER VFO from the one being listened to. Sending FT1 for "on"
|
||||
// regardless is right only on VFO A — on SUB it would CLEAR the split it was
|
||||
// asked to set, which is the same inversion that showed on the FTDX101 panel.
|
||||
func TestYaesuSplitCommand(t *testing.T) {
|
||||
cases := []struct {
|
||||
cmd, vfo string
|
||||
on bool
|
||||
want string
|
||||
}{
|
||||
{"ST", "A", true, "ST1;"},
|
||||
{"ST", "B", true, "ST1;"}, // the flag does not care which VFO
|
||||
{"ST", "B", false, "ST0;"},
|
||||
|
||||
// Listening on A: split means transmit on B.
|
||||
{"FT", "A", true, "FT1;"},
|
||||
{"FT", "A", false, "FT0;"},
|
||||
// Listening on B: split means transmit on A — the reverse.
|
||||
{"FT", "B", true, "FT0;"},
|
||||
{"FT", "B", false, "FT1;"},
|
||||
// Pair enums start with the listening VFO.
|
||||
{"FT", "BA", true, "FT0;"},
|
||||
{"FT", "AB", true, "FT1;"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := yaesuSplitCommand(c.cmd, c.vfo, c.on); got != c.want {
|
||||
t.Errorf("yaesuSplitCommand(%q, vfo=%q, on=%v) = %q, want %q",
|
||||
c.cmd, c.vfo, c.on, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user