diff --git a/BoardUtils.pas b/BoardUtils.pas index 48bd52e..1a6759a 100644 --- a/BoardUtils.pas +++ b/BoardUtils.pas @@ -32,33 +32,37 @@ implementation uses SysUtils; const - BAND_COUNT = 11; + // Максимум слотов среди всех планов (кнопки/кэши бэндов рассчитаны на это + // число). VHF/UHF-план Pluto использует все 12; HF-план (openHPSDR) — только + // 11, 12-й слот пустой (кнопка прячется, см. TMainForm.RelabelBands). + BAND_COUNT = 12; - // ---- HF/6m план (openHPSDR) ---- + // ---- 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'); + '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); + 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); + 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); + 14200000, 18130000, 21300000, 24940000, 28400000, 50150000, 0); - // ---- VHF/UHF/SHF план (Pluto / AD936x), 11 слотов ---- + // ---- 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','FM','Air','ADS-B'); + '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, 88000000, 118000000, 1087000000); + 1240000000, 2300000000, 3300000000, 65000000, 88000000, 118000000, 1087000000); VU_HI: array[0..BAND_COUNT-1] of Double = ( 54000000, 70500000, 148000000, 225000000, 440000000, - 1300000000, 2450000000, 3500000000, 108000000, 137000000, 1093000000); + 1300000000, 2450000000, 3500000000, 74000000, 108000000, 137000000, 1093000000); VU_DEF: array[0..BAND_COUNT-1] of Double = ( 50150000, 70200000, 145000000, 223500000, 433500000, - 1296200000, 2320000000, 3400100000, 100000000, 124000000, 1090000000); + 1296200000, 2320000000, 3400100000, 69000000, 100000000, 124000000, 1090000000); function BoardTypeName(BoardType: Integer): string; begin diff --git a/MainForm.pas b/MainForm.pas index 2caab1b..8a86a47 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -63,7 +63,7 @@ const CLR_SPECTRUM = TColor($0044FF44); WDSP_WISDOM_FILE = 'wdspWisdom00'; - BAND_COUNT = 11; + BAND_COUNT = 12; // макс. слотов среди планов (Pluto VHF/UHF = 12, HF = 11) MODE_COUNT = 11; // Полосы/дефолты фильтров (FILT_COUNT, FILT_*_BW, FILT_*_DEF, FILT_FM_*) // перенесены в Settings.pas — нужны TRadioController. Здесь остаются только @@ -96,8 +96,10 @@ const FM_STEP_NAMES: array[0..3] of string = ('6.25k', '12.5k', '20k', '25k'); FM_STEP_DEF = 3; // 25 kHz + // Стартовые подписи band-кнопок (HF-план); RelabelBands переписывает под + // активный бэкенд. 12-й слот пуст — в HF-плане кнопка прячется. BAND_NAMES: array[0..BAND_COUNT-1] of string = ( - '160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m'); + '160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m',''); MODE_NAMES: array[0..MODE_COUNT-1] of string = ( 'LSB','USB','DSB','CWL','CWU','FM','AM','SAM','DIGU','DIGL','WFM'); @@ -2003,6 +2005,8 @@ begin LeftPanelButtonWidth(LEFT_W, 6, i mod 6), BTN_SM, BtnBandClick); B.Tag := i; + // Пустой стартовый слот (12-й в HF-плане) прячем до RelabelBands. + if BAND_NAMES[i] = '' then B.Visible := False; BtnBand[i] := B; end; // XVTR кнопки создаются позже (в RebuildXvtrButtons), их Tag = -(idx+1) @@ -3849,7 +3853,11 @@ begin pl := FController.IsPluto; for i := 0 to BAND_COUNT - 1 do if BtnBand[i] <> nil then + begin BtnBand[i].Caption := BandName(i, pl); + // Пустой слот плана (HF: 12-й) — прячем кнопку. + BtnBand[i].Visible := BtnBand[i].Caption <> ''; + end; end; procedure TMainForm.ApplyBackendCapsToUI; diff --git a/RadioController.pas b/RadioController.pas index ce507a2..95b3d5a 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -2640,6 +2640,9 @@ procedure TRadioController.SetBand(Idx: Integer); // персист покидаемого, restore нового. Полная команда — не трогает UI. begin if (Idx < 0) or (Idx >= CFG_BAND_COUNT) then Exit; + // Пустой слот плана (HF: 12-й, зарезервирован под 12-местный план Pluto) — + // не диапазон, игнорируем (защита CAT/web/BandUp). + if BandName(Idx, IsPluto) = '' then Exit; if FCurrentXvtr >= 0 then begin DeactivateXvtr; // выход в HF (HF-возврат внутри) diff --git a/Settings.pas b/Settings.pas index 929e6df..e825d8b 100644 --- a/Settings.pas +++ b/Settings.pas @@ -10,21 +10,23 @@ uses SysUtils, Classes, Math, fpJSON, jsonparser, jsonscanner, PlatformUtils; const SETTINGS_FILE = 'hpsdr_settings.json'; - CFG_BAND_COUNT = 11; + CFG_BAND_COUNT = 12; CFG_XVTR_COUNT = 8; // количество XVTR-слотов (трансверторов) QO100_SLOT = CFG_XVTR_COUNT - 1; // последний слот зарезервирован под QO-100 // (split-LO транспондер; настраивается на // отдельной странице, не в общей XVTR-таблице) // PA gain defaults (dB) — match Thetis HERMES/HPSDR defaults // order: 160m,80m,60m,40m,30m,20m,17m,15m,12m,10m,6m + // 12-й слот — пустой в HF-плане (используется только 12-местным VHF/UHF-планом + // Pluto, где частота/режим приходят из плана BoardUtils, а не отсюда). CFG_PA_BAND_CAL_DEFAULT: array[0..CFG_BAND_COUNT-1] of Double = ( - 41.0, 41.2, 41.3, 41.3, 41.0, 40.5, 39.9, 38.8, 38.8, 38.8, 38.8); + 41.0, 41.2, 41.3, 41.3, 41.0, 40.5, 39.9, 38.8, 38.8, 38.8, 38.8, 38.8); CFG_VHF_CAL_DEFAULT = 56.2; // dB, default for all XVTR slots CFG_BAND_DEFAULT_FREQ: array[0..CFG_BAND_COUNT-1] of Double = ( 1900000, 3750000, 5357000, 7100000, 10125000, - 14200000, 18120000, 21200000, 24940000, 28500000, 50150000); + 14200000, 18120000, 21200000, 24940000, 28500000, 50150000, 50150000); CFG_BAND_DEFAULT_MODE: array[0..CFG_BAND_COUNT-1] of Integer = ( - 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1); + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); // Полосы фильтров по типу модуляции (Гц) + дефолтные индексы. Нужны // TRadioController для headless-выбора фильтра при смене режима; UI-подписи diff --git a/WebPageHtml.pas b/WebPageHtml.pas index f4a273f..8e71b6b 100644 --- a/WebPageHtml.pas +++ b/WebPageHtml.pas @@ -586,15 +586,15 @@ begin 'let XVTR_BANDS=[];let XVTR_CUR=-1;' + 'function rebuildBandSel(){const s=q("bandSel");if(!s)return;' + 'const saved=s.value;s.innerHTML="";' + - 'BAND_N.forEach((n,i)=>{const o=document.createElement("option");o.value="h"+i;o.textContent=n;s.appendChild(o);});' + + 'BAND_N.forEach((n,i)=>{if(!n)return;const o=document.createElement("option");o.value="h"+i;o.textContent=n;s.appendChild(o);});' + 'XVTR_BANDS.forEach(xb=>{const o=document.createElement("option");o.value="x"+xb.idx;o.textContent=xb.name||("X"+(xb.idx+1));s.appendChild(o);});' + // Восстановить выбор: предпочитаем "current XVTR"; иначе сохраним прежнее 'if(XVTR_CUR>=0)s.value="x"+XVTR_CUR; else if(saved)s.value=saved;' + '}' + - '(function(){const s=q("bandSel");BAND_N.forEach((n,i)=>{const o=document.createElement("option");o.value="h"+i;o.textContent=n;s.appendChild(o);});' + + '(function(){const s=q("bandSel");BAND_N.forEach((n,i)=>{if(!n)return;const o=document.createElement("option");o.value="h"+i;o.textContent=n;s.appendChild(o);});' + 's.onchange=()=>{const v=s.value;if(!v)return;if(v[0]==="x")ws2({cmd:"xvtr_band",idx:+v.slice(1)});else if(v[0]==="h")ws2({cmd:"band",idx:+v.slice(1)});};' + '})();' + - 'function updBand(vfo){if(XVTR_CUR>=0){q("bandSel").value="x"+XVTR_CUR;return;}let bi=0,bd=1e15;BAND_F.forEach((f,i)=>{const d=Math.abs((vfo||0)-f);if(d=0){q("bandSel").value="x"+XVTR_CUR;return;}let bi=0,bd=1e15;BAND_F.forEach((f,i)=>{if(!BAND_N[i])return;const d=Math.abs((vfo||0)-f);if(d