feat: FlexRadio TX power per band and mode class
Settings → FlexRadio, beside the per-band antennas and applied the same way: when the band or the mode changes. 1.5 kW that is fine on SSB has no business going into an FT8 signal on the same band. Three classes rather than one row per mode, because what decides the power is duty cycle and what the amplifier will take of it, not the mode's name — FT8 and RTTY punish an amplifier the same way, SSB and AM do not. The classification is pinned by a test: a digital mode sorted as phone would deliver exactly the 1.5 kW this exists to prevent. An empty box means "leave the power alone", never zero watts, and an unknown mode changes nothing — setting a transmit power from a name we do not recognise is not a good guess. Unlike the antennas, a locked band does not skip it: the lock means "do not let the rig drag my log entry around", not "let the amplifier keep whatever the last mode left".
This commit is contained in:
@@ -47,7 +47,7 @@ import {
|
||||
DownloadULSCounties, ULSStatus, BackfillUSCounties,
|
||||
ComputeStationInfo,
|
||||
GetUIPref, SetUIPref,
|
||||
GetFlexState, GetFlexBandAntennas, SaveFlexBandAntennas,
|
||||
GetFlexState, GetFlexBandAntennas, SaveFlexBandAntennas, GetFlexBandPower, SaveFlexBandPower,
|
||||
GetADIFMonitor, SaveADIFMonitor, PickADIFMonitorFile,
|
||||
GetRelayAuto, SaveRelayAuto, GetStationDevices,
|
||||
} from '../../wailsjs/go/main/App';
|
||||
@@ -953,6 +953,79 @@ function ComingSoon({ id, icon: Icon }: { id: SectionId; icon?: any }) {
|
||||
);
|
||||
}
|
||||
|
||||
// FlexBandPowerPanel — TX power per band and per class of mode.
|
||||
//
|
||||
// Three classes, not one row per mode: what decides the power is duty cycle and
|
||||
// what the amplifier will take of it, not the mode's name. Blank leaves the
|
||||
// power alone, which is why the boxes are empty rather than showing 0.
|
||||
function FlexBandPowerPanel({ bands }: { bands: string[] }) {
|
||||
const { t } = useI18n();
|
||||
const [map, setMap] = useState<Record<string, { phone: number; cw: number; digi: number }>>({});
|
||||
const [msg, setMsg] = useState('');
|
||||
useEffect(() => { GetFlexBandPower().then((m: any) => setMap(m ?? {})).catch(() => {}); }, []);
|
||||
const set = (band: string, kind: 'phone' | 'cw' | 'digi', v: string) => {
|
||||
const key = band.toUpperCase();
|
||||
const n = Math.max(0, Math.min(100, parseInt(v, 10) || 0));
|
||||
setMap((m) => {
|
||||
const cur = m[key] ?? { phone: 0, cw: 0, digi: 0 };
|
||||
const next = { ...m, [key]: { ...cur, [kind]: n } };
|
||||
SaveFlexBandPower(next as any)
|
||||
.then(() => { setMsg(t('flxpw.saved')); window.setTimeout(() => setMsg(''), 1200); })
|
||||
.catch((e: any) => setMsg(String(e?.message ?? e)));
|
||||
return next;
|
||||
});
|
||||
};
|
||||
const cell = (b: string, kind: 'phone' | 'cw' | 'digi') => {
|
||||
const e = map[b.toUpperCase()] ?? { phone: 0, cw: 0, digi: 0 };
|
||||
return (
|
||||
<td className="px-2 py-1">
|
||||
<Input
|
||||
type="number" min={0} max={100}
|
||||
className="h-7 w-20 text-sm"
|
||||
value={e[kind] ? String(e[kind]) : ''}
|
||||
placeholder="—"
|
||||
onChange={(ev) => set(b, kind, ev.target.value)}
|
||||
/>
|
||||
</td>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<h3 className="text-base font-semibold text-foreground">{t('flxpw.title')}</h3>
|
||||
<p className="text-xs text-muted-foreground">{t('flxpw.hint')}</p>
|
||||
</div>
|
||||
{bands.length === 0 ? (
|
||||
<p className="text-xs text-muted-foreground">{t('flxpw.noBands')}</p>
|
||||
) : (
|
||||
<div className="rounded-md border border-border overflow-hidden max-w-xl">
|
||||
<table className="w-full text-sm">
|
||||
<thead className="bg-muted/40 text-muted-foreground text-xs">
|
||||
<tr>
|
||||
<th className="text-left px-3 py-1.5 font-semibold">{t('flxpw.band')}</th>
|
||||
<th className="text-left px-2 py-1.5 font-semibold">{t('flxpw.phone')}</th>
|
||||
<th className="text-left px-2 py-1.5 font-semibold">CW</th>
|
||||
<th className="text-left px-2 py-1.5 font-semibold">{t('flxpw.digi')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{bands.map((b) => (
|
||||
<tr key={b} className="border-t border-border/60">
|
||||
<td className="px-3 py-1 font-mono">{b}</td>
|
||||
{cell(b, 'phone')}
|
||||
{cell(b, 'cw')}
|
||||
{cell(b, 'digi')}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
{msg && <span className="text-xs text-muted-foreground">{msg}</span>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// FlexBandAntennasPanel — pick the RX/TX antenna per band. Applied automatically
|
||||
// when the band changes (frequency change / spot click). Antennas come live from
|
||||
// the connected FlexRadio; bands come from Lists → Bands.
|
||||
@@ -5591,7 +5664,13 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
||||
antgenius: AntGeniusPanelSettings,
|
||||
tunergenius: TunerGeniusPanelSettings,
|
||||
pgxl: PGXLPanelSettings,
|
||||
flex: () => <FlexBandAntennasPanel bands={lists.bands ?? []} />,
|
||||
flex: () => (
|
||||
<>
|
||||
<FlexBandAntennasPanel bands={lists.bands ?? []} />
|
||||
<div className="h-6" />
|
||||
<FlexBandPowerPanel bands={lists.bands ?? []} />
|
||||
</>
|
||||
),
|
||||
audio: AudioPanel,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user