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>
34 KiB
Интеграция ADALM-PLUTO (libiio) в EWSDR — полный план работ
Цель: добавить поддержку PlutoSDR (AD9363/AD9364) через libiio как второй тип «железа» наряду с трансиверами openHPSDR. Discovery-форма остаётся прежней, но дополняется board-специфическими параметрами Pluto. В UI скрываются функции, которых у Pluto нет, и появляются те, что есть только у Pluto. Весь DSP по-прежнему идёт через WDSP. Платформенно- специфичный код выносится в отдельные файлы, чтобы не загромождать существующую логику openHPSDR.
0. Краткое резюме решения
- Ввести тонкий слой абстракции backend'а (
SDRBackend.pas,TSDRBackend), описывающий ровно тот API, которымMainFormсегодня пользуется уTHPSDRNetwork. СуществующийTHPSDRNetworkобворачивается адаптеромTHPSDRBackend(код самогоHPSDRNetwork.pasне трогаем). - Новый backend Pluto —
PlutoBackend.pas(TPlutoBackend), и низкоуровневые биндинги libiio —IIO.pas(по образцуWDSP.pas). - Поток IQ от Pluto (int16 LE) переупаковывается в тот же 24-битный
big-endian формат, что и openHPSDR, и подаётся в существующий
TWDSPEngine.PushDDCPacket— DSP-конвейер не меняется. - Возможности железа описываются записью
TBoardCaps(BoardCaps.pas).MainForm/SettingsFormгейтят UI поCaps, а не по жёстким спискамBoardType in [...]. - Discovery-форма расширяется панелью Pluto-параметров (URI, gain mode, gain, RF bandwidth, sample rate, диапазон LO) — раскладка прежняя.
- Минимальный 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 → callbackOnDiscover→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),DisconnectConfigureDDCs(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.
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 — описание возможностей (НОВЫЙ)
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:<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. - Решение (минимальная инвазивность): в
TPlutoBackendRX-потоке переупаковывать каждый 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). Имена: Linuxlibiio.so.0, Windowsiio.dll(libiio MSVC/MinGW сборка), macOSlibiio.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)
BoardCaps.pas:TBoardCaps,BoardCapsFor(заполнить для всех HPSDR-плат).SDRBackend.pas:TSDRBackend(абстракт),THPSDRBackend(обёртка над существующимTHPSDRNetwork), фабрика,TSDRKind.MainForm: перевестиFNetworkнаFBackend: TSDRBackend(=THPSDRBackend), все вызовы — через backend. Колбэки — через backend.- Критерий приёмки: поведение с openHPSDR полностью идентично текущему (регресс-проверка RX/TX/discovery/settings). Pluto ещё нет.
Фаза 1 — libiio биндинги и discovery Pluto
IIO.pas: рантайм-загрузка + нужные функции;IIOAvailable.TPlutoBackend.Discover(scan-context) → список Pluto-URI.DeviceForm: тип устройства в списке найденных; расширитьTSavedDeviceи INI; панель Pluto-параметров; результат сKind/URI.- Идентификация Pluto по serial; ключ Settings.
- Критерий: Pluto находится в discovery, сохраняется/загружается,
подключение
iio_create_context_from_uriуспешно (без стрима).
Фаза 2 — RX-стрим Pluto → WDSP
TPlutoBackend: конфигурация phy (LO, sampling_frequency, rf_bandwidth, gain mode/gain), создание RX-буфера, RX-поток.- Repack int16→24-bit BE → синтез
TDDCIQPacket→OnDDCIQ. SampleRateOverlay/валидация поCaps(min 521к).- MainForm START/STOP-ветка для Pluto (вместо
ConfigureDDCs/SetRunAndFreq— вызовы backend, которые у Pluto означают set-rate + start-stream). - Критерий: живой спектр/водопад и аудио с Pluto на FM/AM/SSB.
Фаза 3 — TX-стрим Pluto
- TX-буфер, TX-поток (
iio_buffer_push), 24-bit→int16. SendDUCIQ/SendPTTдля Pluto; drive→TX hardwaregain.- Split/duplex LO RX/TX.
- Критерий: передача SSB/FM, корректный уровень, отсутствие underrun.
Фаза 4 — UI-гейтинг и Pluto-специфика
- Заменить все
BoardType in [...]наCaps. - Скрыть Alex/XVTR/Wideband/Dither/SWR для Pluto; показать RX gain / AGC mode / RF bandwidth; temp вместо supply.
- VHF/UHF/SHF бэнд-план; расширенный ввод частоты до 6 ГГц.
- Замер CPU/латентности на высоких rate; тюнинг буферов/FIR.
- Критерий: UI согласован с возможностями железа для обоих типов.
Фаза 5 — Полировка, сборка, документация
bundle_app.sh/lpi/BUILD.MD/udev.- Обработка ошибок libiio (
iio_strerror), реконнект, выдёргивание USB. - Регресс-тесты openHPSDR + Pluto.
9. Риски и открытые вопросы
- WDSP на высоких sample rate (521к–3М): проверить CPU/латентность;
возможно нужен меньший
BufSizeдля Pluto или FIR-децимация Pluto. - Идентификация Pluto (нет MAC): окончательно выбрать ключ Settings —
расширять
THPSDRDevice(полеSerial/URI) или вводить новый device-info тип. Влияет на форму и Settings — решить в Фазе 1. - USB-троттлинг: верхняя граница реального непрерывного rate по USB 2.0 (~5–6 МS/s); пометить «USB limit» в overlay.
- libiio на Windows/macOS: наличие готовых сборок
iio.dll/libiio.dylib; рантайм-загрузка снижает риск отсутствия. - Масштаб/нормировка IQ: подтвердить, что
<<12даёт правильный уровень S-метра (калибровка по WDSP); при необходимости — поправочный коэффициент. - TX gain маппинг: диапазон слайдера drive → TX atten подобрать на железе.
- 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-параметры — дополнительная панель.