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() }