From 7f328d4eb5a8b4b736ab4e9020c33f7f78d885de Mon Sep 17 00:00:00 2001 From: rouggy Date: Sat, 29 Aug 2026 16:07:42 +0200 Subject: [PATCH] debug(icom): say what the CI-V stream was doing when it goes quiet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A real IC-7760 keeps going silent on the CI-V stream two-three minutes into a session while the control link stays alive. At 10 s of silence the pump now logs the last real socket error and the retransmit backlog, and notes when the stream resumes — the 30 s watchdog that follows cannot tell a dead socket from a rig that stopped talking, and the next occurrence should. --- internal/cat/icomnet.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/internal/cat/icomnet.go b/internal/cat/icomnet.go index 1397cf5..0c8db99 100644 --- a/internal/cat/icomnet.go +++ b/internal/cat/icomnet.go @@ -359,6 +359,14 @@ func (n *icomNet) civPump() { buf := make([]byte, 8192) lastIdle := time.Now() lastReq := time.Now() + // Diagnosis for the recurring 2-3-minute silence a real IC-7760 shows on + // this stream while the control link stays alive: when the stream has been + // quiet for 10 s, say so ONCE, with the last read error — a socket error + // and a rig that stopped talking are different repairs, and the 30 s + // watchdog that follows cannot tell them apart from where it sits. + lastPkt := time.Now() + var lastErr error + quietSaid := false for { select { case <-n.done: @@ -366,7 +374,18 @@ func (n *icomNet) civPump() { default: } _ = n.civ.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - if k, err := n.civ.Read(buf); err == nil && k >= 16 { + k, err := n.civ.Read(buf) + if err != nil { + if e, ok := err.(net.Error); !ok || !e.Timeout() { + lastErr = err // a REAL socket error, not the read deadline + } + } + if err == nil && k >= 16 { + if quietSaid { + debugLog.Printf("icom net: CI-V stream is talking again after %s of silence", time.Since(lastPkt).Round(time.Second)) + quietSaid = false + } + lastPkt = time.Now() n.markRx() switch typ := icnLE.Uint16(buf[4:]); { case typ == 0x07: // ping @@ -410,6 +429,10 @@ func (n *icomNet) civPump() { } } } + if !quietSaid && time.Since(lastPkt) > 10*time.Second { + quietSaid = true + debugLog.Printf("icom net: CI-V stream quiet for 10 s (control link still alive; last socket error: %v; missing-seq backlog: %d) — idles and retransmit requests are still being sent", lastErr, len(n.rxMissing)) + } if time.Since(lastIdle) > 150*time.Millisecond { _, _ = n.civ.Write(icnCtrl(0x00, 0, n.vID, n.vRemote)) lastIdle = time.Now()