fix(sat): the antenna stops flickering, and the pass is readable from the header

THE FLICKER was a real bug and not a rotator problem. The rotator is asked where
it is at most every three seconds — a controller query binds a socket and waits —
but satTrackStep built a fresh status every second and carried over only Radio
and Error. So the antenna readout was filled in on one tick in three and blank
on the other two, which on screen is a rotator that keeps disconnecting. The
status is now rebuilt FROM the previous one, so a field nobody wrote this tick
keeps the value somebody wrote last tick.

THE HEADER now carries the two frequencies and the antenna bearing, beside the
button that started tracking. During a pass an operator watches the radio and
the antenna, not a column on the far side of the window — and that column is the
first thing they hide to get the map full width, which until now took the
numbers with it. The compass spins while the antenna is still on its way: a mast
takes tens of seconds to cross a pass, and "moving" against "stuck" is the whole
reason to look at it, which a number alone cannot show.

THE PRECISION drops from one hertz to a hundred. The Doppler moves about sixty
hertz a second on 70 cm, so the last two digits changed on every tick and the
display was a blur that could not be read and did not need to be. The radio
still gets the whole figure — the correction is computed and sent to the hertz —
this is only how much of it is worth putting in front of somebody. The shift
beside it says "+9.7 kHz" rather than "+9741 Hz", which is how it is read aloud.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
2026-09-09 23:30:57 +02:00
co-authored by Claude Opus 5
parent 5ddc5e38a9
commit b8491f3038
3 changed files with 93 additions and 16 deletions
+15 -9
View File
@@ -338,22 +338,28 @@ func (a *App) satTrackStep(t *satTracker) {
down, up := sh.DownHz, sh.UpHz
t.mu.Lock()
t.status = SatTrackStatus{
On: true, Name: b.Name, Transponder: tp.Label, Mode: tp.Mode,
NominalDown: nominal, NominalUp: nomUp,
DownHz: down, UpHz: up,
Az: pos.Az, El: pos.El, Visible: visible,
Radio: t.status.Radio, Error: t.status.Error,
}
// Rebuilt from the old one, not from nothing.
//
// The rotator fields are written by readRotator, which runs at most every
// three seconds — a controller query binds a socket and waits. Building a
// fresh status here dropped them on every OTHER tick, so the antenna
// readout appeared for one second in three and vanished again, which reads
// as a rotator that keeps disconnecting.
st := t.status
st.On, st.Name, st.Transponder, st.Mode = true, b.Name, tp.Label, tp.Mode
st.NominalDown, st.NominalUp = nominal, nomUp
st.DownHz, st.UpHz = down, up
st.Az, st.El, st.Visible = pos.Az, pos.El, visible
t.status = st
t.mu.Unlock()
t.pointRotator(pos, b.Geostationary)
t.readRotator()
t.mu.Lock()
st := t.status
out := t.status
t.mu.Unlock()
a.emitSatTrack(st)
a.emitSatTrack(out)
// Only send what has actually moved. The step is the smallest change worth a
// command: on SSB a listener hears twenty hertz, on an FM channel nothing