feat: Implemented scope on Ethernet for Icom
This commit is contained in:
+15
-2
@@ -889,12 +889,12 @@ export default function App() {
|
||||
// map ("map1"), the locator street map ("map2"), the cluster grid or the
|
||||
// worked-before grid. Per-profile (stored via SetUIPref → profile-prefixed),
|
||||
// so it's loaded async on mount and re-read on profile:changed below.
|
||||
type MainPaneKind = 'map1' | 'map2' | 'cluster' | 'worked' | 'flex' | 'recent';
|
||||
type MainPaneKind = 'map1' | 'map2' | 'cluster' | 'worked' | 'flex' | 'recent' | 'icom' | 'netcontrol';
|
||||
const [mapZoomSignal, setMapZoomSignal] = useState(0); // bump → world map auto-zooms now
|
||||
const [mainPaneLeft, setMainPaneLeft] = useState<MainPaneKind>('map1');
|
||||
const [mainPaneRight, setMainPaneRight] = useState<MainPaneKind>('map2');
|
||||
const loadMainPanes = useCallback(async () => {
|
||||
const valid = (v: string): v is MainPaneKind => v === 'map1' || v === 'map2' || v === 'cluster' || v === 'worked' || v === 'flex' || v === 'recent';
|
||||
const valid = (v: string): v is MainPaneKind => v === 'map1' || v === 'map2' || v === 'cluster' || v === 'worked' || v === 'flex' || v === 'recent' || v === 'icom' || v === 'netcontrol';
|
||||
const [l, r] = await Promise.all([
|
||||
GetUIPref('mainPaneLeft').catch(() => ''),
|
||||
GetUIPref('mainPaneRight').catch(() => ''),
|
||||
@@ -3080,6 +3080,18 @@ export default function App() {
|
||||
onReportRST={(r) => { setRstSent(r); rstUserEditedRef.current = true; }} />
|
||||
</div>
|
||||
);
|
||||
case 'icom':
|
||||
return (
|
||||
<div className="h-full w-full min-h-0 rounded-lg overflow-hidden border border-border">
|
||||
<IcomPanel onReportRST={(r) => { setRstSent(r); rstUserEditedRef.current = true; }} />
|
||||
</div>
|
||||
);
|
||||
case 'netcontrol':
|
||||
return (
|
||||
<div className="h-full w-full min-h-0 flex flex-col rounded-lg overflow-hidden border border-border">
|
||||
<NetControlPanel onLogged={refresh} countries={countries} bands={bands} modes={modes} />
|
||||
</div>
|
||||
);
|
||||
case 'recent':
|
||||
return (
|
||||
<div className="h-full w-full min-h-0 flex flex-col bg-card border border-border rounded-lg overflow-hidden">
|
||||
@@ -4344,6 +4356,7 @@ export default function App() {
|
||||
onSaved={() => { loadStation(); loadLists(); loadCATCfg(); reloadWk(); }}
|
||||
onMainPaneChanged={(side, v) => { if (side === 'left') setMainPaneLeft(v as MainPaneKind); else setMainPaneRight(v as MainPaneKind); }}
|
||||
flexAvailable={catState.backend === 'flex'}
|
||||
icomAvailable={catState.backend === 'icom'}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Radio, AudioLines, RefreshCw, Mic, Activity, SlidersHorizontal } from 'lucide-react';
|
||||
import { Radio, AudioLines, RefreshCw, Mic, Activity, SlidersHorizontal, Antenna, Filter, Power } from 'lucide-react';
|
||||
import {
|
||||
GetIcomState, IcomRefresh,
|
||||
IcomSetAFGain, IcomSetRFGain, IcomSetNB, IcomSetNBLevel, IcomSetNR, IcomSetNRLevel,
|
||||
IcomSetANF, IcomSetAGC, IcomSetPreamp, IcomSetAtt, IcomSetFilter,
|
||||
IcomSetRFPower, IcomSetMicGain, IcomSetSplit, IcomTune, IcomSetPTT,
|
||||
IcomSetScope, IcomScopeData, IcomSetScopeMode, GetCATState, SetCATFrequency,
|
||||
IcomSetScope, IcomScopeData, IcomSetScopeMode, GetCATState, SetCATFrequency, SetCATMode,
|
||||
IcomSetRIT, IcomSetRITOn, IcomSetXITOn,
|
||||
IcomSetAntenna, IcomSetPBTInner, IcomSetPBTOuter, IcomSetManualNotch, IcomSetNotchPos,
|
||||
IcomSetSquelch, IcomSetComp, IcomSetCompLevel, IcomSetMonitor, IcomSetMonLevel,
|
||||
IcomSetVOX, IcomSetVOXGain, IcomSetAntiVOX, IcomSetPower,
|
||||
} from '../../wailsjs/go/main/App';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
@@ -21,6 +24,11 @@ type IcomState = {
|
||||
nb: boolean; nb_level: number; nr: boolean; nr_level: number; anf: boolean;
|
||||
agc?: string; preamp: number; att: number; filter: number;
|
||||
rit_hz: number; rit_on: boolean; xit_on: boolean;
|
||||
antenna: number;
|
||||
pbt_inner: number; pbt_outer: number; manual_notch: boolean; notch_pos: number;
|
||||
squelch: number; comp: boolean; comp_level: number;
|
||||
monitor: boolean; mon_level: number;
|
||||
vox: boolean; vox_gain: number; anti_vox: number;
|
||||
};
|
||||
|
||||
const ZERO: IcomState = {
|
||||
@@ -30,8 +38,43 @@ const ZERO: IcomState = {
|
||||
nb: false, nb_level: 0, nr: false, nr_level: 0, anf: false,
|
||||
preamp: 0, att: 0, filter: 1,
|
||||
rit_hz: 0, rit_on: false, xit_on: false,
|
||||
antenna: 1,
|
||||
pbt_inner: 50, pbt_outer: 50, manual_notch: false, notch_pos: 50,
|
||||
squelch: 0, comp: false, comp_level: 0,
|
||||
monitor: false, mon_level: 0,
|
||||
vox: false, vox_gain: 0, anti_vox: 0,
|
||||
};
|
||||
|
||||
// Band buttons jump the VFO to a sensible default frequency (SSB/CW mix) using
|
||||
// the plain SetFrequency command — no band-stacking codes needed. Hz values.
|
||||
const BANDS: { l: string; hz: number }[] = [
|
||||
{ l: '160', hz: 1_840_000 }, { l: '80', hz: 3_750_000 }, { l: '40', hz: 7_100_000 },
|
||||
{ l: '30', hz: 10_130_000 }, { l: '20', hz: 14_150_000 }, { l: '17', hz: 18_130_000 },
|
||||
{ l: '15', hz: 21_250_000 }, { l: '12', hz: 24_950_000 }, { l: '10', hz: 28_400_000 },
|
||||
{ l: '6', hz: 50_150_000 },
|
||||
];
|
||||
|
||||
// Mode buttons for the console (like RS-BA1's row). SetCATMode picks USB/LSB for
|
||||
// SSB by frequency and the rig's data variant for digital modes.
|
||||
const MODES = ['SSB', 'CW', 'RTTY', 'PSK', 'AM', 'FM'];
|
||||
|
||||
// fmtVFO renders a Hz frequency the way an Icom front panel does:
|
||||
// MHz "." 3-digit-kHz "." 2-digit-(10 Hz). 21032000 → "21.032.00".
|
||||
function fmtVFO(hz?: number): string {
|
||||
if (!hz || hz <= 0) return '––.–––.––';
|
||||
const mhz = Math.floor(hz / 1_000_000);
|
||||
const khz = Math.floor((hz % 1_000_000) / 1000);
|
||||
const h2 = Math.floor((hz % 1000) / 10);
|
||||
return `${mhz}.${String(khz).padStart(3, '0')}.${String(h2).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
// modeMatches marks a mode button active, folding the rig's USB/LSB into SSB.
|
||||
function modeMatches(btn: string, cur?: string): boolean {
|
||||
if (!cur) return false;
|
||||
if (btn === 'SSB') return cur === 'SSB' || cur === 'USB' || cur === 'LSB';
|
||||
return btn === cur;
|
||||
}
|
||||
|
||||
function Slider({ value, onChange, disabled, accent = '#2563eb', step = 1 }: {
|
||||
value: number; onChange: (v: number) => void; disabled?: boolean; accent?: string; step?: number;
|
||||
}) {
|
||||
@@ -148,25 +191,6 @@ function Meter({ label, value, accent, scale, onClick, title }: { label: string;
|
||||
return <div className="flex items-center gap-2">{body}</div>;
|
||||
}
|
||||
|
||||
// HdrMeter — a compact live meter for the model header band (S when receiving,
|
||||
// Po/SWR when transmitting). Clickable variant sends the S reading to RST tx.
|
||||
function HdrMeter({ label, value, accent, scale, onClick, title }: {
|
||||
label: string; value: number; accent: string; scale: string; onClick?: () => void; title?: string;
|
||||
}) {
|
||||
const v = Math.max(0, Math.min(100, value));
|
||||
const body = (
|
||||
<>
|
||||
<span className="w-5 shrink-0 text-[10px] font-bold uppercase tracking-wider text-muted-foreground">{label}</span>
|
||||
<div className="w-24 sm:w-32 h-2 rounded-full bg-muted/70 overflow-hidden">
|
||||
<div className="h-full rounded-full transition-[width] duration-150" style={{ width: `${v}%`, background: accent }} />
|
||||
</div>
|
||||
<span className="w-12 text-right text-[11px] font-mono font-bold tabular-nums" style={{ color: accent }}>{scale}</span>
|
||||
</>
|
||||
);
|
||||
if (onClick) return <button type="button" onClick={onClick} title={title} className="flex items-center gap-1.5 rounded-md hover:bg-muted/60 px-1.5 py-0.5 -my-0.5">{body}</button>;
|
||||
return <div className="flex items-center gap-1.5 px-1.5">{body}</div>;
|
||||
}
|
||||
|
||||
// ShiftRow — a RIT / ΔTX offset control: on/off chip + a wheel-adjustable signed
|
||||
// offset (±10 Hz per notch or per ± button) + a clear (0) button.
|
||||
function ShiftRow({ label, on, hz, accent, onToggle, onDelta, onClear }: {
|
||||
@@ -475,12 +499,17 @@ function ScopePanadapter() {
|
||||
export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void } = {}) {
|
||||
const { t } = useI18n();
|
||||
const [st, setSt] = useState<IcomState>(ZERO);
|
||||
const [cat, setCat] = useState<any>(null); // RigState (freq/mode/split) for the VFO display
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [tuning, setTuning] = useState(false);
|
||||
const txRef = useRef(false);
|
||||
const stRef = useRef<IcomState>(ZERO); stRef.current = st;
|
||||
|
||||
const load = () => GetIcomState().then((s) => setSt((s ?? ZERO) as IcomState)).catch(() => {});
|
||||
const load = () => {
|
||||
GetIcomState().then((s) => setSt((s ?? ZERO) as IcomState)).catch(() => {});
|
||||
GetCATState().then((c) => setCat(c ?? null)).catch(() => {});
|
||||
};
|
||||
const setMode = (m: string) => { setCat((c: any) => (c ? { ...c, mode: m } : c)); SetCATMode(m).catch(() => {}); };
|
||||
const refresh = async () => {
|
||||
setBusy(true);
|
||||
try { await IcomRefresh(); } catch {}
|
||||
@@ -543,6 +572,12 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
|
||||
}
|
||||
|
||||
const tx = st.transmitting;
|
||||
// VFO readout. In split the active/listening VFO is RX (freq_rx_hz) and the
|
||||
// other is TX (freq_hz); otherwise there's a single VFO (freq_hz).
|
||||
const split = !!cat?.split;
|
||||
const mainHz: number = split ? (cat?.freq_rx_hz || 0) : (cat?.freq_hz || 0);
|
||||
const subHz: number = split ? (cat?.freq_hz || 0) : 0;
|
||||
const curMode: string = cat?.mode || st.mode || '';
|
||||
|
||||
return (
|
||||
<div className="h-full min-h-0 overflow-auto bg-background">
|
||||
@@ -559,26 +594,97 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
|
||||
{st.mode ? <span className="text-xs font-mono text-muted-foreground">{st.mode}</span> : null}
|
||||
{st.split ? <span className="rounded-md bg-warning/20 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-warning">Split</span> : null}
|
||||
</div>
|
||||
{/* Live meter in the header band: S when receiving (click → RST tx), Po when transmitting. */}
|
||||
<div className="hidden md:flex items-center">
|
||||
{tx ? (
|
||||
<HdrMeter label="Po" value={st.power_meter} accent="#ef4444" scale={`${st.power_meter}%`} />
|
||||
) : (() => { const sp = sParts(st.s_meter); return (
|
||||
<HdrMeter label="S" value={st.s_meter} accent="#22c55e" scale={sp.label}
|
||||
title={onReportRST ? t('rst.clickToFill') : undefined}
|
||||
onClick={onReportRST ? () => onReportRST(sMeterRST(sp.s, sp.over, st.mode)) : undefined} />
|
||||
); })()}
|
||||
<div className="flex items-center gap-1.5">
|
||||
{/* Radio power ON / OFF. Manual by design — the app never wakes the rig
|
||||
on connect; ON sends the wake preamble then the rig boots ~15 s. */}
|
||||
<button type="button" onClick={() => IcomSetPower(true).catch(() => {})} title={t('icmp.powerOnHint')}
|
||||
className="inline-flex items-center gap-1 rounded-md border border-success/60 bg-success/10 px-2 py-1 text-xs font-bold text-success hover:bg-success/20">
|
||||
<Power className="size-3.5" /> ON
|
||||
</button>
|
||||
<button type="button" onClick={() => { if (window.confirm(t('icmp.powerOffConfirm'))) IcomSetPower(false).catch(() => {}); }} title={t('icmp.powerOffHint')}
|
||||
className="inline-flex items-center gap-1 rounded-md border border-destructive/60 bg-destructive/10 px-2 py-1 text-xs font-bold text-destructive hover:bg-destructive/20">
|
||||
<Power className="size-3.5" /> OFF
|
||||
</button>
|
||||
<button type="button" onClick={refresh} disabled={busy}
|
||||
className="inline-flex items-center gap-1.5 rounded-md border border-border bg-card px-2 py-1 text-xs hover:bg-muted disabled:opacity-40">
|
||||
<RefreshCw className={cn('size-3.5', busy && 'animate-spin')} /> {t('icmp.refresh')}
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" onClick={refresh} disabled={busy}
|
||||
className="inline-flex items-center gap-1.5 rounded-md border border-border bg-card px-2 py-1 text-xs hover:bg-muted disabled:opacity-40">
|
||||
<RefreshCw className={cn('size-3.5', busy && 'animate-spin')} /> {t('icmp.refresh')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* VFO readout — the RS-BA1-style twin display: MAIN (active) + SUB, the big
|
||||
tabular frequency, mode badge, band, and the RIT/ΔTX offset. */}
|
||||
<div className="rounded-xl border border-border bg-muted/25 shadow-inner overflow-hidden">
|
||||
<div className="grid grid-cols-2 divide-x divide-border/60">
|
||||
{/* MAIN VFO */}
|
||||
<div className="px-4 py-3">
|
||||
<div className="flex items-center justify-between mb-1.5">
|
||||
<span className={cn('text-[10px] font-bold uppercase tracking-widest', tx ? 'text-destructive' : 'text-success')}>{tx ? 'Main · TX' : 'Main'}</span>
|
||||
{curMode ? <span className="rounded px-1.5 py-0.5 text-[10px] font-bold bg-primary/15 text-primary">{curMode}</span> : null}
|
||||
</div>
|
||||
<div className="font-mono font-bold tabular-nums leading-none text-foreground" style={{ fontSize: 'clamp(1.5rem, 4.5vw, 2.25rem)' }}>{fmtVFO(mainHz)}</div>
|
||||
<div className="mt-1.5 flex items-center gap-2 text-[11px] font-mono text-muted-foreground">
|
||||
<span>{cat?.band || (mainHz ? '' : '—')}</span>
|
||||
{st.rit_on ? <span className="text-primary">RIT {st.rit_hz > 0 ? '+' : st.rit_hz < 0 ? '−' : ''}{Math.abs(st.rit_hz)}</span> : null}
|
||||
{st.xit_on ? <span className="text-warning">ΔTX</span> : null}
|
||||
</div>
|
||||
</div>
|
||||
{/* SUB VFO (populated in split; dimmed otherwise) */}
|
||||
<div className={cn('px-4 py-3', !split && 'opacity-40')}>
|
||||
<div className="flex items-center justify-between mb-1.5">
|
||||
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground">Sub</span>
|
||||
{split ? <span className="rounded px-1.5 py-0.5 text-[10px] font-bold bg-warning/15 text-warning">SPLIT</span> : null}
|
||||
</div>
|
||||
<div className="font-mono font-bold tabular-nums leading-none text-muted-foreground" style={{ fontSize: 'clamp(1.5rem, 4.5vw, 2.25rem)' }}>{fmtVFO(subHz)}</div>
|
||||
<div className="mt-1.5 text-[11px] font-mono text-muted-foreground">{split ? 'TX' : ''}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Mode selector row (RS-BA1's SSB/CW/RTTY/PSK/AM/FM). */}
|
||||
<div className="grid grid-cols-6 border-t border-border/60 divide-x divide-border/60">
|
||||
{MODES.map((m) => {
|
||||
const on = modeMatches(m, curMode);
|
||||
return (
|
||||
<button key={m} type="button" onClick={() => setMode(m)}
|
||||
className={cn('py-1.5 text-[11px] font-bold tracking-wide transition-colors',
|
||||
on ? 'bg-primary text-primary-foreground' : 'bg-card/40 text-muted-foreground hover:bg-muted')}>
|
||||
{m}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Live meters — always visible: S (RX, click → RST), Po in watts, SWR. */}
|
||||
<div className="rounded-xl border border-border bg-card px-3 py-2.5 shadow-sm grid grid-cols-1 sm:grid-cols-3 gap-x-5 gap-y-2">
|
||||
{(() => { const sp = sParts(st.s_meter); return (
|
||||
<Meter label="S" value={st.s_meter} accent="#22c55e" scale={sp.label}
|
||||
title={onReportRST ? t('rst.clickToFill') : undefined}
|
||||
onClick={onReportRST ? () => onReportRST(sMeterRST(sp.s, sp.over, st.mode)) : undefined} />
|
||||
); })()}
|
||||
<Meter label="Po" value={st.power_meter} accent="#ef4444" scale={`${st.power_meter} W`} />
|
||||
<Meter label="SWR" value={st.swr_meter} accent="#f59e0b" scale={st.swr_meter > 0 ? `${(1 + st.swr_meter / 33.3).toFixed(1)}` : '1.0'} />
|
||||
</div>
|
||||
|
||||
{/* Spectrum panadapter (full width). */}
|
||||
<ScopePanadapter />
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
|
||||
{/* Band buttons + antenna selection. */}
|
||||
<Card icon={Antenna} title={t('icmp.bandsAntenna')} accent="#0891b2">
|
||||
<div className="grid grid-cols-5 gap-1.5">
|
||||
{BANDS.map((b) => (
|
||||
<button key={b.l} type="button" onClick={() => SetCATFrequency(b.hz).catch(() => {})}
|
||||
className="px-1 py-1.5 rounded-md text-[11px] font-bold border border-border bg-card text-foreground hover:bg-muted transition-colors">
|
||||
{b.l}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<Row label={t('icmp.antenna')}>
|
||||
<Segmented value={String(st.antenna)} options={[{ v: '1', l: 'ANT1' }, { v: '2', l: 'ANT2' }]}
|
||||
onChange={(v) => set({ antenna: parseInt(v) }, () => IcomSetAntenna(parseInt(v)))} />
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
{/* Clarifiers: RIT & ΔTX (XIT) — wheel or ± to shift, Ctrl+←/→ shifts RIT. */}
|
||||
<Card icon={SlidersHorizontal} title={t('icmp.clarifiers')} accent="#8b5cf6">
|
||||
<ShiftRow label="RIT" accent="#8b5cf6" on={st.rit_on} hz={st.rit_hz}
|
||||
@@ -588,12 +694,6 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
|
||||
onToggle={() => set({ xit_on: !st.xit_on }, () => IcomSetXITOn(!st.xit_on))}
|
||||
onDelta={(d) => setRit(st.rit_hz + d)} onClear={() => setRit(0)} />
|
||||
<p className="text-[11px] text-muted-foreground">{t('icmp.ritHint')}</p>
|
||||
{tx && (
|
||||
<div className="pt-1 border-t border-border/60 space-y-3">
|
||||
<Meter label="Po" value={st.power_meter} accent="#ef4444" scale={`${st.power_meter}%`} />
|
||||
<Meter label="SWR" value={st.swr_meter} accent="#f59e0b" scale={st.swr_meter > 0 ? `${(1 + st.swr_meter / 33.3).toFixed(1)}` : '1.0'} />
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
{/* Transmit controls. */}
|
||||
@@ -619,6 +719,22 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
|
||||
TUNE
|
||||
</button>
|
||||
</div>
|
||||
{/* Speech processor / monitor / VOX. */}
|
||||
<div className="pt-2 mt-1 border-t border-border/60 space-y-3">
|
||||
<LevelRow label="COMP" on={st.comp} value={st.comp_level}
|
||||
onToggle={() => set({ comp: !st.comp }, () => IcomSetComp(!st.comp))}
|
||||
onLevel={(v) => set({ comp_level: v }, () => IcomSetCompLevel(v))} />
|
||||
<LevelRow label="MON" on={st.monitor} value={st.mon_level}
|
||||
onToggle={() => set({ monitor: !st.monitor }, () => IcomSetMonitor(!st.monitor))}
|
||||
onLevel={(v) => set({ mon_level: v }, () => IcomSetMonLevel(v))} />
|
||||
<LevelRow label="VOX" on={st.vox} value={st.vox_gain}
|
||||
onToggle={() => set({ vox: !st.vox }, () => IcomSetVOX(!st.vox))}
|
||||
onLevel={(v) => set({ vox_gain: v }, () => IcomSetVOXGain(v))} />
|
||||
<Row label="Anti-VOX">
|
||||
<Slider value={st.anti_vox} disabled={!st.vox} onChange={(v) => set({ anti_vox: v }, () => IcomSetAntiVOX(v))} />
|
||||
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.anti_vox}</span>
|
||||
</Row>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card icon={Radio} title={t('icmp.receive')} accent="#2563eb">
|
||||
@@ -630,6 +746,10 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
|
||||
<Slider value={st.rf_gain} onChange={(v) => set({ rf_gain: v }, () => IcomSetRFGain(v))} />
|
||||
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.rf_gain}</span>
|
||||
</Row>
|
||||
<Row label={t('icmp.squelch')}>
|
||||
<Slider value={st.squelch} onChange={(v) => set({ squelch: v }, () => IcomSetSquelch(v))} />
|
||||
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.squelch}</span>
|
||||
</Row>
|
||||
<Row label="AGC">
|
||||
<Segmented value={st.agc || ''} options={[{ v: 'FAST', l: 'FAST' }, { v: 'MID', l: 'MID' }, { v: 'SLOW', l: 'SLOW' }]}
|
||||
onChange={(v) => set({ agc: v }, () => IcomSetAGC(v))} />
|
||||
@@ -648,6 +768,31 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
{/* Twin PBT + manual notch. Sliders are 0-100 with 50 = centre. */}
|
||||
<Card icon={Filter} title={t('icmp.passband')} accent="#7c3aed">
|
||||
<Row label="PBT-IN">
|
||||
<Slider value={st.pbt_inner} accent="#7c3aed" onChange={(v) => set({ pbt_inner: v }, () => IcomSetPBTInner(v))} />
|
||||
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.pbt_inner - 50 > 0 ? '+' : ''}{st.pbt_inner - 50}</span>
|
||||
</Row>
|
||||
<Row label="PBT-OUT">
|
||||
<Slider value={st.pbt_outer} accent="#7c3aed" onChange={(v) => set({ pbt_outer: v }, () => IcomSetPBTOuter(v))} />
|
||||
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.pbt_outer - 50 > 0 ? '+' : ''}{st.pbt_outer - 50}</span>
|
||||
</Row>
|
||||
<button type="button"
|
||||
onClick={() => { set({ pbt_inner: 50 }, () => IcomSetPBTInner(50)); set({ pbt_outer: 50 }, () => IcomSetPBTOuter(50)); }}
|
||||
className="w-full py-1 rounded-md text-[11px] font-bold border border-border bg-card text-muted-foreground hover:bg-muted">
|
||||
{t('icmp.pbtCenter')}
|
||||
</button>
|
||||
<div className="pt-1 border-t border-border/60 space-y-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Chip label="MN" on={st.manual_notch} onClick={() => set({ manual_notch: !st.manual_notch }, () => IcomSetManualNotch(!st.manual_notch))} />
|
||||
<Slider value={st.notch_pos} disabled={!st.manual_notch} accent="#7c3aed" onChange={(v) => set({ notch_pos: v }, () => IcomSetNotchPos(v))} />
|
||||
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.notch_pos}</span>
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground">{t('icmp.manualNotch')}</p>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card icon={AudioLines} title={t('icmp.noiseNotch')} accent="#16a34a">
|
||||
<LevelRow label="NB" on={st.nb} value={st.nb_level}
|
||||
onToggle={() => set({ nb: !st.nb }, () => IcomSetNB(!st.nb))}
|
||||
|
||||
@@ -146,6 +146,7 @@ interface Props {
|
||||
onSaved: () => void;
|
||||
onMainPaneChanged?: (side: 'left' | 'right', value: string) => void; // live Main-view layout update
|
||||
flexAvailable?: boolean; // CAT backend is FlexRadio → offer it as a Main pane
|
||||
icomAvailable?: boolean; // CAT backend is Icom → offer the Icom console as a Main pane
|
||||
}
|
||||
|
||||
// Pretty little card showing what OpsLog will stamp on each QSO based on
|
||||
@@ -573,17 +574,19 @@ const MAIN_PANE_OPTIONS: { value: string; label: string }[] = [
|
||||
{ value: 'cluster', label: 'Cluster spots' },
|
||||
{ value: 'worked', label: 'Worked before' },
|
||||
{ value: 'recent', label: 'Recent QSOs' },
|
||||
{ value: 'netcontrol', label: 'Net control' },
|
||||
];
|
||||
function MainViewPanes({ onChanged, flexAvailable }: { onChanged?: (side: 'left' | 'right', value: string) => void; flexAvailable?: boolean }) {
|
||||
function MainViewPanes({ onChanged, flexAvailable, icomAvailable }: { onChanged?: (side: 'left' | 'right', value: string) => void; flexAvailable?: boolean; icomAvailable?: boolean }) {
|
||||
const [left, setLeft] = useState('map1');
|
||||
const [right, setRight] = useState('map2');
|
||||
// FlexRadio is only offered when the CAT backend is a Flex. Sorted A→Z.
|
||||
const options = (flexAvailable
|
||||
? [...MAIN_PANE_OPTIONS, { value: 'flex', label: 'FlexRadio controls' }]
|
||||
: [...MAIN_PANE_OPTIONS]
|
||||
).sort((a, b) => a.label.localeCompare(b.label));
|
||||
// Radio-control panes are only offered when that CAT backend is active. Sorted A→Z.
|
||||
const options = [
|
||||
...MAIN_PANE_OPTIONS,
|
||||
...(flexAvailable ? [{ value: 'flex', label: 'FlexRadio controls' }] : []),
|
||||
...(icomAvailable ? [{ value: 'icom', label: 'Icom console' }] : []),
|
||||
].sort((a, b) => a.label.localeCompare(b.label));
|
||||
useEffect(() => {
|
||||
const valid = (v: string) => v === 'flex' || MAIN_PANE_OPTIONS.some((o) => o.value === v);
|
||||
const valid = (v: string) => v === 'flex' || v === 'icom' || MAIN_PANE_OPTIONS.some((o) => o.value === v);
|
||||
Promise.all([GetUIPref('mainPaneLeft').catch(() => ''), GetUIPref('mainPaneRight').catch(() => '')])
|
||||
.then(([l, r]) => { if (valid(l)) setLeft(l); if (valid(r)) setRight(r); });
|
||||
}, []);
|
||||
@@ -756,7 +759,7 @@ function FlexBandAntennasPanel({ bands }: { bands: string[] }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChanged, flexAvailable }: Props) {
|
||||
export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChanged, flexAvailable, icomAvailable }: Props) {
|
||||
const { t } = useI18n();
|
||||
const [selected, setSelected] = useState<SectionId>((initialSection as SectionId) || 'station');
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -3931,7 +3934,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
||||
<TelemetryToggle />
|
||||
<LiveStatusToggle />
|
||||
|
||||
<MainViewPanes onChanged={onMainPaneChanged} flexAvailable={flexAvailable} />
|
||||
<MainViewPanes onChanged={onMainPaneChanged} flexAvailable={flexAvailable} icomAvailable={icomAvailable} />
|
||||
|
||||
<div className="border-t border-border/60 pt-4 space-y-2">
|
||||
<h4 className="text-sm font-semibold text-foreground">Password encryption</h4>
|
||||
|
||||
@@ -193,7 +193,7 @@ const en: Dict = {
|
||||
'agp.portDeselect': 'Port {letter} — click to deselect', 'agp.portSelect': 'Select on port {letter}', 'agp.online': 'online', 'agp.offline': 'offline', 'agp.close': 'Close', 'agp.connecting': 'Connecting…', 'agp.noAntennas': 'No antennas configured.',
|
||||
'flxp.smartsdrRemote': 'SmartSDR remote control', 'flxp.offline': 'OFFLINE', 'flxp.waiting': 'Waiting for the FlexRadio… (set CAT to FlexRadio and connect)', 'flxp.transmit': 'Transmit', 'flxp.rfPower': 'RF Power', 'flxp.tunePwr': 'Tune Pwr', 'flxp.splitHint': 'Split: RX/TX on separate slices. ON creates a TX slice +1 kHz (CW) / +5 kHz (SSB) up, like SmartSDR.', 'flxp.voxDly': 'VOX Dly', 'flxp.speed': 'Speed', 'flxp.pitch': 'Pitch', 'flxp.delay': 'Delay',
|
||||
'flxp.receiveActive': 'Receive (active slice)', 'flxp.muted': 'Muted — click to unmute', 'flxp.mute': 'Mute RX audio', 'flxp.filter': 'Filter', 'flxp.amplifier': 'Amplifier', 'flxp.ampInLine': 'Amplifier is in line (transmitting through PA).', 'flxp.ampBypassed': 'Amplifier bypassed (standby).', 'flxp.pgConnected': 'PowerGenius connected', 'flxp.pgOffline': 'PowerGenius offline', 'flxp.fan': 'Fan', 'flxp.fanStandard': 'Standard', 'flxp.fanContest': 'Contest', 'flxp.fanBroadcast': 'Broadcast', 'flxp.fault': 'FAULT', 'flxp.meters': 'Meters', 'flxp.noMeters': "No meters yet — waiting for the radio's UDP stream…", 'flxp.amplifierHdr': 'AMPLIFIER',
|
||||
'icmp.spectrum': 'Spectrum', 'icmp.scopeFixed': 'Fixed — double-click / wheel to tune', 'icmp.scopeCenter': 'Center — follows VFO', 'icmp.scopeOff': 'Scope off', 'icmp.notConnected': "Icom not connected. Enable the Icom CI-V backend in Settings → CAT and connect the radio's USB port.", 'icmp.refresh': 'Refresh', 'icmp.meters': 'Meters', 'icmp.transmit': 'Transmit', 'icmp.power': 'Power', 'icmp.mic': 'Mic', 'icmp.receive': 'Receive', 'icmp.preamp': 'Preamp', 'icmp.filter': 'Filter', 'icmp.noiseNotch': 'Noise / Notch', 'icmp.autoNotch': 'Auto notch filter', 'icmp.clarifiers': 'RIT / ΔTX', 'icmp.ritHint': 'Wheel or ± to shift · Ctrl+←/→ shifts RIT when active',
|
||||
'icmp.spectrum': 'Spectrum', 'icmp.scopeFixed': 'Fixed — double-click / wheel to tune', 'icmp.scopeCenter': 'Center — follows VFO', 'icmp.scopeOff': 'Scope off', 'icmp.notConnected': "Icom not connected. Enable the Icom CI-V backend in Settings → CAT and connect the radio's USB port.", 'icmp.refresh': 'Refresh', 'icmp.meters': 'Meters', 'icmp.transmit': 'Transmit', 'icmp.power': 'Power', 'icmp.mic': 'Mic', 'icmp.receive': 'Receive', 'icmp.preamp': 'Preamp', 'icmp.filter': 'Filter', 'icmp.noiseNotch': 'Noise / Notch', 'icmp.autoNotch': 'Auto notch filter', 'icmp.clarifiers': 'RIT / ΔTX', 'icmp.ritHint': 'Wheel or ± to shift · Ctrl+←/→ shifts RIT when active', 'icmp.bandsAntenna': 'Bands & Antenna', 'icmp.antenna': 'Antenna', 'icmp.passband': 'Passband / Notch', 'icmp.pbtCenter': 'Center PBT', 'icmp.manualNotch': 'Manual notch — MN on, then set position', 'icmp.squelch': 'Squelch', 'icmp.powerOnHint': 'Power the radio ON (boots ~15 s)', 'icmp.powerOffHint': 'Power the radio OFF', 'icmp.powerOffConfirm': 'Switch the radio OFF?',
|
||||
'rst.clickToFill': 'Click to set RST tx from the signal',
|
||||
'qrz.openTitle': 'Open {call} on QRZ.com',
|
||||
// Misc panels/modals (alerts / send-spot / net / udp / filter / details)
|
||||
@@ -379,7 +379,7 @@ const fr: Dict = {
|
||||
'agp.portDeselect': 'Port {letter} — clic pour désélectionner', 'agp.portSelect': 'Sélectionner sur le port {letter}', 'agp.online': 'en ligne', 'agp.offline': 'hors ligne', 'agp.close': 'Fermer', 'agp.connecting': 'Connexion…', 'agp.noAntennas': 'Aucune antenne configurée.',
|
||||
'flxp.smartsdrRemote': 'Contrôle à distance SmartSDR', 'flxp.offline': 'HORS LIGNE', 'flxp.waiting': 'En attente du FlexRadio… (règle le CAT sur FlexRadio et connecte)', 'flxp.transmit': 'Émission', 'flxp.rfPower': 'Puissance RF', 'flxp.tunePwr': 'Puiss. TUNE', 'flxp.splitHint': 'Split : RX/TX sur des slices séparées. ON crée une slice TX +1 kHz (CW) / +5 kHz (SSB) au-dessus, comme SmartSDR.', 'flxp.voxDly': 'Délai VOX', 'flxp.speed': 'Vitesse', 'flxp.pitch': 'Tonalité', 'flxp.delay': 'Délai',
|
||||
'flxp.receiveActive': 'Réception (slice active)', 'flxp.muted': 'Coupé — clic pour rétablir', 'flxp.mute': "Couper l'audio RX", 'flxp.filter': 'Filtre', 'flxp.amplifier': 'Amplificateur', 'flxp.ampInLine': 'Amplificateur en ligne (émission via le PA).', 'flxp.ampBypassed': 'Amplificateur en bypass (standby).', 'flxp.pgConnected': 'PowerGenius connecté', 'flxp.pgOffline': 'PowerGenius hors ligne', 'flxp.fan': 'Ventilo', 'flxp.fanStandard': 'Standard', 'flxp.fanContest': 'Contest', 'flxp.fanBroadcast': 'Diffusion', 'flxp.fault': 'DÉFAUT', 'flxp.meters': 'Mesures', 'flxp.noMeters': 'Aucune mesure — en attente du flux UDP de la radio…', 'flxp.amplifierHdr': 'AMPLIFICATEUR',
|
||||
'icmp.spectrum': 'Spectre', 'icmp.scopeFixed': 'Fixe — double-clic / molette pour accorder', 'icmp.scopeCenter': 'Centré — suit le VFO', 'icmp.scopeOff': 'Scope éteint', 'icmp.notConnected': 'Icom non connecté. Active le backend CI-V Icom dans Réglages → CAT et connecte le port USB de la radio.', 'icmp.refresh': 'Rafraîchir', 'icmp.meters': 'Mesures', 'icmp.transmit': 'Émission', 'icmp.power': 'Puissance', 'icmp.mic': 'Micro', 'icmp.receive': 'Réception', 'icmp.preamp': 'Préampli', 'icmp.filter': 'Filtre', 'icmp.noiseNotch': 'Bruit / Notch', 'icmp.autoNotch': 'Filtre notch auto', 'icmp.clarifiers': 'RIT / ΔTX', 'icmp.ritHint': 'Molette ou ± pour décaler · Ctrl+←/→ décale le RIT si actif',
|
||||
'icmp.spectrum': 'Spectre', 'icmp.scopeFixed': 'Fixe — double-clic / molette pour accorder', 'icmp.scopeCenter': 'Centré — suit le VFO', 'icmp.scopeOff': 'Scope éteint', 'icmp.notConnected': 'Icom non connecté. Active le backend CI-V Icom dans Réglages → CAT et connecte le port USB de la radio.', 'icmp.refresh': 'Rafraîchir', 'icmp.meters': 'Mesures', 'icmp.transmit': 'Émission', 'icmp.power': 'Puissance', 'icmp.mic': 'Micro', 'icmp.receive': 'Réception', 'icmp.preamp': 'Préampli', 'icmp.filter': 'Filtre', 'icmp.noiseNotch': 'Bruit / Notch', 'icmp.autoNotch': 'Filtre notch auto', 'icmp.clarifiers': 'RIT / ΔTX', 'icmp.ritHint': 'Molette ou ± pour décaler · Ctrl+←/→ décale le RIT si actif', 'icmp.bandsAntenna': 'Bandes & Antenne', 'icmp.antenna': 'Antenne', 'icmp.passband': 'Passe-bande / Notch', 'icmp.pbtCenter': 'Centrer PBT', 'icmp.manualNotch': 'Notch manuel — active MN, puis règle la position', 'icmp.squelch': 'Squelch', 'icmp.powerOnHint': 'Allumer la radio (démarre en ~15 s)', 'icmp.powerOffHint': 'Éteindre la radio', 'icmp.powerOffConfirm': 'Éteindre la radio ?',
|
||||
'rst.clickToFill': 'Clic pour remplir le RST tx depuis le signal',
|
||||
'qrz.openTitle': 'Ouvrir {call} sur QRZ.com',
|
||||
'altm.filterPh': 'Filtrer…', 'altm.noMatch': 'aucun résultat', 'altm.noneAll': 'aucune sélection = TOUT', 'altm.nSelected': '{n} sélectionné(s)', 'altm.giveName': 'Donne un nom à la règle', 'altm.deleteConfirm': "Supprimer l'alerte « {name} » ?", 'altm.title': 'Gestion des alertes', 'altm.desc': 'Alerte quand un spot correspond à une règle. Filtres vides = TOUT ; les filtres définis sont combinés par ET (ex. France + 20m = stations françaises sur 20m).', 'altm.rules': 'Règles', 'altm.noRules': 'Aucune règle — clique sur +', 'altm.emailTo': "E-mail d'alerte à", 'altm.selectOrCreate': 'Sélectionne ou crée une règle.', 'altm.tabDef': 'Définition', 'altm.tabCall': 'Indicatif / DXCC', 'altm.tabBandMode': 'Bande / Mode', 'altm.tabOrigin': 'Origine', 'altm.ruleName': 'Nom de la règle', 'altm.alertEnabled': 'Alerte activée', 'altm.againAfter': 'Réalerter après (min)', 'altm.againHint': '0 = une fois/session · -1 = toujours', 'altm.actions': 'Actions', 'altm.visual': 'Visuel', 'altm.sound': 'Son', 'altm.email': 'E-mail', 'altm.skipWorked': 'Ignorer les indicatifs déjà contactés (même bande + mode)', 'altm.callsigns': 'Indicatifs (un par ligne, jokers : IW3*, */P)', 'altm.countries': 'Pays (DXCC)', 'altm.continents': 'Continents', 'altm.bands': 'Bandes', 'altm.modes': 'Modes', 'altm.spotterCall': 'Indicatif du spotteur (joker)', 'altm.spotterCallPh': 'ex. F* ou DL1ABC', 'altm.spotterContinents': 'Continents du spotteur', 'altm.spotterCountries': 'Pays du spotteur', 'altm.delete': 'Supprimer', 'altm.saveRule': 'Enregistrer la règle', 'altm.close': 'Fermer',
|
||||
|
||||
Vendored
+28
@@ -350,16 +350,30 @@ export function IcomSetAGC(arg1:string):Promise<void>;
|
||||
|
||||
export function IcomSetANF(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetAntenna(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetAntiVOX(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetAtt(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetBreakIn(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetComp(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetCompLevel(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetFilter(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetKeySpeed(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetManualNotch(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetMicGain(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetMonLevel(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetMonitor(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetNB(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetNBLevel(arg1:number):Promise<void>;
|
||||
@@ -368,8 +382,16 @@ export function IcomSetNR(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetNRLevel(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetNotchPos(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetPBTInner(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetPBTOuter(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetPTT(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetPower(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetPreamp(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetRFGain(arg1:number):Promise<void>;
|
||||
@@ -386,6 +408,12 @@ export function IcomSetScopeMode(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetSplit(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetSquelch(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetVOX(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomSetVOXGain(arg1:number):Promise<void>;
|
||||
|
||||
export function IcomSetXITOn(arg1:boolean):Promise<void>;
|
||||
|
||||
export function IcomStopCW():Promise<void>;
|
||||
|
||||
@@ -662,6 +662,14 @@ export function IcomSetANF(arg1) {
|
||||
return window['go']['main']['App']['IcomSetANF'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetAntenna(arg1) {
|
||||
return window['go']['main']['App']['IcomSetAntenna'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetAntiVOX(arg1) {
|
||||
return window['go']['main']['App']['IcomSetAntiVOX'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetAtt(arg1) {
|
||||
return window['go']['main']['App']['IcomSetAtt'](arg1);
|
||||
}
|
||||
@@ -670,6 +678,14 @@ export function IcomSetBreakIn(arg1) {
|
||||
return window['go']['main']['App']['IcomSetBreakIn'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetComp(arg1) {
|
||||
return window['go']['main']['App']['IcomSetComp'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetCompLevel(arg1) {
|
||||
return window['go']['main']['App']['IcomSetCompLevel'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetFilter(arg1) {
|
||||
return window['go']['main']['App']['IcomSetFilter'](arg1);
|
||||
}
|
||||
@@ -678,10 +694,22 @@ export function IcomSetKeySpeed(arg1) {
|
||||
return window['go']['main']['App']['IcomSetKeySpeed'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetManualNotch(arg1) {
|
||||
return window['go']['main']['App']['IcomSetManualNotch'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetMicGain(arg1) {
|
||||
return window['go']['main']['App']['IcomSetMicGain'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetMonLevel(arg1) {
|
||||
return window['go']['main']['App']['IcomSetMonLevel'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetMonitor(arg1) {
|
||||
return window['go']['main']['App']['IcomSetMonitor'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetNB(arg1) {
|
||||
return window['go']['main']['App']['IcomSetNB'](arg1);
|
||||
}
|
||||
@@ -698,10 +726,26 @@ export function IcomSetNRLevel(arg1) {
|
||||
return window['go']['main']['App']['IcomSetNRLevel'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetNotchPos(arg1) {
|
||||
return window['go']['main']['App']['IcomSetNotchPos'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetPBTInner(arg1) {
|
||||
return window['go']['main']['App']['IcomSetPBTInner'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetPBTOuter(arg1) {
|
||||
return window['go']['main']['App']['IcomSetPBTOuter'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetPTT(arg1) {
|
||||
return window['go']['main']['App']['IcomSetPTT'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetPower(arg1) {
|
||||
return window['go']['main']['App']['IcomSetPower'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetPreamp(arg1) {
|
||||
return window['go']['main']['App']['IcomSetPreamp'](arg1);
|
||||
}
|
||||
@@ -734,6 +778,18 @@ export function IcomSetSplit(arg1) {
|
||||
return window['go']['main']['App']['IcomSetSplit'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetSquelch(arg1) {
|
||||
return window['go']['main']['App']['IcomSetSquelch'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetVOX(arg1) {
|
||||
return window['go']['main']['App']['IcomSetVOX'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetVOXGain(arg1) {
|
||||
return window['go']['main']['App']['IcomSetVOXGain'](arg1);
|
||||
}
|
||||
|
||||
export function IcomSetXITOn(arg1) {
|
||||
return window['go']['main']['App']['IcomSetXITOn'](arg1);
|
||||
}
|
||||
|
||||
@@ -694,6 +694,19 @@ export namespace cat {
|
||||
preamp: number;
|
||||
att: number;
|
||||
filter: number;
|
||||
antenna: number;
|
||||
pbt_inner: number;
|
||||
pbt_outer: number;
|
||||
manual_notch: boolean;
|
||||
notch_pos: number;
|
||||
squelch: number;
|
||||
comp: boolean;
|
||||
comp_level: number;
|
||||
monitor: boolean;
|
||||
mon_level: number;
|
||||
vox: boolean;
|
||||
vox_gain: number;
|
||||
anti_vox: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new IcomTXState(source);
|
||||
@@ -727,6 +740,19 @@ export namespace cat {
|
||||
this.preamp = source["preamp"];
|
||||
this.att = source["att"];
|
||||
this.filter = source["filter"];
|
||||
this.antenna = source["antenna"];
|
||||
this.pbt_inner = source["pbt_inner"];
|
||||
this.pbt_outer = source["pbt_outer"];
|
||||
this.manual_notch = source["manual_notch"];
|
||||
this.notch_pos = source["notch_pos"];
|
||||
this.squelch = source["squelch"];
|
||||
this.comp = source["comp"];
|
||||
this.comp_level = source["comp_level"];
|
||||
this.monitor = source["monitor"];
|
||||
this.mon_level = source["mon_level"];
|
||||
this.vox = source["vox"];
|
||||
this.vox_gain = source["vox_gain"];
|
||||
this.anti_vox = source["anti_vox"];
|
||||
}
|
||||
}
|
||||
export class RigState {
|
||||
|
||||
Reference in New Issue
Block a user