From 249881a5797217c400d3134c913e97c61cd0b697 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Tue, 4 Aug 2026 19:23:49 +0300 Subject: [PATCH] =?UTF-8?q?fix(tx):=20=D0=BF=D1=80=D0=BE=D1=84=D0=B8=D0=BB?= =?UTF-8?q?=D1=8C=20=D0=BF=D0=BE=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8F?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=E2=80=94=20=D0=B4=D0=B5=D1=82=D0=B5=D1=80?= =?UTF-8?q?=D0=BC=D0=B8=D0=BD=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=B5=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D0=BE=20+?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B1=D0=B5=D0=BB=D1=8B=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Три связанных правки по отзывам с эфира. 1. Активный профиль однозначно определяется парой «TX-источник + его модуляция»: ячейка таблицы заполнена — её профиль, пуста — базовый (первый в списке). Прежняя «точка возврата» (запомнить, что было активно до автоматики) ломалась в самом частом случае: заходя в FM, оператор обычно УЖЕ имел активным профиль FM с прошлого захода, точка возврата записывала его же, и выход в USB ничего не менял. Плюс она жила только в сессии и после перезапуска не работала вовсе. Поле FTXProfPreAuto удалено. Ручной выбор (дропдаун TX, список настроек, пилюля флага) дополнительно ЗАПОМИНАЕТСЯ за текущей парой — это и есть обещанное «профиль помнится по виду модуляции»: раньше в таблицу писала только пилюля, а выбор дропдауном следа не оставлял. В DMR и FMRAW автоматика активный профиль не трогает вовсе. 2. Смена диапазона и вход/выход трансвертера меняют режим главного в ApplyBandDSP (FMode := B.Mode) МИМО SetMode, поэтому автоматика там не вызывалась и при переходе КВ↔трансвертер оставался профиль прошлого режима. Зовём и оттуда. Заодно: FDSPEngine.SetMode насильно ставит FTXMode в режим главного, а SetMode контроллера следом возвращает режим источника — ApplyBandDSP этого не делала, и передача со слайса после смены диапазона уезжала в чужую модуляцию. 3. Кнопка выбора TX-профиля гаснет, когда режим ИСТОЧНИКА передачи DMR или FMRAW (в DMR передатчика нет, в FMRAW профиль обходится); открытый список закрывается. Гейт по источнику, а не по главному: с главным в DMR можно передавать со слайса. Смена режима на слайсе теперь тоже пересчитывает доступность TX-контролов — это чинит и MOX/TUN/PS. Co-Authored-By: Claude Opus 5 --- MainForm.pas | 14 +++++++++++ RadioController.pas | 60 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/MainForm.pas b/MainForm.pas index 345051c..73dff86 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -3840,6 +3840,18 @@ begin TuneAllowed := MOXAllowed and (FController.ActiveTXMode <> MODE_FMRAW); BtnMOX.Enabled := MOXAllowed; BtnTUN.Enabled := TuneAllowed; + // Выбор TX-профиля: в DMR передатчика нет вовсе, в FM RAW профиль ни на что + // не влияет (ApplyTXModeSettings глушит там всю обработку). Гейт по режиму + // ИСТОЧНИКА передачи, а не главного приёмника: с главным в DMR можно + // передавать со слайса, и там профиль по-прежнему нужен. Run не требуем — + // профиль выбирается и оффлайн, как и на вкладке настроек. + if BtnTXProfile <> nil then + begin + BtnTXProfile.Enabled := + not (FController.ActiveTXMode in [MODE_DMR, MODE_FMRAW]); + if (not BtnTXProfile.Enabled) and (FTXProfileDropDown <> nil) then + FTXProfileDropDown.ClosePopup; // открытый список закрываем сами + end; UpdatePSButtons; end; @@ -6026,6 +6038,8 @@ begin FController.SetSliceModeBW(CurSliceId, Mode, FilterBW); PushFlagStateAllPans(CurSliceId); LayoutFlagsAllPans; + // Режим ИСТОЧНИКА передачи мог смениться — MOX/TUN/PS/профиль гейтятся им. + UpdateTXControlAvailability; Exit; end; // Main flag A and the left panel edit the same receiver. Use the public diff --git a/RadioController.pas b/RadioController.pas index af3a08b..a352dcf 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -594,7 +594,10 @@ type function TXProfileCount: Integer; function TXProfileName(Idx: Integer): string; function ActiveTXProfile: Integer; - procedure SelectTXProfile(Idx: Integer); + // Auto=True — переключение сделала автоматика привязок; ручной выбор + // (дропдаун, список настроек) дополнительно ЗАПОМИНАЕТСЯ за текущей парой + // «источник + модуляция» (BindTXProfileToCurrentMode). + procedure SelectTXProfile(Idx: Integer; Auto: Boolean = False); procedure StoreActiveTXProfile(Persist: Boolean = False); function AddTXProfile(const AName: string): Integer; // форк текущего звука procedure RenameTXProfile(Idx: Integer; const AName: string); @@ -604,6 +607,7 @@ type // звучит активный). Таблица у каждого флага своя: главный в FTXProfiles, // слайсы в своих записях. function FlagMode(SliceId: Integer): Integer; + procedure BindTXProfileToCurrentMode(Idx: Integer); // ручной выбор → в таблицу function SliceTXProfile(SliceId: Integer): Integer; procedure SetSliceTXProfile(SliceId, ProfIdx: Integer); function SliceTXProfileTable(SliceId: Integer): TTXProfModeTable; @@ -3631,6 +3635,16 @@ begin FFMRptOffsetHz := B.FMRptOffsetHz; if FFMRptOffsetHz <= 0 then FFMRptOffsetHz := RptDefaultOffsetHz(B.VfoA); + // --- TX-профиль под новый режим --- + // Смена диапазона и вход/выход трансвертера меняют режим ГЛАВНОГО здесь, а + // не через SetMode, поэтому автоматику привязок надо звать и отсюда — иначе + // при переходе КВ↔трансвертер оставался профиль прошлого режима. + if FTxSliceId = 0 then ApplyBoundTXProfile; + // FDSPEngine.SetMode выше насильно выставил TXA в режим главного приёмника, + // но передавать можем со слайса — возвращаем режим настоящего источника. + if FWDSPReady and Assigned(FDSPEngine) and (ActiveTXMode <> FMode) then + FDSPEngine.SetTXMode(ActiveTXMode); + // --- CTUN --- FCTun := B.CTun; if FWDSPReady and Assigned(FDSPEngine) and not FCTun then FDSPEngine.SetShift(0.0); @@ -4991,7 +5005,7 @@ begin if Persist then SaveTXProfilesToConfig; end; -procedure TRadioController.SelectTXProfile(Idx: Integer); +procedure TRadioController.SelectTXProfile(Idx: Integer; Auto: Boolean); var OldMic: Byte; NewDrive: Integer; @@ -5012,6 +5026,11 @@ begin SetDrive(NewDrive); if FTuning and FWDSPReady then FDSPEngine.SetDriveLevel(EnsureRange(FTXSettings.TUNLevel, 0, 100) / 100.0); + // ★Ручной выбор ЗАПОМИНАЕТСЯ за парой «источник передачи + его модуляция» — + // это и есть обещанное «профиль помнится по виду модуляции». Без этого в + // таблице оказывалось только то, что назначено пилюлей во флаге, а профиль, + // выбранный дропдауном в блоке TX, нигде не оставался следа. + if not Auto then BindTXProfileToCurrentMode(Idx); if FDevConnected and Assigned(FSettings) then begin FSettings.SaveTX(FDevMAC, FTXSettings); @@ -5094,6 +5113,23 @@ begin for m := 0 to CFG_MODE_MAX do Fix(FSlices[i].TXProfByMode[m]); end; +procedure TRadioController.BindTXProfileToCurrentMode(Idx: Integer); +// Пишет профиль в ячейку «текущий TX-источник + его модуляция». Отдельно от +// SetSliceTXProfile: там ещё и применение в эфир, а здесь профиль уже применён +// (нас зовут из SelectTXProfile), повторный ApplyBoundTXProfile был бы циклом. +var m, Slot: Integer; +begin + if (Idx < 0) or (Idx >= FTXProfiles.Count) then Exit; + m := FlagMode(FTxSliceId); + if FTxSliceId <= 0 then + FTXProfiles.MainByMode[m] := Idx // персист — общим блоком в SelectTXProfile + else + begin + Slot := FindSliceIndex(FTxSliceId); + if Slot >= 0 then FSlices[Slot].TXProfByMode[m] := Idx; + end; +end; + function TRadioController.FlagMode(SliceId: Integer): Integer; // Режим, в котором сейчас стоит этот флаг: у главного — FMode, у слайса — свой. var idx: Integer; @@ -5182,13 +5218,23 @@ begin end; procedure TRadioController.ApplyBoundTXProfile; -// Профиль текущего TX-источника → в эфир. Ничего не делает, если источник ни к -// чему не привязан (-1) или нужный профиль уже активен. -var P: Integer; +// Активный профиль ОДНОЗНАЧНО определяется парой «TX-источник + его модуляция»: +// ячейка таблицы заполнена → её профиль; +// ячейка пуста (−1) → базовый профиль (первый в списке). +// Фолбэк обязателен: без него профиль прошлого режима оставался висеть в новом +// (симптом «перешёл из FM в USB, а звучит FM»). Правило детерминированное — +// работает и после перезапуска, в отличие от «вернуть, что было до автоматики». +var P, M: Integer; begin + if FTXProfiles.Count = 0 then Exit; + M := FlagMode(FTxSliceId); + // В DMR передатчика нет, в FM RAW профиль ни на что не влияет + // (ApplyTXModeSettings глушит там всю обработку) — активный не трогаем вовсе, + // иначе заход в эти режимы молча перебивал бы выбор оператора. + if (M = MODE_DMR) or (M = MODE_FMRAW) then Exit; P := SliceTXProfile(FTxSliceId); - if (P < 0) or (P = FTXProfiles.ActiveIdx) then Exit; - SelectTXProfile(P); + if P < 0 then P := 0; + if P <> FTXProfiles.ActiveIdx then SelectTXProfile(P, True); end; procedure TRadioController.ResetTXProfilesToFactory;