mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat(bandplan): диапазон OIRT 65-74 МГц в плане Pluto (кнопка перед FM)
VU-план (Pluto) расширен до 12 слотов: OIRT (65..74 МГц, дефолт 69 МГц) вставлен перед FM. HF-план (openHPSDR) остаётся 11-диапазонным — 12-й слот пустой, кнопка прячется (RelabelBands). CAT индексный (OIRT = band 08 на Pluto), SetBand игнорирует пустой слот. Web bandSel строится динамически из BandPlan; пустые слоты пропускаются. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+15
-11
@@ -32,33 +32,37 @@ implementation
|
|||||||
uses SysUtils;
|
uses SysUtils;
|
||||||
|
|
||||||
const
|
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 = (
|
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 = (
|
HF_LO: array[0..BAND_COUNT-1] of Double = (
|
||||||
1800000, 3500000, 5330000, 7000000, 10100000,
|
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 = (
|
HF_HI: array[0..BAND_COUNT-1] of Double = (
|
||||||
2000000, 4000000, 5410000, 7300000, 10150000,
|
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 = (
|
HF_DEF: array[0..BAND_COUNT-1] of Double = (
|
||||||
1840000, 3700000, 5357000, 7100000, 10120000,
|
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 = (
|
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 = (
|
VU_LO: array[0..BAND_COUNT-1] of Double = (
|
||||||
50000000, 70000000, 144000000, 222000000, 430000000,
|
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 = (
|
VU_HI: array[0..BAND_COUNT-1] of Double = (
|
||||||
54000000, 70500000, 148000000, 225000000, 440000000,
|
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 = (
|
VU_DEF: array[0..BAND_COUNT-1] of Double = (
|
||||||
50150000, 70200000, 145000000, 223500000, 433500000,
|
50150000, 70200000, 145000000, 223500000, 433500000,
|
||||||
1296200000, 2320000000, 3400100000, 100000000, 124000000, 1090000000);
|
1296200000, 2320000000, 3400100000, 69000000, 100000000, 124000000, 1090000000);
|
||||||
|
|
||||||
function BoardTypeName(BoardType: Integer): string;
|
function BoardTypeName(BoardType: Integer): string;
|
||||||
begin
|
begin
|
||||||
|
|||||||
+10
-2
@@ -63,7 +63,7 @@ const
|
|||||||
CLR_SPECTRUM = TColor($0044FF44);
|
CLR_SPECTRUM = TColor($0044FF44);
|
||||||
WDSP_WISDOM_FILE = 'wdspWisdom00';
|
WDSP_WISDOM_FILE = 'wdspWisdom00';
|
||||||
|
|
||||||
BAND_COUNT = 11;
|
BAND_COUNT = 12; // макс. слотов среди планов (Pluto VHF/UHF = 12, HF = 11)
|
||||||
MODE_COUNT = 11;
|
MODE_COUNT = 11;
|
||||||
// Полосы/дефолты фильтров (FILT_COUNT, FILT_*_BW, FILT_*_DEF, FILT_FM_*)
|
// Полосы/дефолты фильтров (FILT_COUNT, FILT_*_BW, FILT_*_DEF, FILT_FM_*)
|
||||||
// перенесены в Settings.pas — нужны TRadioController. Здесь остаются только
|
// перенесены в Settings.pas — нужны TRadioController. Здесь остаются только
|
||||||
@@ -96,8 +96,10 @@ const
|
|||||||
FM_STEP_NAMES: array[0..3] of string = ('6.25k', '12.5k', '20k', '25k');
|
FM_STEP_NAMES: array[0..3] of string = ('6.25k', '12.5k', '20k', '25k');
|
||||||
FM_STEP_DEF = 3; // 25 kHz
|
FM_STEP_DEF = 3; // 25 kHz
|
||||||
|
|
||||||
|
// Стартовые подписи band-кнопок (HF-план); RelabelBands переписывает под
|
||||||
|
// активный бэкенд. 12-й слот пуст — в HF-плане кнопка прячется.
|
||||||
BAND_NAMES: array[0..BAND_COUNT-1] of string = (
|
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 = (
|
MODE_NAMES: array[0..MODE_COUNT-1] of string = (
|
||||||
'LSB','USB','DSB','CWL','CWU','FM','AM','SAM','DIGU','DIGL','WFM');
|
'LSB','USB','DSB','CWL','CWU','FM','AM','SAM','DIGU','DIGL','WFM');
|
||||||
@@ -2003,6 +2005,8 @@ begin
|
|||||||
LeftPanelButtonWidth(LEFT_W, 6, i mod 6),
|
LeftPanelButtonWidth(LEFT_W, 6, i mod 6),
|
||||||
BTN_SM, BtnBandClick);
|
BTN_SM, BtnBandClick);
|
||||||
B.Tag := i;
|
B.Tag := i;
|
||||||
|
// Пустой стартовый слот (12-й в HF-плане) прячем до RelabelBands.
|
||||||
|
if BAND_NAMES[i] = '' then B.Visible := False;
|
||||||
BtnBand[i] := B;
|
BtnBand[i] := B;
|
||||||
end;
|
end;
|
||||||
// XVTR кнопки создаются позже (в RebuildXvtrButtons), их Tag = -(idx+1)
|
// XVTR кнопки создаются позже (в RebuildXvtrButtons), их Tag = -(idx+1)
|
||||||
@@ -3849,7 +3853,11 @@ begin
|
|||||||
pl := FController.IsPluto;
|
pl := FController.IsPluto;
|
||||||
for i := 0 to BAND_COUNT - 1 do
|
for i := 0 to BAND_COUNT - 1 do
|
||||||
if BtnBand[i] <> nil then
|
if BtnBand[i] <> nil then
|
||||||
|
begin
|
||||||
BtnBand[i].Caption := BandName(i, pl);
|
BtnBand[i].Caption := BandName(i, pl);
|
||||||
|
// Пустой слот плана (HF: 12-й) — прячем кнопку.
|
||||||
|
BtnBand[i].Visible := BtnBand[i].Caption <> '';
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.ApplyBackendCapsToUI;
|
procedure TMainForm.ApplyBackendCapsToUI;
|
||||||
|
|||||||
@@ -2640,6 +2640,9 @@ procedure TRadioController.SetBand(Idx: Integer);
|
|||||||
// персист покидаемого, restore нового. Полная команда — не трогает UI.
|
// персист покидаемого, restore нового. Полная команда — не трогает UI.
|
||||||
begin
|
begin
|
||||||
if (Idx < 0) or (Idx >= CFG_BAND_COUNT) then Exit;
|
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
|
if FCurrentXvtr >= 0 then
|
||||||
begin
|
begin
|
||||||
DeactivateXvtr; // выход в HF (HF-возврат внутри)
|
DeactivateXvtr; // выход в HF (HF-возврат внутри)
|
||||||
|
|||||||
+6
-4
@@ -10,21 +10,23 @@ uses SysUtils, Classes, Math, fpJSON, jsonparser, jsonscanner, PlatformUtils;
|
|||||||
|
|
||||||
const
|
const
|
||||||
SETTINGS_FILE = 'hpsdr_settings.json';
|
SETTINGS_FILE = 'hpsdr_settings.json';
|
||||||
CFG_BAND_COUNT = 11;
|
CFG_BAND_COUNT = 12;
|
||||||
CFG_XVTR_COUNT = 8; // количество XVTR-слотов (трансверторов)
|
CFG_XVTR_COUNT = 8; // количество XVTR-слотов (трансверторов)
|
||||||
QO100_SLOT = CFG_XVTR_COUNT - 1; // последний слот зарезервирован под QO-100
|
QO100_SLOT = CFG_XVTR_COUNT - 1; // последний слот зарезервирован под QO-100
|
||||||
// (split-LO транспондер; настраивается на
|
// (split-LO транспондер; настраивается на
|
||||||
// отдельной странице, не в общей XVTR-таблице)
|
// отдельной странице, не в общей XVTR-таблице)
|
||||||
// PA gain defaults (dB) — match Thetis HERMES/HPSDR defaults
|
// PA gain defaults (dB) — match Thetis HERMES/HPSDR defaults
|
||||||
// order: 160m,80m,60m,40m,30m,20m,17m,15m,12m,10m,6m
|
// 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 = (
|
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_VHF_CAL_DEFAULT = 56.2; // dB, default for all XVTR slots
|
||||||
CFG_BAND_DEFAULT_FREQ: array[0..CFG_BAND_COUNT-1] of Double = (
|
CFG_BAND_DEFAULT_FREQ: array[0..CFG_BAND_COUNT-1] of Double = (
|
||||||
1900000, 3750000, 5357000, 7100000, 10125000,
|
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 = (
|
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-подписи
|
// TRadioController для headless-выбора фильтра при смене режима; UI-подписи
|
||||||
|
|||||||
+3
-3
@@ -586,15 +586,15 @@ begin
|
|||||||
'let XVTR_BANDS=[];let XVTR_CUR=-1;' +
|
'let XVTR_BANDS=[];let XVTR_CUR=-1;' +
|
||||||
'function rebuildBandSel(){const s=q("bandSel");if(!s)return;' +
|
'function rebuildBandSel(){const s=q("bandSel");if(!s)return;' +
|
||||||
'const saved=s.value;s.innerHTML="";' +
|
'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);});' +
|
'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"; иначе сохраним прежнее
|
// Восстановить выбор: предпочитаем "current XVTR"; иначе сохраним прежнее
|
||||||
'if(XVTR_CUR>=0)s.value="x"+XVTR_CUR; else if(saved)s.value=saved;' +
|
'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)});};' +
|
'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<bd){bd=d;bi=i;}});q("bandSel").value="h"+bi;}' +
|
'function updBand(vfo){if(XVTR_CUR>=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<bd){bd=d;bi=i;}});q("bandSel").value="h"+bi;}' +
|
||||||
|
|
||||||
'let smAvg=-130,smPeak=-130,smMin=-130;' +
|
'let smAvg=-130,smPeak=-130,smMin=-130;' +
|
||||||
'function dbToX(db,bx,bw){const DB_MIN=-127,DB_MAX=-13;return Math.max(bx,Math.min(bx+bw,Math.round(bx+(db-DB_MIN)/(DB_MAX-DB_MIN)*bw)));}' +
|
'function dbToX(db,bx,bw){const DB_MIN=-127,DB_MAX=-13;return Math.max(bx,Math.min(bx+bw,Math.round(bx+(db-DB_MIN)/(DB_MAX-DB_MIN)*bw)));}' +
|
||||||
|
|||||||
Reference in New Issue
Block a user