up
This commit is contained in:
@@ -13,6 +13,7 @@ package winkeyer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -26,28 +27,28 @@ import (
|
||||
type Mode string
|
||||
|
||||
const (
|
||||
ModeIambicB Mode = "iambic_b"
|
||||
ModeIambicA Mode = "iambic_a"
|
||||
ModeUltimatic Mode = "ultimatic"
|
||||
ModeBug Mode = "bug"
|
||||
ModeIambicB Mode = "iambic_b"
|
||||
ModeIambicA Mode = "iambic_a"
|
||||
ModeUltimatic Mode = "ultimatic"
|
||||
ModeBug Mode = "bug"
|
||||
)
|
||||
|
||||
// Config is the keyer configuration the UI persists and applies on connect.
|
||||
type Config struct {
|
||||
Port string `json:"port"` // e.g. "COM6"
|
||||
Baud int `json:"baud"` // 1200 for WK2, also fine for WK3
|
||||
WPM int `json:"wpm"` // 5..99
|
||||
Weight int `json:"weight"` // 10..90, 50 = normal
|
||||
LeadInMs int `json:"lead_in_ms"` // PTT lead-in, 10 ms units sent to device
|
||||
TailMs int `json:"tail_ms"` // PTT tail
|
||||
Ratio int `json:"ratio"` // dah/dit ratio 33..66 (50 = 3:1)
|
||||
Farnsworth int `json:"farnsworth"` // Farnsworth WPM (0 = off)
|
||||
Sidetone int `json:"sidetone_hz"` // 0 = off; else target Hz (mapped to WK code)
|
||||
Mode Mode `json:"mode"` // paddle mode
|
||||
Swap bool `json:"swap"` // swap dit/dah paddles
|
||||
AutoSpace bool `json:"autospace"` // auto letter-space
|
||||
UsePTT bool `json:"use_ptt"` // key PTT (Key/PTT output)
|
||||
SerialEcho bool `json:"serial_echo"` // device echoes sent chars back to host
|
||||
Port string `json:"port"` // e.g. "COM6"
|
||||
Baud int `json:"baud"` // 1200 for WK2, also fine for WK3
|
||||
WPM int `json:"wpm"` // 5..99
|
||||
Weight int `json:"weight"` // 10..90, 50 = normal
|
||||
LeadInMs int `json:"lead_in_ms"` // PTT lead-in, 10 ms units sent to device
|
||||
TailMs int `json:"tail_ms"` // PTT tail
|
||||
Ratio int `json:"ratio"` // dah/dit ratio 33..66 (50 = 3:1)
|
||||
Farnsworth int `json:"farnsworth"` // Farnsworth WPM (0 = off)
|
||||
Sidetone int `json:"sidetone_hz"` // 0 = off; else target Hz (mapped to WK code)
|
||||
Mode Mode `json:"mode"` // paddle mode
|
||||
Swap bool `json:"swap"` // swap dit/dah paddles
|
||||
AutoSpace bool `json:"autospace"` // auto letter-space
|
||||
UsePTT bool `json:"use_ptt"` // key PTT (Key/PTT output)
|
||||
SerialEcho bool `json:"serial_echo"` // device echoes sent chars back to host
|
||||
}
|
||||
|
||||
func (c Config) normalised() Config {
|
||||
@@ -77,9 +78,9 @@ func (c Config) normalised() Config {
|
||||
// Status is pushed to the UI whenever the link state or keyer activity changes.
|
||||
type Status struct {
|
||||
Connected bool `json:"connected"`
|
||||
Busy bool `json:"busy"` // device is currently sending CW
|
||||
WPM int `json:"wpm"` // current speed (tracks the speed pot)
|
||||
Version int `json:"version"` // host firmware version byte
|
||||
Busy bool `json:"busy"` // device is currently sending CW
|
||||
WPM int `json:"wpm"` // current speed (tracks the speed pot)
|
||||
Version int `json:"version"` // host firmware version byte
|
||||
Port string `json:"port"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
@@ -177,11 +178,11 @@ func (m *Manager) Connect(cfg Config) error {
|
||||
// applyConfig pushes the keying parameters to the device.
|
||||
func (m *Manager) applyConfig(c Config) error {
|
||||
cmds := [][]byte{
|
||||
{0x0E, modeRegister(c)}, // set mode register (paddle mode, swap, autospace…)
|
||||
{0x02, byte(c.WPM)}, // set speed (WPM)
|
||||
{0x03, byte(c.Weight)}, // set weighting
|
||||
{0x0E, modeRegister(c)}, // set mode register (paddle mode, swap, autospace…)
|
||||
{0x02, byte(c.WPM)}, // set speed (WPM)
|
||||
{0x03, byte(c.Weight)}, // set weighting
|
||||
{0x04, byte(c.LeadInMs / 10), byte(c.TailMs / 10)}, // PTT lead-in / tail (10 ms units)
|
||||
{0x11, byte(c.Ratio)}, // set dit/dah ratio
|
||||
{0x11, byte(c.Ratio)}, // set dit/dah ratio
|
||||
}
|
||||
// Sidetone: <0x01 n>. Bit6 enables, low nibble selects the pitch divisor.
|
||||
cmds = append(cmds, []byte{0x01, sidetoneCode(c.Sidetone)})
|
||||
@@ -197,9 +198,11 @@ func (m *Manager) applyConfig(c Config) error {
|
||||
}
|
||||
|
||||
// modeRegister builds the WinKey mode-register byte (command 0x0E).
|
||||
// bits 1..0 : paddle mode (00 Iambic-B, 01 Iambic-A, 10 Ultimatic, 11 Bug)
|
||||
// bit 3 : paddle swap
|
||||
// bit 0/... : (autospace is bit 0 of a separate group on some firmwares)
|
||||
//
|
||||
// bits 1..0 : paddle mode (00 Iambic-B, 01 Iambic-A, 10 Ultimatic, 11 Bug)
|
||||
// bit 3 : paddle swap
|
||||
// bit 0/... : (autospace is bit 0 of a separate group on some firmwares)
|
||||
//
|
||||
// We keep to the widely-compatible WK2 layout.
|
||||
func modeRegister(c Config) byte {
|
||||
var b byte
|
||||
@@ -339,6 +342,14 @@ func (m *Manager) Disconnect() {
|
||||
// the echo of characters being sent. We track busy/idle and the speed pot.
|
||||
func (m *Manager) readLoop(p serial.Port, stop, done chan struct{}) {
|
||||
defer close(done)
|
||||
// A panic here (e.g. in a status/echo callback) would otherwise take down
|
||||
// the whole app — which showed up as a crash when logging a CW QSO while
|
||||
// the keyer was still streaming echo bytes. Recover, log, end the loop.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
applog.Printf("winkeyer: readLoop panic recovered: %v\n%s", r, debug.Stack())
|
||||
}
|
||||
}()
|
||||
buf := make([]byte, 64)
|
||||
for {
|
||||
select {
|
||||
|
||||
Reference in New Issue
Block a user