mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
fix(tci): бухгалтерия пейсинга переезжала из прошлой передачи в следующую
Посреди передачи из MSHV рядом с сигналом вставала вторая несущая — и не
изредка, а с первых миллисекунд посылки. Это голая несущая гетеродина DUC:
очередь пересыхает, модуляции нет.
Цепочка. Конец посылки клиент делает командой trx:N,false. SetMOX(False)
снимает TCIMicActive внутри Invoke, а FTxClient обнуляется ПОСЛЕ возврата из
него, в HandleTrx. Опустить FTxRunning умел только тик планировщика — и только
пока видел живого FTxClient с уже снятым TCIMicActive. Окно = хвост SetMOX,
пара миллисекунд против шага тика в полкванта: тик попадал в него через раз.
Промах означал, что следующая передача идёт МИМО TxResetAccounting и наследует
FTxOwed, FTxInFlight, FTxSatSinceUs и оценку задержки. Долг сразу у потолка,
в полёте чужие кредиты прошлой посылки, условие выдачи не выполняется — маркеры
не идут вовсе, пока не сработает сторож (выдержка до 250 мс). Нулевой pre-roll
кончается раньше, очередь DUC сохнет, радио отдаёт несущую.
Лечение — инвариант «нет клиента, нет и идущей передачи», как в ClearTxClient
(он его соблюдал, а HandleTrx нет):
* FTxRunning := False рядом с FTxClient := Client — первый тик передачи всегда
начинает с TxResetAccounting, каким бы ни был исход гонки;
* то же в обоих местах, где источник снимается;
* то же в выходе PushTxChrono по C = nil — страховка от будущих путей.
Аванс (FTxLeadKeep, FTxGapUs) не трогаем: он намеренно переживает передачу,
на нём стоит pre-roll следующего PTT.
Стенд: новая фаза «повторы» в TestTxPacing — шесть циклов PTT на одном клиенте,
проверка флага сразу по подтверждению trx:0,false и счёт маркеров в первые
200 мс каждой передачи. Негативный контроль на старом коде: флаг протухал 6/6,
маркеров 4 вместо 22. Стенд 262/262, test/cat 50/50, GUI и демон собираются.
★Отдельной тестовой процедурой это сделать нельзя: третий TRadioController в
процессе даёт AV в FreeEngines (состояние WDSP), стенд падает до проверок.
Фаза живёт внутри TestTxPacing и стартует после потерь ответов — то есть с
заведомо отравленной бухгалтерией.
★Почему дефект вылез только сейчас: TraceDump('tx') из снятых зондов стоял в
конце SetMOX(False) и писал до 16 тысяч строк — десятки миллисекунд ровно в
этом окне, и тик гарантированно успевал. Прогоны шли с EWSDR_TXTRACE=1, так
что инструмент собой же и прикрывал гонку.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bkwwyj7xVRrqnSVEseTRfV
This commit is contained in:
+23
-4
@@ -2185,6 +2185,17 @@ begin
|
||||
begin
|
||||
FTxClient := Client;
|
||||
FTxRx := Rx;
|
||||
// ★Новая передача — новая бухгалтерия, и опустить флаг обязаны
|
||||
// ЗДЕСЬ. Сбрасывает его тик, но только пока видит ЖИВОГО FTxClient
|
||||
// и уже снятый TCIMicActive (см. PushTxChrono) — а это окно длиной
|
||||
// в хвост SetMOX, пара миллисекунд против шага тика в полкванта.
|
||||
// Тик в него попадал через раз, и промах означал, что следующая
|
||||
// передача идёт МИМО TxResetAccounting: с долгом у потолка и
|
||||
// чужими кредитами в полёте, то есть с заблокированной выдачей
|
||||
// маркеров на всю выдержку сторожа. В эфире это голая несущая
|
||||
// гетеродина DUC поверх пересохшей очереди с первых же
|
||||
// миллисекунд посылки.
|
||||
FTxRunning := False;
|
||||
// ★Будим планировщик немедленно. Иначе первый маркер уходил на
|
||||
// 10-20 мс позже фронта PTT (дремотный шаг), и ровно этих
|
||||
// миллисекунд не хватало нулевому pre-roll, чтобы дожить до первого
|
||||
@@ -2194,15 +2205,20 @@ begin
|
||||
// Эфир поднял он же, но модуляцию просит НЕ из TCI — снимаем свою.
|
||||
else if Started and (not Tune) and (FTxClient = Client) then
|
||||
begin
|
||||
FTxClient := nil;
|
||||
FTxRx := 0;
|
||||
FTxClient := nil;
|
||||
FTxRx := 0;
|
||||
FTxRunning := False;
|
||||
end;
|
||||
end
|
||||
// Сам просит выключить — источник ему больше не нужен в любом случае.
|
||||
else if (not Tune) and (FTxClient = Client) then
|
||||
begin
|
||||
FTxClient := nil;
|
||||
FTxRx := 0;
|
||||
FTxClient := nil;
|
||||
FTxRx := 0;
|
||||
// ★Тот же инвариант, что и в ClearTxClient: нет клиента — нет и
|
||||
// идущей передачи. Раньше эти две строки расходились, и штатный
|
||||
// конец посылки (trx:N,false у MSHV) оставлял FTxRunning поднятым.
|
||||
FTxRunning := False;
|
||||
end;
|
||||
finally FTxLock.Leave; end;
|
||||
end;
|
||||
@@ -3820,6 +3836,9 @@ begin
|
||||
try
|
||||
C := FTxClient;
|
||||
Rx := FTxRx;
|
||||
// Хозяина нет — считать нечего и не про кого. Флаг снимаем под тем же
|
||||
// локом: он живёт ровно столько, сколько живёт FTxClient.
|
||||
if C = nil then FTxRunning := False;
|
||||
finally
|
||||
FTxLock.Leave;
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user