mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
feat(ui): настройки показывают только то, что есть у активного железа
В TBackendCaps восемь флагов заполнялись обоими бэкендами и не читались нигде, а в ApplyBackendCapsToUI на этом месте стояла расписка «(TODO) гейтинг полей, которых нет у бэкенда». Из-за этого на AD936x оператору предлагали крутить то, чего у платы нет, — и хуже всего страница PA: калибровка драйва по диапазонам там просто ничего не делает (мощность задаётся железной аттенюацией, drive-байта нет вовсе), но выглядела рабочей. Теперь гейт идёт по возможностям, а не по виду устройства: - HasPA — потолок мощности и калибровки драйва (HF + трансвертеры) против «TX att @100% drive»; заголовок и подзаголовок страницы следуют содержимому; - HasHWMic — строка микрофонного разъёма (DUC Specific байт 50). Mic gain остаётся: он идёт в WDSP и работает с любым источником, включая звук с ПК, поэтому поднимается в освободившуюся строку; - HasWideband — галки широкополосного АЦП; сам режим принудительно гасится, иначе сохранённый в конфиге wideband оставлял бы пустую панель без способа её выключить; - HasDitherRandom — группа ADC целиком, Web Server встаёт на её место. Вкладка QO-100 убрана на openHPSDR: TRadioController.InQO100 требует IsPluto, то есть транспондер там недостижим. Симметрично OC Control, которого нет у AD936x. Измеритель: TSMeterView.HasPATelemetry. Без моста детектора FLastFwdW/FLastSWR стоят на значениях инициализации, и «0W / SWR 1.0» на передаче — не показание, а выдумка. Шкала рисуется пустой: деления и рамка на месте, заливки нет, ватты на делениях не подписаны (они считаются от Max power, которого у AD936x нет). ★Отдельно — дефект раскладки, который всё это вскрыло. Перекладка страницы настроек ломается в двух случаях, и оба случались при смене трансивера на живой программе (Stop/Discover/Connect/Start), а не при старте: 1. Страница ПРОКРУЧЕНА. TScrollBox двигает детей, и SetBounds задаёт координаты относительно прокрученного клиента: всё уезжало вверх, а первая группа оставалась на месте — под переключателями Profile/EQ/Hardware зияла дыра. Лечение — сброс прокрутки первой строкой (так уже делал RelayoutCalTab). 2. Страница СПРЯТАНА. Тогда сброс не доходит до виджета, а сохранённое смещение возвращается при показе — и дыра та же. А попадает перекладка почти всегда именно на спрятанную страницу: гейты отрабатывают при открытии окна, когда активна одна вкладка, а до Transmit/Calibration оператор доходит потом. Лечение — перекладка спрятанной страницы взводит флаг и выходит, а SelectPage исполняет её в момент показа (RunDueRelayout). Гард стоит внутри каждой Relayout*, а не у вызывающих: у RelayoutCalTab их два, и второй (LoadXvtrSettings) приходит как раз на спрятанную страницу. Проверено офскрин-рендером окна настроек в обе стороны (openHPSDR ↔ AD936x) для Transmit/Power Amplifier/Calibration/Advanced, в том числе на прокрученной и спрятанной странице. При полном железе координаты совпадают со старыми. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M37eCTZZ9aqppKWkZRxXkP
This commit is contained in:
+30
-2
@@ -4649,10 +4649,12 @@ begin
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyBackendCapsToUI;
|
||||
// Пресеты sample-rate оверлея из Caps (Pluto >560k) + (TODO) гейтинг полей,
|
||||
// которых нет у бэкенда (PA/SWR/Alex/Wideband).
|
||||
// Пресеты sample-rate оверлея из Caps (Pluto >560k) + гейтинг того, чего у
|
||||
// бэкенда физически нет. Настройки гейтятся при открытии окна (SF.Set*Backend
|
||||
// в BtnSettingsClick), здесь — то, что видно в главном окне.
|
||||
var
|
||||
Caps: TBackendCaps;
|
||||
i: Integer;
|
||||
begin
|
||||
Caps := FController.BackendCaps;
|
||||
if Assigned(FSampleRateOverlay) then
|
||||
@@ -4665,6 +4667,21 @@ begin
|
||||
PushBandsToWeb; // band-план бэкенда → web (HF ↔ VHF/UHF)
|
||||
|
||||
// Отдельный Pluto RF-AGC блок под AGC: показываем и сдвигаем панели ниже.
|
||||
// Широкополосный АЦП есть только у openHPSDR. Галка на такой машине из
|
||||
// настроек убрана, поэтому включённой её оставлять нельзя: панель осталась бы
|
||||
// пустой, а выключить её стало бы нечем.
|
||||
if (not Caps.HasWideband) and FController.FShowWideband then
|
||||
ApplyVisibility(FController.FShowSpectrum, FController.FShowWaterfall,
|
||||
False, FController.FWidebandFill, FController.FSpectrumFill);
|
||||
|
||||
// Измеритель PWR/SWR: без моста детектора (AD936x) FLastFwdW/FLastSWR стоят
|
||||
// на инициализации, и «0W / SWR 1.0» на передаче были бы выдумкой — шкала
|
||||
// рисуется пустой.
|
||||
if FSpecView <> nil then FSpecView.HasPATelemetry := Caps.HasPA;
|
||||
for i := 0 to High(FPans) do
|
||||
if (FPans[i] <> nil) and (FPans[i].View <> nil) then
|
||||
FPans[i].View.HasPATelemetry := Caps.HasPA;
|
||||
|
||||
LayoutLeftPanel(Caps.HasHWGain);
|
||||
if Caps.HasHWGain then UpdateRxGainUI;
|
||||
UpdateRxMuteButton; // RX MUTE — видимость по Pluto + full-duplex (если QO-100 уже активен)
|
||||
@@ -7633,6 +7650,7 @@ begin
|
||||
P.View.SpecGridStep := FController.FSpecGridStep;
|
||||
P.View.WfFrameInterval := EffectiveWfInterval;
|
||||
P.View.PAMaxPower := FController.FPAMaxPower;
|
||||
P.View.HasPATelemetry := FController.BackendCaps.HasPA;
|
||||
P.View.CenterFreq := Freq;
|
||||
P.View.SpanHz := FController.PanDDCRateKHz(PanId) * 1000.0;
|
||||
// VFO/TX-маркеры главного на доп. пане не рисуем — уводим за пределы окна.
|
||||
@@ -9767,6 +9785,16 @@ begin
|
||||
SF.LoadOCSettings(FController.FOCSettings);
|
||||
// Вкладка OC Control — только openHPSDR, у Pluto/AD936x нет такого выхода.
|
||||
SF.SetOCBackend(FController.BackendCaps.Kind = bkPluto);
|
||||
// Вкладка QO-100 — ровно наоборот: транспондер живёт только на AD936x
|
||||
// (TRadioController.InQO100 требует IsPluto).
|
||||
SF.SetQOBackend(FController.BackendCaps.Kind = bkPluto);
|
||||
// Остальные гейты — по объявленным возможностям бэкенда, а не по его виду:
|
||||
// мост детектора мощности и drive-байт (PA), микрофонный разъём трансивера,
|
||||
// широкополосный АЦП, dither/random. Всё это есть у openHPSDR и нет у AD936x.
|
||||
SF.SetPABackend(FController.BackendCaps.HasPA);
|
||||
SF.SetTXMicBackend(FController.BackendCaps.HasHWMic);
|
||||
SF.SetWidebandBackend(FController.BackendCaps.HasWideband);
|
||||
SF.SetADCBackend(FController.BackendCaps.HasDitherRandom);
|
||||
SF.LoadPASettings(FController.FPAMaxPower, FController.FPABandCal);
|
||||
SF.LoadCalibration(FController.FCal);
|
||||
SF.LoadPlutoTxMaxAtt(FController.FPlutoTxMaxAttDb);
|
||||
|
||||
+38
-14
@@ -30,6 +30,11 @@ type
|
||||
FLastFwdW: Double;
|
||||
FLastSWR: Double;
|
||||
FPAMaxPower: Double;
|
||||
// Есть ли у железа мост детектора мощности (Caps.HasPA). У AD936x его нет:
|
||||
// FLastFwdW/FLastSWR так и стоят на значениях инициализации, и «0W / SWR
|
||||
// 1.0» на передаче — не показание, а выдумка. Шкала в этом случае рисуется
|
||||
// пустой: деления есть, заливки и цифр нет.
|
||||
FHasPATelemetry: Boolean;
|
||||
FTransmitting: Boolean;
|
||||
FPbSMeterRight: TPaintBox;
|
||||
// Масштаб канвы: 2 на Retina, 1 на Windows/Linux. Битмап растёт во столько
|
||||
@@ -52,6 +57,7 @@ type
|
||||
property LastFwdW: Double read FLastFwdW write FLastFwdW;
|
||||
property LastSWR: Double read FLastSWR write FLastSWR;
|
||||
property PAMaxPower: Double read FPAMaxPower write FPAMaxPower;
|
||||
property HasPATelemetry: Boolean read FHasPATelemetry write FHasPATelemetry;
|
||||
property Transmitting: Boolean read FTransmitting write FTransmitting;
|
||||
property PbSMeterRight: TPaintBox write FPbSMeterRight;
|
||||
|
||||
@@ -76,6 +82,7 @@ begin
|
||||
FLastFwdW := 0;
|
||||
FLastSWR := 1;
|
||||
FPAMaxPower := 100.0;
|
||||
FHasPATelemetry := True;
|
||||
FTransmitting := False;
|
||||
FScale := 1;
|
||||
end;
|
||||
@@ -358,9 +365,17 @@ begin
|
||||
W := R.Right - R.Left; H := R.Bottom - R.Top;
|
||||
if (W < 80 * Sc) or (H < 16 * Sc) then Exit;
|
||||
|
||||
SWRHigh := FLastSWR > SWR_HIGH_THRESH;
|
||||
LblPwr := Format('%.0fW', [FLastFwdW]);
|
||||
LblSWR := Format('SWR:%.1f', [FLastSWR]);
|
||||
SWRHigh := FHasPATelemetry and (FLastSWR > SWR_HIGH_THRESH);
|
||||
if FHasPATelemetry then
|
||||
begin
|
||||
LblPwr := Format('%.0fW', [FLastFwdW]);
|
||||
LblSWR := Format('SWR:%.1f', [FLastSWR]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
LblPwr := ''; // измерять нечем — показания не выдумываем
|
||||
LblSWR := '';
|
||||
end;
|
||||
|
||||
ACanvas.Font.Name := 'Courier New'; ACanvas.Font.Style := [fsBold];
|
||||
ACanvas.Font.Size := 10 * Sc;
|
||||
@@ -394,18 +409,24 @@ begin
|
||||
FillBar(BX, SY1, S_WarnX, SY2, CLR_BAR_GREEN);
|
||||
FillBar(S_WarnX, SY1, BX + BW, SY2, CLR_BAR_OVER);
|
||||
|
||||
if FPAMaxPower > 0 then PwrPct := FLastFwdW / FPAMaxPower else PwrPct := 0;
|
||||
PBarEnd := PwrToX(PwrPct);
|
||||
FillBar(BX, PY1 + Sc, PBarEnd, PY2 - Sc, SM_CLR_METER_ON);
|
||||
|
||||
SBarEnd := SWRToX(FLastSWR);
|
||||
if not SWRHigh then
|
||||
FillBar(BX, SY1 + Sc, SBarEnd, SY2 - Sc, SM_CLR_AMBER)
|
||||
else
|
||||
if FHasPATelemetry then
|
||||
begin
|
||||
FillBar(BX, SY1 + Sc, Min(S_WarnX, SBarEnd), SY2 - Sc, SM_CLR_AMBER);
|
||||
if SBarEnd > S_WarnX then
|
||||
FillBar(S_WarnX, SY1 + Sc, SBarEnd, SY2 - Sc, CLR_SWR_HIGH);
|
||||
if FPAMaxPower > 0 then PwrPct := FLastFwdW / FPAMaxPower else PwrPct := 0;
|
||||
PBarEnd := PwrToX(PwrPct);
|
||||
FillBar(BX, PY1 + Sc, PBarEnd, PY2 - Sc, SM_CLR_METER_ON);
|
||||
end;
|
||||
|
||||
if FHasPATelemetry then
|
||||
begin
|
||||
SBarEnd := SWRToX(FLastSWR);
|
||||
if not SWRHigh then
|
||||
FillBar(BX, SY1 + Sc, SBarEnd, SY2 - Sc, SM_CLR_AMBER)
|
||||
else
|
||||
begin
|
||||
FillBar(BX, SY1 + Sc, Min(S_WarnX, SBarEnd), SY2 - Sc, SM_CLR_AMBER);
|
||||
if SBarEnd > S_WarnX then
|
||||
FillBar(S_WarnX, SY1 + Sc, SBarEnd, SY2 - Sc, CLR_SWR_HIGH);
|
||||
end;
|
||||
end;
|
||||
|
||||
VLine(S_WarnX, SY1, SY2, FTheme.SMeterDivider);
|
||||
@@ -437,6 +458,9 @@ begin
|
||||
begin
|
||||
X := PwrToX(PWR_MARKS[i]);
|
||||
VLine(X, PY1 - TICK_LONG * Sc, PY1 - Sc, CLR_TICK_WHITE);
|
||||
// Ватты на делениях считаются от Max power, а он есть только там, где есть
|
||||
// детектор. Без него оставляем голые деления: подписать их нечем.
|
||||
if not FHasPATelemetry then Continue;
|
||||
Lbl := Format('%.0f', [PWR_MARKS[i] * FPAMaxPower]);
|
||||
TW := ACanvas.TextWidth(Lbl);
|
||||
ACanvas.Font.Color := CLR_SCALE_DBM;
|
||||
|
||||
+361
-11
@@ -210,6 +210,17 @@ type
|
||||
FEdBandCal: array[0..10] of TFlatFloatSpinEdit;
|
||||
FEdVHFCal: array[0..CFG_XVTR_COUNT-1] of TFlatFloatSpinEdit;
|
||||
FVHFCalLabels: array[0..CFG_XVTR_COUNT-1] of TLabel;
|
||||
// Раскладку страницы PA ставит RelayoutPATab под активное железо: у AD936x
|
||||
// нет ни моста детектора, ни drive-байта — мощность там задаётся
|
||||
// аттенюацией, поэтому из всей страницы остаётся один потолок.
|
||||
FPAGrpPower: TPanel;
|
||||
FPAGrpVHF: TPanel;
|
||||
FLblPAHint: TLabel;
|
||||
FLblPAMaxPower: TLabel;
|
||||
FLblPlutoTxAtt: TLabel;
|
||||
FLblPABandHdr: TLabel;
|
||||
FPABandLabels: array[0..10] of TLabel;
|
||||
FPAHasPA: Boolean;
|
||||
|
||||
// ---- Calibration tab controls ----
|
||||
// Таблицы «на диапазон» строятся на 12 слотов (максимум плана); подписи,
|
||||
@@ -242,6 +253,7 @@ type
|
||||
FLblDispBandHdr: TLabel;
|
||||
FLblDispXvtrHdr: TLabel;
|
||||
FBtnDispFromSM: TFlatButton; // «= S-meter» — копия таблицы
|
||||
FLblCalHint: TLabel; // подзаголовок страницы, зависит от железа
|
||||
FCalGrpFreq: TPanel; // Reference frequency
|
||||
FEdFreqCalPPM: TFlatFloatSpinEdit; // калибровка опорника, ppm
|
||||
FCalIsPluto: Boolean; // активное железо — AD936x
|
||||
@@ -274,7 +286,16 @@ type
|
||||
FChkTXMicPTT: TFlatCheckBox;
|
||||
FCmbTXMicTR: TFlatComboBox; // "Tip" / "Ring" (только Orion)
|
||||
FLblTipRing: TLabel; // метка (только Orion)
|
||||
FLblMicJack: TLabel; // метка "Mic jack"
|
||||
FLblMicGain: TLabel; // метка "Mic gain (dB)"
|
||||
FEdTXMicGain: TFlatFloatSpinEdit;
|
||||
// Группы подвкладки Profile — их двигает RelayoutTXProfileSub, когда у
|
||||
// железа нет микрофонного разъёма (AD936x: звук только с ПК).
|
||||
FTXGrpMic: TPanel;
|
||||
FTXGrpFilt: TPanel;
|
||||
FTXGrpDyn: TPanel;
|
||||
FTXGrpPwr: TPanel;
|
||||
FTXHasHWMic: Boolean;
|
||||
FEdTXAttOnTX: TFlatSpinEdit;
|
||||
// Tune (TUN button)
|
||||
FEdTUNLevel: TFlatSpinEdit;
|
||||
@@ -470,6 +491,21 @@ type
|
||||
// ---- Advanced tab controls ----
|
||||
FChkDither: TFlatCheckBox;
|
||||
FChkRandom: TFlatCheckBox;
|
||||
// Группа ADC прячется целиком у AD936x (SetADCBackend), Web Server встаёт
|
||||
// на её место — иначе страница начиналась бы с пустоты.
|
||||
FAdvGrpADC: TPanel;
|
||||
FAdvGrpWeb: TPanel;
|
||||
FLblAdvHint: TLabel;
|
||||
FAdvHasADC: Boolean;
|
||||
// ★Перекладка страницы возможна только когда страница ВИДИМА: сброс
|
||||
// прокрутки не доходит до спрятанного виджета, а сохранённое смещение
|
||||
// возвращается при показе — и блоки разъезжаются. Поэтому перекладка
|
||||
// спрятанной страницы лишь взводит свой флаг, а исполняется из SelectPage
|
||||
// в момент показа (RunDueRelayout).
|
||||
FPARelayoutDue: Boolean;
|
||||
FTXRelayoutDue: Boolean;
|
||||
FCalRelayoutDue: Boolean;
|
||||
FAdvRelayoutDue: Boolean;
|
||||
FChkWebEnabled: TFlatCheckBox;
|
||||
FEdWebPort: TFlatSpinEdit;
|
||||
FEdWebBind: TFlatEdit;
|
||||
@@ -531,7 +567,12 @@ type
|
||||
procedure BuildRX1Tab;
|
||||
procedure BuildPATab;
|
||||
procedure BuildCalibrationTab;
|
||||
function GroupTitle(Grp: TPanel): TLabel;
|
||||
procedure RunDueRelayout(APage: TWinControl);
|
||||
procedure RelayoutCalTab;
|
||||
procedure RelayoutPATab;
|
||||
procedure RelayoutTXProfileSub;
|
||||
procedure RelayoutAdvancedTab;
|
||||
// Раскладка блока офсетов «на диапазон + на трансвертер» внутри группы
|
||||
// (общая для S-метра и спектра). Возвращает нужную высоту группы.
|
||||
function LayoutCalOffsets(const BandLbl: array of TLabel;
|
||||
@@ -694,6 +735,9 @@ type
|
||||
procedure LoadCalibration(const C: TCalibration);
|
||||
// Железо вкладки Calibration: band-план и состав групп (Pluto/openHPSDR).
|
||||
procedure SetCalibrationBackend(IsPluto: Boolean);
|
||||
// Мост детектора мощности и drive-байт есть только у openHPSDR: у AD936x
|
||||
// мощность = железная аттенюация, и вся калибровка по диапазонам мертва.
|
||||
procedure SetPABackend(HasPA: Boolean);
|
||||
// Вкладка Antenna: Alex-таблица (openHPSDR) либо таблица разъёмов AD936x.
|
||||
procedure SetAntennaBackend(IsAD936x, HasAntSwitch: Boolean);
|
||||
// Таблица разъёмов + имена/видимость слотов трансвертеров.
|
||||
@@ -716,6 +760,11 @@ type
|
||||
procedure LoadCWSettings(const C: TCWSettings);
|
||||
// Есть ли у активного железа кейер в прошивке (openHPSDR — да, AD936x — нет).
|
||||
procedure SetCWBackend(HasFWKeyer: Boolean);
|
||||
// Микрофонный разъём трансивера (DUC Specific байт 50) — только openHPSDR.
|
||||
procedure SetTXMicBackend(HasHWMic: Boolean);
|
||||
// Широкополосный АЦП и dither/random — тоже свойства openHPSDR.
|
||||
procedure SetWidebandBackend(HasWideband: Boolean);
|
||||
procedure SetADCBackend(HasDitherRandom: Boolean);
|
||||
// Список TX-профилей + активный + drive активного (ползунок DRV живёт в
|
||||
// главном окне, здесь показываем его значение как часть профиля).
|
||||
procedure LoadTXProfiles(const Names: array of string;
|
||||
@@ -730,6 +779,8 @@ type
|
||||
procedure LoadOCSettings(const O: TOCSettings);
|
||||
// Вкладка OC Control — только openHPSDR (у Pluto/AD936x нет такого выхода).
|
||||
procedure SetOCBackend(IsPluto: Boolean);
|
||||
// Вкладка QO-100 — наоборот, только AD936x (см. TRadioController.InQO100).
|
||||
procedure SetQOBackend(IsPluto: Boolean);
|
||||
procedure LoadWfAGCNF(AGC, NF: Boolean);
|
||||
procedure LoadWfRender(Palette: Integer; Gamma: Double;
|
||||
ResLimit, SpeedDiv: Integer);
|
||||
@@ -1029,6 +1080,26 @@ begin
|
||||
Divider.Color := CLR_BORDER;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.RunDueRelayout(APage: TWinControl);
|
||||
// Зовётся из SelectPage сразу после того, как страница стала видимой: только
|
||||
// теперь у её TScrollBox осмысленная прокрутка, и перекладку можно исполнить.
|
||||
begin
|
||||
if (APage = FPagePA) and FPARelayoutDue then RelayoutPATab
|
||||
else if (APage = FPageTransmit) and FTXRelayoutDue then RelayoutTXProfileSub
|
||||
else if (APage = FPageCalib) and FCalRelayoutDue then RelayoutCalTab
|
||||
else if (APage = FPageAdvanced) and FAdvRelayoutDue then RelayoutAdvancedTab;
|
||||
end;
|
||||
|
||||
function TSettingsForm.GroupTitle(Grp: TPanel): TLabel;
|
||||
// Подпись группы MakeGroupPanel создаёт первой — до разделителя и до всего
|
||||
// содержимого, — поэтому она всегда Controls[0]. Нужна там, где заголовок
|
||||
// зависит от железа (страница PA).
|
||||
begin
|
||||
Result := nil;
|
||||
if (Grp <> nil) and (Grp.ControlCount > 0) and (Grp.Controls[0] is TLabel) then
|
||||
Result := TLabel(Grp.Controls[0]);
|
||||
end;
|
||||
|
||||
function TSettingsForm.MakeScrollPage: TScrollBox;
|
||||
begin
|
||||
Result := TScrollBox.Create(Self);
|
||||
@@ -1556,6 +1627,9 @@ begin
|
||||
// Скрытые alClient-страницы LCL не всегда перекладывает до показа.
|
||||
// После переключения берём уже актуальный ClientWidth выбранной страницы.
|
||||
RelayoutResponsiveCards;
|
||||
// Отложенная перекладка под железо — теперь страница видима, и сброс
|
||||
// прокрутки внутри неё наконец доходит до виджета.
|
||||
RunDueRelayout(APage);
|
||||
UpdateSettingsScrollBar;
|
||||
end;
|
||||
|
||||
@@ -2019,9 +2093,10 @@ begin
|
||||
// шагом. Connector скрыт на не-Orion и потому делит строку с Mic gain —
|
||||
// спрятанная пара не оставляет дыры.
|
||||
Grp := MakeGroupPanel(FTXSubPage[0], 'Microphone', MARGIN, 0, GRP_W, 134);
|
||||
FTXGrpMic := Grp;
|
||||
|
||||
// Row 0: Mic jack | Boost (Mic In) либо Line In gain (Line In) | Bias | PTT
|
||||
MakeLbl(Grp, 'Mic jack', PAD, R1 + 5, LW);
|
||||
FLblMicJack := MakeLbl(Grp, 'Mic jack', PAD, R1 + 5, LW);
|
||||
FCmbTXMicJack := MkCmb(Grp, CX, R1, 110);
|
||||
FCmbTXMicJack.Items.Add('Mic In');
|
||||
FCmbTXMicJack.Items.Add('Line In');
|
||||
@@ -2037,7 +2112,10 @@ begin
|
||||
FChkTXMicPTT := MkChk(Grp, PAD + 596, R1, 130, 'Mic-jack PTT');
|
||||
|
||||
// Row 1: Mic gain | Connector Tip/Ring (только Orion boards 4 и 5)
|
||||
MakeLbl(Grp, 'Mic gain (dB)', PAD, R1 + STEP + 5, LW);
|
||||
// ★Mic gain — единственное здесь, что не про разъём: он идёт в WDSP
|
||||
// (SetMicGain) и работает с любым источником, включая звук с ПК. При
|
||||
// скрытом разъёме RelayoutTXProfileSub поднимает его в первую строку.
|
||||
FLblMicGain := MakeLbl(Grp, 'Mic gain (dB)', PAD, R1 + STEP + 5, LW);
|
||||
FEdTXMicGain := MkFloat(Grp, CX, R1 + STEP, 10.0, -20.0, 60.0, 0.5);
|
||||
|
||||
FLblTipRing := MakeLbl(Grp, 'Connector', PAD + 302, R1 + STEP + 5, 76);
|
||||
@@ -2051,6 +2129,7 @@ begin
|
||||
// ---- Кромки TX-фильтра (FIR/фаза/окно — на вкладке Hardware) ----
|
||||
Y := 134 + 12;
|
||||
Grp := MakeGroupPanel(FTXSubPage[0], 'TX Filter (bandpass)', MARGIN, Y, GRP_W, 108);
|
||||
FTXGrpFilt := Grp;
|
||||
|
||||
MakeLbl(Grp, 'Low cut (Hz)', PAD, R1 + 5, LW);
|
||||
FEdTXFiltLow := MkSpin(Grp, CX, R1, 0, 8000, 200);
|
||||
@@ -2063,6 +2142,7 @@ begin
|
||||
// ---- Динамическая обработка ----
|
||||
Inc(Y, 108 + 12);
|
||||
Grp := MakeGroupPanel(FTXSubPage[0], 'Dynamic processing', MARGIN, Y, GRP_W, 220);
|
||||
FTXGrpDyn := Grp;
|
||||
|
||||
FChkTXCompOn := MkChk(Grp, PAD, R1, 220, 'Compressor');
|
||||
MakeLbl(Grp, 'Gain (dB)', PAD + 230, R1 + 5, 80);
|
||||
@@ -2089,6 +2169,7 @@ begin
|
||||
// ---- Мощность и несущая AM (тоже часть профиля) ----
|
||||
Inc(Y, 220 + 12);
|
||||
Grp := MakeGroupPanel(FTXSubPage[0], 'Power / AM carrier', MARGIN, Y, GRP_W, 148);
|
||||
FTXGrpPwr := Grp;
|
||||
|
||||
MakeLbl(Grp, 'Tune level (%)', PAD, R1 + 5, LW);
|
||||
FEdTUNLevel := MkSpin(Grp, CX, R1, 0, 100, 10);
|
||||
@@ -2101,6 +2182,7 @@ begin
|
||||
R1 + STEP + 28, 26);
|
||||
|
||||
FTXSubPage[0].Height := DpiScale(Y + 148 + 12);
|
||||
FTXHasHWMic := True; // до подключения показываем полный (openHPSDR) вид
|
||||
|
||||
// =========================================================================
|
||||
// Подвкладка 1 — EQ (тоже профильный, но занимает целый экран)
|
||||
@@ -2566,12 +2648,142 @@ procedure TSettingsForm.UpdateMicJackVisibility;
|
||||
var LineIn: Boolean;
|
||||
begin
|
||||
if FCmbTXMicJack = nil then Exit;
|
||||
// Без разъёма прятать нечего и показывать нечего: вся строка снята
|
||||
// RelayoutTXProfileSub, и вернуть её отсюда было бы возвратом дыры.
|
||||
if not FTXHasHWMic then Exit;
|
||||
LineIn := FCmbTXMicJack.ItemIndex = 1;
|
||||
if FChkTXMicBoost <> nil then FChkTXMicBoost.Visible := not LineIn;
|
||||
if FLblLineInGain <> nil then FLblLineInGain.Visible := LineIn;
|
||||
if FEdLineInGain <> nil then FEdLineInGain.Visible := LineIn;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.SetTXMicBackend(HasHWMic: Boolean);
|
||||
// HasHWMic — Caps.HasHWMic: микрофонный разъём самого трансивера. Всё, что
|
||||
// стоит в строке разъёма, уезжает в DUC Specific байт 50 (openHPSDR); у AD936x
|
||||
// такого разъёма нет, звук идёт только с ПК.
|
||||
begin
|
||||
if FTXHasHWMic = HasHWMic then Exit;
|
||||
FTXHasHWMic := HasHWMic;
|
||||
RelayoutTXProfileSub;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.RelayoutTXProfileSub;
|
||||
// Подвкладка Profile: без микрофонного разъёма группа Microphone теряет целую
|
||||
// строку, Mic gain поднимается в неё, а три группы ниже подтягиваются — иначе
|
||||
// на месте снятой строки осталась бы дыра.
|
||||
const
|
||||
TX_MARGIN = 22;
|
||||
TX_STEP = 42;
|
||||
TX_R1 = 42;
|
||||
TX_MIC_H = 134;
|
||||
TX_FILT_H = 108;
|
||||
TX_DYN_H = 220;
|
||||
TX_PWR_H = 148;
|
||||
var
|
||||
MicH, GainY, Y: Integer;
|
||||
|
||||
procedure Vis(C: TControl; V: Boolean);
|
||||
begin
|
||||
if C <> nil then C.Visible := V;
|
||||
end;
|
||||
|
||||
begin
|
||||
if (FTXGrpMic = nil) or (FTXGrpFilt = nil) or (FTXGrpDyn = nil)
|
||||
or (FTXGrpPwr = nil) or (FTXSubPage[0] = nil) then Exit;
|
||||
if not FPageTransmit.Visible then begin FTXRelayoutDue := True; Exit; end;
|
||||
FTXRelayoutDue := False;
|
||||
|
||||
// ★Как и на вкладке Calibration: TScrollBox двигает детей при прокрутке, и
|
||||
// SetBounds ниже задаёт координаты ОТНОСИТЕЛЬНО прокрученного клиента.
|
||||
// Перекладка случается при смене трансивера на живой программе, то есть
|
||||
// страницу к этому моменту уже успели пролистать, — и без сброса группы
|
||||
// разъезжались: всё уезжало вверх, а Microphone оставался на месте.
|
||||
FPageTransmit.VertScrollBar.Position := 0;
|
||||
FPageTransmit.HorzScrollBar.Position := 0;
|
||||
|
||||
Vis(FLblMicJack, FTXHasHWMic);
|
||||
Vis(FCmbTXMicJack, FTXHasHWMic);
|
||||
Vis(FChkTXMicBias, FTXHasHWMic);
|
||||
Vis(FChkTXMicPTT, FTXHasHWMic);
|
||||
if not FTXHasHWMic then
|
||||
begin
|
||||
// Пара «Boost ↔ Line In gain» обычно переключается UpdateMicJackVisibility;
|
||||
// здесь снимаем обе, а тот выше уже знает, что возвращать их не должен.
|
||||
Vis(FChkTXMicBoost, False);
|
||||
Vis(FLblLineInGain, False);
|
||||
Vis(FEdLineInGain, False);
|
||||
Vis(FLblTipRing, False);
|
||||
Vis(FCmbTXMicTR, False);
|
||||
end
|
||||
else
|
||||
UpdateMicJackVisibility; // вернуть ту из пары, что положена по разъёму
|
||||
|
||||
if FTXHasHWMic then
|
||||
begin
|
||||
GainY := TX_R1 + TX_STEP;
|
||||
MicH := TX_MIC_H;
|
||||
end
|
||||
else
|
||||
begin
|
||||
GainY := TX_R1;
|
||||
MicH := TX_MIC_H - TX_STEP;
|
||||
end;
|
||||
if FLblMicGain <> nil then FLblMicGain.Top := DpiScale(GainY + 5);
|
||||
if FEdTXMicGain <> nil then FEdTXMicGain.Top := DpiScale(GainY);
|
||||
|
||||
// Ширину групп ведёт RelayoutResponsiveCards — здесь только высота и Top.
|
||||
FTXGrpMic.SetBounds(DpiScale(TX_MARGIN), 0, FTXGrpMic.Width, DpiScale(MicH));
|
||||
Y := MicH + 12;
|
||||
FTXGrpFilt.Top := DpiScale(Y);
|
||||
Inc(Y, TX_FILT_H + 12);
|
||||
FTXGrpDyn.Top := DpiScale(Y);
|
||||
Inc(Y, TX_DYN_H + 12);
|
||||
FTXGrpPwr.Top := DpiScale(Y);
|
||||
FTXSubPage[0].Height := DpiScale(Y + TX_PWR_H + 12);
|
||||
UpdatePageBottomSpace(FPageTransmit);
|
||||
if FActivePage = FPageTransmit then UpdateSettingsScrollBar;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.SetWidebandBackend(HasWideband: Boolean);
|
||||
// Кадры широкополосного АЦП приходят только от openHPSDR. У AD936x галка
|
||||
// открывала бы пустую панель, поэтому её здесь нет вовсе.
|
||||
begin
|
||||
if FChkShowWideband <> nil then FChkShowWideband.Visible := HasWideband;
|
||||
if FChkWidebandFill <> nil then FChkWidebandFill.Visible := HasWideband;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.SetADCBackend(HasDitherRandom: Boolean);
|
||||
// Dither/random — свойства АЦП openHPSDR; у AD936x такого понятия нет.
|
||||
begin
|
||||
if FAdvHasADC = HasDitherRandom then Exit; // не сбрасывать прокрутку зря
|
||||
FAdvHasADC := HasDitherRandom;
|
||||
RelayoutAdvancedTab;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.RelayoutAdvancedTab;
|
||||
// Без dither/random группа ADC пуста — прячем её целиком, а Web Server
|
||||
// поднимается на её место, иначе страница начиналась бы с пустоты.
|
||||
const
|
||||
ADV_ADC_H = 128;
|
||||
begin
|
||||
if (FAdvGrpADC = nil) or (FAdvGrpWeb = nil) or (FLblAdvHint = nil) then Exit;
|
||||
if not FPageAdvanced.Visible then begin FAdvRelayoutDue := True; Exit; end;
|
||||
FAdvRelayoutDue := False;
|
||||
FPageAdvanced.VertScrollBar.Position := 0;
|
||||
FPageAdvanced.HorzScrollBar.Position := 0;
|
||||
if FAdvHasADC then
|
||||
FLblAdvHint.Caption := 'ADC processing and built-in web server settings.'
|
||||
else
|
||||
FLblAdvHint.Caption := 'Built-in web server settings.';
|
||||
FAdvGrpADC.Visible := FAdvHasADC;
|
||||
if FAdvHasADC then
|
||||
FAdvGrpWeb.Top := DpiScale(86 + ADV_ADC_H + 16)
|
||||
else
|
||||
FAdvGrpWeb.Top := DpiScale(86);
|
||||
UpdatePageBottomSpace(FPageAdvanced);
|
||||
if FActivePage = FPageAdvanced then UpdateSettingsScrollBar;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.OnMicJackChange(Sender: TObject);
|
||||
begin
|
||||
UpdateMicJackVisibility;
|
||||
@@ -2716,8 +2928,11 @@ begin
|
||||
if FEdLineInGain <> nil then FEdLineInGain.Value := EnsureRange(T.LineInGainDB, -34.5, 12.0);
|
||||
if FChkTXMicBias <> nil then FChkTXMicBias.Checked := T.MicBias;
|
||||
if FChkTXMicPTT <> nil then FChkTXMicPTT.Checked := T.MicPTTEnabled;
|
||||
// Tip/Ring (Orion boards 4 и 5)
|
||||
IsOrion := BoardType in [4, 5];
|
||||
// Tip/Ring (Orion boards 4 и 5). ★Без микрофонного разъёма строку уже снял
|
||||
// RelayoutTXProfileSub, и вернуть её отсюда значило бы вернуть дыру: этот
|
||||
// Load зовётся при каждом открытии окна, а SetTXMicBackend — только на
|
||||
// смене железа.
|
||||
IsOrion := FTXHasHWMic and (BoardType in [4, 5]);
|
||||
if FLblTipRing <> nil then FLblTipRing.Visible := IsOrion;
|
||||
if FCmbTXMicTR <> nil then
|
||||
begin
|
||||
@@ -2862,13 +3077,20 @@ var
|
||||
Spin: TFlatSpinEdit;
|
||||
i, r, c, X, Y: Integer;
|
||||
begin
|
||||
MakePageHeader(FPagePA, 'Power Amplifier',
|
||||
'Output limit and per-band calibration values.');
|
||||
// Подпись под заголовком зависит от железа (RelayoutPATab): у AD936x на
|
||||
// странице остаётся один потолок аттенюации, и обещать «per-band calibration»
|
||||
// там нечестно. Поэтому создаём её отдельно, а не через ASubtitle.
|
||||
MakePageHeader(FPagePA, 'Power Amplifier', '');
|
||||
FLblPAHint := MakeTextBlock(FPagePA, '', SETTINGS_MARGIN, 48,
|
||||
SETTINGS_CARD_W, 20);
|
||||
FLblPAHint.Tag := TAG_PAGE_HEADER;
|
||||
|
||||
Grp := MakeGroupPanel(FPagePA, 'Power && Calibration', MARGIN, 86, SETTINGS_CARD_W, GRP_H);
|
||||
FPAGrpPower := Grp;
|
||||
|
||||
// Max Power
|
||||
Lbl := MakeLbl(Grp, 'Max power (W)', GRP_PAD, R1 + 6, 132);
|
||||
FLblPAMaxPower := Lbl;
|
||||
|
||||
Spin := TFlatSpinEdit.Create(Self);
|
||||
Spin.Parent := Grp;
|
||||
@@ -2884,8 +3106,9 @@ begin
|
||||
FEdMaxPower := Spin;
|
||||
|
||||
// Pluto TX max attenuation @ drive 100% (потолок под внешний усилитель), дБ<0
|
||||
Lbl := MakeLbl(Grp, 'Pluto TX att @100% (dB)',
|
||||
Lbl := MakeLbl(Grp, 'TX att @100% drive (dB)',
|
||||
GRP_PAD + 320, R1 + 6, 180);
|
||||
FLblPlutoTxAtt := Lbl;
|
||||
|
||||
FEdPlutoTxMaxAtt := TFlatFloatSpinEdit.Create(Self);
|
||||
FEdPlutoTxMaxAtt.Parent := Grp;
|
||||
@@ -2903,6 +3126,7 @@ begin
|
||||
// Calibration label
|
||||
Lbl := MakeLbl(Grp, 'Calibration per band, 38.8 ... 100.0',
|
||||
GRP_PAD, R1 + ROW_H + 12, 320);
|
||||
FLblPABandHdr := Lbl;
|
||||
|
||||
// Band grid 4 columns × 3 rows
|
||||
for i := 0 to 10 do
|
||||
@@ -2913,6 +3137,7 @@ begin
|
||||
Y := R1 + ROW_H + 34 + r * ROW_H;
|
||||
|
||||
Lbl := MakeLbl(Grp, PA_BAND_NAMES[i] + ':', X, Y + 5, LBL_W);
|
||||
FPABandLabels[i] := Lbl;
|
||||
|
||||
FEdBandCal[i] := MakeFloatSpin(Grp, X + LBL_W, Y, OnBandCalChange);
|
||||
FEdBandCal[i].Tag := i;
|
||||
@@ -2921,6 +3146,7 @@ begin
|
||||
// ── VHF Calibration (Transverters) ──────────────────────────────────────
|
||||
Grp := MakeGroupPanel(FPagePA, 'VHF Calibration (Transverters)',
|
||||
MARGIN, 86 + GRP_H + 14, SETTINGS_CARD_W, R1 + 4 * ROW_H + 44);
|
||||
FPAGrpVHF := Grp;
|
||||
|
||||
Lbl := MakeLbl(Grp, 'Calibration per transverter slot, 38.8 ... 100.0',
|
||||
GRP_PAD, R1, 420);
|
||||
@@ -2946,6 +3172,95 @@ begin
|
||||
FEdVHFCal[i].Tag := i;
|
||||
end;
|
||||
|
||||
FPAHasPA := True; // до подключения показываем полный (openHPSDR) вид
|
||||
RelayoutPATab;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.SetPABackend(HasPA: Boolean);
|
||||
// HasPA — Caps.HasPA активного бэкенда: мост детектора мощности, drive-байт и
|
||||
// телеметрия питания. У AD936x ничего этого нет.
|
||||
begin
|
||||
if FPAHasPA = HasPA then Exit;
|
||||
FPAHasPA := HasPA;
|
||||
RelayoutPATab;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.RelayoutPATab;
|
||||
// openHPSDR: потолок мощности + калибровка драйва по диапазонам и слотам
|
||||
// трансвертера (всё это кормит CalcDriveByte). AD936x: мощность задаётся
|
||||
// железной аттенюацией, drive-байта нет вовсе — на странице остаётся один
|
||||
// потолок аттенюации, остальное прячется вместе со своей группой.
|
||||
const
|
||||
PA_MARGIN = 22;
|
||||
PA_R1 = 42;
|
||||
PA_ROW_H = 32;
|
||||
PA_GRP_H = 222;
|
||||
PA_GRP_PAD = 18;
|
||||
PA_VHF_H = PA_R1 + 4 * PA_ROW_H + 44;
|
||||
var
|
||||
i, H: Integer;
|
||||
Lbl: TLabel;
|
||||
begin
|
||||
if (FPAGrpPower = nil) or (FPAGrpVHF = nil) or (FLblPAHint = nil) then Exit;
|
||||
if not FPagePA.Visible then begin FPARelayoutDue := True; Exit; end;
|
||||
FPARelayoutDue := False;
|
||||
// Как и на вкладке Calibration: SetBounds ниже задаёт координаты относительно
|
||||
// прокрученного клиента, поэтому сперва возвращаем страницу в ноль.
|
||||
FPagePA.VertScrollBar.Position := 0;
|
||||
FPagePA.HorzScrollBar.Position := 0;
|
||||
|
||||
if FPAHasPA then
|
||||
FLblPAHint.Caption := 'Output limit and per-band calibration values.'
|
||||
else
|
||||
FLblPAHint.Caption := 'Transmit power is set by hardware attenuation; '
|
||||
+ 'there is no power detector to calibrate.';
|
||||
|
||||
// Заголовок группы — по её содержимому: калибровки у AD936x не остаётся.
|
||||
Lbl := GroupTitle(FPAGrpPower);
|
||||
if Lbl <> nil then
|
||||
if FPAHasPA then Lbl.Caption := 'Power && Calibration'
|
||||
else Lbl.Caption := 'Transmit power';
|
||||
|
||||
if FLblPAMaxPower <> nil then FLblPAMaxPower.Visible := FPAHasPA;
|
||||
if FEdMaxPower <> nil then FEdMaxPower.Visible := FPAHasPA;
|
||||
if FLblPABandHdr <> nil then FLblPABandHdr.Visible := FPAHasPA;
|
||||
for i := 0 to High(FPABandLabels) do
|
||||
begin
|
||||
if FPABandLabels[i] <> nil then FPABandLabels[i].Visible := FPAHasPA;
|
||||
if FEdBandCal[i] <> nil then FEdBandCal[i].Visible := FPAHasPA;
|
||||
end;
|
||||
FPAGrpVHF.Visible := FPAHasPA;
|
||||
|
||||
// Аттенюация — свойство AD936x. У openHPSDR мощность идёт drive-байтом, и
|
||||
// поле было бы мёртвым; у AD936x оно единственное и переезжает в первую
|
||||
// колонку, чтобы не висеть посреди пустой группы.
|
||||
if (FLblPlutoTxAtt <> nil) and (FEdPlutoTxMaxAtt <> nil) then
|
||||
begin
|
||||
FLblPlutoTxAtt.Visible := not FPAHasPA;
|
||||
FEdPlutoTxMaxAtt.Visible := not FPAHasPA;
|
||||
if FPAHasPA then
|
||||
begin
|
||||
FLblPlutoTxAtt.Left := DpiScale(PA_GRP_PAD + 320);
|
||||
FEdPlutoTxMaxAtt.Left := DpiScale(PA_GRP_PAD + 510);
|
||||
end
|
||||
else
|
||||
begin
|
||||
FLblPlutoTxAtt.Left := DpiScale(PA_GRP_PAD);
|
||||
FEdPlutoTxMaxAtt.Left := DpiScale(PA_GRP_PAD + 190);
|
||||
end;
|
||||
end;
|
||||
|
||||
if FPAHasPA then H := PA_GRP_H
|
||||
else H := PA_R1 + BTN_H + 2 + 18; // ровно одна строка
|
||||
// Ширину не трогаем: карточки тянет по окну RelayoutResponsiveCards, и
|
||||
// фиксированная ширина здесь схлопнула бы их до базовой.
|
||||
FPAGrpPower.SetBounds(DpiScale(PA_MARGIN), DpiScale(86),
|
||||
FPAGrpPower.Width, DpiScale(H));
|
||||
if FPAHasPA then
|
||||
FPAGrpVHF.SetBounds(DpiScale(PA_MARGIN), DpiScale(86 + H + 14),
|
||||
FPAGrpVHF.Width, DpiScale(PA_VHF_H));
|
||||
UpdatePageBottomSpace(FPagePA);
|
||||
if FActivePage = FPagePA then UpdateSettingsScrollBar;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.BuildCalibrationTab;
|
||||
@@ -3004,8 +3319,12 @@ begin
|
||||
FCalXvtrName[i] := '';
|
||||
end;
|
||||
|
||||
MakePageHeader(FPageCalib, 'Calibration',
|
||||
'Power/SWR detector, supply voltage/current and S-meter calibration.');
|
||||
// Подпись зависит от железа (RelayoutCalTab): у AD936x детектора мощности и
|
||||
// телеметрии питания нет, и обещать их калибровку в подзаголовке нечестно.
|
||||
MakePageHeader(FPageCalib, 'Calibration', '');
|
||||
FLblCalHint := MakeTextBlock(FPageCalib, '', SETTINGS_MARGIN, 48,
|
||||
SETTINGS_CARD_W, 20);
|
||||
FLblCalHint.Tag := TAG_PAGE_HEADER;
|
||||
|
||||
// ── Power / SWR detector ────────────────────────────────────────────────
|
||||
GTop := 86;
|
||||
@@ -3177,6 +3496,8 @@ begin
|
||||
if (FCalGrpDet = nil) or (FCalGrpVA = nil) or (FCalGrpSM = nil)
|
||||
or (FCalGrpDisp = nil) or (FLblDispXvtrHdr = nil)
|
||||
or (FCalGrpFreq = nil) then Exit;
|
||||
if not FPageCalib.Visible then begin FCalRelayoutDue := True; Exit; end;
|
||||
FCalRelayoutDue := False;
|
||||
|
||||
// TScrollBox двигает детей при прокрутке, и SetBounds ниже задаёт координаты
|
||||
// ОТНОСИТЕЛЬНО прокрученного клиента. Если страницу успели прокрутить (у
|
||||
@@ -3186,6 +3507,14 @@ begin
|
||||
FPageCalib.VertScrollBar.Position := 0;
|
||||
FPageCalib.HorzScrollBar.Position := 0;
|
||||
|
||||
if FLblCalHint <> nil then
|
||||
if FCalIsPluto then
|
||||
FLblCalHint.Caption := 'S-meter, spectrum and reference frequency '
|
||||
+ 'calibration.'
|
||||
else
|
||||
FLblCalHint.Caption := 'Power/SWR detector, supply voltage/current and '
|
||||
+ 'S-meter calibration.';
|
||||
|
||||
// ---- подписи/видимость строк Det. Cal. (своя сетка, уже с подсказкой) ----
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
begin
|
||||
@@ -3410,11 +3739,15 @@ var
|
||||
Lbl: TLabel;
|
||||
Y, i: Integer;
|
||||
begin
|
||||
MakePageHeader(FPageAdvanced, 'Advanced',
|
||||
'ADC processing and built-in web server settings.');
|
||||
MakePageHeader(FPageAdvanced, 'Advanced', '');
|
||||
FLblAdvHint := MakeTextBlock(FPageAdvanced, '', SETTINGS_MARGIN, 48,
|
||||
SETTINGS_CARD_W, 20);
|
||||
FLblAdvHint.Tag := TAG_PAGE_HEADER;
|
||||
|
||||
// ── ADC ───────────────────────────────────────────────────────────────────
|
||||
Grp := MakeGroupPanel(FPageAdvanced, 'ADC', MARGIN, 86, SETTINGS_CARD_W, 128);
|
||||
FAdvGrpADC := Grp;
|
||||
FAdvHasADC := True; // до подключения показываем полный (openHPSDR) вид
|
||||
|
||||
Chk := TFlatCheckBox.Create(Self);
|
||||
Chk.Parent := Grp;
|
||||
@@ -3438,6 +3771,7 @@ begin
|
||||
|
||||
// ── Web Server ────────────────────────────────────────────────────────────
|
||||
Grp := MakeGroupPanel(FPageAdvanced, 'Web Server', MARGIN, 230, SETTINGS_CARD_W, 318);
|
||||
FAdvGrpWeb := Grp;
|
||||
|
||||
Y := R1;
|
||||
Chk := TFlatCheckBox.Create(Self);
|
||||
@@ -3515,6 +3849,8 @@ begin
|
||||
|
||||
// TCI Server живёт на вкладке CAT (см. BuildCATTab): это такой же канал
|
||||
// внешнего управления трансивером, что и CAT, и оператор ищет его там.
|
||||
|
||||
RelayoutAdvancedTab; // стартовая раскладка (полный, openHPSDR-вид)
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.BuildDXClusterTab;
|
||||
@@ -6110,6 +6446,20 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.SetQOBackend(IsPluto: Boolean);
|
||||
// Транспондер QO-100 у нас существует только на AD936x: InQO100 в контроллере
|
||||
// требует IsPluto (полный дуплекс с раздельными RX/TX LO). На openHPSDR вся
|
||||
// вкладка мертва, поэтому её нет в списке.
|
||||
var
|
||||
Changed: Boolean;
|
||||
begin
|
||||
Changed := FNavQO.Visible <> IsPluto;
|
||||
FNavQO.Visible := IsPluto;
|
||||
if Changed then RelayoutNav; // иначе на её месте останется дыра
|
||||
if (not IsPluto) and FPageQO.Visible then
|
||||
SelectPage(FPageAudio, FNavAudio);
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.SetOCBackend(IsPluto: Boolean);
|
||||
// У Pluto/AD936x нет Open Collector выхода — вкладка целиком скрывается,
|
||||
// а не показывает пустое содержимое (в отличие от Antenna, где Pluto имеет
|
||||
|
||||
@@ -230,6 +230,8 @@ type
|
||||
procedure SetLastSWR(V: Double);
|
||||
function GetPAMaxPower: Double;
|
||||
procedure SetPAMaxPower(V: Double);
|
||||
function GetHasPATelemetry: Boolean;
|
||||
procedure SetHasPATelemetry(V: Boolean);
|
||||
function GetTransmitting: Boolean;
|
||||
procedure SetTransmitting(V: Boolean);
|
||||
procedure SetPbSMeterRight(V: TPaintBox);
|
||||
@@ -301,6 +303,8 @@ type
|
||||
property LastFwdW: Double read GetLastFwdW write SetLastFwdW;
|
||||
property LastSWR: Double read GetLastSWR write SetLastSWR;
|
||||
property PAMaxPower: Double read GetPAMaxPower write SetPAMaxPower;
|
||||
// Есть ли мост детектора мощности: без него шкала PWR/SWR рисуется пустой.
|
||||
property HasPATelemetry: Boolean read GetHasPATelemetry write SetHasPATelemetry;
|
||||
property Transmitting: Boolean read GetTransmitting write SetTransmitting;
|
||||
|
||||
// ── Флаги обновления ──────────────────────────────────────────────────────
|
||||
@@ -612,6 +616,8 @@ function TSpectrumView.GetLastSWR: Double; begin Result := FSMeter.Las
|
||||
procedure TSpectrumView.SetLastSWR(V: Double); begin FSMeter.LastSWR := V; end;
|
||||
function TSpectrumView.GetPAMaxPower: Double; begin Result := FSMeter.PAMaxPower; end;
|
||||
procedure TSpectrumView.SetPAMaxPower(V: Double); begin FSMeter.PAMaxPower := V; end;
|
||||
function TSpectrumView.GetHasPATelemetry: Boolean; begin Result := FSMeter.HasPATelemetry; end;
|
||||
procedure TSpectrumView.SetHasPATelemetry(V: Boolean); begin FSMeter.HasPATelemetry := V; end;
|
||||
function TSpectrumView.GetTransmitting: Boolean; begin Result := FSMeter.Transmitting; end;
|
||||
procedure TSpectrumView.SetTransmitting(V: Boolean); begin FSMeter.Transmitting := V; end;
|
||||
procedure TSpectrumView.SetPbSMeterRight(V: TPaintBox); begin FSMeter.PbSMeterRight := V; end;
|
||||
|
||||
Reference in New Issue
Block a user