mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
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:
co-authored by
Claude Opus 4.8
parent
24102343ea
commit
e09bc21bba
+77
-33
@@ -231,6 +231,10 @@ type
|
||||
function MakeBandSettings: TBandSettings;
|
||||
procedure SaveCurrentBand;
|
||||
procedure RestoreBand(BandIdx: Integer);
|
||||
// Применяет DSP-настройки диапазона (mode/filter/AGC/CTUN/FM) + шлёт события
|
||||
// рендера. НЕ трогает частоты VFO/центр — это переиспользуется как RestoreBand
|
||||
// (с загрузкой VFO), так и SetActiveVfo (bandstack: смена бэнда без сброса VFO).
|
||||
procedure ApplyBandDSP(const B: TBandSettings);
|
||||
|
||||
// Полный HP-кадр в радио (RX/TX freq через трансвертор + drive + MOX).
|
||||
// Вызывается командами смены частоты/центра и UI после правки drive.
|
||||
@@ -547,7 +551,9 @@ end;
|
||||
procedure TRadioController.SaveCurrentBand;
|
||||
// Сохраняет текущее состояние диапазона. В XVTR-режиме пишем в XVTR-слот
|
||||
// (HF band-cache не трогаем — там сохранён HF-диапазон до активации XVTR).
|
||||
var i: Integer;
|
||||
var
|
||||
i: Integer;
|
||||
B: TBandSettings;
|
||||
begin
|
||||
if not FDevConnected then Exit;
|
||||
if FCurrentXvtr >= 0 then
|
||||
@@ -556,6 +562,7 @@ begin
|
||||
begin
|
||||
i := FCurrentXvtr;
|
||||
FXvtrSettings.Entries[i].LastFreq := FVfoA;
|
||||
FXvtrSettings.Entries[i].LastFreqB := FVfoB;
|
||||
FXvtrSettings.Entries[i].LastMode := FMode;
|
||||
FXvtrSettings.Entries[i].LastFilterIdx := FFilter;
|
||||
FXvtrSettings.Entries[i].LastFMSQOn := FFMSQOn;
|
||||
@@ -578,20 +585,19 @@ begin
|
||||
// Не сохраняем, если VFO ушёл в VHF/UHF (например, после канала на 2м без
|
||||
// XVTR) — иначе HF-кэш диапазона перезапишется VHF-частотой.
|
||||
if FVfoA > 61000000 then Exit;
|
||||
FBandCache[FCurrentBand] := MakeBandSettings;
|
||||
B := MakeBandSettings;
|
||||
// Bandstack: VFO A и B независимы и могут стоять на разных бэндах. В кэш
|
||||
// ЭТОГО бэнда пишем только ту частоту VFO, что реально в нём — иначе чужая
|
||||
// частота (напр. VFO A на 40м при сохранении 30м) загрязнит memory бэнда.
|
||||
if FreqToBandIdx(FVfoA) <> FCurrentBand then B.VfoA := FBandCache[FCurrentBand].VfoA;
|
||||
if FreqToBandIdx(FVfoB) <> FCurrentBand then B.VfoB := FBandCache[FCurrentBand].VfoB;
|
||||
FBandCache[FCurrentBand] := B;
|
||||
FSettings.SaveBand(FDevMAC, FCurrentBand, FBandCache[FCurrentBand]);
|
||||
end;
|
||||
|
||||
procedure TRadioController.RestoreBand(BandIdx: Integer);
|
||||
// Загружает состояние диапазона из кэша, применяет к DSP и шлёт события рендера.
|
||||
// Финальную перестройку VFO A (с канальной оркестрацией) делает вызывающий
|
||||
// UI-путь через ApplyVfoA(FVfoA); здесь FVfoA лишь выставляется.
|
||||
var B: TBandSettings;
|
||||
procedure TRadioController.ApplyBandDSP(const B: TBandSettings);
|
||||
// DSP-настройки диапазона + события рендера. Частоты VFO/центр НЕ трогает.
|
||||
begin
|
||||
if (BandIdx < 0) or (BandIdx >= CFG_BAND_COUNT) then Exit;
|
||||
B := FBandCache[BandIdx];
|
||||
FCurrentBand := BandIdx;
|
||||
|
||||
// --- Режим ---
|
||||
FMode := B.Mode;
|
||||
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetMode(FMode);
|
||||
@@ -631,12 +637,6 @@ begin
|
||||
// --- Span (sample rate глобальный, не per-band — лишь ресинк) ---
|
||||
FSpanHz := FSampleRate;
|
||||
|
||||
// --- VFO / drive ---
|
||||
FCenterFreq := B.VfoA;
|
||||
FVfoB := B.VfoB;
|
||||
FVfoA := B.VfoA;
|
||||
FDriveLevel := CalcDriveByte;
|
||||
|
||||
// --- Рендер: единичные события (UI рисует через OnControllerState) ---
|
||||
Changed(rfBand);
|
||||
Changed(rfMode); // rfMode-рендер зовёт UpdateFilterButtons (FM-панели)
|
||||
@@ -651,6 +651,26 @@ begin
|
||||
Changed(rfFMStepIdx); // дропдаун шага + web + grid
|
||||
Changed(rfFMRpt);
|
||||
Changed(rfCTun);
|
||||
end;
|
||||
|
||||
procedure TRadioController.RestoreBand(BandIdx: Integer);
|
||||
// Загружает состояние диапазона из кэша, применяет к DSP и шлёт события рендера.
|
||||
// Финальную перестройку VFO A (с канальной оркестрацией) делает вызывающий
|
||||
// UI-путь через ApplyVfoA(FVfoA); здесь FVfoA лишь выставляется.
|
||||
var B: TBandSettings;
|
||||
begin
|
||||
if (BandIdx < 0) or (BandIdx >= CFG_BAND_COUNT) then Exit;
|
||||
B := FBandCache[BandIdx];
|
||||
FCurrentBand := BandIdx;
|
||||
|
||||
ApplyBandDSP(B);
|
||||
|
||||
// --- VFO / drive (только RestoreBand — bandstack-путь VFO не трогает) ---
|
||||
FCenterFreq := B.VfoA;
|
||||
FVfoB := B.VfoB;
|
||||
FVfoA := B.VfoA;
|
||||
FDriveLevel := CalcDriveByte;
|
||||
|
||||
Changed(rfVfoB);
|
||||
// rfVfoA НЕ шлём: финальную перестройку делает ApplyVfoA в UI-обёртке.
|
||||
end;
|
||||
@@ -743,9 +763,21 @@ procedure TRadioController.SetVfoB(Hz: Double);
|
||||
// ApplyTuneCore (с учётом CTUN), детектим диапазон и толкаем в сеть. Если B
|
||||
// неактивен (split, слушаем A) — только сохраняем частоту (для TX).
|
||||
// Рендер FreqDispB/спектра — в UI через OnControllerState(rfVfoB).
|
||||
var BandIdx: Integer;
|
||||
var
|
||||
BandIdx: Integer;
|
||||
NewFreq: Int64;
|
||||
begin
|
||||
FVfoB := Hz;
|
||||
NewFreq := Round(Hz);
|
||||
// Клэмп в пределах XVTR-band (как в SetVfoA) — VFO B тоже не уходит за край.
|
||||
if (FCurrentXvtr >= 0) and (FCurrentXvtr < CFG_XVTR_COUNT) and
|
||||
FXvtrSettings.Entries[FCurrentXvtr].Enabled then
|
||||
begin
|
||||
if NewFreq < FXvtrSettings.Entries[FCurrentXvtr].FreqBegin then
|
||||
NewFreq := Round(FXvtrSettings.Entries[FCurrentXvtr].FreqBegin);
|
||||
if NewFreq > FXvtrSettings.Entries[FCurrentXvtr].FreqEnd then
|
||||
NewFreq := Round(FXvtrSettings.Entries[FCurrentXvtr].FreqEnd);
|
||||
end;
|
||||
FVfoB := NewFreq;
|
||||
if FActiveVfo = 1 then
|
||||
begin
|
||||
ApplyTuneCore(FVfoB);
|
||||
@@ -766,17 +798,36 @@ end;
|
||||
|
||||
procedure TRadioController.SetActiveVfo(Idx: Integer);
|
||||
// Переключение активного (RX) VFO с перестройкой приёмника на его частоту.
|
||||
// CTUN: если частота нового VFO видна в текущем окне — только меняем shift
|
||||
// Bandstack: если активируемый VFO стоит на ДРУГОМ ham-бэнде — сохраняем
|
||||
// покидаемый бэнд и восстанавливаем DSP-настройки нового (mode/filter/AGC/CTUN/
|
||||
// FM). Частоты обоих VFO при этом НЕ трогаем — каждый VFO несёт свой диапазон.
|
||||
// CTUN (того же бэнда): если частота нового VFO видна в окне — только shift
|
||||
// (DDC/сеть не трогаем); иначе CTUN сбрасывается и центрируемся на частоте.
|
||||
// Рендер (дисплеи/спектр/band/CTUN-кнопка) — в UI через OnControllerState.
|
||||
var
|
||||
ActiveFreq: Double;
|
||||
HalfSpan, Offset: Double;
|
||||
FreqVisible: Boolean;
|
||||
BandIdx: Integer;
|
||||
FreqVisible, NeedPush: Boolean;
|
||||
NewBand: Integer;
|
||||
begin
|
||||
FActiveVfo := Idx;
|
||||
ActiveFreq := ActiveVfoHz;
|
||||
NeedPush := False;
|
||||
|
||||
// --- Bandstack: активируемый VFO на другом ham-бэнде → восстановить бэнд ---
|
||||
if FCurrentXvtr < 0 then
|
||||
begin
|
||||
NewBand := FreqToBandIdx(ActiveFreq);
|
||||
if (NewBand >= 0) and (NewBand <> FCurrentBand) then
|
||||
begin
|
||||
SaveCurrentBand; // сохранить покидаемый бэнд
|
||||
FCurrentBand := NewBand;
|
||||
ApplyBandDSP(FBandCache[NewBand]); // mode/filter/AGC/CTUN/FM + рендер
|
||||
FCenterFreq := ActiveFreq; // центр на активную (CTUN центрируется тут)
|
||||
FDriveLevel := CalcDriveByte; // PA-калибровка нового бэнда
|
||||
NeedPush := True; // DDC-центр сменился → толкнуть в сеть
|
||||
end;
|
||||
end;
|
||||
|
||||
if FCTun then
|
||||
begin
|
||||
@@ -785,7 +836,7 @@ begin
|
||||
FreqVisible := (Offset > -HalfSpan) and (Offset < HalfSpan);
|
||||
if FreqVisible then
|
||||
begin
|
||||
// Частота видна — просто сдвигаем демодулятор, DDC/сеть не трогаем.
|
||||
// Частота видна — просто сдвигаем демодулятор.
|
||||
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(Offset);
|
||||
end
|
||||
else
|
||||
@@ -795,7 +846,7 @@ begin
|
||||
FBandCache[FCurrentBand].CTun := False;
|
||||
FCenterFreq := ActiveFreq;
|
||||
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(0.0);
|
||||
PushNetworkState;
|
||||
NeedPush := True;
|
||||
Changed(rfCTun);
|
||||
end;
|
||||
end
|
||||
@@ -803,17 +854,10 @@ begin
|
||||
begin
|
||||
FCenterFreq := ActiveFreq;
|
||||
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(0.0);
|
||||
PushNetworkState;
|
||||
end;
|
||||
|
||||
// Детект диапазона по новой частоте (без пересчёта drive — как исторически).
|
||||
BandIdx := FreqToBandIdx(ActiveFreq);
|
||||
if (BandIdx >= 0) and (BandIdx <> FCurrentBand) then
|
||||
begin
|
||||
FCurrentBand := BandIdx;
|
||||
Changed(rfBand);
|
||||
NeedPush := True;
|
||||
end;
|
||||
|
||||
if NeedPush then PushNetworkState;
|
||||
Changed(rfActiveVfo);
|
||||
end;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user