fix(kenwood): keep the CAT link up while transmitting (K3 shared-CAT FT8)
A K3 (and other Kenwood-dialect rigs) answers "?;" to an IF; status poll while it is transmitting. ask() latched that as "IF unsupported" and ReadState returned an error, so the Manager dropped the whole CAT link mid-transmit — the log shows connected=false / "IF rejected" the instant JTDX sent TX;. That tore down the shared rigctld CAT the digital-mode software keys through. Two fixes: (1) track PTT (SetPTT) and skip the wire poll while it's held — ReadState hands back the cached last state, capped at 30 s so a missed SetPTT(false) can't freeze it; (2) never latch IF/ID as unsupported — those are universal on Kenwood/Elecraft, so a "?;" to them is a transient busy (mid-TX), not a missing command.
This commit is contained in:
+32
-4
@@ -115,6 +115,17 @@ type Kenwood struct {
|
||||
// nothing. Off by default: that is how this backend behaved for its whole
|
||||
// life before the question came up.
|
||||
lowerLines bool
|
||||
|
||||
// tx tracks whether we currently hold PTT (SetPTT true). A Kenwood/Elecraft rig
|
||||
// answers "?;" to a status poll (IF;) WHILE TRANSMITTING; OpsLog used to read
|
||||
// that as "the rig doesn't support IF;", latch it off and drop the whole CAT
|
||||
// link — which tore down the shared-CAT PTT that WSJT-X / JTDX key through, so a
|
||||
// K3 keyed but the logger's transmission fell apart. While PTT is held we skip
|
||||
// the wire poll and hand back the last good state (lastState) instead. txAt caps
|
||||
// the skip so a missed SetPTT(false) can't freeze the state for ever.
|
||||
tx bool
|
||||
txAt time.Time
|
||||
lastState RigState
|
||||
}
|
||||
|
||||
// SetLowerLines chooses whether DTR and RTS are deasserted on connect. Set
|
||||
@@ -255,6 +266,15 @@ func (k *Kenwood) ReadState() (RigState, error) {
|
||||
if k.port == nil {
|
||||
return RigState{}, fmt.Errorf("kenwood: not connected")
|
||||
}
|
||||
// While transmitting, don't poll: the rig returns "?;" to IF; during TX, and
|
||||
// treating that as a fault dropped the shared CAT link the digital-mode
|
||||
// software keys through. Hand back the last known state. The 30 s cap resyncs
|
||||
// if a SetPTT(false) was somehow missed, so a stuck TX can't freeze state.
|
||||
if k.tx && !k.txAt.IsZero() && time.Since(k.txAt) < 30*time.Second {
|
||||
s := k.lastState
|
||||
s.Connected = true
|
||||
return s, nil
|
||||
}
|
||||
raw, err := k.ask("IF;")
|
||||
if err != nil {
|
||||
return RigState{}, err
|
||||
@@ -339,6 +359,7 @@ func (k *Kenwood) ReadState() (RigState, error) {
|
||||
if s.Split {
|
||||
k.curRXFreq = s.RxFreqHz
|
||||
}
|
||||
k.lastState = s // cache for the transmit window, where we can't poll
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -409,7 +430,9 @@ func (k *Kenwood) SetPTT(on bool) error {
|
||||
if k.port == nil {
|
||||
return fmt.Errorf("kenwood: not connected")
|
||||
}
|
||||
k.tx = on
|
||||
if on {
|
||||
k.txAt = time.Now()
|
||||
return k.write("TX;")
|
||||
}
|
||||
return k.write("RX;")
|
||||
@@ -467,10 +490,15 @@ func (k *Kenwood) ask(cmd string) (string, error) {
|
||||
k.rx = k.rx[i+1:]
|
||||
traceText("kenwood", "RX", frame)
|
||||
if frame == "?;" {
|
||||
// The rig rejected the command. Remember it so the poll loop stops
|
||||
// paying a 600 ms timeout for it on every cycle.
|
||||
k.unsupported[want] = true
|
||||
debugLog.Printf("kenwood: this rig does not support %q — not asking again", cmd)
|
||||
// IF; and ID; are universal on Kenwood/Elecraft — a "?;" to them is a
|
||||
// transient "busy" (typically mid-transmit, or a menu open on the rig),
|
||||
// NOT "unsupported". Latching them off would blind the poll loop for
|
||||
// good and read as "lost the rig". Only remember the OPTIONAL commands
|
||||
// (FR/FT/…) so the poll loop stops paying a 600 ms timeout for those.
|
||||
if want != "IF" && want != "ID" {
|
||||
k.unsupported[want] = true
|
||||
debugLog.Printf("kenwood: this rig does not support %q — not asking again", cmd)
|
||||
}
|
||||
return "", fmt.Errorf("kenwood: %s rejected", want)
|
||||
}
|
||||
if strings.HasPrefix(frame, want) {
|
||||
|
||||
Reference in New Issue
Block a user