mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
feat(cw): телеграф — FPGA-кейер, pitch, сайдтон, передача текста
CW не работал ни на приём, ни на передачу: фильтр стоял симметрично вокруг нуля (тона не было), понятия pitch не существовало, MOX в CWL отправлял в эфир голос 2.9 кГц (в WDSP TXA_CWL — ветка SSB), байт CW-опций DUC всегда был нулевым, поэтому кейер, сайдтон и break-in в прошивке молчали. Pitch сделан ОДНИМ сдвигом в движке. Кромки фильтра везде остаются относительно VFO (у CW — симметрично нулю), а гетеродин и полосу двигают три метода WDSPEngine: CWLOOffset / PushShift / PushPassband. Прямых вызовов SetRXAShiftFreq и RXASetPassband в проекте больше нет. Так таблица фильтров не перестраивается при смене pitch (в отличие от Thetis), полоска на спектре и маркер VFO верны без правок в UI, а слайсы получают свой сдвиг по своему режиму. Правила эфира: - голосовой TXA в CW не запускается вообще (гард по режиму), MOX = только PTT; несущую даёт кейер, бит CWX или тон TUN; - байт 5 собирается из настроек и перепосылается на каждой смене режима и TX-слайса — вне CW он обязан быть нулевым, иначе прошивка поднимет PTT на замыкание ключа посреди SSB; - TUN в CW: тон = pitch и встречный сдвиг DUC, несущая встаёт ровно на VFO; - приёмник на передаче в CW не глушится, иначе умолкает программный сайдтон и эфир между посылками. Программная передача текста (CWMorse): поток с абсолютными дедлайнами дёргает бит CWX в High Priority, элементы рисует прошивка. Касание манипулятора или снятие MOX обрывают передачу. Память сообщений — окно CW Messages и F1..F8 в главном окне. Оживлены CAT KS/KY/ZZKM/ZZKS/ZZKY. Настройки — вкладка Transmit, подвкладка Hardware, перед блоком FM/CTCSS. Программный сайдтон точен для передачи текста и прямого ключа; при иамбике таймингом владеет FPGA, поэтому там верен только аппаратный тон. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+66
-1
@@ -43,7 +43,7 @@ uses
|
||||
WinFirewall,
|
||||
BoardUtils, WisdomBuilder, UISync,
|
||||
FlatEdit, FMRepeater,
|
||||
ChannelStore, ChannelsForm, BeaconScopeForm, DMRDecoder,
|
||||
ChannelStore, ChannelsForm, CWMessagesForm, BeaconScopeForm, DMRDecoder,
|
||||
PowerInhibit,
|
||||
DeviceStore,
|
||||
RadioBackend, PlutoBackend,
|
||||
@@ -367,6 +367,7 @@ type
|
||||
BtnTXProfile: TFlatButton;
|
||||
FTXProfileDropDown: TFlatDropDown;
|
||||
FChannelsForm: TObject; // TChannelsForm (cast при использовании)
|
||||
FCWMsgForm: TObject; // TCWMessagesForm (память телеграфа)
|
||||
FBeaconScopeForm: TBeaconScopeForm; // окно констелляции маяка (ПКМ по BEACON)
|
||||
|
||||
// ---- Right panel ----
|
||||
@@ -763,6 +764,11 @@ type
|
||||
procedure OnAnt936xChange(const A: TAD936xAnt); // разъёмы AD936x (Antenna)
|
||||
procedure OnVHFCalSettingsChange(const VHFCal: array of Double);
|
||||
procedure OnTXSettingsChange(const T: TTXSettings);
|
||||
procedure OnCWSettingsChange(const C: TCWSettings);
|
||||
procedure ShowCWMessages;
|
||||
procedure OnCWMessageSend(const Text: string);
|
||||
procedure OnCWMessageAbort(Sender: TObject);
|
||||
procedure FormKeyDownCW(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
procedure BtnAGCModeClick(Sender: TObject);
|
||||
procedure TrkAGCChange(Sender: TObject);
|
||||
procedure TrkRxGainChange(Sender: TObject);
|
||||
@@ -1065,7 +1071,12 @@ begin
|
||||
FController.FTXSpecGridStep := 10.0;
|
||||
FSettingsForm := nil;
|
||||
FChannelsForm := nil;
|
||||
FCWMsgForm := nil;
|
||||
FBeaconScopeForm := nil;
|
||||
// F1..F8 для памяти телеграфа. Обработчик молчит, пока окно памяти не
|
||||
// открывали и пока режим не CW, поэтому прочим клавишам ничего не мешает.
|
||||
KeyPreview := True;
|
||||
OnKeyDown := FormKeyDownCW;
|
||||
FillChar(FController.FDevMAC, SizeOf(FController.FDevMAC), 0);
|
||||
|
||||
// Инициализируем кэш диапазонов умолчаниями
|
||||
@@ -3400,6 +3411,7 @@ begin
|
||||
T := CurrentAppTheme;
|
||||
if FDeviceDialog <> nil then FDeviceDialog.SetTheme(T);
|
||||
if FChannelsForm <> nil then TChannelsForm(FChannelsForm).ApplyTheme(T);
|
||||
if FCWMsgForm <> nil then TCWMessagesForm(FCWMsgForm).ApplyTheme(T);
|
||||
if FBeaconScopeForm <> nil then FBeaconScopeForm.ApplyTheme(T);
|
||||
FController.FSettings.SaveTheme(V);
|
||||
FController.FSettings.Save;
|
||||
@@ -5831,6 +5843,7 @@ begin
|
||||
TSettingsForm(FSettingsForm).LoadTXSettings(FController.FTXSettings,
|
||||
IfThen(FController.FNetwork.Connected,
|
||||
FController.FNetwork.Device.BoardType, FPendingBoardType));
|
||||
TSettingsForm(FSettingsForm).LoadCWSettings(FController.CWSettings);
|
||||
PushTXProfilesToSettings;
|
||||
end;
|
||||
// Пилюли профиля на флагах: список общий, привязки могли съехать после
|
||||
@@ -8122,6 +8135,54 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnCWSettingsChange(const C: TCWSettings);
|
||||
// Телеграф целиком живёт в контроллере: pitch → движок, кейер/сайдтон → в
|
||||
// прошивку, персист — там же. Форме остаётся только передать запись.
|
||||
begin
|
||||
FController.SetCWSettings(C);
|
||||
// Окно памяти показывает те же ячейки — держим его в курсе правок из настроек.
|
||||
if FCWMsgForm <> nil then TCWMessagesForm(FCWMsgForm).LoadFrom(FController.CWSettings);
|
||||
end;
|
||||
|
||||
procedure TMainForm.ShowCWMessages;
|
||||
begin
|
||||
if FCWMsgForm = nil then
|
||||
begin
|
||||
FCWMsgForm := TCWMessagesForm.Create(Self);
|
||||
TCWMessagesForm(FCWMsgForm).OnSend := OnCWMessageSend;
|
||||
TCWMessagesForm(FCWMsgForm).OnAbort := OnCWMessageAbort;
|
||||
TCWMessagesForm(FCWMsgForm).OnChanged := OnCWSettingsChange;
|
||||
end;
|
||||
TCWMessagesForm(FCWMsgForm).LoadFrom(FController.CWSettings);
|
||||
TCWMessagesForm(FCWMsgForm).ApplyTheme(CurrentAppTheme);
|
||||
TCWMessagesForm(FCWMsgForm).Show;
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnCWMessageSend(const Text: string);
|
||||
begin
|
||||
FController.CWXSend(Text);
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnCWMessageAbort(Sender: TObject);
|
||||
begin
|
||||
FController.CWXAbort;
|
||||
end;
|
||||
|
||||
procedure TMainForm.FormKeyDownCW(Sender: TObject; var Key: Word;
|
||||
Shift: TShiftState);
|
||||
// F1..F8 — ячейки памяти телеграфа. Работают только в CW и только когда окно
|
||||
// памяти уже открывали (иначе клавиши остаются свободными для всего прочего).
|
||||
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;
|
||||
Slot := Key - VK_F1;
|
||||
TCWMessagesForm(FCWMsgForm).SendSlot(Slot);
|
||||
Key := 0;
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnAlexSettingsChange(const A: TAlexSettings);
|
||||
begin
|
||||
FController.FAlexSettings := A;
|
||||
@@ -9047,6 +9108,8 @@ begin
|
||||
SF.OnThemeChange := SetLightTheme;
|
||||
SF.OnFreqMhzDigitsChange := ApplyFreqMhzDigits;
|
||||
SF.OnTXChange := OnTXSettingsChange;
|
||||
SF.OnCWChange := OnCWSettingsChange;
|
||||
SF.OnCWMessagesOpen := ShowCWMessages;
|
||||
SF.OnTXProfileSelect := OnTXProfileSelectFromSettings;
|
||||
SF.OnTXProfileAdd := OnTXProfileAddFromSettings;
|
||||
SF.OnTXProfileRename := OnTXProfileRenameFromSettings;
|
||||
@@ -9063,6 +9126,7 @@ begin
|
||||
PushTXProfilesToSettings;
|
||||
SF.LoadTXSettings(FController.FTXSettings,
|
||||
IfThen(FController.FNetwork.Connected, FController.FNetwork.Device.BoardType, FPendingBoardType));
|
||||
SF.LoadCWSettings(FController.CWSettings);
|
||||
SF.LoadAlexSettings(FController.FAlexSettings,
|
||||
IfThen(FController.FNetwork.Connected, FController.FNetwork.Device.BoardType, FPendingBoardType));
|
||||
// Вкладка Antenna: у AD936x (Pluto/LibreSDR) вместо Alex-таблицы — таблица
|
||||
@@ -9159,6 +9223,7 @@ begin
|
||||
EnsureWDSPWisdom;
|
||||
end;
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
// CAT subsystem
|
||||
// ===========================================================================
|
||||
|
||||
Reference in New Issue
Block a user