feat: added versionning & About window
This commit is contained in:
+71
-19
@@ -184,6 +184,48 @@ func (m *Manager) SetPTT(on bool) error {
|
||||
return m.exec(func(b Backend) error { return b.SetPTT(on) })
|
||||
}
|
||||
|
||||
// SpotInfo is one cluster spot to render on a backend that supports a spot
|
||||
// overlay (the FlexRadio panadapter). Color is an optional "#AARRGGBB" string;
|
||||
// the backend picks a default when it's empty. (Status-based colouring can be
|
||||
// driven later by setting Color per spot.)
|
||||
type SpotInfo struct {
|
||||
FreqHz int64
|
||||
Callsign string
|
||||
Mode string
|
||||
Color string
|
||||
Comment string
|
||||
}
|
||||
|
||||
// Spotter is an OPTIONAL backend capability: show cluster spots on the radio
|
||||
// (FlexRadio panadapter). Backends that don't implement it are simply skipped.
|
||||
type Spotter interface {
|
||||
SendSpot(SpotInfo) error
|
||||
}
|
||||
|
||||
// SendSpot pushes a cluster spot to the backend if it supports spotting. Runs on
|
||||
// the CAT goroutine and is fire-and-forget (dropped if the queue is busy) — a
|
||||
// missed spot on the panadapter is harmless.
|
||||
func (m *Manager) SendSpot(s SpotInfo) {
|
||||
m.mu.RLock()
|
||||
cmds := m.cmdCh
|
||||
b := m.backend
|
||||
m.mu.RUnlock()
|
||||
if cmds == nil || b == nil {
|
||||
return
|
||||
}
|
||||
if _, ok := b.(Spotter); !ok {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case cmds <- func() {
|
||||
if sp, ok := b.(Spotter); ok {
|
||||
_ = sp.SendSpot(s)
|
||||
}
|
||||
}:
|
||||
default: // queue busy → drop this spot
|
||||
}
|
||||
}
|
||||
|
||||
// exec marshals a backend operation onto the CAT goroutine. Returns the
|
||||
// operation's error or a "busy"/"not running" error if dispatch failed.
|
||||
func (m *Manager) exec(fn func(Backend) error) error {
|
||||
@@ -210,23 +252,27 @@ func (m *Manager) run(b Backend, stop, done chan struct{}, cmds chan func(), pol
|
||||
defer runtime.UnlockOSThread()
|
||||
defer close(done)
|
||||
|
||||
if err := b.Connect(); err != nil {
|
||||
m.update(RigState{
|
||||
Enabled: true, Backend: b.Name(), Connected: false,
|
||||
Error: err.Error(), UpdatedAt: time.Now(),
|
||||
})
|
||||
// Stay idle until Stop is called — let the user fix config and re-Start.
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
case fn := <-cmds:
|
||||
fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
defer b.Disconnect()
|
||||
|
||||
// Connection is (re)established lazily and retried with a backoff, so a rig
|
||||
// that's off at startup — or a FlexRadio that reboots/drops its TCP link —
|
||||
// reconnects on its own instead of staying dead until the user toggles CAT.
|
||||
const reconnectEvery = 5 * time.Second
|
||||
connected := false
|
||||
var lastAttempt time.Time
|
||||
tryConnect := func() {
|
||||
if connected || time.Since(lastAttempt) < reconnectEvery {
|
||||
return
|
||||
}
|
||||
lastAttempt = time.Now()
|
||||
if err := b.Connect(); err != nil {
|
||||
m.update(RigState{Enabled: true, Backend: b.Name(), Connected: false, Error: err.Error(), UpdatedAt: time.Now()})
|
||||
return
|
||||
}
|
||||
connected = true
|
||||
}
|
||||
tryConnect()
|
||||
|
||||
ticker := time.NewTicker(pollEvery)
|
||||
defer ticker.Stop()
|
||||
|
||||
@@ -238,12 +284,18 @@ func (m *Manager) run(b Backend, stop, done chan struct{}, cmds chan func(), pol
|
||||
fn()
|
||||
m.applyCommandDelay()
|
||||
case <-ticker.C:
|
||||
if !connected {
|
||||
tryConnect()
|
||||
continue
|
||||
}
|
||||
ns, err := b.ReadState()
|
||||
if err != nil {
|
||||
m.update(RigState{
|
||||
Enabled: true, Backend: b.Name(), Connected: false,
|
||||
Error: err.Error(), UpdatedAt: time.Now(),
|
||||
})
|
||||
// Lost the rig — drop the backend so the next attempt reconnects
|
||||
// cleanly, then back off before retrying.
|
||||
connected = false
|
||||
lastAttempt = time.Now()
|
||||
b.Disconnect()
|
||||
m.update(RigState{Enabled: true, Backend: b.Name(), Connected: false, Error: err.Error(), UpdatedAt: time.Now()})
|
||||
continue
|
||||
}
|
||||
ns.Enabled = true
|
||||
|
||||
Reference in New Issue
Block a user