added SkyCAT support

This commit is contained in:
2026-03-25 00:18:12 +01:00
parent 313d22be2e
commit 5b31a9a9d8
8 changed files with 432 additions and 22 deletions

93
app.go
View File

@@ -9,11 +9,21 @@ import (
"SatMaster/backend/flexradio"
"SatMaster/backend/propagator"
"SatMaster/backend/rotor"
"SatMaster/backend/skycat"
"SatMaster/backend/tle"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
// RadioClient is the common interface for FlexRadio and SkyCAT backends.
type RadioClient interface {
IsConnected() bool
SetFrequency(downHz, upHz float64) error
SetMode(mode string) error
ResetDeadband()
Disconnect()
}
// App holds all subsystems and is the Wails binding target.
type App struct {
dopplerEnabled bool
@@ -23,11 +33,13 @@ type App struct {
trackAzimuth bool // Track azimuth for current sat
savedRxSlice int
savedTxSlice int
radioType string // "flex" or "skycat"
ctx context.Context
tleManager *tle.Manager
propagator *propagator.Engine
flexRadio *flexradio.Client
skyCat *skycat.Client
rotorClient *rotor.PstRotatorClient
dopplerCalc *doppler.Calculator
@@ -47,9 +59,11 @@ func NewApp() *App {
trackAzimuth: false,
savedRxSlice: 0, // defaults — overridden by SetSliceConfig from Settings on connect
savedTxSlice: 1,
radioType: "flex",
tleManager: tle.NewManager(),
propagator: propagator.NewEngine(),
flexRadio: flexradio.NewClient(),
skyCat: skycat.NewClient(),
rotorClient: rotor.NewPstRotatorClient(),
dopplerCalc: doppler.NewCalculator(),
watchlist: []string{"ISS (ZARYA)", "AO-7", "AO-27", "SO-50", "RS-44", "AO-91", "FO-29"},
@@ -92,9 +106,18 @@ func (a *App) startup(ctx context.Context) {
go a.positionLoop(ctx)
}
// activeRadio returns the currently selected radio client.
func (a *App) activeRadio() RadioClient {
if a.radioType == "skycat" {
return a.skyCat
}
return a.flexRadio
}
func (a *App) shutdown(ctx context.Context) {
a.StopTracking()
a.flexRadio.Disconnect()
a.skyCat.Disconnect()
}
// positionLoop emits sat positions to frontend every second.
@@ -142,9 +165,9 @@ func (a *App) updateTracking() {
obs := a.propagator.ObserverPosition()
// Doppler: only when globally enabled AND tracking enabled for this sat AND el >= 0
if a.flexRadio.IsConnected() && pos.Elevation >= 0 && a.dopplerEnabled && a.trackFreqMode {
if a.activeRadio().IsConnected() && pos.Elevation >= 0 && a.dopplerEnabled && a.trackFreqMode {
upFreq, downFreq := a.dopplerCalc.Correct(pos, obs, now)
if err := a.flexRadio.SetFrequency(downFreq, upFreq); err != nil {
if err := a.activeRadio().SetFrequency(downFreq, upFreq); err != nil {
log.Printf("[Doppler] SetFrequency error: %v", err)
}
}
@@ -199,15 +222,21 @@ func (a *App) SetSatelliteFrequencies(downHz, upHz float64) {
a.dopplerCalc.SetNominal(downHz, upHz)
}
// SetSatelliteMode sets the FlexRadio slice mode for satellite operation.
// SetSatelliteMode sets the radio mode for satellite operation.
// Called automatically when a frequency is selected in the frontend.
func (a *App) SetSatelliteMode(mode string) {
if !a.flexRadio.IsConnected() {
radio := a.activeRadio()
if !radio.IsConnected() {
return
}
flexMode := flexradio.SatModeToFlex(mode)
if err := a.flexRadio.SetMode(flexMode); err != nil {
log.Printf("[FlexRadio] SetMode error: %v", err)
var converted string
if a.radioType == "skycat" {
converted = skycat.SatModeToSkyCAT(mode)
} else {
converted = flexradio.SatModeToFlex(mode)
}
if err := radio.SetMode(converted); err != nil {
log.Printf("[Radio] SetMode error: %v", err)
}
}
@@ -304,7 +333,7 @@ func (a *App) SetTrackFreqMode(enabled bool) {
a.trackFreqMode = enabled
// Reset dead-band so freq is sent immediately when tracking starts
if enabled {
a.flexRadio.ResetDeadband()
a.activeRadio().ResetDeadband()
}
log.Printf("[Doppler] Freq/Mode tracking: %v", enabled)
}
@@ -330,11 +359,57 @@ func (a *App) GetDopplerEnabled() bool {
return a.dopplerEnabled
}
// GetFlexRadioStatus returns connection status.
// GetFlexRadioStatus returns FlexRadio connection status.
func (a *App) GetFlexRadioStatus() bool {
return a.flexRadio.IsConnected()
}
// SetRadioType switches between "flex" and "skycat" backends.
func (a *App) SetRadioType(radioType string) {
a.radioType = radioType
log.Printf("[Radio] Backend switched to: %s", radioType)
}
// GetRadioType returns the current radio backend type.
func (a *App) GetRadioType() string {
return a.radioType
}
// ConnectSkyCAT connects to skycatd TCP server.
func (a *App) ConnectSkyCAT(host string, port int) string {
if err := a.skyCat.Connect(host, port); err != nil {
return "Error: " + err.Error()
}
return "OK"
}
// DisconnectSkyCAT closes the SkyCAT connection.
func (a *App) DisconnectSkyCAT() {
a.skyCat.Disconnect()
}
// GetSkyCATStatus returns SkyCAT connection status.
func (a *App) GetSkyCATStatus() bool {
return a.skyCat.IsConnected()
}
// SetSkyCATMode sets the SkyCAT satellite operating mode (Duplex/Split/Simplex).
func (a *App) SetSkyCATMode(mode string) string {
var m skycat.SatMode
switch mode {
case "Split":
m = skycat.ModeSplit
case "Simplex":
m = skycat.ModeSimplex
default:
m = skycat.ModeDuplex
}
if err := a.skyCat.SetSatMode(m); err != nil {
return "Error: " + err.Error()
}
return "OK"
}
// GetSliceConfig returns current RX/TX slice indices.
func (a *App) GetSliceConfig() map[string]int {
rx, tx := a.flexRadio.GetSlices()