other/padump.lpr, patest2.lpr, patest3.lpr писались для диагностики
зависания при выборе входа на слайсе (двойное открытие устройства, дамп
PA-списка). Баг закрыт как невоспроизводимый, зонды в сборку не входят и
ниоткуда не вызываются — при надобности достаются из истории (4aa180e).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VfoOverlay запоминает прямоугольник списка (FAudListRect) и обрабатывает
колесо над ним (HandleMouseWheel): шаг = одна строка. Если курсор в этой
зоне, событие считается обработанным и не уходит в спектр — частота не
съезжает даже когда список целиком помещается и крутить нечего.
PanafallPanel.DispatchFlagsMouseWheel перебирает главный флаг и флаги
слайсов (как остальные Dispatch*), MainForm.FormMouseWheel зовёт его по
всем панам первым делом после дисплеев VFO; координаты берутся через
PbSpectrum.ScreenToClient(Mouse.CursorPos), поэтому работает и в pop-out.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
При раскрытии fly-out AUD (и при переключении вкладок OUT/IN) список
теперь прокручивается к текущему устройству — выбранная строка ставится
примерно в середину видимого окна, а не приходится искать её стрелками.
Ручной скролл при этом не сбрасывается: push списков от контроллера
(SetAudioDevices/SetAudioInDevices) позицию не трогает.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
TX-бейдж на флаге слайса был заблокирован и для DMR, и для FM RAW, хотя тракт
FM RAW передавать умеет: SetTxSlice отбрасывает только DMR, а SetTXMode уводит
FM RAW в WFM с плоской девиацией. RX-only остаётся один DMR (нет AMBE-кодера).
- VfoOverlay.TxSelectionAllowed: запрет сузился до DMR.
- RadioController.SetSliceMode: если режим меняют у слайса, который сейчас
источник TX, передающий тракт перестраивается под новый режим. Без этого
выбор FM RAW на уже выбранном TX-слайсе оставлял в эфире прежнюю модуляцию
до следующего клика по бейджу. На переходах в/из FM RAW заодно пересматривается
источник модуляции (внешний PCM) со сбросом кольца входа — как в главном
SetMode.
Заодно снята временная диагностика [MIC] (MicDbg и её вызовы) из mic-пула:
зависание при выборе на слайсе входа из настроек больше не воспроизводится.
Проверено на железе: TX со слайса в FM RAW работает. Подробное тестирование —
следующим шагом.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Настройки персистятся секцией по MAC радио, но ResolveDevice брал MAC только из
списка найденных дискавери. У сохранённых устройств поля MAC не было вовсе, и
START по AutoStart/CONNECT без дискавери шёл с MAC 00:00:00:00:00:00 — грузился
и сохранялся чужой профиль. Пользователь видел «настройки сбросились»: выключался
wideband, менялся sample rate, терялись банды и паны, причём в зависимости от
того, нажимал ли он перед стартом DISCOVER.
- DeviceStore: у TSavedDevice поле MAC + persist в hpsdr_devices.ini (MAC=..),
FindSavedByAddr/SetSavedMac (пишет ini только при изменении), MacIsZero.
- RadioController.ResolveDevice: saved-ветка восстанавливает и MAC.
- RadioController.EnsureDeviceMac: добор неизвестного MAC — найденное в этой
сессии → ini → короткий служебный поиск в сети (700 мс, unicast на DirectIP,
OnDeviceFound временно снят, чтобы не трогать список устройств в UI).
- ConnectDevice: добор MAC до Connect, после успеха MAC запоминается за
сохранённым устройством, так что следующий AutoStart идёт без пробника.
Проверено на железе (ANAN 172.16.2.200): в hpsdr_devices.ini появился
MAC=04:91:62:FD:7B:86, секция нулевого MAC больше не создаётся, старт по
AutoStart и старт после DISCOVER дают один и тот же профиль.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Паритет с уже существующим выбором вывода: на каждом слайсе своё устройство
входа (микрофон/виртуальный кабель).
- RadioController: TCtrlSlice += InDeviceIndex/InDevName/AudioIn (ссылка, не
владение); mic-пул FMicPool с refcount (Acquire/ReleaseMicInput) — один
открытый TAudioInput на уникальное PA-устройство, смена TX-слайса не
переоткрывает поток; ActiveMicInput/ActiveMicInDevName для PullSoundCardMic,
Flush и DefaultMicSource; SetMainMicDevice перепривязывает ссылки слайсов.
- VfoOverlay: во fly-out AUD ряд вкладок OUT | IN, событие OnAudioInDevice.
- PanafallPanel: проброс списка входных устройств во флаги слайсов и главный.
- Settings: персист in_dev_name.
НЕ ГОТОВО: зависание GUI при выборе на слайсе того же входа, что в настройках
(пул открывает поток вместо шортката на общий FAudioIn). В коде оставлена
временная диагностика [MIC] в stderr. Также подозрение на замедление потока
данных от радио — проверяем сравнением с main.
Со мной в коммите временные тестовые программы PortAudio (other/pa*.lpr).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Вкладка Calibration + всё, что нужно, чтобы шкала dBm и частота были
абсолютными на обоих бэкендах.
- Детектор мощности/КСВ Alex-моста по моделям ANAN, per-band множитель
FWD/REV, калибровка напряжения и тока питания.
- Офсеты S-метра и спектра/водопада — раздельными таблицами на диапазон и на
слот трансвертера, по активному железу: у openHPSDR HF-план, у Pluto
VHF/UHF-план, секции JSON ключуются по MAC.
- Регулируемое усиление входа больше не двигает шкалу: шаговый аттенюатор
openHPSDR (ставший плавным 0..31 дБ с ползунком в RX-блоке и памятью на
диапазон/слот) и hardwaregain AD936x, который в режимах AGC железо крутит
само.
- Частотная калибровка опорника (ppm): у HPSDR — частотное слово DDC/DUC, у
Pluto — xo_correction. Ручные LO Error / TO Error трансвертеров остаются
сверху; в слоте QO-100 сам транспондер-offset теперь стандартный, а уход
тракта правится отдельной поправкой.
Проверено на железе (openHPSDR и Pluto).
Пункт 3 плана. Ручные подгонки остаются: ppm работает ПОД ними, а не вместо —
уход тракта где-то больше, где-то меньше.
- Settings: TCalibration.FreqCalPPM (JSON cal_freq_ppm, +-100 ppm, per-device).
Смысл знака: «опора выше номинала на N ppm», положительное значение
поднимает показываемые частоты.
- RadioBackend: виртуальный SetFreqCalPPM.
- HPSDRNetwork: CalFreq(Hz) = Hz / (1 + ppm) в частотном слове — все четыре
точки (главный DDC, DDC панов, feedback-DDC PureSignal, DUC передачи).
Тактовый генератор радио менять нечем, поэтому правим запрос.
- PlutoBackend: штатный xo_correction в ad9361-phy (device-attr биндинги
добавлены в IIOBindings). Номинал XO снимается при коннекте с округлением
до 100 кГц, чтобы наша же коррекция с прошлой сессии не накапливалась;
после записи LO переписываются, иначе правка ждала бы следующей перестройки.
Одна цифра лечит RX и TX на всех диапазонах.
- QO-100: TXvtrEntry.TxLOError (JSON tx_lo_error) + поле «TO Error (Hz)» на
странице QO-100. Сам транспондер-offset держим стандартным (8089.5 МГц),
уход тракта правим поправкой; ActiveTXFreqHz учитывает её, подсказка внизу
страницы считает TX-частоту уже с ней.
- UI-фиксы вкладки Calibration: длинные подсказки переведены на несколько
строк (WordWrap — TLabel по умолчанию режется по краю группы), заголовки
таблиц укорочены и не заезжают под кнопку «= S-meter»; RelayoutCalTab
сбрасывает прокрутку страницы перед перекладкой (SetBounds в TScrollBox
задаёт координаты относительно прокрученного клиента).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
На Pluto шкала dBm ничего не значила: усиление тракта 0..73 дБ входит в
показания напрямую, а в режимах AGC железо крутит его само, и картинка
«дышит» вместе с ним.
- RadioBackend: виртуальный RxGainNowDb (TELEMETRY_NONE = регулируемого
усиления нет, как у openHPSDR с его аттенюатором).
- PlutoBackend: в MANUAL отдаёт FGainDb (точно, без опроса железа), в режимах
AGC — hardwaregain из телеметрического потока (читается там же, где rssi,
~2 Гц, не блокируя UI).
- RadioController: AttenCalDB -> FrontEndCalDB, общее понятие «регулируемое
усиление входа»: openHPSDR +FAtten (аттенюатор режет), AD936x -hardwaregain
(усиление поднимает). Постоянная часть тракта (LNB, кабель, конвертер)
остаётся за таблицами калибровки на диапазон/трансвертер.
- UI: в блоке RF AGC при режиме != MANUAL вместо надписи «AGC» — фактическое
усиление («~38dB», тильда = измеренное), ползунок ездит сам. Видно, что
цифра гуляет, а уровни на спектре стоят.
Ограничения: FAST AGC крутит усиление быстрее опроса (2 Гц), для стабильной
шкалы нужен MANUAL или SLOW; шумовая полка при смене усиления немного едет —
это физика (input-referred NF), компенсацию проверять по сигналу.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Аттенюатор был только в web и только тремя ступенями (0/-10/-20), а его дБ
никуда не возвращались — при ATT 20 дБ S-метр и спектр уезжали на 20 дБ, и
свежая калибровка уровней была верна лишь при ATT=0.
- RadioController: SetAtten(Db) 0..31 (как умеет железо) вместо индекса *10.
AttenCalDB входит в SMeterCalFor и DispCalFor — стрелка, спектр, водопад и
паны компенсируются, шкала dBm остаётся абсолютной (как Thetis/piHPSDR).
У AD936x аттенюатора нет, там поправка 0 (усиление тракта — hardwaregain).
- Память на диапазон/слот трансвертера по образцу RxGainMode/RxGainDb:
TBandSettings.AttenDB (band 'atten_db') и TXvtrEntry.LastAttenDB
('last_atten_db'); восстановление и отправка в железо — в ApplyBandDSP,
сбор — в MakeBandSettings/SaveCurrentBand, вход в слот — через B.AttenDB.
SetAtten сразу кладёт значение в кэш диапазона/слота (JSON пишется общим
сохранением, а не на каждый шаг ползунка — как у drive).
- MainForm: ряд «ATT [ползунок] NNdB» в RX-блоке левой панели, отступы как у
VOL; на Pluto ряд скрыт и RX-блок ужимается (LayoutLeftPanel двигает
панели ниже). Внешние изменения приходят по rfAtten.
- Web: select → ползунок 0..31 с цифрой, attn_idx -> attn_db, cmd attn {db:}.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Вторая калибровочная таблица рядом с S-метром (паритет с Display Cal Offset
в Thetis): у display-тракта своё окно/детектор, и его уровень расходится с
показаниями стрелки на пару дБ, поэтому таблицы раздельные.
- Settings: DispBandDB[12] / DispXvtrDB[8] (JSON cal_disp_band_i /
cal_disp_xvtr_i, дефолт 0 — картинка не меняется до первой правки).
- WDSPEngine: колбэк OnDispCal(PanId) — движок раз в кадр спрашивает офсет в
UpdateSpectrum и прибавляет к пикселям (главный спектр/водопад в копирующем
цикле, паны in-place при ненулевом офсете). На TX-дисплее не применяется.
Так обошлись без хуков на каждое присваивание FCenterFreq.
- RadioController: общий CalLookup(Hz, BandTbl, XvtrTbl) — на нём SMeterCalFor
и DispCalFor(PanId): главный дисплей по FCenterFreq, пан по FPanFreqHz[p],
т.е. кросс-банд паны получают свой офсет. Колбэк вешается в CreateEngines,
поэтому работает и в GUI, и в ewsdrd; web-зеркало получает готовые кадры.
- SettingsForm: группа «Spectrum / waterfall» с той же разбивкой (диапазоны +
включённые трансвертеры активного железа) и кнопка «= S-meter» — копия
таблицы стрелки как старт калибровки; общая раскладка сеток вынесена в
LayoutCalOffsets.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Вместо одного офсета на всё устройство — таблицы «на диапазон» и «на слот
трансвертера»; состав таблиц задаёт активное железо.
- Settings: SMeterOffsetDB -> SMeterBandDB[12] / SMeterXvtrDB[8] (JSON
cal_smeter_band_i / cal_smeter_xvtr_i). Легаси-ключ cal_smeter_db становится
дефолтом всех слотов — показания после обновления не меняются. Разделение
Pluto/openHPSDR даёт сама секция JSON: она ключуется по MAC устройства
(у Pluto — synthetic MAC из serial).
- Офсет убран из WDSPEngine (FSMeterCalDB): движок не знает ни диапазонов, ни
трансвертеров. Теперь TRadioController.SMeterCalFor(VisibleHz) — окно
включённого XVTR-слота приоритетнее диапазона, индекс диапазона по плану
железа (FreqToBandIdx с IsPluto); ReadSMeterDBm для главного S-метра
(MainForm + ewsdrd) и SliceSMeter по TargetHz слайса — паны N на других
диапазонах считаются по своему банду, а не по главному.
- SettingsForm: таблицы на 12 слотов, подписи/видимость/раскладку ставит
RelayoutCalTab; SetCalibrationBackend(IsPluto) вызывается рядом с
SetAntennaBackend. У openHPSDR — HF-план, у Pluto — VHF/UHF-план и скрытые
группы Power/SWR detector и Supply V/A (нет Alex-моста и его телеметрии).
Слоты трансвертеров показываются только включённые, с их именами.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The RX timeout check sampled GetTickCount64 on the UI thread while the UDP receive thread could update FRXLastPktTime a millisecond later. Both values are QWord, so subtracting the newer packet tick from the older UI tick underflowed to a very large value and falsely satisfied the 3-second timeout.
Snapshot the packet timestamp once for each timeout check and require NowTick >= LastPktTick before calculating the elapsed interval. The initial-packet timeout uses the same snapshot. This preserves real timeout detection while ignoring a packet timestamp that is marginally newer than the UI tick.
Diagnostics confirmed that DDC UDP packets, callbacks, and HP status remained continuous during the reported failures; the issue was local timeout arithmetic rather than network loss or radio stream interruption.
AlertOverlay переписан в общий builder: BuildAlertImage строит RGBA-образ
плашки (попиксельная альфа, Canvas один раз на своём битмапе). GL грузит
образ текстурой (кэш как был), CPU блендит кэш в raw-кадр — убраны
canvas-путь в кадре и полный проход восстановления альфы битмапа.
GL-плашка теперь 1:1 с CPU (было: упрощённый бокс по центру), позиция —
правый верхний угол в обоих рендерах. Удалена мёртвая подсветочная линия
(перекрывалась рамкой).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- сводка «IMD3 −NN dBc» слева от полосы фильтра (не прячется за
SampleRateOverlay), шрифт 9→11
- маркеры пиков: все подписи в dBm как в Thetis (dBc только в сводке),
все зелёные (оранжевый = вычисленная сводка), подпись центрирована
над своим кружком (не наезжают у соседних тонов)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Разбор «IMD3 хуже, чем в Thetis»: юзерская плата (Orion MkII/Anvelina
PRO3) при стоковой цели feedback 152 перегружает входные каскады
ADC2208+кодека — фидбек сам интермодулирует, PS корректирует по
искажённому наблюдению. Замеры eu2av (Thetis-Enhanced): оптимум FB≈22
при ATT≈10 дБ.
- PSFBTarget: цель уровня feedback, авто по плате (board 5 → 22, иначе
152), настройка ps_fb_target (0 = авто)
- авто-ATT: пороги от цели (FB > 1.5×цели / FB < 0.7×цели при ATT>0),
ddB = 20*log10(FB/цель). Заодно чинит «ATT всегда 0»: старый порог
>181 на этой плате никогда не достигался
- PSOutlierSigmaEff → SetPSOutlierSigma (новый экспорт libwdsp): MAD-
фильтр выбросов перед фитом calcc, авто σ=5.0 для Orion MkII,
настройка ps_outlier_sigma (-1 = авто)
- лампа FB в поповере: зоны от цели (0.7–1.3× зелёная), подпись
«FB: тек/цель»
Требует libwdsp с патчами eu2av (форк wdsp, коммит d27684c).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mouse wheel over an extra panadapter now retunes that pan's primary
slice (first created on that receiver) instead of the main VFO; a slice
flag under the cursor still wins, pan 0 keeps driving the VFO.
Slice flags get a clickable RXM badge: RX audio of the slice is muted
while transmitting (default), so the operator no longer hears himself on
every slice in full duplex. State persists with the workspace.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>