fix(cw): первый прогон на железе — частота, мощность, индикация, полоса

Семь дефектов, вскрытых проверкой в эфире. Общий корень у большинства: с
кейером в прошивке FTransmitting не поднимается вовсе — передачей владеет
FPGA, — а половина проекта считала этот флаг признаком эфира.

Обрыв посылки после первого элемента. При break-in железо само поднимает
T/R на каждую посылку, HPS_PTT это отражает, и разбор статуса гонял по
фронту SetMOX(True/False); снятие MOX гасило CWX. Теперь в телеграфе фронт
HPS_PTT не управляет передачей. Без этого и работа манипулятором
пересобирала бы передающий тракт на каждой точке.

Обрыв по «key hit» переведён на фронт лепестка: на плате без ключа входы
могут стоять в единице, и проверка уровня убивала бы передачу сразу.

Посылка уходила по центру дисплея, а не на VFO. StartRunning ставил DUC на
центр DDC; до первой перестройки VFO или до первого MOX там и оставалось.
Без CTUN центр совпадает с VFO, поэтому баг и дожил до телеграфа, где MOX
не бывает. SetRunAndFreq получает TX-частоту, SetSliceTarget толкает кадр,
когда перестраивают слайс-источник. Правило: DUC обязан стоять правильно
всегда, а не только на передаче.

Мощность ниже, чем на TUN: уровень (байт 345) клался в кадр только при
FIsTransmitting. Введён SetCWKeyerArmed — пока кейер вооружён, уровень
лежит в каждом HP-кадре. Там же пересчитывается FDriveLevel, иначе до
первого касания ручки в железо уходил ноль.

Индикация не показывала передачу: события rfTransmitting в телеграфе не
бывает, поэтому блок рендера не выполнялся ни разу. ApplyHPStatus шлёт его
сам на фронтах RadioKeyed («железо в эфире» = передача или замыкание ключа
прошивкой, выдержка 8 точек и не меньше 500 мс). На RadioKeyed переведены
S-метр, красная полоса главного VFO и TX-бейджи флагов вместе с красной
полосой слайса на панадаптерах.

Полоса на спектре рисовалась как SSB: TXSignedEdges обязана отдавать для
CW голосовую боковую (через bp0 идёт тон pitch при настройке), поэтому
экранные кромки развязаны в TXFilterEdgesHz — занимаемая полоса
манипуляции симметрично несущей. Тот же класс, что был у ЧМ.

F1..F8 молчали, пока не откроешь окно памяти: обработчик упирался в
проверку лениво создаваемой формы. Текст берётся из настроек.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 13:14:38 +03:00
co-authored by Claude Opus 5
parent 53329e82e8
commit 0a1a1ee3af
6 changed files with 159 additions and 16 deletions
+18 -7
View File
@@ -1476,7 +1476,9 @@ begin
FSpecView.TXMode := FController.FTransmitting and not FController.FDisplayDuplex;
// Красная полоса главного VFO — только когда передаём с него: при
// TX со слайса краснеет полоса ТОГО слайса (DrawSliceFilterMarkers).
FSpecView.TXOverlay := FController.FTransmitting and
// ★RadioKeyed, а не FTransmitting: в телеграфе ключ замыкает прошивка,
// софт «не передаёт», и полоса оставалась бы приёмной всю связь.
FSpecView.TXOverlay := FController.RadioKeyed and
(FController.FTxSliceId = 0);
PushFilterEdgesToView; // на передаче полоса рисуется по TX-фильтру
ApplySpecViewGridFromState; // сетка спектра под активный тракт
@@ -3711,7 +3713,9 @@ begin
FSpecView.SMeterMin := FSMeterMin;
FSpecView.LastFwdW := FController.FLastFwdW;
FSpecView.LastSWR := FController.FLastSWR;
FSpecView.Transmitting := FController.FTransmitting;
// Метр — по RadioKeyed, а не по FTransmitting: в телеграфе софт «не передаёт»,
// ключ замыкает прошивка, и стрелка осталась бы на S-метре всю связь.
FSpecView.Transmitting := FController.RadioKeyed;
if PbSMeterRight <> nil then PbSMeterRight.Invalidate;
// PWR/SWR метки и бары обновляем здесь (10 Гц), а не в DoUpdateStatus —
@@ -8140,6 +8144,10 @@ procedure TMainForm.OnCWSettingsChange(const C: TCWSettings);
// прошивку, персист — там же. Форме остаётся только передать запись.
begin
FController.SetCWSettings(C);
// Скорость кейера = ширина полосы телеграфа на экране. Движок вьюху сам не
// уведомляет — правило то же, что для профилей и кромок TX.
PushFilterEdgesToView;
if FController.FTransmitting then FSpectrumDirty := True;
// Окно памяти показывает те же ячейки — держим его в курсе правок из настроек.
if FCWMsgForm <> nil then TCWMessagesForm(FCWMsgForm).LoadFrom(FController.CWSettings);
end;
@@ -8170,17 +8178,20 @@ end;
procedure TMainForm.FormKeyDownCW(Sender: TObject; var Key: Word;
Shift: TShiftState);
// F1..F8 — ячейки памяти телеграфа. Работают только в CW и только когда окно
// памяти уже открывали (иначе клавиши остаются свободными для всего прочего).
// F1..F8 — ячейки памяти телеграфа. Единственное условие — телеграф на
// передающем источнике; в прочих режимах клавиши свободны для всего другого.
// ★Текст берём ИЗ НАСТРОЕК, а не из окна памяти: окно создаётся лениво, и
// раньше клавиши молчали, пока его хоть раз не открыли.
var Slot: Integer;
begin
if FCWMsgForm = nil then Exit;
if Shift <> [] then Exit;
if not (FController.ActiveTXMode in [MODE_CWL, MODE_CWU]) then Exit;
if (Key < VK_F1) or (Key > VK_F8) then Exit;
if not (FController.ActiveTXMode in [MODE_CWL, MODE_CWU]) then Exit;
Slot := Key - VK_F1;
TCWMessagesForm(FCWMsgForm).SendSlot(Slot);
if (Slot < 0) or (Slot >= CW_MSG_COUNT) then Exit;
Key := 0;
if FController.CWSettings.Messages[Slot] = '' then Exit;
FController.CWXSend(FController.CWSettings.Messages[Slot]);
end;
procedure TMainForm.OnAlexSettingsChange(const A: TAlexSettings);