# Стенд TCI

Прогон:

```sh
test/tci/run.sh
```

Собирает `tcitest.pas` и запускает его; код возврата ненулевой, если хоть одна
проверка провалена. Внешних библиотек стенд не требует — WebSocket-клиент в нём
написан на сыром сокете. `libwdsp` нужна только последней части (сквозной
прогон через движок); без неё эта часть сообщает о пропуске, а остальные идут
как обычно.

Что проверяется — в шапке `tcitest.pas`; чего стенд **не** покрывает —
в `doc/TCI.md`, §5.

Две грабли, из-за которых стенд собирается именно так (обе стоили по часу):

* **`-Mobjfpc` обязателен.** С `-Mdelphi` в командной строке выключаются
  вложенные комментарии, и `{$MODE Delphi}` внутри шапки `WebUtils.pas`
  закрывает комментарий раньше времени — компиляция падает на
  «illegal character».
* **Каталог `.ppu` — свой, с именем не `lib`, и путь абсолютный.**
  Относительное `lib/<cpu>-<os>` компилятор ищет и относительно `-Fu`, то есть
  находит units GUI-сборки в корне проекта, а там `PlatformUtils` собран с LCL:
  стенд падает на линковке с `undefined reference to TC_$FORMS_$$_SCREEN`.
  По той же причине сборка идёт с `-dHEADLESS`, как у демона.

Каталоги `units/` и `bin/` — выход сборки, в git не попадают.

## Проверка на живом эфире без передачи

```sh
python3 test/tci/live_rx_test.py --host 127.0.0.1 --port 40001
```

Наглядный UI-прогон с автоматическим возвратом к исходным значениям:

```sh
python3 -u test/tci/live_rx_test.py --visible --commands-only --dwell 1.5
```

Стенд проверяет receive-only команды, IQ, аудио демодулятора и
line-out для всех обнаруженных приёмников. Он никогда не посылает
`START`, `STOP`, установку `TRX`/`TUNE`, TX-аудио и CW-текст. Если радио
уже на передаче, прогон аварийно прекращается.

## Стенд совместимости TCI-клиента

```sh
test/tci/mshv_sim.py --rx 0
test/tci/mshv_sim.py --rx 1 --audio
```

`mshv_sim.py` проверяет две особенности поведения совместимых TCI-клиентов:

* **фильтр по номеру приёмника**: строка,
  адресованная другому приёмнику, игнорируется (и то же самое для
  бинарных блоков, по полю `receiver` заголовка);
* **инициализация — один запрос и один ответ**: клиент шлёт `vfo:<rx>,0;` раз в
  500 мс, максимум пять раз, и ждёт `vfo:<rx>,0,<частота>`. Не дождался —
  «Error To Initialize TCI Server». Других причин у этой ошибки нет.

Поэтому стенд диагностирует причину ошибки подключения одной строкой, а заодно
ловит то, что иначе проявляется молча: без `tx_enable` со **своим** номером
приёмника клиент не разрешает PTT.

По умолчанию стенд безопасен на приём: ни `TRX`, ни `TUNE`, ни `START`/`STOP`,
ни TX-аудио он не шлёт. Передачу включает явный `--tx`.
