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:
+57
-6
@@ -181,6 +181,9 @@ type
|
||||
|
||||
// ── Авторизация ──
|
||||
FAuthToken: string; // Base64(user:pass)
|
||||
// ── Сетевая конфигурация ──
|
||||
FPort: Word;
|
||||
FBindIP: string;
|
||||
|
||||
// ── Состояние (обновляется из MainForm) ──
|
||||
FSpectrumBuf: array[0..1023] of Single;
|
||||
@@ -272,11 +275,13 @@ type
|
||||
procedure ProcessWsFrame(Client: TWsClient; const Data: array of Byte; Len: Integer; Opcode: Byte);
|
||||
|
||||
public
|
||||
constructor Create(const Username, Password: string);
|
||||
constructor Create(const Username, Password: string;
|
||||
Port: Word = 8080; const BindIP: string = '0.0.0.0');
|
||||
destructor Destroy; override;
|
||||
|
||||
function Start: Boolean;
|
||||
procedure Stop;
|
||||
procedure Reconfigure(const Username, Password, BindIP: string; Port: Word);
|
||||
|
||||
// Вызывается из DSP-потока (аудио, 48kHz mono)
|
||||
procedure PushAudio(const Samples: PSingle; Count: Integer);
|
||||
@@ -396,7 +401,8 @@ end;
|
||||
TWebServer — конструктор / деструктор
|
||||
═══════════════════════════════════════════════════════════════════════════ }
|
||||
|
||||
constructor TWebServer.Create(const Username, Password: string);
|
||||
constructor TWebServer.Create(const Username, Password: string;
|
||||
Port: Word; const BindIP: string);
|
||||
{$IFDEF WINDOWS}
|
||||
var
|
||||
WSAData: TWSAData;
|
||||
@@ -408,6 +414,8 @@ begin
|
||||
{$ENDIF}
|
||||
inherited Create;
|
||||
FAuthToken := Base64EncodeStr(Username + ':' + Password);
|
||||
FPort := Port;
|
||||
FBindIP := BindIP;
|
||||
FListenSock := SOCK_INVALID;
|
||||
FRunning := False;
|
||||
FClientCount := 0;
|
||||
@@ -531,6 +539,41 @@ end;
|
||||
Start / Stop
|
||||
═══════════════════════════════════════════════════════════════════════════ }
|
||||
|
||||
function ParseIPv4(const S: string): LongWord;
|
||||
// Парсит dotted-decimal '1.2.3.4', возвращает сетевой порядок байт.
|
||||
// '0.0.0.0' и '' → INADDR_ANY (0).
|
||||
var
|
||||
P, Start: PChar;
|
||||
Parts: array[0..3] of Byte;
|
||||
Idx, V: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
if (S = '') or (S = '0.0.0.0') then Exit;
|
||||
Idx := 0;
|
||||
P := PChar(S);
|
||||
Start := P;
|
||||
while True do
|
||||
begin
|
||||
if (P^ = '.') or (P^ = #0) then
|
||||
begin
|
||||
if Idx > 3 then Exit;
|
||||
V := StrToIntDef(Copy(S, Start - PChar(S) + 1, P - Start), -1);
|
||||
if (V < 0) or (V > 255) then Exit;
|
||||
Parts[Idx] := Byte(V);
|
||||
Inc(Idx);
|
||||
if P^ = #0 then Break;
|
||||
Inc(P);
|
||||
Start := P;
|
||||
end else
|
||||
Inc(P);
|
||||
end;
|
||||
if Idx <> 4 then Exit;
|
||||
// Сетевой порядок: старший байт первый
|
||||
Result := (LongWord(Parts[0]) shl 24) or (LongWord(Parts[1]) shl 16)
|
||||
or (LongWord(Parts[2]) shl 8) or LongWord(Parts[3]);
|
||||
Result := htonl(Result);
|
||||
end;
|
||||
|
||||
function TWebServer.InitListen: Boolean;
|
||||
var
|
||||
Addr: {$IFDEF WINDOWS}TSockAddrIn{$ELSE}TInetSockAddr{$ENDIF};
|
||||
@@ -549,16 +592,16 @@ begin
|
||||
setsockopt(FListenSock, SOL_SOCKET, SO_REUSEADDR, @One, SizeOf(One));
|
||||
FillChar(Addr, SizeOf(Addr), 0);
|
||||
Addr.sin_family := AF_INET;
|
||||
Addr.sin_port := htons(WEB_PORT);
|
||||
Addr.sin_addr.S_addr := INADDR_ANY;
|
||||
Addr.sin_port := htons(FPort);
|
||||
Addr.sin_addr.S_addr := ParseIPv4(FBindIP);
|
||||
if bind(FListenSock, @Addr, SizeOf(Addr)) = SOCKET_ERROR then Exit;
|
||||
if listen(FListenSock, 5) = SOCKET_ERROR then Exit;
|
||||
{$ELSE}
|
||||
fpSetSockOpt(FListenSock, SOL_SOCKET, SO_REUSEADDR, @One, SizeOf(One));
|
||||
FillChar(Addr, SizeOf(Addr), 0);
|
||||
Addr.sin_family := AF_INET;
|
||||
Addr.sin_port := htons(WEB_PORT);
|
||||
Addr.sin_addr.s_addr := htonl(INADDR_ANY);
|
||||
Addr.sin_port := htons(FPort);
|
||||
Addr.sin_addr.s_addr := ParseIPv4(FBindIP);
|
||||
if fpBind(FListenSock, @Addr, SizeOf(Addr)) <> 0 then Exit;
|
||||
if fpListen(FListenSock, 5) <> 0 then Exit;
|
||||
{$ENDIF}
|
||||
@@ -628,6 +671,14 @@ begin
|
||||
UnloadOpus;
|
||||
end;
|
||||
|
||||
procedure TWebServer.Reconfigure(const Username, Password, BindIP: string; Port: Word);
|
||||
begin
|
||||
Stop;
|
||||
FAuthToken := Base64EncodeStr(Username + ':' + Password);
|
||||
FPort := Port;
|
||||
FBindIP := BindIP;
|
||||
end;
|
||||
|
||||
{ ═══════════════════════════════════════════════════════════════════════════
|
||||
Accept loop
|
||||
═══════════════════════════════════════════════════════════════════════════ }
|
||||
|
||||
Reference in New Issue
Block a user