Both are the same bug. ReadState returns early while transmitting — the rig answers '?;' to IF; then, and treating that as a fault used to drop the link — but that early return also skipped the panel update and the meter read. So the panel believed the radio was still receiving. Pressing MOX again therefore sent ANOTHER transmit command instead of RX, and the K3 stayed keyed, exactly as reported. And the power and SWR bars were only ever read at the one moment they mean nothing. Reading meters while transmitting needs one more guard: a '?;' then says when the question was asked, not what the radio supports, so the unsupported-command memory is suspended for that read. Without it, one badly timed refusal would silence a meter for the rest of the session. Adds RIT/XIT offset control (±10/±100 Hz, offset shown), a 4.0 kHz filter button for FT8, and logs the K3's icon word when it changes: there is no command for 'is the ATU in line', the reference says the switch functions show up as icon changes, so an operator toggling the ATU while watching the log will name the bit and the button can then light up honestly.
121 lines
4.3 KiB
Go
121 lines
4.3 KiB
Go
package main
|
|
|
|
// Elecraft K3/K4 panel bindings.
|
|
//
|
|
// The controls the operator asked for and nothing else: power, volume, the
|
|
// S-meter and SWR, MOX, and an ATU tune. A K3 exposes dozens of commands, but a
|
|
// panel earns its place by covering what is reached for during a QSO — and each
|
|
// one added without a radio to test it against is a control that may or may not
|
|
// do what its label says. See internal/cat/kenwood_panel.go.
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"hamlog/internal/cat"
|
|
)
|
|
|
|
// GetKenwoodState returns the K3/K4 panel snapshot. Zero value when the active
|
|
// CAT backend is something else, which is how the UI knows to hide the panel.
|
|
func (a *App) GetKenwoodState() cat.KenwoodTXState {
|
|
if a.cat == nil {
|
|
return cat.KenwoodTXState{}
|
|
}
|
|
st, _ := a.cat.KenwoodState()
|
|
return st
|
|
}
|
|
|
|
func (a *App) SetKenwoodPower(w int) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodPower(w) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodAFGain(p int) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodAFGain(p) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodRFGain(p int) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodRFGain(p) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodMicGain(p int) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodMicGain(p) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodSquelch(p int) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodSquelch(p) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodPreamp(on bool) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodPreamp(on) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodAtt(on bool) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodAtt(on) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodNB(on bool) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodNB(on) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodNR(on bool) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodNR(on) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodAGC(name string) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodAGC(name) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodFilter(hz int) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodFilter(hz) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodAntenna(n int) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodAntenna(n) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodRIT(on bool) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodRIT(on) })
|
|
}
|
|
|
|
func (a *App) SetKenwoodXIT(on bool) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodXIT(on) })
|
|
}
|
|
|
|
// NudgeKenwoodRIT moves the RIT/XIT offset by delta Hz.
|
|
func (a *App) NudgeKenwoodRIT(delta int) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.NudgeKenwoodRIT(delta) })
|
|
}
|
|
|
|
// ClearKenwoodRIT zeroes the RIT and XIT offsets together, which is what the
|
|
// radio's own RC does and what an operator means by "clear it".
|
|
func (a *App) ClearKenwoodRIT() error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.ClearKenwoodRIT() })
|
|
}
|
|
|
|
// SetKenwoodTX is the panel's MOX.
|
|
func (a *App) SetKenwoodTX(on bool) error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.SetKenwoodTX(on) })
|
|
}
|
|
|
|
// ToggleKenwoodATU puts the tuner in line or bypasses it (the HOLD of the same
|
|
// front-panel switch the tune uses).
|
|
func (a *App) ToggleKenwoodATU() error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.ToggleKenwoodATU() })
|
|
}
|
|
|
|
func (a *App) TuneKenwoodATU() error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.TuneKenwoodATU() })
|
|
}
|
|
|
|
// RefreshKenwood re-reads the settings on the next poll — for when a knob was
|
|
// turned on the radio itself.
|
|
func (a *App) RefreshKenwood() error {
|
|
return a.kenwoodPanelDo(func(k cat.KenwoodPanelController) error { return k.RefreshKenwood() })
|
|
}
|
|
|
|
func (a *App) kenwoodPanelDo(fn func(cat.KenwoodPanelController) error) error {
|
|
if a.cat == nil {
|
|
return fmt.Errorf("CAT not initialized")
|
|
}
|
|
return a.cat.KenwoodPanelDo(fn)
|
|
}
|