@@ -1,518 +0,0 @@
# Интеграция 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:<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 слайдер (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-параметры — дополнительная панель.