fix(qsl): every confirmation service has a default, and the wiki explains them
HAMLOG.online was added after most profiles were configured, so it had no entry in the shipped defaults and no stored value either: it came back blank, and blank is not a status anybody chose. Every service now starts the same way — the sent side at R, the received side at N — and a blank left by a service that did not exist when the operator last saved is filled in from that. A status they chose themselves is untouched. Two tests hold the line: no sent side may default to Y, and no field may be left without a default. Y means "already sent", so it makes the uploader skip the contact for ever — an operator with eQSL Sent at Y had a logbook that never reached eQSL, and the only trace was one line in the application log. Wiki, both from operator reports: QSL Management opens with Confirmations — what the page actually is (the status stamped on every new QSO, not an action), what each status does, and the warning about Y in the plainest words available, because it fails silently and by design. Digital Modes and GridTracker is new. Unicast and multicast explained from the operating problem rather than the networking: one letterbox that two programs watch, against a broadcast everyone can tune to. It carries the real evidence — two starts of one station an hour apart, decodes in the second and none in the first, the only difference being whether GridTracker or OpsLog reached port 2237 first — then the settings for WSJT-X, JTDX, MSHV, GridTracker and OpsLog, the 127.0.0.1-in-the-group-box mistake, what to do if unicast is unavoidable, and how to check it from the log. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
@@ -11139,6 +11139,19 @@ func (a *App) UILog(msg string) {
|
|||||||
// that hasn't customised them: request the online confirmations (eQSL/LoTW/
|
// that hasn't customised them: request the online confirmations (eQSL/LoTW/
|
||||||
// Clublog/HRDLog/QRZ "sent"=R so OpsLog knows they still need uploading), and
|
// Clublog/HRDLog/QRZ "sent"=R so OpsLog knows they still need uploading), and
|
||||||
// "N" for paper and everything received.
|
// "N" for paper and everything received.
|
||||||
|
// defaultQSLDefaults is the status stamped on a new QSO when the operator has
|
||||||
|
// not chosen otherwise.
|
||||||
|
//
|
||||||
|
// One rule, for every service: the SENT side starts at R (requested — this
|
||||||
|
// contact is waiting to go out) and the RECEIVED side at N (nothing has come
|
||||||
|
// back yet). Paper QSL is the exception on the sent side: a card is only
|
||||||
|
// "requested" once somebody asks for one.
|
||||||
|
//
|
||||||
|
// The sent side must NEVER default to Y. Y means "already sent", so the
|
||||||
|
// uploader skips the contact for ever — which is exactly how an operator ends
|
||||||
|
// up with a logbook that never reaches eQSL and no error to explain it. Every
|
||||||
|
// service added here has to appear in this list for that reason; a service left
|
||||||
|
// out gets an empty status, which is a state nobody chose.
|
||||||
func defaultQSLDefaults() QSLDefaults {
|
func defaultQSLDefaults() QSLDefaults {
|
||||||
return QSLDefaults{
|
return QSLDefaults{
|
||||||
QSLSent: "N", QSLRcvd: "N",
|
QSLSent: "N", QSLRcvd: "N",
|
||||||
@@ -11146,10 +11159,40 @@ func defaultQSLDefaults() QSLDefaults {
|
|||||||
LOTWSent: "R", LOTWRcvd: "N",
|
LOTWSent: "R", LOTWRcvd: "N",
|
||||||
ClublogStatus: "R", ClublogCfm: "N", HRDLogStatus: "R",
|
ClublogStatus: "R", ClublogCfm: "N", HRDLogStatus: "R",
|
||||||
HamqthStatus: "R",
|
HamqthStatus: "R",
|
||||||
|
HamlogStatus: "R", HamlogCfm: "N",
|
||||||
QRZComStatus: "R", QRZComCfm: "N",
|
QRZComStatus: "R", QRZComCfm: "N",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fillMissingQSLDefaults replaces an empty status with the shipped one.
|
||||||
|
//
|
||||||
|
// A service added to OpsLog after an operator last saved their confirmations
|
||||||
|
// has no stored value, so it came back blank — and blank is not one of the
|
||||||
|
// statuses anything acts on, it is the absence of one. HAMLOG.online arrived
|
||||||
|
// that way and every existing profile got nothing for it.
|
||||||
|
//
|
||||||
|
// An operator who genuinely wants a column left alone has "N" for that, which
|
||||||
|
// says the same thing and is a status. So an empty value here means "this was
|
||||||
|
// never asked", and the answer is what a fresh profile would have got.
|
||||||
|
func fillMissingQSLDefaults(d QSLDefaults) QSLDefaults {
|
||||||
|
def := defaultQSLDefaults()
|
||||||
|
for _, f := range []struct{ cur, def *string }{
|
||||||
|
{&d.QSLSent, &def.QSLSent}, {&d.QSLRcvd, &def.QSLRcvd},
|
||||||
|
{&d.LOTWSent, &def.LOTWSent}, {&d.LOTWRcvd, &def.LOTWRcvd},
|
||||||
|
{&d.EQSLSent, &def.EQSLSent}, {&d.EQSLRcvd, &def.EQSLRcvd},
|
||||||
|
{&d.ClublogStatus, &def.ClublogStatus}, {&d.ClublogCfm, &def.ClublogCfm},
|
||||||
|
{&d.HRDLogStatus, &def.HRDLogStatus},
|
||||||
|
{&d.QRZComStatus, &def.QRZComStatus}, {&d.QRZComCfm, &def.QRZComCfm},
|
||||||
|
{&d.HamlogStatus, &def.HamlogStatus}, {&d.HamlogCfm, &def.HamlogCfm},
|
||||||
|
{&d.HamqthStatus, &def.HamqthStatus},
|
||||||
|
} {
|
||||||
|
if strings.TrimSpace(*f.cur) == "" {
|
||||||
|
*f.cur = *f.def
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) GetQSLDefaults() (QSLDefaults, error) {
|
func (a *App) GetQSLDefaults() (QSLDefaults, error) {
|
||||||
out := QSLDefaults{}
|
out := QSLDefaults{}
|
||||||
if a.settings == nil {
|
if a.settings == nil {
|
||||||
@@ -11186,7 +11229,7 @@ func (a *App) GetQSLDefaults() (QSLDefaults, error) {
|
|||||||
out.HamlogStatus = m[keyQSLDefaultHamlogStatus]
|
out.HamlogStatus = m[keyQSLDefaultHamlogStatus]
|
||||||
out.HamqthStatus = m[keyQSLDefaultHamqthStatus]
|
out.HamqthStatus = m[keyQSLDefaultHamqthStatus]
|
||||||
out.HamlogCfm = m[keyQSLDefaultHamlogCfm]
|
out.HamlogCfm = m[keyQSLDefaultHamlogCfm]
|
||||||
return out, nil
|
return fillMissingQSLDefaults(out), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveQSLDefaults persists the configured defaults. Future QSO inserts
|
// SaveQSLDefaults persists the configured defaults. Future QSO inserts
|
||||||
|
|||||||
+4
-2
@@ -4,11 +4,13 @@
|
|||||||
"date": "",
|
"date": "",
|
||||||
"en": [
|
"en": [
|
||||||
"After an update, OpsLog starts again. The fix that stopped Defender calling the updater a trojan removed the helper that waited for the old process to die, and nothing took over the job: the new instance was patient with the single-instance lock for twenty seconds while the old one is allowed thirty to shut down — closing a remote logbook, a CAT session, sometimes a backup. Where that ran long the new process gave up in silence, leaving no window and a leftover OpsLog in the task manager. It now waits for the previous process itself, ending the instant it does; and if it really has not gone, it says so instead of claiming OpsLog is already running.",
|
"After an update, OpsLog starts again. The fix that stopped Defender calling the updater a trojan removed the helper that waited for the old process to die, and nothing took over the job: the new instance was patient with the single-instance lock for twenty seconds while the old one is allowed thirty to shut down — closing a remote logbook, a CAT session, sometimes a backup. Where that ran long the new process gave up in silence, leaving no window and a leftover OpsLog in the task manager. It now waits for the previous process itself, ending the instant it does; and if it really has not gone, it says so instead of claiming OpsLog is already running.",
|
||||||
"A UDP row set to multicast on an address that is not one now listens anyway. 127.0.0.1 in the group box is the common mistake — it is the address every other field in every other program wants — but a multicast group runs 224.0.0.0 to 239.255.255.255, and joining anything else failed on every interface with a Windows error naming nothing the operator had typed. The row simply did not run. It now listens on unicast, which is what such an address means, and says so in the log."
|
"A UDP row set to multicast on an address that is not one now listens anyway. 127.0.0.1 in the group box is the common mistake — it is the address every other field in every other program wants — but a multicast group runs 224.0.0.0 to 239.255.255.255, and joining anything else failed on every interface with a Windows error naming nothing the operator had typed. The row simply did not run. It now listens on unicast, which is what such an address means, and says so in the log.",
|
||||||
|
"The confirmation defaults added for the newest services were blank. HAMLOG.online arrived after most profiles were set up, so it had no default at all — and blank is not a status anybody chose. Every service now starts the same way: the sent side at R (waiting to go out), the received side at N. A blank left by a service that did not exist when you last saved is filled in; a status you chose yourself is untouched."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
"Après une mise à jour, OpsLog redémarre. Le correctif qui a fait cesser la détection en cheval de Troie a supprimé l'assistant qui attendait la mort de l'ancien processus, et rien n'a repris ce travail : la nouvelle instance patientait vingt secondes sur le verrou d'instance unique alors que l'ancienne dispose de trente pour se fermer — elle referme un journal distant, une session CAT, parfois une sauvegarde. Quand cela durait, le nouveau processus abandonnait en silence : pas de fenêtre, et un OpsLog restant dans le gestionnaire des tâches. Il attend désormais l'ancien processus lui-même, et repart à l'instant où celui-ci s'arrête ; et s'il n'est vraiment pas parti, il le dit au lieu d'annoncer qu'OpsLog tourne déjà.",
|
"Après une mise à jour, OpsLog redémarre. Le correctif qui a fait cesser la détection en cheval de Troie a supprimé l'assistant qui attendait la mort de l'ancien processus, et rien n'a repris ce travail : la nouvelle instance patientait vingt secondes sur le verrou d'instance unique alors que l'ancienne dispose de trente pour se fermer — elle referme un journal distant, une session CAT, parfois une sauvegarde. Quand cela durait, le nouveau processus abandonnait en silence : pas de fenêtre, et un OpsLog restant dans le gestionnaire des tâches. Il attend désormais l'ancien processus lui-même, et repart à l'instant où celui-ci s'arrête ; et s'il n'est vraiment pas parti, il le dit au lieu d'annoncer qu'OpsLog tourne déjà.",
|
||||||
"Une ligne UDP réglée en multicast sur une adresse qui n'en est pas une écoute désormais quand même. 127.0.0.1 dans le champ groupe est l'erreur classique — c'est l'adresse que réclame tout autre champ de tout autre programme — mais un groupe multicast va de 224.0.0.0 à 239.255.255.255, et rejoindre autre chose échouait sur toutes les interfaces avec une erreur Windows ne nommant rien de ce que l'opérateur avait saisi. La ligne ne tournait tout simplement pas. Elle écoute maintenant en unicast, ce que veut dire une telle adresse, et le dit dans le journal."
|
"Une ligne UDP réglée en multicast sur une adresse qui n'en est pas une écoute désormais quand même. 127.0.0.1 dans le champ groupe est l'erreur classique — c'est l'adresse que réclame tout autre champ de tout autre programme — mais un groupe multicast va de 224.0.0.0 à 239.255.255.255, et rejoindre autre chose échouait sur toutes les interfaces avec une erreur Windows ne nommant rien de ce que l'opérateur avait saisi. La ligne ne tournait tout simplement pas. Elle écoute maintenant en unicast, ce que veut dire une telle adresse, et le dit dans le journal.",
|
||||||
|
"Les statuts par défaut des services les plus récents étaient vides. HAMLOG.online est arrivé après la configuration de la plupart des profils : il n'avait donc aucun défaut — et vide n'est pas un statut que quelqu'un a choisi. Chaque service démarre désormais pareil : côté envoi R (en attente de départ), côté réception N. Un vide laissé par un service qui n'existait pas lors de votre dernier enregistrement est comblé ; un statut que vous avez choisi n'est pas touché."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The sent side must never start at Y.
|
||||||
|
//
|
||||||
|
// Y means "already sent", so the uploader skips the contact for ever. An
|
||||||
|
// operator whose eQSL default was Y had a logbook that never reached eQSL and
|
||||||
|
// nothing on screen to explain it — the log said "not eligible, EQSLSent
|
||||||
|
// already Y" and that is the only place it was ever said.
|
||||||
|
func TestNoConfirmationDefaultsToAlreadySent(t *testing.T) {
|
||||||
|
d := defaultQSLDefaults()
|
||||||
|
v := reflect.ValueOf(d)
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
name := v.Type().Field(i).Name
|
||||||
|
val := strings.ToUpper(strings.TrimSpace(v.Field(i).String()))
|
||||||
|
if val == "Y" {
|
||||||
|
t.Errorf("%s defaults to Y — every new QSO would be skipped by its uploader for ever", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every field has a default. A service added without one comes back blank,
|
||||||
|
// which is not a status anybody chose — HAMLOG.online arrived that way and
|
||||||
|
// every existing profile got nothing for it.
|
||||||
|
func TestEveryConfirmationHasADefault(t *testing.T) {
|
||||||
|
d := defaultQSLDefaults()
|
||||||
|
v := reflect.ValueOf(d)
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
if strings.TrimSpace(v.Field(i).String()) == "" {
|
||||||
|
t.Errorf("%s has no default — add it to defaultQSLDefaults", v.Type().Field(i).Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A profile saved before a service existed has no value stored for it, and
|
||||||
|
// gets the shipped one rather than a blank.
|
||||||
|
func TestStoredBlanksAreFilledFromTheDefaults(t *testing.T) {
|
||||||
|
// What an old profile looks like: the services it knew about are set, the
|
||||||
|
// ones added later are empty.
|
||||||
|
stored := QSLDefaults{
|
||||||
|
QSLSent: "N", QSLRcvd: "N",
|
||||||
|
EQSLSent: "R", EQSLRcvd: "N",
|
||||||
|
LOTWSent: "R", LOTWRcvd: "N",
|
||||||
|
ClublogStatus: "R", ClublogCfm: "N", HRDLogStatus: "R",
|
||||||
|
QRZComStatus: "R", QRZComCfm: "N",
|
||||||
|
}
|
||||||
|
got := fillMissingQSLDefaults(stored)
|
||||||
|
if got.HamlogStatus != "R" || got.HamlogCfm != "N" || got.HamqthStatus != "R" {
|
||||||
|
t.Errorf("services added later were left blank: hamlog=%q/%q hamqth=%q",
|
||||||
|
got.HamlogStatus, got.HamlogCfm, got.HamqthStatus)
|
||||||
|
}
|
||||||
|
// And a value the operator DID choose is untouched.
|
||||||
|
chosen := QSLDefaults{QSLSent: "I", EQSLSent: "N"}
|
||||||
|
filled := fillMissingQSLDefaults(chosen)
|
||||||
|
if filled.QSLSent != "I" || filled.EQSLSent != "N" {
|
||||||
|
t.Errorf("a chosen status was overwritten: %q / %q", filled.QSLSent, filled.EQSLSent)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,15 @@ WSJT-X and MSHV normally broadcast to a **multicast group** (usually
|
|||||||
give the group. A program sending to one address only needs unicast — leave it
|
give the group. A program sending to one address only needs unicast — leave it
|
||||||
unticked.
|
unticked.
|
||||||
|
|
||||||
|
If you also run **GridTracker**, or anything else that listens to your decoder,
|
||||||
|
read [[Digital Modes and GridTracker]] first: two programs on one unicast port
|
||||||
|
work or not depending on which started first, which is the usual cause of
|
||||||
|
"the decodes arrived yesterday and not today".
|
||||||
|
|
||||||
|
A multicast group is an address between `224.0.0.0` and `239.255.255.255`.
|
||||||
|
`127.0.0.1` is not one — a row ticked *Multicast* with a loopback or LAN
|
||||||
|
address in the group box listens on unicast instead, and says so in the log.
|
||||||
|
|
||||||
> **Do not put an inbound row and an outbound row on the same port.** OpsLog
|
> **Do not put an inbound row and an outbound row on the same port.** OpsLog
|
||||||
> then receives its own messages, and something it publishes can come back as a
|
> then receives its own messages, and something it publishes can come back as a
|
||||||
> command. It says so in the log when it spots the arrangement:
|
> command. It says so in the log when it spots the arrangement:
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
# Digital modes: WSJT-X, GridTracker and OpsLog together
|
||||||
|
|
||||||
|
Running **WSJT-X** (or JTDX or MSHV) with **GridTracker** *and* OpsLog at the
|
||||||
|
same time is the normal digital station, and it is the setup that most often
|
||||||
|
half-works: the decodes arrive one day and not the next, with nothing changed.
|
||||||
|
|
||||||
|
There is one cause and one fix. The cause is **unicast**; the fix is
|
||||||
|
**multicast**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Unicast and multicast, in one minute
|
||||||
|
|
||||||
|
WSJT-X does not know about OpsLog. It sends a stream of UDP messages — every
|
||||||
|
decode, the DX call you are working, each QSO you log — to **one address and
|
||||||
|
port** you give it. Everything else is just listeners.
|
||||||
|
|
||||||
|
**Unicast** is a message addressed to one place: `127.0.0.1:2237`.
|
||||||
|
|
||||||
|
> One letter, one letterbox. If two programs are watching the same letterbox,
|
||||||
|
> the operating system decides which one gets the letter — and it decides on
|
||||||
|
> the order they started, not on what you want. That is why it works after one
|
||||||
|
> restart and not after the next.
|
||||||
|
|
||||||
|
**Multicast** is a message addressed to a **group**: `239.255.0.1:2237`.
|
||||||
|
|
||||||
|
> A radio broadcast. Every program that has tuned to the group gets its own
|
||||||
|
> copy. No competition, no order, no luck.
|
||||||
|
|
||||||
|
Multicast is what WSJT-X offers for exactly this reason, and it is what you
|
||||||
|
want as soon as **more than one program** listens to your decoder.
|
||||||
|
|
||||||
|
### What it looks like when it goes wrong
|
||||||
|
|
||||||
|
Two starts of the same station, an hour apart, nothing changed in any setting:
|
||||||
|
|
||||||
|
```
|
||||||
|
06:43 autostart: GridTracker2 — already_running
|
||||||
|
06:43 udp: [Decodium] listening on unicast :2237
|
||||||
|
… not one decode all morning, though WSJT-X was running and logging QSOs
|
||||||
|
|
||||||
|
10:30 udp: [Decodium] listening on unicast :2237
|
||||||
|
10:30 autostart: GridTracker2 — launched
|
||||||
|
10:30 udp: emit udp:dx_call "JK2TTP" (mode=FT4 freq=21140000)
|
||||||
|
… decodes all the way through
|
||||||
|
```
|
||||||
|
|
||||||
|
In the morning GridTracker was already holding port 2237 when OpsLog started.
|
||||||
|
In the second session OpsLog got there first. Same programs, same settings, and
|
||||||
|
the only difference is who started first.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The setup that works
|
||||||
|
|
||||||
|
Pick one group and one port and give the **same pair** to every program.
|
||||||
|
`239.255.0.1` port `2237` is the usual choice.
|
||||||
|
|
||||||
|
### WSJT-X
|
||||||
|
|
||||||
|
**File → Settings → Reporting**, *UDP Server* box:
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|---|---|
|
||||||
|
| UDP Server | `239.255.0.1` |
|
||||||
|
| UDP Server port number | `2237` |
|
||||||
|
| Outgoing interfaces | tick your **LAN/Wi-Fi adapter** *and* **loopback** |
|
||||||
|
| Accept UDP requests | ✔ ticked |
|
||||||
|
|
||||||
|
*Outgoing interfaces* matters and is easy to miss: with only the LAN adapter
|
||||||
|
ticked, programs on the same PC may never see the traffic. Tick loopback too.
|
||||||
|
|
||||||
|
*Accept UDP requests* is what lets OpsLog answer a station for you and clear
|
||||||
|
the DX call. Without it OpsLog still hears everything, but can only watch.
|
||||||
|
|
||||||
|
### JTDX
|
||||||
|
|
||||||
|
Same place, same values — JTDX keeps WSJT-X's Reporting tab.
|
||||||
|
|
||||||
|
### MSHV
|
||||||
|
|
||||||
|
**Options → Settings → Reporting** (WSJT-X protocol), same address and port.
|
||||||
|
|
||||||
|
### GridTracker
|
||||||
|
|
||||||
|
**Settings → WSJT-X / UDP**: address `239.255.0.1`, port `2237`, multicast
|
||||||
|
enabled. GridTracker joins the group like everyone else instead of owning the
|
||||||
|
port.
|
||||||
|
|
||||||
|
### OpsLog
|
||||||
|
|
||||||
|
**Settings → Connections → Add**:
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|---|---|
|
||||||
|
| Direction | Inbound |
|
||||||
|
| Service | WSJT-X / JTDX / MSHV |
|
||||||
|
| Port | `2237` |
|
||||||
|
| Multicast | ✔ ticked |
|
||||||
|
| Group | `239.255.0.1` |
|
||||||
|
|
||||||
|
Save. The log should say:
|
||||||
|
|
||||||
|
```
|
||||||
|
udp: [WSJT-X] listening on multicast 239.255.0.1:2237 on 2 interface(s) (service=wsjt)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The mistake to avoid: 127.0.0.1 in the group box
|
||||||
|
|
||||||
|
A **multicast group is an address between `224.0.0.0` and `239.255.255.255`**.
|
||||||
|
Nothing else can be joined.
|
||||||
|
|
||||||
|
`127.0.0.1` is loopback — an ordinary unicast address — and it is a very
|
||||||
|
understandable thing to type, because it is what every other field in every
|
||||||
|
other program wants. But a row ticked *Multicast* with `127.0.0.1` in the group
|
||||||
|
box cannot join anything, and used to fail with a Windows message naming
|
||||||
|
nothing you had typed:
|
||||||
|
|
||||||
|
```
|
||||||
|
udp: [Wsjtx] join 127.0.0.1 on Wi-Fi 2: setsockopt: the requested address is not
|
||||||
|
valid in its context
|
||||||
|
udp: start "Wsjtx" failed: couldn't join multicast 127.0.0.1 on any interface
|
||||||
|
```
|
||||||
|
|
||||||
|
OpsLog now listens on unicast instead and says so, so the row still works — but
|
||||||
|
if you meant multicast, put a real group in.
|
||||||
|
|
||||||
|
**Rule of thumb:** if the address starts with `127.` or `192.168.` or `10.`,
|
||||||
|
untick *Multicast*.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## If you have to stay on unicast
|
||||||
|
|
||||||
|
Sometimes you cannot use multicast — an old program, a locked-down network.
|
||||||
|
Then **only one program may listen on the port**, and the others are fed by it:
|
||||||
|
|
||||||
|
```
|
||||||
|
WSJT-X ──unicast 2237──▶ GridTracker ──forward──▶ OpsLog (another port)
|
||||||
|
```
|
||||||
|
|
||||||
|
GridTracker can forward what it receives; point it at a **different** port, add
|
||||||
|
a matching inbound row in OpsLog, and nothing competes. The one arrangement
|
||||||
|
that never works reliably is two programs on one unicast port.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checking it
|
||||||
|
|
||||||
|
1. **Settings → Connections** — the row is enabled and its port matches.
|
||||||
|
2. **Help → Application log** — one of these two lines appears at startup:
|
||||||
|
- `listening on multicast 239.255.0.1:2237 on N interface(s)` ✔
|
||||||
|
- `listening on unicast :2237` — fine only if nothing else listens there
|
||||||
|
3. Tune to a busy FT8 frequency. Within a minute the log fills with:
|
||||||
|
```
|
||||||
|
udp: emit udp:dx_call "F5ABC" (mode=FT8 freq=14074000)
|
||||||
|
```
|
||||||
|
4. Nothing at all? In order: is WSJT-X's UDP server address the same group; is
|
||||||
|
*Outgoing interfaces* including loopback; is another program holding the
|
||||||
|
port; is Windows Firewall blocking OpsLog.
|
||||||
|
|
||||||
|
> **Not the same thing:** `rigctld: sharing CAT on port 2237` in the log is
|
||||||
|
> OpsLog's **TCP** CAT sharing for Hamlib clients. TCP and UDP ports are
|
||||||
|
> separate — it does not conflict with the UDP listener, however alike the
|
||||||
|
> numbers look.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[Connections]] — every inbound and outbound row, and what each service does
|
||||||
|
- [[Logging Basics]] — what happens when a QSO arrives from WSJT-X
|
||||||
|
- [[Troubleshooting]] — where the log lives
|
||||||
@@ -29,6 +29,7 @@ Developed by **F4BPO**.
|
|||||||
| Enter and manage QSOs | [[Logging Basics]] · [[Recent QSOs and Filters]] · [[Import and Export ADIF]] |
|
| Enter and manage QSOs | [[Logging Basics]] · [[Recent QSOs and Filters]] · [[Import and Export ADIF]] |
|
||||||
| Control your radio | [[CAT Control]] · [[FlexRadio]] · [[Icom]] · [[Remote Icom over the Internet]] · [[Yaesu]] · [[Kenwood and Xiegu]] |
|
| Control your radio | [[CAT Control]] · [[FlexRadio]] · [[Icom]] · [[Remote Icom over the Internet]] · [[Yaesu]] · [[Kenwood and Xiegu]] |
|
||||||
| Chase DX | [[DX Cluster and Spots]] · [[Maps and Antennas]] |
|
| Chase DX | [[DX Cluster and Spots]] · [[Maps and Antennas]] |
|
||||||
|
| Digital modes | [[Digital Modes and GridTracker]] · [[Connections]] |
|
||||||
| Station hardware | [[Amplifiers and Switches]] · [[Audio and Keyers]] |
|
| Station hardware | [[Amplifiers and Switches]] · [[Audio and Keyers]] |
|
||||||
| Events & contests | [[Contest Logging]] · [[Net Control]] · [[Multi-Operator Live Status]] |
|
| Events & contests | [[Contest Logging]] · [[Net Control]] · [[Multi-Operator Live Status]] |
|
||||||
| Confirmations | [[Awards]] · [[QSL Management]] · [[QSL Card Designer]] |
|
| Confirmations | [[Awards]] · [[QSL Management]] · [[QSL Card Designer]] |
|
||||||
|
|||||||
@@ -3,6 +3,69 @@
|
|||||||
**Tools → QSL Manager.** Upload and download confirmations for the online QSL
|
**Tools → QSL Manager.** Upload and download confirmations for the online QSL
|
||||||
services, and manage paper QSL.
|
services, and manage paper QSL.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Confirmations — the status every new QSO starts with
|
||||||
|
|
||||||
|
**Settings → Confirmations.** This page does not send anything. It sets the
|
||||||
|
**status stamped on each new QSO**, per service, at the moment it is logged —
|
||||||
|
by hand, or automatically from WSJT-X / JTDX / MSHV.
|
||||||
|
|
||||||
|
Think of it as the starting position of each column in your log. Everything
|
||||||
|
else — the QSL Manager, the automatic uploads, the *Select required* button —
|
||||||
|
reads those columns and acts on what it finds.
|
||||||
|
|
||||||
|
### ⚠ Sent = **Yes** means the QSO will NEVER be uploaded
|
||||||
|
|
||||||
|
`Y` does not mean *please send it*. It means **already sent**.
|
||||||
|
|
||||||
|
A contact stamped `Y` is finished as far as that service is concerned: the
|
||||||
|
uploader skips it, the QSL Manager does not offer it, and nothing is ever sent
|
||||||
|
for it. Set **eQSL Sent** to `Y` here and every QSO you log from that moment on
|
||||||
|
will silently never reach eQSL.
|
||||||
|
|
||||||
|
There is no error, because nothing failed — OpsLog did exactly what the column
|
||||||
|
said. The only trace is one line in the application log:
|
||||||
|
|
||||||
|
```
|
||||||
|
extsvc: QSO 3807 not eligible for eqsl — EQSLSent already "Y"
|
||||||
|
(set Confirmations default to N to upload)
|
||||||
|
```
|
||||||
|
|
||||||
|
If a service has stopped receiving your contacts, this is the first place to
|
||||||
|
look.
|
||||||
|
|
||||||
|
### What each status means
|
||||||
|
|
||||||
|
| | Meaning | Effect on uploads |
|
||||||
|
|---|---|---|
|
||||||
|
| **R** — requested | Waiting to go out | Uploaded ✔ |
|
||||||
|
| **N** — no | Not sent / not received | Uploaded ✔ |
|
||||||
|
| **Q** — queued | Waiting in a batch | Uploaded ✔ |
|
||||||
|
| **Y** — yes | **Already sent / received** | **Skipped for ever** ✘ |
|
||||||
|
| **I** — ignore | Deliberately excluded | Skipped |
|
||||||
|
| *blank* | No status at all | Column stays empty |
|
||||||
|
|
||||||
|
### What OpsLog ships
|
||||||
|
|
||||||
|
One rule, for every service: the **sent** side starts at **R** (this contact is
|
||||||
|
waiting to go out) and the **received** side at **N** (nothing has come back
|
||||||
|
yet).
|
||||||
|
|
||||||
|
Paper QSL is the exception on the sent side — it starts at **N**, because a
|
||||||
|
card is only *requested* once somebody asks for one.
|
||||||
|
|
||||||
|
You only need to change this if you work differently. The common reason is
|
||||||
|
gating: set a service to `N` and nothing goes out until you select the contacts
|
||||||
|
yourself in the QSL Manager.
|
||||||
|
|
||||||
|
### Two things worth knowing
|
||||||
|
|
||||||
|
- **It is per profile.** Your contest callsign can upload to a different set of
|
||||||
|
services from your home one.
|
||||||
|
- **It applies from now on.** Changing a default never touches contacts already
|
||||||
|
in the log — use **Bulk edit field** (right-click in Recent QSOs) for those.
|
||||||
|
|
||||||
## Services
|
## Services
|
||||||
|
|
||||||
| Service | Upload | Download confirmations |
|
| Service | Upload | Download confirmations |
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
- [[Net Control]]
|
- [[Net Control]]
|
||||||
- [[Multi-Operator Live Status]]
|
- [[Multi-Operator Live Status]]
|
||||||
- [[Connections]]
|
- [[Connections]]
|
||||||
|
- [[Digital Modes and GridTracker]]
|
||||||
|
|
||||||
**QSL & Awards**
|
**QSL & Awards**
|
||||||
- [[Awards]]
|
- [[Awards]]
|
||||||
|
|||||||
Reference in New Issue
Block a user