mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
feat: QO-100 beacon lock in web UI + headless daemon
Mirror the desktop QO-100 beacon lock into the web interface and make it work in the headless daemon. Backend: - WebServer: set_beacon/beacon_seed commands (+OnBeacon/OnBeaconSeed events), beacon state fields, SetBeaconStatus, and beacon_visible/on/ text/ref_hz/track_hz in BuildStateJson. beacon_seed carries 'frac' (0..1 click position); absolute Hz is computed controller-side from live FCenterFreq/FSpanHz (mirrors desktop PixelToFreq). - WebAdapter: OnBeacon->SetBeaconLock, OnBeaconSeed->BeaconSeedAtHz; PushState mirrors compact status (matches MainForm.BeaconStatusText) into the PLL status cell when visible (Pluto + active XVTR). - MainForm/ewsdrd: wire the two callbacks. - ewsdrd: call ServiceBeaconLock in the main loop @~10Hz (FRunning+ FWDSPReady gated). Without this the lock loop never ran headless. Frontend (WebPageHtml): - BCN button (visible only on Pluto+XVTR), highlighted while locked. - Seed-on-mousedown with immediate return (like desktop FormMouseDown): no drag/set_center so the gesture never moves the center / tears IQ. Armed (first click after BCN) or Shift, mirroring desktop arm/Shift. - PLL status cell shows beacon status (field-7 parity with desktop). - Ref (green) + tracked (orange) beacon markers on spectrum/waterfall. Known issue (unresolved): after lock the beacon can slowly drift off and drop to "BCN sync". Suspected residual-sign anti-drift or retune-timing on the web/daemon path; needs on-air diagnostics. See memory project_web_beacon for the investigation state. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -66,6 +66,9 @@ type
|
||||
procedure SyncMOX;
|
||||
procedure SyncTun;
|
||||
procedure SyncFMStep;
|
||||
procedure SyncBeacon;
|
||||
procedure SyncBeaconSeed;
|
||||
function BeaconStatusText: string; // компактный статус (как десктоп поле 7)
|
||||
public
|
||||
constructor Create(AController: TRadioController; AServer: TWebServer;
|
||||
AHost: IWebHost);
|
||||
@@ -97,6 +100,9 @@ type
|
||||
procedure OnMOX(On_: Boolean);
|
||||
procedure OnTun(On_: Boolean);
|
||||
procedure OnFMStep(Idx: Integer);
|
||||
// QO-100 beacon: вкл/выкл лок и наведение по клику в спектре (frac 0..1).
|
||||
procedure OnBeacon(On_: Boolean);
|
||||
procedure OnBeaconSeed(Frac: Double);
|
||||
procedure OnClientActiveChanged(Active: Boolean);
|
||||
// TX-mic от web-клиента → WDSP. Вызывается из WS-потока; без маршалинга —
|
||||
// подача в движок thread-safe (как OnMicPacket/OnDDCIQ контроллера).
|
||||
@@ -344,6 +350,29 @@ begin
|
||||
FController.SaveCurrentBand;
|
||||
end;
|
||||
|
||||
procedure TWebAdapter.OnBeacon(On_: Boolean);
|
||||
begin FSyncBool := On_; FController.Invoke(@SyncBeacon); end;
|
||||
|
||||
procedure TWebAdapter.SyncBeacon;
|
||||
begin
|
||||
// Вкл/выкл лок маяка (= запуск декодера + трим LOError). Идемпотентно.
|
||||
FController.SetBeaconLock(FSyncBool);
|
||||
end;
|
||||
|
||||
procedure TWebAdapter.OnBeaconSeed(Frac: Double);
|
||||
begin FSyncFreq := Frac; FController.Invoke(@SyncBeaconSeed); end;
|
||||
|
||||
procedure TWebAdapter.SyncBeaconSeed;
|
||||
var Hz: Double;
|
||||
begin
|
||||
// Frac (доля 0..1 по ширине спектра) → абс. display-Hz от ЖИВЫХ центра/спана
|
||||
// контроллера (зеркалит десктоп PixelToFreq(X,W,FCenterFreq,FSpanHz)). Так
|
||||
// наведение точно, даже когда LO ретюнится локом и клиентский center отстаёт.
|
||||
if (FSyncFreq < 0) or (FSyncFreq > 1) then Exit;
|
||||
Hz := FController.FCenterFreq + (FSyncFreq - 0.5) * FController.FSpanHz;
|
||||
FController.BeaconSeedAtHz(Hz);
|
||||
end;
|
||||
|
||||
procedure TWebAdapter.OnClientActiveChanged(Active: Boolean);
|
||||
// Из потока веб-сервера при connect/disconnect клиента. Простая запись флага —
|
||||
// ядро (SetMOX, в т.ч. HWPTT-путь) выбирает по нему mic-source. Без маршалинга.
|
||||
@@ -387,6 +416,19 @@ end;
|
||||
|
||||
// ── Исходящее зеркало состояния ──────────────────────────────────────────────
|
||||
|
||||
function TWebAdapter.BeaconStatusText: string;
|
||||
// Зеркалит TMainForm.BeaconStatusText (поле 7 десктопа). Pluto в трансвертере.
|
||||
begin
|
||||
if not FController.BeaconLockEnabled then Exit('BCN: off');
|
||||
if FController.BeaconDecodeFreqHz <= 0 then Exit('BCN: click beacon');
|
||||
case FController.BeaconState of
|
||||
bsLock: Result := Format('BCN LOCK %.0fHz /%.0fdB',
|
||||
[FController.BeaconCorrectionHz, FController.BeaconSNRdB]);
|
||||
bsSearch: Result := Format('BCN sync /%.0fdB', [FController.BeaconSNRdB]);
|
||||
else Result := 'BCN --';
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TWebAdapter.PushState;
|
||||
var
|
||||
StatusText, BoardText, IPText, SupplyText: string;
|
||||
@@ -456,6 +498,14 @@ begin
|
||||
else
|
||||
SeqText := 'SEQ --';
|
||||
|
||||
// QO-100 beacon lock — отдельный канал состояния (видим только на Pluto в XVTR).
|
||||
FServer.SetBeaconStatus(
|
||||
FController.IsPluto and (FController.FCurrentXvtr >= 0),
|
||||
FController.BeaconLockEnabled,
|
||||
BeaconStatusText,
|
||||
FController.BeaconRefHz,
|
||||
FController.BeaconTrackedFreqHz);
|
||||
|
||||
FServer.PushSpectrum(
|
||||
FController.FSpectrumBuf, 1024,
|
||||
FController.FWaterfallBuf,
|
||||
|
||||
Reference in New Issue
Block a user