feat(app): auto-call, PSK Reporter analysis and the decode band change
The Wails boundary for the two features above, plus the pieces that belong to neither: - decodes are cut into periods PER RECEIVER, and judged 0.8 s after the last one arrives rather than a slot and four seconds after the period they belong to. That stamp is the START of the slot, thirteen seconds before its decodes exist, so every answer left four seconds into the next slot and the decoder began its call late. - WSJT-X colouring can grey out a station already worked on this band AND in this mode. Its own switch, off by default: the other three verdicts pick out a handful of decodes, this one can match most of a period on a full log. - the watch list's contest auto-add takes a list of callsigns as well as a pattern. A pattern collects a fleet that shares a string; it cannot collect the station taking part under a callsign that says nothing about the event.
This commit is contained in:
@@ -753,6 +753,9 @@ type App struct {
|
||||
// is consulted once per message.
|
||||
chaseBandsMu sync.RWMutex
|
||||
chaseBands map[string]bool
|
||||
// The Chase new panel's OWN band filter, as the set switched off. Read per
|
||||
// message like the list above, so an atomic rather than a settings lookup.
|
||||
chaseNewBandsOff atomic.Value // map[string]bool
|
||||
// pskr is the PSK Reporter MQTT feed, up only while the opening watch is on.
|
||||
// It is the source that makes VHF detection work at all: the cluster and RBN
|
||||
// carry a handful of 6 m spots where PSK Reporter carries hundreds.
|
||||
@@ -773,8 +776,12 @@ type App struct {
|
||||
// FT8 window and an FT4 one do not even share a period length — and one
|
||||
// buffer for both cut every slot into fragments, each judged as a period of
|
||||
// its own. The engine then counted a missed period several times a slot.
|
||||
acPeriod map[string]string
|
||||
acAt map[string]time.Time
|
||||
acPeriod map[string]string
|
||||
acAt map[string]time.Time
|
||||
// acFed is when the last decode of the open period ARRIVED, wall clock. The
|
||||
// period's own timestamp cannot answer "has it gone quiet" — it is the start
|
||||
// of the slot, thirteen seconds before its decodes exist.
|
||||
acFed map[string]time.Time
|
||||
acTR map[string]int
|
||||
acBuf map[string][]acDecode
|
||||
acTX autocall.TXState
|
||||
@@ -782,6 +789,10 @@ type App struct {
|
||||
acLastJudge time.Time
|
||||
// acTXPeriod is the last transmit period already counted — see autoCallNoteTX.
|
||||
acTXPeriod string
|
||||
// What the decodes panel is SHOWING, and whether it is publishing at all.
|
||||
// The panel owns the filters; this is its answer, not a second copy of them.
|
||||
acVisible map[string]bool
|
||||
acVisibleOn bool
|
||||
// Self-spot throttle: when and on what frequency we last announced ourselves.
|
||||
// Held in memory only — a restart legitimately re-announces the station.
|
||||
selfSpotMu sync.Mutex
|
||||
@@ -1653,6 +1664,7 @@ func (a *App) startup(ctx context.Context) {
|
||||
a.startGridCache()
|
||||
a.chaseNew = newChaseNewStore()
|
||||
a.refreshChaseNew()
|
||||
a.refreshChaseNewBands()
|
||||
// PSK Reporter. After the operator's grid is known: without it there is no
|
||||
// distance to measure and no receiver squares to filter on, so it stays down.
|
||||
a.startBandOpenFeed()
|
||||
@@ -20578,6 +20590,15 @@ func (a *App) SaveChaseSettings(cs ChaseSettings) error {
|
||||
a.clusterStatusMu.Lock()
|
||||
a.clusterStatusIdx = nil
|
||||
a.clusterStatusMu.Unlock()
|
||||
// Chase new judges each decode AS IT ARRIVES and keeps only what was new at
|
||||
// that moment, so its list is a set of verdicts reached under the old rule —
|
||||
// and nothing in it would ever be re-judged. Switching to "new only" left
|
||||
// rows listed that are merely unconfirmed; switching the other way could not
|
||||
// bring back what had already been refused. Emptied, it refills from the
|
||||
// live feed within a period or two, under the rule now in force.
|
||||
if a.chaseNew != nil {
|
||||
a.chaseNew.clear()
|
||||
}
|
||||
// The frontend caches resolved verdicts and only asks about unknown keys —
|
||||
// without this it kept judging half the screen under the OLD rules until a
|
||||
// restart, which read as the new mode simply not working.
|
||||
|
||||
Vendored
+8
@@ -454,6 +454,8 @@ export function GetChangelog():Promise<Array<main.ChangelogEntry>>;
|
||||
|
||||
export function GetChaseNew():Promise<boolean>;
|
||||
|
||||
export function GetChaseNewBands():Promise<Array<string>>;
|
||||
|
||||
export function GetChaseNewGrids():Promise<boolean>;
|
||||
|
||||
export function GetChaseNewSpots():Promise<Array<main.ChaseNewSpot>>;
|
||||
@@ -654,6 +656,8 @@ export function GetYaesuState():Promise<cat.YaesuTXState>;
|
||||
|
||||
export function GridSquares(arg1:string):Promise<Array<qso.GridSquare>>;
|
||||
|
||||
export function HaltAutoCall():Promise<void>;
|
||||
|
||||
export function HaltDecodeTx(arg1:string,arg2:boolean):Promise<void>;
|
||||
|
||||
export function HasBuiltinReferences(arg1:string):Promise<boolean>;
|
||||
@@ -1158,6 +1162,8 @@ export function SetAutoCall(arg1:boolean):Promise<void>;
|
||||
|
||||
export function SetAutoCallOnly(arg1:string):Promise<void>;
|
||||
|
||||
export function SetAutoCallVisible(arg1:Array<string>,arg2:boolean):Promise<void>;
|
||||
|
||||
export function SetCATFrequency(arg1:number):Promise<void>;
|
||||
|
||||
export function SetCATMode(arg1:string):Promise<void>;
|
||||
@@ -1168,6 +1174,8 @@ export function SetCWDecoderPitch(arg1:number):Promise<void>;
|
||||
|
||||
export function SetChaseNew(arg1:boolean):Promise<void>;
|
||||
|
||||
export function SetChaseNewBands(arg1:Array<string>):Promise<void>;
|
||||
|
||||
export function SetChaseNewGrids(arg1:boolean):Promise<void>;
|
||||
|
||||
export function SetClublogCtyEnabled(arg1:boolean):Promise<void>;
|
||||
|
||||
@@ -842,6 +842,10 @@ export function GetChaseNew() {
|
||||
return window['go']['main']['App']['GetChaseNew']();
|
||||
}
|
||||
|
||||
export function GetChaseNewBands() {
|
||||
return window['go']['main']['App']['GetChaseNewBands']();
|
||||
}
|
||||
|
||||
export function GetChaseNewGrids() {
|
||||
return window['go']['main']['App']['GetChaseNewGrids']();
|
||||
}
|
||||
@@ -1242,6 +1246,10 @@ export function GridSquares(arg1) {
|
||||
return window['go']['main']['App']['GridSquares'](arg1);
|
||||
}
|
||||
|
||||
export function HaltAutoCall() {
|
||||
return window['go']['main']['App']['HaltAutoCall']();
|
||||
}
|
||||
|
||||
export function HaltDecodeTx(arg1, arg2) {
|
||||
return window['go']['main']['App']['HaltDecodeTx'](arg1, arg2);
|
||||
}
|
||||
@@ -2250,6 +2258,10 @@ export function SetAutoCallOnly(arg1) {
|
||||
return window['go']['main']['App']['SetAutoCallOnly'](arg1);
|
||||
}
|
||||
|
||||
export function SetAutoCallVisible(arg1, arg2) {
|
||||
return window['go']['main']['App']['SetAutoCallVisible'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function SetCATFrequency(arg1) {
|
||||
return window['go']['main']['App']['SetCATFrequency'](arg1);
|
||||
}
|
||||
@@ -2270,6 +2282,10 @@ export function SetChaseNew(arg1) {
|
||||
return window['go']['main']['App']['SetChaseNew'](arg1);
|
||||
}
|
||||
|
||||
export function SetChaseNewBands(arg1) {
|
||||
return window['go']['main']['App']['SetChaseNewBands'](arg1);
|
||||
}
|
||||
|
||||
export function SetChaseNewGrids(arg1) {
|
||||
return window['go']['main']['App']['SetChaseNewGrids'](arg1);
|
||||
}
|
||||
|
||||
@@ -1962,6 +1962,8 @@ export namespace main {
|
||||
misses: number;
|
||||
max_rounds: number;
|
||||
rest_min: number;
|
||||
on_screen_only: boolean;
|
||||
trace: boolean;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new AutoCallSettings(source);
|
||||
@@ -1976,6 +1978,8 @@ export namespace main {
|
||||
this.misses = source["misses"];
|
||||
this.max_rounds = source["max_rounds"];
|
||||
this.rest_min = source["rest_min"];
|
||||
this.on_screen_only = source["on_screen_only"];
|
||||
this.trace = source["trace"];
|
||||
}
|
||||
}
|
||||
export class AutoCallStatus {
|
||||
@@ -1987,6 +1991,7 @@ export namespace main {
|
||||
misses: number;
|
||||
max_miss: number;
|
||||
stopped: boolean;
|
||||
greylisted: number;
|
||||
reason: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
@@ -2003,6 +2008,7 @@ export namespace main {
|
||||
this.misses = source["misses"];
|
||||
this.max_miss = source["max_miss"];
|
||||
this.stopped = source["stopped"];
|
||||
this.greylisted = source["greylisted"];
|
||||
this.reason = source["reason"];
|
||||
}
|
||||
}
|
||||
@@ -4962,6 +4968,8 @@ export namespace pskr {
|
||||
last_err?: string;
|
||||
broker: string;
|
||||
bands: string[];
|
||||
near_km: number;
|
||||
squares: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Status(source);
|
||||
@@ -4975,6 +4983,8 @@ export namespace pskr {
|
||||
this.last_err = source["last_err"];
|
||||
this.broker = source["broker"];
|
||||
this.bands = source["bands"];
|
||||
this.near_km = source["near_km"];
|
||||
this.squares = source["squares"];
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
|
||||
Reference in New Issue
Block a user