fix(pgxl): fan mode needs the "setup" prefix — "setup fanmode=VALUE"

Confirmed live: "setup fanmode=CONTEST" is accepted (reply code 0) while the
bare "fanmode=CONTEST" we switched to earlier is rejected (0x50000015), so the
fan mode snapped back and never changed on the amp. Restored the "setup " verb
and now check the reply code, returning an error if the amp rejects the set.
This commit is contained in:
2026-08-05 17:32:53 +02:00
parent 689d1cc902
commit fbd323af26
2 changed files with 27 additions and 7 deletions
+4 -2
View File
@@ -3,10 +3,12 @@
"version": "0.23.7",
"date": "",
"en": [
"QSO edit: added the QRZ ↗ button next to the callsign, like the main entry form — one click opens that station's qrz.com profile."
"QSO edit: added the QRZ ↗ button next to the callsign, like the main entry form — one click opens that station's qrz.com profile.",
"PowerGenius XL: the fan mode (Standard / Contest / Broadcast) changes on the amp again. A previous fix dropped the \"setup\" prefix the amp requires (\"setup fanmode=…\"), so the amp rejected the command and the mode snapped straight back. The correct command is restored."
],
"fr": [
"Édition de QSO : ajout du bouton QRZ ↗ à côté de l'indicatif, comme dans le formulaire de saisie — un clic ouvre le profil qrz.com de la station."
"Édition de QSO : ajout du bouton QRZ ↗ à côté de l'indicatif, comme dans le formulaire de saisie — un clic ouvre le profil qrz.com de la station.",
"PowerGenius XL : le mode ventilateur (Standard / Contest / Broadcast) change de nouveau sur l'ampli. Un correctif précédent avait retiré le préfixe « setup » exigé par l'ampli (« setup fanmode=… »), qui rejetait donc la commande et le mode revenait aussitôt en arrière. La bonne commande est rétablie."
]
},
{
+23 -5
View File
@@ -125,14 +125,19 @@ func (c *Client) SetFanMode(mode string) error {
default:
return fmt.Errorf("powergenius: invalid fan mode %q", mode)
}
// Set with the bare "key=value" verb the amp uses for its own status fields
// (same convention as "operate=1"). The earlier "setup fanmode=…" carried a
// bogus prefix the amp silently ignored, so the fan never changed and the next
// status kept reporting the old mode — the revert-to-Contest the operator saw.
reply, err := c.command("fanmode=" + m)
// The verb the amp wants is "setup fanmode=VALUE" — confirmed LIVE: with the
// "setup " prefix the amp replies code 0 (accepted), while the bare
// "fanmode=VALUE" we switched to earlier is rejected (reply code 0x50000015).
// That regression is what stopped the fan from changing; restoring "setup "
// fixes it.
reply, err := c.command("setup fanmode=" + m)
if err != nil {
return err
}
if code := replyCode(reply); code != "" && code != "0" {
applog.Printf("pgxl: set fanmode=%s REJECTED, reply=%q", m, reply)
return fmt.Errorf("powergenius: amp rejected fanmode=%s (code %s)", m, code)
}
applog.Printf("pgxl: set fanmode=%s reply=%q", m, reply)
c.statusMu.Lock()
c.status.FanMode = m // optimistic
@@ -141,6 +146,19 @@ func (c *Client) SetFanMode(mode string) error {
return nil
}
// replyCode returns the result code from an "R<id>|<code>|…" reply — "0" means
// the amp accepted the command. Returns "" when the line isn't an R reply.
func replyCode(reply string) string {
if !strings.HasPrefix(reply, "R") {
return ""
}
p := strings.SplitN(reply, "|", 3)
if len(p) < 2 {
return ""
}
return strings.TrimSpace(p[1])
}
// SetOperate puts the amp in OPERATE (1) or STANDBY (0).
func (c *Client) SetOperate(on bool) error {
v := "0"