fix(cat): align Andromeda panel mapping with real G2 hardware (Thetis)

Button/encoder indices follow Thetis MakeNewAndromedaDataset (our 0-based
index = Thetis Number - 1), verified against andromeda_test/AndDecode.pas.
The old map assumed sequential 0,1,2.. and truncated at 32; the real panel
sends sparse indices up to 47.

- AndromedaMap: AND_MAX_BUTTONS 32->48, renumbered button/encoder tables;
  new actions abVFOAtoB/abVFOBtoA/abVFOLock/abStartStop/abShift.
- RadioController: VFO Lock (FVfoLock, rfVfoLock, SetVfoLock, gate in
  TuneActiveBy).
- AndromedaPanel: wire A>B/B>A/SDR-ON/Lock; Shift band-keypad layer
  (#28 latch, #29..39 -> SetBand 160m..6m, non-sticky); aiVFOLock/aiShift
  indicators.
- Filter High/Low (#4/#5) left as width approximation per decision.
- doc/ANDROMEDA.md updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-29 16:11:12 +03:00
co-authored by Claude Opus 4.8
parent 2d7290e44d
commit 0e550dd9f9
4 changed files with 179 additions and 53 deletions
+75 -31
View File
@@ -24,7 +24,12 @@ type
TAndButton = (
abNone, abMOX, abTune, abBandUp, abBandDown, abModeUp, abModeDown,
abMute, abNB, abNR, abSNB, abANF, abVFOSplit, abVFOSwap, abCTUN,
abCTCSS, abSquelch, abFilterUp, abFilterDown);
abCTCSS, abSquelch, abFilterUp, abFilterDown,
abVFOAtoB, // копировать VFO A → B (Thetis eBBVFOAtoB)
abVFOBtoA, // копировать VFO B → A (Thetis eBBVFOBtoA)
abVFOLock, // блокировка перестройки VFO (Thetis eBBVFOLockOnOff)
abStartStop, // старт/стоп SDR (Thetis eBBStartStop)
abShift); // модификатор band-keypad (Thetis eBBShift) — обрабатывается в панели
// Параметр, управляемый поворотным энкодером панели.
TAndEncoder = (
@@ -39,43 +44,82 @@ type
const
// Размеры дефолтных таблиц (кнопки/энкодеры нумеруются с 0 после разбора ZZZP/ZZZE).
AND_MAX_BUTTONS = 32;
AND_MAX_BUTTONS = 48;
AND_MAX_ENCODERS = 20;
// Раскладка кнопок: индекс = номер кнопки (0-based), значение = действие.
// Неназначенные → abNone. Дефолт ewsdr (правится при появлении конкретной панели).
// Нумерация совпадает с дефолтом Thetis (MakeNewAndromedaDataset): наш 0-based
// индекс = «Pushbutton Number» Thetis 1. Проверено на реальной панели
// (см. andromeda_test/AndDecode.pas). Неназначенные / отсутствующий тракт → abNone.
AND_BUTTON_MAP: array[0..AND_MAX_BUTTONS-1] of TAndButton = (
abMOX, // 0
abTune, // 1
abBandUp, // 2
abBandDown, // 3
abModeUp, // 4
abModeDown, // 5
abNB, // 6
abNR, // 7
abANF, // 8
abSNB, // 9
abVFOSplit, // 10
abVFOSwap, // 11
abCTUN, // 12
abMute, // 13
abCTCSS, // 14
abSquelch, // 15
abFilterUp, // 16
abFilterDown, // 17
abNone, abNone, abNone, abNone, abNone, abNone, abNone, abNone,
abNone, abNone, abNone, abNone, abNone, abNone);
abMute, // 0 RX1 Mute
abNone, // 1
abNone, // 2 RX2 Mute — нет второго приёмника
abNone, // 3
abNone, // 4
abNone, // 5
abNone, // 6
abNone, // 7
abNone, // 8
abNone, // 9
abNone, // 10
abNone, // 11
abNone, // 12
abNone, // 13
abNone, // 14
abNone, // 15
abNone, // 16
abNone, // 17
abNone, // 18
abNone, // 19
abNone, // 20
abNone, // 21
abNone, // 22
abNone, // 23
abNone, // 24
abNone, // 25
abNone, // 26
abNone, // 27
abShift, // 28 Shift (band-keypad модификатор)
abBandUp, // 29 Band + (под shift → 160m)
abModeUp, // 30 Mode + (под shift → 80m)
abFilterUp, // 31 Filter + (под shift → 60m)
abBandDown, // 32 Band - (под shift → 40m)
abModeDown, // 33 Mode - (под shift → 30m)
abFilterDown, // 34 Filter - (под shift → 20m)
abVFOAtoB, // 35 A>B (под shift → 17m)
abVFOBtoA, // 36 B>A (под shift → 15m)
abVFOSplit, // 37 Split (под shift → 12m)
abNone, // 38 (под shift → 10m)
abNone, // 39 (под shift → 6m)
abNone, // 40 (под shift → GEN, нет в ewsdr)
abNone, // 41 RIT/XIT toggle — нет RIT/XIT
abVFOSwap, // 42 Toggle A/B
abVFOLock, // 43 VFO Lock
abCTUN, // 44 CTUNE
abStartStop, // 45 SDR ON (start/stop)
abMOX, // 46 MOX
abTune); // 47 TUN
// Раскладка энкодеров: индекс = номер энкодера (0-based), значение = параметр.
// Нумерация = «Encoder Number» Thetis 1 (дефолт MakeNewAndromedaDataset).
// Энкодер #1 в Thetis — AGC Level (слайдер RF), поэтому aeAGCLevel.
// #4/#5 на панели — Filter High/Low (независимые края), но в ewsdr фильтр
// только симметричный (SetFilterBW): #4 крутит ширину, #5 пока не задействован.
AND_ENCODER_MAP: array[0..AND_MAX_ENCODERS-1] of TAndEncoder = (
aeAFGain, // 0
aeAGCLevel, // 1
aeDrive, // 2
aeSquelch, // 3
aeFilterWidth, // 4
aeNone, aeNone, aeNone, aeNone, aeNone,
aeNone, aeNone, aeNone, aeNone, aeNone,
aeNone, aeNone, aeNone, aeNone, aeMulti);
aeAFGain, // 0 RX1 AF Gain
aeAGCLevel, // 1 RX1 AGC Level (Thetis «RF»)
aeNone, // 2 RX2 AF — нет второго приёмника
aeNone, // 3 RX2 AGC
aeFilterWidth, // 4 Filter High → ширина фильтра (краёв нет)
aeNone, // 5 Filter Low — не реализован
aeNone, // 6 Diversity gain
aeNone, // 7 Diversity phase
aeNone, // 8 RIT
aeNone, // 9 XIT
aeMulti, // 10 Multifunction
aeDrive, // 11 TX Drive
aeNone, aeNone, aeNone, aeNone, aeNone, aeNone, aeNone, aeNone);
// Номер LED (ZZZI nn) для каждого индикатора; 0 = панель этот индикатор не имеет.
// 1..11 — дефолт Thetis; 12..17 — функции ewsdr на свободных слотах.