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>
14 KiB
Поддержка передней панели Andromeda / G2 в EWSDR
Ветка разработки: feature/cat-commands-expansion.
Дата последнего обновления: 2026-06-26.
Документ описывает поддержку аппаратной передней панели Apache Labs
Andromeda / ANAN-G2 (поворотные энкодеры, кнопки, LED-индикаторы, LCD).
За эталон протокола взят Thetis (Andromeda/Andromeda.cs, CAT/CATCommands.cs).
См. также CAT_STATUS.md — общий статус CAT-подсистемы.
1. Что такое Andromeda и чем отличается от обычного CAT
Andromeda — это не отдельный набор команд, а двунаправленный протокол панели поверх CAT-фрейминга. В отличие от обычного CAT (реактивный «запрос → ответ»), панель требует, чтобы хост сам инициативно отправлял обновления подсветки.
ZZZD/ZZZU/ZZZE/ZZZP/ZZZS (панель → хост: ввод)
┌─────────┐ ───────────────────────────► ┌──────────┐
│ Панель │ │ EWSDR │
│ G2 / │ ◄─────────────────────────── │ (хост) │
│Andromeda│ ZZZI / ZZMF / ZZZS; └──────────┘
└─────────┘ (хост → панель: подсветка, LCD, рукопожатие)
| Направление | Команды | Назначение |
|---|---|---|
| Панель → хост | ZZZS<v> |
панель сообщает версию HW/SW (рукопожатие) |
ZZZU<nn> / ZZZD<nn> |
энкодер VFO повёрнут вверх/вниз на nn шагов | |
ZZZE<eees> |
энкодер #ee повёрнут (01–20 = +шаг, 51–70 = −шаг) | |
ZZZP<bbs> |
кнопка #bb: s=1 нажата, 2 long-press, 0 отпущена | |
| Хост → панель | ZZZI<nn><s> |
LED-индикатор #nn (00–19) вкл (1)/выкл (0) |
ZZMF<30 цифр> |
текст мультифункц. энкодера на LCD (пока не реализован) | |
ZZZS; |
запрос версии у панели |
2. Архитектура реализации
Логика панели вынесена в отдельные юниты; в существующих файлах — только тонкие хуки. Зависимости однонаправленные, без циклов.
┌────────────────────┐
serial-порт ──────► │ TCATEngine │ разбор ZZZ* → generic callbacks
(Andromeda) │ (CATEngine.pas) │ (OnPanelVfoStep/Encoder/Button/Version)
└─────────┬──────────┘
│ callbacks
┌─────────▼──────────┐ создаёт/связывает
│ TCATAdapter │ ◄───────────────────┐
│ (CATAdapter.pas) │ │
└─────────┬──────────┘ │
SendProc (ZZZI/ZZZS;) │ ▲ AddStateListener │
на Andromeda-порт ▼ │ (push индикаторов) │
┌────────────────────┐ ┌────────────┴───────┐
│ TAndromedaPanel │ ───────►│ TRadioController │
│ (AndromedaPanel.pas)│ Invoke │ (ядро) │
│ использует ▼ │ действия└────────────────────┘
│ AndromedaMap.pas │ (таблицы раскладки — только данные)
└────────────────────┘
| Файл | Роль |
|---|---|
AndromedaMap.pas |
Только данные: enum'ы TAndButton / TAndEncoder / TAndIndicator, дефолтные таблицы раскладки кнопок/энкодеров и номера LED (ZZZI). Без логики и зависимостей. |
AndromedaPanel.pas |
TAndromedaPanel — «мозг»: входящие события → действия контроллера (свой маршалинг через FController.Invoke); подписка на состояние контроллера → построение ZZZI → отправка через callback SendProc. Зависит только от RadioController + AndromedaMap. |
CATEngine.pas |
Разбор входящих ZZZD/ZZZU/ZZZE/ZZZP/ZZZS в 4 generic-callback'а TCATContext. Движок остаётся чистым парсером, про Andromeda «не знает». |
CATAdapter.pas |
Тонкий клей: создаёт панель, маршрутизирует callback'и движка в неё, даёт SendProc на Andromeda-порт, регистрирует панель как слушателя состояния, инициирует рукопожатие. |
CATSerial.pas |
Флаг Andromeda в конфиге порта + HasAndromeda / SendToAndromeda. |
RadioController.pas |
AddStateListener — multicast-наблюдатель состояния (push не «ворует» единственный OnStateChanged, занятый MainForm). |
Settings.pas / SettingsForm.pas / MainForm.pas |
Поле CATSerialAndromeda[0..3], персист, чекбокс на каждом serial-порту. |
Потоки
- Входящие хэндлеры (
HandleVfoStep/Encoder/Button/Version) зовутся из потока CAT-транспорта и маршалят действия в поток контроллера черезFController.Invoke(GUI =TThread.Synchronize). - Слушатель состояния и
SendProcработают из потока, вызвавшегоChanged(); отправка в порт потокобезопасна (serialSendStrпод своим локом).
3. Раскладка по умолчанию (AndromedaMap.pas)
Раскладка зашита в коде и зеркалит дефолтную таблицу Thetis
(MakeNewAndromedaDataset): наш 0-based индекс = «Pushbutton/Encoder Number»
Thetis − 1. Номера проверены на реальной панели (см.
andromeda_test/AndDecode.pas). Правится в AndromedaMap.pas.
Кнопки (ZZZP, индекс 0-based после разбора)
| # | Действие | # | Действие |
|---|---|---|---|
| 0 | RX1 Mute | 35 | A>B (под shift → 17m) |
| 28 | Shift (band-keypad) | 36 | B>A (под shift → 15m) |
| 29 | Band Up (под shift → 160m) | 37 | Split (под shift → 12m) |
| 30 | Mode Up (под shift → 80m) | 38 | (под shift → 10m) |
| 31 | Filter Up (под shift → 60m) | 39 | (под shift → 6m) |
| 32 | Band Down (под shift → 40m) | 42 | VFO Swap (toggle A/B) |
| 33 | Mode Down (под shift → 30m) | 43 | VFO Lock |
| 34 | Filter Down (под shift → 20m) | 44 | CTUN |
| 45 | SDR ON (start/stop) | ||
| 46 | MOX | ||
| 47 | TUN |
Не назначены (нет тракта в ewsdr): 2 (RX2 Mute), 40 (band GEN), 41 (RIT/XIT). NB/NR/ANF/SNB/CTCSS/Squelch у реальной панели на кнопках не выведены (в Thetis — на тачскрине), действия в enum сохранены для кастомной раскладки.
Shift / band-keypad
Кнопка #28 — модификатор-защёлка (как eBBShift в Thetis). Пока активен
(LED aiShift #6), кнопки band-группы #29..39 выбирают диапазон напрямую
(SetBand 0..10: 160m…6m); #40 = GEN — в ewsdr отсутствует. Снимается
повторным Shift либо автоматически после выбора диапазона (non-sticky).
Логика — в TAndromedaPanel.HandleButton.
Энкодеры (ZZZE, индекс 0-based)
| # | Параметр | Шаг |
|---|---|---|
| 0 | AF Gain (громкость) | ±1 |
| 1 | AGC-T (в Thetis — слайдер «RF») | ±1 dB |
| 4 | Filter High → ширина фильтра | ±50 Гц (AND_BW_STEP_HZ) |
| 11 | Drive (мощность) | ±1 % |
| VFO | энкодер VFO (ZZZU/ZZZD) |
±10 Гц/шаг (AND_VFO_STEP_HZ) |
#4/#5 на панели — независимые края фильтра (Filter High/Low). В ewsdr фильтр симметричный (
SetFilterBW), поэтому #4 крутит ширину, #5 пока не задействован. Энкодеры RX2 AF/AGC (#2/#3), diversity (#6/#7), RIT/XIT (#8/#9) — нет тракта.
Индикаторы (ZZZI, номера зеркалят дефолт Thetis)
| LED # | Индикатор | LED # | Индикатор |
|---|---|---|---|
| 1 | MOX | 12 | Split |
| 2 | ATU Ready (нет в ewsdr) | 13 | NB |
| 3 | Tune | 14 | NR |
| 6 | Shift | 15 | SNB |
| 7 | CTUN | 16 | ANF |
| 8/9 | RIT/XIT (нет) | 17 | Squelch |
| 10 | VFO A/B | ||
| 11 | VFO Lock |
Драйвятся реально: MOX, Tune, CTUN, VFO A/B, VFO Lock, Shift, Split, NB, NR, SNB, ANF, Squelch. Остальные слоты дефолтной таблицы Thetis (ATU/RIT/XIT) в ewsdr функций не имеют и не зажигаются.
4. Как включить
- Подключить панель как обычный serial CAT-порт (USB).
- Settings → CAT → выбрать нужный Serial Port, поставить Enable и параметры порта (скорость и т.д. — как требует панель).
- Поставить галку «Andromeda / G2 front panel» на этом порту.
- При применении настроек EWSDR пошлёт
ZZZS;; панель ответит версией — после этого включается push индикаторов и панель управляет радио.
Только один порт может быть Andromeda-портом (первый помеченный).
Настройки сохраняются ключами cat_serial_androm_N / ser_androm_N
(N = 0..3) в JSON-конфиге.
5. Что сделано / что осталось
Сделано
- Транспорт: serial (USB CAT).
- Вход:
ZZZD/ZZZU(VFO),ZZZE(энкодеры),ZZZP(кнопки),ZZZS(рукопожатие). - Выход:
ZZZI— LED-индикаторы (push отOnStateChanged, дедуп повторов). - Раскладка — зашитый дефолт, выверена по Thetis и реальной панели.
- Shift / band-keypad — прямой выбор диапазона (#29..39 →
SetBand), LEDaiShift. - VFO Lock — блокировка перестройки (
SetVfoLock, гейт вTuneActiveBy), LEDaiVFOLock. - A>B / B>A / Toggle A/B, SDR ON (start/stop) — на штатных кнопках панели.
- UI-чекбокс на каждый serial-порт + персист.
Осталось / возможные улучшения
| Задача | Заметки |
|---|---|
Filter High/Low (ZZZE #4/#5) |
независимые края фильтра; сейчас #4 = ширина, #5 не задействован. Нужны FFilterLow/High + переработка ApplyModeFilter и passband дисплея (sideband-aware, как в Thetis) |
| Sticky shift | сейчас shift всегда non-sticky (снимается band-нажатием); в Thetis есть AndromedaStickyShift |
ZZMF — текст на LCD мультифункц. энкодера |
кодировка: 15 ASCII-символов парами цифр (код−32) |
| TCP-транспорт (G2 V2 panel) | сейчас только serial; нужен режим в CATTcp |
| Настраиваемая раскладка | сейчас зашита; вынести в конфиг/UI (как AndromedaEditForm в Thetis) |
| Long-press кнопок | принимается (ZZZP state=2), но действий пока нет — обрабатывается только нажатие (state=1) |
| Индикаторы RIT/XIT/PureSignal/Diversity/ATU | нет соответствующих функций в TRadioController |
Мультифункц. энкодер (aeMulti) |
назначение не задано |
6. Точки расширения (чек-лист)
- Добавить действие кнопки/энкодера: новый элемент в
TAndButton/TAndEncoder(AndromedaMap.pas) + ветка вTAndromedaPanel.SyncButton/SyncEncoder(AndromedaPanel.pas) + правка таблицыAND_BUTTON_MAP/AND_ENCODER_MAP. - Добавить индикатор: элемент
TAndIndicator+ номер вAND_INDICATOR_NUM+ push вSyncAllIndicatorsи вOnControllerState(по нужномуrf*-полю). - Изменить раскладку: только
AndromedaMap.pas(таблицы-константы). - Сверяться с форматами Thetis:
Andromeda/Andromeda.cs(логика панели,EIndicatorActions/EButtonBarActions/EEncoderActions) иCAT/CATCommands.cs(ZZZ*).