feat(icom): a DATA button, native PSK, real watts — and the audio codec
The console gains a DATA mode button (USB-D, what FT8 and friends ride on); the PSK button now maps to the rigs' native PSK mode (0x12) instead of erroring as an unknown mode — rigs without one NAK it, exactly as RS-BA1's button does there. The power meter shows real watts on the IC-7760, whose meter face runs to 250 W where a 100 W rig's percentage was the watts. The clickable S-meter gets a pointer cursor so it looks like what it is. Network audio: rxcodec 0x04 — the experiments on the real 7760 settle the codec table (0x10 = 16-bit stereo, 0x02 = 8-bit mono, both heard as garble), and 0x04 is the 16-bit mono the playback path actually plays.
This commit is contained in:
@@ -79,7 +79,7 @@ function bandsFor(model?: string): Band[] {
|
||||
|
||||
// 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'];
|
||||
const MODES = ['SSB', 'CW', 'RTTY', 'PSK', 'AM', 'FM', 'DATA'];
|
||||
|
||||
// Attenuator steps are MODEL-dependent even though the CI-V command (0x11) is the
|
||||
// same: the value byte is the dB. The IC-7610 (and 7700/7800/7851) have a 6/12/18
|
||||
@@ -132,6 +132,10 @@ function fmtVFO(hz?: number): string {
|
||||
function modeMatches(btn: string, cur?: string): boolean {
|
||||
if (!cur) return false;
|
||||
if (btn === 'SSB') return cur === 'SSB' || cur === 'USB' || cur === 'LSB';
|
||||
// The backend surfaces USB-D as the operator's digital default (FT8…), or as
|
||||
// plain DATA — either way it is the DATA button that should light.
|
||||
if (btn === 'DATA') return ['DATA', 'FT8', 'FT4', 'JS8', 'JT65', 'JT9', 'MFSK', 'OLIVIA'].includes(cur);
|
||||
if (btn === 'PSK') return cur === 'PSK' || cur === 'PSK31';
|
||||
return btn === cur;
|
||||
}
|
||||
|
||||
@@ -246,7 +250,7 @@ function Meter({ label, value, accent, scale, onClick, title }: { label: string;
|
||||
</>
|
||||
);
|
||||
if (onClick) {
|
||||
return <button type="button" onClick={onClick} title={title} className="flex items-center gap-2 w-full rounded hover:bg-muted/50 -mx-1 px-1 py-0.5">{body}</button>;
|
||||
return <button type="button" onClick={onClick} title={title} className="flex items-center gap-2 w-full rounded cursor-pointer hover:bg-muted/50 -mx-1 px-1 py-0.5">{body}</button>;
|
||||
}
|
||||
return <div className="flex items-center gap-2">{body}</div>;
|
||||
}
|
||||
@@ -718,7 +722,7 @@ export function IcomPanel({ onReportRST, isNetwork = false }: { onReportRST?: (r
|
||||
</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">
|
||||
<div className="grid grid-cols-7 border-t border-border/60 divide-x divide-border/60">
|
||||
{MODES.map((m) => {
|
||||
const on = modeMatches(m, curMode);
|
||||
return (
|
||||
@@ -739,7 +743,11 @@ export function IcomPanel({ onReportRST, isNetwork = false }: { onReportRST?: (r
|
||||
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`} />
|
||||
{/* The meter reads 0-100% of the rig's own scale. On a 100 W rig the
|
||||
percentage IS the watts; the IC-7760's meter runs to 250 W (the rig
|
||||
makes 200), so its percentage is worth 2.5 W a point — same face as
|
||||
the radio's. */}
|
||||
<Meter label="Po" value={st.power_meter} accent="#ef4444" scale={`${Math.round(st.power_meter * (((st.model ?? '').includes('7760')) ? 2.5 : 1))} 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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user