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
+23
View File
@@ -473,6 +473,7 @@ type
FDisplayResLimit: Integer; // потолок точек анализатора (настройка display_pixels)
FShiftHz: Double; // NCO shift для CTUN
FCWPitch: Integer; // Гц, тон телеграфа (см. CWLOOffset)
FCWSpeed: Integer; // WPM — только для занимаемой полосы на экране
FNRMode: Integer;
FNBMode: Integer;
FSNBEnabled: Boolean;
@@ -654,6 +655,9 @@ type
// применяется немедленно (главный + слайсы), персист делает контроллер.
procedure SetCWPitch(Hz: Integer);
function CWPitch: Integer;
// Скорость кейера нужна движку ровно для одного — ширины полосы телеграфа
// на экране (TXFilterEdgesHz). Тайминги делает прошивка, не мы.
procedure SetCWSpeed(WPM: Integer);
// Смещение гетеродина демодулятора относительно VFO в телеграфе (см.
// комментарий у PushShift). Публично: тем же сдвигом контроллер двигает
// DUC при настройке TUN, чтобы несущая легла ровно на VFO.
@@ -1370,6 +1374,7 @@ begin
FAGCMode := agcMedium;
FShiftHz := 0.0;
FCWPitch := 600;
FCWSpeed := 20;
FAGCTop := -90.0;
FVolume := 0.7;
FSMeter := -130.0;
@@ -3090,6 +3095,13 @@ begin
end;
end;
procedure TWDSPEngine.SetCWSpeed(WPM: Integer);
begin
if WPM < 5 then WPM := 5;
if WPM > 60 then WPM := 60;
FCWSpeed := WPM;
end;
procedure TWDSPEngine.SetAGCTop(TopDBm: Double);
begin
FAGCTop := TopDBm;
@@ -3821,6 +3833,17 @@ begin
MODE_FM: Half := FTXFMDeviation + FTXFMHighCut;
MODE_WFM: Half := WFM_DEVIATION + WFM_AF_HIGH;
MODE_FMRAW: Half := FRawFMDeviation + RAW_AF_HIGH;
// ★Телеграф. TXSignedEdges отдаёт для CWL/CWU ГОЛОСОВУЮ боковую (bp0 обязан
// оставаться открытым: через него идёт тон pitch при настройке TUN), но в
// эфир уходит манипулируемая НЕСУЩАЯ на самом VFO. Рисовать её юбкой SSB
// нельзя — полоса выглядела как в SSB и уезжала вбок от несущей.
// Занимаемая полоса телеграфа: B = WPM/1.2 бод, BW ≈ 5·B при мягкой
// манипуляции (фронт CWRampPeriod). Симметрично несущей.
MODE_CWL, MODE_CWU:
begin
Half := 5.0 * (FCWSpeed / 1.2) / 2.0;
if Half < 25.0 then Half := 25.0; // не вырождаться в нулевую полоску
end;
end;
if Half > 0.0 then
begin