|
|
|
@@ -160,6 +160,7 @@ func (a *App) applyAutoCall() {
|
|
|
|
|
e.Reset()
|
|
|
|
|
a.acMu.Lock()
|
|
|
|
|
a.acPeriod, a.acBuf = nil, nil
|
|
|
|
|
a.acJudged, a.acDirty = nil, nil
|
|
|
|
|
a.acMu.Unlock()
|
|
|
|
|
}
|
|
|
|
|
a.emitAutoCall()
|
|
|
|
@@ -279,17 +280,37 @@ func (a *App) autoCallFeed(d autocall.Decode) {
|
|
|
|
|
if a.acPeriod == nil {
|
|
|
|
|
a.acPeriod, a.acAt, a.acTR, a.acBuf = map[string]string{}, map[string]time.Time{}, map[string]int{}, map[string][]acDecode{}
|
|
|
|
|
a.acFed = map[string]time.Time{}
|
|
|
|
|
a.acJudged, a.acDirty = map[string]string{}, map[string]bool{}
|
|
|
|
|
}
|
|
|
|
|
if prev := a.acPeriod[inst]; prev != "" && prev != key {
|
|
|
|
|
prevAt, prevTR, buf := a.acAt[inst], a.acTR[inst], a.acBuf[inst]
|
|
|
|
|
// Only if something in it has NOT been judged. The buffer now outlives
|
|
|
|
|
// the judgement (see below), so without this the arrival of the next
|
|
|
|
|
// period would judge the previous one a second time on the very same
|
|
|
|
|
// decodes — and act on them, a slot late.
|
|
|
|
|
pending := a.acDirty[inst] || a.acJudged[inst] != prev
|
|
|
|
|
a.acPeriod[inst], a.acAt[inst], a.acTR[inst] = key, d.At, d.TRPeriod
|
|
|
|
|
a.acBuf[inst] = []acDecode{{d: d}}
|
|
|
|
|
a.acFed[inst], a.acDirty[inst] = time.Now(), true
|
|
|
|
|
a.acMu.Unlock()
|
|
|
|
|
a.autoCallJudge(inst, prev, prevAt, prevTR, buf)
|
|
|
|
|
// The previous period ends here whatever the sweeper was going to do: a
|
|
|
|
|
// decode stamped with the next slot is proof the old one is over.
|
|
|
|
|
if pending {
|
|
|
|
|
a.autoCallJudge(inst, prev, prevAt, prevTR, buf)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// APPENDED, never restarted. The buffer survives the period being judged,
|
|
|
|
|
// so a decode that arrives after the others belongs to the same period and
|
|
|
|
|
// is weighed against all of them.
|
|
|
|
|
//
|
|
|
|
|
// It used to be dropped and then judged on its own: the sweeper cleared the
|
|
|
|
|
// buffer, a straggler opened a "new" one under the same key, and the ladder
|
|
|
|
|
// was applied to whatever handful had come late — with the other thirty
|
|
|
|
|
// stations of that period nowhere in sight. A deep decode arriving a second
|
|
|
|
|
// after the burst is exactly the station worth calling.
|
|
|
|
|
a.acPeriod[inst], a.acAt[inst], a.acTR[inst] = key, d.At, d.TRPeriod
|
|
|
|
|
a.acFed[inst] = time.Now()
|
|
|
|
|
a.acFed[inst], a.acDirty[inst] = time.Now(), true
|
|
|
|
|
a.acBuf[inst] = append(a.acBuf[inst], acDecode{d: d})
|
|
|
|
|
a.acMu.Unlock()
|
|
|
|
|
}
|
|
|
|
@@ -344,9 +365,14 @@ func (a *App) autoCallSweep() {
|
|
|
|
|
if time.Since(a.acFed[inst]) < acQuiet {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// Judged once per period, and again only when something new has come in
|
|
|
|
|
// for it. The period itself is kept open until a decode from the NEXT one
|
|
|
|
|
// arrives, so a straggler is judged with the whole period behind it.
|
|
|
|
|
if a.acJudged[inst] == key && !a.acDirty[inst] {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
ready = append(ready, due{inst, key, a.acAt[inst], tr, a.acBuf[inst]})
|
|
|
|
|
delete(a.acPeriod, inst)
|
|
|
|
|
delete(a.acBuf, inst)
|
|
|
|
|
a.acJudged[inst], a.acDirty[inst] = key, false
|
|
|
|
|
}
|
|
|
|
|
a.acMu.Unlock()
|
|
|
|
|
for _, d := range ready {
|
|
|
|
@@ -369,7 +395,9 @@ func (a *App) autoCallSilence() {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
a.acMu.Lock()
|
|
|
|
|
quiet := a.acPeriod[inst] == "" && time.Since(a.acLastJudge) > 20*time.Second
|
|
|
|
|
// Nothing pending for this receiver, and nothing judged for a while: the
|
|
|
|
|
// band has gone quiet under it.
|
|
|
|
|
quiet := !a.acDirty[inst] && time.Since(a.acLastJudge) > 20*time.Second
|
|
|
|
|
tr := a.acTR[inst]
|
|
|
|
|
a.acMu.Unlock()
|
|
|
|
|
if !quiet {
|
|
|
|
|