{
  Copyright (C)
  2026 - Uladzimir Karpenka, EW8BAK

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
}

unit AndromedaMap;

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

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

  Таблицы соответствуют нумерации команд аппаратной панели. Для LED-индикаторов
  используются номера 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
    abVFOBtoA,    // копировать VFO B → A
    abVFOLock,    // блокировка перестройки VFO
    abStartStop,  // старт/стоп SDR
    abShift);     // модификатор band-keypad — обрабатывается в панели

  // Параметр, управляемый поворотным энкодером панели.
  TAndEncoder = (
    aeNone, aeAFGain, aeAGCLevel, aeDrive, aeSquelch,
    aeFilterWidth, aeFilterHigh, aeFilterLow, aeMulti);

  // Индикатор (LED) панели в порядке протокольной нумерации.
  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), значение = действие.
  // Внутренний индекс 0-based на единицу меньше номера кнопки в протоколе.
  // Нумерация проверена на реальной панели
  // (см. 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), значение = параметр.
  // Внутренний индекс на единицу меньше номера энкодера в протоколе.
  // Энкодер #1 управляет AGC Level, поэтому используется aeAGCLevel.
  // #4/#5 — Filter High/Low: настоящие независимые края (как на железе G2).
  // aeFilterWidth оставлен в перечислении для раскладок, где нужен один
  // энкодер «ширина» — в дефолтной раскладке не используется.
  AND_ENCODER_MAP: array[0..AND_MAX_ENCODERS-1] of TAndEncoder = (
    aeAFGain,      // 0   RX1 AF Gain
    aeAGCLevel,    // 1   RX1 AGC Level
    aeNone,        // 2   RX2 AF — нет второго приёмника
    aeNone,        // 3   RX2 AGC
    aeFilterHigh,  // 4   Filter High — верхний край
    aeFilterLow,   // 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 — базовая раскладка панели; 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.
