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
+45
View File
@@ -39,16 +39,20 @@ type
FController: TRadioController;
FSend: TAndromedaSend;
FConnected: Boolean; // панель прислала версию (ZZZS)
FShiftActive: Boolean; // band-keypad модификатор (latched)
FIndState: array[0..20] of Integer; // кэш состояний LED: -1 неизв., 0/1
// scratch для маршалинга в поток контроллера
FPendingVfoSteps: Integer;
FPendingEnc: TAndEncoder;
FPendingStep: Integer;
FPendingButton: TAndButton;
FPendingBand: Integer;
procedure SyncVfo;
procedure SyncEncoder;
procedure SyncButton;
procedure SyncBand;
procedure SyncShiftLed;
procedure PushIndicator(Ind: TAndIndicator; State: Boolean);
procedure SendIndicatorNum(Num: Integer; State: Boolean);
@@ -126,15 +130,49 @@ begin
end;
procedure TAndromedaPanel.HandleButton(Btn: Integer; State, LongPress: Boolean);
// Раскладка зеркалит Thetis: кнопка Shift (0-based 28) — модификатор-защёлка;
// пока он активен, кнопки band-группы (29..40) выбирают диапазон напрямую
// (29→160m … 39→6m; 40=GEN в ewsdr нет). Остальные кнопки работают всегда,
// shift при их нажатии не снимается (non-sticky: снимается только band-нажатием).
var a: TAndButton;
begin
if not State then Exit; // реагируем на нажатие; отпускание/long-press — позже
a := ButtonAction(Btn);
if a = abShift then // toggle band-keypad
begin
FShiftActive := not FShiftActive;
FController.Invoke(@SyncShiftLed);
Exit;
end;
if FShiftActive and (Btn >= 29) and (Btn <= 40) then // band-keypad
begin
if (Btn >= 29) and (Btn <= 39) then // 160m..6m → SetBand 0..10
begin
FPendingBand := Btn - 29;
FController.Invoke(@SyncBand);
end;
FShiftActive := False; // non-sticky: снять shift
FController.Invoke(@SyncShiftLed);
Exit;
end;
if a = abNone then Exit;
FPendingButton := a;
FController.Invoke(@SyncButton);
end;
procedure TAndromedaPanel.SyncBand;
begin
FController.SetBand(FPendingBand);
end;
procedure TAndromedaPanel.SyncShiftLed;
begin
PushIndicator(aiShift, FShiftActive);
end;
procedure TAndromedaPanel.SyncButton;
begin
case FPendingButton of
@@ -151,6 +189,10 @@ begin
abANF: FController.SetANF(not FController.FANF);
abVFOSplit: FController.SetSplit(not FController.FSplitTxB);
abVFOSwap: FController.SetActiveVfo(1 - FController.FActiveVfo);
abVFOAtoB: FController.VfoACopyB;
abVFOBtoA: FController.VfoBCopyA;
abVFOLock: FController.SetVfoLock(not FController.FVfoLock);
abStartStop: FController.StartStop;
abCTUN: FController.SetCTun(not FController.FCTun);
abCTCSS: FController.SetFMCTCSS(not FController.FFMCTCSSOn);
abSquelch: FController.SetFMSquelch(not FController.FFMSQOn);
@@ -191,6 +233,8 @@ begin
PushIndicator(aiTune, FController.FTuning);
PushIndicator(aiCTune, FController.FCTun);
PushIndicator(aiVFOAB, FController.FActiveVfo = 1);
PushIndicator(aiVFOLock, FController.FVfoLock);
PushIndicator(aiShift, FShiftActive);
PushIndicator(aiSplit, FController.FSplitTxB);
PushIndicator(aiNB, FController.FNBMode > 0);
PushIndicator(aiNR, FController.FNRMode > 0);
@@ -206,6 +250,7 @@ begin
rfTransmitting: PushIndicator(aiMOX, FController.FTransmitting);
rfTuning: PushIndicator(aiTune, FController.FTuning);
rfCTun: PushIndicator(aiCTune, FController.FCTun);
rfVfoLock: PushIndicator(aiVFOLock, FController.FVfoLock);
rfActiveVfo: begin
PushIndicator(aiVFOAB, FController.FActiveVfo = 1);
PushIndicator(aiSplit, FController.FSplitTxB);