refactor(winkeyer): learn the slow boot instead of naming the keyer

The K3NG entry added an hour ago is gone. It named one clone among many —
WKmini, home-built Arduinos, unbranded boxes — for hardware that speaks
exactly the same protocol, and it was the only line in the engine list that
picked a boot delay rather than a protocol. An operator with an unlabelled
clone would have had to guess.

The delay is now learnt per port. The first connect finds out by failing the
quick attempt and succeeding on the slow one; that fact is written to a
global setting keyed by the port, and every connect afterwards goes straight
to the slow attempt. Global rather than per profile on purpose: which keyer
is plugged into COM3 belongs to the computer, and switching profiles for a
different rig does not change the keyer on the desk.

Two tests hold the contract from both sides — a slow keyer must be reported
as slow, and a keyer that answers at once must not be, or every K1EL connect
would inherit seconds it never needed.
This commit is contained in:
2026-08-14 13:05:13 +02:00
parent aca4dc5678
commit 3ce930e9cc
7 changed files with 94 additions and 30 deletions
+7 -6
View File
@@ -65,9 +65,10 @@ var errNoKeyer = errors.New("no WinKeyer answered on this port — check the cab
// by whoever talked to it last (the first attempt's nulls clear that), and an
// Arduino-based keyer still rebooting from the DTR edge (the second attempt
// waits long enough for it).
// slowBoot skips straight to the long wait: set when the operator has told us
// the keyer is a K3NG, which reboots on every connect.
func hostOpen(p serial.Port, slowBoot bool) (int, error) {
// slowBoot skips straight to the long wait, set when this port has already been
// seen to need it. The second return value says whether the long wait is what
// worked, so the caller can remember it and open quickly next time.
func hostOpen(p serial.Port, slowBoot bool) (ver int, needsSlowBoot bool, err error) {
var lastErr error
for attempt := 1; attempt <= handshakeTry; attempt++ {
wait := bootDelay
@@ -77,16 +78,16 @@ func hostOpen(p serial.Port, slowBoot bool) (int, error) {
ver, err := hostOpenOnce(p, wait)
if err == nil {
if attempt > 1 {
applog.Printf("winkeyer: answered on attempt %d — the keyer needed %s to boot (a K3NG or other Arduino keyer with auto-reset enabled)", attempt, wait)
applog.Printf("winkeyer: answered on attempt %d — this keyer needs %s to boot (a K3NG or another Arduino keyer with auto-reset on); remembering that for this port", attempt, wait)
}
return ver, nil
return ver, wait == resetDelay, nil
}
lastErr = err
if attempt < handshakeTry {
applog.Printf("winkeyer: handshake attempt %d failed (%v) — retrying after %s in case the keyer is rebooting", attempt, err, resetDelay)
}
}
return 0, lastErr
return 0, false, lastErr
}
func hostOpenOnce(p serial.Port, boot time.Duration) (int, error) {