mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-26 22:37:32 +00:00
feature(rx): плавный аттенюатор 0..31 дБ в UI, память на диапазон, компенсация уровней
Аттенюатор был только в web и только тремя ступенями (0/-10/-20), а его дБ
никуда не возвращались — при ATT 20 дБ S-метр и спектр уезжали на 20 дБ, и
свежая калибровка уровней была верна лишь при ATT=0.
- RadioController: SetAtten(Db) 0..31 (как умеет железо) вместо индекса *10.
AttenCalDB входит в SMeterCalFor и DispCalFor — стрелка, спектр, водопад и
паны компенсируются, шкала dBm остаётся абсолютной (как Thetis/piHPSDR).
У AD936x аттенюатора нет, там поправка 0 (усиление тракта — hardwaregain).
- Память на диапазон/слот трансвертера по образцу RxGainMode/RxGainDb:
TBandSettings.AttenDB (band 'atten_db') и TXvtrEntry.LastAttenDB
('last_atten_db'); восстановление и отправка в железо — в ApplyBandDSP,
сбор — в MakeBandSettings/SaveCurrentBand, вход в слот — через B.AttenDB.
SetAtten сразу кладёт значение в кэш диапазона/слота (JSON пишется общим
сохранением, а не на каждый шаг ползунка — как у drive).
- MainForm: ряд «ATT [ползунок] NNdB» в RX-блоке левой панели, отступы как у
VOL; на Pluto ряд скрыт и RX-блок ужимается (LayoutLeftPanel двигает
панели ниже). Внешние изменения приходят по rfAtten.
- Web: select → ползунок 0..31 с цифрой, attn_idx -> attn_db, cmd attn {db:}.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+68
-2
@@ -347,6 +347,11 @@ type
|
||||
FPSPopup: TObject; // TPureSignalPopup (cast при использовании)
|
||||
|
||||
PanelRXBlock: TPanel;
|
||||
// Шаговый аттенюатор ADC (openHPSDR): плавные 0..31 дБ. На Pluto ряд
|
||||
// скрыт — там усиление тракта живёт в блоке RF AGC.
|
||||
LblAtt: TLabel;
|
||||
LblAttVal: TLabel;
|
||||
TrkAtt: TFlatSlider;
|
||||
BtnChannels: TFlatButton;
|
||||
FChannelsDropDown: TFlatDropDown;
|
||||
FChannelsForm: TObject; // TChannelsForm (cast при использовании)
|
||||
@@ -706,6 +711,8 @@ type
|
||||
procedure BtnAGCModeClick(Sender: TObject);
|
||||
procedure TrkAGCChange(Sender: TObject);
|
||||
procedure TrkRxGainChange(Sender: TObject);
|
||||
procedure TrkAttChange(Sender: TObject);
|
||||
procedure UpdateAttLabel;
|
||||
// (BtnPlutoGainClick объявлен выше)
|
||||
procedure MeterTimerTick(Sender: TObject);
|
||||
procedure SpectrumTimerTick(Sender: TObject);
|
||||
@@ -762,6 +769,13 @@ uses SettingsForm;
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
const
|
||||
// Высота RX-блока левой панели: с рядом ATT (openHPSDR) и без него (Pluto —
|
||||
// там усиление тракта в блоке RF AGC). Переключает LayoutLeftPanel, он же
|
||||
// двигает панели ниже.
|
||||
RX_BLOCK_H = 96;
|
||||
RX_BLOCK_H_ATT = 120;
|
||||
|
||||
function TMainForm.LeftPanelButtonWidth(PanelWidth, ColCount,
|
||||
ColIndex: Integer): Integer;
|
||||
var
|
||||
@@ -1505,6 +1519,12 @@ begin
|
||||
TrkVolume.Position := FController.ActiveVolume; // RX или TX-монитор
|
||||
rfRxGain:
|
||||
UpdateRxGainUI;
|
||||
rfAtten:
|
||||
if TrkAtt <> nil then
|
||||
begin
|
||||
TrkAtt.Position := FController.FAtten;
|
||||
UpdateAttLabel;
|
||||
end;
|
||||
rfDrive:
|
||||
begin
|
||||
TrkDrive.Position := FController.FDrivePercent; // слайдер ← drive%
|
||||
@@ -2028,7 +2048,7 @@ begin
|
||||
// RX block: CTUN + VOL + NR/NB/SNB/ANF/MUTE
|
||||
PanelRXBlock := TPanel.Create(Self);
|
||||
PanelRXBlock.Parent := PanelLeft;
|
||||
PanelRXBlock.SetBounds(0, Y, LEFT_W, 96);
|
||||
PanelRXBlock.SetBounds(0, Y, LEFT_W, RX_BLOCK_H_ATT);
|
||||
PanelRXBlock.BevelOuter := bvNone;
|
||||
MakeLbl(PanelRXBlock, 'RX', 4, 2);
|
||||
|
||||
@@ -2084,7 +2104,29 @@ begin
|
||||
LeftPanelButtonLeft(LEFT_W, 5, 4), 70,
|
||||
LeftPanelButtonWidth(LEFT_W, 5, 4), BTN_SM, BtnMuteClick);
|
||||
|
||||
Inc(Y, 100);
|
||||
// Шаговый аттенюатор ADC — плавный 0..31 дБ (железо openHPSDR так и умеет,
|
||||
// ступени 0/10/20 были только в web-UI). Показания S-метра/спектра на эти
|
||||
// дБ компенсируются в контроллере, шкала dBm остаётся абсолютной.
|
||||
LblAtt := TLabel.Create(Self);
|
||||
LblAtt.Parent := PanelRXBlock; LblAtt.Left := 4; LblAtt.Top := 106;
|
||||
LblAtt.Caption := 'ATT'; LblAtt.Font.Color := CLR_TEXTDIM;
|
||||
LblAtt.Font.Name := 'Courier New'; LblAtt.Font.Size := 7;
|
||||
|
||||
TrkAtt := TFlatSlider.Create(Self);
|
||||
TrkAtt.Parent := PanelRXBlock; TrkAtt.Left := 34; TrkAtt.Top := 102;
|
||||
TrkAtt.Width := LEFT_W - 76; TrkAtt.Height := 16;
|
||||
TrkAtt.Min := 0; TrkAtt.Max := 31; // ADC step attenuator, дБ
|
||||
TrkAtt.Position := FController.FAtten;
|
||||
TrkAtt.OnChange := TrkAttChange;
|
||||
|
||||
LblAttVal := TLabel.Create(Self);
|
||||
LblAttVal.Parent := PanelRXBlock;
|
||||
LblAttVal.Left := LEFT_W - 38; LblAttVal.Top := 106;
|
||||
LblAttVal.Font.Color := CLR_TEXT; LblAttVal.Font.Name := 'Courier New';
|
||||
LblAttVal.Font.Size := 7;
|
||||
UpdateAttLabel;
|
||||
|
||||
Inc(Y, RX_BLOCK_H_ATT + 4);
|
||||
|
||||
// AGC controls
|
||||
PanelAGC := TPanel.Create(Self);
|
||||
@@ -7933,6 +7975,19 @@ begin
|
||||
FController.SetRxGain(TrkRxGain.Position); // переводит в manual
|
||||
end;
|
||||
|
||||
procedure TMainForm.TrkAttChange(Sender: TObject);
|
||||
begin
|
||||
if FSyncingFromController then Exit;
|
||||
FController.SetAtten(TrkAtt.Position);
|
||||
UpdateAttLabel;
|
||||
end;
|
||||
|
||||
procedure TMainForm.UpdateAttLabel;
|
||||
begin
|
||||
if LblAttVal <> nil then
|
||||
LblAttVal.Caption := Format('%ddB', [FController.FAtten]);
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnPlutoGainClick(Sender: TObject);
|
||||
begin
|
||||
if FSyncingFromController then Exit;
|
||||
@@ -7966,6 +8021,17 @@ procedure TMainForm.LayoutLeftPanel(Pluto: Boolean);
|
||||
var baseTop: Integer;
|
||||
begin
|
||||
if (PanelPlutoAGC = nil) or (PanelAGC = nil) or (PanelBands = nil) then Exit;
|
||||
// Шаговый аттенюатор — только у openHPSDR; у AD936x усиление тракта в блоке
|
||||
// RF AGC ниже, поэтому ряд ATT убираем и RX-блок ужимаем.
|
||||
if (TrkAtt <> nil) and (LblAtt <> nil) and (LblAttVal <> nil) then
|
||||
begin
|
||||
TrkAtt.Visible := not Pluto;
|
||||
LblAtt.Visible := not Pluto;
|
||||
LblAttVal.Visible := not Pluto;
|
||||
if Pluto then PanelRXBlock.Height := RX_BLOCK_H
|
||||
else PanelRXBlock.Height := RX_BLOCK_H_ATT;
|
||||
PanelAGC.Top := PanelRXBlock.Top + PanelRXBlock.Height + 4;
|
||||
end;
|
||||
baseTop := PanelAGC.Top + PanelAGC.Height + 4;
|
||||
PanelPlutoAGC.Top := baseTop;
|
||||
PanelPlutoAGC.Visible := Pluto;
|
||||
|
||||
+35
-7
@@ -601,7 +601,7 @@ type
|
||||
procedure ToggleMute;
|
||||
procedure SetDrive(V: Integer);
|
||||
procedure DriveBy(Delta: Integer);
|
||||
procedure SetAtten(Idx: Integer);
|
||||
procedure SetAtten(Db: Integer); // ADC step attenuator, дБ (0..31)
|
||||
|
||||
// ---- Мультислайсы (софт-fan-out) ----
|
||||
// Создаёт слайс на TargetHz: заводит WDSP-канал в движке + свой аудио-выход
|
||||
@@ -635,6 +635,8 @@ type
|
||||
// Офсет спектра/водопада (дБ) для дисплея: PanId 0 = главный, 1..N — пан.
|
||||
// Колбэк движка (display-поток), см. TOnDispCalQuery.
|
||||
function DispCalFor(PanId: Integer): Double;
|
||||
// Поправка на шаговый аттенюатор ADC (дБ) — входит в оба офсета выше.
|
||||
function AttenCalDB: Double;
|
||||
procedure SetSliceDevice(Id, DevIndex: Integer; const DevName: string);
|
||||
function SliceCount: Integer;
|
||||
function GetSlice(Id: Integer; out S: TCtrlSlice): Boolean;
|
||||
@@ -2094,7 +2096,17 @@ end;
|
||||
|
||||
function TRadioController.SMeterCalFor(VisibleHz: Double): Double;
|
||||
begin
|
||||
Result := CalLookup(VisibleHz, FCal.SMeterBandDB, FCal.SMeterXvtrDB);
|
||||
Result := CalLookup(VisibleHz, FCal.SMeterBandDB, FCal.SMeterXvtrDB)
|
||||
+ AttenCalDB;
|
||||
end;
|
||||
|
||||
function TRadioController.AttenCalDB: Double;
|
||||
// Шаговый аттенюатор ADC режет вход — чтобы шкала dBm оставалась абсолютной,
|
||||
// его дБ возвращаются в показания (так же делают Thetis и piHPSDR). У AD936x
|
||||
// такого аттенюатора нет: там усиление тракта — hardwaregain.
|
||||
begin
|
||||
if IsPluto then Result := 0.0
|
||||
else Result := FAtten;
|
||||
end;
|
||||
|
||||
function TRadioController.DispCalFor(PanId: Integer): Double;
|
||||
@@ -2105,7 +2117,7 @@ begin
|
||||
if (PanId > 0) and (PanId < MAX_PANS) then Hz := FPanFreqHz[PanId]
|
||||
else Hz := FCenterFreq;
|
||||
if Hz <= 0 then Exit(0.0);
|
||||
Result := CalLookup(Hz, FCal.DispBandDB, FCal.DispXvtrDB);
|
||||
Result := CalLookup(Hz, FCal.DispBandDB, FCal.DispXvtrDB) + AttenCalDB;
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetSliceDevice(Id, DevIndex: Integer;
|
||||
@@ -2808,6 +2820,7 @@ begin
|
||||
// Аппаратный AGC AD936x — на диапазон (усиление тракта разное на 2м и QO-100).
|
||||
Result.RxGainMode := FRxGainMode;
|
||||
Result.RxGainDb := FRxGainDb;
|
||||
Result.AttenDB := FAtten; // шаговый аттенюатор ADC — тоже на диапазон
|
||||
// Waterfall AGC/NF — глобальные (не диапазонные)
|
||||
end;
|
||||
|
||||
@@ -2846,6 +2859,7 @@ begin
|
||||
FXvtrSettings.Entries[i].LastPanSlider := FPanSlider;
|
||||
FXvtrSettings.Entries[i].LastRxGainMode := FRxGainMode;
|
||||
FXvtrSettings.Entries[i].LastRxGainDb := FRxGainDb;
|
||||
FXvtrSettings.Entries[i].LastAttenDB := FAtten;
|
||||
end;
|
||||
FSettings.SaveXvtr(FDevMAC, FXvtrSettings);
|
||||
Exit;
|
||||
@@ -2975,6 +2989,11 @@ begin
|
||||
ApplyRxGainToBackend;
|
||||
Changed(rfRxGain); // UI: кнопки FAST/SLOW/HYB/MAN + ползунок
|
||||
|
||||
// --- Шаговый аттенюатор ADC (openHPSDR) — на диапазон/слот трансвертера.
|
||||
FAtten := EnsureRange(B.AttenDB, 0, 31);
|
||||
if Assigned(FNetwork) then FNetwork.SetStepAtten(Byte(FAtten));
|
||||
Changed(rfAtten);
|
||||
|
||||
// --- FM squelch / CTCSS / step / repeater ---
|
||||
FFMSQOn := B.FMSQOn;
|
||||
FFMSQLevel := B.FMSQLevel;
|
||||
@@ -3646,12 +3665,20 @@ begin
|
||||
else FDSPEngine.SetDriveLevel(EnsureRange(Pct, 0, 100) / 100.0);
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetAtten(Idx: Integer);
|
||||
procedure TRadioController.SetAtten(Db: Integer);
|
||||
// Шаговый аттенюатор ADC — плавный 0..31 дБ (как в железе openHPSDR), а не
|
||||
// три фиксированные ступени. Уровни S-метра/спектра компенсируются на ту же
|
||||
// величину (CalLookup), поэтому шкала dBm остаётся абсолютной.
|
||||
begin
|
||||
if Idx < 0 then Idx := 0 else if Idx > 2 then Idx := 2;
|
||||
FAtten := Idx;
|
||||
if Assigned(FNetwork) then FNetwork.SetStepAtten(FAtten * 10);
|
||||
FAtten := EnsureRange(Db, 0, 31);
|
||||
if Assigned(FNetwork) then FNetwork.SetStepAtten(Byte(FAtten));
|
||||
Changed(rfAtten);
|
||||
// Персист — вместе с диапазоном/слотом (SaveCurrentBand на выходе из них),
|
||||
// писать JSON на каждый шаг ползунка незачем, как и у drive.
|
||||
if (FCurrentXvtr >= 0) and (FCurrentXvtr < CFG_XVTR_COUNT) then
|
||||
FXvtrSettings.Entries[FCurrentXvtr].LastAttenDB := FAtten
|
||||
else if (FCurrentBand >= 0) and (FCurrentBand < CFG_BAND_COUNT) then
|
||||
FBandCache[FCurrentBand].AttenDB := FAtten;
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetBand(Idx: Integer);
|
||||
@@ -3742,6 +3769,7 @@ begin
|
||||
B.FMRptOffsetHz := E.LastFMRptOffsetHz;
|
||||
B.RxGainMode := E.LastRxGainMode; // hw-AGC слота (AD936x)
|
||||
B.RxGainDb := E.LastRxGainDb;
|
||||
B.AttenDB := E.LastAttenDB; // аттенюатор ADC слота
|
||||
B.VfoA := Vis;
|
||||
B.VfoB := FVfoB;
|
||||
ApplyBandDSP(B);
|
||||
|
||||
@@ -103,6 +103,9 @@ type
|
||||
// сильно разное на 2м и на QO-100, поэтому режим и manual-гейн per-band.
|
||||
RxGainMode: Integer; // 0=manual,1=fast,2=slow,3=hybrid
|
||||
RxGainDb: Integer; // manual gain, дБ (0..73)
|
||||
// Шаговый аттенюатор ADC (openHPSDR) — на диапазон: на 40м ночью нужен,
|
||||
// на 10м нет. 0..31 дБ.
|
||||
AttenDB: Integer;
|
||||
end;
|
||||
|
||||
// Персист панадаптеров и слайсов (секция "pans" под MAC). Восстанавливается
|
||||
@@ -295,6 +298,7 @@ type
|
||||
// Аппаратный AGC AD936x на слот трансвертера (у QO-100 своё усиление тракта).
|
||||
LastRxGainMode: Integer; // 0=manual,1=fast,2=slow,3=hybrid
|
||||
LastRxGainDb: Integer; // manual gain, дБ
|
||||
LastAttenDB: Integer; // шаговый аттенюатор ADC слота, дБ (0..31)
|
||||
end;
|
||||
|
||||
TXvtrSettings = record
|
||||
@@ -558,6 +562,7 @@ begin
|
||||
B.SpanHz := 192000;
|
||||
B.RxGainMode := 2; // slow_attack (как глобальный дефолт Pluto)
|
||||
B.RxGainDb := 40;
|
||||
B.AttenDB := 0;
|
||||
B.FMSQOn := False;
|
||||
B.FMSQLevel := 30;
|
||||
B.CTCSSOn := False;
|
||||
@@ -944,6 +949,7 @@ begin
|
||||
Bands[i].FMRptOffsetHz := JD(BObj,'fmrpt_offset', Bands[i].FMRptOffsetHz);
|
||||
Bands[i].RxGainMode := EnsureRange(JI(BObj,'rx_gain_mode', Bands[i].RxGainMode), 0, 3);
|
||||
Bands[i].RxGainDb := EnsureRange(JI(BObj,'rx_gain_db', Bands[i].RxGainDb), 0, 73);
|
||||
Bands[i].AttenDB := EnsureRange(JI(BObj,'atten_db', Bands[i].AttenDB), 0, 31);
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -1060,6 +1066,7 @@ begin
|
||||
JW(O,'fmrpt_dir',B.FMRptDir); JW(O,'fmrpt_offset',B.FMRptOffsetHz);
|
||||
JW(O,'zoom_factor',B.ZoomFactor); JW(O,'pan_slider',B.PanSlider);
|
||||
JW(O,'rx_gain_mode',B.RxGainMode); JW(O,'rx_gain_db',B.RxGainDb);
|
||||
JW(O,'atten_db',B.AttenDB);
|
||||
end;
|
||||
|
||||
function TSettingsManager.LoadBand(const MAC: array of Byte; BandIdx: Integer;
|
||||
@@ -1091,6 +1098,7 @@ begin
|
||||
B.FMRptOffsetHz := JD(O,'fmrpt_offset', B.FMRptOffsetHz);
|
||||
B.RxGainMode := EnsureRange(JI(O,'rx_gain_mode', B.RxGainMode), 0, 3);
|
||||
B.RxGainDb := EnsureRange(JI(O,'rx_gain_db', B.RxGainDb), 0, 73);
|
||||
B.AttenDB := EnsureRange(JI(O,'atten_db', B.AttenDB), 0, 31);
|
||||
B.ZoomFactor := EnsureRange(JD(O,'zoom_factor', B.ZoomFactor), 0.0, 1.0);
|
||||
B.PanSlider := EnsureRange(JD(O,'pan_slider', B.PanSlider), 0.0, 1.0);
|
||||
end;
|
||||
@@ -1617,6 +1625,7 @@ begin
|
||||
X.Entries[i].LastPanSlider := 0.5;
|
||||
X.Entries[i].LastRxGainMode := 2; // slow_attack
|
||||
X.Entries[i].LastRxGainDb := 40;
|
||||
X.Entries[i].LastAttenDB := 0;
|
||||
end;
|
||||
// Шаблоны (пользователь должен сам Enable, чтобы трансверторы появились)
|
||||
X.Entries[0].ButtonText := '2m';
|
||||
@@ -1698,6 +1707,7 @@ begin
|
||||
X.Entries[i].LastPanSlider := EnsureRange(JD(EObj, 'last_pan_slider', X.Entries[i].LastPanSlider), 0.0, 1.0);
|
||||
X.Entries[i].LastRxGainMode := EnsureRange(JI(EObj, 'last_rx_gain_mode', X.Entries[i].LastRxGainMode), 0, 3);
|
||||
X.Entries[i].LastRxGainDb := EnsureRange(JI(EObj, 'last_rx_gain_db', X.Entries[i].LastRxGainDb), 0, 73);
|
||||
X.Entries[i].LastAttenDB := EnsureRange(JI(EObj, 'last_atten_db', X.Entries[i].LastAttenDB), 0, 31);
|
||||
// Валидация: Last freqs должны быть в [FreqBegin..FreqEnd]
|
||||
if (X.Entries[i].LastFreq < X.Entries[i].FreqBegin) or
|
||||
(X.Entries[i].LastFreq > X.Entries[i].FreqEnd) then
|
||||
@@ -1798,6 +1808,7 @@ begin
|
||||
JW(EObj, 'last_pan_slider', X.Entries[i].LastPanSlider);
|
||||
JW(EObj, 'last_rx_gain_mode', X.Entries[i].LastRxGainMode);
|
||||
JW(EObj, 'last_rx_gain_db', X.Entries[i].LastRxGainDb);
|
||||
JW(EObj, 'last_atten_db', X.Entries[i].LastAttenDB);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
+4
-4
@@ -199,7 +199,7 @@ begin
|
||||
'<option value="10">10 Hz</option><option value="100" selected>100 Hz</option>' +
|
||||
'<option value="1000">1 kHz</option><option value="10000">10 kHz</option>' +
|
||||
'</select>' +
|
||||
'<select id="attSel"><option value="0" selected>0 dB</option><option value="1">-10 dB</option><option value="2">-20 dB</option></select>' +
|
||||
'<div class="sl-g"><span class="sl-lb">ATT</span><input type="range" id="attSl" min="0" max="31" value="0"><span class="sl-val" id="attVal">0</span></div>' +
|
||||
'<button id="nbBtn">NB</button>' +
|
||||
'<button id="snbBtn">SNB</button>' +
|
||||
'<button id="anfBtn">ANF</button>' +
|
||||
@@ -311,7 +311,7 @@ begin
|
||||
'q("modGrpSel").onchange=function(){const grp=GRP_MAP[modGrp()];const defaultMode=grp[0];cur.mode=defaultMode;syncModGrp(defaultMode);pend("mode");ws2({cmd:"mode",mode:defaultMode});};' +
|
||||
'q("modTglBtn").onclick=function(){audioKick();const next=modTglTarget();cur.mode=next;syncModGrp(next);pend("mode");ws2({cmd:"mode",mode:next});};' +
|
||||
'q("agcSel").onchange=function(e){pend("agc");ws2({cmd:"agc",mode:+e.target.value});};' +
|
||||
'q("attSel").onchange=function(e){pend("attn");ws2({cmd:"attn",idx:+e.target.value});};' +
|
||||
'q("attSl").oninput=function(e){var v=+e.target.value;var lbl=q("attVal");if(lbl)lbl.textContent=v;pend("attn");ws2({cmd:"attn",db:v});};' +
|
||||
|
||||
// FNP — фильтровый оверлей
|
||||
'var FNP_N={ssb:["5.0k","4.4k","3.8k","3.3k","2.9k","2.7k","2.4k","2.1k","1.8k","1.0k"],' +
|
||||
@@ -732,7 +732,7 @@ begin
|
||||
'function isPending(field){return !!(pendingCmds[field]&&pendingCmds[field]>Date.now());}' +
|
||||
|
||||
// Маппинг: server JSON field → pend key
|
||||
'var PEND_MAP={vfo_a_hz:"freq",vfo_b_hz:"freq",nr:"nr",nr_mode:"nr",nb:"nb",nb_mode:"nb",snb:"snb",anf:"anf",running:"run",mode:"mode",agc_mode:"agc",transmitting:"mox",drive:"drive",attn_idx:"attn",tuning:"tun",filter_bw:"filter",mute:"mute",beacon_on:"beacon",rx_mute_on:"rxmute",rx_gain_mode:"rxgain",rx_gain_db:"rxgain"};' +
|
||||
'var PEND_MAP={vfo_a_hz:"freq",vfo_b_hz:"freq",nr:"nr",nr_mode:"nr",nb:"nb",nb_mode:"nb",snb:"snb",anf:"anf",running:"run",mode:"mode",agc_mode:"agc",transmitting:"mox",drive:"drive",attn_db:"attn",tuning:"tun",filter_bw:"filter",mute:"mute",beacon_on:"beacon",rx_mute_on:"rxmute",rx_gain_mode:"rxgain",rx_gain_db:"rxgain"};' +
|
||||
|
||||
'function applyState(msg){' +
|
||||
'Object.keys(msg).forEach(function(k){var pk=PEND_MAP[k];if(!pk||!isPending(pk))cur[k]=msg[k];});' +
|
||||
@@ -786,7 +786,7 @@ begin
|
||||
'if(!isPending("mute"))updMuteIc();' +
|
||||
'if(!isPending("drive")){const ts=q("txSl");if(ts&&!ts.matches(":active")){ts.value=cur.drive||0;var tv=q("txVal");if(tv)tv.textContent=cur.drive||0;}}' +
|
||||
'if(!isPending("mode")){syncModGrp(cur.mode||0);syncStepSel();}' +
|
||||
'if(!isPending("attn")){const at=q("attSel");if(at)at.value=cur.attn_idx||0;}' +
|
||||
'if(!isPending("attn")){const at=q("attSl");if(at&&!at.matches(":active")){at.value=cur.attn_db||0;var av=q("attVal");if(av)av.textContent=cur.attn_db||0;}}' +
|
||||
'updBand(activeVfo==="A"?(cur.vfo_a_hz||0):(vfoB||0));updSpan(cur.span_hz||192000);' +
|
||||
'paintSM(Number(cur.smeter_dbm||-130));' +
|
||||
'updStatusBar();' +
|
||||
|
||||
+9
-9
@@ -296,7 +296,7 @@ type
|
||||
FDriveLevel: Integer;
|
||||
FOnFreqA: TWebCmdFreqA;
|
||||
FOnAttn: TWebCmdAttn;
|
||||
FAttnIdx: Integer;
|
||||
FAttnDB: Integer; // шаговый аттенюатор ADC, дБ (0..31)
|
||||
FOnTun: TWebCmdTun;
|
||||
FOnFMStep: TWebCmdFMStep;
|
||||
FTuning: Boolean;
|
||||
@@ -406,7 +406,7 @@ type
|
||||
CenterHz: Double; FilterIdx: Integer;
|
||||
VfoB: Double; ActiveVfo: Integer;
|
||||
Transmitting: Boolean; DriveLevel: Integer;
|
||||
AttnIdx: Integer; Tuning: Boolean; Duplex: Boolean;
|
||||
AttnDB: Integer; Tuning: Boolean; Duplex: Boolean;
|
||||
FwdW, SWRV, PAMaxPower: Double;
|
||||
const StatusText, BoardText, IPText, SupplyText, PLLText,
|
||||
RXText, TXText, SeqText: string);
|
||||
@@ -1572,10 +1572,10 @@ begin
|
||||
end
|
||||
else if Cmd = 'attn' then
|
||||
begin
|
||||
Idx := JsonGetInt(Json, 'idx', FAttnIdx);
|
||||
Idx := JsonGetInt(Json, 'db', FAttnDB);
|
||||
if Idx < 0 then Idx := 0;
|
||||
if Idx > 2 then Idx := 2;
|
||||
FStateLock.Enter; FAttnIdx := Idx; FStateLock.Leave;
|
||||
if Idx > 31 then Idx := 31;
|
||||
FStateLock.Enter; FAttnDB := Idx; FStateLock.Leave;
|
||||
if Assigned(FOnAttn) then FOnAttn(Idx);
|
||||
end
|
||||
else if Cmd = 'fm_step' then
|
||||
@@ -1778,7 +1778,7 @@ begin
|
||||
'"wf_agc":%s,"wf_nf":%s,"band_idx":%d,"smeter_dbm":%.1f,' +
|
||||
'"running":%s,"mute":%s,"ctun":%s,' +
|
||||
'"nr_mode":%d,"nr":%s,"nb_mode":%d,"nb":%s,"snb":%s,"anf":%s,"connected":%s,' +
|
||||
'"transmitting":%s,"drive":%d,"attn_idx":%d,"tuning":%s,"dup":%s,' +
|
||||
'"transmitting":%s,"drive":%d,"attn_db":%d,"tuning":%s,"dup":%s,' +
|
||||
'"fwd_w":%.1f,"swr":%.2f,"pa_max_power":%.0f,' +
|
||||
'"status_text":"%s","board_text":"%s","ip_text":"%s","supply_text":"%s",' +
|
||||
'"pll_text":"%s","rx_text":"%s","tx_text":"%s","seq_text":"%s",' +
|
||||
@@ -1809,7 +1809,7 @@ begin
|
||||
BoolToStr(FConnected, 'true', 'false'),
|
||||
BoolToStr(FTransmitting, 'true', 'false'),
|
||||
FDriveLevel,
|
||||
FAttnIdx,
|
||||
FAttnDB,
|
||||
BoolToStr(FTuning, 'true', 'false'),
|
||||
BoolToStr(FDuplex, 'true', 'false'),
|
||||
FFwdW, FSWR, FPAMaxPower,
|
||||
@@ -1889,7 +1889,7 @@ procedure TWebServer.PushSpectrum(
|
||||
CenterHz: Double; FilterIdx: Integer;
|
||||
VfoB: Double; ActiveVfo: Integer;
|
||||
Transmitting: Boolean; DriveLevel: Integer;
|
||||
AttnIdx: Integer; Tuning: Boolean; Duplex: Boolean;
|
||||
AttnDB: Integer; Tuning: Boolean; Duplex: Boolean;
|
||||
FwdW, SWRV, PAMaxPower: Double;
|
||||
const StatusText, BoardText, IPText, SupplyText, PLLText,
|
||||
RXText, TXText, SeqText: string);
|
||||
@@ -1926,7 +1926,7 @@ begin
|
||||
FActiveVfo := ActiveVfo;
|
||||
FTransmitting := Transmitting;
|
||||
FDriveLevel := DriveLevel;
|
||||
FAttnIdx := AttnIdx;
|
||||
FAttnDB := AttnDB;
|
||||
FTuning := Tuning;
|
||||
FDuplex := Duplex;
|
||||
FFwdW := FwdW;
|
||||
|
||||
Reference in New Issue
Block a user