chore: release v0.26.0

This commit is contained in:
2026-08-20 17:53:55 +02:00
parent 47992b5f03
commit 1e507225dd
44 changed files with 3197 additions and 240 deletions
+31 -3
View File
@@ -51,7 +51,7 @@ type WSJTEvent struct {
// known dial frequency (from Status) to DeltaFreqHz to get the RF frequency.
IsDecode bool
DecodeCall string // the sender (DE) callsign extracted from the message text
DecodeGrid string // 4-char grid, CQ decodes only — the exchange carries none
DecodeGrid string // 4-char grid: from a CQ, or a reply that answers with its locator
DeltaFreqHz int64 // audio offset within the passband (Hz)
SNR int // reported signal-to-noise (dB)
IsCQ bool // the decode was a CQ call
@@ -64,6 +64,12 @@ type WSJTEvent struct {
// exchange is what tells an operator where a station is in a QSO, and no set
// of extracted fields says "R-09" the way the line itself does.
DecodeMsg string
// DecodeMsgRaw is the message EXACTLY as the datagram carried it, trailing
// spaces and all. DecodeMsg above is trimmed for display; a Reply has to
// send this one, because the receiving application matches a Reply against
// its own decode list field for field and a stripped space is a mismatch it
// reports nowhere.
DecodeMsgRaw string
// DecodeMsSinceMidnight is the decode's own timestamp, in milliseconds since
// 00:00 UTC, as the sender reported it. It is what groups decodes into T/R
// PERIODS — arrival time cannot, since a whole period's decodes land in one
@@ -80,8 +86,14 @@ type WSJTEvent struct {
// from Status, so they arrive about once a second.
TxMessage string
Transmitting bool
DECall string // the operator's own callsign, as the digital app knows it
DEGrid string // and their square
// TxEnabled is the sender's "Enable Tx" toggle. It is what the WATCHDOG
// turns off: the application stops transmitting but leaves the DX call set,
// so a caller that reads only the DX call believes the QSO is still running
// and waits for ever. This is the difference between "between overs" and
// "given up".
TxEnabled bool
DECall string // the operator's own callsign, as the digital app knows it
DEGrid string // and their square
// TRPeriod is the transmit/receive period in seconds (15 for FT8, 7 or 8 for
// FT4 depending on the sender's rounding). The authority on how long a slot
// is — better than inferring it from the mode name, which says nothing about
@@ -214,6 +226,7 @@ func ParseWSJT(pkt []byte) (WSJTEvent, bool, error) {
}
}
ev.Transmitting = transmitting != 0
ev.TxEnabled = txEnabled != 0
// rx_df, tx_df
var i32 int32
for i := 0; i < 2; i++ {
@@ -331,6 +344,7 @@ func ParseWSJT(pkt []byte) (WSJTEvent, bool, error) {
ev.SNR = int(snr)
ev.Mode = strings.ToUpper(strings.TrimSpace(mode))
ev.DecodeMsg = strings.TrimSpace(msg)
ev.DecodeMsgRaw = msg
ev.DecodeMsSinceMidnight = t32
ev.LowConfidence = lowConf != 0
ev.OffAir = offAir != 0
@@ -386,7 +400,21 @@ func wsjtSender(message string) (call string, isCQ bool, grid string) {
return "", true, ""
}
// Standard exchange: the DE (sender) call is the second token.
//
// And the THIRD token is a grid whenever the station is answering with its
// locator — "C91RU IZ5EME JN52", the ordinary first reply to a CQ. This used
// to return no grid at all on the grounds that "the exchange carries none",
// which is simply not true: it is the commonest grid-bearing message on a
// busy band, and only a CQ being read meant a station whose CQ we missed had
// no known grid — so it could never be flagged as a new one. GridTracker
// reads both, which is why its wanted-grid count ran so far ahead of ours.
//
// isGridField is what keeps the reports and sign-offs out: -05, R-05, RRR,
// 73 and RR73 all fail it, on length, charset or by name.
if len(f) >= 2 && looksLikeCall(f[1]) {
if len(f) >= 3 && isGridField(f[2]) {
return f[1], false, f[2]
}
return f[1], false, ""
}
return "", false, ""