diff --git a/app.go b/app.go index 7556767..3cc99af 100644 --- a/app.go +++ b/app.go @@ -5844,8 +5844,20 @@ func (a *App) TestPTT(cfg AudioSettings) error { if err := a.pttKey(cfg); err != nil { return err } + // Hold long enough to be observable. OmniRig is async and coalesces rapid + // writes to the same parameter: it stores the desired Tx value and flushes + // on its own poll timer, so a key (PM_TX) followed too quickly by an unkey + // (PM_RX) can land in ONE flush cycle — OmniRig then sends only the last + // value (PM_RX) and the rig never actually transmits (while an already-MOX'd + // rig gets dropped by that lone PM_RX). A longer hold guarantees the key + // command is sent and held before the release. Serial RTS/DTR is instant, + // so it keeps the short window. + hold := 600 * time.Millisecond + if cfg.PTTMethod == "cat" { + hold = 1500 * time.Millisecond + } gen := a.pttGenNow() - go func() { time.Sleep(600 * time.Millisecond); a.unkeyIfCurrent(gen) }() + go func() { time.Sleep(hold); a.unkeyIfCurrent(gen) }() return nil } diff --git a/internal/cat/omnirig.go b/internal/cat/omnirig.go index 14745ee..2046934 100644 --- a/internal/cat/omnirig.go +++ b/internal/cat/omnirig.go @@ -414,6 +414,16 @@ func (o *OmniRig) SetPTT(on bool) error { debugLog.Printf("OmniRig.SetPTT error: %v", err) return fmt.Errorf("set Tx=%s: %w", name, err) } + // Read the Tx param straight back. OmniRig is async — this may still show the + // previous value for a poll cycle — but if a key/unkey NEVER changes it, the + // write was coalesced or the rig isn't honouring PM_TX/PM_RX (wrong .ini). + if v, err := oleutil.GetProperty(o.rig, "Tx"); err == nil { + txState := "PM_RX" + if v.Val&pmTX != 0 { + txState = "PM_TX" + } + debugLog.Printf("OmniRig.SetPTT: Tx readback = 0x%X (%s)", v.Val, txState) + } return nil }