chore: log a DELAYED frequency readback after an OmniRig set

An FTDX10 operator reports that changing band from OpsLog moves the rig but the
displayed frequency stays on the old band until they nudge the VFO. The existing
readback is taken immediately after the write, so it always shows the old value
and proves nothing: OmniRig queues the CAT command and sends it over serial.

A second readback is now logged ~1.5 s later, from ReadState (the goroutine that
owns the COM apartment), together with what OpsLog concluded. That separates the
two candidates, which look identical to the operator: the rig ignored the write,
or the rig moved and its rig file never re-reads the frequency.
This commit is contained in:
2026-07-28 14:39:04 +02:00
parent 386fb7f030
commit 91f046444a
+36 -14
View File
@@ -67,6 +67,10 @@ type OmniRig struct {
splitFlaky bool splitFlaky bool
splitFlips int splitFlips int
splitFlipWindow time.Time splitFlipWindow time.Time
// pendingReadback schedules one delayed frequency log after a Set — see
// SetFrequency. Zero when nothing is pending.
pendingReadback time.Time
} }
// NewOmniRig creates a non-connected backend. Call Connect before use. // NewOmniRig creates a non-connected backend. Call Connect before use.
@@ -328,6 +332,14 @@ func (o *OmniRig) ReadState() (RigState, error) {
} }
s.FreqHz, s.RxFreqHz, s.Split = resolveOmniRigVFOs(o.rigType, freqMain, freqA, freqB, vfo, splitRaw, splitRecentOn) s.FreqHz, s.RxFreqHz, s.Split = resolveOmniRigVFOs(o.rigType, freqMain, freqA, freqB, vfo, splitRaw, splitRecentOn)
// Delayed readback after a Set (see SetFrequency): logged from HERE because
// this runs on the COM-owning goroutine. One line, once per set.
if !o.pendingReadback.IsZero() && time.Now().After(o.pendingReadback) {
o.pendingReadback = time.Time{}
debugLog.Printf("OmniRig.SetFrequency: readback +1.5s FreqA=%d FreqB=%d Freq=%d → shown %d",
freqA, freqB, freqMain, s.FreqHz)
}
// Diagnostic logged ONLY when Split or VFO changes (not on a timer), so normal // Diagnostic logged ONLY when Split or VFO changes (not on a timer), so normal
// operation stays quiet but toggling split or SUB VFO on the radio is // operation stays quiet but toggling split or SUB VFO on the radio is
// captured. It logs the RESOLVED tx/rx/split too: with the raw values alone a // captured. It logs the RESOLVED tx/rx/split too: with the raw values alone a
@@ -517,21 +529,31 @@ func (o *OmniRig) SetFrequency(hz int64) error {
} }
} }
// Read back all three immediately. OmniRig is async (the CAT command is // Read back all three, then AGAIN a moment later. OmniRig is async the CAT
// queued + sent over serial), so these may still show the OLD value for // command is queued and sent over serial so an immediate read always shows
// one poll cycle — but if they NEVER change in the next poll, the rig // the old value and proves nothing. The delayed one is the useful half: it
// isn't honouring the write (wrong .ini WRITE command for this model). // separates "the rig ignored the write" from "the rig moved but its .ini
fa, fb, fg := int64(-1), int64(-1), int64(-1) // never re-reads the frequency", which look identical to an operator whose
if v, err := oleutil.GetProperty(o.rig, "FreqA"); err == nil { // display stays on the old band until they nudge the VFO.
fa = v.Val //
// Off the CAT goroutine so the poll loop is not held for a second. COM is
// thread-affine, so the delayed read goes through the manager's own command
// channel rather than touching o.rig from here.
logFreqs := func(when string) {
fa, fb, fg := int64(-1), int64(-1), int64(-1)
if v, err := oleutil.GetProperty(o.rig, "FreqA"); err == nil {
fa = v.Val
}
if v, err := oleutil.GetProperty(o.rig, "FreqB"); err == nil {
fb = v.Val
}
if v, err := oleutil.GetProperty(o.rig, "Freq"); err == nil {
fg = v.Val
}
debugLog.Printf("OmniRig.SetFrequency: readback %s FreqA=%d FreqB=%d Freq=%d (target %d)", when, fa, fb, fg, hz)
} }
if v, err := oleutil.GetProperty(o.rig, "FreqB"); err == nil { logFreqs("now")
fb = v.Val o.pendingReadback = time.Now().Add(1500 * time.Millisecond)
}
if v, err := oleutil.GetProperty(o.rig, "Freq"); err == nil {
fg = v.Val
}
debugLog.Printf("OmniRig.SetFrequency: readback FreqA=%d FreqB=%d Freq=%d (target %d)", fa, fb, fg, hz)
return nil return nil
} }