feat(cat): make the DTR/RTS lowering a setting

Both defaults break someone. 0.22.7 lowered the lines on Yaesu and
Kenwood and silenced a TS-990 whose interface needs RTS raised to
transmit; 0.22.8 stopped lowering them and an FT8 station reported its
output power wandering, cured by closing OpsLog — Windows raises both on
open and the interface reads one as PTT.

So it is now a checkbox on those two backends, off by default: that is
how they behaved before any of this. Xiegu keeps lowering them
unconditionally (its own report, its own explicit keying setting), and
the CI-V backend keeps the behaviour it has always had.
This commit is contained in:
2026-08-01 19:25:04 +02:00
parent 85bf0da006
commit 5777c119cb
7 changed files with 112 additions and 54 deletions
+26 -12
View File
@@ -88,6 +88,26 @@ type Kenwood struct {
// Kept only to put it in the error message: "not answering" and "answering
// something unreadable" are different faults with different fixes.
heard string
// lowerLines deasserts DTR and RTS after opening the port.
//
// Neither default is safe for everyone, which is why this is a setting and
// not a decision. Windows raises both lines on open: an interface that reads
// them as PTT then keys the rig for as long as OpsLog is running — reported
// as FT8 output power wandering, and gone the moment OpsLog was closed.
// Lowering them instead silences the radios whose USB-serial interface needs
// RTS asserted to transmit at all — a TS-990 that opened cleanly and answered
// nothing. Off by default: that is how this backend behaved for its whole
// life before the question came up.
lowerLines bool
}
// SetLowerLines chooses whether DTR and RTS are deasserted on connect. Set
// before Connect.
func (k *Kenwood) SetLowerLines(v bool) {
k.mu.Lock()
k.lowerLines = v
k.mu.Unlock()
}
// where names the link for a message, so an error does not read "COM @ 0 baud"
@@ -572,18 +592,12 @@ func (k *Kenwood) openPort() (serial.Port, error) {
if err != nil {
return nil, err
}
// The modem lines are LEFT ALONE.
//
// They were briefly deasserted here, to stop an interface that reads them as
// PTT from keying the rig on connect. That silenced radios instead: a TS-990
// on COM3 opened fine and answered nothing, because a great many USB-serial
// interfaces will not transmit with RTS low — hardware flow control, or an
// output stage the line enables. "Opened but the rig sent nothing" was this,
// and it arrived as "CAT stopped working after the update".
//
// The fault that change was written for was a Xiegu G90 behind a DE-19, and
// that backend now has an explicit setting for which line keys it. A rig
// whose PTT is a CAT command has no business touching DTR or RTS at all.
// The modem lines are only touched when the operator asks for it. See
// lowerLines: both defaults break somebody's station.
if k.lowerLines {
_ = p.SetDTR(false)
_ = p.SetRTS(false)
}
return p, nil
}
+20 -9
View File
@@ -82,9 +82,12 @@ var yaesuModeToADIF = map[byte]string{
}
type Yaesu struct {
portName string
baud int
digital string // ADIF mode reported for DATA (FT8, RTTY…)
// lowerLines deasserts DTR and RTS on connect — see Kenwood.lowerLines for
// why neither default is safe for every station.
lowerLines bool
portName string
baud int
digital string // ADIF mode reported for DATA (FT8, RTTY…)
mu sync.Mutex
port serial.Port
@@ -127,6 +130,14 @@ func NewYaesu(portName string, baud int, digital string) *Yaesu {
return &Yaesu{portName: strings.TrimSpace(portName), baud: baud, digital: digital, curVFO: "A"}
}
// SetLowerLines chooses whether DTR and RTS are deasserted on connect. Set
// before Connect.
func (y *Yaesu) SetLowerLines(v bool) {
y.mu.Lock()
y.lowerLines = v
y.mu.Unlock()
}
func (y *Yaesu) Name() string { return "yaesu" }
func (y *Yaesu) Connect() error {
@@ -150,12 +161,12 @@ func (y *Yaesu) Connect() error {
if err != nil {
return fmt.Errorf("yaesu: open %s @ %d baud: %w", y.portName, y.baud, err)
}
// The modem lines are LEFT ALONE — see the same note in kenwood.go.
//
// Deasserting them to keep an interface from keying the rig silenced radios
// instead: many USB-serial interfaces will not transmit with RTS low. The
// Xiegu fault that change was written for is handled in that backend, which
// now has an explicit setting for which line keys the rig.
// The modem lines are only touched when the operator asks for it — see the
// note on Kenwood.lowerLines. Both defaults break somebody's station.
if y.lowerLines {
_ = p.SetDTR(false)
_ = p.SetRTS(false)
}
p.SetReadTimeout(300 * time.Millisecond)
y.port = p