# Интеграция ADALM-PLUTO (libiio) в EWSDR — полный план работ > Цель: добавить поддержку **PlutoSDR** (AD9363/AD9364) через **libiio** как > второй тип «железа» наряду с трансиверами **openHPSDR**. Discovery-форма > остаётся прежней, но дополняется board-специфическими параметрами Pluto. > В UI скрываются функции, которых у Pluto нет, и появляются те, что есть > только у Pluto. Весь DSP по-прежнему идёт через **WDSP**. Платформенно- > специфичный код выносится в отдельные файлы, чтобы не загромождать > существующую логику openHPSDR. --- ## 0. Краткое резюме решения 1. Ввести **тонкий слой абстракции backend'а** (`SDRBackend.pas`, `TSDRBackend`), описывающий ровно тот API, которым `MainForm` сегодня пользуется у `THPSDRNetwork`. Существующий `THPSDRNetwork` обворачивается адаптером `THPSDRBackend` (код самого `HPSDRNetwork.pas` не трогаем). 2. Новый backend Pluto — `PlutoBackend.pas` (`TPlutoBackend`), и низкоуровневые биндинги libiio — `IIO.pas` (по образцу `WDSP.pas`). 3. Поток IQ от Pluto (int16 LE) **переупаковывается в тот же 24-битный big-endian формат**, что и openHPSDR, и подаётся в существующий `TWDSPEngine.PushDDCPacket` — DSP-конвейер не меняется. 4. Возможности железа описываются записью **`TBoardCaps`** (`BoardCaps.pas`). `MainForm`/`SettingsForm` гейтят UI по `Caps`, а не по жёстким спискам `BoardType in [...]`. 5. Discovery-форма расширяется панелью Pluto-параметров (URI, gain mode, gain, RF bandwidth, sample rate, диапазон LO) — раскладка прежняя. 6. Минимальный sample rate Pluto = **≈521 кS/s** (без программируемого FIR) учитывается в `SampleRateOverlay` и в валидации. --- ## 1. Текущая архитектура (контекст) Стек: **Lazarus / Free Pascal** (FPC 3.2 / Lazarus 2.x), LCL, кросс-платформенно (Windows / Linux / macOS). DSP — внешняя **WDSP** (`wdsp.dll` / `libwdsp.so` / `libwdsp.dylib`). Аудио — PortAudio (`AudioInput.pas` / `AudioOutput.pas`). ### 1.1 Путь данных RX ``` THPSDRNetwork (UDP, HPSDRNetwork.pas) → receive thread → MainForm.OnDDCIQCB(DDCIndex, TDDCIQPacket) → FDSPEngine.PushDDCPacket(IQData, 0, SamplesPerFrame) // сырые 24-bit BE байты → WDSP DSP-поток: декод 24-bit BE → double (scale 1/8388608), RXA-цепь → OnAudio (AudioOutput) + OnSpectrum/OnWaterfall ``` Декод IQ зашит в `TWDSPEngine.PushIQItemToDSP` (`WDSPEngine.pas:1199-1209`): 3 байта I + 3 байта Q, big-endian, `SCALE = 1/8388608.0`. ### 1.2 Путь данных TX ``` Mic: OnMicPacketCB (HW-mic) или AudioInput (звуковая карта) → FDSPEngine.PushTXMicSamples* → WDSP TXA-цепь → OnTXIQReady(double IQ @ 192k, MainForm.pas:6795) → батчинг по 240 пар → FNetwork.SendDUCIQ → UDP (порт 1029) ``` Масштаб TX: `V * 8388607.0`, кламп в 24-bit (`MainForm.pas:6801`). ### 1.3 Discovery / устройство - `DeviceForm.pas` (`TDeviceDialog`): слева сохранённые устройства (`TSavedDevice`: Name / IPAddress / BoardType / AutoStart → `hpsdr_devices.ini`), справа найденные. Кнопка DISCOVER → callback `OnDiscover` → `MainForm.BtnDiscoverFromDialog` → `TDiscoverThread` → `FNetwork.Discover` → `OnDeviceFound` → `FDeviceDialog.AddDiscovered(IP, name, BoardType)`. - Устройство в сети идентифицируется по **IP**, а настройки хранятся по **MAC** (`Settings.pas`, JSON по `MacToStr`). ### 1.4 Поверхность API `THPSDRNetwork`, которой пользуется MainForm (`HPSDRNetwork.pas:204-249`) — именно это станет интерфейсом backend'а: - `Discover`, `Connect(THPSDRDevice)`, `Disconnect` - `ConfigureDDCs(NumDDCs, SampleRate, ADCSource, Dither, Random)` - `SetRunAndFreq(Run, RXFreq, TXFreq, Drive)` - `UpdateState(RXFreq, TXFreq, Drive, TX, PAEnabled, AlexEnabled)` - `SendDUCIQ(I, Q)`, `SendDDCAudio`, `SendDUCSpecific`, `SetStepAtten`, `SetAlexConfig`, `SetXvtrMode`, `SendPTT`, `SendFullHP` - Свойства: `Connected`, `Running`, `Device`, `LastError` - Колбэки: `OnDeviceFound`, `OnDDCIQ`, `OnMicPacket`, `OnHPStatus`, `OnWideband` ### 1.5 Board-специфичные места (по `BoardType`) - `BoardUtils.BoardTypeName`, `FreqToBandIdx`. - `HPSDRProtocol`: `BoardSupportsSupplyVoltage/Current`, `ADCToWatts*`, `ADCToSupplyVolts/Current`. - `HPSDRNetwork.ConfigureDDCs`: число ADC и базовый DDC (`BoardType in [3,4,5,10]`). - `MainForm`: телеметрия (supply V/A, fwd/rev power, SWR) в `OnHPStatusCB`, step-attenuator (`FAtten`), Alex/XVTR, wideband-панель, dither/random. - `SettingsForm`: вкладки Antenna/Alex, Transverter, Tip/Ring (Orion), ADC dither/random, PA-калибровка. ### 1.6 Линковка внешних библиотек - `WDSP.pas`: `WDSP_LIB` по платформе; на macOS `{$linklib wdsp}`; weak — если библиотеки нет, указатели `nil`, проверяется `Assigned(@WDSPwisdom)`. - `ewsdr.lpi`: `CustomOptions = -k-L/usr/local/lib`. - Сборка: `lazbuild --ws=qt6 ewsdr.lpr` (`BUILD.MD`). --- ## 2. Pluto SDR / libiio — факты и ограничения **Железо:** ADALM-PLUTO на AD9363 (заводской), прошивкой разблокируется до возможностей AD9364/AD9361. **Один RX и один TX** канал (один ADC / один DAC). **libiio API (нужный минимум):** - Контекст: `iio_create_context_from_uri("ip:192.168.2.1" | "ip:pluto.local" | "usb:1.x.x" | "local:")`. - Discovery: `iio_create_scan_context(NULL,0)` → `iio_scan_context_get_info_list` → `iio_context_info_get_uri/_description`. - Устройства: `ad9361-phy` (управление), `cf-ad9361-lpc` (RX-стрим), `cf-ad9361-dds-core-lpc` (TX-стрим). - Каналы phy: `voltage0` (RX, input) / `voltage0` (TX, output) — gain, rf_bandwidth, sampling_frequency; `altvoltage0` (RX LO), `altvoltage1` (TX LO). - Стрим: `iio_device_create_buffer`, `iio_buffer_refill` (RX), `iio_buffer_push` (TX); каналы `voltage0`(I)+`voltage1`(Q), формат **int16 LE**, интерливинг I/Q. Полезных бит — 12 (знаковые, в младших битах). - Атрибуты (строки): `frequency` (LO, Hz), `sampling_frequency` (Hz), `rf_bandwidth` (Hz), `hardwaregain` (dB), `gain_control_mode` (`manual|slow_attack|fast_attack|hybrid`), `rssi`, `temp0` (xadc, mC). **Платформенные ограничения Pluto (важно для UI/валидации):** | Параметр | Значение | |---|---| | Sample rate (min) | **≈520.83 кS/s** без FIR; ~65 кS/s только с загруженным FIR | | Sample rate (max) | 61.44 МS/s (по USB 2.0 реально ~5–6 МS/s непрерывно) | | Частота LO (AD9363) | 325 МГц – 3.8 ГГц | | Частота LO (AD9364, разблок.) | 70 МГц – 6 ГГц | | RX gain | 0–73 дБ (manual) + режимы AGC | | TX «gain» | аттенюатор −89.75…0 дБ | | RF bandwidth | 200 кГц – 56 МГц | | Транспорт | USB / Ethernet-gadget; интерфейс — URI, не broadcast | **Чего у Pluto НЕТ:** нескольких DDC/ADC, dither/random, Alex-фильтров/реле антенн, аппаратного wideband-ADC, PureSignal, измерения напряжения/тока питания, fwd/rev power и КСВ, аппаратного step-attenuator, HW-CW-keyer. XVTR-логика возможна только как программный сдвиг частоты (без реле). --- ## 3. openHPSDR vs Pluto — матрица возможностей | Возможность | openHPSDR | Pluto | Действие в UI | |---|---|---|---| | Несколько DDC | да | нет (1 RX) | скрыть мульти-DDC | | Dither / Random ADC | да | нет | скрыть в Advanced | | Step attenuator (RX) | да | нет (есть RX gain dB) | заменить контрол | | RX gain / AGC mode | косвенно | да (manual/AGC) | показать для Pluto | | Drive level (TX) | 0–255 | TX atten dB | переинтерпретировать | | Alex антенны/фильтры | да | нет | скрыть вкладку | | XVTR (реле) | да | только сдвиг | показать упрощённо | | Wideband ADC панель | да | нет | скрыть | | Supply V / A | часть плат | нет (есть temp) | заменить на temp | | Fwd/Rev power, SWR | да | нет | скрыть SWR/PWR | | RF bandwidth | фикс. | настраиваемый | показать для Pluto | | Диапазон частот | 0–61.44М (HF/6м) | 70М–6Г | расширить ввод/бэнд-план | | Sample rates | 48к–1536к | 521к–~6М | свой набор в overlay | --- ## 4. Архитектурное решение ### 4.1 Слой абстракции backend'а — `SDRBackend.pas` (НОВЫЙ) Абстрактный класс `TSDRBackend`, повторяющий публичный контракт `THPSDRNetwork` (раздел 1.4). MainForm работает с `FBackend: TSDRBackend` вместо прямого `FNetwork`. Колбэки переносятся на backend. ```pascal type TSDRKind = (sdrHPSDR, sdrPluto); TSDRBackend = class protected FOnDDCIQ: TOnDDCIQPacket; // (повторно используем типы из HPSDRNetwork) FOnMic: TOnMicPacket; FOnHPStatus: TOnHPStatus; // для Pluto заполняем синтетически (RSSI/temp) FOnWideband: TOnWidebandFrame;// Pluto: не вызывается FOnDeviceFound: TOnDeviceFound; public function Kind: TSDRKind; virtual; abstract; function Caps: TBoardCaps; virtual; abstract; function Discover(TimeoutMs: Integer): THPSDRDeviceArray; virtual; abstract; function Connect(const Dev: THPSDRDevice): Boolean; virtual; abstract; procedure Disconnect; virtual; abstract; procedure ConfigureDDCs(NumDDCs: Byte; SampleRate: Word; ...); virtual; abstract; procedure SetRunAndFreq(Run: Boolean; RXFreqHz, TXFreqHz: Double; Drive: Byte); virtual; abstract; procedure UpdateState(...); virtual; abstract; procedure SendDUCIQ(const I, Q: array of Integer); virtual; abstract; // ... остальные методы из 1.4; для неподдерживаемых — пустая реализация в Pluto property Connected: Boolean read FConnected; property Running: Boolean read FRunning; property Device: THPSDRDevice read FDevice; property LastError: string read FLastError; property OnDDCIQ: ... ; // + остальные колбэки end; ``` **Почему не интерфейс (`interface`/IUnknown):** класс проще для FPC-кода без ARC-сюрпризов, повторяет существующий стиль и не требует менять `HPSDRNetwork.pas`. ### 4.2 `THPSDRBackend` (адаптер) — в `SDRBackend.pas` или отдельно Тонкая обёртка: внутри `FNet: THPSDRNetwork`, делегирует все методы и пробрасывает колбэки. `Caps` возвращает capabilities по `BoardType`. `HPSDRNetwork.pas` остаётся **без изменений**. ### 4.3 `TPlutoBackend` — `PlutoBackend.pas` (НОВЫЙ) Реализует `TSDRBackend` поверх libiio. Внутри: - RX-поток: `iio_buffer_refill` → int16→24-bit BE repack → синтез `TDDCIQPacket` (seq, SamplesPerFrame) → `FOnDDCIQ(0, pkt)`. - TX-поток: очередь как в HPSDR (`DUC_TX_QUEUE_SIZE`), пары I/Q (24-bit) → int16 → `iio_buffer_push`. - Телеметрия-поток (~5–10 Гц): читает `rssi`/`temp0` → синтетический `THighPriorityStatus` → `FOnHPStatus` (S-метр + температура). - `Discover` → `iio_create_scan_context`; маппинг URI/serial → `THPSDRDevice` (см. 7.3 про идентификацию). ### 4.4 `IIO.pas` — биндинги libiio (НОВЫЙ) По образцу `WDSP.pas`. **Рекомендация: динамическая загрузка через `dynlibs`** (`LoadLibrary`/`GetProcedureAddress`) с `function IIOAvailable: Boolean` — тогда приложение запускается даже без установленной libiio, а Pluto просто недоступен (как сейчас weak-WDSP). Имена: `libiio.so.0`/`libiio.so` (Linux), `iio.dll` (Windows), `libiio.dylib`/framework (macOS). ### 4.5 `BoardCaps.pas` — описание возможностей (НОВЫЙ) ```pascal type TBoardCaps = record Kind: TSDRKind; DisplayName: string; HasMultiDDC, HasDitherRandom, HasStepAtten, HasRXGain, HasAGCModes, HasAlex, HasXvtrRelays, HasWideband, HasSupplyVolts, HasSupplyCurrent, HasPower, HasSWR, HasRFBandwidth, HasHWMic, HasPureSignal: Boolean; MinSampleRate, MaxSampleRate: Integer; MinFreqHz, MaxFreqHz: Double; SampleRates: array of Integer; // что показывать в overlay end; function BoardCapsFor(Kind: TSDRKind; BoardType: Integer): TBoardCaps; ``` Единый источник правды для гейтинга UI — заменяет разбросанные `if BoardType in [...]`. --- ## 5. Список новых и изменяемых файлов **Новые:** - `IIO.pas` — биндинги libiio (динамическая загрузка). - `PlutoBackend.pas` — `TPlutoBackend` (RX/TX/telemetry потоки, repack). - `SDRBackend.pas` — `TSDRBackend` + `THPSDRBackend`-адаптер + `TSDRKind`. - `BoardCaps.pas` — `TBoardCaps` + `BoardCapsFor`. - `PlutoUtils.pas` (опц.) — частотные бэнд-планы/пресеты для VHF/UHF/SHF. **Изменяемые:** - `MainForm.pas` — `FNetwork: THPSDRNetwork` → `FBackend: TSDRBackend` (+ фабрика по `Kind`); гейтинг UI по `FBackend.Caps`; телеметрия; drive/gain; START/STOP. - `DeviceForm.pas` — `TSavedDevice` += поля Pluto; панель Pluto-параметров; `AddDiscovered` += URI/Kind. - `SettingsForm.pas` — показывать/прятать вкладки и контролы по Caps; новые контролы Pluto (RX gain, AGC mode, RF bandwidth). - `BoardUtils.pas` — имя для Pluto, бэнд-план VHF/UHF (или вынести в PlutoUtils). - `Settings.pas` — ключ устройства (MAC vs serial), новые поля (gain mode, gain, rf_bandwidth, pluto sample rate), set частот для Pluto. - `SampleRateOverlay.pas` — набор скоростей зависит от backend/Caps. - `ewsdr.lpr` — добавить новые units в `uses`. - `ewsdr.lpi` — пути/линковка libiio (если link-time), новые файлы в проекте. - `bundle_app.sh` — включать libiio в macOS-бандл. - `BUILD.MD` — отметить зависимость libiio (опциональная). --- ## 6. Детальный разбор по подсистемам ### 6.1 libiio биндинги (`IIO.pas`) Объявить нужные типы-указатели (`p_iio_context`, `p_iio_device`, `p_iio_channel`, `p_iio_buffer`, `p_iio_scan_context`, `p_iio_context_info`) и функции: - контекст: `iio_create_context_from_uri`, `iio_context_destroy`, `iio_context_get_device`, `iio_context_find_device`. - scan: `iio_create_scan_context`, `iio_scan_context_get_info_list`, `iio_context_info_get_uri`, `iio_context_info_get_description`, `iio_context_info_list_free`, `iio_scan_context_destroy`. - каналы: `iio_device_find_channel`, `iio_channel_enable`, `iio_channel_attr_write_longlong/_read_longlong`, `..._write/_read` (строки), `iio_channel_attr_write_double` (для gain). - буферы: `iio_device_create_buffer`, `iio_buffer_destroy`, `iio_buffer_refill`, `iio_buffer_push`, `iio_buffer_first`, `iio_buffer_step`, `iio_buffer_end`, `iio_channel_read/_write` (или прямой доступ к памяти буфера). - `iio_strerror`. Все `cdecl`. Использовать `TIIO_*` typedef'ы. Реализовать `InitIIO/IIOAvailable` (грузим библиотеку, резолвим символы; при отсутствии — `False`). ### 6.2 Backend-абстракция и подключение в MainForm - Завести фабрику: `function CreateBackend(Kind: TSDRKind): TSDRBackend;`. - В `MainForm` заменить тип поля `FNetwork` на `FBackend: TSDRBackend` (или оставить имя `FNetwork`, сменив тип — меньше правок в тексте). - Колбэки (`OnDeviceFound`, `OnDDCIQCB`, `OnHPStatusCB`, `OnMicPacketCB`, `OnWidebandCB`) переключить на backend. - При выборе устройства в discovery узнаём `Kind` (Pluto vs HPSDR) и создаём нужный backend перед `Connect`. - `BoardTypeName`-вывод в статус-баре и Web (`MainForm:3172`, `3257`) — через `FBackend.Caps.DisplayName`. ### 6.3 Discovery-форма (`DeviceForm.pas`) - `TSavedDevice` расширить: `Kind: TSDRKind; URI: string; PlutoGainMode: Integer; PlutoGainDB: Double; PlutoRFBW: Integer; PlutoSampleRate: Integer;` (BoardType остаётся для HPSDR). - INI (`hpsdr_devices.ini`): дописать поля; обратная совместимость — отсутствующие читать с дефолтами, `Kind` по умолчанию `sdrHPSDR`. - DISCOVER запускает **обе** ветки: HPSDR broadcast и libiio-scan (если `IIOAvailable`). В списке найденных помечать тип: `[HPSDR]` / `[PLUTO]`. `AddDiscovered` получает доп. параметры (URI, Kind, отображаемое имя). - Раскладка прежняя; снизу/справа добавить **сворачиваемую панель «Pluto parameters»**, активную только когда выбранное/добавляемое устройство — Pluto: поля URI, Gain mode (combo), Gain (dB), RF bandwidth, Sample rate. Для HPSDR-устройств панель скрыта/неактивна. - `BtnConnect` отдаёт в результат не только IP, но и `Kind`/URI/Pluto-параметры. ### 6.4 Идентификация устройства и Settings - HPSDR: ключ настроек — **MAC**. Pluto: MAC нет → использовать **serial number** Pluto (атрибут контекста `hw_serial`/usb serial) как ключ. В `Settings.pas` обобщить `MacToStr` до строкового device-id, либо завести отдельную ветку ключей `pluto:`. - `THPSDRDevice` дополнить (или ввести `TSDRDeviceInfo`) полями `Kind`, `URI`, `Serial`. Чтобы не плодить типы, можно положить serial в поле `MAC` как хэш — но честнее расширить запись. (Решить в Фазе 1, см. открытые вопросы.) - Новые per-device поля в `TGlobalSettings` (или отдельная секция `pluto`): `PlutoGainMode`, `PlutoGainDB`, `PlutoRFBW`, `PlutoLOOffset`. ### 6.5 Sample rate (`SampleRateOverlay.pas` + валидация) - Текущий `SPAN_RATES = (48k..1536k)` сделать зависимым от `Caps.SampleRates`. - Для Pluto предложить набор: `521000, 768000, 1000000, 1536000, 2000000, 3000000` (верх — с оглядкой на USB-троттлинг; пометить «USB limit»). - Жёсткая валидация: для Pluto `SampleRate >= MinSampleRate(521000)`. При попытке выставить ниже — клампить + статус-предупреждение. - `FSpanHz` = выбранный rate (как сейчас). WDSP rate-agnostic; пересоздание движка через существующий `RecreateDSPEngine/ChangeSampleRate`. - **CPU/латентность:** при 521к–3М `FBufSize = BufSize*Rate/48000` большой (≈5.5k–32k). Проверить нагрузку; при необходимости — уменьшить базовый `BufSize` для Pluto или включить программируемый FIR Pluto для понижения rate. (Замер в Фазе 4.) ### 6.6 RX-поток IQ и формат сэмплов (ключевой момент) - Pluto отдаёт **int16 LE** (12 значащих бит). openHPSDR/WDSP ждёт **24-bit BE**, scale `1/8388608`. - **Решение (минимальная инвазивность):** в `TPlutoBackend` RX-потоке переупаковывать каждый int16-сэмпл в 3-байтовый big-endian с тем же динамическим диапазоном: `v24 = v16 << 12` (12→24 бита, знак сохраняется), затем разложить в 3 байта BE. Это даёт корректный масштаб для существующего декодера `PushIQItemToDSP` без изменений в WDSPEngine. - Альтернатива: добавить в `TWDSPEngine` метод `PushIQDoubles(constI,Q)` и кормить double напрямую (чище, но трогает WDSPEngine — оставить как опцию). - Размер «пакета»: эмулируем `TDDCIQPacket` — заполняем `Seq` (монотонно), `SamplesPerFrame` (например 238, как у HPSDR, чтобы переиспользовать ветку `MainForm.OnDDCIQCB`), и режем буфер `iio_buffer_refill` на такие кадры. - `FActiveDDC`/seq-контроль в `OnDDCIQCB` продолжают работать (DDCIndex=0). ### 6.7 TX-поток - `OnTXIQReady` (MainForm:6795) уже даёт 24-bit-клампленные `I/Q` пары → `FBackend.SendDUCIQ`. В `TPlutoBackend.SendDUCIQ` конвертировать 24-bit → int16 (`v16 = v24 >> 12` или scale), писать в TX-буфер, `iio_buffer_push` в отдельном потоке (равномерная подача, как DUC-sender). - TX-частота: Pluto имеет отдельный TX LO (`altvoltage1`). Поддержать split/duplex; при не-дуплексе LO RX=TX. - «Drive level» (0–100 слайдер) маппить в TX `hardwaregain` (аттенюатор 0…−89.75 дБ): 100%→0 дБ, 0%→−89.75 дБ (или разумный практический диапазон, напр. 0…−40 дБ). См. `CalcDriveByte`/`TrkDriveChange` в MainForm. ### 6.8 Gain / AGC модель - HPSDR: step-attenuator (`FAtten`, 0/10/20 дБ) + WDSP-AGC. - Pluto: RX `gain_control_mode` (manual/slow/fast/hybrid) + `hardwaregain` (дБ). - В UI: если `Caps.HasRXGain` — показать RX-gain слайдер (0–73 дБ) и combo AGC-mode вместо step-attenuator. Когда mode≠manual — слайдер gain disable. - WDSP-AGC RXA оставить включённым для пост-обработки (как у HPSDR), но основной gain — аппаратный Pluto. ### 6.9 Телеметрия (S-meter / temp вместо supply/SWR) - `OnHPStatusCB` (MainForm:3286) и панель статуса завязаны на supply V/A, fwd/rev power, SWR. - Pluto: `Caps.HasSupplyVolts/Current/Power/SWR = False`. В этих местах показывать прочерк/скрывать. Вместо supply показать `temp0` (°C) Pluto. - S-метр: WDSP `GetSMeterDBm` остаётся основным (по IQ); RSSI Pluto можно показывать как доп. индикатор. - TX-метр (см. memory `project_smeter_tx`: мощность+КСВ): для Pluto скрыть КСВ и показывать только относительный уровень / TX gain (нет датчиков мощности). ### 6.10 Частотный диапазон / LO / XVTR - Расширить допустимый ввод частоты до 70 МГц–6 ГГц (по `Caps.MinFreqHz/Max`). - Бэнд-план: `BoardUtils.FreqToBandIdx` сейчас только HF/6м. Добавить VHF/UHF/SHF бэнды (2м, 70см, 23см, и т.д.) для Pluto (в `PlutoUtils.pas` или расширить `BoardUtils`), чтобы per-band настройки/калибровка работали. - XVTR-реле у Pluto нет → вкладка Transverter в упрощённом виде (только программный сдвиг частоты), либо скрыть, оставив встроенную перестройку LO. ### 6.11 Гейтинг UI (`MainForm` + `SettingsForm`) - Везде, где сейчас `BoardType in [...]` или прямые предположения о HPSDR — заменить на `FBackend.Caps.*`. - `SettingsForm`: вкладки `Antenna/Alex`, `Transverter`, контролы Tip/Ring, ADC dither/random, PA-калибровка показывать только при соответствующих Caps. Для Pluto добавить секцию «Pluto RF» (gain mode, gain, RF bandwidth, LO offset). - Главная форма: кнопки/оверлеи Wideband, ATT, SWR-индикатор — скрывать по Caps. --- ## 7. Сборка и зависимости - **Линковка libiio:** предпочтительно **рантайм-загрузка** (`dynlibs`) — приложение работает без libiio (Pluto просто не появляется в discovery). Имена: Linux `libiio.so.0`, Windows `iio.dll` (libiio MSVC/MinGW сборка), macOS `libiio.dylib` или `/Library/Frameworks/iio.framework`. - Если выбрать link-time (как WDSP `{$linklib}`) — добавить путь в `ewsdr.lpi` (`-k-L...`) и `{$linklib iio}` под `{$IFDEF DARWIN}`/нужные платформы. - `ewsdr.lpr`: добавить `IIO, SDRBackend, PlutoBackend, BoardCaps` в `uses`. - `ewsdr.lpi`: внести новые `.pas` в список файлов проекта. - `bundle_app.sh`: при сборке macOS-бандла копировать `libiio.dylib` и его зависимости (как уже делается для прочих не-системных dylib). - `BUILD.MD`: отметить опциональную зависимость и где взять libiio (пакет `libiio` / Analog Devices релизы). - Документация: dev-права на USB (Linux udev-правило для Pluto `0456:b673`), доступ к `ip:192.168.2.1`. --- ## 8. План работ по фазам ### Фаза 0 — Подготовка и каркас абстракции (без поведения Pluto) 1. `BoardCaps.pas`: `TBoardCaps`, `BoardCapsFor` (заполнить для всех HPSDR-плат). 2. `SDRBackend.pas`: `TSDRBackend` (абстракт), `THPSDRBackend` (обёртка над существующим `THPSDRNetwork`), фабрика, `TSDRKind`. 3. `MainForm`: перевести `FNetwork` на `FBackend: TSDRBackend` (= `THPSDRBackend`), все вызовы — через backend. Колбэки — через backend. 4. **Критерий приёмки:** поведение с openHPSDR полностью идентично текущему (регресс-проверка RX/TX/discovery/settings). Pluto ещё нет. ### Фаза 1 — libiio биндинги и discovery Pluto 1. `IIO.pas`: рантайм-загрузка + нужные функции; `IIOAvailable`. 2. `TPlutoBackend.Discover` (scan-context) → список Pluto-URI. 3. `DeviceForm`: тип устройства в списке найденных; расширить `TSavedDevice` и INI; панель Pluto-параметров; результат с `Kind`/URI. 4. Идентификация Pluto по serial; ключ Settings. 5. **Критерий:** Pluto находится в discovery, сохраняется/загружается, подключение `iio_create_context_from_uri` успешно (без стрима). ### Фаза 2 — RX-стрим Pluto → WDSP 1. `TPlutoBackend`: конфигурация phy (LO, sampling_frequency, rf_bandwidth, gain mode/gain), создание RX-буфера, RX-поток. 2. Repack int16→24-bit BE → синтез `TDDCIQPacket` → `OnDDCIQ`. 3. `SampleRateOverlay`/валидация по `Caps` (min 521к). 4. MainForm START/STOP-ветка для Pluto (вместо `ConfigureDDCs`/`SetRunAndFreq` — вызовы backend, которые у Pluto означают set-rate + start-stream). 5. **Критерий:** живой спектр/водопад и аудио с Pluto на FM/AM/SSB. ### Фаза 3 — TX-стрим Pluto 1. TX-буфер, TX-поток (`iio_buffer_push`), 24-bit→int16. 2. `SendDUCIQ`/`SendPTT` для Pluto; drive→TX hardwaregain. 3. Split/duplex LO RX/TX. 4. **Критерий:** передача SSB/FM, корректный уровень, отсутствие underrun. ### Фаза 4 — UI-гейтинг и Pluto-специфика 1. Заменить все `BoardType in [...]` на `Caps`. 2. Скрыть Alex/XVTR/Wideband/Dither/SWR для Pluto; показать RX gain / AGC mode / RF bandwidth; temp вместо supply. 3. VHF/UHF/SHF бэнд-план; расширенный ввод частоты до 6 ГГц. 4. Замер CPU/латентности на высоких rate; тюнинг буферов/FIR. 5. **Критерий:** UI согласован с возможностями железа для обоих типов. ### Фаза 5 — Полировка, сборка, документация 1. `bundle_app.sh`/`lpi`/`BUILD.MD`/udev. 2. Обработка ошибок libiio (`iio_strerror`), реконнект, выдёргивание USB. 3. Регресс-тесты openHPSDR + Pluto. --- ## 9. Риски и открытые вопросы 1. **WDSP на высоких sample rate (521к–3М):** проверить CPU/латентность; возможно нужен меньший `BufSize` для Pluto или FIR-децимация Pluto. 2. **Идентификация Pluto (нет MAC):** окончательно выбрать ключ Settings — расширять `THPSDRDevice` (поле `Serial`/`URI`) или вводить новый device-info тип. Влияет на форму и Settings — решить в Фазе 1. 3. **USB-троттлинг:** верхняя граница реального непрерывного rate по USB 2.0 (~5–6 МS/s); пометить «USB limit» в overlay. 4. **libiio на Windows/macOS:** наличие готовых сборок `iio.dll`/`libiio.dylib`; рантайм-загрузка снижает риск отсутствия. 5. **Масштаб/нормировка IQ:** подтвердить, что `<<12` даёт правильный уровень S-метра (калибровка по WDSP); при необходимости — поправочный коэффициент. 6. **TX gain маппинг:** диапазон слайдера drive → TX atten подобрать на железе. 7. **Discovery-таймаут:** libiio-scan может блокировать; запускать в потоке (как `TDiscoverThread`) и не вешать UI. --- ## 10. Тест-план - **Регресс openHPSDR:** discovery, connect, RX все режимы, TX SSB/CW/FM, Alex/XVTR/wideband, supply/SWR — без изменений после Фазы 0. - **Pluto RX:** discovery (USB и IP), connect, спектр/водопад/аудио на разных rate (521к/768к/1.5М), смена LO в пределах диапазона, gain manual/AGC. - **Pluto TX:** SSB/FM, уровень по drive, split RX/TX, отсутствие drop/underrun (логи seq/drops). - **UI-гейтинг:** при Pluto скрыты Alex/XVTR/Wideband/SWR/dither; показаны RX gain/AGC/RF bandwidth/temp. - **Устойчивость:** выдёргивание USB / разрыв сети → корректный Disconnect, reconnect, отсутствие крэшей; запуск без установленной libiio. - **Кросс-платформа:** Linux (qt6) обязательно; Windows/macOS — по мере доступности libiio. --- ## 11. Принципы, которых держимся - `HPSDRNetwork.pas`, `WDSPEngine.pas`, `WDSP.pas` — **не меняем** (или минимально: опц. `PushIQDoubles`). Pluto-логика — в новых файлах. - Один источник правды о возможностях железа — `TBoardCaps`. - Pluto переиспользует существующий DSP-конвейер за счёт repack в 24-bit BE. - Discovery-форма сохраняет раскладку; Pluto-параметры — дополнительная панель.