mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix: persist CTun center + save VHF/UHF bands (Pluto); QO-100 transverter template
CTun position was lost on band restore / restart, and VHF/UHF bands were never saved on Pluto. - SaveCurrentBand: the >61 MHz guard (HPSDR HF-only) skipped saving native Pluto VHF/UHF bands → 2m/70cm reverted to defaults. Now HPSDR-only; Pluto saves VU-plan bands (FreqToBandIdx guards cross-band pollution). - Persist DDC center for CTun: new TBandSettings.CenterHz (+ JSON center_hz) and TXvtrEntry.LastCenterHz (+ last_center_hz). RestoreBand / ActivateXvtr restore the saved center when CTun is on and the offset fits the span, instead of forcing center := VFO (which re-centered the receiver). - UpdateFreqDisplayMax: freq-display upper bound from active transverter's FreqEnd (lets QO-100 show 10 GHz past the 6 GHz Pluto cap). - QO-100 transverter template (slot 2, disabled): downlink 10489.5–10490.0, LO 9750. MigrateXvtrTemplate injects it into the first free slot for devices that already have a saved xvtr config (template was otherwise masked by the loaded slots). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+24
-13
@@ -534,6 +534,7 @@ type
|
|||||||
WidebandFill, SpectrumFill: Boolean);
|
WidebandFill, SpectrumFill: Boolean);
|
||||||
procedure ApplyFPS(FPS: Integer);
|
procedure ApplyFPS(FPS: Integer);
|
||||||
procedure ApplyFreqMhzDigits(Digits: Integer);
|
procedure ApplyFreqMhzDigits(Digits: Integer);
|
||||||
|
procedure UpdateFreqDisplayMax; // верхняя граница FreqDisplay (XVTR/Pluto/HF)
|
||||||
|
|
||||||
published
|
published
|
||||||
// Обработчики событий формы — должны быть в published для RTTI/LFM
|
// Обработчики событий формы — должны быть в published для RTTI/LFM
|
||||||
@@ -1188,6 +1189,7 @@ begin
|
|||||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||||
if BtnXvtrBand[i] <> nil then
|
if BtnXvtrBand[i] <> nil then
|
||||||
StyleButton(BtnXvtrBand[i], i = FController.FCurrentXvtr);
|
StyleButton(BtnXvtrBand[i], i = FController.FCurrentXvtr);
|
||||||
|
UpdateFreqDisplayMax; // трансвертер может быть >6 ГГц (QO-100)
|
||||||
// Wideband-вид + web-зеркало xvtr (ранее в обёртках Activate/Deactivate).
|
// Wideband-вид + web-зеркало xvtr (ранее в обёртках Activate/Deactivate).
|
||||||
// rfXvtr эмитят ТОЛЬКО ActivateXvtr/DeactivateXvtr — состояние финальное.
|
// rfXvtr эмитят ТОЛЬКО ActivateXvtr/DeactivateXvtr — состояние финальное.
|
||||||
UpdateWidebandFrequencyView;
|
UpdateWidebandFrequencyView;
|
||||||
@@ -5539,30 +5541,39 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.ApplyFreqMhzDigits(Digits: Integer);
|
procedure TMainForm.ApplyFreqMhzDigits(Digits: Integer);
|
||||||
const
|
|
||||||
MaxFreqs: array[3..5] of Int64 = (999999999, 9999999999, 99999999999);
|
|
||||||
begin
|
begin
|
||||||
Digits := EnsureRange(Digits, 3, 5);
|
Digits := EnsureRange(Digits, 3, 5);
|
||||||
FFreqMhzDigits := Digits;
|
FFreqMhzDigits := Digits;
|
||||||
FController.FLoadedGlobal.FreqMhzDigits := Digits; // зеркало в persist-буфер контроллера
|
FController.FLoadedGlobal.FreqMhzDigits := Digits; // зеркало в persist-буфер контроллера
|
||||||
FreqDispA.MinMhzDigits := Digits;
|
FreqDispA.MinMhzDigits := Digits;
|
||||||
FreqDispB.MinMhzDigits := Digits;
|
FreqDispB.MinMhzDigits := Digits;
|
||||||
// Pluto/VHF/UHF: верхняя граница из Caps (до 6 ГГц), иначе HF по числу цифр.
|
UpdateFreqDisplayMax; // верхняя граница: активный XVTR / Pluto Caps / HF по цифрам
|
||||||
if FController.IsPluto then
|
|
||||||
begin
|
|
||||||
FreqDispA.MaxFreq := Round(FController.BackendCaps.MaxFreqHz);
|
|
||||||
FreqDispB.MaxFreq := Round(FController.BackendCaps.MaxFreqHz);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
FreqDispA.MaxFreq := MaxFreqs[Digits];
|
|
||||||
FreqDispB.MaxFreq := MaxFreqs[Digits];
|
|
||||||
end;
|
|
||||||
if Assigned(FWebServer) then
|
if Assigned(FWebServer) then
|
||||||
FWebServer.FreqMhzDigits := Digits;
|
FWebServer.FreqMhzDigits := Digits;
|
||||||
LayoutTopVfoBlock;
|
LayoutTopVfoBlock;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.UpdateFreqDisplayMax;
|
||||||
|
// Верхняя граница FreqDisplay. Активный трансвертер (XVTR/QO-100) может показывать
|
||||||
|
// частоты выше диапазона железа (напр. QO-100 — 10.5 ГГц) → берём его FreqEnd.
|
||||||
|
// Иначе Pluto — из Caps (до 6 ГГц), HPSDR — по числу MHz-цифр.
|
||||||
|
const
|
||||||
|
MaxFreqs: array[3..5] of Int64 = (999999999, 9999999999, 99999999999);
|
||||||
|
var
|
||||||
|
hi: Int64; xi: Integer;
|
||||||
|
begin
|
||||||
|
xi := FController.FCurrentXvtr;
|
||||||
|
if (xi >= 0) and (xi < CFG_XVTR_COUNT) then
|
||||||
|
hi := Round(FController.FXvtrSettings.Entries[xi].FreqEnd) + 1000000 // +1 МГц запас
|
||||||
|
else if FController.IsPluto then
|
||||||
|
hi := Round(FController.BackendCaps.MaxFreqHz)
|
||||||
|
else
|
||||||
|
hi := MaxFreqs[EnsureRange(FFreqMhzDigits, 3, 5)];
|
||||||
|
if hi < 1000000 then hi := MaxFreqs[3];
|
||||||
|
if FreqDispA <> nil then FreqDispA.MaxFreq := hi;
|
||||||
|
if FreqDispB <> nil then FreqDispB.MaxFreq := hi;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMainForm.BtnSettingsClick(Sender: TObject);
|
procedure TMainForm.BtnSettingsClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
SF: TSettingsForm;
|
SF: TSettingsForm;
|
||||||
|
|||||||
+28
-6
@@ -1050,6 +1050,7 @@ begin
|
|||||||
Result.AGCMode := FAGCMode;
|
Result.AGCMode := FAGCMode;
|
||||||
Result.AGCTop := FAGCTop;
|
Result.AGCTop := FAGCTop;
|
||||||
Result.CTun := FCTun;
|
Result.CTun := FCTun;
|
||||||
|
Result.CenterHz := FCenterFreq; // DDC-центр → восстановим offset CTun при загрузке
|
||||||
Result.SpanHz := FSpanHz;
|
Result.SpanHz := FSpanHz;
|
||||||
Result.FMSQOn := FFMSQOn;
|
Result.FMSQOn := FFMSQOn;
|
||||||
Result.FMSQLevel := FFMSQLevel;
|
Result.FMSQLevel := FFMSQLevel;
|
||||||
@@ -1088,6 +1089,7 @@ begin
|
|||||||
FXvtrSettings.Entries[i].LastFMRptDir := FFMRptDir;
|
FXvtrSettings.Entries[i].LastFMRptDir := FFMRptDir;
|
||||||
FXvtrSettings.Entries[i].LastFMRptOffsetHz := FFMRptOffsetHz;
|
FXvtrSettings.Entries[i].LastFMRptOffsetHz := FFMRptOffsetHz;
|
||||||
FXvtrSettings.Entries[i].LastCTun := FCTun;
|
FXvtrSettings.Entries[i].LastCTun := FCTun;
|
||||||
|
FXvtrSettings.Entries[i].LastCenterHz := FCenterFreq;
|
||||||
FXvtrSettings.Entries[i].LastAGCMode := FAGCMode;
|
FXvtrSettings.Entries[i].LastAGCMode := FAGCMode;
|
||||||
FXvtrSettings.Entries[i].LastAGCTop := FAGCTop;
|
FXvtrSettings.Entries[i].LastAGCTop := FAGCTop;
|
||||||
FXvtrSettings.Entries[i].LastCTCSSAutoActive := FFMCTCSSAutoActive;
|
FXvtrSettings.Entries[i].LastCTCSSAutoActive := FFMCTCSSAutoActive;
|
||||||
@@ -1096,9 +1098,11 @@ begin
|
|||||||
FSettings.SaveXvtr(FDevMAC, FXvtrSettings);
|
FSettings.SaveXvtr(FDevMAC, FXvtrSettings);
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
// Не сохраняем, если VFO ушёл в VHF/UHF (например, после канала на 2м без
|
// HPSDR: приёмник только HF — если VFO ушёл в VHF/UHF (напр. канал на 2м без
|
||||||
// XVTR) — иначе HF-кэш диапазона перезапишется VHF-частотой.
|
// XVTR), не сохраняем, иначе HF-кэш диапазона перезапишется VHF-частотой.
|
||||||
if FVfoA > 61000000 then Exit;
|
// Pluto: VHF/UHF — нативные диапазоны (VU-план), сохранять обязательно;
|
||||||
|
// от перезаписи чужим диапазоном защищает FreqToBandIdx-проверка ниже.
|
||||||
|
if (not IsPluto) and (FVfoA > 61000000) then Exit;
|
||||||
B := MakeBandSettings;
|
B := MakeBandSettings;
|
||||||
// Bandstack: VFO A и B независимы и могут стоять на разных бэндах. В кэш
|
// Bandstack: VFO A и B независимы и могут стоять на разных бэндах. В кэш
|
||||||
// ЭТОГО бэнда пишем только ту частоту VFO, что реально в нём — иначе чужая
|
// ЭТОГО бэнда пишем только ту частоту VFO, что реально в нём — иначе чужая
|
||||||
@@ -1262,7 +1266,14 @@ begin
|
|||||||
ApplyBandDSP(B);
|
ApplyBandDSP(B);
|
||||||
|
|
||||||
// --- VFO / drive (только RestoreBand — bandstack-путь VFO не трогает) ---
|
// --- VFO / drive (только RestoreBand — bandstack-путь VFO не трогает) ---
|
||||||
FCenterFreq := B.VfoA;
|
// При CTun восстанавливаем сохранённый DDC-центр, чтобы VFO остался на своём
|
||||||
|
// месте в полосе (а не прыгал в центр). Берём только если offset влезает в
|
||||||
|
// текущий span — иначе (сменился sample rate / битый конфиг) центрируем на VFO.
|
||||||
|
// ApplyTuneCore в SetVfoA при необходимости сам прокрутит центр к краю.
|
||||||
|
if FCTun and (B.CenterHz > 0) and (Abs(B.VfoA - B.CenterHz) < FSpanHz / 2) then
|
||||||
|
FCenterFreq := B.CenterHz
|
||||||
|
else
|
||||||
|
FCenterFreq := B.VfoA;
|
||||||
FVfoB := B.VfoB;
|
FVfoB := B.VfoB;
|
||||||
FVfoA := B.VfoA;
|
FVfoA := B.VfoA;
|
||||||
FDriveLevel := CalcDriveByte;
|
FDriveLevel := CalcDriveByte;
|
||||||
@@ -1808,8 +1819,19 @@ begin
|
|||||||
// VFO: B — своя сохранённая частота слота (клэмп в диапазон); A = visible.
|
// VFO: B — своя сохранённая частота слота (клэмп в диапазон); A = visible.
|
||||||
FVfoB := EnsureRange(E.LastFreqB, E.FreqBegin, E.FreqEnd);
|
FVfoB := EnsureRange(E.LastFreqB, E.FreqBegin, E.FreqEnd);
|
||||||
FVfoA := Vis;
|
FVfoA := Vis;
|
||||||
FCenterFreq := Vis;
|
// При CTun восстанавливаем сохранённый DDC-центр, чтобы VFO остался на своём
|
||||||
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(0.0);
|
// месте в полосе (а не прыгал в центр). Берём только если offset влезает в
|
||||||
|
// текущий span — иначе центрируемся на видимой частоте.
|
||||||
|
if FCTun and (E.LastCenterHz > 0) and (Abs(Vis - E.LastCenterHz) < FSpanHz / 2) then
|
||||||
|
begin
|
||||||
|
FCenterFreq := E.LastCenterHz;
|
||||||
|
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(Vis - FCenterFreq);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
FCenterFreq := Vis;
|
||||||
|
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(0.0);
|
||||||
|
end;
|
||||||
FDriveLevel := CalcDriveByte;
|
FDriveLevel := CalcDriveByte;
|
||||||
PushNetworkState;
|
PushNetworkState;
|
||||||
|
|
||||||
|
|||||||
+45
-1
@@ -54,6 +54,7 @@ type
|
|||||||
AGCMode: Integer;
|
AGCMode: Integer;
|
||||||
AGCTop: Integer;
|
AGCTop: Integer;
|
||||||
CTun: Boolean;
|
CTun: Boolean;
|
||||||
|
CenterHz: Double; // DDC-центр при CTun (восстановление offset VFO в полосе)
|
||||||
SpanHz: Double;
|
SpanHz: Double;
|
||||||
FMSQOn: Boolean;
|
FMSQOn: Boolean;
|
||||||
FMSQLevel: Integer; // 0..100 → WDSP threshold 0.0..0.5
|
FMSQLevel: Integer; // 0..100 → WDSP threshold 0.0..0.5
|
||||||
@@ -172,6 +173,7 @@ type
|
|||||||
LastFMStepOn: Boolean;
|
LastFMStepOn: Boolean;
|
||||||
LastFMStepIdx: Integer;
|
LastFMStepIdx: Integer;
|
||||||
LastCTun: Boolean;
|
LastCTun: Boolean;
|
||||||
|
LastCenterHz: Double; // Hz — DDC-центр при CTun (восстановление offset VFO)
|
||||||
LastAGCMode: Integer;
|
LastAGCMode: Integer;
|
||||||
LastAGCTop: Integer;
|
LastAGCTop: Integer;
|
||||||
LastFMRptDir: Integer;
|
LastFMRptDir: Integer;
|
||||||
@@ -293,6 +295,8 @@ type
|
|||||||
procedure JW(O: TJSONObject; const K: string; V: Double); overload;
|
procedure JW(O: TJSONObject; const K: string; V: Double); overload;
|
||||||
procedure JW(O: TJSONObject; const K: string; V: Boolean); overload;
|
procedure JW(O: TJSONObject; const K: string; V: Boolean); overload;
|
||||||
procedure JWS(O: TJSONObject; const K: string; const V: string);
|
procedure JWS(O: TJSONObject; const K: string; const V: string);
|
||||||
|
procedure MigrateXvtrTemplate(var X: TXvtrSettings;
|
||||||
|
const AName: string; ABegin, AEnd, ALO: Double);
|
||||||
public
|
public
|
||||||
constructor Create(const FilePath: string = '');
|
constructor Create(const FilePath: string = '');
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@@ -381,6 +385,7 @@ begin
|
|||||||
B.AGCMode := 1;
|
B.AGCMode := 1;
|
||||||
B.AGCTop := 90;
|
B.AGCTop := 90;
|
||||||
B.CTun := False;
|
B.CTun := False;
|
||||||
|
B.CenterHz := 0; // 0 = нет сохранённого центра → центрировать на VFO
|
||||||
B.SpanHz := 192000;
|
B.SpanHz := 192000;
|
||||||
B.FMSQOn := False;
|
B.FMSQOn := False;
|
||||||
B.FMSQLevel := 30;
|
B.FMSQLevel := 30;
|
||||||
@@ -695,6 +700,7 @@ begin
|
|||||||
Bands[i].AGCMode := JI(BObj,'agc_mode', Bands[i].AGCMode);
|
Bands[i].AGCMode := JI(BObj,'agc_mode', Bands[i].AGCMode);
|
||||||
Bands[i].AGCTop := JI(BObj,'agc_top', Bands[i].AGCTop);
|
Bands[i].AGCTop := JI(BObj,'agc_top', Bands[i].AGCTop);
|
||||||
Bands[i].CTun := JB(BObj,'ctun', Bands[i].CTun);
|
Bands[i].CTun := JB(BObj,'ctun', Bands[i].CTun);
|
||||||
|
Bands[i].CenterHz := JD(BObj,'center_hz', Bands[i].CenterHz);
|
||||||
Bands[i].SpanHz := JD(BObj,'span_hz', Bands[i].SpanHz);
|
Bands[i].SpanHz := JD(BObj,'span_hz', Bands[i].SpanHz);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -781,7 +787,7 @@ begin
|
|||||||
JW(O,'mode',B.Mode);
|
JW(O,'mode',B.Mode);
|
||||||
JW(O,'filter_idx',B.FilterIdx); JW(O,'filter_bw',B.FilterBW);
|
JW(O,'filter_idx',B.FilterIdx); JW(O,'filter_bw',B.FilterBW);
|
||||||
JW(O,'agc_mode',B.AGCMode); JW(O,'agc_top',B.AGCTop);
|
JW(O,'agc_mode',B.AGCMode); JW(O,'agc_top',B.AGCTop);
|
||||||
JW(O,'ctun',B.CTun); JW(O,'span_hz',B.SpanHz);
|
JW(O,'ctun',B.CTun); JW(O,'center_hz',B.CenterHz); JW(O,'span_hz',B.SpanHz);
|
||||||
JW(O,'fmsq_on',B.FMSQOn); JW(O,'fmsq_level',B.FMSQLevel);
|
JW(O,'fmsq_on',B.FMSQOn); JW(O,'fmsq_level',B.FMSQLevel);
|
||||||
JW(O,'ctcss_on',B.CTCSSOn); JW(O,'ctcss_idx',B.CTCSSToneIdx);
|
JW(O,'ctcss_on',B.CTCSSOn); JW(O,'ctcss_idx',B.CTCSSToneIdx);
|
||||||
JW(O,'fmstep_on',B.FMStepOn); JW(O,'fmstep_idx',B.FMStepIdx);
|
JW(O,'fmstep_on',B.FMStepOn); JW(O,'fmstep_idx',B.FMStepIdx);
|
||||||
@@ -805,6 +811,7 @@ begin
|
|||||||
B.AGCMode := JI(O,'agc_mode', B.AGCMode);
|
B.AGCMode := JI(O,'agc_mode', B.AGCMode);
|
||||||
B.AGCTop := JI(O,'agc_top', B.AGCTop);
|
B.AGCTop := JI(O,'agc_top', B.AGCTop);
|
||||||
B.CTun := JB(O,'ctun', B.CTun);
|
B.CTun := JB(O,'ctun', B.CTun);
|
||||||
|
B.CenterHz := JD(O,'center_hz', B.CenterHz);
|
||||||
B.SpanHz := JD(O,'span_hz', B.SpanHz);
|
B.SpanHz := JD(O,'span_hz', B.SpanHz);
|
||||||
B.FMSQOn := JB(O,'fmsq_on', B.FMSQOn);
|
B.FMSQOn := JB(O,'fmsq_on', B.FMSQOn);
|
||||||
B.FMSQLevel := JI(O,'fmsq_level', B.FMSQLevel);
|
B.FMSQLevel := JI(O,'fmsq_level', B.FMSQLevel);
|
||||||
@@ -1223,6 +1230,7 @@ begin
|
|||||||
X.Entries[i].LastFMStepOn := True;
|
X.Entries[i].LastFMStepOn := True;
|
||||||
X.Entries[i].LastFMStepIdx := 3; // 25 kHz
|
X.Entries[i].LastFMStepIdx := 3; // 25 kHz
|
||||||
X.Entries[i].LastCTun := False;
|
X.Entries[i].LastCTun := False;
|
||||||
|
X.Entries[i].LastCenterHz := 0.0;
|
||||||
X.Entries[i].LastAGCMode := 1;
|
X.Entries[i].LastAGCMode := 1;
|
||||||
X.Entries[i].LastAGCTop := 90;
|
X.Entries[i].LastAGCTop := 90;
|
||||||
X.Entries[i].LastFMRptDir := 0;
|
X.Entries[i].LastFMRptDir := 0;
|
||||||
@@ -1243,6 +1251,14 @@ begin
|
|||||||
X.Entries[1].LOOffset := 404000000;
|
X.Entries[1].LOOffset := 404000000;
|
||||||
X.Entries[1].LastFreq := 432200000;
|
X.Entries[1].LastFreq := 432200000;
|
||||||
X.Entries[1].LastFreqB := 433000000;
|
X.Entries[1].LastFreqB := 433000000;
|
||||||
|
// QO-100 (Es'hail-2) NB downlink: 10489.500–10490.000 МГц, LO 9750 МГц.
|
||||||
|
// RX-трансвертер: tune = downlink − LO. Калибровать LOError по маяку.
|
||||||
|
X.Entries[2].ButtonText := 'QO-100';
|
||||||
|
X.Entries[2].FreqBegin := 10489500000;
|
||||||
|
X.Entries[2].FreqEnd := 10490000000;
|
||||||
|
X.Entries[2].LOOffset := 9750000000;
|
||||||
|
X.Entries[2].LastFreq := 10489750000;
|
||||||
|
X.Entries[2].LastFreqB := 10489750000;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSettingsManager.LoadXvtr(const MAC: array of Byte;
|
function TSettingsManager.LoadXvtr(const MAC: array of Byte;
|
||||||
@@ -1286,6 +1302,7 @@ begin
|
|||||||
X.Entries[i].LastFMStepOn := JB(EObj, 'last_fmstep_on', X.Entries[i].LastFMStepOn);
|
X.Entries[i].LastFMStepOn := JB(EObj, 'last_fmstep_on', X.Entries[i].LastFMStepOn);
|
||||||
X.Entries[i].LastFMStepIdx := EnsureRange(JI(EObj, 'last_fmstep_idx', X.Entries[i].LastFMStepIdx), 0, 3);
|
X.Entries[i].LastFMStepIdx := EnsureRange(JI(EObj, 'last_fmstep_idx', X.Entries[i].LastFMStepIdx), 0, 3);
|
||||||
X.Entries[i].LastCTun := JB(EObj, 'last_ctun', X.Entries[i].LastCTun);
|
X.Entries[i].LastCTun := JB(EObj, 'last_ctun', X.Entries[i].LastCTun);
|
||||||
|
X.Entries[i].LastCenterHz := JD(EObj, 'last_center_hz', X.Entries[i].LastCenterHz);
|
||||||
X.Entries[i].LastAGCMode := EnsureRange(JI(EObj, 'last_agc_mode', X.Entries[i].LastAGCMode), 0, 4);
|
X.Entries[i].LastAGCMode := EnsureRange(JI(EObj, 'last_agc_mode', X.Entries[i].LastAGCMode), 0, 4);
|
||||||
X.Entries[i].LastAGCTop := EnsureRange(JI(EObj, 'last_agc_top', X.Entries[i].LastAGCTop), 0, 120);
|
X.Entries[i].LastAGCTop := EnsureRange(JI(EObj, 'last_agc_top', X.Entries[i].LastAGCTop), 0, 120);
|
||||||
X.Entries[i].LastFMRptDir := EnsureRange(JI(EObj, 'last_fmrpt_dir', X.Entries[i].LastFMRptDir), 0, 2);
|
X.Entries[i].LastFMRptDir := EnsureRange(JI(EObj, 'last_fmrpt_dir', X.Entries[i].LastFMRptDir), 0, 2);
|
||||||
@@ -1300,6 +1317,32 @@ begin
|
|||||||
(X.Entries[i].LastFreqB > X.Entries[i].FreqEnd) then
|
(X.Entries[i].LastFreqB > X.Entries[i].FreqEnd) then
|
||||||
X.Entries[i].LastFreqB := (X.Entries[i].FreqBegin + X.Entries[i].FreqEnd) / 2.0;
|
X.Entries[i].LastFreqB := (X.Entries[i].FreqBegin + X.Entries[i].FreqEnd) / 2.0;
|
||||||
end;
|
end;
|
||||||
|
// Миграция: на устройствах с уже сохранённым xvtr-конфигом шаблон QO-100 из
|
||||||
|
// DefaultXvtr был перекрыт загруженными слотами. Если слота 'QO-100' нет —
|
||||||
|
// вписать шаблон (disabled) в первый свободный слот, чтобы он был в таблице.
|
||||||
|
MigrateXvtrTemplate(X, 'QO-100', 10489500000, 10490000000, 9750000000);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSettingsManager.MigrateXvtrTemplate(var X: TXvtrSettings;
|
||||||
|
const AName: string; ABegin, AEnd, ALO: Double);
|
||||||
|
var
|
||||||
|
i, freeIdx: Integer;
|
||||||
|
begin
|
||||||
|
freeIdx := -1;
|
||||||
|
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||||
|
begin
|
||||||
|
if SameText(X.Entries[i].ButtonText, AName) then Exit; // уже есть — ничего не делаем
|
||||||
|
if (freeIdx < 0) and (not X.Entries[i].Enabled) and
|
||||||
|
(Trim(X.Entries[i].ButtonText) = '') then
|
||||||
|
freeIdx := i;
|
||||||
|
end;
|
||||||
|
if freeIdx < 0 then Exit; // нет свободных слотов
|
||||||
|
X.Entries[freeIdx].ButtonText := AName;
|
||||||
|
X.Entries[freeIdx].FreqBegin := ABegin;
|
||||||
|
X.Entries[freeIdx].FreqEnd := AEnd;
|
||||||
|
X.Entries[freeIdx].LOOffset := ALO;
|
||||||
|
X.Entries[freeIdx].LastFreq := (ABegin + AEnd) / 2.0;
|
||||||
|
X.Entries[freeIdx].LastFreqB := (ABegin + AEnd) / 2.0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSettingsManager.SaveXvtr(const MAC: array of Byte;
|
procedure TSettingsManager.SaveXvtr(const MAC: array of Byte;
|
||||||
@@ -1335,6 +1378,7 @@ begin
|
|||||||
JW(EObj, 'last_fmstep_on', X.Entries[i].LastFMStepOn);
|
JW(EObj, 'last_fmstep_on', X.Entries[i].LastFMStepOn);
|
||||||
JW(EObj, 'last_fmstep_idx',X.Entries[i].LastFMStepIdx);
|
JW(EObj, 'last_fmstep_idx',X.Entries[i].LastFMStepIdx);
|
||||||
JW(EObj, 'last_ctun', X.Entries[i].LastCTun);
|
JW(EObj, 'last_ctun', X.Entries[i].LastCTun);
|
||||||
|
JW(EObj, 'last_center_hz', X.Entries[i].LastCenterHz);
|
||||||
JW(EObj, 'last_agc_mode', X.Entries[i].LastAGCMode);
|
JW(EObj, 'last_agc_mode', X.Entries[i].LastAGCMode);
|
||||||
JW(EObj, 'last_agc_top', X.Entries[i].LastAGCTop);
|
JW(EObj, 'last_agc_top', X.Entries[i].LastAGCTop);
|
||||||
JW(EObj, 'last_fmrpt_dir', X.Entries[i].LastFMRptDir);
|
JW(EObj, 'last_fmrpt_dir', X.Entries[i].LastFMRptDir);
|
||||||
|
|||||||
Reference in New Issue
Block a user