mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Phase 5 (batch 25b): move HP-status callback into the controller
OnHPStatusCB + DoUpdateStatus move into TRadioController as OnHPStatus (network thread: board-specific supply/power/SWR decode -> pending fields -> Invoke) and ApplyHPStatus (marshalled: PEP-style fwd/SWR ballistics + supply EMA into FLast*, ADC-overload via Changed(rfADCOverload), and the HW-PTT edge -> SetMOX). FNetwork.OnHPStatus is wired to the controller; the ADC-overload indicator renders via OnControllerState(rfADCOverload). The HWPTT->TX path is now headless-capable and reads an always-current FWebClientActive for mic-source. TStatusUISync is left dead in UISync.pas (unit still used for TDDCSeqSync) pending a separate cleanup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9d2324cc6c
commit
c1da506f73
@@ -69,6 +69,7 @@ type
|
||||
rfFMStep, rfFMStepIdx, rfFMRpt,
|
||||
rfChannel,
|
||||
rfSMeter, rfPower, rfSWR, rfSupply, rfPLL, // телеметрия
|
||||
rfADCOverload, // ADC overload (рендер индикатора)
|
||||
rfDevice // подключённое устройство сменилось
|
||||
);
|
||||
|
||||
@@ -213,6 +214,12 @@ type
|
||||
FLastSeqErrorDDC: Integer;
|
||||
FLastSeqErrorDelta: Int64;
|
||||
FSeqOkStreak: Integer;
|
||||
FADCOverloadActive: Boolean; // ADC overload (рендерится по rfADCOverload)
|
||||
// Pending-значения декода HP-статуса (сетевой поток → ApplyHPStatus через
|
||||
// Invoke; Synchronize блокирующий и последовательный, гонок нет).
|
||||
FHPpFwdW, FHPpSWR, FHPpSupplyV, FHPpSupplyA: Double;
|
||||
FHPpPLL, FHPpHWPTT: Boolean;
|
||||
FHPpOverload: Byte;
|
||||
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
@@ -230,6 +237,8 @@ type
|
||||
procedure OnMicPacket(const Data: TMicDataPacket);
|
||||
function PullSoundCardMic(MaxN: Integer): Integer;
|
||||
procedure OnDDCIQ(DDCIndex: Integer; const Data: TDDCIQPacket);
|
||||
procedure OnHPStatus(const Status: THighPriorityStatus);
|
||||
procedure ApplyHPStatus; // маршалится из OnHPStatus (сглаживание/overload/HWPTT)
|
||||
|
||||
// Маршалинг команды в поток контроллера (GUI: TThread.Synchronize).
|
||||
procedure Invoke(M: TThreadMethod);
|
||||
@@ -499,6 +508,142 @@ begin
|
||||
FLastDDCIndex := DDCIndex;
|
||||
end;
|
||||
|
||||
procedure TRadioController.OnHPStatus(const Status: THighPriorityStatus);
|
||||
// Сетевой поток: декод HP-статуса (board-specific supply/power/SWR) → pending →
|
||||
// маршалинг в ApplyHPStatus (сглаживание + overload + HWPTT уже на потоке UI/ядра).
|
||||
const
|
||||
SWR_MIN_FWD_W = 1.0; // ниже — fwd это ADC-шум, SWR не считаем
|
||||
SWR_CAP = 9.9;
|
||||
var
|
||||
FwdPwr, RevPwr: Word;
|
||||
SupplyV, SupplyA, FwdW, SWRV, Rho: Double;
|
||||
IsTx: Boolean;
|
||||
begin
|
||||
FwdPwr := (Status.FwdPwrAlex0Hi shl 8) or Status.FwdPwrAlex0Lo;
|
||||
RevPwr := (Status.RevPwrAlex0Hi shl 8) or Status.RevPwrAlex0Lo;
|
||||
SupplyV := -1.0;
|
||||
SupplyA := -1.0;
|
||||
|
||||
// Board 5 (Orion MkII): напряжение на UserADC0, ток на UserADC1 (как Thetis).
|
||||
// Прочие платы — в SupplyVolts-байтах, без тока.
|
||||
if BoardSupportsSupplyVoltage(FNetwork.Device.BoardType) then
|
||||
begin
|
||||
if FNetwork.Device.BoardType = 5 then
|
||||
SupplyV := ADCToSupplyVolts(
|
||||
(Status.UserADC0Hi shl 8) or Status.UserADC0Lo,
|
||||
FNetwork.Device.BoardType)
|
||||
else
|
||||
SupplyV := ADCToSupplyVolts(
|
||||
(Status.SupplyVoltsHi shl 8) or Status.SupplyVoltsLo,
|
||||
FNetwork.Device.BoardType);
|
||||
|
||||
if BoardSupportsSupplyCurrent(FNetwork.Device.BoardType) then
|
||||
SupplyA := ADCToSupplyCurrent(
|
||||
(Status.UserADC1Hi shl 8) or Status.UserADC1Lo,
|
||||
FNetwork.Device.BoardType);
|
||||
end;
|
||||
FwdW := ADCToWatts100(FwdPwr);
|
||||
// FTransmitting — программный флаг; HPS_PTT — вход HW-PTT (footswitch/mic).
|
||||
IsTx := FTransmitting or ((Status.StatusBits and HPS_PTT) <> 0);
|
||||
// SWR = (1+ρ)/(1-ρ), ρ = adc_r/adc_f; только при значимой fwd-мощности.
|
||||
if IsTx and (FwdW >= SWR_MIN_FWD_W) and (FwdPwr > 0) then
|
||||
begin
|
||||
Rho := RevPwr / FwdPwr;
|
||||
if Rho >= 0.99 then
|
||||
SWRV := SWR_CAP
|
||||
else
|
||||
begin
|
||||
SWRV := (1.0 + Rho) / (1.0 - Rho);
|
||||
if SWRV > SWR_CAP then SWRV := SWR_CAP;
|
||||
if SWRV < 1.0 then SWRV := 1.0;
|
||||
end;
|
||||
end else
|
||||
SWRV := 1.0;
|
||||
if not IsTx then FwdW := 0;
|
||||
|
||||
FHPpFwdW := FwdW;
|
||||
FHPpSWR := SWRV;
|
||||
FHPpSupplyV := SupplyV;
|
||||
FHPpSupplyA := SupplyA;
|
||||
FHPpPLL := (Status.StatusBits and HPS_PLL_LOCKED) <> 0;
|
||||
FHPpHWPTT := (Status.StatusBits and HPS_PTT) <> 0;
|
||||
FHPpOverload := Status.ADCOverload;
|
||||
Invoke(ApplyHPStatus);
|
||||
end;
|
||||
|
||||
procedure TRadioController.ApplyHPStatus;
|
||||
// Маршалится из OnHPStatus. PEP-style баллистика (мгновенная атака, медленный
|
||||
// спад) для FwdW/SWR; EMA для supply. + overload-событие + HWPTT-фронт → SetMOX.
|
||||
const
|
||||
DECAY_FWD = 0.02;
|
||||
DECAY_SWR = 0.015;
|
||||
ALPHA_SUPPLY = 0.05;
|
||||
begin
|
||||
if FHPpFwdW <= 0 then
|
||||
FLastFwdW := 0
|
||||
else if FHPpFwdW > FLastFwdW then
|
||||
FLastFwdW := FHPpFwdW // attack: instant
|
||||
else
|
||||
FLastFwdW := DECAY_FWD * FHPpFwdW + (1.0 - DECAY_FWD) * FLastFwdW;
|
||||
if FHPpSWR <= 1.0 then
|
||||
FLastSWR := 1.0
|
||||
else if FHPpSWR > FLastSWR then
|
||||
FLastSWR := FHPpSWR // attack: instant
|
||||
else
|
||||
FLastSWR := DECAY_SWR * FHPpSWR + (1.0 - DECAY_SWR) * FLastSWR;
|
||||
if FHPpSupplyV >= 0 then
|
||||
begin
|
||||
if FLastSupplyV < 0 then
|
||||
FLastSupplyV := FHPpSupplyV // первое значение — без сглаживания
|
||||
else
|
||||
FLastSupplyV := ALPHA_SUPPLY * FHPpSupplyV + (1.0 - ALPHA_SUPPLY) * FLastSupplyV;
|
||||
end else
|
||||
FLastSupplyV := -1.0;
|
||||
if FHPpSupplyA >= 0 then
|
||||
begin
|
||||
if FLastSupplyA < 0 then
|
||||
FLastSupplyA := FHPpSupplyA
|
||||
else
|
||||
FLastSupplyA := ALPHA_SUPPLY * FHPpSupplyA + (1.0 - ALPHA_SUPPLY) * FLastSupplyA;
|
||||
end else
|
||||
FLastSupplyA := -1.0;
|
||||
FLastPLLLock := FHPpPLL;
|
||||
|
||||
// ADC overload — индикатор рисует UI по rfADCOverload (только на изменении).
|
||||
if FADCOverloadActive <> (FHPpOverload <> 0) then
|
||||
begin
|
||||
FADCOverloadActive := FHPpOverload <> 0;
|
||||
Changed(rfADCOverload);
|
||||
end;
|
||||
|
||||
// Hardware PTT (footswitch / mic PTT): фронт на rate HP Status — не пропустить
|
||||
// короткое нажатие. HWPTT не перекрывает ручной MOX; выключаем TX только если
|
||||
// его включил именно HWPTT.
|
||||
if FHPpHWPTT <> FHWPTTActive then
|
||||
begin
|
||||
FHWPTTActive := FHPpHWPTT;
|
||||
if not FTuning then
|
||||
begin
|
||||
if FHPpHWPTT then
|
||||
begin
|
||||
if not FTransmitting then
|
||||
begin
|
||||
SetMOX(True);
|
||||
FHWPTTStartedTX := True;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if FHWPTTStartedTX then
|
||||
begin
|
||||
FHWPTTStartedTX := False;
|
||||
SetMOX(False);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TRadioController.OnMicPacket(const Data: TMicDataPacket);
|
||||
// HW mic-стрим уходит в WDSP только если выбран источник Radio; иначе сэмплы
|
||||
// игнорируются (mic берётся со звуковой карты).
|
||||
|
||||
Reference in New Issue
Block a user