fix: CW speed drove the wrong keyer; survey the meters to find the SWR one
Speed: with DTR/RTS line keying the PC does the timing, so the Yaesu console's slider — which sets the rig's internal keyer — changed nothing audible and looked broken. Both entry points now go through one handler that drives the engine actually sending, and additionally sets the rig's own keyer whenever a Yaesu is on CAT, so the radio's front panel shows the same figure. SWR: an operator reads 80 on the bar with a real SWR of 1.1. That is the shape of reading the WRONG METER — ALC, say — not of a scaling error, and which RM index carries which meter is not consistent across the family. Rather than guess again and move the wrong number somewhere else, the first transmission now logs RM1 through RM6 raw, once. The log will say which index is which on this radio, and the mapping can then be corrected as a fact.
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
"version": "0.21.9",
|
"version": "0.21.9",
|
||||||
"date": "2026-07-28",
|
"date": "2026-07-28",
|
||||||
"en": [
|
"en": [
|
||||||
|
"CW speed is now one setting wherever you change it: the Yaesu console slider and the CW panel drive the keyer that is actually sending, and the rig own keyer follows so its front panel agrees.",
|
||||||
"Antenna Genius: port A no longer jumps onto port B antenna a few seconds after a change. Only one port can hold the transmit antenna, so the switch reports the same one on both — the display now follows each port own receive antenna.",
|
"Antenna Genius: port A no longer jumps onto port B antenna a few seconds after a change. Only one port can hold the transmit antenna, so the switch reports the same one on both — the display now follows each port own receive antenna.",
|
||||||
"CW through the Yaesu keyer: a fifth CW engine sends your macros with the radio own keyer (CAT \"KY\"), for the FTDX101 / FT-991A / FT-710 family. An FTDX10 does not accept it — DAKY included — and OpsLog says so, pointing to the serial DTR keyer on the rig second COM port, which works.",
|
"CW through the Yaesu keyer: a fifth CW engine sends your macros with the radio own keyer (CAT \"KY\"), for the FTDX101 / FT-991A / FT-710 family. An FTDX10 does not accept it — DAKY included — and OpsLog says so, pointing to the serial DTR keyer on the rig second COM port, which works.",
|
||||||
"CW through the Yaesu keyer: a fifth CW engine sends your macros with the radio own keyer (CAT \"KY\") — no WinKeyer, no second cable. Pick \"Yaesu (rig keyer)\" in Settings → CW keyer, with the Yaesu CAT backend active.",
|
"CW through the Yaesu keyer: a fifth CW engine sends your macros with the radio own keyer (CAT \"KY\") — no WinKeyer, no second cable. Pick \"Yaesu (rig keyer)\" in Settings → CW keyer, with the Yaesu CAT backend active.",
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
"CQ and ITU zones you correct by hand in your profile stay corrected. They are derived from cty.dat, which gives the zones of the whole entity — in a country spanning several, the automatic value is wrong and it came back at every restart. They now only fill in when empty, and recompute when the callsign or grid changes."
|
"CQ and ITU zones you correct by hand in your profile stay corrected. They are derived from cty.dat, which gives the zones of the whole entity — in a country spanning several, the automatic value is wrong and it came back at every restart. They now only fill in when empty, and recompute when the callsign or grid changes."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
|
"La vitesse CW est désormais un réglage unique où que vous la changiez : le curseur de la console Yaesu et le panneau CW pilotent le manipulateur qui émet réellement, et le keyer interne de la radio suit pour que sa façade affiche la même valeur.",
|
||||||
"Antenna Genius : le port A ne bascule plus sur l'antenne du port B quelques secondes après un changement. Un seul port peut porter l'antenne d'émission, le switch renvoie donc la même sur les deux — l'affichage suit désormais l'antenne de réception propre à chaque port.",
|
"Antenna Genius : le port A ne bascule plus sur l'antenne du port B quelques secondes après un changement. Un seul port peut porter l'antenne d'émission, le switch renvoie donc la même sur les deux — l'affichage suit désormais l'antenne de réception propre à chaque port.",
|
||||||
"CW par le keyer Yaesu : un cinquième moteur CW envoie vos macros avec le keyer de la radio (CAT « KY »), pour la famille FTDX101 / FT-991A / FT-710. Un FTDX10 ne l'accepte pas — DAKY compris — et OpsLog le dit en renvoyant vers le keyer série DTR sur son second port COM, qui fonctionne.",
|
"CW par le keyer Yaesu : un cinquième moteur CW envoie vos macros avec le keyer de la radio (CAT « KY »), pour la famille FTDX101 / FT-991A / FT-710. Un FTDX10 ne l'accepte pas — DAKY compris — et OpsLog le dit en renvoyant vers le keyer série DTR sur son second port COM, qui fonctionne.",
|
||||||
"CW par le keyer Yaesu : un cinquième moteur CW envoie vos macros avec le keyer de la radio (CAT « KY ») — sans WinKeyer ni second câble. À choisir dans Réglages → Keyer CW sous « Yaesu (keyer de la radio) », avec le backend CAT Yaesu actif.",
|
"CW par le keyer Yaesu : un cinquième moteur CW envoie vos macros avec le keyer de la radio (CAT « KY ») — sans WinKeyer ni second câble. À choisir dans Réglages → Keyer CW sous « Yaesu (keyer de la radio) », avec le backend CAT Yaesu actif.",
|
||||||
|
|||||||
+25
-9
@@ -503,6 +503,9 @@ export default function App() {
|
|||||||
|
|
||||||
// CAT — receives live rig state via Wails events.
|
// CAT — receives live rig state via Wails events.
|
||||||
const [catState, setCatState] = useState<CATState>({ enabled: false, connected: false } as any);
|
const [catState, setCatState] = useState<CATState>({ enabled: false, connected: false } as any);
|
||||||
|
// Live copy for callbacks that must not close over a stale snapshot.
|
||||||
|
const catStateRef = useRef(catState);
|
||||||
|
useEffect(() => { catStateRef.current = catState; }, [catState]);
|
||||||
// Configured CAT backend ('icom' USB vs 'icom-net'): the live catState.backend
|
// Configured CAT backend ('icom' USB vs 'icom-net'): the live catState.backend
|
||||||
// is "icom" for BOTH, so we track the settings value to tell them apart (used to
|
// is "icom" for BOTH, so we track the settings value to tell them apart (used to
|
||||||
// hide the rig ON/OFF buttons on USB, where the interface is unpowered when the
|
// hide the rig ON/OFF buttons on USB, where the interface is unpowered when the
|
||||||
@@ -966,6 +969,25 @@ export default function App() {
|
|||||||
// auto-call and <LOGQSO> are shared; only the transport differs.
|
// auto-call and <LOGQSO> are shared; only the transport differs.
|
||||||
const [wkEngine, setWkEngine] = useState<string>('winkeyer');
|
const [wkEngine, setWkEngine] = useState<string>('winkeyer');
|
||||||
const cwSource: 'winkeyer' | 'icom' | 'flex' | 'yaesu' = wkEngine === 'icom' ? 'icom' : wkEngine === 'flex' ? 'flex' : wkEngine === 'yaesu' ? 'yaesu' : 'winkeyer';
|
const cwSource: 'winkeyer' | 'icom' | 'flex' | 'yaesu' = wkEngine === 'icom' ? 'icom' : wkEngine === 'flex' ? 'flex' : wkEngine === 'yaesu' ? 'yaesu' : 'winkeyer';
|
||||||
|
// Setting the CW speed has to reach the keyer that is ACTUALLY sending, and
|
||||||
|
// both the CW panel and the Yaesu console can ask for it. With DTR/RTS line
|
||||||
|
// keying the PC does the timing, so the rig's internal keyer speed changes
|
||||||
|
// nothing audible — the Yaesu console's slider looked broken because it drove
|
||||||
|
// that one alone. It now drives both: the rig's keyer for its own front panel,
|
||||||
|
// and the engine doing the work.
|
||||||
|
const setCWSpeedEverywhere = useCallback((w: number) => {
|
||||||
|
setWkWpm(w); saveWk({ wpm: w });
|
||||||
|
const src = cwSourceRef.current;
|
||||||
|
if (src === 'icom') IcomSetKeySpeed(w).catch(() => {});
|
||||||
|
else if (src === 'flex') FlexSetKeySpeed(w).catch(() => {});
|
||||||
|
else if (src === 'yaesu') SetYaesuKeySpeed(w).catch(() => {});
|
||||||
|
else WinkeyerSetSpeed(w).catch(() => {});
|
||||||
|
// The rig's own keyer follows too whenever a Yaesu is on CAT, even when it is
|
||||||
|
// not the sending engine: its front panel and OpsLog then agree.
|
||||||
|
if (src !== 'yaesu' && catStateRef.current?.backend === 'yaesu') {
|
||||||
|
SetYaesuKeySpeed(w).catch(() => {});
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
const cwSourceRef = useRef(cwSource);
|
const cwSourceRef = useRef(cwSource);
|
||||||
useEffect(() => { cwSourceRef.current = cwSource; }, [cwSource]);
|
useEffect(() => { cwSourceRef.current = cwSource; }, [cwSource]);
|
||||||
// CW break-in (0=OFF, 1=SEMI, 2=FULL) — must be on for the rig's 0x17 keyer to
|
// CW break-in (0=OFF, 1=SEMI, 2=FULL) — must be on for the rig's 0x17 keyer to
|
||||||
@@ -4295,7 +4317,7 @@ export default function App() {
|
|||||||
case 'yaesu':
|
case 'yaesu':
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-full min-h-0 rounded-lg overflow-hidden border border-border">
|
<div className="h-full w-full min-h-0 rounded-lg overflow-hidden border border-border">
|
||||||
<YaesuPanel onReportRST={(r) => { setRstSent(r); rstUserEditedRef.current = true; }} />
|
<YaesuPanel onReportRST={(r) => { setRstSent(r); rstUserEditedRef.current = true; }} onKeySpeed={setCWSpeedEverywhere} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case 'icom':
|
case 'icom':
|
||||||
@@ -5245,13 +5267,7 @@ export default function App() {
|
|||||||
onRefreshPorts={reloadWkPorts}
|
onRefreshPorts={reloadWkPorts}
|
||||||
onConnect={() => WinkeyerConnect().catch((e) => setError(String(e?.message ?? e)))}
|
onConnect={() => WinkeyerConnect().catch((e) => setError(String(e?.message ?? e)))}
|
||||||
onDisconnect={() => WinkeyerDisconnect().catch(() => {})}
|
onDisconnect={() => WinkeyerDisconnect().catch(() => {})}
|
||||||
onSetSpeed={(w) => {
|
onSetSpeed={setCWSpeedEverywhere}
|
||||||
setWkWpm(w); saveWk({ wpm: w });
|
|
||||||
if (cwSource === 'icom') IcomSetKeySpeed(w).catch(() => {});
|
|
||||||
else if (cwSource === 'flex') FlexSetKeySpeed(w).catch(() => {});
|
|
||||||
else if (cwSource === 'yaesu') SetYaesuKeySpeed(w).catch(() => {});
|
|
||||||
else WinkeyerSetSpeed(w).catch(() => {});
|
|
||||||
}}
|
|
||||||
onSend={wkSend}
|
onSend={wkSend}
|
||||||
onSendMacro={wkSendMacro}
|
onSendMacro={wkSendMacro}
|
||||||
onStop={() => { stopAutoCall(); stopKeyerTx(); }}
|
onStop={() => { stopAutoCall(); stopKeyerTx(); }}
|
||||||
@@ -5813,7 +5829,7 @@ export default function App() {
|
|||||||
{/* Yaesu CAT control panel — only when the CAT backend is a Yaesu. */}
|
{/* Yaesu CAT control panel — only when the CAT backend is a Yaesu. */}
|
||||||
{catState.backend === 'yaesu' && (
|
{catState.backend === 'yaesu' && (
|
||||||
<TabsContent value="yaesu" className="flex-1 min-h-0 p-0">
|
<TabsContent value="yaesu" className="flex-1 min-h-0 p-0">
|
||||||
<YaesuPanel onReportRST={(r) => { setRstSent(r); rstUserEditedRef.current = true; }} />
|
<YaesuPanel onReportRST={(r) => { setRstSent(r); rstUserEditedRef.current = true; }} onKeySpeed={setCWSpeedEverywhere} />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -223,7 +223,14 @@ function Row({ label, children }: { label: string; children: React.ReactNode })
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function YaesuPanel({ onReportRST }: { onReportRST?: (rst: string) => void }) {
|
export function YaesuPanel({ onReportRST, onKeySpeed }: {
|
||||||
|
onReportRST?: (rst: string) => void;
|
||||||
|
// Told whenever the operator moves the CW speed here, so the app can keep the
|
||||||
|
// keyer that is ACTUALLY sending in step. With DTR/RTS line keying the PC does
|
||||||
|
// the timing and the rig's internal keyer speed changes nothing audible — the
|
||||||
|
// slider looked broken because it was driving the wrong keyer.
|
||||||
|
onKeySpeed?: (wpm: number) => void;
|
||||||
|
}) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const [st, setSt] = useState<YaesuState>(ZERO);
|
const [st, setSt] = useState<YaesuState>(ZERO);
|
||||||
// The frequency being LISTENED to. RigState follows ADIF, where freq_hz is the
|
// The frequency being LISTENED to. RigState follows ADIF, where freq_hz is the
|
||||||
@@ -465,7 +472,7 @@ export function YaesuPanel({ onReportRST }: { onReportRST?: (rst: string) => voi
|
|||||||
<Card icon={Radio} title={t('yaesu.cw')}>
|
<Card icon={Radio} title={t('yaesu.cw')}>
|
||||||
<Row label="SPEED">
|
<Row label="SPEED">
|
||||||
<Slider value={view.key_speed || 20} min={4} max={60} accent="var(--primary)"
|
<Slider value={view.key_speed || 20} min={4} max={60} accent="var(--primary)"
|
||||||
onChange={(v) => push('key_speed', v, () => SetYaesuKeySpeed(v))} />
|
onChange={(v) => { push('key_speed', v, () => SetYaesuKeySpeed(v)); onKeySpeed?.(v); }} />
|
||||||
<span className="w-12 text-right text-xs font-mono tabular-nums text-muted-foreground">{view.key_speed || 20} wpm</span>
|
<span className="w-12 text-right text-xs font-mono tabular-nums text-muted-foreground">{view.key_speed || 20} wpm</span>
|
||||||
</Row>
|
</Row>
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ type Yaesu struct {
|
|||||||
panelLoaded bool
|
panelLoaded bool
|
||||||
// Commands this rig answered "?;" to — asked once, then never again.
|
// Commands this rig answered "?;" to — asked once, then never again.
|
||||||
unsupported map[string]bool
|
unsupported map[string]bool
|
||||||
|
// metersSurveyed: the one-shot RM1..RM6 dump during the first transmission.
|
||||||
|
metersSurveyed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewYaesu(portName string, baud int, digital string) *Yaesu {
|
func NewYaesu(portName string, baud int, digital string) *Yaesu {
|
||||||
|
|||||||
@@ -121,6 +121,26 @@ func (y *Yaesu) readPanel(mode string, split bool, txHz int64) {
|
|||||||
y.panel.SMeter = scale255(v)
|
y.panel.SMeter = scale255(v)
|
||||||
}
|
}
|
||||||
if y.panel.Transmitting {
|
if y.panel.Transmitting {
|
||||||
|
// One-shot survey of every meter while transmitting.
|
||||||
|
//
|
||||||
|
// Which RM index carries which meter is NOT the same across the family, and
|
||||||
|
// an operator reported an SWR bar at 80 with a real SWR of 1.1 — the shape
|
||||||
|
// of reading the wrong index (ALC, say) rather than of a scaling error.
|
||||||
|
// Guessing again would just move the wrong number; this prints all six
|
||||||
|
// once, and the log then says which is which on THIS radio.
|
||||||
|
if !y.metersSurveyed {
|
||||||
|
y.metersSurveyed = true
|
||||||
|
raw := make([]string, 0, 6)
|
||||||
|
for i := 1; i <= 6; i++ {
|
||||||
|
cmd := fmt.Sprintf("RM%d;", i)
|
||||||
|
if v, ok := y.askNum(cmd, fmt.Sprintf("RM%d", i), 3); ok {
|
||||||
|
raw = append(raw, fmt.Sprintf("RM%d=%d", i, v))
|
||||||
|
} else {
|
||||||
|
raw = append(raw, fmt.Sprintf("RM%d=-", i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debugLog.Printf("yaesu: meters while transmitting: %s (send this if a bar reads wrong)", strings.Join(raw, " "))
|
||||||
|
}
|
||||||
if v, ok := y.askNum("RM4;", "RM4", 3); ok {
|
if v, ok := y.askNum("RM4;", "RM4", 3); ok {
|
||||||
y.panel.PowerMeter = scale255(v)
|
y.panel.PowerMeter = scale255(v)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user