fix(kenwood): split frequencies swapped on transmit
IF reports the VFO "in use". In split that is the RECEIVE VFO while receiving and the TRANSMIT VFO while transmitting — the backend took it as the receive VFO in both cases. Everything therefore read correctly until the PTT closed and then reversed, which is exactly how it was reported from a TS-590 on USB. The IF frame has carried the transmit bit all along; parseKenwoodIF already decoded it into f.TX. It was simply never consulted here. This is not only a display fault. FreqHz is what a QSO is LOGGED on, so a contact worked in split went into the log on the DX's frequency instead of the operator's — wrong in the log, wrong in every ADIF exported from it, and invisible until someone checked a QSO by hand. The emulated rig in the test package can now be keyed, so the case is pinned from both sides: verified failing without the fix (tx and rx exchanged) and passing with it.
This commit is contained in:
+4
-2
@@ -10,7 +10,8 @@
|
|||||||
"Band-opening detection now works on the bands it was meant for. Switching on \"Watch for band openings\" (Settings › DX Cluster) subscribes to the PSK Reporter feed and adds the two RBN nodes it needs — it was reading a handful of VHF cluster spots while thousands of stations were reporting. It watches 10, 6, 4 and 2 m, counts only reports collected within 300 km of you so an opening means an opening HERE, no longer throws away paths beyond 2400 km, and looks for the busiest direction instead of demanding that every station heard sit in one sector. An opening under way shows as a blinking badge beside the clock until the band goes quiet, and the direction it names is right — a sector crossing north used to be announced as its opposite.",
|
"Band-opening detection now works on the bands it was meant for. Switching on \"Watch for band openings\" (Settings › DX Cluster) subscribes to the PSK Reporter feed and adds the two RBN nodes it needs — it was reading a handful of VHF cluster spots while thousands of stations were reporting. It watches 10, 6, 4 and 2 m, counts only reports collected within 300 km of you so an opening means an opening HERE, no longer throws away paths beyond 2400 km, and looks for the busiest direction instead of demanding that every station heard sit in one sector. An opening under way shows as a blinking badge beside the clock until the band goes quiet, and the direction it names is right — a sector crossing north used to be announced as its opposite.",
|
||||||
"Test connection now actually tests. Club Log checked that the three fields were not empty and reported success without contacting anyone, so a wrong password looked exactly like a right one; it now signs in for real, through the read-only endpoint so a test can never add a record. LoTW reports its two credentials separately: TQSL signs uploads and never uses the website password, so a wrong one used to break nothing until the day confirmations were downloaded.",
|
"Test connection now actually tests. Club Log checked that the three fields were not empty and reported success without contacting anyone, so a wrong password looked exactly like a right one; it now signs in for real, through the read-only endpoint so a test can never add a record. LoTW reports its two credentials separately: TQSL signs uploads and never uses the website password, so a wrong one used to break nothing until the day confirmations were downloaded.",
|
||||||
"The Ultrabeam / SteppIR widget in Station Control can now drive the antenna, not just describe it: a button per configured band tunes it there, up and down move it 25 kHz at a time, and tracking can be switched on or off with its 25 / 50 / 100 kHz threshold beside it. The band you are on lights up, and the commanded frequency is shown in the header.",
|
"The Ultrabeam / SteppIR widget in Station Control can now drive the antenna, not just describe it: a button per configured band tunes it there, up and down move it 25 kHz at a time, and tracking can be switched on or off with its 25 / 50 / 100 kHz threshold beside it. The band you are on lights up, and the commanded frequency is shown in the header.",
|
||||||
"The QSO filter can express a real question. Every condition was joined by one global AND or OR, so \"2 m or 70 cm, in FT8, since January\" had no form: AND killed the two bands, OR let every FT8 QSO through. Two operators — is one of / is none of — take a comma-separated list, so the OR sits inside one condition and the rest keeps ANDing."
|
"The QSO filter can express a real question. Every condition was joined by one global AND or OR, so \"2 m or 70 cm, in FT8, since January\" had no form: AND killed the two bands, OR let every FT8 QSO through. Two operators — is one of / is none of — take a comma-separated list, so the OR sits inside one condition and the rest keeps ANDing.",
|
||||||
|
"Kenwood in split: the transmit and receive frequencies no longer swap the moment you key up. The rig reports the VFO in use, which is the receive one on receive and the transmit one on transmit; OpsLog took it as the receive VFO always. It showed on the display, and it decided which frequency a split QSO was logged on."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
"Décodes digitaux : le carré locator d une station pouvait être enregistré comme son indicatif quand le texte du message sortait de l ordinaire. Un grid à la place de l indicatif est maintenant refusé.",
|
"Décodes digitaux : le carré locator d une station pouvait être enregistré comme son indicatif quand le texte du message sortait de l ordinaire. Un grid à la place de l indicatif est maintenant refusé.",
|
||||||
@@ -20,7 +21,8 @@
|
|||||||
"La détection d ouverture de bande fonctionne enfin sur les bandes visées. Activer « Surveiller les ouvertures de bande » (Paramètres › Cluster DX) souscrit au flux PSK Reporter et ajoute les deux nœuds RBN nécessaires — elle lisait quelques spots VHF du cluster alors que des milliers de stations rapportaient. Elle surveille le 10, 6, 4 et 2 m, ne retient que les reports collectés à moins de 300 km de toi pour qu une ouverture veuille dire une ouverture ICI, ne jette plus les chemins au-delà de 2400 km, et cherche la direction la plus dense au lieu d exiger que toutes les stations entendues soient dans un même secteur. Une ouverture en cours s affiche en pastille clignotante à côté de l heure jusqu à ce que la bande se taise, et la direction annoncée est juste — un secteur traversant le nord était auparavant annoncé à l opposé.",
|
"La détection d ouverture de bande fonctionne enfin sur les bandes visées. Activer « Surveiller les ouvertures de bande » (Paramètres › Cluster DX) souscrit au flux PSK Reporter et ajoute les deux nœuds RBN nécessaires — elle lisait quelques spots VHF du cluster alors que des milliers de stations rapportaient. Elle surveille le 10, 6, 4 et 2 m, ne retient que les reports collectés à moins de 300 km de toi pour qu une ouverture veuille dire une ouverture ICI, ne jette plus les chemins au-delà de 2400 km, et cherche la direction la plus dense au lieu d exiger que toutes les stations entendues soient dans un même secteur. Une ouverture en cours s affiche en pastille clignotante à côté de l heure jusqu à ce que la bande se taise, et la direction annoncée est juste — un secteur traversant le nord était auparavant annoncé à l opposé.",
|
||||||
"Le bouton Tester la connexion teste vraiment. Club Log vérifiait que les trois champs n étaient pas vides et annonçait la réussite sans contacter personne : un mauvais mot de passe ressemblait exactement à un bon. Il s authentifie maintenant pour de vrai, via le point d accès en lecture seule pour qu un test ne puisse jamais ajouter un enregistrement. LoTW annonce ses deux identifiants séparément : TQSL signe les envois et n utilise jamais le mot de passe du site, donc un mauvais ne cassait rien jusqu au jour du téléchargement des confirmations.",
|
"Le bouton Tester la connexion teste vraiment. Club Log vérifiait que les trois champs n étaient pas vides et annonçait la réussite sans contacter personne : un mauvais mot de passe ressemblait exactement à un bon. Il s authentifie maintenant pour de vrai, via le point d accès en lecture seule pour qu un test ne puisse jamais ajouter un enregistrement. LoTW annonce ses deux identifiants séparément : TQSL signe les envois et n utilise jamais le mot de passe du site, donc un mauvais ne cassait rien jusqu au jour du téléchargement des confirmations.",
|
||||||
"Le widget Ultrabeam / SteppIR de Station Control pilote enfin l antenne au lieu de seulement la décrire : un bouton par bande configurée l accorde dessus, haut et bas la déplacent par pas de 25 kHz, et le suivi s active ou se coupe avec son seuil de 25 / 50 / 100 kHz à côté. La bande courante s allume, et la fréquence commandée s affiche dans l en-tête.",
|
"Le widget Ultrabeam / SteppIR de Station Control pilote enfin l antenne au lieu de seulement la décrire : un bouton par bande configurée l accorde dessus, haut et bas la déplacent par pas de 25 kHz, et le suivi s active ou se coupe avec son seuil de 25 / 50 / 100 kHz à côté. La bande courante s allume, et la fréquence commandée s affiche dans l en-tête.",
|
||||||
"Le filtre des QSO sait exprimer une vraie question. Toutes les conditions étaient jointes par un seul ET ou OU global, donc « 2 m ou 70 cm, en FT8, depuis janvier » n avait aucune forme : le ET tuait les deux bandes, le OU laissait passer tous les QSO FT8. Deux opérateurs — est parmi / n est pas parmi — acceptent une liste séparée par des virgules, le OU tient donc dans une seule condition et le reste continue de se combiner en ET."
|
"Le filtre des QSO sait exprimer une vraie question. Toutes les conditions étaient jointes par un seul ET ou OU global, donc « 2 m ou 70 cm, en FT8, depuis janvier » n avait aucune forme : le ET tuait les deux bandes, le OU laissait passer tous les QSO FT8. Deux opérateurs — est parmi / n est pas parmi — acceptent une liste séparée par des virgules, le OU tient donc dans une seule condition et le reste continue de se combiner en ET.",
|
||||||
|
"Kenwood en split : les fréquences d émission et de réception ne s inversent plus dès qu on passe en émission. Le rig annonce le VFO en service, qui est celui de réception à la réception et celui d émission à l émission ; OpsLog le prenait toujours pour celui de réception. Ça se voyait à l affichage, et ça décidait surtout sur quelle fréquence un QSO en split était enregistré."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+24
-4
@@ -377,16 +377,36 @@ func (k *Kenwood) ReadState() (RigState, error) {
|
|||||||
f.Split = split
|
f.Split = split
|
||||||
|
|
||||||
if f.Split {
|
if f.Split {
|
||||||
// The transmit VFO is the other one. Read it rather than assume, and fall
|
// The OTHER VFO is the one IF did not report. Read it rather than assume,
|
||||||
// back to simplex if it cannot be read: a wrong TX frequency is written
|
// and fall back to simplex if it cannot be read: a wrong TX frequency is
|
||||||
// into the log, which is worse than showing no split at all.
|
// written into the log, which is worse than showing no split at all.
|
||||||
other := "FB;"
|
other := "FB;"
|
||||||
if f.VFO == "B" {
|
if f.VFO == "B" {
|
||||||
other = "FA;"
|
other = "FA;"
|
||||||
}
|
}
|
||||||
|
var otherHz int64
|
||||||
if r, err := k.ask(other); err == nil {
|
if r, err := k.ask(other); err == nil {
|
||||||
if hz, ok := parseKenwoodFreq(r, strings.TrimSuffix(other, ";")); ok && hz > 0 && hz != rx {
|
if hz, ok := parseKenwoodFreq(r, strings.TrimSuffix(other, ";")); ok && hz > 0 && hz != rx {
|
||||||
tx = hz
|
otherHz = hz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if otherHz > 0 {
|
||||||
|
// WHICH of the two is the transmit frequency depends on whether the rig
|
||||||
|
// is transmitting RIGHT NOW.
|
||||||
|
//
|
||||||
|
// IF reports the VFO "in use", and in split that is the RECEIVE VFO on
|
||||||
|
// receive and the TRANSMIT VFO on transmit. The code took it as the
|
||||||
|
// receive VFO always, so the moment the operator keyed up the two
|
||||||
|
// frequencies swapped: correct on receive, reversed on transmit, which
|
||||||
|
// is exactly how it was reported from a TS-590 on USB.
|
||||||
|
//
|
||||||
|
// It matters beyond the display. FreqHz is what a QSO is logged on, and
|
||||||
|
// a contact made in split would have gone into the log on the DX's
|
||||||
|
// frequency instead of the operator's.
|
||||||
|
if f.TX {
|
||||||
|
tx, rx = rx, otherHz
|
||||||
|
} else {
|
||||||
|
tx = otherHz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ type ts2000 struct {
|
|||||||
mode byte
|
mode byte
|
||||||
onB bool
|
onB bool
|
||||||
split bool
|
split bool
|
||||||
|
// tx models the rig KEYED. On a real Kenwood in split, IF then reports the
|
||||||
|
// TRANSMIT VFO as the one in use — which is the whole point of the test below.
|
||||||
|
tx bool
|
||||||
// lazyIF models a rig that answers FR/FT correctly but never fills IF's
|
// lazyIF models a rig that answers FR/FT correctly but never fills IF's
|
||||||
// split bit — the behaviour reported on a Flex through its Kenwood CAT
|
// split bit — the behaviour reported on a Flex through its Kenwood CAT
|
||||||
// emulation, where the frequency reads perfectly and split never appears.
|
// emulation, where the frequency reads perfectly and split never appears.
|
||||||
@@ -138,8 +141,12 @@ func (r *ts2000) answer(cmd string) string {
|
|||||||
}
|
}
|
||||||
// The catemu layout: IF | freq(11) | step(4) | RIT(±5) | 3 | mem(2) |
|
// The catemu layout: IF | freq(11) | step(4) | RIT(±5) | 3 | mem(2) |
|
||||||
// rx/tx | mode | VFO | scan | split | tone | tone#(2) | shift | ;
|
// rx/tx | mode | VFO | scan | split | tone | tone#(2) | shift | ;
|
||||||
|
txByte := 0
|
||||||
|
if r.tx {
|
||||||
|
txByte = 1
|
||||||
|
}
|
||||||
return fmt.Sprintf("IF%011d%04d%+06d%03d%02d%01d%c%c%01d%c%01d%02d%01d;",
|
return fmt.Sprintf("IF%011d%04d%+06d%03d%02d%01d%c%c%01d%c%01d%02d%01d;",
|
||||||
cur, 0, 0, 0, 0, 0, r.mode, vfoDigit, 0, split, 0, 0, 0)
|
cur, 0, 0, 0, 0, txByte, r.mode, vfoDigit, 0, split, 0, 0, 0)
|
||||||
case strings.HasPrefix(cmd, "FA") && len(cmd) > 3:
|
case strings.HasPrefix(cmd, "FA") && len(cmd) > 3:
|
||||||
fmt.Sscanf(cmd, "FA%d;", &r.vfoA)
|
fmt.Sscanf(cmd, "FA%d;", &r.vfoA)
|
||||||
return ""
|
return ""
|
||||||
@@ -456,3 +463,43 @@ func TestKenwoodBusyRigKeepsTheLink(t *testing.T) {
|
|||||||
t.Error("a rig refusing IF; forever was still reported as healthy")
|
t.Error("a rig refusing IF; forever was still reported as healthy")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In split, the two frequencies must not swap the moment the operator keys up.
|
||||||
|
//
|
||||||
|
// IF reports the VFO "in use", and in split that is the RECEIVE VFO on receive
|
||||||
|
// and the TRANSMIT VFO on transmit. The backend took it as the receive VFO
|
||||||
|
// always, so everything read correctly until the PTT closed and then reversed —
|
||||||
|
// reported from a TS-590 on USB.
|
||||||
|
//
|
||||||
|
// It matters beyond the display: FreqHz is what a QSO is LOGGED on, so a split
|
||||||
|
// contact would have been logged on the DX's frequency instead of the operator's.
|
||||||
|
func TestKenwoodSplitDoesNotSwapOnTransmit(t *testing.T) {
|
||||||
|
rig := &ts2000{vfoA: 14200000, vfoB: 14205000, mode: '2', split: true}
|
||||||
|
k := NewKenwood("COM-TEST", 9600, "FT8")
|
||||||
|
k.dialPort = dialTo(rig)
|
||||||
|
if err := k.Connect(); err != nil {
|
||||||
|
t.Fatalf("connect: %v", err)
|
||||||
|
}
|
||||||
|
defer k.Disconnect()
|
||||||
|
|
||||||
|
// Receiving: IF reports VFO A, the receive dial.
|
||||||
|
s, err := k.ReadState()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read on receive: %v", err)
|
||||||
|
}
|
||||||
|
if !s.Split || s.FreqHz != 14205000 || s.RxFreqHz != 14200000 {
|
||||||
|
t.Fatalf("on receive: split=%v tx=%d rx=%d — want tx 14205000, rx 14200000",
|
||||||
|
s.Split, s.FreqHz, s.RxFreqHz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keyed: the rig switches to the transmit VFO and sets IF's TX byte.
|
||||||
|
rig.onB, rig.tx = true, true
|
||||||
|
s, err = k.ReadState()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read on transmit: %v", err)
|
||||||
|
}
|
||||||
|
if s.FreqHz != 14205000 || s.RxFreqHz != 14200000 {
|
||||||
|
t.Errorf("on transmit: tx=%d rx=%d — the two swapped; want tx 14205000, rx 14200000",
|
||||||
|
s.FreqHz, s.RxFreqHz)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user