style(icom): the shared LED meters, and the sideband named

The console's thin home-made bars were the one holdout — every other panel
(Flex, Elecraft, the amps, the tuner) draws the same MeterBar. And the mode
badge said SSB, which on any band leaves the operator guessing which
sideband the rig is on: the panel now shows USB or LSB (the log keeps ADIF's
SSB).
This commit is contained in:
2026-08-30 03:00:58 +02:00
parent dad762a0f1
commit 605c934d33
3 changed files with 39 additions and 10 deletions
+4 -2
View File
@@ -33,7 +33,8 @@
"Icom console: the spectrum scope is removed. Every model streams its waveform differently — and on the IC-7760 enabling it killed the whole CI-V link, audio included. The radios own scope does it better.", "Icom console: the spectrum scope is removed. Every model streams its waveform differently — and on the IC-7760 enabling it killed the whole CI-V link, audio included. The radios own scope does it better.",
"Icom: any leftover waveform stream is switched off at connect — the scope flag lives in the radio and survived sessions, and its flood is what was killing the IC-7760s CI-V link.", "Icom: any leftover waveform stream is switched off at connect — the scope flag lives in the radio and survived sessions, and its flood is what was killing the IC-7760s CI-V link.",
"Icom console: an ATU chip beside SPLIT engages or DISENGAGES the internal tuner — TUNE started a cycle but could never take the tuner back out of line.", "Icom console: an ATU chip beside SPLIT engages or DISENGAGES the internal tuner — TUNE started a cycle but could never take the tuner back out of line.",
"Icom console: the TX meters get needle inertia — power holds its peak instead of flickering to 0 W between syllables, SWR shows the real peak then returns to the live value — and the wattage readout no longer wraps at three digits." "Icom console: the TX meters get needle inertia — power holds its peak instead of flickering to 0 W between syllables, SWR shows the real peak then returns to the live value — and the wattage readout no longer wraps at three digits.",
"Icom console: the meters use the same LED bars as the Flex and Elecraft consoles, and the mode badge says USB or LSB instead of an ambiguous SSB."
], ],
"fr": [ "fr": [
"Console Elecraft : le S-mètre est calibré sur un vrai K3 — S9 et les +dB correspondent désormais à laffichage de la radio (il lisait environ deux points S trop bas).", "Console Elecraft : le S-mètre est calibré sur un vrai K3 — S9 et les +dB correspondent désormais à laffichage de la radio (il lisait environ deux points S trop bas).",
@@ -66,7 +67,8 @@
"Console Icom : le scope spectral est retiré. Chaque modèle streame sa forme donde différemment — et sur lIC-7760 son activation tuait tout le lien CI-V, audio compris. Le scope de la radio fait ça mieux.", "Console Icom : le scope spectral est retiré. Chaque modèle streame sa forme donde différemment — et sur lIC-7760 son activation tuait tout le lien CI-V, audio compris. Le scope de la radio fait ça mieux.",
"Icom : tout flux waveform résiduel est coupé à la connexion — le drapeau scope vit dans la radio et survivait aux sessions, et son flot est ce qui tuait le lien CI-V de lIC-7760.", "Icom : tout flux waveform résiduel est coupé à la connexion — le drapeau scope vit dans la radio et survivait aux sessions, et son flot est ce qui tuait le lien CI-V de lIC-7760.",
"Console Icom : une puce ATU à côté de SPLIT engage ou DÉSENGAGE le tuner interne — TUNE lançait un cycle mais ne pouvait jamais remettre le tuner hors ligne.", "Console Icom : une puce ATU à côté de SPLIT engage ou DÉSENGAGE le tuner interne — TUNE lançait un cycle mais ne pouvait jamais remettre le tuner hors ligne.",
"Console Icom : les mètres TX gagnent une inertie daiguille — la puissance tient sa crête au lieu de retomber à 0 W entre les syllabes, le ROS montre la vraie crête puis revient à la valeur vive — et laffichage en watts ne passe plus à la ligne à trois chiffres." "Console Icom : les mètres TX gagnent une inertie daiguille — la puissance tient sa crête au lieu de retomber à 0 W entre les syllabes, le ROS montre la vraie crête puis revient à la valeur vive — et laffichage en watts ne passe plus à la ligne à trois chiffres.",
"Console Icom : les mètres utilisent les mêmes barres LED que les consoles Flex et Elecraft, et le badge de mode dit USB ou LSB au lieu dun SSB ambigu."
] ]
}, },
{ {
+22 -8
View File
@@ -284,6 +284,13 @@ function Meter({ label, value, accent, scale, onClick, title }: { label: string;
// sParts turns the raw 0-100 S-meter into S-unit + dB-over-S9 (S9 ≈ 47% on the // sParts turns the raw 0-100 S-meter into S-unit + dB-over-S9 (S9 ≈ 47% on the
// CI-V 0-255 scale, +60 dB near full scale). Used for both the display label and // CI-V 0-255 scale, +60 dB near full scale). Used for both the display label and
// the RST-tx value on click. // the RST-tx value on click.
// Green to S9, amber through +20, red above — the Elecraft console's scale.
function sSegColor(frac: number) {
if (frac > 0.78) return '#dc2626';
if (frac > 0.55) return '#f59e0b';
return '#16a34a';
}
function sParts(v: number): { s: number; over: number; label: string } { function sParts(v: number): { s: number; over: number; label: string } {
if (v >= 47) { if (v >= 47) {
const over = Math.max(0, Math.round((v - 47) * 60 / 47)); const over = Math.max(0, Math.round((v - 47) * 60 / 47));
@@ -420,7 +427,9 @@ export function IcomPanel({ onReportRST, isNetwork = false }: { onReportRST?: (r
// in split the CAT state's TX freq is the authority, otherwise the panel's // in split the CAT state's TX freq is the authority, otherwise the panel's
// own sub_hz read. // own sub_hz read.
const subHz: number = split ? (cat?.freq_hz || 0) : (st.sub_hz || 0); const subHz: number = split ? (cat?.freq_hz || 0) : (st.sub_hz || 0);
const curMode: string = cat?.mode || st.mode || ''; // The panel's own mode first: it carries the sideband (USB/LSB) where the
// CAT state folds both into ADIF's SSB.
const curMode: string = st.mode || cat?.mode || '';
// Mode-dependent controls: VOX / speech-comp / mic are voice-only (hidden on // Mode-dependent controls: VOX / speech-comp / mic are voice-only (hidden on
// CW and data); APF (audio peak filter) is CW-only. Fold USB/LSB into phone. // CW and data); APF (audio peak filter) is CW-only. Fold USB/LSB into phone.
const um = curMode.toUpperCase(); const um = curMode.toUpperCase();
@@ -512,21 +521,26 @@ export function IcomPanel({ onReportRST, isNetwork = false }: { onReportRST?: (r
</div> </div>
</div> </div>
{/* Live meters — always visible: S (RX, click → RST), Po in watts, SWR. */} {/* Live meters — the SAME LED MeterBar every other console uses (Flex,
<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"> Elecraft, the amp cards): one instrument look across the app, per the
operator's "les consoles doivent se ressembler". S is clickable → RST. */}
<div className="grid grid-cols-1 sm:grid-cols-3 gap-2">
{(() => { const sp = sParts(st.s_meter); return ( {(() => { const sp = sParts(st.s_meter); return (
<Meter label="S" value={st.s_meter} accent="#22c55e" scale={sp.label} <MeterBar label="S-METER" value={st.transmitting ? 0 : st.s_meter} lo={0} hi={100}
accent="#16a34a" segColor={sSegColor}
display={st.transmitting ? '—' : sp.label}
title={onReportRST ? t('rst.clickToFill') : undefined} title={onReportRST ? t('rst.clickToFill') : undefined}
onClick={onReportRST ? () => onReportRST(sMeterRST(sp.s, sp.over, st.mode)) : undefined} /> onClick={onReportRST ? () => { if (!st.transmitting) onReportRST(sMeterRST(sp.s, sp.over, st.mode)); } : undefined} />
); })()} ); })()}
{(() => { {(() => {
if ((st.model ?? '').includes('7760')) { if ((st.model ?? '').includes('7760')) {
const { w, defl } = icomWatts(st.power_meter); const { w, defl } = icomWatts(st.power_meter);
return <Meter label="Po" value={defl} accent="#ef4444" scale={`${w} W`} />; return <MeterBar label="PWR" value={defl} lo={0} hi={100} accent="#0ea5e9" display={`${w} W`} />;
} }
return <Meter label="Po" value={st.power_meter} accent="#ef4444" scale={`${st.power_meter} W`} />; return <MeterBar label="PWR" value={st.power_meter} lo={0} hi={100} accent="#0ea5e9" display={`${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'} /> <MeterBar label="SWR" value={st.swr_meter > 0 ? 1 + st.swr_meter / 33.3 : 0} lo={1} hi={4} accent="#f59e0b"
display={st.swr_meter > 0 ? (1 + st.swr_meter / 33.3).toFixed(1) : '—'} />
</div> </div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3"> <div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
+13
View File
@@ -422,6 +422,19 @@ func (b *IcomSerial) ReadState() (RigState, error) {
} }
b.dspMu.Lock() b.dspMu.Lock()
b.dsp.Mode = s.Mode b.dsp.Mode = s.Mode
// The console says which SIDEBAND, not the ADIF family: "SSB" on 40 m
// leaves the operator guessing whether the rig is where convention puts
// it. The log keeps SSB; the panel shows what the radio is actually doing.
switch b.curModeByte {
case civ.ModeUSB:
if s.Mode == "SSB" {
b.dsp.Mode = "USB"
}
case civ.ModeLSB:
if s.Mode == "SSB" {
b.dsp.Mode = "LSB"
}
}
b.dspMu.Unlock() b.dspMu.Unlock()
} }