refactor(controller): единая дверь SetTXSettings для правки TX-настроек

Применение TX-настроек (WDSP, DUC Specific при смене mic-битов/ATT, живое
обновление TUN, запись в активный профиль, персист) жило в обработчике
MainForm — то есть было недоступно ничему, кроме вкладки Transmit. CAT и web
по архитектуре ходят только в контроллер и дотянуться туда не могли.

Логика переехала в TRadioController.SetTXSettings по образцу уже
существовавшего SetCWSettings; MainForm делегирует ей и оставляет себе только
рендер. Notify=False у формы — иначе rfTXProfile перезагрузил бы вкладку
Transmit прямо под руками у того, кто её правит.

Заодно SetTXMonVolume: громкость self-monitor'а адресно, вне TX-контекста
(слайдер добирается до неё только на передаче, CAT-клиенту такой контекст
не нужен).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 13:12:10 +03:00
co-authored by Claude Opus 5
parent f89f202a34
commit f7bed07831
2 changed files with 76 additions and 48 deletions
+7 -48
View File
@@ -8520,64 +8520,23 @@ begin
end;
procedure TMainForm.OnTXSettingsChange(const T: TTXSettings);
// Любая правка в Settings→Transmit летит сюда: обновляем FController.FTXSettings,
// перешиваем WDSP TX-цепь и (если поменялись mic-биты) перепосылаем DUC Specific.
var
OldMicByte, NewMicByte: Byte;
OldAtt, OldTUNLevel, OldTUNFreq: Integer;
GridChanged: Boolean;
// Любая правка в Settings→Transmit летит сюда. Применение записи (WDSP, DUC
// Specific, живой TUN, профиль, персист) — в контроллере: SetTXSettings, та же
// дверь, что у CAT и web. Форме остаётся рендер.
// Notify=False — иначе rfTXProfile перезагрузил бы вкладку Transmit прямо под
// руками у того, кто её сейчас правит.
var GridChanged: Boolean;
begin
OldMicByte := FController.BuildMicLineSelectByte;
OldAtt := FController.FTXSettings.AttOnTX;
OldTUNLevel := FController.FTXSettings.TUNLevel;
OldTUNFreq := FController.FTXSettings.TUNFreq;
GridChanged := (FController.FTXSpecRefLevel <> T.TXSpecRefLevel)
or (FController.FTXSpecRange <> T.TXSpecRange)
or (FController.FTXSpecGridStep <> T.TXSpecGridStep);
FController.FTXSettings := T;
NewMicByte := FController.BuildMicLineSelectByte;
// TX-grid в момент правки — обновляем рабочие поля и (если на передаче) пушим в FSpecView
FController.FTXSpecRefLevel := FController.FTXSettings.TXSpecRefLevel;
FController.FTXSpecRange := FController.FTXSettings.TXSpecRange;
if FController.FTXSettings.TXSpecGridStep > 0 then
FController.FTXSpecGridStep := FController.FTXSettings.TXSpecGridStep;
FController.SetTXSettings(T, False);
if GridChanged and FController.FTransmitting then
ApplySpecViewGridFromState;
FController.ApplyTXSettingsToDSP;
// Low/High из вкладки Transmit — та же полоска фильтра на спектре: кромки
// берём уже пересчитанными движком (знак боковой) и на передаче перерисовываем.
PushFilterEdgesToView;
if FController.FTransmitting then FSpectrumDirty := True;
if (OldMicByte <> NewMicByte) or (OldAtt <> FController.FTXSettings.AttOnTX) then
FController.SendDUCSpecificFromSettings;
// TUN-параметры live: если идёт tune — обновить тон/drive, иначе просто запомнить.
if FController.FTuning then
begin
if (OldTUNFreq <> FController.FTXSettings.TUNFreq) and FController.FWDSPReady then
FController.FDSPEngine.SetTXTone(True, FController.FTXSettings.TUNFreq, 1.0);
if OldTUNLevel <> FController.FTXSettings.TUNLevel then
begin
FController.FDriveLevel := CalcDriveByte;
if FController.FWDSPReady then
FController.FDSPEngine.SetDriveLevel(FController.FTXSettings.TUNLevel / 100.0);
if FController.FNetwork.Connected and FController.FNetwork.Running then
begin
FController.FNetwork.UpdateState(XvtrTranslate(FController.FCenterFreq), FController.TXTuneFreqHz, FController.FDriveLevel,
FController.FTransmitting, True, True, FController.FTuning, FController.FTwoTone);
FController.FNetwork.SendFullHP;
end;
end;
end;
// Правка «звуковых» полей — это правка активного профиля: отдельной кнопки
// «сохранить» нет, профиль ведётся за живым состоянием (см. TTXProfile).
FController.StoreActiveTXProfile;
// Сохраняем сразу — настройки per-device, попадают в hpsdr_settings.json
if FController.FDevConnected then
begin
FController.FSettings.SaveTX(FController.FDevMAC, FController.FTXSettings);
FController.FSettings.SaveTXProfiles(FController.FDevMAC, FController.FTXProfiles);
FController.FSettings.Save;
end;
end;
procedure TMainForm.OnCWSettingsChange(const C: TCWSettings);
+69
View File
@@ -691,6 +691,11 @@ type
function TXProfileCount: Integer;
function TXProfileName(Idx: Integer): string;
function ActiveTXProfile: Integer;
// Единая дверь для правки TX-настроек снаружи (вкладка Transmit, CAT, web):
// применяет запись к движку/железу, дописывает активный профиль и персистит.
// Notify=False — вызывающий сам отрисует изменения (так делает MainForm,
// иначе rfTXProfile перезагрузил бы форму настроек прямо под руками).
procedure SetTXSettings(const T: TTXSettings; Notify: Boolean = True);
// Auto=True — переключение сделала автоматика привязок; ручной выбор
// (дропдаун, список настроек) дополнительно ЗАПОМИНАЕТСЯ за текущей парой
// «источник + модуляция» (BindTXProfileToCurrentMode).
@@ -787,6 +792,9 @@ type
// Громкость / mute / drive / аттенюатор
procedure SetVolume(V: Integer);
procedure VolumeBy(Delta: Integer);
// Громкость self-monitor'а на передаче отдельно от RX-громкости: слайдер
// правит её только когда MonitoringTX, а CAT (ZZTM) — в любой момент.
procedure SetTXMonVolume(V: Integer);
// True — сейчас звучит self-monitor даунлинка на передаче (TX + DUP + RX MUTE
// off). В этом контексте SetVolume/слайдер правят FTxMonVolume, иначе FVolume.
function MonitoringTX: Boolean;
@@ -4683,6 +4691,14 @@ end;
procedure TRadioController.VolumeBy(Delta: Integer);
begin SetVolume(ActiveVolume + Delta); end;
procedure TRadioController.SetTXMonVolume(V: Integer);
// Адресно правит громкость self-monitor'а. Слайдер добирается до неё только на
// передаче (SetVolume через ActiveVolume), CAT-клиенту такой контекст не нужен.
begin
FTxMonVolume := EnsureRange(V, 0, 100);
if MonitoringTX then ApplyActiveVolume;
end;
procedure TRadioController.SetMute(On_: Boolean);
begin
FMuted := On_;
@@ -5531,6 +5547,59 @@ begin
FSettings.Save;
end;
procedure TRadioController.SetTXSettings(const T: TTXSettings; Notify: Boolean);
// Одна дверь для правки TX-настроек — по образцу SetCWSettings. Клиенту
// (вкладка Transmit, CAT, web) достаточно отдать запись целиком: применение к
// WDSP, перепосыл DUC Specific при смене mic-битов/ATT, живое обновление TUN,
// запись в активный профиль и персист — здесь.
var
OldMicByte: Byte;
OldAtt, OldTUNLevel, OldTUNFreq: Integer;
begin
OldMicByte := BuildMicLineSelectByte;
OldAtt := FTXSettings.AttOnTX;
OldTUNLevel := FTXSettings.TUNLevel;
OldTUNFreq := FTXSettings.TUNFreq;
FTXSettings := T;
// TX-сетка спектра — рабочие поля рендера; их перерисовку заказывает вызывающий.
FTXSpecRefLevel := FTXSettings.TXSpecRefLevel;
FTXSpecRange := FTXSettings.TXSpecRange;
if FTXSettings.TXSpecGridStep > 0 then FTXSpecGridStep := FTXSettings.TXSpecGridStep;
ApplyTXSettingsToDSP;
// Маршрутизация микрофона и ATT on TX живут в железе (DUC Specific), WDSP тут
// ни при чём — пакет перепосылаем только когда байты реально поменялись.
if (BuildMicLineSelectByte <> OldMicByte) or (OldAtt <> FTXSettings.AttOnTX) then
SendDUCSpecificFromSettings;
// TUN-параметры live: идёт настройка — обновить тон/уровень, иначе просто запомнить.
if FTuning then
begin
if (OldTUNFreq <> FTXSettings.TUNFreq) and FWDSPReady then
FDSPEngine.SetTXTone(True, FTXSettings.TUNFreq, 1.0);
if OldTUNLevel <> FTXSettings.TUNLevel then
begin
FDriveLevel := CalcDriveByte;
if FWDSPReady then
FDSPEngine.SetDriveLevel(EnsureRange(FTXSettings.TUNLevel, 0, 100) / 100.0);
if FNetwork.Connected and FNetwork.Running then
begin
FNetwork.UpdateState(XvtrTranslate(FCenterFreq), TXTuneFreqHz, FDriveLevel,
FTransmitting, True, True, FTuning, FTwoTone);
FNetwork.SendFullHP;
end;
end;
end;
// Правка «звуковых» полей — это правка активного профиля: отдельной кнопки
// «сохранить» нет, профиль ведётся за живым состоянием (см. TTXProfile).
StoreActiveTXProfile;
if FDevConnected and Assigned(FSettings) then
begin
FSettings.SaveTX(FDevMAC, FTXSettings);
FSettings.SaveTXProfiles(FDevMAC, FTXProfiles);
FSettings.Save;
end;
if Notify then Changed(rfTXProfile);
end;
procedure TRadioController.StoreActiveTXProfile(Persist: Boolean = False);
// Живое состояние → активный профиль. Зовётся на каждой правке TX-настроек и
// на смене drive; Persist=False не трогает диск (drive ездит слайдером).