chore: release v0.27.12
This commit is contained in:
@@ -262,7 +262,18 @@ func (s *Server) serve(c net.Conn) {
|
||||
return
|
||||
}
|
||||
req := strings.TrimSpace(line)
|
||||
started := time.Now()
|
||||
resp, quit := s.handle(req)
|
||||
// A command the radio took a visible time to accept is worth a line of its
|
||||
// own, always — not behind the trace switch below.
|
||||
//
|
||||
// This is the shape every "WSJT-X takes ten seconds to change band" report
|
||||
// has: the client is waiting on us, we are waiting on the rig, and the log
|
||||
// showed neither. Which command, and how long, is the whole diagnosis —
|
||||
// and one second is already far outside anything a healthy link does.
|
||||
if took := time.Since(started); took > time.Second && req != "" {
|
||||
s.log("rigctld: %q took %s — the radio was slow to answer, the client waited that long", req, took.Round(10*time.Millisecond))
|
||||
}
|
||||
// The whole exchange, when tracing is on.
|
||||
//
|
||||
// Only PTT transitions were ever recorded, so when JTDX aborted a
|
||||
@@ -362,6 +373,21 @@ func (s *Server) handle(line string) (resp string, quit bool) {
|
||||
if len(args) < 1 {
|
||||
return rprt(-1), false
|
||||
}
|
||||
// Only touch the radio on a CHANGE, the same rule set_ptt above follows.
|
||||
//
|
||||
// WSJT-X restates the mode on every band change and after every transmit,
|
||||
// almost always the mode the rig is already in. On a native backend that
|
||||
// is not free: an Icom set_mode is the mode frame, the data-mode frame and
|
||||
// a readback to check the rig honoured them, each a round trip — over a
|
||||
// remote CI-V link that is seconds, spent to arrive where we already were,
|
||||
// with the client blocked on the answer the whole time.
|
||||
//
|
||||
// Compared in the CLIENT's own vocabulary — what "m" would report against
|
||||
// what it just asked for — so nothing it can observe changes. A rig whose
|
||||
// mode we do not know yet (empty) is never assumed.
|
||||
if cur := s.rig.Mode(); cur != "" && adifToHamlib(cur) == adifToHamlib(hamlibToADIF(args[0])) {
|
||||
return rprt(0), false
|
||||
}
|
||||
if err := s.rig.SetMode(hamlibToADIF(args[0])); err != nil {
|
||||
s.log("rigctld: set_mode %q failed: %v", args[0], err)
|
||||
return rprt(-9), false
|
||||
|
||||
@@ -332,3 +332,31 @@ func TestModeMapping(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A mode the rig is already in must not reach it. WSJT-X restates the mode on
|
||||
// every band change, and on a native backend each restatement is several CI-V
|
||||
// round trips with the client blocked on the answer.
|
||||
func TestSetModeSkipsWhenUnchanged(t *testing.T) {
|
||||
cases := []struct {
|
||||
rig string // what the rig reports (ADIF)
|
||||
ask string // what the client asks for (hamlib)
|
||||
want int // times the radio should be touched
|
||||
}{
|
||||
{"CW", "CW", 0},
|
||||
{"SSB", "USB", 0}, // "SSB" is reported as USB to a client
|
||||
{"FT8", "PKTUSB", 0}, // data rides on USB; both name it PKTUSB
|
||||
{"USB", "PKTUSB", 1}, // out of data mode into it: a real change
|
||||
{"CW", "USB", 1}, // a real change
|
||||
{"", "USB", 1}, // mode unknown: never assume
|
||||
}
|
||||
for _, c := range cases {
|
||||
f := &fakeRig{mode: c.rig, freq: 14074000}
|
||||
s := New(4532, f, nil)
|
||||
if got, _ := s.handle("M " + c.ask); got != "RPRT 0\n" {
|
||||
t.Fatalf("set_mode %q on a rig in %q = %q", c.ask, c.rig, got)
|
||||
}
|
||||
if n := len(f.setModes); n != c.want {
|
||||
t.Errorf("rig in %q, client asked %q: rig touched %d times, want %d", c.rig, c.ask, n, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user