fix(sat): both antennas on both satellite slices
A slice has an rxant and a txant, and each pair belongs to that slice's own band. Only two of the four were being set — the downlink's receive antenna and the uplink's transmit one — so the downlink slice was left with an empty txant. It never keys, so nothing was wrong on the air, but the slice was half-configured: move transmit focus to it and the radio uses whatever antenna it happened to be left on. Reported with XVTA on 2 m and XVTB on 70 cm, where the 70 cm slice showed one antenna and the 2 m slice showed two. SatAntennas now takes all four, and the late-slice replay in adoptSatSlice hands the uplink its own pair instead of putting the transmit antenna on both of its ports.
This commit is contained in:
+11
-7
@@ -697,21 +697,25 @@ func (a *App) applySatRadio(tp sat.Transponder) {
|
||||
if err != nil || len(m) == 0 {
|
||||
return
|
||||
}
|
||||
// The downlink is received, so it takes that band's RX antenna; the uplink
|
||||
// is transmitted, so it takes that band's TX antenna.
|
||||
// Each slice gets BOTH antennas of ITS OWN band. Only two of the four were
|
||||
// set — the downlink's receive and the uplink's transmit — which left the
|
||||
// downlink slice with no txant. It never keys, so nothing was wrong on the
|
||||
// air, but a half-configured slice uses whatever antenna it was last left
|
||||
// on the moment transmit focus moves to it.
|
||||
downBand, upBand := flexBandAntKey(tp.DownLo), flexBandAntKey(tp.UpLo)
|
||||
rxAnt := m[downBand].RX
|
||||
txAnt := m[upBand].TX
|
||||
if strings.TrimSpace(rxAnt) == "" && strings.TrimSpace(txAnt) == "" {
|
||||
down, up := m[downBand], m[upBand]
|
||||
if strings.TrimSpace(down.RX) == "" && strings.TrimSpace(down.TX) == "" &&
|
||||
strings.TrimSpace(up.RX) == "" && strings.TrimSpace(up.TX) == "" {
|
||||
// Worth a line: an operator who HAS configured the pair and still sees
|
||||
// the wrong antenna has no other way to tell a setting he never made
|
||||
// from a lookup that missed.
|
||||
applog.Printf("sat: no antenna configured for this pass (down %s, up %s)", downBand, upBand)
|
||||
return
|
||||
}
|
||||
applog.Printf("sat: antennas rx=%q (%s) tx=%q (%s)", rxAnt, downBand, txAnt, upBand)
|
||||
applog.Printf("sat: antennas down %s rx=%q tx=%q, up %s rx=%q tx=%q",
|
||||
downBand, down.RX, down.TX, upBand, up.RX, up.TX)
|
||||
if err := a.cat.FlexDo(func(fc cat.FlexController) error {
|
||||
return fc.SatAntennas(rxAnt, txAnt)
|
||||
return fc.SatAntennas(down.RX, down.TX, up.RX, up.TX)
|
||||
}); err != nil {
|
||||
// Not fatal: a rig that is not a Flex has no such thing, and a pass with
|
||||
// the wrong antenna is still a pass.
|
||||
|
||||
+6
-2
@@ -8,7 +8,9 @@
|
||||
"Badges on the satellite panel for the band, the Doppler offset, an inverting transponder, the passband width and a pass's peak elevation.",
|
||||
"The satellite ground track is visible on every basemap — it was drawn in a colour the map could not use and came out near-white.",
|
||||
"The decode panel no longer warns about band drift on a second slice: it now compares against every band the radio is receiving on, not just the transmit band.",
|
||||
"OpsLog appears again after an update. The relaunch was starting the new build with its window hidden, so it ran with no window at all."
|
||||
"OpsLog appears again after an update. The relaunch was starting the new build with its window hidden, so it ran with no window at all.",
|
||||
"Each satellite slice now gets both of its antennas, RX and TX, from its own band — the downlink slice was left with no transmit antenna at all.",
|
||||
"The satellite ground track no longer draws a straight line across the map when it crosses the antimeridian."
|
||||
],
|
||||
"fr": [
|
||||
"Le tracé du ciel et la position passent dans leur propre colonne, à gauche de la carte. Largeur réglable, et la colonne se replie comme celle de droite.",
|
||||
@@ -17,7 +19,9 @@
|
||||
"Des pastilles sur le panneau satellite pour la bande, l’écart Doppler, un transpondeur inverseur, la largeur de bande passante et le pic d’élévation d’une passe.",
|
||||
"Le tracé au sol des satellites est visible sur tous les fonds de carte — il était dessiné dans une couleur inexploitable et sortait presque blanc.",
|
||||
"Le panneau de décodages n’avertit plus d’une dérive de bande sur une seconde tranche : la comparaison porte sur toutes les bandes reçues, pas seulement celle d’émission.",
|
||||
"OpsLog réapparaît après une mise à jour. La relance démarrait la nouvelle version avec sa fenêtre masquée, donc sans aucune fenêtre."
|
||||
"OpsLog réapparaît après une mise à jour. La relance démarrait la nouvelle version avec sa fenêtre masquée, donc sans aucune fenêtre.",
|
||||
"Chaque slice satellite reçoit désormais ses deux antennes, RX et TX, depuis sa propre bande — la slice de descente restait sans antenne d’émission.",
|
||||
"Le tracé au sol du satellite ne trace plus une ligne droite en travers de la carte lorsqu’il franchit l’antiméridien."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
+2
-2
@@ -594,9 +594,9 @@ type FlexController interface {
|
||||
SetMute(bool) error
|
||||
SetRXAntenna(string) error
|
||||
SetTXAntenna(string) error
|
||||
// SatAntennas sets the antenna on each SATELLITE slice — they are on two
|
||||
// SatAntennas sets BOTH antennas on each SATELLITE slice — they are on two
|
||||
// different bands and, with transverters, two different ports.
|
||||
SatAntennas(rxAnt, txAnt string) error
|
||||
SatAntennas(downRX, downTX, upRX, upTX string) error
|
||||
// SatTone sets the CTCSS tone the satellite uplink transmits (0 = off).
|
||||
SatTone(hz float64) error
|
||||
SetActiveSlice(int) error // focus slice idx so commands target it
|
||||
|
||||
@@ -79,9 +79,13 @@ type Flex struct {
|
||||
// turns up LATE. Arming, the antennas, the tone and the mode all happen
|
||||
// before the radio has necessarily reported the slice it was asked to
|
||||
// create; without this they were applied to an index of -1 and never again.
|
||||
satUpMode string
|
||||
satRXAnt string
|
||||
satTXAnt string
|
||||
satUpMode string
|
||||
// Both antennas of both slices: a slice has an rxant and a txant, and each
|
||||
// pair belongs to that slice's own band.
|
||||
satDownRX string
|
||||
satDownTX string
|
||||
satUpRX string
|
||||
satUpTX string
|
||||
satTone float64
|
||||
spotCall map[int]string // spot index → callsign (to fill the call on a panadapter click)
|
||||
spotMode map[int]string // spot index → ADIF mode, so a click can also set the slice mode (SmartSDR tunes the spot's freq but not its mode)
|
||||
|
||||
+32
-21
@@ -155,11 +155,13 @@ func (f *Flex) adoptSatSlice(role string, idx int) {
|
||||
// antenna and the tone are all sent ONCE — the step only re-sends
|
||||
// frequencies.
|
||||
f.mu.Lock()
|
||||
mode, ant, tone := f.satUpMode, f.satTXAnt, f.satTone
|
||||
mode, rxAnt, txAnt, tone := f.satUpMode, f.satUpRX, f.satUpTX, f.satTone
|
||||
f.mu.Unlock()
|
||||
if strings.TrimSpace(ant) != "" {
|
||||
f.send(fmt.Sprintf("slice s %d txant=%s", idx, ant))
|
||||
f.send(fmt.Sprintf("slice s %d rxant=%s", idx, ant))
|
||||
if strings.TrimSpace(rxAnt) != "" {
|
||||
f.send(fmt.Sprintf("slice s %d rxant=%s", idx, rxAnt))
|
||||
}
|
||||
if strings.TrimSpace(txAnt) != "" {
|
||||
f.send(fmt.Sprintf("slice s %d txant=%s", idx, txAnt))
|
||||
}
|
||||
if strings.TrimSpace(mode) != "" {
|
||||
f.satMode(idx, mode, 0)
|
||||
@@ -259,7 +261,7 @@ func (f *Flex) SatReceiveHz() (int64, error) {
|
||||
return s.freqHz, nil
|
||||
}
|
||||
|
||||
// SatAntennas selects the antenna each satellite slice uses.
|
||||
// SatAntennas selects both antennas of each satellite slice.
|
||||
//
|
||||
// The two slices are on two different bands — a V/U bird receives on 70 cm and
|
||||
// transmits on 2 m, a U/V one does the reverse — so they cannot share one
|
||||
@@ -274,30 +276,39 @@ func (f *Flex) SatReceiveHz() (int64, error) {
|
||||
// Empty strings are left alone: an operator who has configured 2 m and not
|
||||
// 70 cm should keep whatever the radio already had on the other side rather
|
||||
// than have it cleared.
|
||||
func (f *Flex) SatAntennas(rxAnt, txAnt string) error {
|
||||
// A slice has an rxant AND a txant, and both belong to the slice's own band.
|
||||
// Only two of the four were being set — the downlink's receive antenna and
|
||||
// the uplink's transmit one — which left the downlink slice with an empty
|
||||
// txant. It never keys, so nothing was wrong on the air, but the slice was
|
||||
// half-configured: move transmit focus to it and the radio uses whatever
|
||||
// antenna it was last left on.
|
||||
func (f *Flex) SatAntennas(downRX, downTX, upRX, upTX string) error {
|
||||
f.mu.Lock()
|
||||
rx, tx := f.satRX, f.satTX
|
||||
connected := f.conn != nil
|
||||
// Remembered so a slice that is reported late still gets its antenna.
|
||||
f.satRXAnt, f.satTXAnt = rxAnt, txAnt
|
||||
// Remembered so a slice that is reported late still gets its antennas.
|
||||
f.satDownRX, f.satDownTX = downRX, downTX
|
||||
f.satUpRX, f.satUpTX = upRX, upTX
|
||||
f.mu.Unlock()
|
||||
if !connected {
|
||||
return fmt.Errorf("flex: not connected")
|
||||
}
|
||||
// The downlink slice is the one being listened to, so it takes the receive
|
||||
// antenna; the uplink slice is the one keyed, so it takes the transmit one.
|
||||
if rx >= 0 && strings.TrimSpace(rxAnt) != "" {
|
||||
f.send(fmt.Sprintf("slice s %d rxant=%s", rx, rxAnt))
|
||||
applog.Printf("flex: satellite downlink slice %d on antenna %s", rx, rxAnt)
|
||||
}
|
||||
if tx >= 0 && strings.TrimSpace(txAnt) != "" {
|
||||
f.send(fmt.Sprintf("slice s %d txant=%s", tx, txAnt))
|
||||
// A transmit slice also has to HEAR its own band on some radios, and a
|
||||
// transverter port is the only thing connected to it. Setting the
|
||||
// receive antenna to match costs nothing when it is already right.
|
||||
f.send(fmt.Sprintf("slice s %d rxant=%s", tx, txAnt))
|
||||
applog.Printf("flex: satellite uplink slice %d on antenna %s", tx, txAnt)
|
||||
set := func(idx int, which, rxAnt, txAnt string) {
|
||||
if idx < 0 {
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(rxAnt) != "" {
|
||||
f.send(fmt.Sprintf("slice s %d rxant=%s", idx, rxAnt))
|
||||
}
|
||||
if strings.TrimSpace(txAnt) != "" {
|
||||
f.send(fmt.Sprintf("slice s %d txant=%s", idx, txAnt))
|
||||
}
|
||||
if strings.TrimSpace(rxAnt) != "" || strings.TrimSpace(txAnt) != "" {
|
||||
applog.Printf("flex: satellite %s slice %d rx=%s tx=%s", which, idx, rxAnt, txAnt)
|
||||
}
|
||||
}
|
||||
set(rx, "downlink", downRX, downTX)
|
||||
set(tx, "uplink", upRX, upTX)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user