// IARU band plans, by region. // // The band maps used to carry one hard-coded table — Region 1's — so a US or // Australian operator saw 40 m stop at 7200 while stations sat spotted at 7250, // and the SSB wash started 25 kHz early. The region is a station-level fact the // operator states once (Settings → General); everything drawing a band edge or // a mode segment reads it from here. // // The tables are deliberately coarse: a band map's wash is CONTEXT, not a // regulatory chart. Only the segments that differ between regions in ways an // operator notices are split out; national fine print (US licence classes, // beacon slots) does not belong in a background tint. import { writeUiPref } from '@/lib/uiPref'; export type IaruRegion = 1 | 2 | 3; export const KEY_IARU_REGION = 'opslog.iaruRegion'; export function iaruRegion(): IaruRegion { try { const v = localStorage.getItem(KEY_IARU_REGION); return v === '2' ? 2 : v === '3' ? 3 : 1; } catch { return 1; } } export function setIaruRegion(r: IaruRegion): void { writeUiPref(KEY_IARU_REGION, String(r)); listeners.forEach((l) => l()); } // The band maps capture the plan inside their render, so a change must reach // them the way the distance unit reaches the grids. const listeners = new Set<() => void>(); export function subscribeIaruRegion(fn: () => void): () => void { listeners.add(fn); return () => { listeners.delete(fn); }; } export type SegMode = 'cw' | 'digi' | 'phone'; type Seg = [number, number, SegMode]; interface Plan { ranges: Record; segments: Record; } // Region 1 — Europe / Africa / Middle East / northern Asia. The baseline the // other two override. const R1: Plan = { ranges: { '160m': [1800, 2000], '80m': [3500, 3800], '60m': [5350, 5450], '40m': [7000, 7200], '30m': [10100, 10150], '20m': [14000, 14350], '17m': [18068, 18168], '15m': [21000, 21450], '12m': [24890, 24990], '10m': [28000, 29700], '6m': [50000, 50500], '4m': [70000, 70500], '2m': [144000, 146000], '70cm': [430000, 440000], }, segments: { '160m': [[1800, 1838, 'cw'], [1838, 1840, 'digi'], [1840, 2000, 'phone']], '80m': [[3500, 3580, 'cw'], [3580, 3600, 'digi'], [3600, 3800, 'phone']], '60m': [[5350, 5450, 'phone']], '40m': [[7000, 7040, 'cw'], [7040, 7100, 'digi'], [7100, 7200, 'phone']], '30m': [[10100, 10130, 'cw'], [10130, 10150, 'digi']], '20m': [[14000, 14070, 'cw'], [14070, 14100, 'digi'], [14100, 14350, 'phone']], '17m': [[18068, 18095, 'cw'], [18095, 18110, 'digi'], [18110, 18168, 'phone']], '15m': [[21000, 21070, 'cw'], [21070, 21150, 'digi'], [21150, 21450, 'phone']], '12m': [[24890, 24915, 'cw'], [24915, 24940, 'digi'], [24940, 24990, 'phone']], '10m': [[28000, 28070, 'cw'], [28070, 28300, 'digi'], [28300, 29700, 'phone']], '6m': [[50000, 50100, 'cw'], [50100, 50500, 'phone']], }, }; // Region 2 — the Americas. 80 m runs to 4000 and 40 m to 7300, with phone from // 7125 (the whole point of asking the region: a KP4 ragchew on 7250 must not // hang past the top of the map). const R2: Plan = { ranges: { ...R1.ranges, '80m': [3500, 4000], '40m': [7000, 7300], '6m': [50000, 54000], '2m': [144000, 148000], '70cm': [420000, 450000], }, segments: { ...R1.segments, '80m': [[3500, 3570, 'cw'], [3570, 3600, 'digi'], [3600, 4000, 'phone']], '40m': [[7000, 7040, 'cw'], [7040, 7125, 'digi'], [7125, 7300, 'phone']], '6m': [[50000, 50100, 'cw'], [50100, 54000, 'phone']], }, }; // Region 3 — Asia-Pacific. 80 m to 3900; 40 m as Region 1's shape. const R3: Plan = { ranges: { ...R1.ranges, '80m': [3500, 3900], '6m': [50000, 54000], '2m': [144000, 148000], '70cm': [430000, 450000], }, segments: { ...R1.segments, '80m': [[3500, 3535, 'cw'], [3535, 3600, 'digi'], [3600, 3900, 'phone']], '6m': [[50000, 50100, 'cw'], [50100, 54000, 'phone']], }, }; function plan(): Plan { const r = iaruRegion(); return r === 2 ? R2 : r === 3 ? R3 : R1; } export function bandRange(band: string): [number, number] | undefined { return plan().ranges[band]; } export function bandSegments(band: string): Seg[] { return plan().segments[band] ?? []; }