Fix active-VFO desync; add bandstack-on-VFO-switch and per-XVTR VFO-B

Active-VFO desync (batch 15 follow-up): DoConnectDevice loaded
FActiveVfo from settings but never re-rendered the highlight (it was
drawn once in FormCreate while the field was still 0) nor re-tuned the
receiver. Result on reconnect with B last-active: the engine (spectrum,
filter band, mouse tuning) ran on VFO B while the UI showed A active.
Now the connect path brings both the receiver and the highlight to the
actually-active VFO via SetActiveVfo, and RestoreBand's final retune
follows the active VFO (A -> ApplyVfoA, B -> SetVfoB) instead of always A.

Bandstack on VFO switch: switching the active VFO to one parked on a
different ham band now restores that band's DSP state (mode/filter/AGC/
CTUN/FM). Extracted ApplyBandDSP (the DSP half of RestoreBand, without
the VFO frequencies) and reused it from both RestoreBand and SetActiveVfo.
VFO frequencies stay independent (each VFO carries its own band);
continuous tuning across a band edge still does not recall (band button
only) as on real radios. SaveCurrentBand no longer writes a VFO frequency
into a band's memory unless that VFO is actually within the band, so a
40m VFO-A no longer pollutes 30m's stored VfoA.

Per-transverter VFO-B: TXvtrEntry gains LastFreqB (load/save/default +
range clamp). ActivateXvtrBand restores VFO B, Deactivate/SaveAllAndExit
persist it, and SetVfoB clamps to the transverter range like SetVfoA.
The connect-time guard that forced VFO A in XVTR is dropped since B is now
a valid, in-range frequency there too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Uladzimir Karpenka
2026-06-05 12:45:11 +03:00
co-authored by Claude Opus 4.8
parent 24102343ea
commit e09bc21bba
3 changed files with 114 additions and 40 deletions
+26 -5
View File
@@ -878,9 +878,14 @@ begin
FSpecView.ResetWfAvgBuf;
// Состояние + DSP + события рендера — в контроллере.
FController.RestoreBand(BandIdx);
// Финальная перестройка VFO A с канальной оркестрацией (auto-CTCSS,
// pre-channel drive) — через UI-путь ApplyVfoA.
ApplyVfoA(Round(FController.FVfoA));
// Финальная перестройка приёмника на АКТИВНЫЙ VFO. Если активен B — нельзя
// центрироваться на VFO A (иначе движок слушает A, а маркер/мышь — на B).
// VFO A идёт через ApplyVfoA (канальная оркестрация: auto-CTCSS, pre-channel
// drive); VFO B — через SetVfoB (перестройка + рендер rfVfoB).
if FController.FActiveVfo = 0 then
ApplyVfoA(Round(FController.FVfoA))
else
FController.SetVfoB(Round(FController.FVfoB));
end;
procedure TMainForm.SaveAllAndExit;
@@ -891,9 +896,12 @@ begin
FController.FSettings.SaveGlobal(FController.FDevMAC, MakeGlobalSettings);
if FController.FDevConnected then
FController.FSettings.SaveTX(FController.FDevMAC, FController.FTXSettings);
// Запомнить LastFreq XVTR для следующего запуска
// Запомнить LastFreq A/B XVTR для следующего запуска
if (FController.FCurrentXvtr >= 0) and (FController.FCurrentXvtr < CFG_XVTR_COUNT) then
FController.FXvtrSettings.Entries[FController.FCurrentXvtr].LastFreq := FController.FVfoA;
begin
FController.FXvtrSettings.Entries[FController.FCurrentXvtr].LastFreq := FController.FVfoA;
FController.FXvtrSettings.Entries[FController.FCurrentXvtr].LastFreqB := FController.FVfoB;
end;
FController.FSettings.SaveXvtr(FController.FDevMAC, FController.FXvtrSettings);
FController.FSettings.Save;
end;
@@ -4140,6 +4148,15 @@ begin
and FController.FXvtrSettings.Entries[G_Settings.LastXvtr].Enabled then
ActivateXvtrBand(G_Settings.LastXvtr);
// Активный VFO загружен из настроек (выше), но подсветку рисовали в FormCreate
// (тогда FActiveVfo ещё = 0 → A), а RestoreBand/ActivateXvtrBand перестраивают
// только VFO A. Приводим приёмник И подсветку к фактически активному VFO,
// иначе движок работает по B, а UI показывает активным A.
if FController.FActiveVfo = 1 then
FController.SetActiveVfo(1) // перестройка RX на VFO B + рендер (rfActiveVfo)
else
UpdateVfoDisplay;
SetStatusText(1, 'IP: ' + FController.FNetwork.Device.IPAddress);
SetStatusText(0, 'Board: ' + BoardTypeName(FController.FNetwork.Device.BoardType));
@@ -6562,6 +6579,9 @@ begin
// CTUN
FController.FCTun := E.LastCTun;
StyleButton(BtnCTun, FController.FCTun);
// VFO-B: своя сохранённая частота слота, клэмп в диапазон трансвертера.
FController.FVfoB := EnsureRange(E.LastFreqB, E.FreqBegin, E.FreqEnd);
FreqDispB.Frequency := Round(FController.FVfoB);
// VFO на видимую частоту; FController.FCenterFreq тоже visible
FController.FVfoA := Vis;
FController.FCenterFreq := Vis;
@@ -6600,6 +6620,7 @@ begin
if FController.FCurrentXvtr < CFG_XVTR_COUNT then
begin
FController.FXvtrSettings.Entries[FController.FCurrentXvtr].LastFreq := FController.FVfoA;
FController.FXvtrSettings.Entries[FController.FCurrentXvtr].LastFreqB := FController.FVfoB;
FController.FXvtrSettings.Entries[FController.FCurrentXvtr].LastMode := FController.FMode;
FController.FXvtrSettings.Entries[FController.FCurrentXvtr].LastFilterIdx := FController.FFilter;
FController.FXvtrSettings.Entries[FController.FCurrentXvtr].LastFMSQOn := FController.FFMSQOn;