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.