fix(logging): name the antenna disagreement, and confirm an outbound send

Two silences from one operator's log.

The SteppIR is not blocked — it is being overruled. Every tune is commanded,
acknowledged on the next poll with the frequency asked for, then replaced on
the poll after by a different one: 21075 asked, 21075 confirmed, 21050
reported, again and again, with the operator tuning once more each time. Two
minutes of that reads as a dead link. It now says what it is, once, when the
motors have stopped and the reported frequency is more than 10 kHz from the
commanded one — a controller quantising to its own grid is not a fault, one
sitting somewhere else entirely is.

UDP outbound had no positive signal at all: only failures were logged. When
an operator sets up an ADIF message to a second logger and nothing arrives,
"OpsLog never sent it" and "the other program did not take it" looked exactly
the same from here — and the first is the common case, because a row created
as an inbound ADIF listener instead of an outbound ADIF message matches
nothing and emits nothing. Successful sends are logged with their destination
and service, and a QSO logged with no outbound row says so once a session.
This commit is contained in:
2026-08-14 17:37:12 +02:00
parent 7470ebf47e
commit c5c9d355ec
5 changed files with 141 additions and 3 deletions
+50
View File
@@ -0,0 +1,50 @@
package steppir
import "testing"
// An operator's log read as "the antenna stops responding": every tune was
// commanded, acknowledged with the requested frequency on the next poll, then
// replaced on the poll after by a different one — 21075 asked, 21075 confirmed,
// 21050 reported — with the operator tuning again each time. Nothing in the log
// named that, so it looked like a dead link.
func TestCheckDriftReportsOnceAndRecovers(t *testing.T) {
c := &Client{}
c.lastSetKHz = 21075
// Where it was asked to go: nothing to say.
c.checkDrift(&Status{Frequency: 21075})
if c.lastDriftKHz != 0 {
t.Errorf("a controller on frequency was reported as drifting (%d)", c.lastDriftKHz)
}
// Its own grid is not a fault.
c.checkDrift(&Status{Frequency: 21070})
if c.lastDriftKHz != 0 {
t.Errorf("%d kHz is within tolerance and was reported", 21070)
}
// Somewhere else entirely: recorded, so it is said once.
c.checkDrift(&Status{Frequency: 21050})
if c.lastDriftKHz != 21050 {
t.Errorf("lastDriftKHz = %d, want 21050", c.lastDriftKHz)
}
// Still there on the next poll: nothing new to say, and the marker stands.
c.checkDrift(&Status{Frequency: 21050})
if c.lastDriftKHz != 21050 {
t.Errorf("lastDriftKHz = %d after a repeat, want it unchanged", c.lastDriftKHz)
}
// Back where it belongs: the marker clears, so the next divergence is said.
c.checkDrift(&Status{Frequency: 21075})
if c.lastDriftKHz != 0 {
t.Errorf("lastDriftKHz = %d after recovery, want 0", c.lastDriftKHz)
}
}
// A frequency read while the elements are travelling is not a disagreement, it
// is an antenna on its way — reporting it would cry wolf on every single tune.
func TestCheckDriftIgnoresMovingMotors(t *testing.T) {
c := &Client{}
c.lastSetKHz = 21075
c.checkDrift(&Status{Frequency: 21000, MotorsMoving: 1})
if c.lastDriftKHz != 0 {
t.Errorf("a moving antenna was reported as drifting (%d)", c.lastDriftKHz)
}
}