fix: <LOGQSO> logs immediately at its position instead of waiting the full CW-duration estimate first (buffered keyers keep sending; logging never interrupts them) — was delaying the log up to ~10s; only the final segment still waits, for auto-call timing

This commit is contained in:
2026-07-21 16:01:15 +02:00
parent 54dd109288
commit 1f54656256
+27 -21
View File
@@ -2147,39 +2147,45 @@ export default function App() {
// Split the macro on <LOGQSO> so the log happens AT the token's position, not // Split the macro on <LOGQSO> so the log happens AT the token's position, not
// only at the very end: "TU <LOGQSO> QRZ" sends "TU", logs, then sends "QRZ". // only at the very end: "TU <LOGQSO> QRZ" sends "TU", logs, then sends "QRZ".
// Each split boundary (every part except the last) is one <LOGQSO>. // Each split boundary (every part except the last) is one <LOGQSO>.
const parts = rawText.split(/<LOGQSO>/i); // RESOLVE every segment up front — while the form still holds the callsign — so a
// segment AFTER the <LOGQSO> (which logs and clears the form) still expands its
// variables correctly.
const parts = rawText.split(/<LOGQSO>/i).map((pt) => resolveCW(pt));
const isRig = cwSourceRef.current === 'icom' || cwSourceRef.current === 'flex'; const isRig = cwSourceRef.current === 'icom' || cwSourceRef.current === 'flex';
for (let p = 0; p < parts.length; p++) { for (let p = 0; p < parts.length; p++) {
if (aborted()) return; // ESC / Stop before this segment → stop sending, don't log if (aborted()) return; // ESC / Stop before this segment → stop sending, don't log
const resolved = resolveCW(parts[p]); const resolved = parts[p];
const isLast = p === parts.length - 1;
const logAfter = !isLast; // a <LOGQSO> follows this segment
if (resolved) { if (resolved) {
// Trailing word space so back-to-back sends don't run together in the keyer // Trailing word space so back-to-back sends don't run together in the keyer
// buffer ("CQ"+"TEST" → "CQTEST"); the keyer keys it as a word gap at the // buffer ("CQ"+"TEST" → "CQTEST"); the keyer keys it as a word gap at the
// current WPM, so it scales automatically. // current WPM, so it scales automatically.
const keyed = resolved + ' '; const keyed = resolved + ' ';
setWkSent(resolved); setWkSent(resolved);
if (isRig) { const sendFn = cwSourceRef.current === 'flex' ? FlexSendCW : cwSourceRef.current === 'icom' ? IcomSendCW : null;
// The rig keyer (Icom 0x17 / Flex CWX) gives no busy echo we track, so if (sendFn) await sendFn(keyed).catch((e) => setError(String(e?.message ?? e)));
// wait the ESTIMATED send duration before moving on / logging. else await WinkeyerSend(keyed).catch((e) => setError(String(e?.message ?? e)));
const sendFn = cwSourceRef.current === 'flex' ? FlexSendCW : IcomSendCW; // Only WAIT for the CW to finish on the FINAL segment — auto-call needs the
await sendFn(keyed).catch((e) => setError(String(e?.message ?? e))); // send done before its gap+resend. A segment a <LOGQSO> follows is NOT waited
await waitMs(Math.round(estimateCwMs(resolved, wkWpm)) + (p < parts.length - 1 ? 200 : 600)); // on: the keyer has already buffered the CW, so logging happens AT ONCE and
} else { // never interrupts what's being sent. (Gating the log on a CW-length ESTIMATE
await WinkeyerSend(keyed).catch((e) => setError(String(e?.message ?? e))); // made <LOGQSO> log up to ~10s late when the estimate ran long.)
// Wait for the keyer to actually finish this segment before we log / if (isLast) {
// continue. We'd like to watch busy rise then fall, but over a if (isRig) {
// remote/serial-over-IP link that echo can lag tens of seconds, so cap await waitMs(Math.round(estimateCwMs(resolved, wkWpm)) + 600);
// the wait at the ESTIMATED send duration + slack: proceed when busy } else {
// clears OR the estimate elapses, whichever comes first. // WinKeyer: watch the busy echo, capped by the estimate (+slack) since
const capMs = Math.round(estimateCwMs(resolved, wkWpm) * 1.4) + 2500; // over a remote/serial-over-IP link that echo can lag tens of seconds.
for (let i = 0; i < 20 && !wkBusyRef.current && !aborted(); i++) await sleep(50); // ≤1s to start const capMs = Math.round(estimateCwMs(resolved, wkWpm) * 1.4) + 2500;
const deadline = Date.now() + capMs; for (let i = 0; i < 20 && !wkBusyRef.current && !aborted(); i++) await sleep(50); // ≤1s to start
while (wkBusyRef.current && !aborted() && Date.now() < deadline) await sleep(50); const deadline = Date.now() + capMs;
while (wkBusyRef.current && !aborted() && Date.now() < deadline) await sleep(50);
}
} }
} }
if (aborted()) return; // aborted while this segment was sending → don't log if (aborted()) return; // aborted while this segment was sending → don't log
// A <LOGQSO> token follows every part except the last → log the contact here. if (logAfter) void save(); // log NOW — the buffered CW keeps sending
if (p < parts.length - 1) void save();
} }
} }
// stopAutoCall cancels any running auto-call loop. // stopAutoCall cancels any running auto-call loop.