Files
ewsdr/WebAdapter.pas
T
Uladzimir KarpenkaandClaude Opus 4.8 2f8b0bdf48 Phase 3 (WA1): extract web adapter into WebAdapter.pas
Move the pure controller-command web handlers out of MainForm into a
new TWebAdapter (bridge between TWebServer and TRadioController),
marshalling via FController.Invoke so it is daemon-ready.

- 20 handlers moved: Mode/Filter/AGC/AGCTop/Volume/WfAGC/WfNF/Mute/
  NR/NB/SNB/ANF/FreqB/Center/Attn/ActiveVfo/Ctun/MOX/Tun/FMStep +
  ClientActiveChanged. Each calls a controller command directly.
- CAT context (Ctx.Set*) and CATSetFilterIdx repointed to the adapter,
  since CAT reuses these as its command layer.
- Host-dependent handlers (Freq/Band/XvtrBand/Span/Run/Drive/connect/
  disconnect/CRUD/mic) and the outgoing PushSpectrum mirror stay in
  MainForm for now (WA2/WA3); IWebHost is the placeholder seam.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 16:03:49 +03:00

265 lines
9.5 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);
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;
end.