A spot at 10131.5 showed as DATA in the cluster list and raised an alert announcing SSB. Two tables answered the same question: the frontend knew 10.130-10.150 is the 30 m data segment, while the alert engine knew a CW range that stopped at 10.130 and ended with a bare 'return SSB' for everything else. That fall-through was the fault. A band plan that answers 'SSB' for anything it does not recognise is not a band plan, it is a default wearing one — and it fed the alert text, the FlexRadio spot colours and the mode the radio is told to switch to. The Go table is now transcribed from the frontend's, segment for segment, and returns nothing where it knows nothing. The order matters and is now load-bearing — the FT8 and FT4 watering holes are listed BEFORE the wide data blocks they sit inside — so there is a test that fails if anybody sorts the table by frequency and quietly turns every FT8 hole into DATA. WPM counts as CW while we are here: nothing else is reported in words per minute, and RBN puts it on every line.
77 lines
3.2 KiB
Go
77 lines
3.2 KiB
Go
package alerts
|
|
|
|
// The band plan behind InferMode, and why it is written out segment by segment.
|
|
//
|
|
// A cluster line carries no mode, so it has to be inferred — and OpsLog was
|
|
// inferring it TWICE, in two places, from two different tables. The frontend
|
|
// knew that 10.130-10.150 is the 30 m data segment; this side only knew a CW
|
|
// range that stopped at 10.130 and called everything after it SSB. So a spot at
|
|
// 10131.5 showed as DATA in the cluster list and raised an alert saying SSB.
|
|
// Reported with a screenshot of exactly that, on RI1FJL.
|
|
//
|
|
// The two tables are now the same table, transcribed from the frontend's
|
|
// (frontend/src/lib/spot.ts) with its segment boundaries kept intact. They stay
|
|
// two files because they are two languages, and the test next door is what
|
|
// keeps them one answer.
|
|
|
|
// modeSeg is one stretch of a band, in Hz, and what is worked there.
|
|
type modeSeg struct {
|
|
loHz, hiHz int64
|
|
mode string
|
|
}
|
|
|
|
// bandPlan is scanned IN ORDER, so a narrow watering hole listed before the
|
|
// wide segment it sits inside wins — FT8 at 14.074 before the 14.070-14.100
|
|
// data block. Order is the whole mechanism here; sorting this table by
|
|
// frequency would quietly turn every FT8 hole into "DATA".
|
|
var bandPlan = []modeSeg{
|
|
{1_800_000, 1_838_000, "CW"}, {1_838_000, 1_840_000, "FT8"}, {1_840_000, 2_000_000, "SSB"},
|
|
|
|
{3_573_000, 3_576_000, "FT8"}, {3_500_000, 3_580_000, "CW"},
|
|
{3_580_000, 3_600_000, "DATA"}, {3_600_000, 4_000_000, "SSB"},
|
|
|
|
{5_300_000, 5_500_000, "SSB"},
|
|
|
|
{7_074_000, 7_077_000, "FT8"}, {7_047_500, 7_048_500, "FT4"},
|
|
{7_000_000, 7_040_000, "CW"}, {7_040_000, 7_100_000, "DATA"}, {7_100_000, 7_300_000, "SSB"},
|
|
|
|
// 30 m: CW to 10.130, data above it — and nothing else. No SSB on this band.
|
|
{10_100_000, 10_130_000, "CW"}, {10_130_000, 10_150_000, "DATA"},
|
|
|
|
{14_074_000, 14_077_000, "FT8"}, {14_080_000, 14_081_500, "FT4"},
|
|
{14_000_000, 14_070_000, "CW"}, {14_070_000, 14_100_000, "DATA"}, {14_100_000, 14_350_000, "SSB"},
|
|
|
|
{18_100_000, 18_103_000, "FT8"},
|
|
{18_068_000, 18_095_000, "CW"}, {18_095_000, 18_110_000, "DATA"}, {18_110_000, 18_168_000, "SSB"},
|
|
|
|
{21_074_000, 21_077_000, "FT8"}, {21_140_000, 21_143_000, "FT4"},
|
|
{21_000_000, 21_070_000, "CW"}, {21_070_000, 21_150_000, "DATA"}, {21_150_000, 21_450_000, "SSB"},
|
|
|
|
{24_915_000, 24_917_000, "FT8"},
|
|
{24_890_000, 24_915_000, "CW"}, {24_915_000, 24_940_000, "DATA"}, {24_940_000, 24_990_000, "SSB"},
|
|
|
|
{28_074_000, 28_077_000, "FT8"}, {28_180_000, 28_183_000, "FT4"},
|
|
{28_000_000, 28_070_000, "CW"}, {28_070_000, 28_300_000, "DATA"}, {28_300_000, 29_700_000, "SSB"},
|
|
|
|
{50_313_000, 50_316_000, "FT8"}, {50_318_000, 50_321_000, "FT4"},
|
|
{50_000_000, 50_100_000, "CW"}, {50_100_000, 50_500_000, "SSB"},
|
|
|
|
{144_174_000, 144_177_000, "FT8"},
|
|
{144_000_000, 144_150_000, "CW"}, {144_150_000, 144_500_000, "SSB"},
|
|
}
|
|
|
|
// modeFromFrequency returns what the band plan says is worked at freqHz, or ""
|
|
// where it says nothing.
|
|
//
|
|
// Empty rather than a guess: a spot outside every listed segment is on a band
|
|
// this table does not cover, and answering "SSB" for it is how a 30 m data spot
|
|
// came to raise an SSB alert.
|
|
func modeFromFrequency(freqHz int64) string {
|
|
for _, s := range bandPlan {
|
|
if freqHz >= s.loHz && freqHz < s.hiHz {
|
|
return s.mode
|
|
}
|
|
}
|
|
return ""
|
|
}
|