fix(cw): реле T/R и антенна за ключом прошивки + залипание HW-PTT

Отвязав FTransmitting от телеграфа, я оставил в приёмной конфигурации всё,
что бэкенд считает от состояния передачи: CalcAlex0 бит 27 (реле T/R),
выбор антенны (TxAnt вместо RxAnt), bypass/Ext1 и CalcOCBits, которым
ключуется внешний усилитель. Прошивка гнала несущую, пока плата фильтров
стояла на приём, и приёмник видел собственный передатчик — на водопаде это
широкополосные полосы в моменты манипуляции.

PushNetworkState отдаёт в UpdateState RadioKeyed, и он же вызывается на
фронтах ключа. PTT в кадре этим не поднимается (он живёт в SendPTT), так
что манипуляцией по-прежнему владеет FPGA. Выдержка RadioKeyed поднята до
hang + 250 мс: по ней теперь щёлкает реле, и щёлкать оно обязано раз на
передачу, а не на каждую посылку. FTuning из RadioKeyed убран — при TUN
и так взведён FTransmitting, а в разборе SetTune флаги гаснут не разом.

Второе: телеграфная ветка разбора статуса заканчивается Exit, и падающий
фронт HW-PTT обработать было некому. Если в эфир увёл именно HW-PTT, пока
источником передачи был не телеграф, а телеграф включился уже после, то
передача залипала навсегда — FTransmitting взведён, Alex в TX, PTT не
снимается. Подтверждено на железе: всплески появлялись после переключения
передачи на слайс и оставались после возврата на главный.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 13:54:58 +03:00
co-authored by Claude Opus 5
parent 0a1a1ee3af
commit c6d1e409ff
+27 -2
View File
@@ -1324,8 +1324,11 @@ procedure TRadioController.PushNetworkState;
begin
if Assigned(FNetwork) and FNetwork.Connected and FNetwork.Running then
begin
// Состояние передачи для ЖЕЛЕЗА — RadioKeyed, а не FTransmitting: в
// телеграфе ключ замыкает прошивка, и реле T/R с антенной и OC обязаны
// ехать за ней. PTT в кадре этим не поднимается (он живёт в SendPTT).
FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslateTX(ActiveTXFreqHz),
FDriveLevel, FTransmitting, True, True, FTuning, FTwoTone);
FDriveLevel, RadioKeyed, True, True, FTuning, FTwoTone);
FNetwork.SendFullHP;
end;
end;
@@ -1578,6 +1581,17 @@ begin
// модуляции, — но передачей по нему не управляем.
if CWTXActive then
begin
// ★Ниже стоит Exit, поэтому падающий фронт HWPTT здесь обработать НЕКОМУ.
// Если в эфир нас увёл именно HWPTT, пока источником передачи был не
// телеграф (например слайс в голосовом режиме), а телеграф включился уже
// после — передача залипала бы НАВСЕГДА: FTransmitting остаётся взведённым,
// Alex стоит в TX, PTT не снимается, и приёмник всю дорогу видит свой же
// передатчик. Снимаем такую передачу здесь.
if FHWPTTStartedTX and (not FHPpHWPTT) then
begin
FHWPTTStartedTX := False;
SetMOX(False);
end;
FHWPTTActive := FHPpHWPTT;
if FHPpHWPTT then FCWKeyedAt := GetTickCount64;
// UI про телеграфную передачу иначе не узнает вовсе: SetMOX здесь не
@@ -1586,6 +1600,11 @@ begin
if FCWKeyedShown <> RadioKeyed then
begin
FCWKeyedShown := RadioKeyed;
// ★Железная обвязка обязана идти за фактическим ключом: реле T/R (Alex
// bit 27), TX-антенна, bypass/Ext1 и выходы OC (ими ключуется усилитель)
// считаются в бэкенде от состояния передачи. Без этого пути прошивка
// гнала бы несущую, пока Alex стоит в ПРИЁМНОЙ конфигурации.
PushNetworkState;
Changed(rfTransmitting);
end;
Exit;
@@ -1594,6 +1613,7 @@ begin
if FCWKeyedShown then
begin
FCWKeyedShown := False;
PushNetworkState;
Changed(rfTransmitting);
end;
// Hardware PTT (footswitch / mic PTT): фронт на rate HP Status — не пропустить
@@ -5683,11 +5703,16 @@ function TRadioController.RadioKeyed: Boolean;
// выдержка гасила бы индикацию между словами.
var Hold: QWord;
begin
Result := FTransmitting or FTuning;
Result := FTransmitting;
if Result then Exit;
if not CWTXActive then Exit(False);
if FCWKeyedAt = 0 then Exit(False);
// Выдержка = hang прошивки + запас, но не меньше 8 точек: полурывок semi-QSK.
// По ней же переключается реле T/R, поэтому щёлкать оно обязано РАЗ на
// передачу, а не на каждую посылку.
Hold := 8 * (1200 div EnsureRange(FCWSettings.Speed, 5, 60));
if Hold < QWord(FCWSettings.HangTimeMS) + 250 then
Hold := QWord(FCWSettings.HangTimeMS) + 250;
if Hold < 500 then Hold := 500;
Result := (GetTickCount64 - FCWKeyedAt) < Hold;
end;