fix: serial CAT keyed the radio on connect; Xiegu can key on RTS/DTR

Reported on a Xiegu G90. With the blue programming cable — three wires, no
modem lines — CAT works perfectly. Behind a DE-19, which carries audio, CAT and
PTT, the radio went into transmit the moment OpsLog connected and stayed there.

Windows raises DTR and RTS when a serial port is opened, and the DE-19 reads
them as PTT; Xiegu's own documentation asks for both low. The CI-V backend has
dropped them since it was written, for the same reason on Icom rigs with USB
SEND mapped to a line. Xiegu, Yaesu and Kenwood did not. They do now.

The second half of the report: WSJT-X through OpsLog's rigctld decoded fine and
never transmitted. Nothing was broken in that chain — set_ptt reaches the
backend, which sends the CI-V PTT command, which a G90 ignores. That is why
Xiegu keys on a hardware line instead. The backend can now do that: Settings →
CAT → Xiegu → how the rig is keyed (CI-V / RTS / DTR).

Untested here — no G90 in reach. The operator who reported it offered to try.
This commit is contained in:
2026-07-31 22:16:03 +02:00
parent 258fa717f1
commit d4bfd30636
8 changed files with 112 additions and 6 deletions
+19 -1
View File
@@ -492,7 +492,25 @@ func (k *Kenwood) openPort() (serial.Port, error) {
}
return &tcpSerial{conn: c}, nil
}
return serial.Open(k.portName, &serial.Mode{BaudRate: k.baud})
p, err := serial.Open(k.portName, &serial.Mode{BaudRate: k.baud})
if err != nil {
return nil, err
}
// Deassert DTR and RTS.
//
// Windows raises both when a serial port is opened, and a great many
// interfaces read them as PTT: a Xiegu G90 behind a DE-19 goes into
// transmit the moment OpsLog connects and STAYS there — Xiegu's own
// documentation asks for RTS and DTR low. The same applies to an Icom with
// USB SEND mapped to a line (which is why the CI-V backend has done this
// from the start) and to any rig keyed by a home-made cable.
//
// PTT on this backend is a CAT command, so neither line should ever be
// asserted here. A station keying by RTS/DTR configures that separately,
// on its own port.
_ = p.SetDTR(false)
_ = p.SetRTS(false)
return p, nil
}
// tcpSerial presents a TCP connection as a serial.Port, so the backend has one