From a8a192a3a3b03b867ef1c5ec6c00a1611fe2b1b8 Mon Sep 17 00:00:00 2001 From: Uladzimir Karpenka Date: Thu, 4 Jun 2026 21:17:50 +0300 Subject: [PATCH] Phase 3 (batch 14): route VFO swap / A>B / B>A through controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Filled the three VFO-transfer commands (the skeletons were also backwards: VfoACopyB stored A:=B etc). - VfoSwap: swaps A/B, retunes the receiver to the active VFO freq (center=freq, shift 0), HF band-detect, network push. Fires rfVfoA/rfVfoB/rfBand. UI handler is thin (+ ruler-cache invalidate, since a swap is a large freq jump). - VfoACopyB (A>B): delegates to SetVfoB(FVfoA) — store B:=A, retune when B active, render via rfVfoB. - VfoBCopyA (B>A): copies B->A; when A active goes through SetVfoA, else just fires rfVfoA. The desktop B>A handler still calls ApplyVfoA for the active-A case to preserve channel orchestration (auto-CTCSS / pre-channel drive), matching the original (A>B never had that path). Net simplification; builds clean, links. Co-Authored-By: Claude Opus 4.8 --- MainForm.pas | 67 +++++++-------------------------------------- RadioController.pas | 37 +++++++++++++++++++++---- 2 files changed, 41 insertions(+), 63 deletions(-) diff --git a/MainForm.pas b/MainForm.pas index 40f49f9..b2caeb8 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -5395,78 +5395,31 @@ begin end; procedure TMainForm.BtnVfoSwapClick(Sender: TObject); -var - Tmp: Double; - BandIdx: Integer; - ActiveFreq: Int64; begin - // Меняем частоты местами - Tmp := FController.FVfoA; FController.FVfoA := FController.FVfoB; FController.FVfoB := Tmp; - - // Определяем новую частоту активного VFO - if FController.FActiveVfo = 0 then ActiveFreq := Round(FController.FVfoA) - else ActiveFreq := Round(FController.FVfoB); - - // Перестраиваем приёмник - FController.FCenterFreq := ActiveFreq; - if FController.FWDSPReady then FController.FDSPEngine.SetShift(0.0); - if FController.FNetwork.Connected and FController.FNetwork.Running then - begin - FController.FNetwork.UpdateState(XvtrTranslate(FController.FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FController.FDriveLevel, FController.FTransmitting, True, True); - FController.FNetwork.SendFullHP; - end; - - // Обновляем кнопку диапазона - BandIdx := FreqToBandIdx(ActiveFreq); - if (BandIdx >= 0) and (BandIdx <> FController.FCurrentBand) then - begin - StyleButton(BtnBand[FController.FCurrentBand], False); - FController.FCurrentBand := BandIdx; - StyleButton(BtnBand[FController.FCurrentBand], True); - end; - + // Своп + перестройка — в контроллере; рендер дисплеев/спектра/band — через + // OnControllerState(rfVfoA/rfVfoB/rfBand). Кэш линейки сбрасываем здесь + // (большой скачок частоты — позиции тиков меняются). + FController.VfoSwap; FSpecView.InvalidateRulerCache; - UpdateVfoDisplay; - SyncSpecViewFreq; - FSpecView.DrawSpectrum; - PbSpectrum.Invalidate; if PbRuler <> nil then PbRuler.Invalidate; end; procedure TMainForm.BtnVfoACopyBClick(Sender: TObject); begin - // A>B: копируем частоту A в B (VFO-B получает частоту VFO-A) - FController.FVfoB := FController.FVfoA; - if FController.FActiveVfo = 1 then - begin - // B активен — перестраиваем приёмник на новую частоту B - FController.FCenterFreq := Round(FController.FVfoB); - if FController.FWDSPReady then FController.FDSPEngine.SetShift(0.0); - if FController.FNetwork.Connected and FController.FNetwork.Running then - begin - FController.FNetwork.UpdateState(XvtrTranslate(FController.FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FController.FDriveLevel, FController.FTransmitting, True, True); - FController.FNetwork.SendFullHP; - end; - FSpecView.InvalidateRulerCache; - SyncSpecViewFreq; - FSpecView.DrawSpectrum; PbSpectrum.Invalidate; - if PbRuler <> nil then PbRuler.Invalidate; - end; - FreqDispB.Frequency := Round(FController.FVfoB); - UpdateVfoDisplay; + // A>B: B получает частоту A. Команда сохраняет B, перестраивает если B + // активен, рендерит через OnControllerState(rfVfoB). + FController.VfoACopyB; end; procedure TMainForm.BtnVfoBCopyAClick(Sender: TObject); begin - // B>A: копируем частоту B в A (VFO-A получает частоту VFO-B) + // B>A: A получает частоту B. При активном A идём через ApplyVfoA (сохраняем + // канальную оркестрацию); иначе только сохраняем + рендер дисплея. FController.FVfoA := FController.FVfoB; if FController.FActiveVfo = 0 then - ApplyVfoA(Round(FController.FVfoA)) // A активен — перестраиваем приёмник + ApplyVfoA(Round(FController.FVfoA)) else - begin FreqDispA.Frequency := Round(FController.FVfoA); - UpdateVfoDisplay; - end; end; function TMainForm.ActiveTXFreqHz: Double; diff --git a/RadioController.pas b/RadioController.pas index d709084..39c44fd 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -672,14 +672,39 @@ procedure TRadioController.SetCenter(Hz: Double); begin FCenterFreq := Hz; Changed(rfCenterFreq); { TODO wiring } end; procedure TRadioController.VfoSwap; -var T: Double; -begin T := FVfoA; FVfoA := FVfoB; FVfoB := T; Changed(rfVfoA); Changed(rfVfoB); { TODO wiring } end; +// Меняем VFO A/B местами и перестраиваем приёмник на новую частоту активного +// VFO (центр=частота, shift 0 — CTUN-оффсет после свопа теряет смысл). +var + T: Double; + ActiveFreq: Double; + BandIdx: Integer; +begin + T := FVfoA; FVfoA := FVfoB; FVfoB := T; + ActiveFreq := ActiveVfoHz; + FCenterFreq := ActiveFreq; + if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(0.0); + BandIdx := FreqToBandIdx(ActiveFreq); + if (BandIdx >= 0) and (BandIdx <> FCurrentBand) then + begin + FCurrentBand := BandIdx; + Changed(rfBand); + end; + PushNetworkState; + Changed(rfVfoA); + Changed(rfVfoB); +end; -procedure TRadioController.VfoACopyB; -begin FVfoA := FVfoB; Changed(rfVfoA); { TODO wiring } end; +procedure TRadioController.VfoACopyB; // A>B: частота A копируется в B +begin + SetVfoB(FVfoA); // сохраняет B:=A, перестраивает если B активен, рендер rfVfoB +end; -procedure TRadioController.VfoBCopyA; -begin FVfoB := FVfoA; Changed(rfVfoB); { TODO wiring } end; +procedure TRadioController.VfoBCopyA; // B>A: частота B копируется в A +begin + FVfoA := FVfoB; + if FActiveVfo = 0 then SetVfoA(FVfoA) // A активен — перестраиваем приёмник + else Changed(rfVfoA); // A неактивен — только рендер дисплея +end; procedure TRadioController.SetMode(M: Integer); begin