fix: the FTDX10 refuses KY; — stop waiting on a status it will never send

The log settled it: the rig answers "?;" — its "unknown command" — to KY; and to
MG;. So the keyer status query cannot work on this model, and every send spent
four seconds waiting for an answer that was never coming.

"?;" is now recognised as what it is. A command refused once is never asked
again: models implement different subsets, and re-asking costs a 600 ms timeout
on every slow beat for a control that will never answer — which is also why the
panel felt sluggish.

Without a buffer status there is still a real constraint: one KY command carries
24 characters and the rig DROPS the rest silently. So the send is now paced by
how long the text takes to key, from PARIS timing at the rig's own speed. A long
macro goes out complete instead of losing its tail.

That leaves the question the log cannot answer: whether KY <text>; itself is
accepted. If the rig also replies "?;" to it, the CAT menu's PC KEYING setting is
the next suspect — but nothing in the code will be guessing at it.
This commit is contained in:
2026-07-29 13:15:36 +02:00
parent d0666581c3
commit d114a73729
4 changed files with 111 additions and 2 deletions
+28
View File
@@ -3,6 +3,7 @@ package cat
import (
"strings"
"testing"
"time"
)
// What reaches the rig's keyer.
@@ -92,3 +93,30 @@ func TestYaesuCWBufferFull(t *testing.T) {
}
}
}
// Pacing when the rig will not report its buffer.
//
// An FTDX10 answers "?;" to KY;, so there is nothing to wait on and the send has
// to be spaced by how long the text takes to key — otherwise the second piece
// overruns the 24-character buffer and the rig drops it silently.
func TestYaesuCWDuration(t *testing.T) {
// PARIS: at 20 wpm a dit is 60 ms and a character averages 10 dits, so 24
// characters take about 14.4 s.
got := yaesuCWDuration("ABCDEFGHIJKLMNOPQRSTUVWX", 20)
if got < 13*time.Second || got > 16*time.Second {
t.Errorf("24 chars at 20 wpm = %s, expected about 14.4s", got)
}
// Twice the speed, half the time.
fast := yaesuCWDuration("ABCDEFGHIJKLMNOPQRSTUVWX", 40)
if fast >= got || fast < got/3 {
t.Errorf("40 wpm = %s vs 20 wpm = %s — should be about half", fast, got)
}
// A nonsense speed must not produce a zero wait (send everything at once) nor
// an absurd one (the operator waiting minutes).
if d := yaesuCWDuration("TEST", 0); d <= 0 || d > 10*time.Second {
t.Errorf("4 chars at an unknown speed = %s, want a sane fallback", d)
}
if d := yaesuCWDuration("", 20); d != 0 {
t.Errorf("empty text = %s, want 0", d)
}
}