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:
@@ -0,0 +1,50 @@
|
||||
package udp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// Sending WSJT-X UDP messages, as opposed to parsing them (wsjt.go).
|
||||
//
|
||||
// This exists for Logger32, and for anything else that listens on the WSJT-X
|
||||
// interface rather than for plain text. Logger32's "additional WSJT/JTDX UDP
|
||||
// sockets" receivers — ports 2250, 2251, 2252 — are documented as receiving
|
||||
// "UDP logging packets": they speak the WSJT-X v2 protocol, and a raw ADIF
|
||||
// record posted to them is discarded without a word.
|
||||
//
|
||||
// That is a real distinction and not a detail: an operator can watch OpsLog
|
||||
// report "sent 1153 bytes to 127.0.0.1:2250" and see nothing whatsoever appear
|
||||
// in Logger32, because both statements are true.
|
||||
|
||||
// buildQString encodes a Qt QString/QByteArray as QDataStream writes it: a
|
||||
// big-endian int32 length followed by the UTF-8 bytes. A negative length means
|
||||
// null, which is not what we ever want here — an empty string is length 0.
|
||||
func buildQString(s string) []byte {
|
||||
out := make([]byte, 4, 4+len(s))
|
||||
binary.BigEndian.PutUint32(out, uint32(len(s)))
|
||||
return append(out, s...)
|
||||
}
|
||||
|
||||
// BuildWSJTLoggedADIF frames a WSJT-X "Logged ADIF" datagram (message type 12).
|
||||
//
|
||||
// uint32 magic 0xadbccbda
|
||||
// uint32 schema 2
|
||||
// uint32 type 12
|
||||
// QString id the sending program's name
|
||||
// QString adif the ADIF record
|
||||
//
|
||||
// id matters more than it looks: a receiver uses it to tell instances apart, and
|
||||
// some show it in their log. "OpsLog" is honest — pretending to be WSJT-X would
|
||||
// make a second instance of the real thing indistinguishable from us.
|
||||
func BuildWSJTLoggedADIF(id, adif string) []byte {
|
||||
var b bytes.Buffer
|
||||
var hdr [12]byte
|
||||
binary.BigEndian.PutUint32(hdr[0:4], wsjtMagic)
|
||||
binary.BigEndian.PutUint32(hdr[4:8], 2) // schema 2 — what WSJT-X 2.x speaks
|
||||
binary.BigEndian.PutUint32(hdr[8:12], wsjtMsgLoggedADIF)
|
||||
b.Write(hdr[:])
|
||||
b.Write(buildQString(id))
|
||||
b.Write(buildQString(adif))
|
||||
return b.Bytes()
|
||||
}
|
||||
Reference in New Issue
Block a user