feat(udp): speak WSJT-X to Logger32, and lighten Sahara

"sent 1153 bytes to 127.0.0.1:2250" and nothing in Logger32. Both true: the
line the operator screenshotted is titled "Setup additional WSJT/JTDX UDP
sockets", and those receivers take UDP LOGGING PACKETS — the WSJT-X v2
protocol. A bare ADIF record posted to them is dropped without a word.

So there is a new outbound service rather than a change to the existing one:
"WSJT-X logged QSO (Logger32)" sends the same ADIF wrapped in a Logged ADIF
datagram (magic 0xadbccbda, schema 2, type 12), defaulting to port 2250. The
plain-text row stays for JTAlert/GridTracker-style receivers, because the two
really are different wire formats and one row cannot be both.

The id string is "OpsLog", not "WSJT-X": a receiver uses it to tell instances
apart, and impersonating the real thing would make a second WSJT-X
indistinguishable from us.

Tested both ways — the header byte for byte, and a round trip back through our
own ParseWSJT, since that is the same decoding every receiver applies.

Sahara moves to the parchment an operator asked for: page #e6ded0, panels
#f3eee2, toolbars #ded5c4, terracotta #c4501e on the buttons and the focus
ring. Lighter and less saturated than the deep sand it was.
This commit is contained in:
2026-08-14 17:51:31 +02:00
parent c5c9d355ec
commit d95c998081
10 changed files with 165 additions and 32 deletions
+6 -2
View File
@@ -2777,7 +2777,9 @@ func (a *App) AddQSO(q qso.QSO) (id int64, err error) {
a.maybeSelfSpot(qc)
a.publishSoon() // refresh the published web page, debounced
if a.udp != nil {
a.udp.EmitLoggedADIF(adif.SingleRecordADIF(qc))
rec := adif.SingleRecordADIF(qc)
a.udp.EmitLoggedADIF(rec)
a.udp.EmitLoggedADIFWSJT(rec)
}
// Nudge the grid again so the award_refs columns appear once materialised.
if a.ctx != nil {
@@ -12203,7 +12205,9 @@ func (a *App) LogUDPLoggedADIF(adifText string) (int64, error) {
// path — otherwise a QSO logged FROM WSJT-X/JTDX/MSHV was never re-emitted
// to the outbound ADIF listeners (Log4OM, N1MM, gridtracker…).
if a.udp != nil {
a.udp.EmitLoggedADIF(adif.SingleRecordADIF(qc))
rec := adif.SingleRecordADIF(qc)
a.udp.EmitLoggedADIF(rec)
a.udp.EmitLoggedADIFWSJT(rec)
}
if a.ctx != nil {
wruntime.EventsEmit(a.ctx, "qso:logged", id) // refresh again so award_refs show