mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-26 04:47:35 +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
+10
-165
@@ -351,7 +351,6 @@ type
|
|||||||
|
|
||||||
// Network callbacks
|
// Network callbacks
|
||||||
procedure OnDeviceFound(const Dev: THPSDRDevice);
|
procedure OnDeviceFound(const Dev: THPSDRDevice);
|
||||||
procedure OnHPStatusCB(const Status: THighPriorityStatus);
|
|
||||||
procedure OnWidebandCB(ADCIndex: Integer; const Samples: array of SmallInt;
|
procedure OnWidebandCB(ADCIndex: Integer; const Samples: array of SmallInt;
|
||||||
Count: Integer);
|
Count: Integer);
|
||||||
procedure OnWDSPOpenDone(Success: Boolean);
|
procedure OnWDSPOpenDone(Success: Boolean);
|
||||||
@@ -364,8 +363,6 @@ type
|
|||||||
|
|
||||||
// Public UI update (called from sync objects)
|
// Public UI update (called from sync objects)
|
||||||
procedure DoAddDevice(const Dev: THPSDRDevice; const Entry: string);
|
procedure DoAddDevice(const Dev: THPSDRDevice; const Entry: string);
|
||||||
procedure DoUpdateStatus(FwdW, SWRV, SupplyV, SupplyA: Double; PLLLock, HWPTT: Boolean;
|
|
||||||
ADCOverload: Byte);
|
|
||||||
procedure UpdateTXMeters;
|
procedure UpdateTXMeters;
|
||||||
procedure DoUpdateDDCSeq(DDCIdx: Integer; Seq: LongWord);
|
procedure DoUpdateDDCSeq(DDCIdx: Integer; Seq: LongWord);
|
||||||
procedure DoUpdateDDCSeqOrNoDevice(DDCIdx: Integer; Seq: LongWord);
|
procedure DoUpdateDDCSeqOrNoDevice(DDCIdx: Integer; Seq: LongWord);
|
||||||
@@ -1139,7 +1136,7 @@ begin
|
|||||||
// startup-preview выше, поэтому FDSPEngine рождается с нужной частотой.
|
// startup-preview выше, поэтому FDSPEngine рождается с нужной частотой.
|
||||||
FController.CreateEngines(FController.FSampleRate);
|
FController.CreateEngines(FController.FSampleRate);
|
||||||
FController.FNetwork.OnDeviceFound := OnDeviceFound;
|
FController.FNetwork.OnDeviceFound := OnDeviceFound;
|
||||||
FController.FNetwork.OnHPStatus := OnHPStatusCB;
|
FController.FNetwork.OnHPStatus := FController.OnHPStatus;
|
||||||
FController.FNetwork.OnDDCIQ := FController.OnDDCIQ;
|
FController.FNetwork.OnDDCIQ := FController.OnDDCIQ;
|
||||||
FController.FNetwork.OnMicPacket := FController.OnMicPacket;
|
FController.FNetwork.OnMicPacket := FController.OnMicPacket;
|
||||||
FController.FNetwork.OnWideband := OnWidebandCB;
|
FController.FNetwork.OnWideband := OnWidebandCB;
|
||||||
@@ -1317,6 +1314,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
rfTuning:
|
rfTuning:
|
||||||
StyleButton(BtnTUN, FController.FTuning);
|
StyleButton(BtnTUN, FController.FTuning);
|
||||||
|
rfADCOverload:
|
||||||
|
if FSpecView <> nil then
|
||||||
|
begin
|
||||||
|
FSpecView.ADCOverloadVisible := FController.FADCOverloadActive;
|
||||||
|
if PbSpectrum <> nil then PbSpectrum.Invalidate;
|
||||||
|
end;
|
||||||
rfBand:
|
rfBand:
|
||||||
// В XVTR-режиме HF-кнопки гасим (активна XVTR-кнопка, см. rfXvtr).
|
// В XVTR-режиме HF-кнопки гасим (активна XVTR-кнопка, см. rfXvtr).
|
||||||
for i := 0 to BAND_COUNT - 1 do
|
for i := 0 to BAND_COUNT - 1 do
|
||||||
@@ -3281,169 +3284,11 @@ begin
|
|||||||
SetStatusText(2, Format('Found: %s', [Dev.IPAddress]));
|
SetStatusText(2, Format('Found: %s', [Dev.IPAddress]));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.OnHPStatusCB(const Status: THighPriorityStatus);
|
|
||||||
const
|
|
||||||
// Порог fwd-мощности (W), ниже которого SWR не вычисляем — там всё ADC-шум.
|
|
||||||
SWR_MIN_FWD_W = 1.0;
|
|
||||||
// Верхняя граница SWR (выше — это всё равно «беда»).
|
|
||||||
SWR_CAP = 9.9;
|
|
||||||
var
|
|
||||||
ExcPwr, FwdPwr, RevPwr: Word;
|
|
||||||
SupplyV, SupplyA, FwdW, SWRV, Rho: Double;
|
|
||||||
IsTx: Boolean;
|
|
||||||
Sync: TStatusUISync;
|
|
||||||
M: TThreadMethod;
|
|
||||||
begin
|
|
||||||
ExcPwr := (Status.ExciterPwr0Hi shl 8) or Status.ExciterPwr0Lo;
|
|
||||||
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): voltage on UserADC0 (bytes 57-58),
|
|
||||||
// current on UserADC1 (bytes 55-56) — matching Thetis behaviour.
|
|
||||||
// Other supported boards report voltage in SupplyVolts bytes and no current.
|
|
||||||
if BoardSupportsSupplyVoltage(FController.FNetwork.Device.BoardType) then
|
|
||||||
begin
|
|
||||||
if FController.FNetwork.Device.BoardType = 5 then
|
|
||||||
SupplyV := ADCToSupplyVolts(
|
|
||||||
(Status.UserADC0Hi shl 8) or Status.UserADC0Lo,
|
|
||||||
FController.FNetwork.Device.BoardType)
|
|
||||||
else
|
|
||||||
SupplyV := ADCToSupplyVolts(
|
|
||||||
(Status.SupplyVoltsHi shl 8) or Status.SupplyVoltsLo,
|
|
||||||
FController.FNetwork.Device.BoardType);
|
|
||||||
|
|
||||||
if BoardSupportsSupplyCurrent(FController.FNetwork.Device.BoardType) then
|
|
||||||
SupplyA := ADCToSupplyCurrent(
|
|
||||||
(Status.UserADC1Hi shl 8) or Status.UserADC1Lo,
|
|
||||||
FController.FNetwork.Device.BoardType);
|
|
||||||
end;
|
|
||||||
// FController.FLastSMeter обновляется только из WDSP (GetSMeterDBm) в SpectrumTimerTick —
|
|
||||||
// ExciterPwr это мощность TX, не уровень принятого сигнала.
|
|
||||||
FwdW := ADCToWatts100(FwdPwr);
|
|
||||||
// FController.FTransmitting — наш программный флаг (MOX/TUN/HW-PTT через ApplyMOX).
|
|
||||||
// HPS_PTT-бит в StatusBits — это вход аппаратного PTT (footswitch/mic),
|
|
||||||
// а не «трансивер сейчас передаёт», поэтому только на него полагаться нельзя.
|
|
||||||
IsTx := FController.FTransmitting or ((Status.StatusBits and HPS_PTT) <> 0);
|
|
||||||
// SWR: правильная формула (1+ρ)/(1-ρ), считаем только когда есть значимая
|
|
||||||
// прямая мощность — иначе ADC-шум RevPwr даёт случайные «прыжки» SWR.
|
|
||||||
// Не на передаче — SWR не показываем (фиксируем 1.0), Fwd принудительно 0.
|
|
||||||
if IsTx and (FwdW >= SWR_MIN_FWD_W) and (FwdPwr > 0) then
|
|
||||||
begin
|
|
||||||
// ρ = sqrt(Pr/Pf). Поскольку P=V²/R и V пропорционально ADC, то
|
|
||||||
// sqrt(Pr/Pf) = adc_r/adc_f напрямую — лишнего sqrt не нужно.
|
|
||||||
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;
|
|
||||||
Sync := TStatusUISync.Create(DoUpdateStatus, FwdW, SWRV, SupplyV, SupplyA,
|
|
||||||
(Status.StatusBits and HPS_PLL_LOCKED) <> 0,
|
|
||||||
(Status.StatusBits and HPS_PTT) <> 0,
|
|
||||||
Status.ADCOverload);
|
|
||||||
try
|
|
||||||
M := Sync.Execute;
|
|
||||||
TThread.Synchronize(nil, M);
|
|
||||||
finally
|
|
||||||
Sync.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TMainForm.DoUpdateStatus(FwdW, SWRV, SupplyV, SupplyA: Double; PLLLock, HWPTT: Boolean;
|
|
||||||
ADCOverload: Byte);
|
|
||||||
const
|
|
||||||
// Thetis/piHPSDR PEP-style баллистика для FwdW и SWR: атака мгновенная
|
|
||||||
// (peak-hold), спад медленный — стрелка «висит» на пике и плавно опускается.
|
|
||||||
// Это маскирует огибающую SSB-голоса, которая на ADC прыгает на 10-20 дБ
|
|
||||||
// внутри слога. На rate ~150 пакетов/с эти α дают τ_decay ≈ 350 мс / 500 мс.
|
|
||||||
DECAY_FWD = 0.02;
|
|
||||||
DECAY_SWR = 0.015;
|
|
||||||
// Напряжение питания меняется медленно — обычное симметричное EMA.
|
|
||||||
ALPHA_SUPPLY = 0.05;
|
|
||||||
begin
|
|
||||||
// Запоминаем значения; вывод в UI делает MeterTimerTick на 10 Гц.
|
|
||||||
// Сама обработка здесь идёт на UI-потоке через Synchronize.
|
|
||||||
// FwdW=0 / SWRV=1 — это «не на передаче»: снапим без decay,
|
|
||||||
// чтобы метры моментально падали при отпускании PTT.
|
|
||||||
if FwdW <= 0 then
|
|
||||||
FController.FLastFwdW := 0
|
|
||||||
else if FwdW > FController.FLastFwdW then
|
|
||||||
FController.FLastFwdW := FwdW // attack: instant
|
|
||||||
else
|
|
||||||
FController.FLastFwdW := DECAY_FWD * FwdW + (1.0 - DECAY_FWD) * FController.FLastFwdW;
|
|
||||||
if SWRV <= 1.0 then
|
|
||||||
FController.FLastSWR := 1.0
|
|
||||||
else if SWRV > FController.FLastSWR then
|
|
||||||
FController.FLastSWR := SWRV // attack: instant
|
|
||||||
else
|
|
||||||
FController.FLastSWR := DECAY_SWR * SWRV + (1.0 - DECAY_SWR) * FController.FLastSWR;
|
|
||||||
if SupplyV >= 0 then
|
|
||||||
begin
|
|
||||||
if FController.FLastSupplyV < 0 then
|
|
||||||
FController.FLastSupplyV := SupplyV // первое значение — без сглаживания
|
|
||||||
else
|
|
||||||
FController.FLastSupplyV := ALPHA_SUPPLY * SupplyV + (1.0 - ALPHA_SUPPLY) * FController.FLastSupplyV;
|
|
||||||
end else
|
|
||||||
FController.FLastSupplyV := -1.0;
|
|
||||||
|
|
||||||
if SupplyA >= 0 then
|
|
||||||
begin
|
|
||||||
if FController.FLastSupplyA < 0 then
|
|
||||||
FController.FLastSupplyA := SupplyA
|
|
||||||
else
|
|
||||||
FController.FLastSupplyA := ALPHA_SUPPLY * SupplyA + (1.0 - ALPHA_SUPPLY) * FController.FLastSupplyA;
|
|
||||||
end else
|
|
||||||
FController.FLastSupplyA := -1.0;
|
|
||||||
FController.FLastPLLLock := PLLLock;
|
|
||||||
|
|
||||||
if (FSpecView <> nil) and (FSpecView.ADCOverloadVisible <> (ADCOverload <> 0)) then
|
|
||||||
begin
|
|
||||||
FSpecView.ADCOverloadVisible := ADCOverload <> 0;
|
|
||||||
if PbSpectrum <> nil then
|
|
||||||
PbSpectrum.Invalidate;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Hardware PTT (foot switch / mic PTT) — обнаружение фронта (нужно делать
|
|
||||||
// на rate HP Status, а не таймера, чтобы не пропустить короткое нажатие).
|
|
||||||
if HWPTT <> FController.FHWPTTActive then
|
|
||||||
begin
|
|
||||||
FController.FHWPTTActive := HWPTT;
|
|
||||||
if not FController.FTuning then
|
|
||||||
begin
|
|
||||||
if HWPTT then
|
|
||||||
begin
|
|
||||||
// Press: не перекрываем ручной MOX; запоминаем что мы включили TX.
|
|
||||||
if not BtnMOX.Active then
|
|
||||||
begin
|
|
||||||
ApplyMOX(True);
|
|
||||||
FController.FHWPTTStartedTX := True;
|
|
||||||
end;
|
|
||||||
end else
|
|
||||||
begin
|
|
||||||
// Release: выключаем TX только если он был включён через HWPTT.
|
|
||||||
// Нельзя проверять BtnMOX.Active — ApplyMOX(True) сам его выставляет.
|
|
||||||
if FController.FHWPTTStartedTX then
|
|
||||||
begin
|
|
||||||
FController.FHWPTTStartedTX := False;
|
|
||||||
ApplyMOX(False);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TMainForm.UpdateTXMeters;
|
procedure TMainForm.UpdateTXMeters;
|
||||||
// Вызывается из MeterTimerTick (10 Гц). Использует FController.FLastFwdW/FController.FLastSWR/
|
// Вызывается из MeterTimerTick (10 Гц). FController.FLastFwdW/FLastSWR/
|
||||||
// FController.FLastSupplyV/FController.FLastSupplyA обновляются на rate HP Status (~150/с)
|
// FLastSupplyV/FLastSupplyA обновляются на rate HP Status (~150/с)
|
||||||
// в DoUpdateStatus.
|
// в TRadioController.ApplyHPStatus.
|
||||||
begin
|
begin
|
||||||
if not FController.FRunning then
|
if not FController.FRunning then
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ type
|
|||||||
rfFMStep, rfFMStepIdx, rfFMRpt,
|
rfFMStep, rfFMStepIdx, rfFMRpt,
|
||||||
rfChannel,
|
rfChannel,
|
||||||
rfSMeter, rfPower, rfSWR, rfSupply, rfPLL, // телеметрия
|
rfSMeter, rfPower, rfSWR, rfSupply, rfPLL, // телеметрия
|
||||||
|
rfADCOverload, // ADC overload (рендер индикатора)
|
||||||
rfDevice // подключённое устройство сменилось
|
rfDevice // подключённое устройство сменилось
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -213,6 +214,12 @@ type
|
|||||||
FLastSeqErrorDDC: Integer;
|
FLastSeqErrorDDC: Integer;
|
||||||
FLastSeqErrorDelta: Int64;
|
FLastSeqErrorDelta: Int64;
|
||||||
FSeqOkStreak: Integer;
|
FSeqOkStreak: Integer;
|
||||||
|
FADCOverloadActive: Boolean; // ADC overload (рендерится по rfADCOverload)
|
||||||
|
// Pending-значения декода HP-статуса (сетевой поток → ApplyHPStatus через
|
||||||
|
// Invoke; Synchronize блокирующий и последовательный, гонок нет).
|
||||||
|
FHPpFwdW, FHPpSWR, FHPpSupplyV, FHPpSupplyA: Double;
|
||||||
|
FHPpPLL, FHPpHWPTT: Boolean;
|
||||||
|
FHPpOverload: Byte;
|
||||||
|
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@@ -230,6 +237,8 @@ type
|
|||||||
procedure OnMicPacket(const Data: TMicDataPacket);
|
procedure OnMicPacket(const Data: TMicDataPacket);
|
||||||
function PullSoundCardMic(MaxN: Integer): Integer;
|
function PullSoundCardMic(MaxN: Integer): Integer;
|
||||||
procedure OnDDCIQ(DDCIndex: Integer; const Data: TDDCIQPacket);
|
procedure OnDDCIQ(DDCIndex: Integer; const Data: TDDCIQPacket);
|
||||||
|
procedure OnHPStatus(const Status: THighPriorityStatus);
|
||||||
|
procedure ApplyHPStatus; // маршалится из OnHPStatus (сглаживание/overload/HWPTT)
|
||||||
|
|
||||||
// Маршалинг команды в поток контроллера (GUI: TThread.Synchronize).
|
// Маршалинг команды в поток контроллера (GUI: TThread.Synchronize).
|
||||||
procedure Invoke(M: TThreadMethod);
|
procedure Invoke(M: TThreadMethod);
|
||||||
@@ -499,6 +508,142 @@ begin
|
|||||||
FLastDDCIndex := DDCIndex;
|
FLastDDCIndex := DDCIndex;
|
||||||
end;
|
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);
|
procedure TRadioController.OnMicPacket(const Data: TMicDataPacket);
|
||||||
// HW mic-стрим уходит в WDSP только если выбран источник Radio; иначе сэмплы
|
// HW mic-стрим уходит в WDSP только если выбран источник Radio; иначе сэмплы
|
||||||
// игнорируются (mic берётся со звуковой карты).
|
// игнорируются (mic берётся со звуковой карты).
|
||||||
|
|||||||
Reference in New Issue
Block a user