feat(decodes): say when the decoder's band is not the rig's
A decoding application that loses its CAT link keeps announcing the last dial frequency it knew, and every decode after that carries a stale band. Nothing downstream can tell: the entity verdicts, the band filter and the FT map all believe it. Seen for real — MSHV kept saying 80 m, and Korea read as a NEW BAND because on 80 m it would have been. Said, not decided. Taking the rig's band instead would be wrong for anyone decoding a second receiver on another band, and a warning costs that setup nothing but a line to read past. Shown only while CAT is actually connected: an empty band means there is nothing to compare with, never that the rig is on no band. Opens 0.27.9.
This commit is contained in:
@@ -1,4 +1,14 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "0.27.9",
|
||||||
|
"date": "",
|
||||||
|
"en": [
|
||||||
|
"FT decodes warn when the decoding application announces a band the radio is not on — the signature of a lost CAT link, where it repeats the last frequency it knew and every decode after that carries a stale band. Nothing downstream could tell, so NEW BAND was being judged against a band the operator had left. OpsLog says it rather than deciding: a second receiver on another band is a real setup, and it costs that one only a line to read past."
|
||||||
|
],
|
||||||
|
"fr": [
|
||||||
|
"Les FT decodes signalent quand le logiciel de décodage annonce une bande sur laquelle la radio n’est pas — la signature d’une liaison CAT perdue, où il répète la dernière fréquence connue et où tous les décodages suivants portent une bande périmée. Rien en aval ne pouvait s’en apercevoir : NOUVELLE BANDE était donc jugé sur une bande quittée. OpsLog le dit sans décider à votre place : un second récepteur sur une autre bande est une configuration légitime, et il ne lui en coûte qu’une ligne à ignorer."
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "0.27.8",
|
"version": "0.27.8",
|
||||||
"date": "",
|
"date": "",
|
||||||
|
|||||||
@@ -6328,6 +6328,9 @@ export default function App() {
|
|||||||
txState={txState}
|
txState={txState}
|
||||||
txStates={txStates}
|
txStates={txStates}
|
||||||
spotStatus={spotStatus as any}
|
spotStatus={spotStatus as any}
|
||||||
|
// Only while CAT is actually connected: an empty band means "nothing to
|
||||||
|
// compare with", never "the rig is on no band".
|
||||||
|
rigBand={catState.connected ? (catState.band || '') : ''}
|
||||||
myCall={station.callsign}
|
myCall={station.callsign}
|
||||||
// A click ANSWERS the station: it hands the decode back to WSJT-X/MSHV as
|
// A click ANSWERS the station: it hands the decode back to WSJT-X/MSHV as
|
||||||
// a Reply, which is the same thing as double-clicking the line in their
|
// a Reply, which is the same thing as double-clicking the line in their
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
// come from the same resolver the cluster uses, so a call means the same thing in
|
// come from the same resolver the cluster uses, so a call means the same thing in
|
||||||
// both panels rather than being judged twice by two rules.
|
// both panels rather than being judged twice by two rules.
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { Radio, Search, X, Signal, ArrowUpRight, Timer, Trash2, Ban, Columns2, Bot } from 'lucide-react';
|
import { AlertTriangle, Radio, Search, X, Signal, ArrowUpRight, Timer, Trash2, Ban, Columns2, Bot } from 'lucide-react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { useI18n } from '@/lib/i18n';
|
import { useI18n } from '@/lib/i18n';
|
||||||
import { chaseAllows } from '@/lib/spotDisplay';
|
import { chaseAllows } from '@/lib/spotDisplay';
|
||||||
@@ -95,6 +95,9 @@ interface Props {
|
|||||||
// receiver reported last, which is a coin toss — each pane needs its own.
|
// receiver reported last, which is a coin toss — each pane needs its own.
|
||||||
txStates?: Record<string, TxMsg>;
|
txStates?: Record<string, TxMsg>;
|
||||||
spotStatus: Record<string, StatusEntry>;
|
spotStatus: Record<string, StatusEntry>;
|
||||||
|
// The band the RIG is on, when CAT is connected. Only ever compared with what
|
||||||
|
// the decoder announces — see the drift warning.
|
||||||
|
rigBand?: string;
|
||||||
onCall: (d: Decode) => void;
|
onCall: (d: Decode) => void;
|
||||||
myCall?: string;
|
myCall?: string;
|
||||||
// Drop every decode and transmit message held for this panel. The list is a
|
// Drop every decode and transmit message held for this panel. The list is a
|
||||||
@@ -539,7 +542,7 @@ function buildPeriods(filtered: Decode[], txMsgs: TxMsg[]) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DecodesPanel({ decodes, txMsgs, txState, txStates, spotStatus, onCall, myCall, onClear, onHalt, autoCallOn, onToggleAutoCall }: Props) {
|
export function DecodesPanel({ decodes, txMsgs, txState, txStates, spotStatus, rigBand, onCall, myCall, onClear, onHalt, autoCallOn, onToggleAutoCall }: Props) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
// Column widths, dragged in the header and shared by every row. Persisted
|
// Column widths, dragged in the header and shared by every row. Persisted
|
||||||
// through writeUiPref (not raw localStorage) so the layout travels with data/
|
// through writeUiPref (not raw localStorage) so the layout travels with data/
|
||||||
@@ -597,6 +600,21 @@ export function DecodesPanel({ decodes, txMsgs, txState, txStates, spotStatus, o
|
|||||||
|
|
||||||
// The mode currently on the air, for the slot clock. The newest decode knows
|
// The mode currently on the air, for the slot clock. The newest decode knows
|
||||||
// best; between overs the transmit state still does.
|
// best; between overs the transmit state still does.
|
||||||
|
// A decoder that has lost its CAT link keeps announcing the last dial
|
||||||
|
// frequency it knew, and every decode after that carries a stale band. Nothing
|
||||||
|
// downstream can tell: the entity verdicts, the band filter and the FT map all
|
||||||
|
// believe what the decoder said, and an operator ends up reading NEW BAND for a
|
||||||
|
// band they are not on. (Seen for real: MSHV lost CAT, kept saying 80 m, and
|
||||||
|
// Korea showed as a new band because on 80 m it would have been.)
|
||||||
|
//
|
||||||
|
// Said, not decided. Using the rig's band instead would be wrong for anyone
|
||||||
|
// decoding a second receiver on another band, and a warning costs that setup
|
||||||
|
// nothing but a line it can read past.
|
||||||
|
const decoderBand = decodes.length ? (decodes[decodes.length - 1].band ?? '') : '';
|
||||||
|
const bandDrift = !!rigBand && !!decoderBand
|
||||||
|
&& rigBand.toLowerCase() !== decoderBand.toLowerCase();
|
||||||
|
const driftInstance = decodes.length ? (decodes[decodes.length - 1].instance ?? '') : '';
|
||||||
|
|
||||||
const liveMode = decodes.length ? decodes[decodes.length - 1].mode : txState?.mode;
|
const liveMode = decodes.length ? decodes[decodes.length - 1].mode : txState?.mode;
|
||||||
const liveTr = trSeconds(liveMode, decodes.length ? decodes[decodes.length - 1].tr_period : undefined);
|
const liveTr = trSeconds(liveMode, decodes.length ? decodes[decodes.length - 1].tr_period : undefined);
|
||||||
|
|
||||||
@@ -733,6 +751,18 @@ export function DecodesPanel({ decodes, txMsgs, txState, txStates, spotStatus, o
|
|||||||
what the transmit state reports, so it is right the moment anything
|
what the transmit state reports, so it is right the moment anything
|
||||||
is heard and keeps running when the band goes quiet. */}
|
is heard and keeps running when the band goes quiet. */}
|
||||||
<PeriodClock trSec={liveTr} mode={liveMode} />
|
<PeriodClock trSec={liveTr} mode={liveMode} />
|
||||||
|
{bandDrift && (
|
||||||
|
<span
|
||||||
|
title={t('dec.bandDriftTip')}
|
||||||
|
className="inline-flex items-center gap-1 rounded-full border border-warning px-2 py-0.5 text-[11px] font-semibold text-warning">
|
||||||
|
<AlertTriangle className="size-3.5" />
|
||||||
|
{t('dec.bandDrift', {
|
||||||
|
app: driftInstance || t('dec.bandDriftApp'),
|
||||||
|
dec: decoderBand.toUpperCase(),
|
||||||
|
rig: (rigBand ?? '').toUpperCase(),
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
<span className="w-px h-5 bg-border/60 mx-1" />
|
<span className="w-px h-5 bg-border/60 mx-1" />
|
||||||
|
|
||||||
<button type="button" className={chip(cqOnly, 'success')} onClick={() => setCqOnly(!cqOnly)}>
|
<button type="button" className={chip(cqOnly, 'success')} onClick={() => setCqOnly(!cqOnly)}>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ const en: Dict = {
|
|||||||
'mx.tipThisCall': 'already worked with this callsign',
|
'mx.tipThisCall': 'already worked with this callsign',
|
||||||
'mx.tipThisCallConf': 'already confirmed with this callsign',
|
'mx.tipThisCallConf': 'already confirmed with this callsign',
|
||||||
// FTx decodes panel (Tools -> FT decodes)
|
// FTx decodes panel (Tools -> FT decodes)
|
||||||
'ftmap.tab': 'FT Map', 'ftmap.noGrid': 'Set your station grid in Preferences to place the map.', 'dec.tab': 'FT decodes', 'dec.title': 'Decodes', 'dec.cqOnly': 'CQ only',
|
'ftmap.tab': 'FT Map', 'ftmap.noGrid': 'Set your station grid in Preferences to place the map.', 'dec.tab': 'FT decodes', 'dec.title': 'Decodes', 'dec.bandDrift': '{app} says {dec}, the rig is on {rig}', 'dec.bandDriftApp': 'the decoder', 'dec.bandDriftTip': 'The decoding application is announcing a band the radio is not on — it has most likely lost its CAT link and is repeating the last frequency it knew. Every decode below carries that band, so the NEW / NEW BAND verdicts are judged against it.', 'dec.cqOnly': 'CQ only',
|
||||||
'dec.allBands': 'All bands', 'dec.allModes': 'All modes', 'toast.qsoLogged': 'QSO logged', 'dec.contsHint': 'Continents: click to keep one or several', 'dec.allConts': 'All continents',
|
'dec.allBands': 'All bands', 'dec.allModes': 'All modes', 'toast.qsoLogged': 'QSO logged', 'dec.contsHint': 'Continents: click to keep one or several', 'dec.allConts': 'All continents',
|
||||||
'dec.minSnrTitle': 'Hide anything weaker than this SNR', 'dec.searchPh': 'Call, grid or message',
|
'dec.minSnrTitle': 'Hide anything weaker than this SNR', 'dec.searchPh': 'Call, grid or message',
|
||||||
'dec.clearFilters': 'Clear', 'dec.live': 'live', 'dec.tx': 'TX',
|
'dec.clearFilters': 'Clear', 'dec.live': 'live', 'dec.tx': 'TX',
|
||||||
@@ -682,7 +682,7 @@ const fr: Dict = {
|
|||||||
'mx.tipThisCall': 'déjà contacté avec cet indicatif',
|
'mx.tipThisCall': 'déjà contacté avec cet indicatif',
|
||||||
'mx.tipThisCallConf': 'déjà confirmé avec cet indicatif',
|
'mx.tipThisCallConf': 'déjà confirmé avec cet indicatif',
|
||||||
// Panneau des decodes FTx (Outils -> Decodes FT)
|
// Panneau des decodes FTx (Outils -> Decodes FT)
|
||||||
'ftmap.tab': 'FT Map', 'ftmap.noGrid': 'Renseigne ton locator dans les Préférences pour placer la carte.', 'dec.tab': 'Decodes FT', 'dec.title': 'Decodes', 'dec.cqOnly': 'CQ seulement',
|
'ftmap.tab': 'FT Map', 'ftmap.noGrid': 'Renseigne ton locator dans les Préférences pour placer la carte.', 'dec.tab': 'Decodes FT', 'dec.title': 'Decodes', 'dec.bandDrift': '{app} annonce {dec}, le poste est sur {rig}', 'dec.bandDriftApp': 'le décodeur', 'dec.bandDriftTip': 'Le logiciel de décodage annonce une bande sur laquelle la radio n’est pas — il a très probablement perdu sa liaison CAT et répète la dernière fréquence connue. Tous les décodages ci-dessous portent cette bande, et les verdicts NOUVEAU / NOUVELLE BANDE sont jugés dessus.', 'dec.cqOnly': 'CQ seulement',
|
||||||
'dec.allBands': 'Toutes bandes', 'dec.allModes': 'Tous modes', 'toast.qsoLogged': 'QSO enregistré', 'dec.contsHint': 'Continents : clique pour en garder un ou plusieurs', 'dec.allConts': 'Tous continents',
|
'dec.allBands': 'Toutes bandes', 'dec.allModes': 'Tous modes', 'toast.qsoLogged': 'QSO enregistré', 'dec.contsHint': 'Continents : clique pour en garder un ou plusieurs', 'dec.allConts': 'Tous continents',
|
||||||
'dec.minSnrTitle': 'Masquer tout ce qui est plus faible que ce rapport', 'dec.searchPh': 'Indicatif, locator ou message',
|
'dec.minSnrTitle': 'Masquer tout ce qui est plus faible que ce rapport', 'dec.searchPh': 'Indicatif, locator ou message',
|
||||||
'dec.clearFilters': 'Effacer', 'dec.live': 'en direct', 'dec.tx': 'TX',
|
'dec.clearFilters': 'Effacer', 'dec.live': 'en direct', 'dec.tx': 'TX',
|
||||||
|
|||||||
Reference in New Issue
Block a user