feat(cat): distinct Elecraft K3/K4 backend in the rig list
The Elecraft handling was buried in the Kenwood "data mode" option, so users couldn't find it. Add "Elecraft K3/K4" as its own entry in the CAT backend selector. It reuses the Kenwood-dialect transport and the Kenwood USB/network settings (the K3 emulates the Kenwood command set — a separate transport would be a near-total duplicate), with an `elecraft` flag on the client that forces digital modes to DATA A (MD6+DT0) — no data-mode dropdown needed. RigState still reports Backend "kenwood" so the CW-over-CAT keyer capability keeps working.
This commit is contained in:
@@ -13140,6 +13140,21 @@ func (a *App) reloadCAT() {
|
|||||||
kw.SetDataMode(s.KenwoodDataMode)
|
kw.SetDataMode(s.KenwoodDataMode)
|
||||||
a.cat.Start(kw)
|
a.cat.Start(kw)
|
||||||
}
|
}
|
||||||
|
case "elecraft":
|
||||||
|
// Elecraft K3/K4: the Kenwood-dialect client with the Elecraft specifics on
|
||||||
|
// (digital modes → DATA A via MD6+DT0). Reuses the Kenwood port/baud/host
|
||||||
|
// settings — the K3 emulates the Kenwood command set, so a separate transport
|
||||||
|
// would be a near-total duplicate.
|
||||||
|
if h := strings.TrimSpace(s.KenwoodHost); h != "" {
|
||||||
|
kw := cat.NewKenwoodTCP(h, s.DigitalDefault)
|
||||||
|
kw.SetElecraft(true)
|
||||||
|
a.cat.Start(kw)
|
||||||
|
} else {
|
||||||
|
kw := cat.NewKenwood(s.KenwoodPort, s.KenwoodBaud, s.DigitalDefault)
|
||||||
|
kw.SetLowerLines(s.KenwoodLowLines)
|
||||||
|
kw.SetElecraft(true)
|
||||||
|
a.cat.Start(kw)
|
||||||
|
}
|
||||||
case "icom":
|
case "icom":
|
||||||
// Native Icom CI-V over the radio's USB serial port (local control).
|
// Native Icom CI-V over the radio's USB serial port (local control).
|
||||||
// Same civ protocol the network backend reuses for remote.
|
// Same civ protocol the network backend reuses for remote.
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@
|
|||||||
"UDP outbound: a QSO logged from WSJT-X / JTDX / MSHV (via the inbound UDP listener) is now forwarded to the outbound ADIF integrations too — previously only QSOs typed directly into OpsLog were re-emitted.",
|
"UDP outbound: a QSO logged from WSJT-X / JTDX / MSHV (via the inbound UDP listener) is now forwarded to the outbound ADIF integrations too — previously only QSOs typed directly into OpsLog were re-emitted.",
|
||||||
"Backup: with \"back up on every exit\", a new \"Keep every backup\" sub-option writes a distinct time-stamped file per exit (opslog-YYYY-MM-DD-HHMMSS.db) instead of overwriting the day's file. Rotation still keeps the newest N — raise it for more history.",
|
"Backup: with \"back up on every exit\", a new \"Keep every backup\" sub-option writes a distinct time-stamped file per exit (opslog-YYYY-MM-DD-HHMMSS.db) instead of overwriting the day's file. Rotation still keeps the newest N — raise it for more history.",
|
||||||
"Awards editor: the PRIMARY QSOFIELDS search now has a Prefix field too (prepended to each found reference, e.g. captured 01 → D01) — previously only the OR fallback searches could add a prefix, so a DOK-style award couldn't match on its main rule.",
|
"Awards editor: the PRIMARY QSOFIELDS search now has a Prefix field too (prepended to each found reference, e.g. captured 01 → D01) — previously only the OR fallback searches could add a prefix, so a DOK-style award couldn't match on its main rule.",
|
||||||
"CAT (Elecraft K3/K4): the DATA data-mode now sends MD6 + DT0 (DATA A), the sub-mode FT8 audio actually needs — MD6 alone could leave the rig in an FSK/PSK sub-mode where it keyed but sent no audio. Pick \"DATA A — MD6+DT0 (Elecraft K3/K4)\" under CAT data modes."
|
"CAT: new Elecraft K3/K4 backend in the rig list. Select it (it reuses the Kenwood USB/network settings) and digital modes automatically use DATA A (MD6+DT0) — the sub-mode FT8 audio needs, so the K3 no longer keys the transmitter without modulating."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
"Sauvegarde : nouvelle option \"Sauvegarder à chaque fermeture\" (Réglages → Sauvegarde). Activée, OpsLog sauvegarde la base à chaque fois que tu quittes au lieu d'une seule fois par jour — les QSO d'une seconde session sont ainsi toujours pris.",
|
"Sauvegarde : nouvelle option \"Sauvegarder à chaque fermeture\" (Réglages → Sauvegarde). Activée, OpsLog sauvegarde la base à chaque fois que tu quittes au lieu d'une seule fois par jour — les QSO d'une seconde session sont ainsi toujours pris.",
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"UDP sortant : un QSO enregistré depuis WSJT-X / JTDX / MSHV (via l'écouteur UDP entrant) est désormais aussi transmis aux intégrations ADIF sortantes — avant, seuls les QSO saisis directement dans OpsLog étaient réémis.",
|
"UDP sortant : un QSO enregistré depuis WSJT-X / JTDX / MSHV (via l'écouteur UDP entrant) est désormais aussi transmis aux intégrations ADIF sortantes — avant, seuls les QSO saisis directement dans OpsLog étaient réémis.",
|
||||||
"Sauvegarde : avec \"sauvegarder à chaque fermeture\", une nouvelle sous-option \"Garder chaque sauvegarde\" écrit un fichier horodaté distinct par fermeture (opslog-AAAA-MM-JJ-HHMMSS.db) au lieu d'écraser le fichier du jour. La rotation garde les N plus récents — augmente-la pour plus d'historique.",
|
"Sauvegarde : avec \"sauvegarder à chaque fermeture\", une nouvelle sous-option \"Garder chaque sauvegarde\" écrit un fichier horodaté distinct par fermeture (opslog-AAAA-MM-JJ-HHMMSS.db) au lieu d'écraser le fichier du jour. La rotation garde les N plus récents — augmente-la pour plus d'historique.",
|
||||||
"Éditeur de diplômes : la recherche PRINCIPALE QSOFIELDS a aussi un champ Préfixe (ajouté devant chaque référence trouvée, ex. 01 capturé → D01) — avant, seules les recherches OR de repli pouvaient ajouter un préfixe, empêchant un diplôme type DOK de matcher sur sa règle principale.",
|
"Éditeur de diplômes : la recherche PRINCIPALE QSOFIELDS a aussi un champ Préfixe (ajouté devant chaque référence trouvée, ex. 01 capturé → D01) — avant, seules les recherches OR de repli pouvaient ajouter un préfixe, empêchant un diplôme type DOK de matcher sur sa règle principale.",
|
||||||
"CAT (Elecraft K3/K4) : le mode data DATA envoie désormais MD6 + DT0 (DATA A), le sous-mode dont l'audio FT8 a réellement besoin — MD6 seul pouvait laisser le rig dans un sous-mode FSK/PSK où il passait en émission sans audio. Choisis \"DATA A — MD6+DT0 (Elecraft K3/K4)\" dans les modes data CAT."
|
"CAT : nouveau backend Elecraft K3/K4 dans la liste des rigs. Sélectionne-le (il réutilise les réglages USB/réseau Kenwood) et les modes numériques passent automatiquement en DATA A (MD6+DT0) — le sous-mode dont l'audio FT8 a besoin, donc le K3 ne passe plus en émission sans moduler."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2527,6 +2527,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
|||||||
<SelectItem value="flex">{t('cat.optFlex')}</SelectItem>
|
<SelectItem value="flex">{t('cat.optFlex')}</SelectItem>
|
||||||
<SelectItem value="yaesu">{t('cat.optYaesu')}</SelectItem>
|
<SelectItem value="yaesu">{t('cat.optYaesu')}</SelectItem>
|
||||||
<SelectItem value="kenwood">{t('cat.optKenwood')}</SelectItem>
|
<SelectItem value="kenwood">{t('cat.optKenwood')}</SelectItem>
|
||||||
|
<SelectItem value="elecraft">{t('cat.optElecraft')}</SelectItem>
|
||||||
<SelectItem value="xiegu">{t('cat.optXiegu')}</SelectItem>
|
<SelectItem value="xiegu">{t('cat.optXiegu')}</SelectItem>
|
||||||
<SelectItem value="icom">{t('cat.optIcom')}</SelectItem>
|
<SelectItem value="icom">{t('cat.optIcom')}</SelectItem>
|
||||||
<SelectItem value="icom-net">{t('cat.optIcomNet')}</SelectItem>
|
<SelectItem value="icom-net">{t('cat.optIcomNet')}</SelectItem>
|
||||||
@@ -2688,7 +2689,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
|||||||
{t('cat.civTrace')}
|
{t('cat.civTrace')}
|
||||||
</label> </div>
|
</label> </div>
|
||||||
)}
|
)}
|
||||||
{catCfg.backend === 'kenwood' && (
|
{(catCfg.backend === 'kenwood' || catCfg.backend === 'elecraft') && (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>{t('cat.kenwoodPort')}</Label>
|
<Label>{t('cat.kenwoodPort')}</Label>
|
||||||
@@ -2725,16 +2726,21 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
|||||||
</label>
|
</label>
|
||||||
<span className="text-xs text-muted-foreground">{t('cat.lowerLinesHint')}</span>
|
<span className="text-xs text-muted-foreground">{t('cat.lowerLinesHint')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1">
|
{catCfg.backend === 'kenwood' ? (
|
||||||
<Label>{t('cat.kwDataMode')}</Label>
|
<div className="space-y-1">
|
||||||
<Select value={(catCfg as any).kenwood_data_mode || 'usb'} onValueChange={(v) => setCatCfg((s) => ({ ...s, kenwood_data_mode: v } as any))}>
|
<Label>{t('cat.kwDataMode')}</Label>
|
||||||
<SelectTrigger className="h-8"><SelectValue /></SelectTrigger>
|
<Select value={(catCfg as any).kenwood_data_mode || 'usb'} onValueChange={(v) => setCatCfg((s) => ({ ...s, kenwood_data_mode: v } as any))}>
|
||||||
<SelectContent>
|
<SelectTrigger className="h-8"><SelectValue /></SelectTrigger>
|
||||||
<SelectItem value="usb">{t('cat.kwDataUsb')}</SelectItem>
|
<SelectContent>
|
||||||
<SelectItem value="data">{t('cat.kwDataMd6')}</SelectItem>
|
<SelectItem value="usb">{t('cat.kwDataUsb')}</SelectItem>
|
||||||
<SelectItem value="keep">{t('cat.kwDataKeep')}</SelectItem>
|
<SelectItem value="data">{t('cat.kwDataMd6')}</SelectItem>
|
||||||
</SelectContent>
|
<SelectItem value="keep">{t('cat.kwDataKeep')}</SelectItem>
|
||||||
</Select> </div>
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span className="text-xs text-muted-foreground">{t('cat.elecraftHint')}</span>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{catCfg.backend === 'icom' && (
|
{catCfg.backend === 'icom' && (
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -62,6 +62,10 @@ type Kenwood struct {
|
|||||||
// leave the rig's current mode untouched (safest for a TS-590SG/TS-990S whose
|
// leave the rig's current mode untouched (safest for a TS-590SG/TS-990S whose
|
||||||
// data mode is a USB modifier the operator sets on the rig). See SetMode.
|
// data mode is a USB modifier the operator sets on the rig). See SetMode.
|
||||||
dataMode string
|
dataMode string
|
||||||
|
// elecraft marks a K3/K4 (the "Elecraft" backend). It reuses this Kenwood-dialect
|
||||||
|
// client but, being an Elecraft, always drives digital modes to DATA A (MD6+DT0)
|
||||||
|
// — the sub-mode FT8 audio needs — instead of going through the dataMode option.
|
||||||
|
elecraft bool
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
port serial.Port
|
port serial.Port
|
||||||
@@ -391,6 +395,14 @@ func (k *Kenwood) SetMode(mode string) error {
|
|||||||
// mode digit fits every rig, so the operator picks: keep the rig's mode, use
|
// mode digit fits every rig, so the operator picks: keep the rig's mode, use
|
||||||
// MD6 (K3/K4 DATA), or fall through to the default USB from kenwoodModeDigit.
|
// MD6 (K3/K4 DATA), or fall through to the default USB from kenwoodModeDigit.
|
||||||
if isKenwoodDataMode(mode) {
|
if isKenwoodDataMode(mode) {
|
||||||
|
// An Elecraft always uses DATA A for a soundcard digital mode — that's what
|
||||||
|
// the "Elecraft" backend means, so the dataMode option doesn't apply.
|
||||||
|
if k.elecraft {
|
||||||
|
if err := k.write("MD6;"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return k.write("DT0;")
|
||||||
|
}
|
||||||
switch k.dataMode {
|
switch k.dataMode {
|
||||||
case "keep":
|
case "keep":
|
||||||
return nil // leave whatever data mode the operator set on the rig
|
return nil // leave whatever data mode the operator set on the rig
|
||||||
@@ -424,6 +436,14 @@ func (k *Kenwood) SetDataMode(m string) {
|
|||||||
k.mu.Unlock()
|
k.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetElecraft marks this client as driving a K3/K4 (the "Elecraft" backend), so
|
||||||
|
// digital modes always land in DATA A (MD6+DT0). Set before Start.
|
||||||
|
func (k *Kenwood) SetElecraft(v bool) {
|
||||||
|
k.mu.Lock()
|
||||||
|
k.elecraft = v
|
||||||
|
k.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// isKenwoodDataMode reports whether a mode name is a soundcard/data mode (FT8,
|
// isKenwoodDataMode reports whether a mode name is a soundcard/data mode (FT8,
|
||||||
// PSK, JT…) rather than a voice/CW/RTTY mode the rig sets natively.
|
// PSK, JT…) rather than a voice/CW/RTTY mode the rig sets natively.
|
||||||
func isKenwoodDataMode(mode string) bool {
|
func isKenwoodDataMode(mode string) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user