Files
ewsdr/pluto_integration.MD
T
Uladzimir KarpenkaandClaude Opus 4.8 f122079b83 Phase 5 (D2): move spectrum/waterfall raw frames into the controller
OnSpectrumReady/OnWaterfallReady move into TRadioController. The controller now
owns the last spectrum/waterfall frame (FSpectrumBuf/FWaterfallBuf) for the web
mirror and emits raw pixels via OnSpectrumData/OnWaterfallData. MainForm
subscribes for FSpecView rendering (+ waterfall scroll decimation, a UI concern).
TWebAdapter.PushState now reads the frame from the controller (no buffer params).
Behavior-preserving; removes the last spectrum/waterfall data-path coupling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 14:46:39 +03:00

34 KiB
Raw Blame History

Интеграция 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 OnDiscoverMainForm.BtnDiscoverFromDialogTDiscoverThreadFNetwork.DiscoverOnDeviceFoundFDeviceDialog.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_listiio_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 073 дБ (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) 0255 TX atten dB переинтерпретировать
Alex антенны/фильтры да нет скрыть вкладку
XVTR (реле) да только сдвиг показать упрощённо
Wideband ADC панель да нет скрыть
Supply V / A часть плат нет (есть temp) заменить на temp
Fwd/Rev power, SWR да нет скрыть SWR/PWR
RF bandwidth фикс. настраиваемый показать для Pluto
Диапазон частот 061.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.

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 TPlutoBackendPlutoBackend.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 → синтетический THighPriorityStatusFOnHPStatus (S-метр + температура).
  • Discoveriio_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 — описание возможностей (НОВЫЙ)

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.pasTPlutoBackend (RX/TX/telemetry потоки, repack).
  • SDRBackend.pasTSDRBackend + THPSDRBackend-адаптер + TSDRKind.
  • BoardCaps.pasTBoardCaps + BoardCapsFor.
  • PlutoUtils.pas (опц.) — частотные бэнд-планы/пресеты для VHF/UHF/SHF.

Изменяемые:

  • MainForm.pasFNetwork: THPSDRNetworkFBackend: TSDRBackend (+ фабрика по Kind); гейтинг UI по FBackend.Caps; телеметрия; drive/gain; START/STOP.
  • DeviceForm.pasTSavedDevice += поля 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:<serial>.
  • 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 слайдер (073 дБ) и 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 → синтез TDDCIQPacketOnDDCIQ.
  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 (~56 М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-параметры — дополнительная панель.