feat(antgenius): the selected antenna can fill MY_ANTENNA

A station with a switch knows something the log does not: which antenna
is actually connected. The working conditions hold what was PLANNED for
the band, and stay right until the operator throws the switch — after
which every QSO keeps claiming the other antenna.

Optional, and off by default: a station that names its antennas
differently in the two places would otherwise find its log quietly
rewritten. The name written is the one configured on the device, since
that is the name the operator gave it and the one they will look for.

WHICH PORT is the real problem, and the reason this is not a one-liner.
The switch has two, the radio has two jacks, and the QSO went out through
one of them; naming the wrong port's antenna is worse than naming the
band default, because it looks authoritative. The radio's own TX antenna
selection decides, and the jack-to-port wiring is a setting — it is the
station's cabling and neither device can report it.

When the port cannot be told — a transverter jack, a rig that reports
nothing, both switch ports live — nothing is written and the band default
stands. Silence beats a confident guess in a field nobody re-checks.
This commit is contained in:
2026-08-25 15:08:48 +02:00
parent ed099a660e
commit df1d2767cd
7 changed files with 275 additions and 38 deletions
+55
View File
@@ -0,0 +1,55 @@
package main
import (
"testing"
"hamlog/internal/antgenius"
)
// The switch has two ports and the radio two antenna jacks; a QSO was made
// through exactly one of them. Naming the wrong port's antenna would be worse
// than naming the band default — it is a wrong answer that looks authoritative.
func TestAntennaNameComesFromTheDeviceList(t *testing.T) {
st := antgenius.Status{
Connected: true,
PortA: 2,
PortB: 5,
Antennas: []antgenius.Antenna{
{Index: 2, Name: "OB11-5 20/15/10"},
{Index: 5, Name: "Vertical 80m"},
},
}
if got := antGeniusNameOf(st, 2); got != "OB11-5 20/15/10" {
t.Fatalf("port A antenna = %q", got)
}
if got := antGeniusNameOf(st, 5); got != "Vertical 80m" {
t.Fatalf("port B antenna = %q", got)
}
// An index the device never described has no name to give, and inventing
// one ("Antenna 7") would put a label in the log that exists nowhere else.
if got := antGeniusNameOf(st, 7); got != "" {
t.Fatalf("unknown index produced %q", got)
}
}
// The jack-to-port wiring is the station's own. Defaulting ANT1 to port A is a
// convention, not a fact, so it is a setting — and the mapping has to hold both
// ways round.
func TestJackToPortMapping(t *testing.T) {
app := &App{}
// No settings store: settingOr falls back, which is ANT1 → port A.
if got := app.antGeniusPortFor("ANT1"); got != 1 {
t.Fatalf("ANT1 mapped to port %d, want A(1)", got)
}
if got := app.antGeniusPortFor("ANT2"); got != 2 {
t.Fatalf("ANT2 mapped to port %d, want B(2)", got)
}
// A jack that is neither — a transverter port, or a rig that reports
// nothing — has no port to name, and saying so beats guessing.
if got := app.antGeniusPortFor("XVTR"); got != 0 {
t.Fatalf("XVTR mapped to port %d, want none", got)
}
if got := app.antGeniusPortFor(""); got != 0 {
t.Fatalf("an unreported jack mapped to port %d, want none", got)
}
}