fix(bandopen): the watch switch now gates the detector
"Watch for band openings" only ever governed the extra DATA SOURCES — the RBN nodes and the PSK Reporter feed. The detector itself ran on every ordinary cluster spot regardless, so an operator who had never enabled the watch still got 10 m and 6 m opening banners from a feature he had deliberately left off. The flag is cached on bandOpenState rather than read per spot: this is the cluster hot path, where a settings query per spot is exactly what the rest of this file avoids. startBandOpenFeed owns it, and it already runs at startup and on every save, so the switch takes effect without a restart. Switching it off also clears the live badges and the accumulated spot window. The badges only fade on a timer fed by spots the detector no longer looks at, so they would otherwise hang there until the next restart; and dropping the window means switching back on starts from what is on the air rather than from an hour-old burst. The remembered openings are kept — those really happened.
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"hamlog/internal/applog"
|
||||
@@ -21,6 +22,13 @@ import (
|
||||
)
|
||||
|
||||
type bandOpenState struct {
|
||||
// on mirrors the "Watch for band openings" setting.
|
||||
//
|
||||
// Cached rather than read per spot: this is the cluster hot path, where a
|
||||
// settings query per spot is exactly what the rest of this file avoids.
|
||||
// startBandOpenFeed owns it — it runs at startup and again on every save, so
|
||||
// the switch takes effect without a restart.
|
||||
on atomic.Bool
|
||||
mu sync.Mutex
|
||||
det *bandopen.Detector
|
||||
last []bandopen.Opening // most recent first, for the UI
|
||||
@@ -45,6 +53,16 @@ const maxRememberedOpenings = 20
|
||||
|
||||
// detectBandOpening feeds one spot to the detector and announces a hit.
|
||||
func (a *App) detectBandOpening(s cluster.Spot) {
|
||||
// The watch has to be switched on.
|
||||
//
|
||||
// It was not checked here at all: the setting only ever governed the extra
|
||||
// DATA SOURCES (the RBN nodes and the PSK Reporter feed), while the detector
|
||||
// itself ran on every ordinary cluster spot. So an operator who had never
|
||||
// enabled the watch still got opening banners, from a feature they had
|
||||
// deliberately left off.
|
||||
if !a.bandOpen.on.Load() {
|
||||
return
|
||||
}
|
||||
// No operator grid = no distance and no bearing on the spot, and the whole
|
||||
// detection rests on those two. Say nothing rather than guess.
|
||||
if !a.opSet || s.DistanceKm <= 0 || !bandopen.Watched(s.Band) {
|
||||
@@ -122,6 +140,21 @@ func (a *App) GetLiveOpenings() []bandopen.Opening {
|
||||
return out
|
||||
}
|
||||
|
||||
// clearBandOpenings puts out every lit badge and forgets the detector's window.
|
||||
// Called when the watch is switched off: the badges fade on a timer fed by
|
||||
// spots the detector no longer looks at, so without this they would stay up
|
||||
// until the next restart. The remembered list is left alone — those openings
|
||||
// really did happen, and the operator may still want to see what he missed.
|
||||
func (a *App) clearBandOpenings() {
|
||||
a.bandOpen.mu.Lock()
|
||||
defer a.bandOpen.mu.Unlock()
|
||||
a.bandOpen.live = nil
|
||||
a.bandOpen.aliveUntil = nil
|
||||
// Drop the accumulated spot window too, so switching the watch back on starts
|
||||
// from what is on the air now rather than from an hour-old burst.
|
||||
a.bandOpen.det = nil
|
||||
}
|
||||
|
||||
// announceOpening logs and pushes one detection. Shared by both feeds — the
|
||||
// cluster path here and the PSK Reporter path in bandopen_sources.go — so an
|
||||
// opening reads the same however it was noticed.
|
||||
|
||||
Reference in New Issue
Block a user