diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 813921d..6ad7ab0 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -44,6 +44,7 @@ import { GetUIPref, GetActiveProfile, QuitApp, ReportLiveActivity, LiveLastQSOAgeSec, GetPGXLSettings, GetPGXLStatus, GetSPEStatus, GetACOMStatus, SPESetOperate, ACOMSetOperate, PGXLSetOperate, + GetFlexState, FlexAmpOperate, } from '../wailsjs/go/main/App'; import { Combobox } from '@/components/ui/combobox'; import { applyAwardRefs } from '@/lib/awardRefs'; @@ -452,8 +453,26 @@ export default function App() { useEffect(() => { if (!ampCfg.enabled) { setAmpSt({ connected: false }); return; } let alive = true; - const get = ampCfg.type === 'pgxl' ? GetPGXLStatus : ampCfg.type.startsWith('acom') ? GetACOMStatus : GetSPEStatus; - const tick = () => get().then((s: any) => alive && setAmpSt(s || { connected: false })).catch(() => {}); + // PGXL: the Flex reports the amp's OPERATE state authoritatively (the direct + // GSCP status doesn't carry it), so merge GetFlexState in when a Flex sees + // the amp — state AND toggle then go through the radio; the direct TCP link + // remains the fallback (fan mode always uses it). + const tick = ampCfg.type === 'pgxl' + ? () => Promise.all([ + GetPGXLStatus().catch(() => ({ connected: false })), + GetFlexState().catch(() => null), + ]).then(([pg, fx]: any[]) => { + if (!alive) return; + const viaFlex = !!fx?.amp_available; + setAmpSt({ + ...(pg || {}), + connected: !!pg?.connected || viaFlex, + operate: viaFlex ? !!fx.amp_operate : !!pg?.operate, + via_flex: viaFlex, + }); + }) + : () => (ampCfg.type.startsWith('acom') ? GetACOMStatus : GetSPEStatus)() + .then((s: any) => alive && setAmpSt(s || { connected: false })).catch(() => {}); tick(); const id = window.setInterval(tick, 2000); return () => { alive = false; window.clearInterval(id); }; @@ -5160,7 +5179,7 @@ export default function App() { if (!ampSt.connected) { setSettingsSection('pgxl'); setShowSettings(true); return; } const want = !ampSt.operate; setAmpSt((s: any) => ({ ...s, operate: want })); - (isPGXL ? PGXLSetOperate(want) + (isPGXL ? (ampSt.via_flex ? FlexAmpOperate(want) : PGXLSetOperate(want)) : ampCfg.type.startsWith('acom') ? ACOMSetOperate(want) : SPESetOperate(want)).catch(() => {}); }; diff --git a/frontend/src/components/StationControlPanel.tsx b/frontend/src/components/StationControlPanel.tsx index d95d92f..f2e1656 100644 --- a/frontend/src/components/StationControlPanel.tsx +++ b/frontend/src/components/StationControlPanel.tsx @@ -13,7 +13,7 @@ import { GetRotatorHeading, RotatorGoTo, RotatorStop, GetUltrabeamStatus, SetUltrabeamDirection, UltrabeamRetract, MotorSetElement, MotorReadElements, ListDenkoviDevices, ListSerialPorts, TestStationDevice, - GetPGXLSettings, GetPGXLStatus, PGXLSetFanMode, PGXLSetOperate, + GetPGXLSettings, GetPGXLStatus, PGXLSetFanMode, PGXLSetOperate, GetFlexState, FlexAmpOperate, GetSPEStatus, SPESetOperate, SPESetPower, SPESetPowerLevel, GetACOMStatus, ACOMSetOperate, ACOMSetPower, } from '../../wailsjs/go/main/App'; @@ -259,8 +259,24 @@ function AmplifierWidget({ ampType, t }: { ampType: string; t: (k: string, v?: a const [st, setSt] = useState({ connected: false }); useEffect(() => { let alive = true; - const get = isPGXL ? GetPGXLStatus : isACOM ? GetACOMStatus : GetSPEStatus; - const tick = () => get().then((s: any) => alive && setSt(s || { connected: false })).catch(() => {}); + // PGXL: the Flex reports the amp's OPERATE state authoritatively (the direct + // GSCP status doesn't carry it) — merge it in when a Flex sees the amp. + const tick = isPGXL + ? () => Promise.all([ + GetPGXLStatus().catch(() => ({ connected: false })), + GetFlexState().catch(() => null), + ]).then(([pg, fx]: any[]) => { + if (!alive) return; + const viaFlex = !!fx?.amp_available; + setSt({ + ...(pg || {}), + connected: !!pg?.connected || viaFlex, + operate: viaFlex ? !!fx.amp_operate : !!pg?.operate, + via_flex: viaFlex, + }); + }) + : () => (isACOM ? GetACOMStatus : GetSPEStatus)() + .then((s: any) => alive && setSt(s || { connected: false })).catch(() => {}); tick(); const id = window.setInterval(tick, 1500); return () => { alive = false; window.clearInterval(id); }; @@ -285,7 +301,7 @@ function AmplifierWidget({ ampType, t }: { ampType: string; t: (k: string, v?: a {isPGXL ? (