Files
ewsdr/BoardUtils.pas
T
ew8bakandClaude Opus 4.8 4749cf0cbc feat: unify band plan across desktop + web UIs
Web band selector was hardcoded to the HF plan, so on Pluto it showed
160m..6m instead of the VHF/UHF plan and highlighted the wrong entry
(band switching itself already worked: web sends idx, controller maps it
via the IsPluto plan). Mirror the sample-rate unification.

Single source of truth = BoardUtils -> controller:
- BoardUtils: TBandInfo/TBandPlanArray + BuildBandPlan(Pluto).
- TRadioController.BandPlan returns BuildBandPlan(IsPluto).

Both UIs derive from it:
- Desktop already plan-aware (RelabelBands + RestoreBand) - unchanged.
- Web: WebServer.SetBands + "bands" in state JSON; hosts push
  BandPlan on connect/startup; JS builds the band selector from
  state.bands (BAND_N/BAND_F now dynamic).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 14:01:23 +03:00

139 lines
4.8 KiB
ObjectPascal

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;
// Полный band-план активного бэкенда (имена + дефолтные частоты).
function BuildBandPlan(Pluto: Boolean): TBandPlanArray;
implementation
uses SysUtils;
const
BAND_COUNT = 11;
// ---- HF/6m план (openHPSDR) ----
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);
HF_HI: array[0..BAND_COUNT-1] of Double = (
2000000, 4000000, 5410000, 7300000, 10150000,
14350000, 18168000, 21450000, 24990000, 29700000, 54000000);
HF_DEF: array[0..BAND_COUNT-1] of Double = (
1840000, 3700000, 5357000, 7100000, 10120000,
14200000, 18130000, 21300000, 24940000, 28400000, 50150000);
// ---- VHF/UHF/SHF план (Pluto / AD936x), 11 слотов ----
VU_NAMES: array[0..BAND_COUNT-1] of string = (
'6m','4m','2m','1.25m','70cm','23cm','13cm','9cm','FM','Air','ADS-B');
VU_LO: array[0..BAND_COUNT-1] of Double = (
50000000, 70000000, 144000000, 222000000, 430000000,
1240000000, 2300000000, 3300000000, 88000000, 118000000, 1087000000);
VU_HI: array[0..BAND_COUNT-1] of Double = (
54000000, 70500000, 148000000, 225000000, 440000000,
1300000000, 2450000000, 3500000000, 108000000, 137000000, 1093000000);
VU_DEF: array[0..BAND_COUNT-1] of Double = (
50150000, 70200000, 145000000, 223500000, 433500000,
1296200000, 2320000000, 3400100000, 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 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.