diff --git a/OpsLog-res.syso b/OpsLog-res.syso deleted file mode 100644 index 79a0989..0000000 Binary files a/OpsLog-res.syso and /dev/null differ diff --git a/app.go b/app.go index 31a16ce..88aa9ef 100644 --- a/app.go +++ b/app.go @@ -7698,7 +7698,9 @@ func (a *App) startUltrabeam() { a.ubFollowStop = nil } if a.ultrabeam != nil { - a.ultrabeam.Stop() + // Background teardown so saving Settings doesn't block on an in-progress + // connect (Stop waits for the dial timeout). + go a.ultrabeam.Stop() a.ultrabeam = nil } s, err := a.GetUltrabeamSettings() @@ -7896,7 +7898,9 @@ func (a *App) SaveAntGeniusSettings(s AntGeniusSettings) error { // startAntGenius stops any existing client and starts a fresh one if enabled. func (a *App) startAntGenius() { if a.antgenius != nil { - a.antgenius.Stop() + // Background teardown so saving Settings doesn't block on an in-progress + // connect (Stop waits for the dial timeout). + go a.antgenius.Stop() a.antgenius = nil } s, err := a.GetAntGeniusSettings() @@ -7932,7 +7936,7 @@ func (a *App) AntGeniusDeselect(port int) error { return a.antgenius.Activate(port, 0) } -// ── PowerGenius XL (4O3A) amplifier fan control (TCP, default port 9006) ───── +// ── PowerGenius XL (4O3A) amplifier fan control (TCP, default port 9008) ───── // PGXLSettings is the JSON shape for the Hardware → PowerGenius panel. type PGXLSettings struct { @@ -7942,7 +7946,7 @@ type PGXLSettings struct { } func (a *App) GetPGXLSettings() (PGXLSettings, error) { - out := PGXLSettings{Port: 9006} + out := PGXLSettings{Port: 9008} if a.settings == nil { return out, fmt.Errorf("db not initialized") } @@ -7963,7 +7967,7 @@ func (a *App) SavePGXLSettings(s PGXLSettings) error { return fmt.Errorf("db not initialized") } if s.Port <= 0 || s.Port > 65535 { - s.Port = 9006 + s.Port = 9008 } for k, v := range map[string]string{ keyPGXLEnabled: boolStr(s.Enabled), @@ -7981,7 +7985,10 @@ func (a *App) SavePGXLSettings(s PGXLSettings) error { // startPGXL stops any existing client and starts a fresh one if enabled. func (a *App) startPGXL() { if a.pgxl != nil { - a.pgxl.Stop() + // Stop() can block up to the dial timeout waiting for an in-progress + // connect; tear down in the background so saving Settings (this runs on + // the Wails RPC goroutine) doesn't freeze the UI. + go a.pgxl.Stop() a.pgxl = nil } s, err := a.GetPGXLSettings() diff --git a/frontend/src/components/FlexPanel.tsx b/frontend/src/components/FlexPanel.tsx index f5c7caa..38420b4 100644 --- a/frontend/src/components/FlexPanel.tsx +++ b/frontend/src/components/FlexPanel.tsx @@ -217,7 +217,7 @@ export function FlexPanel() { }, []); // PowerGenius XL direct connection (fan mode), independent of the Flex link. - const [pg, setPg] = useState<{ connected: boolean; fan_mode?: string }>({ connected: false }); + const [pg, setPg] = useState<{ connected: boolean; fan_mode?: string; host?: string; last_error?: string }>({ connected: false }); useEffect(() => { let alive = true; const tick = async () => { try { const s: any = await GetPGXLStatus(); if (alive) setPg(s || { connected: false }); } catch {} }; @@ -441,15 +441,18 @@ export function FlexPanel() { {st.amp_operate ? 'Amplifier is in line (transmitting through PA).' : 'Amplifier bypassed (standby).'} - {/* Fan mode — only when the PowerGenius direct connection is up - (configured in Settings → PowerGenius). */} - {pg.connected && ( - + {/* Fan mode — shown when the PowerGenius is configured (Settings → + PowerGenius). The dot shows the direct-connection state; the + selector is disabled until connected (hover it for the error). */} + {(pg.host || pg.connected) && ( + + Fan { const v = e.target.value; setPg((s) => ({ ...s, fan_mode: v })); PGXLSetFanMode(v).catch(() => {}); }} - className="h-8 rounded-md border border-orange-300 bg-card px-2 text-xs font-semibold text-orange-800 outline-none focus:border-orange-500" + className="h-8 rounded-md border border-orange-300 bg-card px-2 text-xs font-semibold text-orange-800 outline-none focus:border-orange-500 disabled:opacity-40" > Standard Contest diff --git a/frontend/src/components/SettingsModal.tsx b/frontend/src/components/SettingsModal.tsx index cdc9906..24ecea6 100644 --- a/frontend/src/components/SettingsModal.tsx +++ b/frontend/src/components/SettingsModal.tsx @@ -639,7 +639,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan const [antgenius, setAntgenius] = useState<{ enabled: boolean; host: string }>({ enabled: false, host: '' }); // PowerGenius XL (4O3A) amp fan-control settings. - const [pgxl, setPgxl] = useState<{ enabled: boolean; host: string; port: number }>({ enabled: false, host: '', port: 9006 }); + const [pgxl, setPgxl] = useState<{ enabled: boolean; host: string; port: number }>({ enabled: false, host: '', port: 9008 }); // WinKeyer CW keyer settings + macro editor. type WKMac = { label: string; text: string }; @@ -1962,7 +1962,6 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan <> @@ -2024,9 +2023,6 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan {ubTest.msg} )} - - Once enabled, the antenna's direction control (Normal / 180° / Bidirectional) appears in the bottom status bar, next to CAT and Rotator. Changing the direction re-tunes the elements at the current frequency. - > ); @@ -2052,11 +2048,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan placeholder="192.168.1.60" className="font-mono" /> - TCP port is fixed at 9007. - - Once enabled, an Antenna Genius button appears in the top bar to show/hide the antenna-switch widget. In the widget, the A and B buttons select that antenna for the matching port; clicking an already-selected port deselects it (sets the port to None). - > ); @@ -2088,14 +2080,11 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan setPgxl((s) => ({ ...s, port: parseInt(e.target.value) || 9006 }))} + onChange={(e) => setPgxl((s) => ({ ...s, port: parseInt(e.target.value) || 9008 }))} className="font-mono" /> - - Default port is 9006. Once enabled, a fan-mode dropdown (Standard / Contest / Broadcast) appears next to the amplifier Operate button in the FlexRadio tab. - > ); @@ -2179,7 +2168,6 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan <> diff --git a/internal/cat/flex.go b/internal/cat/flex.go index 2c4b517..f1aafac 100644 --- a/internal/cat/flex.go +++ b/internal/cat/flex.go @@ -339,7 +339,10 @@ func (f *Flex) handleStatus(payload string) { // Transmit object — RF/tune power, VOX, speech processor, monitor, mic, // tune carrier. Field names per the SmartSDR API (logged so the exact set // is auditable against a real radio). - if len(fields) >= 1 && fields[0] == "transmit" { + // "transmit band band_name=… rfpower=…" lines are PER-BAND power + // presets, not the current TX state — ignore them, otherwise the last + // band's rfpower (e.g. 630m=100) clobbers the real current value. + if len(fields) >= 1 && fields[0] == "transmit" && !(len(fields) >= 2 && fields[1] == "band") { if !f.txRawLogged { f.txRawLogged = true debugLog.Printf("Flex: FIRST transmit status: %s", payload) diff --git a/internal/powergenius/powergenius.go b/internal/powergenius/powergenius.go index 4155667..f2907b2 100644 --- a/internal/powergenius/powergenius.go +++ b/internal/powergenius/powergenius.go @@ -18,7 +18,7 @@ import ( ) const ( - defaultPort = 9006 + defaultPort = 9008 dialTimeout = 5 * time.Second ioTimeout = 3 * time.Second pollEvery = 1500 * time.Millisecond
- Once enabled, the antenna's direction control (Normal / 180° / Bidirectional) appears in the bottom status bar, next to CAT and Rotator. Changing the direction re-tunes the elements at the current frequency. -
TCP port is fixed at 9007.
- Once enabled, an Antenna Genius button appears in the top bar to show/hide the antenna-switch widget. In the widget, the A and B buttons select that antenna for the matching port; clicking an already-selected port deselects it (sets the port to None). -
- Default port is 9006. Once enabled, a fan-mode dropdown (Standard / Contest / Broadcast) appears next to the amplifier Operate button in the FlexRadio tab. -