chore(tx): детектор голодания снят — всплесков не видно, вернём при нужде

Прибор из b173b7f отработал своё на этом заходе: всплески не появляются, и
держать его в тракте нет причин. Снято ровно то, что тот коммит поставил:
юнит TxHealth.pas, замеры простоев в отправителе DUC (обе ветки), публикация
контекста пейсинга из планировщика TCI, счёт бита HPS_FIFO_EMPTY, вызовы
TxHealthService в таймере UI и цикле демона, индикатор «·сухо N» в статусной
строке и секция G стенда.

Вернуть — реверсом этого коммита; опора детектора и правило его устройства
(в тракте передачи ничего, кроме записи в память) записаны в
test/hpsdr/README.md, чтобы не восстанавливать рассуждение заново.

Проверено: test/tci 262/262, test/cat 50/50, GUI (--ws=qt6) и демон собираются.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bkwwyj7xVRrqnSVEseTRfV
This commit is contained in:
2026-08-24 19:25:57 +03:00
co-authored by Claude Opus 5
parent b173b7f542
commit 867da5921e
8 changed files with 30 additions and 553 deletions
+1 -22
View File
@@ -19,7 +19,7 @@ uses
{$ELSE}
Sockets, BaseUnix,
{$ENDIF}
HPSDRProtocol, SyncObjs, Settings, RadioBackend, TxHealth, PlatformUtils;
HPSDRProtocol, SyncObjs, Settings, RadioBackend;
const
DUC_TX_QUEUE_SIZE = 256; // power of two, bounded latency on TX underrun/overrun
@@ -497,7 +497,6 @@ const
DUC_WIN_SPIN_US = 350; // final part of 1.25 ms interval: avoid Sleep jitter
var
Pkt: TDUCIQPacket;
DryFrom: Int64; // детектор: начало простоя очереди, мкс (см. TxHealth)
{$IFDEF WINDOWS}
QPCFreq: Int64;
QPCValue: Int64;
@@ -552,15 +551,11 @@ begin
if not QueryPerformanceFrequency(QPCFreq) or (QPCFreq <= 0) then
QPCFreq := 1000;
NextDueUs := ClockUs;
DryFrom := 0;
while not Terminated do
begin
if not FNet.DequeueDUCIQ(Pkt) then
begin
// Детектор голодания: очередь пуста на передаче. Стоимость — одно чтение
// монотонных часов на ПЕРЕХОД, ни файлов, ни локов (см. TxHealth.pas).
if FNet.FIsTransmitting and (DryFrom = 0) then DryFrom := MonotonicUs;
RTLEventWaitFor(FNet.FDUCIQSem, 20);
NowUs := ClockUs;
if NextDueUs < NowUs - DUC_PACKET_INTERVAL_US then
@@ -573,12 +568,6 @@ begin
if not FNet.FIsTransmitting then
Continue;
if DryFrom <> 0 then
begin
TxHealthDrought(DryFrom, MonotonicUs, FNet.FDUCIQCount);
DryFrom := 0;
end;
FNet.PackSeqBytes(Pkt.Seq, FNet.NextSeq(FNet.FSeqDUCIQ));
FNet.DoSendTo(FNet.FSocket, Pkt, SizeOf(Pkt), FNet.FDevice.IPAddress,
FNet.FPortDUCIQ);
@@ -591,16 +580,12 @@ begin
{$ELSE}
VirtualSamples := 0;
LastTick := GetTickCount64;
DryFrom := 0;
while not Terminated do
begin
if not FNet.DequeueDUCIQ(Pkt) then
begin
DrainVirtualFIFO;
// Детектор голодания: очередь пуста на передаче. Стоимость — одно чтение
// монотонных часов на ПЕРЕХОД, ни файлов, ни локов (см. TxHealth.pas).
if FNet.FIsTransmitting and (DryFrom = 0) then DryFrom := MonotonicUs;
// Очередь пуста. НЕ инжектируем нулевые пакеты — 1.25мс тишины прямо
// в поток сэмплов = разрыв данных = всплеск на водопаде/в эфире. Как
// dl1ycf pihpsdr (txiq_thread: пустая очередь → просто sem_wait): ждём
@@ -619,12 +604,6 @@ begin
if not FNet.FIsTransmitting then
Continue;
if DryFrom <> 0 then
begin
TxHealthDrought(DryFrom, MonotonicUs, FNet.FDUCIQCount);
DryFrom := 0;
end;
FNet.PackSeqBytes(Pkt.Seq, FNet.NextSeq(FNet.FSeqDUCIQ));
FNet.DoSendTo(FNet.FSocket, Pkt, SizeOf(Pkt), FNet.FDevice.IPAddress,
FNet.FPortDUCIQ);