fix: Antenna Genius drew both ports on the same antenna
Reported on an 8x2: port A correctly on the 80 m vertical, then a few seconds later both A and B shown on the same beam. The display preferred the TX antenna, falling back to RX. On an 8x2 only ONE port can hold the transmit antenna, so the switch reports the same txant on both — and every keepalive poll redrew port A as whatever port B transmits through. The RX antenna is the per-port selection, and the only thing Activate sets, so it is what a port shows; TX stays the fallback for a port reporting no RX antenna. A port change is now logged with the raw line — but only on CHANGE, since the device pushes state every few seconds and logging each one would bury the rest. Without any trace, "port A jumped to the wrong antenna" cannot be checked. Two tests pin it: rx wins over a disagreeing tx, and a message about one port never moves the other — which is the shape that was actually on screen.
This commit is contained in:
@@ -66,11 +66,12 @@ type Client struct {
|
||||
authTries int
|
||||
ready atomic.Bool // init commands sent → keepalive may run
|
||||
|
||||
statusMu sync.RWMutex
|
||||
status Status
|
||||
antennas map[int]string // index → name (rebuilt into status.Antennas)
|
||||
antBands map[int]int // index → band bitmask (which bands the antenna covers)
|
||||
antRawN int // one-shot: how many raw antenna lines we've logged
|
||||
statusMu sync.RWMutex
|
||||
status Status
|
||||
antennas map[int]string // index → name (rebuilt into status.Antennas)
|
||||
antBands map[int]int // index → band bitmask (which bands the antenna covers)
|
||||
antRawN int // one-shot: how many raw antenna lines we've logged
|
||||
lastShown map[int]int // port id → antenna last reported, so only CHANGES are logged
|
||||
|
||||
stop chan struct{}
|
||||
running bool
|
||||
@@ -81,13 +82,14 @@ func New(host string, port int, password string) *Client {
|
||||
port = defaultPort
|
||||
}
|
||||
return &Client{
|
||||
host: host,
|
||||
port: port,
|
||||
password: strings.TrimSpace(password),
|
||||
stop: make(chan struct{}),
|
||||
antennas: map[int]string{},
|
||||
antBands: map[int]int{},
|
||||
status: Status{Host: host},
|
||||
host: host,
|
||||
port: port,
|
||||
password: strings.TrimSpace(password),
|
||||
stop: make(chan struct{}),
|
||||
antennas: map[int]string{},
|
||||
antBands: map[int]int{},
|
||||
lastShown: map[int]int{},
|
||||
status: Status{Host: host},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,9 +400,27 @@ func (c *Client) parsePort(msg string) {
|
||||
}
|
||||
tx := kvInt(msg, "txant")
|
||||
rx := kvInt(msg, "rxant")
|
||||
active := tx
|
||||
// The RX antenna is what identifies a port's selection, and it is the only
|
||||
// thing Activate sets. Preferring the TX antenna made both ports converge on
|
||||
// the same row a few seconds after a change: on an 8x2 only ONE port can hold
|
||||
// the transmit antenna, so the device reports the same txant on both, and a
|
||||
// port A genuinely on the 80 m vertical was redrawn as the beam that port B
|
||||
// transmits through.
|
||||
//
|
||||
// TX remains the fallback for a port that reports no RX antenna at all.
|
||||
active := rx
|
||||
if active == 0 {
|
||||
active = rx
|
||||
active = tx
|
||||
}
|
||||
// Logged only when the shown antenna CHANGES: the device pushes port state
|
||||
// every few seconds, and logging each one would bury everything else — but
|
||||
// without any trace, "port A jumped to the wrong antenna" is unfalsifiable.
|
||||
c.statusMu.Lock()
|
||||
prev, seen := c.lastShown[id]
|
||||
c.lastShown[id] = active
|
||||
c.statusMu.Unlock()
|
||||
if !seen || prev != active {
|
||||
applog.Printf("antgenius: port %d → antenna %d (rxant=%d txant=%d) raw=%q", id, active, rx, tx, msg)
|
||||
}
|
||||
txOn := kvInt(msg, "tx") != 0 // the standalone "tx=0|1" transmit flag
|
||||
c.setStatus(func(s *Status) {
|
||||
|
||||
Reference in New Issue
Block a user