fix(sat): the Flex slices get their antenna, their sideband and their tone
Three things the tracker was leaving to chance on a FlexRadio, all reported from a real pass. ANTENNAS. Settings ▸ FlexRadio holds a per-band RX/TX antenna map, and it was applied in exactly one place: the entry form, on a band change, to the active slice. A pass never goes through that path — the tracker arms two slices itself. So both were left on whatever the radio last used, and a station with transverters (XVTA on 2 m, XVTB on 70 cm) heard nothing at all, having configured precisely the thing being ignored. The two slices are on two different bands, so they cannot share one setting: the downlink takes the receive antenna for ITS band, the uplink the transmit antenna for its. Per slice, not through sendSlice, which addresses whichever slice is active — during a pass that is the downlink, so the uplink would never have been set. SIDEBAND. satMode forced USB above 30 MHz on both sides. An inverting transponder turns the passband over, so lower sideband up comes back as upper sideband down: FO-29, RS-44 and AO-73 were being worked with the operator's own audio going through upside down. The tracker now decides both sidebands from the transponder's inverting flag and passes them separately; a bare "SSB" still means USB, so nothing else changes. CTCSS. Nothing set it, on any bird. The frequency plan has carried the tone all along — 67.0 on SO-50 and AO-91, 141.3 on PO-101 — and an FM repeater does not answer without it, which is indistinguishable from a satellite that is not there. It goes on the uplink slice, value before mode so the radio cannot transmit the previous tone in the gap between two commands. Written against the SmartSDR slice API and UNTESTED on hardware. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
+74
-3
@@ -158,6 +158,7 @@ func (a *App) StartSatelliteTracking(name string, transponder int) error {
|
||||
t.status.Error = err.Error()
|
||||
} else {
|
||||
radio = "sat"
|
||||
a.applySatRadio(b.Transponders[transponder])
|
||||
}
|
||||
}
|
||||
t.status.Radio = radio
|
||||
@@ -359,11 +360,12 @@ func (a *App) satTrackStep(t *satTracker) {
|
||||
return
|
||||
}
|
||||
|
||||
mode := tp.Mode
|
||||
downMode, upMode := satSidebands(tp)
|
||||
if lastDown != 0 {
|
||||
mode = "" // set once, at the start of the pass — see satMode/satSetMode
|
||||
// Set once, at the start of the pass — see satMode/satSetMode.
|
||||
downMode, upMode = "", ""
|
||||
}
|
||||
err := a.satTune(down, up, mode, mode)
|
||||
err := a.satTune(down, up, downMode, upMode)
|
||||
t.mu.Lock()
|
||||
if err == nil {
|
||||
t.lastDown, t.lastUp, t.fails = down, up, 0
|
||||
@@ -634,3 +636,72 @@ func satBandLetter(hz int64) string {
|
||||
}
|
||||
return "K" // 24 GHz and above
|
||||
}
|
||||
|
||||
// applySatAntennas puts each satellite slice on the antenna configured for ITS
|
||||
// band.
|
||||
//
|
||||
// Settings ▸ FlexRadio already holds a per-band RX/TX antenna map, and it was
|
||||
// only ever applied by the entry form on a band change — to the active slice.
|
||||
// A pass never goes through that path: the tracker arms two slices itself, on
|
||||
// two different bands, and both were left on whatever the radio last used. A
|
||||
// station with transverters (XVTA on 2 m, XVTB on 70 cm) therefore heard
|
||||
// nothing at all, having configured exactly the thing that was being ignored.
|
||||
//
|
||||
// The bands come from the NOMINAL frequencies, not the Doppler-corrected ones:
|
||||
// a correction of ten kilohertz cannot change the band, and the nominal pair is
|
||||
// what the operator's configuration is written against.
|
||||
func (a *App) applySatRadio(tp sat.Transponder) {
|
||||
if a.cat == nil || !a.cat.SatCapable() {
|
||||
return
|
||||
}
|
||||
// The CTCSS tone first: an FM bird will not answer without it, and it is the
|
||||
// one setting an operator cannot make from the front panel once a pass has
|
||||
// started. Zero turns it off, which is what a linear bird needs.
|
||||
if err := a.cat.FlexDo(func(fc cat.FlexController) error {
|
||||
return fc.SatTone(tp.CTCSS)
|
||||
}); err != nil {
|
||||
applog.Printf("sat: could not set the uplink tone: %v", err)
|
||||
}
|
||||
|
||||
m, err := a.GetFlexBandAntennas()
|
||||
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.
|
||||
rxAnt := m[bandForHz(tp.DownLo)].RX
|
||||
txAnt := m[bandForHz(tp.UpLo)].TX
|
||||
if strings.TrimSpace(rxAnt) == "" && strings.TrimSpace(txAnt) == "" {
|
||||
return
|
||||
}
|
||||
if err := a.cat.FlexDo(func(fc cat.FlexController) error {
|
||||
return fc.SatAntennas(rxAnt, txAnt)
|
||||
}); 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.
|
||||
applog.Printf("sat: could not set the satellite antennas: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// satSidebands is which sideband to set on each side of a linear transponder.
|
||||
//
|
||||
// The two are NOT the same when the transponder inverts, and FO-29, RS-44 and
|
||||
// AO-73 all do: the passband is turned over, so a signal transmitted on lower
|
||||
// sideband comes back on upper. Setting USB at both ends — which is what
|
||||
// happened until now — put the operator's own audio through the transponder
|
||||
// upside down, which is unreadable at the far end and sounds like nothing much
|
||||
// at ours.
|
||||
//
|
||||
// Anything that is not SSB is the same on both sides: an FM repeater is FM up
|
||||
// and FM down, and CW is CW whichever way round the passband runs.
|
||||
func satSidebands(tp sat.Transponder) (downMode, upMode string) {
|
||||
if !strings.EqualFold(strings.TrimSpace(tp.Mode), "SSB") {
|
||||
return tp.Mode, tp.Mode
|
||||
}
|
||||
// Every satellite is above 30 MHz, so the downlink is upper sideband — even
|
||||
// on the AO-7 10 m downlink, which would be lower sideband on HF.
|
||||
if tp.Inverting {
|
||||
return "USB", "LSB"
|
||||
}
|
||||
return "USB", "USB"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user