diff --git a/internal/cat/icomnet.go b/internal/cat/icomnet.go index 78c3867..7949b7b 100644 --- a/internal/cat/icomnet.go +++ b/internal/cat/icomnet.go @@ -98,6 +98,13 @@ type icomNet struct { vTracked uint16 vCivSeq uint16 seqMu sync.Mutex // guards vTracked/vCivSeq: the command loop AND the pump's quiet-recovery both send + // txCiv counts CI-V command packets sent, and txAtData snapshots it at the + // last received CI-V data. Their difference during a silence answers the + // question the reconnects cannot: were we still ASKING when the answers + // stopped? Zero writes-since-data would mean the fault is our own poll + // loop, not the rig — and RS-BA1 showing no such dropouts points that way. + txCiv atomic.Uint32 + txAtData atomic.Uint32 rx chan []byte // CI-V byte chunks from civPump → Read (control replies) scopeRx chan []byte // scope (0x27) frames, kept off rx so the panadapter @@ -233,6 +240,7 @@ func (n *icomNet) Write(p []byte) (int, error) { n.vTracked++ n.vCivSeq++ n.seqMu.Unlock() + n.txCiv.Add(1) pkt := icnCivData(seq, n.vID, n.vRemote, civSeq, p) n.sentMu.Lock() n.sentBuf[seq] = pkt @@ -405,6 +413,7 @@ func (n *icomNet) civPump() { quietSaid, gaveUp = false, false } lastData = time.Now() + n.txAtData.Store(n.txCiv.Load()) n.trackRxSeq(icnLE.Uint16(buf[6:])) // note gaps for retransmit civBytes := buf[0x15:k] cp := append([]byte(nil), civBytes...) @@ -443,8 +452,8 @@ func (n *icomNet) civPump() { if !lastScope.IsZero() { scopeAge = time.Since(lastScope).Round(time.Second).String() } - debugLog.Printf("icom net: no CI-V DATA for 10 s (transport last heard %s ago; last scope frame %s ago; last socket error: %v; missing-seq backlog: %d)", - time.Since(lastPkt).Round(time.Second), scopeAge, lastErr, len(n.rxMissing)) + debugLog.Printf("icom net: no CI-V DATA for 10 s (transport last heard %s ago; last scope frame %s ago; last socket error: %v; missing-seq backlog: %d; CI-V commands SENT since the last answer: %d)", + time.Since(lastPkt).Round(time.Second), scopeAge, lastErr, len(n.rxMissing), n.txCiv.Load()-n.txAtData.Load()) // And try the gentle repair before the 30 s watchdog tears the whole // session down: if the rig quietly closed the CI-V data flow (the // transport is still chatting, so the session itself stands), saying