Add a thin colored strip along the bottom of the spectrum (above the ruler) showing the QO-100 narrow-band transponder bandplan: mode segments (CW ONLY / NB DIGI / DIGI / SSB / MIXED MODES) plus the three beacons (CW / PSK / EXP) as muted-red cells at their ranges. - New unit BandPlanOverlay.pas (TBandPlanOverlay), modelled on VfoOverlay: content rendered once into a cache bitmap, per-frame cost is just a constant-alpha composite (CPU) / one textured quad (GL). Cache invalidates only on view change (center/span/width) so it idles while the QO-100 downlink display is static. - Wired into both render paths: SpectrumView (CPU composite) and SpectrumViewOpengl (texture, re-uploaded only when dirty). - MainForm: SetView fed from SyncSpecViewFreq; visibility gated by InQO100 (Pluto + full-duplex transponder), like RX MUTE / BEACON. - DPI-robust: strip height scales with Screen.PixelsPerInch and the font height is tied to the strip height (not point size), so labels always fit at any Windows scaling. - Segment/beacon frequencies and colors are a single editable table. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
29 KiB
План интеграции ADALM-PLUTO (PlutoSDR) в EWSDR
Ветка: feature/pluto-sdr-integration (от feature/radio-controller-refactor).
Документ — результат анализа текущей кодовой базы и предлагаемый поэтапный план. Цель: добавить второй бэкенд железа (Pluto, libiio/AD936x) рядом с openHPSDR так, чтобы оба находились в одном окне discovery, а различия возможностей корректно отражались в UI (включая оверлей samplerate с другими значениями для Pluto).
Ключевые решения по продукту:
- Pluto — только VHF/UHF, HF исключён. Свой band-план: 2 м, 70 см, 23 см, 13 см (и т.д.).
- Отдельный режим QO-100 (геостационарный транспондер): RX через LNB, TX напрямую на 2400 МГц, раздельные RX/TX LO, full-duplex.
1. Анализ текущей архитектуры
1.1 Слои и владение
TMainForm (GUI) ─┐
ewsdrd.lpr (демон)─┤── владеют ─→ TRadioController (backend-агностичное ядро)
WebServer/Adapter ─┘ │
├─ FNetwork: THPSDRNetwork ← ЕДИНСТВЕННАЯ точка железа
├─ FDSPEngine: TWDSPEngine
├─ FAudioOut / FAudioIn
├─ FSettings: TSettingsManager (per-device по MAC)
└─ FDeviceStore: TDeviceStore (saved + discovered)
TRadioController уже спроектирован как backend-агностичное ядро — в коде есть
прямые комментарии-намёки на Pluto (RadioController.pas:541, :603). Но
FNetwork объявлен конкретным типом THPSDRNetwork, а не интерфейсом, и
используется в 52 местах контроллера.
1.2 Путь данных (ключевое для бэкенда)
RX (вход IQ):
THPSDRNetwork (RX-поток, UDP 1035) → OnDDCIQ(DDCIndex, TDDCIQPacket)
→ FDSPEngine.PushDDCPacket(Data.IQData, 0, SamplesPerFrame)
IQ — 24-битные интерливнутые пары I/Q (6 байт/пара), формат зашит в
PushDDCPacket (WDSPEngine.pas:1136) и в декодере DSP-потока.
TX (выход IQ):
WDSP TXA → OnTXIQ(Buf, Count) → накопление 240 пар (24-бит, clamp)
→ FNetwork.SendDUCIQ(I[], Q[])
Телеметрия: OnHPStatus(THighPriorityStatus) → fwd power / SWR / supply V/A /
PLL lock / ADC overload. S-meter считается отдельно в WDSP (FLastSMeter).
1.3 Discovery
FController.Discover → TDiscoverThread → FNetwork.Discover(2000)
(UDP broadcast :1024, CMD_DISCOVERY)
→ per device: OnDeviceFound(THPSDRDevice)
→ FDeviceStore.AddDiscovered(...) → Changed(rfDeviceList)
→ DeviceForm.RefreshFound (один список «DISCOVERED DEVICES»)
THPSDRDevice: IP, Port, MAC[6], BoardType, ProtocolVersion, NumDDCs…TDeviceStore:TSavedDevice(Name/IP/BoardType/AutoStart) иTDiscoveredDevice(IP/DisplayName/BoardType/MAC[6]).- Per-device настройки (
Settings.pas) ключуются по MAC черезMacToStr(MAC)→ строковая секция JSON.LoadDevice/LoadTX/LoadAlex/LoadXvtrвсе принимаютMAC: array of Byte.
1.4 Sample rate
SampleRateOverlay.pas— жёстко зашитый массивSPAN_RATES = (48000,96000,192000,384000,768000,1536000)иSPAN_NAMES.SetSampleRate(Hz)(RadioController.pas:1791): span ≡ sample rate;FDSPEngine.ChangeSampleRate(Hz)+FNetwork.ConfigureDDCs(1, Hz div 1000, …).- Дискретные значения HPSDR кратны DSP-clock 122.88 МГц.
1.5 Частота / диапазоны / XVTR
FreqToPhaseWord(HPSDRProtocol.pas): phase = 2³² · f / 122.88 МГц.FreqToBandIdx/ band-план — HF/6m (1.8–54 МГц, 11 диапазонов).- Есть полноценная XVTR-подсистема (8 слотов, LO offset/error, трансляция
видимой частоты в IF,
XvtrTranslate) — но один LO-offset на слот (RX=TX). Для QO-100 нужны раздельные RX/TX LO → отдельная модель (см. §4). SetDuplex(RadioController.pas:1851) — сейчас заглушка ({TODO wiring}). Для QO-100 full-duplex это нужно довести.
2. Pluto: что отличается (capability-матрица)
| Возможность | openHPSDR | Pluto (AD936x) |
|---|---|---|
| Транспорт | UDP/Ethernet (свой) | libiio: USB / IP / local |
| Discovery | UDP broadcast :1024 | iio_scan_context (USB/network/local) |
| Идентификатор | MAC[6] | serial / context URI |
| Кол-во приёмников (DDC) | до 80, sync | 1 RX (2×2 только с хаком прошивки) |
| Sample rate | дискрет 48k…1536k | непрерывный, ≥ ~521 ksps, до 61.44 MSPS (по USB2 практически ~5–6 MSPS) |
| RF-полоса (аналог. фильтр) | нет (фикс CIC) | отдельная настройка RX/TX LPF |
| Диапазон частот | 0–61.44 МГц (HF/6m) | 325 МГц–3.8 ГГц (сток), 70 МГц–6 ГГц с хаком. HF не используем |
| Разрядность IQ | 24-бит | 12-бит ADC, по шине 16-бит |
| Усиление RX | step atten + dither/random | manual gain 0–73 дБ / AGC (slow/fast/hybrid/manual) |
| TX | DUC + PA + Alex T/R | 1 DAC, TX atten −89…0 дБ, без PA/SWR |
| Full-duplex | (зависит) | да (раздельные RX/TX LO) — нужно для QO-100 |
| S-meter | WDSP (есть) | WDSP (есть) + аппаратный RSSI |
| Fwd power / SWR / supply V/A | HP status | нет (нет PA) |
| PLL lock | HP status | нет (другой механизм) |
| ADC overload | HP status | косвенно (gain/RSSI) |
| Wideband ADC дисплей | есть | нет |
| Alex / антенный коммутатор | есть | нет |
| Mic over network / HW CW keyer / sidetone / open collector | есть | нет (TX-аудио через звуковую карту/web) |
| 10 МГц reference / PA config | есть | нет; есть XO ppm-калибровка, темп.сенсор |
Только у Pluto (нужно в UI): RF bandwidth, manual gain / режим AGC железа, XO ppm-коррекция, выбор транспорта (USB/IP), buffer size/timeout, температура.
3. Band-план Pluto (VHF/UHF) и режим QO-100
3.1 VHF/UHF band-план
HF исключён. Для Pluto — отдельная таблица диапазонов (используется, когда
подключён бэкенд bkPluto); FreqToBandIdx/band-кнопки переключаются на неё:
| Band | Частоты | Примечание |
|---|---|---|
| 2 м | 144–146 МГц | требует freq-range хак Pluto (<325 МГц) |
| 70 см | 430–440 МГц | требует freq-range хак Pluto |
| 23 см | 1240–1300 МГц | нативно |
| 13 см | 2300–2450 МГц | нативно (включает QO-100 uplink 2400) |
| (опц.) FM bcast / ADS-B / прочие — позже |
⚠️ 2 м и 70 см ниже стокового минимума 325 МГц → нужен AD9363→AD9361 frequency-range мод прошивки Pluto. В UI/доках это отметить.
3.2 Режим QO-100 (геостационар Es'hail-2 NB-транспондер)
Геометрия сигнала:
- Downlink (RX): 10489.50–10489.99 МГц (10 ГГц). Принимается через LNB: LNB LO (обычно 9750 МГц) → Pluto RX ≈ 739.5–739.99 МГц. Нативный диапазон Pluto.
- Uplink (TX): 2400.05–2400.54 МГц. Pluto TX напрямую (нативно).
- Связь частот: uplink = downlink − 8089.5 МГц (offset транспондера).
- Full-duplex — стандартный режим работы (слышишь себя через спутник).
Отсюда QO-100 — это трансвертер с раздельными RX/TX LO, чего нынешняя XVTR-модель (один offset) не даёт. Предлагаемая модель — отдельная подсистема/слот:
TQO100Settings = record
Enabled: Boolean;
DisplayBase: Double; // отображаем downlink (10489.x ГГц)
LnbLoHz: Double; // LO LNB, по умолч. 9750e6
LnbPpm: Double; // калибровка дрейфа LNB (по маяку)
TransponderOfs: Double; // 8089.5e6 (downlink - uplink)
TxAttenDb: Double; // -89..0
FullDuplex: Boolean; // RX во время TX
end;
Трансляция:
- RX:
PlutoRxLO = DisplayFreq − LnbLoHz(с учётомLnbPpm). - TX:
PlutoTxLO = DisplayFreq − TransponderOfs. - Дисплей/VFO/курсор работают в терминах downlink (10 ГГц).
- Калибровка по маяку: подстройка
LnbPpm, чтобы наблюдаемый маяк совпал с опорной частотой.
Требует довести SetDuplex (сейчас TODO) до реального full-duplex (одновременно
RX-поток refill и TX-поток push в libiio — Pluto это поддерживает аппаратно).
4. Предлагаемая архитектура интеграции
4.1 Абстракция бэкенда (ядро плана)
Базовый класс/интерфейс TRadioBackend, который реализуют оба:
THPSDRNetwork и новый TPlutoBackend. Контроллер держит FBackend: TRadioBackend
(сохранить имя поля FNetwork, сменив только тип на базовый — минимизирует дифф).
Методы, которых у Pluto нет, — пустые no-op (Alex, wideband, step atten, speaker
audio, DUC specific и т.д.).
Дескриптор возможностей:
TBackendKind = (bkHPSDR, bkPluto);
TSampleRateMode = (srmDiscrete, srmContinuous);
TBackendCaps = record
Kind: TBackendKind;
HasTX, HasPA, HasAlex, HasWideband: Boolean;
HasDitherRandom, HasHWMic, HasPLLStatus: Boolean;
HasHWGain: Boolean; // manual gain / hw AGC (Pluto)
HasRFBandwidth: Boolean;
HasFullDuplex: Boolean;
MinSampleRate, MaxSampleRate: Integer;
SampleRateMode: TSampleRateMode;
RatePresets: array of Integer; // для оверлея
MinFreqHz, MaxFreqHz: Double;
end;
Контроллер по FBackend.Caps: гейтит UI, подставляет пресеты samplerate,
выбирает band-план (VHF/UHF), путь телеметрии.
4.2 libiio binding
- FPC-биндинг к
libiio(и опц.libad9361) через динамическую загрузку (dynlibs):libiio.so/libiio.dll/libiio.dylib. Приложение запускается без libiio (Pluto просто не появляется в discovery). - Новые юниты:
IIOBindings.pas(типы/прототипы) +PlutoBackend.pas(TPlutoBackend: scan/connect, RX/TX потоки, gain/freq/rate/bandwidth).
4.3 Discovery в одном окне
- Расширить записи устройств:
Kind: TBackendKind,URI: string(Pluto:usb:1.5.5/ip:192.168.2.1),Serial: string. TDiscoverThreadзапускает оба скана параллельно, сливает в один store: HPSDR (FNetwork.Discover) + Pluto (iio_create_scan_context).DeviceFormструктурно не меняется: тот же список, лишь метка типа в строке (PlutoSDR usb:1.5.5).BoardTypeName/рендер дополнить веткой Pluto.ConnectDeviceдиспетчеризует поKind: создаёт нужный бэкенд перед Connect.
4.4 Ключ per-device настроек
Минимальное изменение: для Pluto синтезировать 6-байтовый ключ из serial
(хэш serial → 6 байт) и подавать в существующие LoadDevice/LoadTX/.... Settings.pas
не трогаем. (Альтернатива — обобщить ключ до строки; дороже, отложить.)
4.5 Sample rate overlay
TSampleRateOverlayполучает список значений/имён от контроллера (SetRatePresets). HPSDR — текущие 48k…1536k. Pluto — пресеты > 560 кбит, напр.768k / 1536k / 2304k / 3072k / 3840k / 5760k.SetSampleRateдля Pluto зовётFBackend(setsampling_frequency+rf_bandwidth), безConfigureDDCs.
4.6 IQ-конвертация (формат WDSP не меняем)
- RX:
TPlutoBackendчитает int16 изiio_buffer, конвертирует 16→24-бит, упаковывает вTDDCIQPacket(seq синтезируется), вызываетOnDDCIQ. - TX: ✅
SendDUCIQапсемплит 192k→device-rate полифазным FIR-интерполятором ×L (BuildTxResampler: оконный sinc-ФНЧ, окно Блэкмана ~−58 дБ,TX_FIR_TAPS=16отводов/фазу, срезTX_FIR_CUT=40 кГц, нормировка на единичное DC-усиление фазы; пресеты рейта кратны 192k → L целое), конвертирует 24→16-бит (>>8, full-scale MSB-aligned), инвертирует Q (симметрично RX) и кладёт в кольцевой FIFO. Линия задержкиFTxDlI/Qживёт между вызовами, сбрасывается вStartTX/ClearDUCIQQueue. ОтдельныйTPlutoTXThreadльёт пары в tx-буфер libiio иiio_buffer_push(блокирующий push = пейсинг на device-rate); при underrun — нули (непрерывный full-duplex). Решение rate-mismatch (риск §6.2) — апсемпл в host (RX/TX делят одинsampling_frequency). - Размер TX-буфера масштабируется от device-rate (модель SoapyPlutoSDR):
round(rate/60)→ следующая степень 2, кламп[4096..65536](576k→16384, 1536k→32768). Фикс 4096 был мал для full-duplex выше ~1 Msps → дропы/щелчки. FIFO держит ~4 таких буфера запаса (TxBufPairsForRate, пересчёт вStartTX). - Подтверждено по каноничному драйверу (SoapyPlutoSDR): TX full-scale = 32768,
MSB-aligned → наш
>>8(24→16) верен; занижения уровня по дизайну нет.
4.7 Усиление / телеметрия
- ✅ RX gain: блок
RF AGC(десктоп) — кнопки FAST/SLOW/HYB/MAN (4 режима AD9361, подтверждены на железеgain_control_mode_available) + слайдер manual 0–73 дБ приCaps.HasHWGain; персист per-device. WDSP AGC поверх. TODO: проброс RF-AGC в web (сейчас в web только отображение, без управления). - Телеметрия: S-meter (WDSP) — для обоих. fwd/SWR/supply/PLL/overload — скрыть при
not Caps.HasPA. ✅ RSSI/температура Pluto:ReadTelemetry(backend) →ServicePlutoTelemetry(контроллер, опрос ~2 Гц с фильтром выбросов) → поле 3 статус-бара (Temp/RSSI вместо Supply, т.к. у Pluto нет PA). ✅ Две температуры: трансивер AD9361 (ad9361-phy temp0) + Zynq SoC/FPGA (xadc temp0,(raw+offset)*scale/1000) — форматTemp 37/53Cв десктопе и web.
4.8 TX-мощность / drive (Pluto)
- ✅ Мощность задаётся ОДИН раз — железной аттенюацией (
hardwaregain), а не цифрой WDSP.ApplyWDSPDrive(контроллер): на PlutoSetDriveLevel(1.0)(полная цифра), HPSDR —Pct/100. Раньше drive резался дважды (цифра × атт). - ✅
PlutoTxAttForDrive— power-linear:дБ = потолок + 20·log10(pct/100)(100% → потолок, 50% → −6, 10% → −20). Старый dB-линейный маппинг от −89.75 уводил низкие % в −80 дБ — из-за этого TUN (TUNLevel 10%) давал −81.8 дБ → тон не слышен. Потолок —FPlutoTxMaxAttDb(дефолт −10 дБ), на приёме −89.75 (≈выкл). - ✅ TX LO (
altvoltage1) гасится по PTT (SetTxLOPowerdown): на приёмеpowerdown=1→ нет утечки несущей TX на частоте VFO в RX-спектре и нет излучения в простое; на передачеpowerdown=0.ApplyTxLOставит powerdown поFTransmitting(заодно возвращает LO, если стороннее ПО его погасило). RX LO (altvoltage0) — всегда вкл (приём непрерывен, QO-100 full-duplex не ломается). Цена: повторное включение LO запускает калибровку синтезатора AD9361 (единицы–десятки мс) → первый слог SSB может чуть подрезаться.
5. Поэтапный план (фазы)
Фаза 0 — Абстракция (без поведения Pluto)
TRadioBackend(база) +TBackendCaps;THPSDRNetworkреализует, заполняет caps. Сменить типFNetwork/вызовы. Регрессия: HPSDR как раньше. ✅
Фаза 1 — libiio binding + discovery
IIOBindings.pas,PlutoBackend.pas(skeleton: scan/connect/disconnect/caps).Kind/URI/Serialв store, объединённый discovery, диспетчер поKind.- UI: оба типа в одном окне. ✅ (видим Pluto, ещё без RX).
Фаза 2 — RX-тракт Pluto + VHF/UHF band-план
- RX-поток libiio → 16→24-бит →
OnDDCIQ→ WDSP. Set freq (Hz в LO), gain, sample rate, RF bandwidth. - VHF/UHF band-план (§3.1) при
bkPluto; samplerate-оверлей с Pluto-пресетами. - Гейтинг UI по caps. ✅ приём на Pluto (спектр/водопад/аудио на 2м/70см/23см/13см).
Фаза 3 — Управление/калибровка
- ✅ RX gain / hw-AGC, транспорт (USB/IP), persist per-device по synthetic-MAC.
- ✅ Имя платы (Pluto/LibreSDR + serial) и телеметрия в статус-бар: RSSI + две
температуры (трансивер AD9361 + Zynq SoC
xadc, форматTemp 37/53C). - TODO: XO ppm-калибровка, buffer/timeout-контролы.
Фаза 4 — TX-тракт Pluto ✅
- ✅
SendDUCIQ24→16 + апсемпл 192k→device-rate + пейсинг (FIFO + push-поток, §4.6). - ✅ Полифазный FIR-интерполятор вместо линейной интерполяции (§4.6) — образы на кратных 192k давятся ~−58 дБ (раньше только sinc²), чище аплинк, громкость не меняется.
- ✅ TX-буфер по sample-rate (§4.6) — устранены щелчки/дропы на full-duplex >1 Msps.
- ✅ Управление мощностью через TX-аттенюацию (ADI-модель), маппинг power-linear
- полная цифра WDSP (§4.8). Без PA → нет drive-байта/SWR/Alex/keyer.
- ✅ TX LO powerdown по PTT (§4.8) — нет утечки несущей TX в RX-спектре в простое.
- TODO: проверка на железе на rate ≥1536k (ориентация SSB по Q-инверсии, уровни);
опц. headroom −6 дБ для FM (full-scale const-envelope → нелинейность ЦАП); опц.
зануление IQ на приёме. Опц. поддержка F5OEO-прошивки (PTT внешнего PA через
hardwaregain=−40) — отложено, нужно только под конкретное железо.
Фаза 5 — Режим QO-100 ✅
- ✅ Калибровка LNB по маяку (beacon lock) — стабилизация дрейфа.
- ✅ Hardware full-duplex + ✅ display-duplex (
SetDuplexдоведён: живойKeepRXDuringTX; авто-вкл при входе в QO-100 — слышим свой downlink). - ✅ Раздельные RX/TX LO (§3.2): QO-100 = XVTR-слот с флагом
FullDuplexTx+TxLOOffset;XvtrTranslateTXдаёт TX-LO = visible−TxLOOffset (без LOError). RX-путь (LNB LO + beacon-дрейф) не тронут. Дисплей/VFO в downlink-терминах. - ✅ Отдельная страница «QO-100» в SettingsForm (LNB LO / транспондер-offset /
границы downlink / RX gain / TX-потолок); зарезервирован последний XVTR-слот
(
QO100_SLOT), не засоряет таблицу трансвертеров openHPSDR. - ✅ TX↔RX связка с фиксированным офсетом: TX-VFO в downlink-домене,
XvtrTranslateTX=visible − TxLOOffset(≈8089.5 МГц) — крутишь приём, аплинк едет следом, офсет держится сам (через общий VFO). Split — через VFO-B. - ✅ Аудио self-monitor («слышу себя со спутника»): кнопка
RX MUTEв TX-панели рядом с DUP — видна только Pluto + full-duplex (QO-100). По умолчанию ON (RX-аудио глушится на TX, как раньше); OFF → RX-аудио идёт на колонки и во время TX (свой downlink через транспондер, ~250 мс). Реализация: гейтWDSPEngine(not FTXActive or (FKeepRXDuringTX and FMonitorRXDuringTX)) + флагFRxMuteOnTxв контроллере, персист в глобале (rx_mute_on_tx). Web — не сделано (пока вне области). - ✅ Bandplan-оверлей NB-транспондера (
BandPlanOverlay.pas): полоска внизу спектра (над ruler) с сегментами CW ONLY / NB DIGI / DIGI / SSB / MIXED MODES + маяки CW/PSK/EXP. МодельVfoOverlay(кэш-битмап + const-alpha), CPU и GL, виден поInQO100. DPI-устойчив (высота и шрифт поScreen.PixelsPerInch). - TODO (визуальный self-monitor / навигация по транспондеру):
- Индикатор «не громче маяка» — сравнение уровня своего downlink с маяком (этикет QO-100); амплитуда маяка уже известна декодеру.
- RIT/XIT-клариффайер — опц., на геостационаре нужен редко.
- TODO: проверка на железе.
- ОТВЕРГНУТО: TX-маркер на RX-спектре в DUP — в обычной работе RX=TX (один VFO), маркер ложится на RX-курсор, информации не даёт; полезен только в split (редко).
Фаза 6 — Полировка ✅ (в основном)
- ✅ Web/CAT-фронтенды (команды уже агностичны) + гейтинг полей; демон
ewsdrd.lpr(discovery/connect Pluto headless, beacon-lock @10 Гц); кросс-платформенная сборка с/без libiio. - TODO: проброс в web того, чего там ещё нет — RF-AGC (gain/режимы) и QO-100
RX MUTE(self-monitor). Доки актуализируются по ходу.
Сопутствующие исправления (найдены при тесте Pluto VHF/UHF FM, но баги общие):
- ✅ Восстановление per-band FM-настроек на старте (
Settings.LoadDevice): bulk- загрузчик бэндов читал только freq/mode/filter/AGC/CTun/center/span и пропускал FM-поля (fmsq_on/fmsq_level/ctcss_*/fmstep_*/fmrpt_*), хотяSaveBandих пишет, аLoadBandчитает. Итог: SQL/CTCSS/шаг/репитер-сдвиг сохранялись на выходе, но сбрасывались в дефолт при следующем запуске (смена бэндов работала — идёт через in-memory band-cache). Затрагивало все бэкенды, не только Pluto.
6. Риски и открытые вопросы
- 2 м / 70 см ниже 325 МГц → требуется freq-range мод прошивки Pluto. Документировать; возможно гейтить эти кнопки при стоковой прошивке.
- ✅ TX sample-rate mismatch (192k WDSP vs ≥521k Pluto) — решено host-апсемплом
192k→device-rate в
SendDUCIQ(целочисленно, пресеты кратны 192k). ✅ Качество образов — полифазный FIR-интерполятор (окно Блэкмана ~−58 дБ). ✅ Щелчки на full-duplex >1 Msps — TX-буфер масштабируется от rate (модель SoapyPlutoSDR). - QO-100 display-duplex — hardware full-duplex есть (Фаза 4), остаётся довести
SetDuplex(водопад RX во время TX); проверить латентность/буферы libiio. - LNB дрейф — калибровка
LnbPpmпо маяку (ручная/полуавтомат). - Ключ настроек — synthetic-MAC из serial (быстро) vs обобщение до строки.
- libiio как зависимость — динамическая загрузка, поведение при отсутствии.
- USB-латентность/пропускная — реальный максимум sample-rate по USB2.
7. Затрагиваемые файлы (ориентир)
| Файл | Изменение |
|---|---|
RadioController.pas |
тип FBackend, диспетчер по Kind, гейтинг по caps, QO-100 трансляция |
HPSDRNetwork.pas |
реализовать TRadioBackend + заполнить caps |
IIOBindings.pas (нов) |
биндинг libiio (dynamic) |
PlutoBackend.pas (нов) |
TPlutoBackend (scan/connect/RX/TX/gain/rate/bw) |
DeviceStore.pas |
Kind/URI/Serial в записях |
DeviceForm.pas |
метка типа в списке (структурно без изменений) |
SampleRateOverlay.pas |
пресеты из контроллера вместо констант |
BoardUtils.pas |
имя Pluto, VHF/UHF band-план |
Settings.pas |
без изменений (synthetic-MAC) / QO-100 persist |
MainForm.pas / ewsdrd.lpr |
гейтинг виджетов по caps, wiring, QO-100 UI |