fix: IC-7610 VFO A over OmniRig + faster Icom LAN reconnect
OmniRig: on the IC-7610 the generic Freq property reports the wrong VFO (its Main/Sub model confuses the stock ini), so OpsLog showed VFO B. Detect the rig by RigType and, in simplex, read VFO A explicitly — matching Log4OM. Only the 7610 is affected; other rigs keep using the generic Freq. Icom network: when the rig tears the session down (control/CI-V 0x05) OpsLog only logged it and kept the half-dead link until the 6 s liveness timeout expired. Mark the link dead on 0x05 so Alive() fails on the next poll and the manager reconnects cleanly right away.
This commit is contained in:
@@ -136,6 +136,11 @@ type icomNet struct {
|
|||||||
// but link fine" (stay connected) from "link dead" (reconnect). See Alive().
|
// but link fine" (stay connected) from "link dead" (reconnect). See Alive().
|
||||||
lastRx atomic.Int64
|
lastRx atomic.Int64
|
||||||
|
|
||||||
|
// dead is set when the rig explicitly tears the session down (control 0x05):
|
||||||
|
// Alive() then returns false immediately so ReadState fails on the next poll and
|
||||||
|
// the manager reconnects cleanly, instead of waiting out the 6 s lastRx timeout.
|
||||||
|
dead atomic.Bool
|
||||||
|
|
||||||
// audio is the optional RX audio stream (UDP 50003). nil when audio is off.
|
// audio is the optional RX audio stream (UDP 50003). nil when audio is off.
|
||||||
// Torn down alongside the CI-V/control streams in Close.
|
// Torn down alongside the CI-V/control streams in Close.
|
||||||
audio *icomAudio
|
audio *icomAudio
|
||||||
@@ -178,6 +183,9 @@ func (n *icomNet) markRx() { n.lastRx.Store(time.Now().UnixNano()) }
|
|||||||
// the radio — is gone. Independent of CI-V replies, so a powered-off rig still
|
// the radio — is gone. Independent of CI-V replies, so a powered-off rig still
|
||||||
// reads as Alive and the session isn't torn down. Satisfies aliveTransport.
|
// reads as Alive and the session isn't torn down. Satisfies aliveTransport.
|
||||||
func (n *icomNet) Alive() bool {
|
func (n *icomNet) Alive() bool {
|
||||||
|
if n.dead.Load() {
|
||||||
|
return false // rig sent an explicit disconnect — reconnect now, don't wait
|
||||||
|
}
|
||||||
last := n.lastRx.Load()
|
last := n.lastRx.Load()
|
||||||
if last == 0 {
|
if last == 0 {
|
||||||
return true // just connected, nothing received yet — give it a chance
|
return true // just connected, nothing received yet — give it a chance
|
||||||
@@ -292,6 +300,7 @@ func (n *icomNet) ctrlPump() {
|
|||||||
n.ctrlResend(icnLE.Uint16(buf[6:]))
|
n.ctrlResend(icnLE.Uint16(buf[6:]))
|
||||||
}
|
}
|
||||||
case 0x05: // rig-initiated disconnect — it dropped US
|
case 0x05: // rig-initiated disconnect — it dropped US
|
||||||
|
n.dead.Store(true) // make Alive() fail now → prompt clean reconnect
|
||||||
debugLog.Printf("icom net: rig sent DISCONNECT on control stream — session dropped by the rig")
|
debugLog.Printf("icom net: rig sent DISCONNECT on control stream — session dropped by the rig")
|
||||||
default:
|
default:
|
||||||
// Anything else on the control stream is (almost always) the rig's
|
// Anything else on the control stream is (almost always) the rig's
|
||||||
@@ -367,6 +376,7 @@ func (n *icomNet) civPump() {
|
|||||||
n.resend(icnLE.Uint16(buf[6:]))
|
n.resend(icnLE.Uint16(buf[6:]))
|
||||||
}
|
}
|
||||||
case typ == 0x05: // rig-initiated disconnect — it dropped US
|
case typ == 0x05: // rig-initiated disconnect — it dropped US
|
||||||
|
n.dead.Store(true) // make Alive() fail now → prompt clean reconnect
|
||||||
debugLog.Printf("icom net: rig sent DISCONNECT on CI-V stream — session dropped by the rig")
|
debugLog.Printf("icom net: rig sent DISCONNECT on CI-V stream — session dropped by the rig")
|
||||||
case typ == 0x00 && k > 0x15 && buf[0x10] == 0xc1: // CI-V data
|
case typ == 0x00 && k > 0x15 && buf[0x10] == 0xc1: // CI-V data
|
||||||
n.trackRxSeq(icnLE.Uint16(buf[6:])) // note gaps for retransmit
|
n.trackRxSeq(icnLE.Uint16(buf[6:])) // note gaps for retransmit
|
||||||
|
|||||||
+17
-1
@@ -32,6 +32,7 @@ type OmniRig struct {
|
|||||||
omnirig *ole.IDispatch
|
omnirig *ole.IDispatch
|
||||||
rig *ole.IDispatch
|
rig *ole.IDispatch
|
||||||
lastSig string // last logged Split/VFO signature — only log on change
|
lastSig string // last logged Split/VFO signature — only log on change
|
||||||
|
rigType string // OmniRig's RigType string (the .ini title), e.g. "IC-7610"
|
||||||
|
|
||||||
// lastSetFreq is the frequency most recently COMMANDED via SetFrequency.
|
// lastSetFreq is the frequency most recently COMMANDED via SetFrequency.
|
||||||
// SetMode uses it to pick USB vs LSB for "SSB" instead of reading OmniRig's
|
// SetMode uses it to pick USB vs LSB for "SSB" instead of reading OmniRig's
|
||||||
@@ -80,11 +81,20 @@ func (o *OmniRig) Connect() error {
|
|||||||
o.rig = rigVar.ToIDispatch()
|
o.rig = rigVar.ToIDispatch()
|
||||||
|
|
||||||
if rt, err := oleutil.GetProperty(o.rig, "RigType"); err == nil {
|
if rt, err := oleutil.GetProperty(o.rig, "RigType"); err == nil {
|
||||||
debugLog.Printf("OmniRig connected to Rig%d type=%q", o.RigNum, rt.ToString())
|
o.rigType = rt.ToString()
|
||||||
|
debugLog.Printf("OmniRig connected to Rig%d type=%q", o.RigNum, o.rigType)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isIC7610 reports whether the connected rig is an IC-7610. OmniRig's generic
|
||||||
|
// Freq property reads the wrong VFO on the 7610 (its Main/Sub model confuses the
|
||||||
|
// stock ini), so we read VFO A explicitly for it instead — matching what Log4OM
|
||||||
|
// shows.
|
||||||
|
func (o *OmniRig) isIC7610() bool {
|
||||||
|
return strings.Contains(strings.ToUpper(o.rigType), "7610")
|
||||||
|
}
|
||||||
|
|
||||||
func (o *OmniRig) Disconnect() {
|
func (o *OmniRig) Disconnect() {
|
||||||
if o.rig != nil {
|
if o.rig != nil {
|
||||||
o.rig.Release()
|
o.rig.Release()
|
||||||
@@ -199,6 +209,12 @@ func (o *OmniRig) ReadState() (RigState, error) {
|
|||||||
s.Split = false
|
s.Split = false
|
||||||
s.RxFreqHz = 0
|
s.RxFreqHz = 0
|
||||||
s.FreqHz = freqMain
|
s.FreqHz = freqMain
|
||||||
|
// IC-7610 quirk: OmniRig's generic Freq reports VFO B (its Main/Sub model
|
||||||
|
// confuses the stock ini), so OpsLog showed the wrong VFO. Read VFO A
|
||||||
|
// explicitly for the 7610 — what the operator actually wants to see.
|
||||||
|
if o.isIC7610() && freqA != 0 {
|
||||||
|
s.FreqHz = freqA
|
||||||
|
}
|
||||||
if s.FreqHz == 0 {
|
if s.FreqHz == 0 {
|
||||||
if s.Vfo == "B" || s.Vfo == "BB" {
|
if s.Vfo == "B" || s.Vfo == "BB" {
|
||||||
s.FreqHz = freqB
|
s.FreqHz = freqB
|
||||||
|
|||||||
Reference in New Issue
Block a user