Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3745d23339 |
+4
-2
@@ -15,7 +15,8 @@
|
||||
"Audio: the Listening device now says when it cannot be opened. A device unplugged, renamed by Windows or unable to run at 16 kHz failed silently while everything upstream reported success — the stream up, the packets arriving, the monitor started — which is the whole of “I turned the sound on and nothing comes out”. The log also says, once, whether the network RX audio is reaching the speakers or arriving with nobody listening.",
|
||||
"ADIF export: a record is written on one line again. ADDRESS is a multi-line field by the standard and callbooks and other loggers fill it that way — “Kabul”, four blank lines, “Afghanistan” — and OpsLog wrote it out as it was, so a record ran down a dozen lines with the next apparently starting in the middle of the page. Line breaks inside a value are now joined with a comma, which is how an address reads on one line anyway. The files were always valid (ADIF counts bytes); they were unreadable.",
|
||||
"Club Log uploads are no longer refused as “not configured”. The check added for services with no credentials demanded a Club Log API key, which nobody has ever set — OpsLog carries its own application key — so an operator whose live upload had worked for months was turned away when sending QSOs by hand. Each service’s requirements now live beside the uploader that enforces them, and the message names the fields that are actually missing.",
|
||||
"FT map: the callsign, square and report show on hover again. The invisible circle that catches the clicks sits on top of the dot, so it takes the hover too — and the label was bound only to the dot underneath, which left the map silent from the moment the stations became clickable."
|
||||
"FT map: the callsign, square and report show on hover again. The invisible circle that catches the clicks sits on top of the dot, so it takes the hover too — and the label was bound only to the dot underneath, which left the map silent from the moment the stations became clickable.",
|
||||
"Yaesu CAT now drives the older radios. The FTDX10, FT-991A, FT-891 and FT-710 write a frequency in nine digits; everything before them — FTDX3000, FTDX5000, FTDX1200, FT-2000, FT-950, FT-450 — writes eight and answers a nine-digit command with a rejection, which is what an FTDX3000 owner saw: every FA refused and a radio that would not follow. The width is taken from the rig’s own reply rather than from a table of models, so a set is in the format that radio speaks — including models this backend has never heard of."
|
||||
],
|
||||
"fr": [
|
||||
"[NEW] Les couleurs de mise en évidence WSJT-X / JTDX sont au choix (Réglages → UDP), une par verdict — watchlist, nouveau DXCC, nouvelle bande, contactée. Seul le fond se règle : la couleur du texte en est déduite, pour qu’une couleur choisie ne revienne jamais illisible dans la fenêtre du décodeur. L’option « griser les stations déjà contactées » garde sa raison d’être — elle décide SI les doublons sont marqués, pas de quelle couleur — et s’appelle désormais « Marquer les stations déjà contactées ».",
|
||||
@@ -30,7 +31,8 @@
|
||||
"Audio : le périphérique d’écoute signale désormais quand il ne peut pas s’ouvrir. Un périphérique débranché, renommé par Windows ou incapable de fonctionner en 16 kHz échouait en silence pendant que tout en amont annonçait le succès — flux ouvert, paquets reçus, moniteur démarré — ce qui est exactement le « j’ai remis le son et rien ne sort ». Le journal dit aussi, une fois, si l’audio réseau atteint les haut-parleurs ou arrive sans que personne n’écoute.",
|
||||
"Export ADIF : un enregistrement tient de nouveau sur une ligne. ADDRESS est un champ multiligne selon la norme, et les callbooks comme les autres logiciels le remplissent ainsi — « Kabul », quatre lignes vides, « Afghanistan » — qu’OpsLog recopiait tel quel : un enregistrement s’étalait sur une douzaine de lignes, le suivant semblant commencer au milieu de la page. Les retours à la ligne dans une valeur sont désormais réunis par une virgule, ce qui est de toute façon la façon de lire une adresse sur une ligne. Les fichiers étaient valides (l’ADIF compte les octets) ; ils étaient illisibles.",
|
||||
"Les envois vers Club Log ne sont plus refusés comme « non configuré ». Le contrôle ajouté pour les services sans identifiants réclamait une clé API Club Log que personne n’a jamais saisie — OpsLog embarque la sienne — et un opérateur dont l’envoi automatique fonctionnait depuis des mois se voyait éconduit au moment d’envoyer des QSO à la main. Les exigences de chaque service vivent désormais à côté du code qui les applique, et le message nomme les champs réellement manquants.",
|
||||
"Carte FTx : l’indicatif, le locator et le report réapparaissent au survol. Le cercle invisible qui capte les clics est au-dessus du point, donc il capte aussi le survol — et l’étiquette n’était liée qu’au point du dessous, ce qui rendait la carte muette dès que les stations sont devenues cliquables."
|
||||
"Carte FTx : l’indicatif, le locator et le report réapparaissent au survol. Le cercle invisible qui capte les clics est au-dessus du point, donc il capte aussi le survol — et l’étiquette n’était liée qu’au point du dessous, ce qui rendait la carte muette dès que les stations sont devenues cliquables.",
|
||||
"Le CAT Yaesu pilote désormais les postes plus anciens. FTDX10, FT-991A, FT-891 et FT-710 écrivent une fréquence sur neuf chiffres ; tout ce qui précède — FTDX3000, FTDX5000, FTDX1200, FT-2000, FT-950, FT-450 — l’écrit sur huit et rejette une commande à neuf chiffres. C’est ce que voyait un possesseur de FTDX3000 : chaque FA refusée et une radio qui ne suivait pas. Le format est pris dans la réponse du poste plutôt que dans une table de modèles : l’envoi part donc dans la langue de cette radio-là, y compris pour des modèles que ce backend ne connaît pas."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
+59
-2
@@ -59,6 +59,13 @@ var yaesuModels = map[string]string{
|
||||
"0650": "FT-891",
|
||||
"0670": "FT-DX3000",
|
||||
"0460": "FT-450D",
|
||||
// The eight-digit family. Named for the console; the frequency format is
|
||||
// learned from the rig either way (see learnFreqWidth).
|
||||
"0251": "FT-2000",
|
||||
"0310": "FT-950",
|
||||
"0583": "FTDX1200",
|
||||
"0462": "FTDX3000",
|
||||
"0101": "FTDX5000",
|
||||
}
|
||||
|
||||
// yaesuModeToADIF maps the MD digit to an ADIF mode. The DATA and RTTY variants
|
||||
@@ -100,6 +107,9 @@ type Yaesu struct {
|
||||
// rxVFOCmd is "FR" when the rig reports its receive VFO that way, else empty
|
||||
// and VS is used — see ReadState.
|
||||
rxVFOCmd string
|
||||
// freqDigits is how many digits this rig writes a frequency in, LEARNED from
|
||||
// its own replies. See setFreqWidth.
|
||||
freqDigits int
|
||||
|
||||
curFreq int64
|
||||
curRXFreq int64
|
||||
@@ -275,6 +285,7 @@ func (y *Yaesu) ReadState() (RigState, error) {
|
||||
if err != nil {
|
||||
return RigState{}, err // the rig stopped answering — let the Manager reconnect
|
||||
}
|
||||
y.learnFreqWidth(faRaw, "FA")
|
||||
freqA, ok := parseYaesuFreq(faRaw, "FA")
|
||||
if !ok {
|
||||
return RigState{}, fmt.Errorf("yaesu: unparsable FA reply %q", faRaw)
|
||||
@@ -355,7 +366,7 @@ func (y *Yaesu) SetFrequency(hz int64) error {
|
||||
if y.curVFO == "B" {
|
||||
cmd = "FB"
|
||||
}
|
||||
return y.write(fmt.Sprintf("%s%09d;", cmd, hz))
|
||||
return y.write(fmt.Sprintf("%s%0*d;", cmd, y.freqWidth(), hz))
|
||||
}
|
||||
|
||||
func (y *Yaesu) SetMode(mode string) error {
|
||||
@@ -481,7 +492,53 @@ func cmdPrefix(cmd string) string {
|
||||
return c
|
||||
}
|
||||
|
||||
// parseYaesuFreq reads "FA014074000;" into Hz.
|
||||
// EIGHT DIGITS OR NINE — the rig says which, and it is not a matter of taste.
|
||||
//
|
||||
// The FTDX10, FT-991A, FT-891 and FT-710 write a frequency in nine digits;
|
||||
// everything before them — FTDX3000, FTDX5000, FTDX1200, FT-2000, FT-950,
|
||||
// FT-450 — writes eight, and answers a nine-digit SET with "?;". An operator
|
||||
// with an FTDX3000 saw exactly that: every FA command rejected, a radio that
|
||||
// would not follow, and nothing to say why.
|
||||
//
|
||||
// The width is LEARNED rather than tabulated: the rig announces it in every
|
||||
// reply to "FA;", so the answer comes from the radio in front of the operator
|
||||
// instead of from a list of models that will always be one release behind. Nine
|
||||
// until the first reply lands, which is what the modern rigs use and what this
|
||||
// backend was written against.
|
||||
const yaesuFreqDigitsDefault = 9
|
||||
|
||||
func (y *Yaesu) freqWidth() int {
|
||||
if y.freqDigits >= 8 && y.freqDigits <= 11 {
|
||||
return y.freqDigits
|
||||
}
|
||||
return yaesuFreqDigitsDefault
|
||||
}
|
||||
|
||||
// learnFreqWidth takes the width from a frequency reply. Only a reply that
|
||||
// parses as a frequency teaches anything — a "?;" or a stray frame says nothing
|
||||
// about the format, and a width learned from one would be worse than the
|
||||
// default.
|
||||
func (y *Yaesu) learnFreqWidth(reply, prefix string) {
|
||||
r := strings.TrimSpace(reply)
|
||||
if !strings.HasPrefix(r, prefix) {
|
||||
return
|
||||
}
|
||||
digits := strings.TrimSuffix(strings.TrimPrefix(r, prefix), ";")
|
||||
if len(digits) < 8 || len(digits) > 11 {
|
||||
return
|
||||
}
|
||||
for _, c := range digits {
|
||||
if c < '0' || c > '9' {
|
||||
return
|
||||
}
|
||||
}
|
||||
if y.freqDigits != len(digits) {
|
||||
debugLog.Printf("yaesu: this rig writes frequencies in %d digits — commands will match", len(digits))
|
||||
y.freqDigits = len(digits)
|
||||
}
|
||||
}
|
||||
|
||||
// parseYaesuFreq reads "FA014074000;" (or "FA14074000;") into Hz.
|
||||
func parseYaesuFreq(reply, prefix string) (int64, bool) {
|
||||
r := strings.TrimSpace(reply)
|
||||
if !strings.HasPrefix(r, prefix) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package cat
|
||||
|
||||
import "testing"
|
||||
|
||||
// The FTDX10 family writes a frequency in nine digits; everything before it —
|
||||
// FTDX3000, FTDX5000, FTDX1200, FT-2000, FT-950, FT-450 — writes eight and
|
||||
// answers a nine-digit SET with "?;". Reported from an FTDX3000: every FA
|
||||
// command rejected, a radio that would not follow.
|
||||
//
|
||||
// The width is taken from the rig's own reply, so a model this backend has
|
||||
// never heard of is right on the first read.
|
||||
func TestYaesuFrequencyWidthIsLearnedFromTheRig(t *testing.T) {
|
||||
y := &Yaesu{}
|
||||
if got := y.freqWidth(); got != 9 {
|
||||
t.Errorf("before any reply the width is %d, want the modern 9", got)
|
||||
}
|
||||
|
||||
y.learnFreqWidth("FA14074000;", "FA") // an FTDX3000
|
||||
if got := y.freqWidth(); got != 8 {
|
||||
t.Errorf("width %d after an eight-digit reply, want 8", got)
|
||||
}
|
||||
|
||||
y.learnFreqWidth("FA014074000;", "FA") // and an FTDX10 on the next session
|
||||
if got := y.freqWidth(); got != 9 {
|
||||
t.Errorf("width %d after a nine-digit reply, want 9", got)
|
||||
}
|
||||
|
||||
// Nothing that is not a frequency teaches anything: a rejection, a stray
|
||||
// frame or a reply from another command would otherwise set the format for
|
||||
// every command that follows.
|
||||
for _, junk := range []string{"?;", "FA;", "FB014074000;", "FA1407400X;", "FA1234567;", "FA123456789012;"} {
|
||||
before := y.freqWidth()
|
||||
y.learnFreqWidth(junk, "FA")
|
||||
if after := y.freqWidth(); after != before {
|
||||
t.Errorf("%q changed the width from %d to %d", junk, before, after)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user