feat: Support for Power Genius XL
This commit is contained in:
@@ -41,6 +41,7 @@ import (
|
||||
"hamlog/internal/rotator/pst"
|
||||
"hamlog/internal/settings"
|
||||
"hamlog/internal/antgenius"
|
||||
"hamlog/internal/powergenius"
|
||||
"hamlog/internal/ultrabeam"
|
||||
"hamlog/internal/winkeyer"
|
||||
|
||||
@@ -146,6 +147,11 @@ const (
|
||||
keyAntGeniusEnabled = "antgenius.enabled"
|
||||
keyAntGeniusHost = "antgenius.host"
|
||||
|
||||
// PowerGenius XL (4O3A) amplifier fan-mode control — Hardware → PowerGenius.
|
||||
keyPGXLEnabled = "pgxl.enabled"
|
||||
keyPGXLHost = "pgxl.host"
|
||||
keyPGXLPort = "pgxl.port"
|
||||
|
||||
// WinKeyer CW keyer (serial) — Hardware → CW Keyer.
|
||||
keyWKEnabled = "winkeyer.enabled"
|
||||
keyWKPort = "winkeyer.port"
|
||||
@@ -389,7 +395,8 @@ type App struct {
|
||||
clublog *clublog.Manager
|
||||
ultrabeam *ultrabeam.Client // Ultrabeam antenna (TCP); nil when disabled
|
||||
ubFollowStop chan struct{} // stops the "follow frequency" loop; nil when off
|
||||
antgenius *antgenius.Client // Antenna Genius (4O3A) switch (TCP); nil when disabled
|
||||
antgenius *antgenius.Client // Antenna Genius (4O3A) switch (TCP); nil when disabled
|
||||
pgxl *powergenius.Client // PowerGenius XL (4O3A) amp fan control (TCP); nil when disabled
|
||||
audioMgr *audio.Manager
|
||||
qsoRec *audio.Recorder // continuous QSO recorder (rolling pre-roll)
|
||||
cwMu sync.Mutex // guards the CW decoder lifecycle
|
||||
@@ -824,6 +831,8 @@ func (a *App) startup(ctx context.Context) {
|
||||
a.startUltrabeam()
|
||||
// Antenna Genius switch: connect in the background if enabled.
|
||||
a.startAntGenius()
|
||||
// PowerGenius XL amp fan control: connect in the background if enabled.
|
||||
a.startPGXL()
|
||||
|
||||
// Autostart: launch the active profile's configured external programs that
|
||||
// aren't already running (WSJT-X, JTAlert, rotator control, …). Background
|
||||
@@ -7923,6 +7932,82 @@ func (a *App) AntGeniusDeselect(port int) error {
|
||||
return a.antgenius.Activate(port, 0)
|
||||
}
|
||||
|
||||
// ── PowerGenius XL (4O3A) amplifier fan control (TCP, default port 9006) ─────
|
||||
|
||||
// PGXLSettings is the JSON shape for the Hardware → PowerGenius panel.
|
||||
type PGXLSettings struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
}
|
||||
|
||||
func (a *App) GetPGXLSettings() (PGXLSettings, error) {
|
||||
out := PGXLSettings{Port: 9006}
|
||||
if a.settings == nil {
|
||||
return out, fmt.Errorf("db not initialized")
|
||||
}
|
||||
m, err := a.settings.GetMany(a.ctx, keyPGXLEnabled, keyPGXLHost, keyPGXLPort)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.Enabled = m[keyPGXLEnabled] == "1"
|
||||
out.Host = m[keyPGXLHost]
|
||||
if p, _ := strconv.Atoi(m[keyPGXLPort]); p > 0 && p <= 65535 {
|
||||
out.Port = p
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (a *App) SavePGXLSettings(s PGXLSettings) error {
|
||||
if a.settings == nil {
|
||||
return fmt.Errorf("db not initialized")
|
||||
}
|
||||
if s.Port <= 0 || s.Port > 65535 {
|
||||
s.Port = 9006
|
||||
}
|
||||
for k, v := range map[string]string{
|
||||
keyPGXLEnabled: boolStr(s.Enabled),
|
||||
keyPGXLHost: strings.TrimSpace(s.Host),
|
||||
keyPGXLPort: strconv.Itoa(s.Port),
|
||||
} {
|
||||
if err := a.settings.Set(a.ctx, k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
a.startPGXL()
|
||||
return nil
|
||||
}
|
||||
|
||||
// startPGXL stops any existing client and starts a fresh one if enabled.
|
||||
func (a *App) startPGXL() {
|
||||
if a.pgxl != nil {
|
||||
a.pgxl.Stop()
|
||||
a.pgxl = nil
|
||||
}
|
||||
s, err := a.GetPGXLSettings()
|
||||
if err != nil || !s.Enabled || strings.TrimSpace(s.Host) == "" {
|
||||
return
|
||||
}
|
||||
a.pgxl = powergenius.New(s.Host, s.Port)
|
||||
_ = a.pgxl.Start()
|
||||
}
|
||||
|
||||
// GetPGXLStatus returns the amp's fan/connection state for the UI poll.
|
||||
func (a *App) GetPGXLStatus() powergenius.Status {
|
||||
if a.pgxl == nil {
|
||||
return powergenius.Status{}
|
||||
}
|
||||
return a.pgxl.GetStatus()
|
||||
}
|
||||
|
||||
// PGXLSetFanMode sets the amplifier fan mode (STANDARD | CONTEST | BROADCAST).
|
||||
func (a *App) PGXLSetFanMode(mode string) error {
|
||||
if a.pgxl == nil {
|
||||
return fmt.Errorf("PowerGenius not connected — enable it in Settings → PowerGenius")
|
||||
}
|
||||
return a.pgxl.SetFanMode(mode)
|
||||
}
|
||||
|
||||
// --- WinKeyer (CW keyer) bindings ---
|
||||
|
||||
// WKMacro is one CW message slot (F1…): a short label + the macro text, which
|
||||
|
||||
Reference in New Issue
Block a user