"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.
50 lines
1.5 KiB
Go
50 lines
1.5 KiB
Go
package udp
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
)
|
|
|
|
// What we send has to be what we can read back: Logger32 and the rest decode
|
|
// this with the same rules our own parser uses, so a round trip through
|
|
// ParseWSJT is the honest check.
|
|
//
|
|
// The case behind it: OpsLog reported "sent 1153 bytes to 127.0.0.1:2250" and
|
|
// Logger32 showed nothing. Both were true — its UDP sockets speak the WSJT-X
|
|
// protocol and discard a bare ADIF record without a word.
|
|
func TestWSJTLoggedADIFRoundTrips(t *testing.T) {
|
|
const rec = "<CALL:5>VK9XX<BAND:3>20m<MODE:3>FT8<QSO_DATE:8>20260814<TIME_ON:6>174433<EOR>"
|
|
pkt := BuildWSJTLoggedADIF("OpsLog", rec)
|
|
|
|
ev, ok, err := ParseWSJT(pkt)
|
|
if err != nil {
|
|
t.Fatalf("ParseWSJT: %v", err)
|
|
}
|
|
if !ok {
|
|
t.Fatal("our own parser did not recognise the datagram we build")
|
|
}
|
|
if ev.LoggedADIF != rec {
|
|
t.Errorf("ADIF = %q, want %q", ev.LoggedADIF, rec)
|
|
}
|
|
if ev.ProgramID != "OpsLog" {
|
|
t.Errorf("id = %q, want OpsLog — a receiver uses it to tell instances apart", ev.ProgramID)
|
|
}
|
|
}
|
|
|
|
// The header is fixed and other programs match on it byte for byte.
|
|
func TestWSJTLoggedADIFHeader(t *testing.T) {
|
|
pkt := BuildWSJTLoggedADIF("OpsLog", "<EOR>")
|
|
want := []byte{
|
|
0xad, 0xbc, 0xcb, 0xda, // magic
|
|
0x00, 0x00, 0x00, 0x02, // schema 2
|
|
0x00, 0x00, 0x00, 0x0c, // type 12 — Logged ADIF
|
|
0x00, 0x00, 0x00, 0x06, // len("OpsLog")
|
|
'O', 'p', 's', 'L', 'o', 'g',
|
|
0x00, 0x00, 0x00, 0x05, // len("<EOR>")
|
|
'<', 'E', 'O', 'R', '>',
|
|
}
|
|
if !bytes.Equal(pkt, want) {
|
|
t.Errorf("packet = % X\nwant % X", pkt, want)
|
|
}
|
|
}
|