From ced42fbac9ac9bd436a261b0145ba20d7a934fb8 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Tue, 21 Jul 2026 00:13:35 +0300 Subject: [PATCH] fix(hpsdr): prevent false connection lost on tick race The RX timeout check sampled GetTickCount64 on the UI thread while the UDP receive thread could update FRXLastPktTime a millisecond later. Both values are QWord, so subtracting the newer packet tick from the older UI tick underflowed to a very large value and falsely satisfied the 3-second timeout. Snapshot the packet timestamp once for each timeout check and require NowTick >= LastPktTick before calculating the elapsed interval. The initial-packet timeout uses the same snapshot. This preserves real timeout detection while ignoring a packet timestamp that is marginally newer than the UI tick. Diagnostics confirmed that DDC UDP packets, callbacks, and HP status remained continuous during the reported failures; the issue was local timeout arithmetic rather than network loss or radio stream interruption. --- MainForm.pas | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/MainForm.pas b/MainForm.pas index 2ee321b..6cdd417 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -3409,6 +3409,7 @@ procedure TMainForm.SpectrumTimerTick(Sender: TObject); var NowTick: QWord; ElapsedTick: QWord; + LastPktTick: QWord; I: Integer; begin // «×» шапки пана: закрытие отложено сюда (нельзя free панель из её кнопки). @@ -3438,8 +3439,12 @@ begin begin NowTick := GetTickCount64; ElapsedTick := NowTick - FController.FRXStartTime; + // Сетевой поток может обновить FRXLastPktTime на 1 ms ПОСЛЕ NowTick. + // QWord-вычитание в таком случае underflow'ится в огромное значение и + // давало ложный "Connection lost" при совершенно живом DDC-потоке. + LastPktTick := FController.FRXLastPktTime; // Ждём первый пакет 5 секунд после старта - if (FController.FRXLastPktTime = 0) and (ElapsedTick > 5000) then + if (LastPktTick = 0) and (ElapsedTick > 5000) then begin BtnStartStop.Caption := 'START'; StyleButton(BtnStartStop, False); @@ -3451,7 +3456,8 @@ begin Exit; end; // После первого пакета — следим чтобы поток не прерывался более 3 сек - if (FController.FRXLastPktTime > 0) and ((NowTick - FController.FRXLastPktTime) > 3000) then + if (LastPktTick > 0) and (NowTick >= LastPktTick) and + ((NowTick - LastPktTick) > 3000) then begin BtnStartStop.Caption := 'START'; StyleButton(BtnStartStop, False);