# CAT-система EWSDR — статус реализации Ветка разработки: `feature/cat-commands-expansion`. Дата последнего обновления: 2026-06-26. Документ описывает текущее состояние CAT-подсистемы EWSDR: архитектуру, полный перечень реализованных команд, осознанные заглушки и план дальнейших работ. За эталон протокола взят **Thetis / PowerSDR** (`CATParser.cs`, `CATCommands.cs`, `CATStructs.xml`) — диалект Kenwood TS-2000 + расширения `ZZ*`. --- ## 1. Архитектура ``` CAT-транспорты ──► TCATEngine (парсер протокола) ──► TCATContext ──► TCATAdapter ──► TRadioController serial (4×) CATEngine.pas (callbacks) CATAdapter.pas (ядро) TCP-сервер разбор/формат команд мост, маршалинг ``` | Файл | Назначение | |---|---| | `CATEngine.pas` (~2270 строк) | Движок протокола: разбор `;`, формирование ответов, реализации всех команд Kenwood + `ZZ*`. Зависит только от RTL. | | `CATAdapter.pas` (~445 строк) | Мост к `TRadioController`. Строит `TCATContext`: геттеры читают поля контроллера напрямую (CAT-поток, read-only), сеттеры/команды маршалятся в поток контроллера через `FController.Invoke`. Владеет движком + транспортами. | | `CATSerial.pas` (~313 строк) | Менеджер до 4 последовательных портов (виртуальные COM-пары для rigctld/N1MM/WSJT-X). | | `CATTcp.pas` (~507 строк) | TCP-сервер (Thetis-совместимый), управление клиентами по GUID (`ZZGA`/`ZZGR`). | ### 1.1 Принципы - **CAT — равноправный клиент контроллера** наряду с `WebAdapter` и GUI. Никаких обращений к `MainForm`. Только `TRadioController`. - **Потокобезопасность.** Геттеры читают поля контроллера напрямую (атомарное чтение в CAT-потоке). Сеттеры пишут параметр в scratch-поля (`FSyncFreq/FSyncInt/FSyncBool`) и зовут `FController.Invoke(@SyncXxx)` — GUI исполняет через `TThread.Synchronize`, демон — своей очередью. - **`TCATContext`** — плоская запись callback'ов (`Get*`/`Set*`/`Do*`). Чтобы пробросить новую возможность контроллера в CAT, достаточно: (1) добавить callback в запись, (2) реализовать в адаптере геттер/сеттер/sync, (3) зарегистрировать в `TCATAdapter.Create`, (4) переписать тело команды в движке. - **Формат команд:** ``` SET: ; (suffix = значение) GET: ; (suffix пустой) Resp: ; Err: ?; (неверный формат) | E; (ошибка выполнения) ``` Расширенные `ZZ*` дублируют Kenwood-команды и добавляют то, чего в Kenwood нет. ### 1.2 Статистика покрытия (ZZ-команды) | | Кол-во | |---|---| | Всего `ZZ*` в Thetis | 315 | | Реально реализовано в EWSDR | **98** | | Заглушки (отвечают валидным dummy, функции нет) | ~211 | | Совсем не обрабатываются (вернут `?;`) | 7 | Большинство заглушек закрыть **нечем** — в EWSDR физически отсутствует соответствующий тракт (см. §4). --- ## 2. Что сделано ### 2.1 Реализованные команды Kenwood (одиночный префикс) | Команда | Функция | Маппинг на контроллер | |---|---|---| | `FA` / `FB` | VFO A / B частота (11 цифр, Гц) | `Set/GetVfoA`, `Set/GetVfoB` | | `FR` | приёмный VFO (0/1) | `Set/GetActiveVfo` | | `FT` | передающий VFO / split | → `ZZSP` | | `FW` / `SH` / `SL` | ширина фильтра (индекс пресета) | `Set/GetFilterIdx` | | `MD` | режим (Kenwood-код) | `Set/GetMode` | | `GT` | режим AGC (0=FAST…4=OFF) | `Set/GetAGCMode` | | `AG` | громкость AF | `Set/GetVolume` | | `PC` | мощность TX 0–100 % | `Set/GetDriveLevel` | | `NB` | шумоподавитель (NB) | `Set/GetNBMode` | | `NT` | автонотч (ANF) | `Set/GetANFEnabled` | | `SM` | S-метр (шкала Kenwood 0000–0030) | `GetSMeter` | | `IF` | составной статус (37 байт) | freq/mode/tx/split | | `ID` | идентификатор (TS-2000 = 019) | const | | `PS` | питание/состояние | `GetRunning` | | `TX` / `RX` | передача / приём | `SetTransmitting` | | `BU` / `BD` | смена диапазона ±1 | `DoBandUp/Down` | | `UP` / `DN` / `RU` / `RD` | шаг настройки ±1 | `DoTuneUp/Down` | | `SQ` | шумоподавитель FM (шкала 0–255) | `Set/GetSquelchLevel`+`On` | | `CN` / `CT` | CTCSS тон / вкл | `Set/GetCTCSSTone`, `…On` | | `OF` / `OS` | репитер: offset / направление | `Set/GetFMRptOffset`, `…Dir` | ### 2.2 Реализованные расширенные `ZZ*` (выборочно, наиболее значимые) VFO/режим/фильтр: `ZZFA ZZFB ZZFI ZZFL ZZFH ZZFM ZZMD ZZFT ZZSP`, диапазоны: `ZZBS ZZBU ZZBD ZZBA ZZBI ZZBM`, AGC/громкость/мощность: `ZZGT ZZAG ZZPC ZZPD ZZAR`, шумодав/нотч: `ZZNA ZZNB ZZNR ZZNS ZZNT ZZNL ZZNN`, FM: `ZZSQ ZZSO ZZTA ZZTB ZZST`, CTUN: `ZZCN`, S-метр/телеметрия: `ZZSM`, шаги VFO: `ZZAU ZZBP ZZSU ZZSA ZZSB`, передача: `ZZTX ZZRX`, сервис: `ZZID ZZRV ZZGA ZZGR`. ### 2.3 Сделано в ветке `feature/cat-commands-expansion` Все команды ниже **были заглушками** и стали рабочими — функционал в `TRadioController` уже существовал, но не был проброшен в CAT. **Группа 1 — Split TX** - `ZZSP`, `FT` — split (TX на VFO-B), `FR` — выбор приёмного VFO, split-байт в составном `IF`. - В `TRadioController` добавлен публичный метод `SetSplit(TxOnB)` (флаг `FSplitTxB` + `PushNetworkState` + `Changed(rfActiveVfo)`). TX-частоту радио берёт из `ActiveTXFreqHz` (учитывает split). **Группа 2 — FM Squelch** - `SQ` (шкала Kenwood 0–255), `ZZSQ` (0–100 %), `ZZSO` (вкл/выкл). - Маппинг: `SetFMSquelch` / `SetFMSquelchLevel`. Уровень>0 включает шумоподавитель. **Группа 3 — FM CTCSS** - `CT`/`ZZTA` (вкл/выкл), `CN` (1-based тон 01–38), `ZZTB` (0-based 00–37). - Маппинг: `SetFMCTCSS` / `SetFMCTCSSTone`, таблица `CTCSS_TONES[38]`. **Группа 4 — FM-репитер** - `OF` (offset, 9 цифр Гц), `OS` (направление). - Трансляция направлений Kenwood (0=simplex,1=+,2=−) ↔ внутренние `RPT_NONE/MINUS/PLUS`. Маппинг: `SetFMRpt` / `SetFMRptOffset`. **Группа 5 — FM tuning step** - `ZZST` (индекс 00–03: 6.25/12.5/20/25 кГц). Маппинг: `SetFMStep`. **Доп. команды (вторая итерация)** | Команда | Что | Примечание | |---|---|---| | `ZZSO` | Squelch on/off | завершает группу squelch | | `ZZNT` | ANF on/off | раньше ошибочно был алиасом NB | | `ZZCN` | CTUN (click-tune) RX1 | новый callback `Get/SetCTun` → `SetCTun` | | `ZZAR` | RX1 AGC-T / RF gain (`±nnn`) | новый callback `Get/SetAGCTop` → `SetAGCTop` (кламп 20–120 dB) | | `ZZAU`/`ZZBP` | сдвиг VFO A/B вверх на шаг `nn` (00–14) | **исправлен баг**: были заалиашены на `ZZFA`/`ZZAP` | | `ZZSU` | шаг активного VFO вверх | `DoTuneUp` | Шкала шагов `ZZAU/ZZBP` — `StepIdxToHz` (зеркало Thetis `Step2Freq`): 1 Гц, 10, 25, 50, 100, 250, 500, 1к, 5к, 9к, 10к, 100к, 250к, 500к, 1 МГц. **Новые callback'и в `TCATContext`** (этой ветки): split, squelch on/level, CTCSS on/tone, FM repeater dir/offset, FM step, AGC-T, CTUN. --- ## 3. Что нужно сделать (актуально / есть чем закрыть) Эти команды — заглушки, но соответствующая функция в EWSDR **уже есть** или легко добавляется. Приоритетные кандидаты: | Команда(ы) | Что | Чем закрыть | Сложность | |---|---|---|---| | `ZZCU` | загрузка CPU (read) | телеметрия процесса | низкая | | `ZZMY` / `ZZQR` / `ZZQS` / `ZZQM` | память каналов (запись/чтение/quick) | `ChannelStore` уже есть | средняя | | `ZZFD` | FM-девиация (radio button) | нужен публичный `SetFMDeviation` (сейчас только поле `FFMDeviation`) | низкая | | `ZZDM` / `ZZDA` / `ZZPO` / `ZZDY` | режим/усреднение/пик/порог спектра | UI-параметры спектра | средняя | | `ZZAS` | RX2 AGC-T | — только при появлении RX2 | — | > Прежде чем реализовывать новую команду, сверяйся с форматом поля в > `Thetis/.../CAT/CATStructs.xml` (`` / ``) и телом > метода в `CATCommands.cs`, чтобы ширина/знак значения совпадали. ### 3.1 Совсем не обрабатываются (вернут `?;`) `ZZCU` (CPU), `ZZDY` (DX threshold), `ZZPK`/`ZZPL` (речевой компрессор), `ZZQA`/`ZZQB` (Quick Play/Rec), `ZZVF` (VAC stereo). Из них реалистично добавить только `ZZCU` и (частично) `ZZDY`. --- ## 4. Осознанные заглушки (закрывать нечем) Команды отвечают валидным dummy-значением для совместимости с управляющим ПО (rigctld, N1MM, WSJT-X, Log4OM), но функции в EWSDR нет. Это ~70 % всех заглушек. | Область | Команды (примеры) | Причина | |---|---|---| | **Второй приёмник RX2 / sub-RX** | `ZZAB ZZAS ZZBA ZZMB ZZOB`, ext `BF BG BR DO DQ DR OF OG OH OL SG SH SS` | один приёмник | | **TX-DSP тракт** | mic gain `ZZMG`/`MG`, монитор `ZZMO`/`MO`, TX-EQ `ZZEB/ER/ET`, компрессор `ZZPK/ZZPL/CF CI CL CM`, two-tone `ZZUS`, VAC `ZZVB/ZZVF` | нет обработки передачи | | **CW-кейер / CWX** | `ZZKM ZZKS ZZKY ZZCB ZZCD ZZCS`, `KY KS` | нет кейера | | **RTTY / DIGI** | `ZZRA ZZRL`, ext `RF RH RM RS RY` | нет RTTY-движка | | **RIT / XIT** | `RT XT RC RU RD` (как RIT), ext `RB RF RH` | нет смещения приёма | | **Diversity** | `ZZDA(div) ZZDB`, ext `DA` | нет диверсити-приёма | | **Спектр/водопад (внутр.)** | ext `SV SW SX SY SZ WT WU WV WW` | не управляется по CAT | --- ## 5. Транспорты - **Serial** (`CATSerial.pas`): до 4 портов, параметры (порт/скорость/биты/ чётность/стоп) из `TGlobalSettings.CATSerial*`, применяются `TCATAdapter.ApplySettings`. На текущей платформе сборки может быть `{$DEFINE CAT_SERIAL_STUB}` (см. начало файла) — проверить перед релизом. - **TCP** (`CATTcp.pas`): сервер на `CATTcpPort`, включается флагом `CATTcpEnabled`. Клиенты идентифицируются GUID через `ZZGA`/`ZZGR`. --- ## 6. Как добавить новую CAT-команду (чек-лист) 1. **Сверить формат** в `CATStructs.xml` + `CATCommands.cs` (Thetis). 2. Если нужна новая возможность контроллера — есть ли публичный метод/поле в `TRadioController`? Если нет — добавить (по образцу `SetSplit`). 3. В `CATEngine.pas`: добавить callback(и) в `TCATContext`, `SafeGet*`-хелпер для GET, переписать тело команды (`CmdXX` или `ZZXX`). 4. В `CATAdapter.pas`: геттер (чтение `FController.F*`), сеттер + `SyncXX` (через `Invoke`), регистрация в `TCATAdapter.Create`. 5. Если команда `ZZ*` ещё не в диспетчере — добавить ветку `else if ext = '..'`. 6. Сборка-проверка: `lazbuild -B --ws=qt6 ewsdr.lpr` (GUI-граф включает CAT; headless-демон `ewsdrd` CAT **не** содержит).