feat(omnirig): say which of its two CW bits means CW on this rig

Reported on an IC-7610 shared through OmniRig: clicking a CW spot put
the radio in CW-R every time, and the only way out was to edit the
OmniRig rig file by hand.

OmniRig's model has two CW modes, PM_CW_U and PM_CW_L, and nothing in it
says which one an .ini calls plain CW. Icom rig files disagree with each
other — on some PM_CW_U is CI-V mode 0x03 (CW), on others 0x07 (CW-R) —
so asking for "CW" is a question with two right answers and OpsLog was
only ever giving one of them.

Settings ▸ CAT ▸ OmniRig now carries the answer for THIS rig, and it is
pushed to a radio that is already connected rather than waiting for a
reconnect: which bit a mode maps to is not worth dropping the link, and
with it WSJT-X's rigctl session. Same shape as the Yaesu RTTY sideband,
for the same reason.

Nothing changes for anyone whose rig file already agrees with us.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
2026-09-08 12:05:31 +02:00
co-authored by Claude Opus 5
parent 82cd5c5d0b
commit f8f8de4a30
8 changed files with 80 additions and 14 deletions
+24 -3
View File
@@ -36,6 +36,14 @@ type OmniRig struct {
// on the main VFO) and read B — the frequency "never followed the knob",
// while it was following the other one all along.
ForceVFO string
// CWLower sends PM_CW_L rather than PM_CW_U when asked for CW.
//
// OmniRig has two CW modes and nothing says which one an .ini file calls
// plain CW. Icom rig files disagree: on some PM_CW_U is CI-V mode 0x03 (CW),
// on others it is 0x07 (CW-R). An operator clicking a CW spot on an IC-7610
// landed in CW-R every time and had to edit the rig file to get out of it.
// This is the setting that means he does not have to.
CWLower bool
omnirig *ole.IDispatch
rig *ole.IDispatch
@@ -76,7 +84,7 @@ type OmniRig struct {
// NewOmniRig creates a non-connected backend. Call Connect before use.
// NewOmniRig builds the backend. forceVFO is "" to follow whatever the rig file
// reports, or "A"/"B" to override it — see the ForceVFO field.
func NewOmniRig(rigNum int, forceVFO string) *OmniRig {
func NewOmniRig(rigNum int, forceVFO string, cwLower bool) *OmniRig {
if rigNum < 1 || rigNum > 2 {
rigNum = 1
}
@@ -84,7 +92,7 @@ func NewOmniRig(rigNum int, forceVFO string) *OmniRig {
if v != "A" && v != "B" {
v = ""
}
return &OmniRig{RigNum: rigNum, ForceVFO: v}
return &OmniRig{RigNum: rigNum, ForceVFO: v, CWLower: cwLower}
}
func (o *OmniRig) Name() string { return "omnirig" }
@@ -602,6 +610,13 @@ func (o *OmniRig) SetFrequency(hz int64) error {
return nil
}
// SetCWLower chooses which of OmniRig's two CW bits means plain CW.
//
// Applied to the RUNNING backend, because the CAT link does not depend on it:
// dropping the rig — and with it WSJT-X's rigctl session — to change which bit
// a mode maps to would cost far more than it fixes.
func (o *OmniRig) SetCWLower(on bool) { o.CWLower = on }
// SetMode maps an ADIF mode to the OmniRig PM_* bit and pushes it to the rig.
// For SSB, the USB/LSB side is chosen from the rig's current frequency
// following worldwide convention (LSB below 14 MHz, USB above).
@@ -625,7 +640,13 @@ func (o *OmniRig) SetMode(mode string) error {
)
switch strings.ToUpper(strings.TrimSpace(mode)) {
case "CW":
bit, bitName = pmCWU, "PM_CW_U"
// Which bit means plain CW is a property of the RIG FILE, not of CW —
// see the CWLower field.
if o.CWLower {
bit, bitName = pmCWL, "PM_CW_L"
} else {
bit, bitName = pmCWU, "PM_CW_U"
}
case "SSB":
// Decide USB vs LSB from the frequency. Prefer the freq we just COMMANDED
// (a clicked spot sets freq then mode ~150ms later): OmniRig's Freq