fix(rst): a change of mode changes the notation
An operator with a callsign in the field, switching FT8 to SSB, kept "+00" as the report. The edited flag protects a report the operator chose — 57 rather than 59 — and it was holding across a change of mode as well, where it protects nothing: a decibel figure is not a weak SSB report, it is not a report at all. Worse, anything that fills the field from the rig sets that flag too (the S-meter readouts in the rig consoles), so the field could be stuck in the wrong notation for the rest of the QSO. The flag now holds only while the report still belongs to the mode's family. When it does not, the operator's own judgement is carried across where it can be — 57 becomes 579, 599 becomes 59 — and the mode's preset answers where it cannot.
This commit is contained in:
+4
-2
@@ -10,7 +10,8 @@
|
||||
"Auto-call never parks a watched callsign. After a few series of unanswered calls a station is set aside for the session — the right answer for one the LOG picked out, the wrong one for a station YOU named: a DXpedition running a pileup takes more than two series to get through to, which is exactly why it is on the list. The rest between series still applies.",
|
||||
"Right-click → Send to: an upload to a service with no credentials is refused, and says which ones are missing and where. It used to run on its own and report into the QSL Manager’s console, which is not open when the command came from the QSO list — so it looked exactly like an upload that worked. Cloudlog / Wavelog and HamQTH also name themselves properly in the toast.",
|
||||
"[NEW] The mouse wheel steps the RST fields, in the entry strip and in the QSO editor. It counts the way an operator does — 57, 58, 59, 59+5, 59+10, 59+15, 59+20 — one S-unit up to nine and then five decibels at a time, and one decibel on a digital report. R and T do not move. The dropdown beside them lists the reports worth having to hand, not every legal one, so the wheel works on the value rather than walking the list.",
|
||||
"PSK Reporter panel: with the whole-band scope, clicking a decode no longer resets the report count to zero. The window there belongs to the BAND — every FTx report on it, filtered by target only when the analysis is drawn — and it was being emptied on every target change, throwing away an hour of evidence at the exact moment it was worth something. The narrow scope still clears it, because there the window is one station’s."
|
||||
"PSK Reporter panel: with the whole-band scope, clicking a decode no longer resets the report count to zero. The window there belongs to the BAND — every FTx report on it, filtered by target only when the analysis is drawn — and it was being emptied on every target change, throwing away an hour of evidence at the exact moment it was worth something. The narrow scope still clears it, because there the window is one station’s.",
|
||||
"Changing mode with a callsign in the field now fixes the report. The “the operator chose this report” flag was holding across a change of mode, where it means nothing — “+00” is not a weak SSB report, it is not a report at all — and anything that fills the field from the rig (the S-meter readouts in the rig consoles) sets that flag too, so it could stay in the wrong notation for the whole QSO. A judgement that can be carried across is carried (57 → 579, 599 → 59); otherwise the mode’s preset answers."
|
||||
],
|
||||
"fr": [
|
||||
"L’auto-call voit un décodage qui arrive après les autres. Un décodeur envoie une période en rafale, puis les retardataires — un décodage « deep » une seconde plus tard — et le retardataire était jugé tout seul, sans les trente stations de sa propre période. La période reste maintenant ouverte jusqu’au début de la suivante, et un arrivant tardif est pesé face à l’ensemble.",
|
||||
@@ -20,7 +21,8 @@
|
||||
"L’auto-call ne met jamais de côté un indicatif de la watchlist. Après quelques séries d’appels sans réponse, une station est écartée pour la session — la bonne réponse pour une station choisie par le CARNET, la mauvaise pour une station que VOUS avez nommée : un DX en pile-up demande plus de deux séries pour passer, et c’est précisément pour ça qu’il est sur la liste. Le repos entre séries s’applique toujours.",
|
||||
"Clic droit → Envoyer vers : un envoi vers un service non configuré est refusé, en disant ce qui manque et où. Il partait tout seul et rendait compte dans la console du gestionnaire QSL, qui n’est pas ouverte quand la commande vient de la liste des QSO — ça ressemblait donc exactement à un envoi réussi. Cloudlog / Wavelog et HamQTH s’annoncent aussi sous leur nom dans le message.",
|
||||
"[NEW] La molette fait défiler les champs RST, dans la barre de saisie comme dans l’éditeur de QSO. Elle compte comme un opérateur — 57, 58, 59, 59+5, 59+10, 59+15, 59+20 — un point S jusqu’à neuf puis cinq décibels à la fois, et un décibel sur un report numérique. R et T ne bougent pas. La liste déroulante à côté contient les reports qu’on veut sous la main, pas tous les reports légaux : la molette agit donc sur la valeur plutôt que de parcourir la liste.",
|
||||
"Panneau PSK Reporter : en portée « toute la bande », cliquer sur un décodage ne remet plus le nombre de reports à zéro. La fenêtre appartient là à la BANDE — tous les reports FTx qui y circulent, filtrés par cible seulement à l’affichage — et elle était vidée à chaque changement de cible, jetant une heure d’observations au moment précis où elles servent. La portée étroite continue de la vider : là, la fenêtre est celle d’une seule station."
|
||||
"Panneau PSK Reporter : en portée « toute la bande », cliquer sur un décodage ne remet plus le nombre de reports à zéro. La fenêtre appartient là à la BANDE — tous les reports FTx qui y circulent, filtrés par cible seulement à l’affichage — et elle était vidée à chaque changement de cible, jetant une heure d’observations au moment précis où elles servent. La portée étroite continue de la vider : là, la fenêtre est celle d’une seule station.",
|
||||
"Changer de mode avec un indicatif dans le champ corrige désormais le report. Le drapeau « l’opérateur a choisi ce report » tenait au travers d’un changement de mode, où il ne veut rien dire — « +00 » n’est pas un report SSB faible, ce n’est pas un report du tout — et tout ce qui remplit le champ depuis le poste (les lectures S-mètre des consoles) lève ce drapeau aussi : la notation pouvait rester fausse pour tout le QSO. Un jugement transposable l’est (57 → 579, 599 → 59) ; sinon le préréglage du mode répond."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
+25
-4
@@ -150,7 +150,7 @@ import { cn } from '@/lib/utils';
|
||||
import { pathBetween, pathBetweenLatLon, gridToLatLon, latLonToGrid } from '@/lib/maidenhead';
|
||||
import { flagURL } from '@/lib/flags';
|
||||
import { LogViewer } from '@/components/LogViewer';
|
||||
import { stepRST } from '@/lib/rst';
|
||||
import { convertRST, rstFitsMode, stepRST } from '@/lib/rst';
|
||||
|
||||
type QSO = QSOForm;
|
||||
type ImportResult = adifModels.ImportResult;
|
||||
@@ -658,6 +658,11 @@ export default function App() {
|
||||
useEffect(() => { rstListsRef.current = rstLists; }, [rstLists]);
|
||||
const [rstSent, setRstSent] = useState('59');
|
||||
const [rstRcvd, setRstRcvd] = useState('59');
|
||||
// Read by applyModePreset, which runs from those same long-lived closures.
|
||||
const rstSentRef = useRef(rstSent);
|
||||
const rstRcvdRef = useRef(rstRcvd);
|
||||
useEffect(() => { rstSentRef.current = rstSent; }, [rstSent]);
|
||||
useEffect(() => { rstRcvdRef.current = rstRcvd; }, [rstRcvd]);
|
||||
const [grid, setGrid] = useState('');
|
||||
const [name, setName] = useState('');
|
||||
const [qth, setQth] = useState('');
|
||||
@@ -3341,15 +3346,31 @@ export default function App() {
|
||||
return m;
|
||||
}
|
||||
function applyModePreset(m: string) {
|
||||
if (rstUserEditedRef.current) return;
|
||||
// AN EDIT IS ABOUT A SIGNAL, NOT ABOUT A NOTATION.
|
||||
//
|
||||
// The edited flag protects a report the operator chose — 57 rather than 59 —
|
||||
// and it used to protect it across a change of mode as well, where it means
|
||||
// nothing: "+00" is not a weak SSB report, it is not a report at all. An
|
||||
// operator with a callsign in the field, switching from FT8 to SSB, was left
|
||||
// with a decibel figure to log, and anything that fills the report from the
|
||||
// rig (the S-meter readouts in the rig consoles) sets that flag too — so the
|
||||
// field could be stuck in the wrong notation for the rest of the QSO.
|
||||
//
|
||||
// So the flag holds only while the report still belongs to the mode. When it
|
||||
// does not, the judgement is carried across where it can be (57 → 579,
|
||||
// 599 → 59) and the preset answers where it cannot.
|
||||
const fits = rstFitsMode(rstSentRef.current, m) && rstFitsMode(rstRcvdRef.current, m);
|
||||
if (rstUserEditedRef.current && fits) return;
|
||||
// Prefer the user's configured preset RST; otherwise fall back to the mode
|
||||
// category default (CW/RTTY/PSK → 599, phone → 59, digital → first option)
|
||||
// so switching SSB→CW flips 59→599 even without a configured preset.
|
||||
// Read through the refs, never the state: see their declaration.
|
||||
const p = modePresetsRef.current.find((x) => x.name === m);
|
||||
const fallback = rstOptions(m, rstListsRef.current)[0] || '';
|
||||
setRstSent(p?.default_rst_sent || fallback);
|
||||
setRstRcvd(p?.default_rst_rcvd || fallback);
|
||||
const keep = (cur: string, preset: string) =>
|
||||
(rstUserEditedRef.current && convertRST(cur, m)) || preset || fallback;
|
||||
setRstSent(keep(rstSentRef.current, p?.default_rst_sent || ''));
|
||||
setRstRcvd(keep(rstRcvdRef.current, p?.default_rst_rcvd || ''));
|
||||
}
|
||||
// Clicking a spot (cluster grid or any band map): tune the rig, set the mode,
|
||||
// fill the call, pre-fill POTA, (re)start the recording. Shared so every spot
|
||||
|
||||
@@ -86,3 +86,35 @@ export function stepRST(value: string, dir: number, mode: string): string {
|
||||
}
|
||||
return head + String(sUnit) + tone + (over > 0 ? '+' + over : '');
|
||||
}
|
||||
|
||||
// rstFitsMode says whether a report belongs to the family a mode reports in.
|
||||
//
|
||||
// The three families are written differently and are not interchangeable: a
|
||||
// signed decibel figure ("+00"), a three-figure RST ("599"), a two-figure RS
|
||||
// ("59", with an optional "+20" above S9). "+00" on SSB is not a weak report,
|
||||
// it is not a report at all.
|
||||
export function rstFitsMode(value: string, mode: string): boolean {
|
||||
const v = (value || '').trim();
|
||||
if (v === '') return false;
|
||||
switch (rstCategory(mode)) {
|
||||
case 'digital': return /^[+-]\d{1,2}$/.test(v);
|
||||
case 'cw': return /^\d{3}(\+\d+)?$/.test(v);
|
||||
default: return /^\d{2}(\+\d+)?$/.test(v);
|
||||
}
|
||||
}
|
||||
|
||||
// convertRST carries a report across the CW/phone divide, keeping the operator's
|
||||
// own judgement of the signal: 57 becomes 579, 599 becomes 59.
|
||||
//
|
||||
// Only between those two — a decibel figure says nothing about readability and
|
||||
// an RST says nothing in decibels, so there the preset is the honest answer.
|
||||
// Returns '' when it cannot be done.
|
||||
export function convertRST(value: string, toMode: string): string {
|
||||
const v = (value || '').trim();
|
||||
const to = rstCategory(toMode);
|
||||
if (to === 'digital') return '';
|
||||
const m = /^(\d)(\d)(\d?)((?:\+\d+)?)$/.exec(v);
|
||||
if (!m) return '';
|
||||
if (to === 'cw') return m[1] + m[2] + '9' + m[4]; // RS → RST, tone 9
|
||||
return m[1] + m[2] + m[4]; // RST → RS, tone dropped
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user