fix(filter): слот VAR переживает перезапуск в режиме трансвертера

Симптом: в XVTR-режиме выбрать VAR1, выключить и включить трансивер — фильтр
откатывался на заводской (в FM это NFM). Вне трансвертера всё сохранялось.

Причина: персист XVTR клампил last_filt диапазоном 0..9, оставшимся от эпохи
десяти пресетов. VAR1/VAR2 (10/11) при загрузке схлопывались в 9, а дальше
ClampFilterIdx видел индекс вне таблицы режима (у FM пресетов всего два) и по
своему правилу откатывался на заводской индекс — отсюда NFM. У band-cache
такой границы нет, поэтому в обычном режиме баг не проявлялся.

Граница поднята до FILT_SLOTS-1. Проверено round-trip-тестом SaveXvtr/LoadXvtr:
слот 10 сохраняется и читается как 10.

Проверены заодно остальные пути, где слот мог потеряться: band-cache (клэмпа
нет), каналы памяти (фильтр не хранят вовсе), рендер rfMode (сброс обёрнут
save/restore), web SetFilterBW, SanitizeFilterForMode. Клэмп 0..9 в CAT-командах
FW/SH/ZZBI намеренно оставлен — это ограничение протокола, а не хранения; VAR
снаружи доступен через ZZFL/ZZFH.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 13:22:56 +03:00
co-authored by Claude Opus 5
parent 25521a2d10
commit ce43116490
+5 -2
View File
@@ -340,7 +340,7 @@ type
LastFreq: Double; // Hz — последняя tuned visible частота VFO A (BandStack) LastFreq: Double; // Hz — последняя tuned visible частота VFO A (BandStack)
LastFreqB: Double; // Hz — последняя tuned visible частота VFO B LastFreqB: Double; // Hz — последняя tuned visible частота VFO B
LastMode: Integer; // Mode (LSB=0,USB=1,…FM=5) LastMode: Integer; // Mode (LSB=0,USB=1,…FM=5)
LastFilterIdx: Integer; // FM: 0=NFM, 1=WFM; иначе 0..FILT_COUNT-1 LastFilterIdx: Integer; // слот фильтра 0..FILT_SLOTS-1 (10/11 = VAR1/VAR2)
LastFMSQOn: Boolean; LastFMSQOn: Boolean;
LastFMSQLevel: Integer; LastFMSQLevel: Integer;
LastCTCSSOn: Boolean; LastCTCSSOn: Boolean;
@@ -2085,7 +2085,10 @@ begin
X.Entries[i].LastFreq := JD(EObj, 'last_freq', X.Entries[i].LastFreq); X.Entries[i].LastFreq := JD(EObj, 'last_freq', X.Entries[i].LastFreq);
X.Entries[i].LastFreqB := JD(EObj, 'last_freq_b', X.Entries[i].LastFreqB); X.Entries[i].LastFreqB := JD(EObj, 'last_freq_b', X.Entries[i].LastFreqB);
X.Entries[i].LastMode := EnsureRange(JI(EObj, 'last_mode', X.Entries[i].LastMode), CFG_MODE_MIN, CFG_MODE_MAX); X.Entries[i].LastMode := EnsureRange(JI(EObj, 'last_mode', X.Entries[i].LastMode), CFG_MODE_MIN, CFG_MODE_MAX);
X.Entries[i].LastFilterIdx := EnsureRange(JI(EObj, 'last_filt', X.Entries[i].LastFilterIdx), 0, 9); // Верхняя граница = FILT_SLOTS-1, а не 9: слоты VAR1/VAR2 (10/11) иначе
// схлопывались в 9, и при восстановлении трансвертера ClampFilterIdx
// видел индекс вне таблицы режима и откатывал на заводской фильтр.
X.Entries[i].LastFilterIdx := EnsureRange(JI(EObj, 'last_filt', X.Entries[i].LastFilterIdx), 0, FILT_SLOTS - 1);
X.Entries[i].LastFMSQOn := JB(EObj, 'last_fmsq_on', X.Entries[i].LastFMSQOn); X.Entries[i].LastFMSQOn := JB(EObj, 'last_fmsq_on', X.Entries[i].LastFMSQOn);
X.Entries[i].LastFMSQLevel := EnsureRange(JI(EObj, 'last_fmsq_lvl', X.Entries[i].LastFMSQLevel), 0, 100); X.Entries[i].LastFMSQLevel := EnsureRange(JI(EObj, 'last_fmsq_lvl', X.Entries[i].LastFMSQLevel), 0, 100);
X.Entries[i].LastCTCSSOn := JB(EObj, 'last_ctcss_on', X.Entries[i].LastCTCSSOn); X.Entries[i].LastCTCSSOn := JB(EObj, 'last_ctcss_on', X.Entries[i].LastCTCSSOn);