unit AndromedaMap;

{
  AndromedaMap.pas — таблицы раскладки передней панели Apache Labs Andromeda / G2.

  Только ДАННЫЕ: перечисления действий и дефолтные таблицы
  «номер кнопки → действие», «номер энкодера → параметр»,
  «индикатор → номер LED (ZZZI)». Без логики и без зависимостей от
  контроллера — этим занимается AndromedaPanel.pas.

  Соответствие протоколу Thetis:
    • действия кнопок/энкодеров — подмножество EButtonBarActions / EEncoderActions;
    • номера LED-индикаторов (ZZZI nn) зеркалят дефолтную таблицу Thetis
      (MakeNewAndromedaDataset): 1=MOX, 3=Tune, 7=CTUN и т.д. Свободные слоты
      12..17 заняты функциями ewsdr (Split/NB/NR/SNB/ANF/Squelch).
}

{$mode objfpc}{$H+}

interface

type
  // Действие кнопки панели (подмножество, поддержанное ewsdr).
  TAndButton = (
    abNone, abMOX, abTune, abBandUp, abBandDown, abModeUp, abModeDown,
    abMute, abNB, abNR, abSNB, abANF, abVFOSplit, abVFOSwap, abCTUN,
    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 = (
    aeNone, aeAFGain, aeAGCLevel, aeDrive, aeSquelch,
    aeFilterWidth, aeMulti);

  // Индикатор (LED) панели. Порядок зеркалит EIndicatorActions Thetis.
  TAndIndicator = (
    aiNone, aiMOX, aiTune, aiRIT, aiXIT, aiSplit, aiCTune, aiVFOSync,
    aiVFOAB, aiVFOLock, aiNB, aiNR, aiSNB, aiANF, aiSquelch,
    aiCompander, aiPuresignal, aiDiversity, aiATUReady, aiShift);

const
  // Размеры дефолтных таблиц (кнопки/энкодеры нумеруются с 0 после разбора ZZZP/ZZZE).
  AND_MAX_BUTTONS  = 48;
  AND_MAX_ENCODERS = 20;

  // Раскладка кнопок: индекс = номер кнопки (0-based), значение = действие.
  // Нумерация совпадает с дефолтом Thetis (MakeNewAndromedaDataset): наш 0-based
  // индекс = «Pushbutton Number» Thetis − 1. Проверено на реальной панели
  // (см. andromeda_test/AndDecode.pas). Неназначенные / отсутствующий тракт → abNone.
  AND_BUTTON_MAP: array[0..AND_MAX_BUTTONS-1] of TAndButton = (
    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   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 на свободных слотах.
  AND_INDICATOR_NUM: array[TAndIndicator] of Integer = (
    {aiNone}       0,
    {aiMOX}        1,
    {aiTune}       3,
    {aiRIT}        8,
    {aiXIT}        9,
    {aiSplit}      12,
    {aiCTune}      7,
    {aiVFOSync}    0,
    {aiVFOAB}      10,
    {aiVFOLock}    11,
    {aiNB}         13,
    {aiNR}         14,
    {aiSNB}        15,
    {aiANF}        16,
    {aiSquelch}    17,
    {aiCompander}  0,
    {aiPuresignal} 0,
    {aiDiversity}  0,
    {aiATUReady}   2,
    {aiShift}      6);

{ Возвращает действие для номера кнопки (0-based); abNone вне диапазона. }
function ButtonAction(BtnIndex: Integer): TAndButton;
{ Возвращает параметр для номера энкодера (0-based); aeNone вне диапазона. }
function EncoderParam(EncIndex: Integer): TAndEncoder;
{ Номер ZZZI для индикатора; 0 если панель его не отображает. }
function IndicatorNum(Ind: TAndIndicator): Integer;

implementation

function ButtonAction(BtnIndex: Integer): TAndButton;
begin
  if (BtnIndex >= 0) and (BtnIndex < AND_MAX_BUTTONS) then
    Result := AND_BUTTON_MAP[BtnIndex]
  else
    Result := abNone;
end;

function EncoderParam(EncIndex: Integer): TAndEncoder;
begin
  if (EncIndex >= 0) and (EncIndex < AND_MAX_ENCODERS) then
    Result := AND_ENCODER_MAP[EncIndex]
  else
    Result := aeNone;
end;

function IndicatorNum(Ind: TAndIndicator): Integer;
begin
  Result := AND_INDICATOR_NUM[Ind];
end;

end.
