mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
WebOnMic only feeds TX mic samples to the controller's WDSP engine (no UI, thread-safe like the other engine data callbacks), so it moves verbatim into TWebAdapter.OnMic. FWebServer.OnWebMic now points there. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
286 lines
10 KiB
ObjectPascal
286 lines
10 KiB
ObjectPascal
unit WebAdapter;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
// Адаптер веб-интерфейса: мост между TWebServer (входящие команды из WS-потока)
|
|
// и TRadioController (ядро). Раньше эти WebOnXxx/SyncWebXxx жили в TMainForm —
|
|
// вынесены сюда, чтобы развязать UI от веба и подготовить headless-демон.
|
|
//
|
|
// Маршалинг: входящие команды приходят из потока веб-сервера; выполняем их в
|
|
// потоке контроллера через FController.Invoke (GUI = TThread.Synchronize; демон
|
|
// подставит свою очередь). Synchronize блокирующий и последовательный — поля
|
|
// FSync* для передачи параметров безопасны (гонок нет).
|
|
//
|
|
// Часть команд (тюнинг VFO/диапазон/MOX/...) идёт через UI-обёртки MainForm,
|
|
// которые ещё не headless — для них есть IWebHost (его реализует хозяин). По мере
|
|
// переноса оркестрации в контроллер интерфейс будет сужаться.
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,
|
|
RadioController, WebServer, WDSPEngine;
|
|
|
|
type
|
|
// UI/оркестрационные операции, которые адаптер дёргает у хозяина (пока не
|
|
// headless — десктоп: методы MainForm; демон: своя реализация). Наполняется
|
|
// в WA2 по мере переноса host-зависимых хендлеров.
|
|
IWebHost = interface
|
|
['{B3A1F7C2-9D54-4E18-9C6B-2E5A7F0D1A33}']
|
|
end;
|
|
|
|
{ TWebAdapter }
|
|
TWebAdapter = class
|
|
private
|
|
FController: TRadioController;
|
|
FServer: TWebServer;
|
|
FHost: IWebHost;
|
|
// Поля для передачи параметров команды в Sync-метод (через Invoke).
|
|
FSyncInt: Integer;
|
|
FSyncBool: Boolean;
|
|
FSyncFreq: Double;
|
|
// Sync-методы (выполняются в потоке контроллера через Invoke).
|
|
procedure SyncMode;
|
|
procedure SyncFilter;
|
|
procedure SyncAGC;
|
|
procedure SyncAGCTop;
|
|
procedure SyncVolume;
|
|
procedure SyncWfAGC;
|
|
procedure SyncWfNF;
|
|
procedure SyncMute;
|
|
procedure SyncNR;
|
|
procedure SyncNB;
|
|
procedure SyncSNB;
|
|
procedure SyncANF;
|
|
procedure SyncFreqB;
|
|
procedure SyncCenter;
|
|
procedure SyncAttn;
|
|
procedure SyncActiveVfo;
|
|
procedure SyncCtun;
|
|
procedure SyncMOX;
|
|
procedure SyncTun;
|
|
procedure SyncFMStep;
|
|
public
|
|
constructor Create(AController: TRadioController; AServer: TWebServer;
|
|
AHost: IWebHost);
|
|
|
|
// Колбэки веб-сервера (навешиваются хозяином на FServer.OnXxx).
|
|
procedure OnMode(Mode: Integer);
|
|
procedure OnFilter(BW: Integer);
|
|
procedure OnAGC(Mode: Integer);
|
|
procedure OnAGCTop(DB: Integer);
|
|
procedure OnVolume(V: Integer);
|
|
procedure OnWfAGC(On_: Boolean);
|
|
procedure OnWfNF(On_: Boolean);
|
|
procedure OnMute(On_: Boolean);
|
|
procedure OnNR(Mode: Integer);
|
|
procedure OnNB(Mode: Integer);
|
|
procedure OnSNB(On_: Boolean);
|
|
procedure OnANF(On_: Boolean);
|
|
procedure OnFreqB(Hz: Double);
|
|
procedure OnCenter(Hz: Double);
|
|
procedure OnAttn(Idx: Integer);
|
|
procedure OnActiveVfo(Idx: Integer);
|
|
procedure OnCtun(On_: Boolean);
|
|
procedure OnMOX(On_: Boolean);
|
|
procedure OnTun(On_: Boolean);
|
|
procedure OnFMStep(Idx: Integer);
|
|
procedure OnClientActiveChanged(Active: Boolean);
|
|
// TX-mic от web-клиента → WDSP. Вызывается из WS-потока; без маршалинга —
|
|
// подача в движок thread-safe (как OnMicPacket/OnDDCIQ контроллера).
|
|
procedure OnMic(Samples: PSingle; Count: Integer);
|
|
end;
|
|
|
|
implementation
|
|
|
|
constructor TWebAdapter.Create(AController: TRadioController;
|
|
AServer: TWebServer; AHost: IWebHost);
|
|
begin
|
|
inherited Create;
|
|
FController := AController;
|
|
FServer := AServer;
|
|
FHost := AHost;
|
|
end;
|
|
|
|
// ── Входящие команды: запоминаем параметр, выполняем в потоке контроллера ─────
|
|
|
|
procedure TWebAdapter.OnMode(Mode: Integer);
|
|
begin FSyncInt := Mode; FController.Invoke(@SyncMode); end;
|
|
|
|
procedure TWebAdapter.SyncMode;
|
|
begin
|
|
if (FSyncInt < 0) or (FSyncInt > MODE_SAM) then Exit;
|
|
FController.SetMode(FSyncInt); // дефолт фильтра + DSP + cache; рендер через rfMode
|
|
end;
|
|
|
|
procedure TWebAdapter.OnFilter(BW: Integer);
|
|
begin FSyncInt := BW; FController.Invoke(@SyncFilter); end;
|
|
|
|
procedure TWebAdapter.SyncFilter;
|
|
begin
|
|
// Web-клиент шлёт полосу в Гц (кнопки панели фильтров = пресетные значения);
|
|
// команда применяет её и подсвечивает ближайший пресет (рендер — rfFilter).
|
|
FController.SetFilterBW(FSyncInt);
|
|
end;
|
|
|
|
procedure TWebAdapter.OnAGC(Mode: Integer);
|
|
begin FSyncInt := Mode; FController.Invoke(@SyncAGC); end;
|
|
|
|
procedure TWebAdapter.SyncAGC;
|
|
begin
|
|
FController.SetAGCMode(FSyncInt); // единый маппинг (исправляет старый web-баг)
|
|
end;
|
|
|
|
procedure TWebAdapter.OnAGCTop(DB: Integer);
|
|
begin FSyncInt := DB; FController.Invoke(@SyncAGCTop); end;
|
|
|
|
procedure TWebAdapter.SyncAGCTop;
|
|
begin
|
|
FController.SetAGCTop(FSyncInt); // клампит, применяет, OnControllerState обновит UI
|
|
end;
|
|
|
|
procedure TWebAdapter.OnVolume(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncVolume); end;
|
|
|
|
procedure TWebAdapter.SyncVolume;
|
|
begin FController.SetVolume(FSyncInt); end;
|
|
|
|
procedure TWebAdapter.OnWfAGC(On_: Boolean);
|
|
begin FSyncBool := On_; FController.Invoke(@SyncWfAGC); end;
|
|
|
|
procedure TWebAdapter.SyncWfAGC;
|
|
begin FController.SetWfAGC(FSyncBool); end;
|
|
|
|
procedure TWebAdapter.OnWfNF(On_: Boolean);
|
|
begin FSyncBool := On_; FController.Invoke(@SyncWfNF); end;
|
|
|
|
procedure TWebAdapter.SyncWfNF;
|
|
begin FController.SetWfNF(FSyncBool); end;
|
|
|
|
procedure TWebAdapter.OnMute(On_: Boolean);
|
|
begin FSyncBool := On_; FController.Invoke(@SyncMute); end;
|
|
|
|
procedure TWebAdapter.SyncMute;
|
|
begin FController.SetMute(FSyncBool); end; // идемпотентно; OnControllerState обновит UI
|
|
|
|
procedure TWebAdapter.OnNR(Mode: Integer);
|
|
begin FSyncInt := Mode; FController.Invoke(@SyncNR); end;
|
|
|
|
procedure TWebAdapter.SyncNR;
|
|
begin FController.SetNR(FSyncInt); end; // клампит и применяет; рендер через rfNR
|
|
|
|
procedure TWebAdapter.OnNB(Mode: Integer);
|
|
begin FSyncInt := Mode; FController.Invoke(@SyncNB); end;
|
|
|
|
procedure TWebAdapter.SyncNB;
|
|
begin FController.SetNB(FSyncInt); end;
|
|
|
|
procedure TWebAdapter.OnSNB(On_: Boolean);
|
|
begin FSyncBool := On_; FController.Invoke(@SyncSNB); end;
|
|
|
|
procedure TWebAdapter.SyncSNB;
|
|
begin FController.SetSNB(FSyncBool); end;
|
|
|
|
procedure TWebAdapter.OnANF(On_: Boolean);
|
|
begin FSyncBool := On_; FController.Invoke(@SyncANF); end;
|
|
|
|
procedure TWebAdapter.SyncANF;
|
|
begin FController.SetANF(FSyncBool); end;
|
|
|
|
procedure TWebAdapter.OnFreqB(Hz: Double);
|
|
begin FSyncFreq := Hz; FController.Invoke(@SyncFreqB); end;
|
|
|
|
procedure TWebAdapter.SyncFreqB;
|
|
begin
|
|
// Унифицировано с десктопом: команда хранит частоту, при активном B
|
|
// перестраивает приёмник (CTUN-aware) + сеть; рендер — через rfVfoB/rfBand.
|
|
FController.SetVfoB(FSyncFreq);
|
|
end;
|
|
|
|
procedure TWebAdapter.OnCenter(Hz: Double);
|
|
begin FSyncFreq := Hz; FController.Invoke(@SyncCenter); end;
|
|
|
|
procedure TWebAdapter.SyncCenter;
|
|
begin
|
|
// Сдвигаем DDC-центр без смены VFO (аналог CTUN-drag в десктопе).
|
|
FController.SetCenter(FSyncFreq);
|
|
end;
|
|
|
|
procedure TWebAdapter.OnAttn(Idx: Integer);
|
|
begin FSyncInt := Idx; FController.Invoke(@SyncAttn); end;
|
|
|
|
procedure TWebAdapter.SyncAttn;
|
|
begin FController.SetAtten(FSyncInt); end;
|
|
|
|
procedure TWebAdapter.OnActiveVfo(Idx: Integer);
|
|
begin FSyncInt := Idx; FController.Invoke(@SyncActiveVfo); end;
|
|
|
|
procedure TWebAdapter.SyncActiveVfo;
|
|
begin
|
|
if (FSyncInt < 0) or (FSyncInt > 1) then Exit;
|
|
if FSyncInt = FController.FActiveVfo then Exit;
|
|
FController.SetActiveVfo(FSyncInt); // перестройка RX-VFO; рендер rfActiveVfo
|
|
end;
|
|
|
|
procedure TWebAdapter.OnCtun(On_: Boolean);
|
|
begin FSyncBool := On_; FController.Invoke(@SyncCtun); end;
|
|
|
|
procedure TWebAdapter.SyncCtun;
|
|
begin
|
|
if FSyncBool <> FController.FCTun then
|
|
FController.SetCTun(FSyncBool); // band cache + center/shift + сеть; рендер rfCTun
|
|
end;
|
|
|
|
procedure TWebAdapter.OnMOX(On_: Boolean);
|
|
begin FSyncBool := On_; FController.Invoke(@SyncMOX); end;
|
|
|
|
procedure TWebAdapter.SyncMOX;
|
|
begin
|
|
// FWebClientActive держится актуальным OnClientActiveChanged — выбор mic-source.
|
|
FController.SetMOX(FSyncBool); // ядро TX (safety/PTT/DSP); рендер rfTransmitting
|
|
end;
|
|
|
|
procedure TWebAdapter.OnTun(On_: Boolean);
|
|
begin FSyncBool := On_; FController.Invoke(@SyncTun); end;
|
|
|
|
procedure TWebAdapter.SyncTun;
|
|
begin
|
|
FController.SetTune(FSyncBool); // ядро TUN (safety/тон/drive/MOX); рендер rfTuning
|
|
end;
|
|
|
|
procedure TWebAdapter.OnFMStep(Idx: Integer);
|
|
begin FSyncInt := Idx; FController.Invoke(@SyncFMStep); end;
|
|
|
|
procedure TWebAdapter.SyncFMStep;
|
|
begin
|
|
FController.SetFMStep(FSyncInt); // клампит 0..3 внутри; рендер rfFMStepIdx
|
|
FController.SaveCurrentBand;
|
|
end;
|
|
|
|
procedure TWebAdapter.OnClientActiveChanged(Active: Boolean);
|
|
// Из потока веб-сервера при connect/disconnect клиента. Простая запись флага —
|
|
// ядро (SetMOX, в т.ч. HWPTT-путь) выбирает по нему mic-source. Без маршалинга.
|
|
begin
|
|
FController.FWebClientActive := Active;
|
|
end;
|
|
|
|
procedure TWebAdapter.OnMic(Samples: PSingle; Count: Integer);
|
|
var
|
|
Buf: array[0..5759] of Double;
|
|
SP: PSingle;
|
|
i, n: Integer;
|
|
begin
|
|
if not FController.FWDSPReady then Exit;
|
|
n := Count;
|
|
if n > Length(Buf) then n := Length(Buf);
|
|
SP := Samples;
|
|
for i := 0 to n - 1 do
|
|
begin
|
|
Buf[i] := SP^;
|
|
Inc(SP);
|
|
end;
|
|
FController.FDSPEngine.PushTXMicSamplesD(Buf, n);
|
|
end;
|
|
|
|
end.
|