fix: serial CW keyer PTT dropping between words on CP210x (SCU-17)

Confirmed from HB9HBY's log: ptt=true, yet the FT-891 dropped to RX between
words during a CQ macro — while the same SCU-17 works in N1MM. Root cause:
go.bug.st/serial drives DTR/RTS through GetCommState/SetCommState, which on the
SCU-17's Silicon Labs CP210x drops the asserted RTS (PTT) the moment DTR (CW)
is toggled. N1MM/WSJT use EscapeCommFunction, which sets one line without
disturbing the other.

OpsLog now drives the lines the same way: a new lineCtl abstraction with a
Windows implementation (linectl_windows.go) that opens the COM port via
CreateFile and toggles DTR/RTS with windows.EscapeCommFunction (SETDTR/CLRDTR/
SETRTS/CLRRTS). linectl_other.go keeps go.bug.st/serial for non-Windows builds.
The serial keyer holds a lineCtl instead of a serial.Port. RTS (PTT) now stays
asserted for the whole macro, so the rig holds TX between words.

Promotes golang.org/x/sys to a direct dependency.
This commit is contained in:
2026-07-23 21:35:59 +02:00
parent 89584f173d
commit aa871a07b7
5 changed files with 150 additions and 24 deletions
+37
View File
@@ -0,0 +1,37 @@
//go:build !windows
package winkeyer
// linectl_other.go — non-Windows DTR/RTS line control via go.bug.st/serial. On
// Linux/macOS the SetDTR/SetRTS ioctls control the lines independently, so the
// CP210x-on-Windows problem that motivated the native path (see linectl_windows.go)
// doesn't apply. OpsLog ships on Windows; this keeps the package building elsewhere.
import (
"fmt"
"strings"
"go.bug.st/serial"
)
type serialLineCtl struct {
port serial.Port
}
func openLineCtl(port string) (lineCtl, error) {
if strings.TrimSpace(port) == "" {
return nil, fmt.Errorf("no serial port")
}
p, err := serial.Open(port, &serial.Mode{BaudRate: 9600, DataBits: 8, Parity: serial.NoParity, StopBits: serial.OneStopBit})
if err != nil {
return nil, fmt.Errorf("open %s: %w", port, err)
}
c := &serialLineCtl{port: p}
_ = c.setDTR(false)
_ = c.setRTS(false)
return c, nil
}
func (c *serialLineCtl) setDTR(on bool) error { return c.port.SetDTR(on) }
func (c *serialLineCtl) setRTS(on bool) error { return c.port.SetRTS(on) }
func (c *serialLineCtl) close() error { return c.port.Close() }