{spe.connected ? (spe.tx ? 'TX' : 'RX') : t('flxp.pgOffline')}
diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts
index 5225b79..99854e4 100644
--- a/frontend/wailsjs/go/main/App.d.ts
+++ b/frontend/wailsjs/go/main/App.d.ts
@@ -721,6 +721,10 @@ export function RunBackupNow():Promise;
export function SPESetOperate(arg1:boolean):Promise;
+export function SPESetPower(arg1:boolean):Promise;
+
+export function SPESetPowerLevel(arg1:string):Promise;
+
export function SaveADIFFile():Promise;
export function SaveADIFMonitor(arg1:main.ADIFMonitorConfig):Promise;
diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js
index ed793b9..3d080c4 100644
--- a/frontend/wailsjs/go/main/App.js
+++ b/frontend/wailsjs/go/main/App.js
@@ -1398,6 +1398,14 @@ export function SPESetOperate(arg1) {
return window['go']['main']['App']['SPESetOperate'](arg1);
}
+export function SPESetPower(arg1) {
+ return window['go']['main']['App']['SPESetPower'](arg1);
+}
+
+export function SPESetPowerLevel(arg1) {
+ return window['go']['main']['App']['SPESetPowerLevel'](arg1);
+}
+
export function SaveADIFFile() {
return window['go']['main']['App']['SaveADIFFile']();
}
diff --git a/internal/spe/spe.go b/internal/spe/spe.go
index 52133c9..9212816 100644
--- a/internal/spe/spe.go
+++ b/internal/spe/spe.go
@@ -30,9 +30,17 @@ import (
)
const (
- cmdOperate byte = 0x0D // toggles STANDBY ↔ OPERATE
+ cmdOperate byte = 0x0D // toggles STANDBY ↔ OPERATE (confirmed on hw)
cmdStatus byte = 0x90 // request the status string
+ // Best-guess keystroke codes reconstructed from the APG command table after
+ // correcting the PDF's note-wrap misalignment (anchored to the confirmed
+ // OPERATE=0x0D): OFF=0x0A, POWER=0x0B. The POWER key doubles as power-on (when
+ // the amp is off) and the output-level cycle L→M→H (when it's on) — same as the
+ // single physical POWER button. To be verified on hardware.
+ cmdOff byte = 0x0A // OFF key — switch the amplifier off
+ cmdPower byte = 0x0B // POWER key — turn on / cycle output power level
+
syncHost = 0x55
syncAmp = 0xAA
@@ -138,6 +146,34 @@ func (c *Client) Operate(on bool) error {
// ToggleOperate flips STANDBY/OPERATE unconditionally.
func (c *Client) ToggleOperate() error { return c.sendCmd(cmdOperate) }
+// PowerOn presses the POWER key (turns the amp on when it's off).
+func (c *Client) PowerOn() error { return c.sendCmd(cmdPower) }
+
+// PowerOff presses the OFF key (switches the amp off).
+func (c *Client) PowerOff() error { return c.sendCmd(cmdOff) }
+
+// SetPowerLevel cycles the output power level (L/M/H) to the requested one by
+// tapping the POWER key until the reported level matches, giving the amp time to
+// report each change. `level` is "L", "M" or "H" (case-insensitive).
+func (c *Client) SetPowerLevel(level string) error {
+ want := strings.ToUpper(strings.TrimSpace(level))
+ if want == "" {
+ return nil
+ }
+ // At most 3 taps to walk the 3-way cycle back around to the target.
+ for i := 0; i < 3; i++ {
+ cur := strings.ToUpper(strings.TrimSpace(c.GetStatus().PowerLevel))
+ if cur == want {
+ return nil
+ }
+ if err := c.sendCmd(cmdPower); err != nil {
+ return err
+ }
+ time.Sleep(1 * time.Second) // let the amp apply it and the poll refresh status
+ }
+ return nil
+}
+
func (c *Client) pollLoop() {
t := time.NewTicker(pollEvery)
defer t.Stop()