mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Add FM mode improvements: NFM/FM filters, CTCSS, squelch; ADC and web settings
FM modulation: - Replace 10 generic FM filter buttons with NFM (2.5kHz dev/11kHz BW) and FM (5.0kHz dev/16kHz BW); deviation applied to both RX and TX via WDSP - Add FM squelch panel (SQL toggle + slider 0..100, per-band save/restore) with WDSP SetRXAFMSQRun/SetRXAFMSQThreshold (threshold = level/200.0) - Add CTCSS panel with on/off toggle and custom flat-button tone picker popup (38 standard tones 67.0..250.3 Hz, default 67.0); tone selection and enable state saved per band via SetTXACTCSS* - FM panels (SQL, CTCSS) shown only in FM mode, layout via RelayoutBelowBands - PanelFilter height shrinks in FM mode so panels sit tight below filters - FlatButton: handle CMTextChanged to invalidate on Caption change ADC settings (Dither/Random): - Add DitherEnabled/RandomEnabled to TGlobalSettings (default true) - Pass as bitmask to ConfigureDDCs DDC Specific packet bytes 5/6 - Exposed in Settings → Advanced tab with live apply via ApplyADCSettings Web server settings: - Add TWebSettings (enabled, port, bind_addr, user, pass) stored globally - WebServer: configurable port/bind IP via ParseIPv4; Reconfigure method - Exposed in Settings → Advanced tab with live apply via ApplyWebSettings Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+358
-26
@@ -76,12 +76,26 @@ const
|
||||
(16000, 12000, 10000, 8000, 6600, 5200, 4000, 3100, 2900, 2400);
|
||||
FILT_AM_DEF = 3; // 8k
|
||||
|
||||
// FM
|
||||
FILT_FM_NAMES: array[0..FILT_COUNT-1] of string =
|
||||
('20k','15k','12k','10k','8k','6k','5k','4k','3k','2k');
|
||||
FILT_FM_BW: array[0..FILT_COUNT-1] of Integer =
|
||||
(20000, 15000, 12000, 10000, 8000, 6000, 5000, 4000, 3000, 2000);
|
||||
FILT_FM_DEF = 0; // 20k
|
||||
// FM: NFM (2.5 kHz deviation / 11 kHz BW) and FM (5.0 kHz deviation / 16 kHz BW)
|
||||
FILT_FM_COUNT = 2;
|
||||
FILT_FM_NAMES: array[0..1] of string = ('NFM', 'FM');
|
||||
FILT_FM_BW: array[0..1] of Integer = (11000, 16000);
|
||||
FILT_FM_DEV: array[0..1] of Double = (2500.0, 5000.0);
|
||||
FILT_FM_DEF = 0; // NFM
|
||||
|
||||
// CTCSS tones (38 standard tones, no None — toggle via CTCSS button)
|
||||
CTCSS_COUNT = 38;
|
||||
CTCSS_TONES: array[0..37] of Double = (
|
||||
67.0, 71.9, 74.4, 77.0, 79.7, 82.5, 85.4, 88.5, 91.5, 94.8,
|
||||
97.4, 100.0, 103.5, 107.2, 110.9, 114.8, 118.8, 123.0, 127.3, 131.8,
|
||||
136.5, 141.3, 146.2, 151.4, 156.7, 162.2, 167.9, 173.8, 179.9, 186.2,
|
||||
192.8, 203.5, 210.7, 218.1, 225.7, 233.6, 241.8, 250.3);
|
||||
CTCSS_NAMES: array[0..37] of string = (
|
||||
'67.0', '71.9', '74.4', '77.0', '79.7', '82.5', '85.4', '88.5',
|
||||
'91.5', '94.8', '97.4', '100.0', '103.5', '107.2', '110.9', '114.8',
|
||||
'118.8', '123.0', '127.3', '131.8', '136.5', '141.3', '146.2', '151.4',
|
||||
'156.7', '162.2', '167.9', '173.8', '179.9', '186.2', '192.8', '203.5',
|
||||
'210.7', '218.1', '225.7', '233.6', '241.8', '250.3');
|
||||
|
||||
BAND_NAMES: array[0..BAND_COUNT-1] of string = (
|
||||
'160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m');
|
||||
@@ -230,6 +244,13 @@ type
|
||||
// Waterfall settings (kept here for MakeGlobalSettings, buttons, settings dialog)
|
||||
FWfAGCEnabled: Boolean;
|
||||
FWfNFEnabled: Boolean;
|
||||
FDitherEnabled: Boolean;
|
||||
FRandomEnabled: Boolean;
|
||||
FFMDeviation: Double;
|
||||
FFMCTCSSOn: Boolean;
|
||||
FFMCTCSSToneIdx: Integer;
|
||||
FFMSQOn: Boolean;
|
||||
FFMSQLevel: Integer;
|
||||
FWfManualHigh: Double;
|
||||
FWfManualLow: Double;
|
||||
FWfAGCOffset: Double;
|
||||
@@ -257,7 +278,12 @@ type
|
||||
FSplitterRatio: Double;
|
||||
// --- Settings ---
|
||||
FSettings: TSettingsManager;
|
||||
FWebServer: TWebServer; // веб-интерфейс (порт 8080)
|
||||
FWebServer: TWebServer;
|
||||
FWebEnabled: Boolean;
|
||||
FWebPort: Integer;
|
||||
FWebBindAddr: string;
|
||||
FWebUser: string;
|
||||
FWebPass: string;
|
||||
FSavedMicSource: TTXMicSource; // сохраняется при переключении на txmsWeb
|
||||
FWebMicActive: Boolean; // True если текущий TX идёт через txmsWeb
|
||||
// --- CAT ---
|
||||
@@ -331,6 +357,15 @@ type
|
||||
BtnFilter: array[0..FILT_COUNT-1] of TFlatButton;
|
||||
BtnCTun: TFlatButton;
|
||||
BtnDUP: TFlatButton;
|
||||
PanelFMSQ: TPanel;
|
||||
BtnFMSQ: TFlatButton;
|
||||
TrkFMSQ: TFlatSlider;
|
||||
LblFMSQ: TLabel;
|
||||
PanelFMCTCSS: TPanel;
|
||||
BtnFMCTCSS: TFlatButton;
|
||||
BtnFMCTCSSTone: TFlatButton;
|
||||
PanelFMCTCSSPop: TPanel;
|
||||
FBtnCTCSSTones: array[0..CTCSS_COUNT - 1] of TFlatButton;
|
||||
|
||||
PanelRX: TPanel;
|
||||
BtnAGCMode: array[0..4] of TFlatButton; // FAST MED SLOW LONG OFF
|
||||
@@ -441,6 +476,14 @@ type
|
||||
procedure BtnTUNClick(Sender: TObject);
|
||||
procedure ApplyTUN(Active: Boolean);
|
||||
procedure UpdateFilterButtons;
|
||||
procedure BtnFMSQClick(Sender: TObject);
|
||||
procedure TrkFMSQChange(Sender: TObject);
|
||||
procedure ApplyFMSquelch;
|
||||
procedure BtnFMCTCSSClick(Sender: TObject);
|
||||
procedure BtnFMCTCSSToneClick(Sender: TObject);
|
||||
procedure BtnFMToneSelectClick(Sender: TObject);
|
||||
procedure SetFMCTCSSTone(Idx: Integer);
|
||||
procedure CloseCTCSSPopup;
|
||||
procedure PbSpectrumMouseDown(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
procedure PbSpectrumMouseMove(Sender: TObject; Shift: TShiftState;
|
||||
@@ -610,6 +653,9 @@ type
|
||||
procedure ApplyWaterfallParams(WfDet, WfAvgMode: Integer;
|
||||
WfAvgTimeMS, WfHigh, WfLow, WfAGCOffset: Double);
|
||||
procedure ApplyWfAGCNF(WfAGC, WfNF: Boolean);
|
||||
procedure ApplyADCSettings(Dither, Random: Boolean);
|
||||
procedure ApplyWebSettings(Enabled: Boolean; Port: Integer;
|
||||
const BindAddr, User, Pass: string);
|
||||
procedure ApplyGridParams(RefLevel, Range, GridStep: Double);
|
||||
// Пушит активные grid-параметры (RX или TX в зависимости от FTransmitting)
|
||||
// в FSpecView и сбрасывает кэш сетки. Вызывается при смене RX↔TX и при
|
||||
@@ -857,6 +903,8 @@ begin
|
||||
Result.AGCTop := FAGCTop;
|
||||
Result.CTun := FCTun;
|
||||
Result.SpanHz := FSpanHz;
|
||||
Result.FMSQOn := FFMSQOn;
|
||||
Result.FMSQLevel := FFMSQLevel;
|
||||
// Waterfall AGC/NF — глобальные (не диапазонные)
|
||||
end;
|
||||
|
||||
@@ -877,6 +925,8 @@ begin
|
||||
Result.AGCHangThreshold := 100;
|
||||
Result.WfAGCEnabled := FWfAGCEnabled;
|
||||
Result.WfNFEnabled := FWfNFEnabled;
|
||||
Result.DitherEnabled := FDitherEnabled;
|
||||
Result.RandomEnabled := FRandomEnabled;
|
||||
Result.LastBand := FCurrentBand;
|
||||
Result.LastXvtr := FCurrentXvtr;
|
||||
Result.SampleRate := FSampleRate;
|
||||
@@ -990,6 +1040,11 @@ begin
|
||||
end;
|
||||
FSpecView.AGCTop := FAGCTop;
|
||||
|
||||
// --- FM Squelch ---
|
||||
FFMSQOn := B.FMSQOn;
|
||||
FFMSQLevel := B.FMSQLevel;
|
||||
// UI update happens inside UpdateFilterButtons (called above) when mode=FM
|
||||
|
||||
// --- CTUN ---
|
||||
FCTun := B.CTun;
|
||||
StyleButton(BtnCTun, FCTun);
|
||||
@@ -1035,6 +1090,7 @@ end;
|
||||
procedure TMainForm.FormCreate(Sender: TObject);
|
||||
var
|
||||
bi_, StartupRate, i: Integer;
|
||||
WebCfg: TWebSettings;
|
||||
StartupVfoA, StartupVfoB: Double;
|
||||
begin
|
||||
FVfoA := 14200000;
|
||||
@@ -1069,6 +1125,13 @@ begin
|
||||
FWfAGCOffset := 0.0;
|
||||
FWfAGCEnabled := True;
|
||||
FWfNFEnabled := False;
|
||||
FDitherEnabled := True;
|
||||
FRandomEnabled := True;
|
||||
FFMDeviation := FILT_FM_DEV[FILT_FM_DEF];
|
||||
FFMCTCSSOn := False;
|
||||
FFMCTCSSToneIdx := 0;
|
||||
FFMSQOn := False;
|
||||
FFMSQLevel := 30;
|
||||
FSpectrumBufCount := 1024;
|
||||
FWaterfallBufCount := 1024;
|
||||
FWaterfallFrameInterval := 2;
|
||||
@@ -1110,8 +1173,14 @@ begin
|
||||
// (будет пересчитан в первом тике SpectrumTimerTick)
|
||||
FLastSMeter := -130;
|
||||
|
||||
// Создаём веб-сервер (логин: admin, пароль: hpsdr — менять здесь)
|
||||
FWebServer := TWebServer.Create('admin', 'hpsdr');
|
||||
// Загружаем настройки веб-сервера из JSON и создаём сервер
|
||||
FSettings.LoadWebSettings(WebCfg);
|
||||
FWebEnabled := WebCfg.Enabled;
|
||||
FWebPort := WebCfg.Port;
|
||||
FWebBindAddr := WebCfg.BindAddr;
|
||||
FWebUser := WebCfg.User;
|
||||
FWebPass := WebCfg.Pass;
|
||||
FWebServer := TWebServer.Create(FWebUser, FWebPass, Word(FWebPort), FWebBindAddr);
|
||||
FWebServer.OnFreq := WebOnFreq;
|
||||
FWebServer.OnMode := WebOnMode;
|
||||
FWebServer.OnFilter := WebOnFilter;
|
||||
@@ -1139,7 +1208,7 @@ begin
|
||||
FWebServer.OnTun := WebOnTun;
|
||||
FWebServer.OnWebMic := WebOnMic;
|
||||
FWebServer.OnXvtrBand := WebOnXvtrBand;
|
||||
FWebServer.Start;
|
||||
if FWebEnabled then FWebServer.Start;
|
||||
PushXvtrToWeb;
|
||||
FillChar(FCATLastGlobal, SizeOf(FCATLastGlobal), 0);
|
||||
FCATLastGlobal.CATTcpPort := 19090;
|
||||
@@ -1653,6 +1722,70 @@ begin
|
||||
|
||||
Inc(Y, 76);
|
||||
|
||||
// FM Squelch panel (visible only in FM mode, above CTCSS)
|
||||
PanelFMSQ := TPanel.Create(Self);
|
||||
PanelFMSQ.Parent := PanelLeft;
|
||||
PanelFMSQ.SetBounds(0, Y, LEFT_W, 50);
|
||||
PanelFMSQ.BevelOuter := bvNone;
|
||||
PanelFMSQ.Visible := False;
|
||||
MakeLbl(PanelFMSQ, 'SQL', 4, 4);
|
||||
W := LEFT_W div 4 - 2; // button width ~56px
|
||||
BtnFMSQ := MakeBtn(PanelFMSQ, 'SQL', 2, 20, W, BTN_SM, BtnFMSQClick);
|
||||
StyleButton(BtnFMSQ, False);
|
||||
// Slider: vertically centred with button text (button top=20, h=24 → center=32)
|
||||
// Reserve 28px on the right for the numeric label
|
||||
TrkFMSQ := TFlatSlider.Create(Self);
|
||||
TrkFMSQ.Parent := PanelFMSQ;
|
||||
TrkFMSQ.Left := W + 6;
|
||||
TrkFMSQ.Top := 25; // 32 - 14/2 = 25
|
||||
TrkFMSQ.Width := LEFT_W - W - 6 - 30 - 4; // leave 30px for label + margins
|
||||
TrkFMSQ.Height := 14;
|
||||
TrkFMSQ.Min := 0; TrkFMSQ.Max := 100;
|
||||
TrkFMSQ.Position := FFMSQLevel;
|
||||
TrkFMSQ.OnChange := TrkFMSQChange;
|
||||
// Numeric value label to the right of the slider
|
||||
LblFMSQ := TLabel.Create(Self);
|
||||
LblFMSQ.Parent := PanelFMSQ;
|
||||
LblFMSQ.Left := TrkFMSQ.Left + TrkFMSQ.Width + 3;
|
||||
LblFMSQ.Top := 25;
|
||||
LblFMSQ.Width := 26;
|
||||
LblFMSQ.Caption := IntToStr(FFMSQLevel);
|
||||
LblFMSQ.Font.Color := CLR_TEXT;
|
||||
LblFMSQ.Font.Name := 'Courier New';
|
||||
LblFMSQ.Font.Size := 8;
|
||||
|
||||
// FM CTCSS panel (visible only when FM mode is active)
|
||||
PanelFMCTCSS := TPanel.Create(Self);
|
||||
PanelFMCTCSS.Parent := PanelLeft;
|
||||
PanelFMCTCSS.SetBounds(0, Y, LEFT_W, 50);
|
||||
PanelFMCTCSS.BevelOuter := bvNone;
|
||||
PanelFMCTCSS.Visible := False;
|
||||
MakeLbl(PanelFMCTCSS, 'CTCSS', 4, 4);
|
||||
W := LEFT_W div 3 - 2;
|
||||
BtnFMCTCSS := MakeBtn(PanelFMCTCSS, 'CTCSS', 2, 20, W, BTN_H, BtnFMCTCSSClick);
|
||||
StyleButton(BtnFMCTCSS, False);
|
||||
BtnFMCTCSSTone := MakeBtn(PanelFMCTCSS, CTCSS_NAMES[0], W + 4, 20, LEFT_W - W - 8, BTN_H, BtnFMCTCSSToneClick);
|
||||
StyleButton(BtnFMCTCSSTone, False);
|
||||
|
||||
// Tone picker popup (child of PanelLeft, hidden until BtnFMCTCSSTone is clicked)
|
||||
PanelFMCTCSSPop := TPanel.Create(Self);
|
||||
PanelFMCTCSSPop.Parent := PanelLeft;
|
||||
PanelFMCTCSSPop.BevelOuter := bvNone;
|
||||
PanelFMCTCSSPop.Color := CLR_PANEL;
|
||||
PanelFMCTCSSPop.Visible := False;
|
||||
W := (LEFT_W - 4) div 4;
|
||||
PanelFMCTCSSPop.SetBounds(0, 0, LEFT_W, ((CTCSS_COUNT + 3) div 4) * BTN_SM);
|
||||
for i := 0 to CTCSS_COUNT - 1 do
|
||||
begin
|
||||
B := MakeBtn(PanelFMCTCSSPop, CTCSS_NAMES[i],
|
||||
2 + (i mod 4) * W,
|
||||
(i div 4) * BTN_SM,
|
||||
W - 2, BTN_SM, BtnFMToneSelectClick);
|
||||
B.Tag := i;
|
||||
StyleButton(B, i = FFMCTCSSToneIdx);
|
||||
FBtnCTCSSTones[i] := B;
|
||||
end;
|
||||
|
||||
// CTUN / DUP buttons (display-related)
|
||||
BtnCTun := MakeBtn(PanelLeft, 'CTUN', 2, Y, LEFT_W div 3 - 2, BTN_H, BtnCTunClick);
|
||||
BtnCTun.Tag := 0;
|
||||
@@ -2251,6 +2384,9 @@ begin
|
||||
DP(PanelTopVfoGroup); DP(PanelTopVfoA); DP(PanelTopVfoB);
|
||||
DP(PanelVfoA); DP(PanelVfoB); DP(PanelVfoButtons);
|
||||
DP(PanelBands); DP(PanelMode); DP(PanelFilter);
|
||||
if PanelFMSQ <> nil then DP(PanelFMSQ);
|
||||
if PanelFMCTCSS <> nil then DP(PanelFMCTCSS);
|
||||
if PanelFMCTCSSPop <> nil then DP(PanelFMCTCSSPop);
|
||||
DP(PanelRX); DP(PanelTX);
|
||||
DP(PanelRight); DP(PanelSpanButtons);
|
||||
|
||||
@@ -2262,6 +2398,7 @@ begin
|
||||
// Метки
|
||||
DL(LblAGCTop, False);
|
||||
DL(LblDrv); DL(LblSpan);
|
||||
if LblFMSQ <> nil then DL(LblFMSQ, False);
|
||||
|
||||
// Кнопки тулбара
|
||||
BtnDiscover.ClrNorm := T.TbDiscoverNorm;
|
||||
@@ -2283,6 +2420,12 @@ begin
|
||||
for i := 0 to 4 do StyleButton(BtnAGCMode[i],BtnAGCMode[i].Active);
|
||||
StyleButton(BtnCTun, BtnCTun.Active);
|
||||
StyleButton(BtnDUP, BtnDUP.Active);
|
||||
if BtnFMSQ <> nil then StyleButton(BtnFMSQ, BtnFMSQ.Active);
|
||||
if TrkFMSQ <> nil then DS(TrkFMSQ);
|
||||
if BtnFMCTCSS <> nil then StyleButton(BtnFMCTCSS, BtnFMCTCSS.Active);
|
||||
if BtnFMCTCSSTone <> nil then StyleButton(BtnFMCTCSSTone, False);
|
||||
for i := 0 to CTCSS_COUNT-1 do
|
||||
if FBtnCTCSSTones[i] <> nil then StyleButton(FBtnCTCSSTones[i], FBtnCTCSSTones[i].Active);
|
||||
StyleButton(BtnNR, BtnNR.Active);
|
||||
StyleButton(BtnNB, BtnNB.Active);
|
||||
StyleButton(BtnSNB, BtnSNB.Active);
|
||||
@@ -3511,8 +3654,10 @@ begin
|
||||
BtnNB.Tag := EnsureRange(G_Settings.NBMode, 0, 2); UpdateNBButton;
|
||||
BtnSNB.Tag := Ord(G_Settings.SNBEnabled); UpdateSNBButton;
|
||||
BtnANF.Tag := Ord(G_Settings.ANFEnabled); UpdateANFButton;
|
||||
FWfAGCEnabled := G_Settings.WfAGCEnabled;
|
||||
FWfNFEnabled := G_Settings.WfNFEnabled;
|
||||
FWfAGCEnabled := G_Settings.WfAGCEnabled;
|
||||
FWfNFEnabled := G_Settings.WfNFEnabled;
|
||||
FDitherEnabled := G_Settings.DitherEnabled;
|
||||
FRandomEnabled := G_Settings.RandomEnabled;
|
||||
FWfManualHigh := G_Settings.WfManualHigh;
|
||||
FWfManualLow := G_Settings.WfManualLow;
|
||||
FWfAGCOffset := G_Settings.WfAGCOffset;
|
||||
@@ -3639,7 +3784,7 @@ begin
|
||||
|
||||
// DDC и DUC Specific — теперь потоки эмулятора слушают на своих портах.
|
||||
// DUC Specific содержит mic-конфигурацию (boost/bias/line/PTT) из FTXSettings.
|
||||
FNetwork.ConfigureDDCs(1, FSampleRate div 1000, 0);
|
||||
FNetwork.ConfigureDDCs(1, FSampleRate div 1000, 0, FDitherEnabled, FRandomEnabled);
|
||||
SendDUCSpecificFromSettings;
|
||||
// Применяем TX-цепь (фильтр, mic gain, EQ, leveler, ALC, comp, ...).
|
||||
ApplyTXSettingsToDSP;
|
||||
@@ -3879,7 +4024,56 @@ var
|
||||
i: Integer;
|
||||
Names: array[0..FILT_COUNT-1] of string;
|
||||
DefIdx: Integer;
|
||||
W: Integer;
|
||||
begin
|
||||
if FMode = MODE_FM then
|
||||
begin
|
||||
// FM: show only NFM and WFM buttons, resize them to fill the row
|
||||
CloseCTCSSPopup;
|
||||
FFilter := FILT_FM_DEF;
|
||||
FFilterBW := FILT_FM_BW[FILT_FM_DEF];
|
||||
FFMDeviation := FILT_FM_DEV[FILT_FM_DEF];
|
||||
W := (PanelFilter.Width - 6) div 2;
|
||||
BtnFilter[0].Caption := FILT_FM_NAMES[0];
|
||||
BtnFilter[0].Left := 2;
|
||||
BtnFilter[0].Width := W - 2;
|
||||
BtnFilter[0].Top := 16;
|
||||
BtnFilter[0].Visible := True;
|
||||
StyleButton(BtnFilter[0], FFilter = 0);
|
||||
BtnFilter[1].Caption := FILT_FM_NAMES[1];
|
||||
BtnFilter[1].Left := W + 2;
|
||||
BtnFilter[1].Width := W - 2;
|
||||
BtnFilter[1].Top := 16;
|
||||
BtnFilter[1].Visible := True;
|
||||
StyleButton(BtnFilter[1], FFilter = 1);
|
||||
for i := 2 to FILT_COUNT - 1 do BtnFilter[i].Visible := False;
|
||||
// Shrink panel to fit label + 1 button row so SQL/CTCSS sit right below
|
||||
PanelFilter.Height := BtnFilter[0].Top + BtnFilter[0].Height + 4;
|
||||
if PanelFMSQ <> nil then
|
||||
begin
|
||||
PanelFMSQ.Visible := True;
|
||||
StyleButton(BtnFMSQ, FFMSQOn);
|
||||
TrkFMSQ.Position := FFMSQLevel;
|
||||
LblFMSQ.Caption := IntToStr(FFMSQLevel);
|
||||
end;
|
||||
if PanelFMCTCSS <> nil then PanelFMCTCSS.Visible := True;
|
||||
RelayoutBelowBands;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// Non-FM: restore full 2-row height and 5-column layout, hide FM panels
|
||||
PanelFilter.Height := 74;
|
||||
if PanelFMSQ <> nil then PanelFMSQ.Visible := False;
|
||||
if PanelFMCTCSS <> nil then PanelFMCTCSS.Visible := False;
|
||||
W := (PanelFilter.Width - 6) div 5;
|
||||
for i := 0 to FILT_COUNT - 1 do
|
||||
begin
|
||||
BtnFilter[i].Left := 2 + (i mod 5) * W;
|
||||
BtnFilter[i].Top := 16 + (i div 5) * 27;
|
||||
BtnFilter[i].Width := W - 2;
|
||||
BtnFilter[i].Visible := True;
|
||||
end;
|
||||
|
||||
case FMode of
|
||||
0, 1: begin
|
||||
for i := 0 to FILT_COUNT-1 do Names[i] := FILT_SSB_NAMES[i];
|
||||
@@ -3889,10 +4083,6 @@ begin
|
||||
for i := 0 to FILT_COUNT-1 do Names[i] := FILT_CW_NAMES[i];
|
||||
DefIdx := FILT_CW_DEF;
|
||||
end;
|
||||
5: begin
|
||||
for i := 0 to FILT_COUNT-1 do Names[i] := FILT_FM_NAMES[i];
|
||||
DefIdx := FILT_FM_DEF;
|
||||
end;
|
||||
else begin
|
||||
for i := 0 to FILT_COUNT-1 do Names[i] := FILT_AM_NAMES[i];
|
||||
DefIdx := FILT_AM_DEF;
|
||||
@@ -3903,7 +4093,6 @@ begin
|
||||
case FMode of
|
||||
0, 1: FFilterBW := FILT_SSB_BW[DefIdx];
|
||||
3, 4: FFilterBW := FILT_CW_BW[DefIdx];
|
||||
5: FFilterBW := FILT_FM_BW[DefIdx];
|
||||
else FFilterBW := FILT_AM_BW[DefIdx];
|
||||
end;
|
||||
|
||||
@@ -3912,6 +4101,7 @@ begin
|
||||
BtnFilter[i].Caption := Names[i];
|
||||
StyleButton(BtnFilter[i], i = FFilter);
|
||||
end;
|
||||
RelayoutBelowBands;
|
||||
end;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -4398,7 +4588,7 @@ var
|
||||
begin
|
||||
Half := FFilterBW div 2;
|
||||
case FMode of
|
||||
0: begin Lo := -FFilterBW; Hi := -100; end; // LSB: верхний срез -100 Гц
|
||||
0: begin Lo := -FFilterBW; Hi := -100; end; // LSB
|
||||
1: begin Lo := 100; Hi := FFilterBW; end; // USB
|
||||
2: begin Lo := -Half; Hi := Half; end; // DSB
|
||||
3: begin Lo := -Half; Hi := Half; end; // CWL
|
||||
@@ -4408,9 +4598,19 @@ begin
|
||||
7: begin Lo := -Half; Hi := Half; end; // SAM
|
||||
else Lo := -Half; Hi := Half;
|
||||
end;
|
||||
if FWDSPReady then begin
|
||||
if FWDSPReady then
|
||||
begin
|
||||
FDSPEngine.SetFilter(Lo, Hi);
|
||||
FDSPEngine.SetTXFilter(Lo, Hi);
|
||||
if FMode = MODE_FM then
|
||||
begin
|
||||
FDSPEngine.SetRXFMDeviation(FFMDeviation);
|
||||
FDSPEngine.SetTXFMParams(FFMDeviation, FTXSettings.FMLowCut,
|
||||
FTXSettings.FMHighCut, FTXSettings.FMEmphPosition);
|
||||
FDSPEngine.SetFMSquelch(FFMSQOn, FFMSQLevel);
|
||||
end
|
||||
else
|
||||
FDSPEngine.SetFMSquelch(False, 0);
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -4439,18 +4639,109 @@ var
|
||||
begin
|
||||
N := (Sender as TFlatButton).Tag;
|
||||
FFilter := N;
|
||||
// Устанавливаем полосу по текущему режиму
|
||||
case FMode of
|
||||
0, 1: FFilterBW := FILT_SSB_BW[N];
|
||||
3, 4: FFilterBW := FILT_CW_BW[N];
|
||||
5: FFilterBW := FILT_FM_BW[N];
|
||||
else FFilterBW := FILT_AM_BW[N]; // DSB, AM, SAM
|
||||
0, 1: FFilterBW := FILT_SSB_BW[N];
|
||||
3, 4: FFilterBW := FILT_CW_BW[N];
|
||||
5: begin
|
||||
FFilterBW := FILT_FM_BW[N];
|
||||
FFMDeviation := FILT_FM_DEV[N];
|
||||
end;
|
||||
else FFilterBW := FILT_AM_BW[N];
|
||||
end;
|
||||
for i := 0 to FILT_COUNT - 1 do StyleButton(BtnFilter[i], i = FFilter);
|
||||
ApplyModeFilter;
|
||||
SyncSpecViewFreq;
|
||||
end;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FM CTCSS helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
procedure TMainForm.ApplyFMSquelch;
|
||||
begin
|
||||
if FWDSPReady then
|
||||
FDSPEngine.SetFMSquelch(FFMSQOn and (FMode = MODE_FM), FFMSQLevel);
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnFMSQClick(Sender: TObject);
|
||||
begin
|
||||
FFMSQOn := not FFMSQOn;
|
||||
StyleButton(BtnFMSQ, FFMSQOn);
|
||||
BtnFMSQ.Repaint;
|
||||
ApplyFMSquelch;
|
||||
SaveCurrentBand;
|
||||
end;
|
||||
|
||||
procedure TMainForm.TrkFMSQChange(Sender: TObject);
|
||||
begin
|
||||
FFMSQLevel := TrkFMSQ.Position;
|
||||
if LblFMSQ <> nil then LblFMSQ.Caption := IntToStr(FFMSQLevel);
|
||||
ApplyFMSquelch;
|
||||
SaveCurrentBand;
|
||||
end;
|
||||
|
||||
procedure TMainForm.CloseCTCSSPopup;
|
||||
begin
|
||||
if (PanelFMCTCSSPop <> nil) and PanelFMCTCSSPop.Visible then
|
||||
PanelFMCTCSSPop.Visible := False;
|
||||
end;
|
||||
|
||||
procedure TMainForm.SetFMCTCSSTone(Idx: Integer);
|
||||
var
|
||||
OldIdx: Integer;
|
||||
begin
|
||||
OldIdx := FFMCTCSSToneIdx;
|
||||
FFMCTCSSToneIdx := Idx;
|
||||
if BtnFMCTCSSTone <> nil then
|
||||
begin
|
||||
BtnFMCTCSSTone.Caption := CTCSS_NAMES[Idx];
|
||||
BtnFMCTCSSTone.Invalidate;
|
||||
end;
|
||||
// Only flip Active on the two affected buttons — avoids 38× StyleButton/font overhead
|
||||
if (OldIdx <> Idx) and (FBtnCTCSSTones[OldIdx] <> nil) then
|
||||
FBtnCTCSSTones[OldIdx].Active := False;
|
||||
if FBtnCTCSSTones[Idx] <> nil then
|
||||
FBtnCTCSSTones[Idx].Active := True;
|
||||
if FWDSPReady then
|
||||
FDSPEngine.SetTXCTCSS(FFMCTCSSOn, CTCSS_TONES[Idx]);
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnFMCTCSSClick(Sender: TObject);
|
||||
begin
|
||||
FFMCTCSSOn := not FFMCTCSSOn;
|
||||
StyleButton(BtnFMCTCSS, FFMCTCSSOn);
|
||||
BtnFMCTCSS.Repaint; // Flush visual state before WDSP call
|
||||
if FWDSPReady then
|
||||
FDSPEngine.SetTXCTCSS(FFMCTCSSOn, CTCSS_TONES[FFMCTCSSToneIdx]);
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnFMCTCSSToneClick(Sender: TObject);
|
||||
var
|
||||
Y0: Integer;
|
||||
begin
|
||||
// Toggle the dropdown
|
||||
if PanelFMCTCSSPop.Visible then
|
||||
begin
|
||||
CloseCTCSSPopup;
|
||||
Exit;
|
||||
end;
|
||||
// Position below the CTCSS panel, or above if no room
|
||||
Y0 := PanelFMCTCSS.Top + PanelFMCTCSS.Height + 2;
|
||||
if Y0 + PanelFMCTCSSPop.Height > PanelLeft.ClientHeight then
|
||||
Y0 := PanelFMCTCSS.Top - PanelFMCTCSSPop.Height - 2;
|
||||
if Y0 < 0 then Y0 := 0;
|
||||
PanelFMCTCSSPop.Top := Y0;
|
||||
PanelFMCTCSSPop.Left := 0;
|
||||
PanelFMCTCSSPop.BringToFront;
|
||||
PanelFMCTCSSPop.Visible := True;
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnFMToneSelectClick(Sender: TObject);
|
||||
begin
|
||||
CloseCTCSSPopup;
|
||||
SetFMCTCSSTone((Sender as TFlatButton).Tag);
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnVfoSwapClick(Sender: TObject);
|
||||
var
|
||||
Tmp: Double;
|
||||
@@ -4730,6 +5021,35 @@ begin
|
||||
FSpecView.WfNFEnabled := FWfNFEnabled;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyADCSettings(Dither, Random: Boolean);
|
||||
begin
|
||||
FDitherEnabled := Dither;
|
||||
FRandomEnabled := Random;
|
||||
if FNetwork.Connected and FRunning then
|
||||
FNetwork.ConfigureDDCs(1, FSampleRate div 1000, 0, FDitherEnabled, FRandomEnabled);
|
||||
if FDevConnected then
|
||||
FSettings.SaveGlobal(FDevMAC, MakeGlobalSettings);
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyWebSettings(Enabled: Boolean; Port: Integer;
|
||||
const BindAddr, User, Pass: string);
|
||||
var W: TWebSettings;
|
||||
begin
|
||||
FWebEnabled := Enabled;
|
||||
FWebPort := Port;
|
||||
FWebBindAddr := BindAddr;
|
||||
FWebUser := User;
|
||||
FWebPass := Pass;
|
||||
FWebServer.Reconfigure(User, Pass, BindAddr, Word(Port));
|
||||
if Enabled then FWebServer.Start;
|
||||
W.Enabled := Enabled;
|
||||
W.Port := Port;
|
||||
W.BindAddr := BindAddr;
|
||||
W.User := User;
|
||||
W.Pass := Pass;
|
||||
FSettings.SaveWebSettings(W);
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnHidePanelClick(Sender: TObject);
|
||||
begin
|
||||
FPanelHidden := not FPanelHidden;
|
||||
@@ -4831,7 +5151,7 @@ begin
|
||||
// 2. Отправляем новый rate трансиверу
|
||||
// (после остановки DSP — новые пакеты сразу идут с правильным rate)
|
||||
if FNetwork.Connected then
|
||||
FNetwork.ConfigureDDCs(1, DDCRate, 0);
|
||||
FNetwork.ConfigureDDCs(1, DDCRate, 0, FDitherEnabled, FRandomEnabled);
|
||||
|
||||
// 3. Восстанавливаем настройки DSP
|
||||
FWDSPReady := FDSPEngine.Initialized;
|
||||
@@ -5626,6 +5946,14 @@ begin
|
||||
Y := PanelBands.Top + PanelBands.Height + 2;
|
||||
PanelMode.Top := Y; Y := Y + PanelMode.Height + 2;
|
||||
PanelFilter.Top := Y; Y := Y + PanelFilter.Height + 2;
|
||||
if (PanelFMSQ <> nil) and PanelFMSQ.Visible then
|
||||
begin
|
||||
PanelFMSQ.Top := Y; Y := Y + PanelFMSQ.Height + 2;
|
||||
end;
|
||||
if (PanelFMCTCSS <> nil) and PanelFMCTCSS.Visible then
|
||||
begin
|
||||
PanelFMCTCSS.Top := Y; Y := Y + PanelFMCTCSS.Height + 2;
|
||||
end;
|
||||
BtnCTun.Top := Y; BtnDUP.Top := Y; Y := Y + BtnCTun.Height + 4;
|
||||
PanelRX.Top := Y;
|
||||
end;
|
||||
@@ -6141,6 +6469,8 @@ begin
|
||||
SF.OnAlexChange := OnAlexSettingsChange;
|
||||
SF.OnXvtrChange := OnXvtrSettingsChange;
|
||||
SF.OnWfAGCNFChange := ApplyWfAGCNF;
|
||||
SF.OnADCChange := ApplyADCSettings;
|
||||
SF.OnWebSettingsChange := ApplyWebSettings;
|
||||
end;
|
||||
SF := TSettingsForm(FSettingsForm);
|
||||
SF.LoadTXSettings(FTXSettings);
|
||||
@@ -6161,6 +6491,8 @@ begin
|
||||
SF.RefreshAudioDevices(FAudioOut, FAudioIn);
|
||||
SF.LoadVisibility(FShowSpectrum, FShowWaterfall);
|
||||
SF.LoadWfAGCNF(FWfAGCEnabled, FWfNFEnabled);
|
||||
SF.LoadADCSettings(FDitherEnabled, FRandomEnabled);
|
||||
SF.LoadWebSettings(FWebEnabled, FWebPort, FWebBindAddr, FWebUser, FWebPass);
|
||||
SF.LoadFPS(FDisplayFPS);
|
||||
SF.LoadLightTheme(FLightTheme);
|
||||
SF.LoadFreqMhzDigits(FFreqMhzDigits);
|
||||
|
||||
Reference in New Issue
Block a user