{ Copyright (C) 2026 - Uladzimir Karpenka, EW8BAK This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. } unit BoardUtils; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface type // Один диапазон плана (имя кнопки + частота по умолчанию). Общий тип для // desktop/web UI — единый источник band-плана через TRadioController.BandPlan. TBandInfo = record Name: string; FreqHz: Double; end; TBandPlanArray = array of TBandInfo; function BoardTypeName(BoardType: Integer): string; // Короткое человекочитаемое имя AD936x-платы по hw_model (Pluto / LibreSDR / прочие). function PlutoModelName(const HwModel: string): string; // Индекс диапазона по частоте. Pluto=True → VHF/UHF план, иначе HF (openHPSDR). function FreqToBandIdx(Hz: Double; Pluto: Boolean = False): Integer; // Короткое имя диапазона для кнопки (зависит от плана). function BandName(Idx: Integer; Pluto: Boolean = False): string; // Частота по умолчанию при входе в диапазон (если нет сохранённой/в диапазоне). function BandDefaultFreq(Idx: Integer; Pluto: Boolean = False): Double; // Границы диапазона по плану. False = слот пуст/индекс вне плана (Lo=Hi=0). function BandEdges(Idx: Integer; Pluto: Boolean; out LoHz, HiHz: Double): Boolean; // Полный band-план активного бэкенда (имена + дефолтные частоты). function BuildBandPlan(Pluto: Boolean): TBandPlanArray; implementation uses SysUtils; const // Максимум слотов среди всех планов (кнопки/кэши бэндов рассчитаны на это // число). VHF/UHF-план Pluto использует все 12; HF-план (openHPSDR) — только // 11, 12-й слот пустой (кнопка прячется, см. TMainForm.RelabelBands). BAND_COUNT = 12; // ---- HF/6m план (openHPSDR), 11 диапазонов + пустой 12-й слот ---- HF_NAMES: array[0..BAND_COUNT-1] of string = ( '160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m',''); HF_LO: array[0..BAND_COUNT-1] of Double = ( 1800000, 3500000, 5330000, 7000000, 10100000, 14000000, 18068000, 21000000, 24890000, 28000000, 50000000, 0); HF_HI: array[0..BAND_COUNT-1] of Double = ( 2000000, 4000000, 5410000, 7300000, 10150000, 14350000, 18168000, 21450000, 24990000, 29700000, 54000000, 0); HF_DEF: array[0..BAND_COUNT-1] of Double = ( 1840000, 3700000, 5357000, 7100000, 10120000, 14200000, 18130000, 21300000, 24940000, 28400000, 50150000, 0); // ---- VHF/UHF/SHF план (Pluto / AD936x), 12 слотов ---- // OIRT (65..74 МГц) — вещательный УКВ-диапазон, кнопка стоит перед FM. VU_NAMES: array[0..BAND_COUNT-1] of string = ( '6m','4m','2m','1.25m','70cm','23cm','13cm','9cm','OIRT','FM','Air','ADS-B'); VU_LO: array[0..BAND_COUNT-1] of Double = ( 50000000, 70000000, 144000000, 222000000, 430000000, 1240000000, 2300000000, 3300000000, 65000000, 88000000, 118000000, 1087000000); VU_HI: array[0..BAND_COUNT-1] of Double = ( 54000000, 70500000, 148000000, 225000000, 440000000, 1300000000, 2450000000, 3500000000, 74000000, 108000000, 137000000, 1093000000); VU_DEF: array[0..BAND_COUNT-1] of Double = ( 50150000, 70200000, 145000000, 223500000, 433500000, 1296200000, 2320000000, 3400100000, 69000000, 100000000, 124000000, 1090000000); function BoardTypeName(BoardType: Integer): string; begin case BoardType of 1: Result := 'HERMES (ANAN-10/100)'; 2: Result := 'HERMES-E (ANAN-10E/100B)'; 3: Result := 'ANGELIA (ANAN-100D)'; 4: Result := 'ORION (ANAN-200D)'; 5: Result := 'ORION MkII (ANAN-7000/8000)'; 6: Result := 'HERMES-LITE 2'; 10: Result := 'SATURN (G2)'; else Result := Format('Unknown Board #%d', [BoardType]); end; end; function PlutoModelName(const HwModel: string): string; var L: string; begin // hw_model клонов AD936x обычно содержит маркер платы. Узнаём Pluto/LibreSDR, // иначе показываем сырой hw_model, а при его отсутствии — обобщённое имя. L := LowerCase(HwModel); if Pos('libre', L) > 0 then Result := 'LibreSDR' else if Pos('pluto', L) > 0 then Result := 'PlutoSDR' else if HwModel <> '' then Result := HwModel else Result := 'AD936x SDR'; end; function BandEdges(Idx: Integer; Pluto: Boolean; out LoHz, HiHz: Double): Boolean; begin LoHz := 0; HiHz := 0; Result := (Idx >= 0) and (Idx < BAND_COUNT); if not Result then Exit; if Pluto then begin LoHz := VU_LO[Idx]; HiHz := VU_HI[Idx]; end else begin LoHz := HF_LO[Idx]; HiHz := HF_HI[Idx]; end; Result := HiHz > LoHz; // пустой 12-й слот HF-плана end; function FreqToBandIdx(Hz: Double; Pluto: Boolean): Integer; var i: Integer; begin Result := -1; if Pluto then begin for i := 0 to BAND_COUNT - 1 do if (Hz >= VU_LO[i]) and (Hz <= VU_HI[i]) then Exit(i); end else begin for i := 0 to BAND_COUNT - 1 do if (Hz >= HF_LO[i]) and (Hz <= HF_HI[i]) then Exit(i); end; end; function BandName(Idx: Integer; Pluto: Boolean): string; begin if (Idx < 0) or (Idx >= BAND_COUNT) then Exit(''); if Pluto then Result := VU_NAMES[Idx] else Result := HF_NAMES[Idx]; end; function BandDefaultFreq(Idx: Integer; Pluto: Boolean): Double; begin if (Idx < 0) or (Idx >= BAND_COUNT) then Exit(0); if Pluto then Result := VU_DEF[Idx] else Result := HF_DEF[Idx]; end; function BuildBandPlan(Pluto: Boolean): TBandPlanArray; var i: Integer; begin SetLength(Result, BAND_COUNT); for i := 0 to BAND_COUNT - 1 do begin if Pluto then begin Result[i].Name := VU_NAMES[i]; Result[i].FreqHz := VU_DEF[i]; end else begin Result[i].Name := HF_NAMES[i]; Result[i].FreqHz := HF_DEF[i]; end; end; end; end.