feat: Super Check Partial + N+1 helper; fix Flex binding to SmartSDR CAT; telemetry callsign wait

- SCP/N+1: new internal/scp downloads the community MASTER.SCP master list and a
  docked two-column widget shows, as you type a call, the known calls containing it
  (Partial) and the calls one edit away (N+1) — click to fix a busted call. Opt-in
  in Settings → General; top-bar toggle; queried debounced on callsign input.
- Flex: OpsLog's GUI-client detection was too loose and could bind to "SmartSDR CAT"
  (or DAX) — both carry "smartsdr" in the program name — instead of the real GUI
  client, making SmartSDR CAT drop and reconnect in a loop while OpsLog was open.
  Now it binds only to a real SmartSDR/Maestro GUI client (e.g. a FLEX-8600M's
  integrated screen) and excludes cat/dax; dropped the risky empty-program fallback.
- Telemetry: on a fresh install the callsign isn't set at launch, so the once-a-day
  heartbeat recorded the machine UUID. Now it waits (~10 min) for the operator to
  enter their callsign before sending, falling back to the UUID only if none appears.
This commit is contained in:
2026-07-25 20:05:33 +02:00
parent 7e08553e6e
commit 51e279887d
12 changed files with 619 additions and 7 deletions
+8 -1
View File
@@ -518,7 +518,14 @@ func (f *Flex) handleStatus(payload string) {
alreadyBound := f.boundClientID != ""
f.mu.Unlock()
lp := strings.ToLower(program)
isGUI := program == "" || strings.Contains(lp, "smartsdr") || strings.Contains(lp, "maestro")
// The real GUI client is SmartSDR (Windows) or Maestro. Its non-GUI
// helpers "SmartSDR CAT" and "SmartSDR DAX" also carry "smartsdr" in the
// name, so exclude them — and require an explicit GUI name (dropping the
// old program=="" fallback that could match CAT before its program field
// arrived). Binding to CAT/DAX is invalid and the radio was seen to drop
// SmartSDR CAT (connect/disconnect loop) when a logger did this.
isGUI := (strings.Contains(lp, "smartsdr") || strings.Contains(lp, "maestro")) &&
!strings.Contains(lp, "cat") && !strings.Contains(lp, "dax")
if !disconnected && clientID != "" && !alreadyBound && isGUI {
f.mu.Lock()
f.boundClientID = clientID