mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-26 04:47:35 +00:00
chore: refine project documentation
This commit is contained in:
+22
-28
@@ -3,9 +3,9 @@
|
||||
Ветка разработки: `feature/tci-protocol`.
|
||||
Дата последнего обновления: 2026-08-18.
|
||||
|
||||
Эталон протокола — «Протокол TCI, версия 2.0» Expert Electronics
|
||||
Реализация соответствует спецификации «Протокол TCI, версия 2.0»
|
||||
(`doc/TCI Protocol_RU.pdf`, 12 января 2024). EWSDR выступает **сервером**
|
||||
(как ExpertSDR3): порт слушаем мы, клиенты — логгеры, скиммеры, программы
|
||||
по стандартной серверной модели: порт слушаем мы, клиенты — логгеры, скиммеры, программы
|
||||
цифровых видов, внешние усилители и коммутаторы.
|
||||
|
||||
---
|
||||
@@ -187,13 +187,12 @@ UI — вкладка **CAT → TCI Server**, справа от «TCP CAT Server
|
||||
| `arg1` у `DRIVE`, `TUNE_DRIVE` | мощность одна на радио — номер не адресует ничего |
|
||||
|
||||
★**Почему приёмник — слайс, а не панорама.** Сперва приёмником был панадаптер,
|
||||
как в ExpertSDR3, где приёмник = DDC. У нас это разошлось с жизнью сразу на
|
||||
в модели, где приёмник соответствует DDC. В EWSDR это разошлось с жизнью сразу на
|
||||
двух концах. У Pluto панорама ровно одна (`BackendCaps.MaxPans = 1`), и второй
|
||||
приёмник существует там **только** как слайс главного пана — при нумерации по
|
||||
панам он был бы недоступен вообще, а `TRX_COUNT` навсегда равнялся единице. С
|
||||
другого конца — клиенты: у MSHV в настройках всего две модели, «TCI Client rx1»
|
||||
и «rx2», то есть приёмники 0 и 1, и никакого третьего номера ввести некуда
|
||||
(`hvrigcontrol.cpp`: `netServPort[3]`/`[4]`, `network.cpp`: `tci_trx`). Значит
|
||||
панам он был бы недоступен вообще, а `TRX_COUNT` навсегда равнялся единице.
|
||||
Кроме того, некоторые клиенты позволяют выбрать только приёмники 0 и 1.
|
||||
Значит
|
||||
«первый добавленный слайс» обязан быть приёмником **1** на любом железе.
|
||||
|
||||
Слот слайса даёт ровно это. Слоты глобальные и стабильные, у каждого своя
|
||||
@@ -255,9 +254,8 @@ B независимо от того, где он живёт: на openHPSDR э
|
||||
слотов слайсов) один раз и навсегда, а слот из этого потолка может быть пуст.
|
||||
Про пустой слот не шлётся ничего — ни `vfo`, ни `dds`, ни показания
|
||||
измерителей, и команды к нему тоже игнорируются целиком (`LiveRx`). Раньше
|
||||
уходили `dds`/`vfo`/`if` с нулём, и клиент принимал ноль за настоящую частоту;
|
||||
для MSHV это вообще фатально — именно ответом на `vfo:<rx>,0;` он завершает
|
||||
инициализацию, то есть подключился бы к пустоте. Состояние появляется в момент
|
||||
уходили `dds`/`vfo`/`if` с нулём, и клиент принимал ноль за настоящую частоту,
|
||||
завершая инициализацию несуществующего приёмника. Состояние появляется в момент
|
||||
создания слайса: `PushChannelMap` рассылает картину нового приёмника целиком,
|
||||
включая `tx_enable` с его номером.
|
||||
|
||||
@@ -501,10 +499,8 @@ web-клиента: явная просьба сильнее умолчания
|
||||
отбрасывается молча: отвечать ошибкой на каждый чужой блок значит захлебнуться.
|
||||
|
||||
**★Маркер `TX_CHRONO` называет приёмник КЛИЕНТА, а не нулевой.** Клиент шлёт
|
||||
TX-аудио не по своей воле, а строго в ответ на маркер, и все входящие бинарные
|
||||
блоки фильтрует по номеру приёмника — у MSHV это первая строка обработчика
|
||||
(`network.cpp`: `if (pStream->receiver != tci_trx) return;`, ветка `TxChrono`
|
||||
там же собирает и отправляет блок). С жёстким нулём в заголовке клиент,
|
||||
TX-аудио строго в ответ на маркер и может фильтровать входящие бинарные блоки
|
||||
по номеру приёмника. С жёстким нулём в заголовке клиент,
|
||||
сидящий на **втором слайсе** (`tci_trx = 1`), маркеров не видел вовсе: эфир по
|
||||
`trx:1,true,tci` поднимался, а звука не было ни одного блока. Поэтому вместе с
|
||||
клиентом-модулятором запоминается номер приёмника из его же `TRX`
|
||||
@@ -536,8 +532,8 @@ TX-аудио не по своей воле, а строго в ответ на
|
||||
Срок считается **по часам** от `START`, а не по накопленным сэмплам: линейный
|
||||
выход может молчать (мьют, стоящий приёмник), а время записи всё равно идёт.
|
||||
Кольцо «последние N секунд» вело себя иначе в обе стороны — начало записи
|
||||
затирало само себя, а `SAVE` через час после `START` отдавал файл, которого у
|
||||
ExpertSDR3 давно бы не было.
|
||||
затирало само себя, а `SAVE` через час после `START` отдавало бы файл уже после
|
||||
завершения заданного окна записи.
|
||||
`SAVE` завершает запись и ставит её в очередь писателю: файл бывает в десятки
|
||||
мегабайт, а команда пришла в потоке клиента, который в это время не читает свой
|
||||
сокет. MP3 не поддержан — кодера в проекте нет, и на `.mp3` уходит честный
|
||||
@@ -794,9 +790,8 @@ running`), а сам телеграф уходит **текущему TX-ист
|
||||
настройки обязана вставать на тот же слайс, что и модуляция;
|
||||
- **ответ автору называет ЕГО номер приёмника**, а состояние в нём — «в эфире
|
||||
именно твой слайс» (`FTransmitting and (TxRx = Rx)`). Так надо потому, что
|
||||
клиенты фильтруют входящие строки по `arg1`: MSHV, например, отбрасывает
|
||||
всё, что адресовано не его приёмнику (`network.cpp`:
|
||||
`if (ls2.at(0)!=tci_trx) continue;`), — и отказ, названный чужим номером, до
|
||||
клиенты могут фильтровать входящие строки по `arg1`, и отказ, названный
|
||||
чужим номером, до
|
||||
него бы просто не дошёл. В **рассылку** уходит номер того, чей слайс сейчас
|
||||
источник передачи (`TxRx` по `TxSliceId`): клиент на приёмнике 1 по ней
|
||||
видит, что в эфире не он. Смена TX-источника оператором доходит до клиентов
|
||||
@@ -872,8 +867,8 @@ running`), а сам телеграф уходит **текущему TX-ист
|
||||
Порядок обратный: сперва UI, потом TCI.
|
||||
- **`RX_ANC_ENABLE`, `RX_APF_ENABLE`, `RX_DSE_ENABLE`, `RX_NF_ENABLE`.** Этих
|
||||
узлов в тракте нет физически. У нас `NR`/`NR2` (EMNR), `NB`/`NB2` (ANB/SNBA)
|
||||
и `ANF` — они в TCI настоящие. `ANC` и `DSE` — блоки собственной обработки
|
||||
Expert, не WDSP; `APF` и `NF` были бы новыми узлами в цепочке.
|
||||
и `ANF` — они в TCI настоящие. Для `ANC`, `DSE`, `APF` и `NF` потребовались
|
||||
бы новые узлы обработки в цепочке WDSP.
|
||||
- **`RX_NB_PARAM`.** Пороги шумодава у нас — подобранные константы
|
||||
`FILTER_NB_*`, одинаковые для всех каналов и не выведенные даже в интерфейс.
|
||||
Клиент, покрутивший их по TCI, оставил бы шумодав расстроенным насовсем.
|
||||
@@ -898,7 +893,7 @@ running`), а сам телеграф уходит **текущему TX-ист
|
||||
| `MUTE` и линейный выход | глушит и поток: движок под мьютом не зовёт `OnAudio`. Аудиопоток приёмника (`AUDIO_START`) мьют не трогает — он снимается до громкости |
|
||||
| DIGL/DIGU, 2 канала | по §3.4 в цифровых модах два канала должны нести комплексный сигнал; у нас это обычное стерео с выхода WDSP — оба тапа стоят там, где сигнал уже вещественный: `rakDemod` сразу за демодулятором, `rakLineOut` за громкостью. Комплексный выход потребовал бы отдельной ветки панели RXA и третьего маршрута тапа, а цифровые клиенты берут `IQ_START` — он честно комплексный |
|
||||
| Поток канала B | не бывает: в протоколе аудиопоток один на приёмник, и он всегда про канал A |
|
||||
| Формат IQ | всегда float32, два канала — `AUDIO_STREAM_SAMPLE_TYPE` относится к аудио (§4.3), а ExpertSDR3 IQ иначе и не шлёт |
|
||||
| Формат IQ | всегда float32, два канала — `AUDIO_STREAM_SAMPLE_TYPE` относится к аудио (§4.3), а TCI IQ иначе и не шлёт |
|
||||
| `IQ_SAMPLERATE` 384 кГц на Pluto 576/960 кГц | нацело не делится, поэтому уходит 192 кГц (см. §2.5). Клиент обязан читать частоту из заголовка блока, а не считать её равной запрошенной |
|
||||
| MP3 у рекордера | не поддержан: кодера в проекте нет, а тащить внешний (lame) ради рекордера — это новая зависимость и её лицензия в сборке, которых у ewsdr сейчас нигде нет. WAV пишется без потерь и открывается всем; на `.mp3` уходит честный `tci_error`, а не молчаливый WAV с чужим расширением |
|
||||
|
||||
@@ -918,7 +913,7 @@ running`), а сам телеграф уходит **текущему TX-ист
|
||||
одинаковыми — в телеметрии платы одно значение forward power.
|
||||
|
||||
У `TRX` третий аргумент разобран только для `tci` (см. §2.5). Значения
|
||||
`mic1`/`mic2`/`micpc`/`ecoder2` называют физические входы ExpertSDR3, которых у
|
||||
`mic1`/`mic2`/`micpc`/`ecoder2` называют физические входы TCI, которых у
|
||||
нас нет: они значат «микрофон, выбранный в программе», то есть ровно то же, что
|
||||
и отсутствие аргумента.
|
||||
|
||||
@@ -933,7 +928,7 @@ running`), а сам телеграф уходит **текущему TX-ист
|
||||
(`AddSliceAtFreq` + `CreateSliceFlag` — флаг, раскладка, персист), у
|
||||
контроллера есть только `RemoveSlice`. Адаптер TCI, как и CAT, до MainForm
|
||||
не дотягивается и не имеет права: он обязан собираться в демоне, где LCL
|
||||
нет вовсе. Вторая по существу: канал B у ExpertSDR3 — второй приёмник внутри
|
||||
нет вовсе. Вторая по существу: канал B у TCI — второй приёмник внутри
|
||||
того же DDC, а у нас слайс — полноценная сущность со своим флагом, звуком,
|
||||
входом и CAT-портом. Клиент, «выключивший канал B», снёс бы оператору
|
||||
рабочий слайс вместе с его модой, фильтром и портом. Правильный порядок:
|
||||
@@ -1086,12 +1081,11 @@ running`), а сам телеграф уходит **текущему TX-ист
|
||||
rate устройства сама переобъявляет и `iq_samplerate`, и `if_limits`, а на
|
||||
576 кГц (Pluto) та же просьба даёт законные 192 кГц.
|
||||
- **Слайс как приёмник** (часть E, живой движок): созданный на ГЛАВНОМ пане
|
||||
слайс становится приёмником 1, отвечает на `vfo:1,0;` своей частотой (это и
|
||||
есть вся инициализация MSHV), слушается командой `vfo:1,0,<Гц>`, отдаёт своё
|
||||
слайс становится приёмником 1, отвечает на `vfo:1,0;` своей частотой,
|
||||
слушается командой `vfo:1,0,<Гц>`, отдаёт своё
|
||||
аудио блоками с `receiver = 1`, ★по `trx:1,true,tci` берёт модуляцию из TCI
|
||||
(то есть просьбу не стирает `Changed(rfTransmitting)` из `SetTxSlice`) и шлёт
|
||||
маркеры `TX_CHRONO` **под номером 1** — оба этих места и ломали передачу
|
||||
MSHV, сидящего на втором слайсе; а `trx:0,true,tci` поверх этой же передачи
|
||||
маркеры `TX_CHRONO` **под номером 1**; а `trx:0,true,tci` поверх этой же передачи
|
||||
(команда-пустышка) номер приёмника в маркерах не меняет, а после удаления слайса приёмник 1 замолкает
|
||||
целиком — вместо прежнего `vfo:1,0,0`.
|
||||
- **Сквозной прогон через живой WDSP:** синтетический 24-битный IQ подаётся
|
||||
|
||||
Reference in New Issue
Block a user