feat: serial-line CW keyer (DTR=CW / RTS=PTT) — SCU-17 / N1MM style
Adds a 4th CW keyer engine alongside K1EL WinKeyer, Icom CI-V and Flex CWX:
OpsLog bit-bangs the Morse itself on a serial control line (DTR keys CW, RTS
keys PTT — swappable), the hardware-keying method N1MM/WSJT use with a Yaesu
SCU-17 and generic interfaces. No WinKeyer chip needed.
- internal/winkeyer/serialcw.go: serialKeyer — worker goroutine, morse table,
WPM + Farnsworth timing (live speed changes), abortable, PTT lead-in/tail/hang.
- winkeyer.Config gains Type ("k1el"|"serial") + CWKeyLine ("dtr"|"rts");
Manager routes Connect/Send/Stop/SetSpeed/Backspace/Disconnect to it.
- app.go: keyWKCWLine setting; WinkeyerConnect sets Type from the engine.
- Settings -> CW Keyer: new "Serial port (DTR=CW/RTS=PTT)" engine with COM port,
key-line selector, speed/Farnsworth/lead-in/tail/PTT. Macros, auto-CQ and
<LOGQSO> reuse the WinKeyer path unchanged.
UNTESTED on hardware (no SCU-17 to hand): polarity assumes N1MM convention
(line HIGH = active). Weight not yet honoured; Farnsworth is.
This commit is contained in:
@@ -214,9 +214,10 @@ const (
|
||||
keyWKUsePTT = "winkeyer.use_ptt"
|
||||
keyWKSerialEcho = "winkeyer.serial_echo"
|
||||
keyWKMacros = "winkeyer.macros" // JSON array of {label,text}
|
||||
keyWKEngine = "winkeyer.engine" // "winkeyer" | "icom" | "tci"
|
||||
keyWKEngine = "winkeyer.engine" // "winkeyer" | "serial" | "icom" | "flex" | "tci"
|
||||
keyWKEscClears = "winkeyer.esc_clears_call" // ESC also clears the callsign
|
||||
keyWKSendOnType = "winkeyer.send_on_type" // key characters live as typed
|
||||
keyWKCWLine = "winkeyer.cw_key_line" // serial engine: "dtr" (CW) / "rts" (PTT) or swapped
|
||||
|
||||
keyClusterAutoConnect = "cluster.auto_connect" // open every enabled server at app start
|
||||
|
||||
@@ -13052,13 +13053,16 @@ func (a *App) GetWinkeyerSettings() (WinkeyerSettings, error) {
|
||||
keyWKEnabled, keyWKPort, keyWKBaud, keyWKWPM, keyWKWeight, keyWKLeadIn,
|
||||
keyWKTail, keyWKRatio, keyWKFarnsworth, keyWKSidetone, keyWKMode,
|
||||
keyWKSwap, keyWKAutoSpace, keyWKUsePTT, keyWKSerialEcho, keyWKMacros,
|
||||
keyWKEngine, keyWKEscClears, keyWKSendOnType)
|
||||
keyWKEngine, keyWKEscClears, keyWKSendOnType, keyWKCWLine)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
if v := m[keyWKEngine]; v != "" {
|
||||
out.Engine = v
|
||||
}
|
||||
if v := m[keyWKCWLine]; v != "" {
|
||||
out.CWKeyLine = v
|
||||
}
|
||||
if v := m[keyWKEscClears]; v != "" {
|
||||
out.EscClearsCall = v == "1"
|
||||
}
|
||||
@@ -13125,6 +13129,7 @@ func (a *App) SaveWinkeyerSettings(s WinkeyerSettings) error {
|
||||
keyWKEngine: strings.TrimSpace(s.Engine),
|
||||
keyWKEscClears: boolStr(s.EscClearsCall),
|
||||
keyWKSendOnType: boolStr(s.SendOnType),
|
||||
keyWKCWLine: strings.TrimSpace(s.CWKeyLine),
|
||||
} {
|
||||
if err := a.settings.Set(a.ctx, k, v); err != nil {
|
||||
return err
|
||||
@@ -13142,7 +13147,13 @@ func (a *App) WinkeyerConnect() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return a.winkeyer.Connect(s.Config)
|
||||
cfg := s.Config
|
||||
// The "serial" engine keys CW on the port's DTR/RTS lines (SCU-17 style)
|
||||
// instead of talking the K1EL WinKeyer protocol — flag it for the manager.
|
||||
if s.Engine == "serial" {
|
||||
cfg.Type = "serial"
|
||||
}
|
||||
return a.winkeyer.Connect(cfg)
|
||||
}
|
||||
|
||||
// WinkeyerDisconnect closes the serial link.
|
||||
|
||||
Reference in New Issue
Block a user