Commit Graph
341 Commits
Author SHA1 Message Date
ew8bakandClaude Fable 5 3db823474d feat(slices): этап 3.2 — WDSPEngine per-pan (аккумулятор, анализаторы, слайсы в панах)
- общая IQ-очередь с TIQQueueItem.PanId (64→256 слотов); DSP-поток
  диспетчеризует пан-пакеты в PushPanItemToDSP: декод, feed анализатора
  PAN_DISP_BASE+PanId, аккумулятор, ProcessSlicesFor(PanId) под FSliceLock
- пан-анализаторы: Create/DestroyPanAnalyzer + ApplyPanAnalyzerSettings
  (rate пана, без зума — пан-зум в 3.3+), живут в OpenAnalyzer/CloseAnalyzer,
  общие настройки дисплея перекатываются (ReapplyPanDisplaySettings)
- слайсы в панах: TSliceChan.PanId, AddSlice(..., APanId), OpenSliceChannel
  от rate/блока своего пана, SliceDSPRateFor (WFM от rate пана); блок пана
  = FAudioBufSize*Rate/FAudioRate => аудио-блок слайсов неизменен
- выдача пикселей: OnPanSpectrum/OnPanWaterfall(PanId,...) из display-потока,
  GetPixels пана под FSliceLock, колбэки вне лока
- MAX_PANS=4 переехал в WDSPEngine (единый движок/контроллер/UI)
- контроллер: AddPanDDC создаёт пан в движке до включения DDC, RemovePanDDC
  убирает слайсы (со звуковухами)+движок+DDC, гейт/NCO слайсов от центра
  своего пана, ретюн пана двигает его слайсы
- смоук-тест на libwdsp без железа ALL PASS: пик спектра пана точно на месте,
  слайс пана выдал 1 кГц RMS 0.68, главный тракт жив, RemovePan чисто

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:45:12 +03:00
ew8bakandClaude Fable 5 5dfd7bbb6c feat(slices): этап 3.1 — per-DDC бэкенд HPSDR (пан-DDC) + фикс Saturn в StartRunning
- TBackendCaps: MaxPans/IndependentPanFreq (HPSDR 4/True, Pluto 1/False);
  SetPanDDC/SetPanDDCFreq — виртуальные no-op в TRadioBackend
- HPSDRNetwork: ConfigureDDCs → кэш главного DDC + RebuildDDCSpecific
  (главный + активные пан-DDC, каждый со своим rate/ADC); SendFullHP пишет
  частотные слова всех активных пан-DDC; хелпер DDCBaseIndex; сброс
  пан-состояния в Connect
- RadioController: MAX_PANS=4, PAN_DDC_RATES 192/384/768; AddPanDDC/
  RemovePanDDC/SetPanDDCFreq/PanDDC* (аллокатор hw-индексов от FActiveDDC+1,
  обратный маппинг FDDCPanMap); OnDDCIQ роутит пан-DDC → PushPanIQ;
  паны гасятся в StopRunning, пул сбрасывается в StartRunning
- WDSPEngine: PushPanIQ — заглушка-дроп (аккумулятор/анализатор — этап 3.2)
- фикс: StartRunning не включал Saturn (BoardType 10) в список плат с
  DDCBase=2 — на Saturn гейт FActiveDDC ждал бы IQ с DDC0
- doc/SLICES_PLAN.md: статус 3.1 + B1 проверена на экране

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 10:52:31 +03:00
ew8bakandClaude Fable 5 26bfacc0a3 docs(slices): статус 3.0 (фазы A/B1 готовы) + решение отложить мышь/тик до 3.3
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 22:54:01 +03:00
ew8bakandClaude Fable 5 cc9919c35a refactor(slices): этап 3.0B1 — флаги слайсов переехали в TPanafallPanel
Панель владеет коллекцией флагов B+ (создание/закрытие/заливка состояния из
контроллера), раскладкой LayoutFlags, диспетчером мыши флагов, тиком S-метров
(TickFlags) и видимостью флага A (UpdateMainFlagVisibility). Главный флаг A
создаёт MainForm (проводка семантических событий у него) и отдаёт через
AttachMainFlag; новые флаги проводятся через OnWireFlag. Роутинг по слайсу —
FPan.CurSliceId; закрытие «×» — RequestSliceClose/OnSliceClosed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 22:51:47 +03:00
ew8bakandClaude Fable 5 c125e5978e refactor(slices): этап 3.0A — панадаптер выделен в TPanafallPanel
PanafallPanel.pas: view (CPU/GL), контролы стека (спектр/линейка/сплиттер/
водопад/пан-зум/кнопки зума), геометрия Layout, drag сплиттера и мышь
пан/зум-полосы. MainForm работает через алиасы (FSpecView/PbSpectrum/… =
FPan.*), размеры областей — FPan.SpectrumWidth/SpectrumHeight/WaterfallHeight.
Семантика мыши/флаги/тик пока в MainForm (фаза B). GL-аудит per-instance
пройден (глобальных GL-ресурсов нет). План: doc/SLICES_PLAN.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 22:41:32 +03:00
ew8bakandClaude Opus 4.8 cdbdfec792 feat(bandplan): диапазон OIRT 65-74 МГц в плане Pluto (кнопка перед FM)
VU-план (Pluto) расширен до 12 слотов: OIRT (65..74 МГц, дефолт 69 МГц)
вставлен перед FM. HF-план (openHPSDR) остаётся 11-диапазонным — 12-й слот
пустой, кнопка прячется (RelabelBands). CAT индексный (OIRT = band 08 на
Pluto), SetBand игнорирует пустой слот. Web bandSel строится динамически из
BandPlan; пустые слоты пропускаются.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 21:40:05 +03:00
ew8bakandClaude Opus 4.8 bf21b49bc3 fix(control): web/CAT принимают режимы WFM и DIGI-U/L
TWebAdapter.SyncMode и TCATAdapter.SyncMode клампили индекс режима по
MODE_SAM (7), тогда как новые режимы дописаны в конец: DIGU=8, DIGL=9,
WFM=10. Команда на WFM/DIGI молча выходила из SyncMode, SetMode не
вызывался — приёмник оставался в прежнем режиме. У web-клиента окно
pend("mode") (600мс) истекало и UI откатывался на старый режим, что
выглядело как «переключение не успело по таймауту». Дело не в самплрейте.
Верхняя граница поднята до MODE_WFM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 21:12:03 +03:00
ew8bakandClaude Opus 4.8 ba2a75bb04 feat(dsp): режимы WFM, DIGI-U и DIGI-L
WFM использует новые wfmd/wfmmod из нашего форка WDSP. Демодулятор —
квадратурный дискриминатор на dsp_rate, поэтому при штатных 48 кГц
девиация 75 кГц не помещается в полосу. В WFM цепь RXA поднимается до
WFMDSPRate (наибольший FAudioRate*2^k <= 192 кГц, делящий SampleRate
нацело), rsmpin децимирует вход сам. Выше 192 кГц смысла нет: энергия
демодулированного тона выходит на полку (33.5k при 192 кГц против 31.8k
при 576 кГц), а FFT дорожает.

Две ловушки WDSP, найденные по дороге:

  * firmin.c: nfor = nc / size, idxmask = nfor - 1. Все fircore создаются
    с nc = max(2048, dsp_size), поэтому смена dsp_size без RXASetNC даёт
    nfor = 0 — пустой массив планов и падение в fftw_execute.

  * fir.c/bandpass.c планируют с FFTW_PATIENT, а wisdom.c пишет в
    wdspWisdom00 только степени двойки. При SampleRate 576 кГц наивный
    dsp_size = in_size = 12288 требовал FFT на 24576 точек — FFTW мерил
    план 25 секунд. Отсюда потолок 192 кГц и dsp_size = степень двойки.

RXA и TXA гейтятся раздельно: рейты TXA (48 кГц вход, 192 кГц выход) от
SampleRate не зависят, поэтому wfmmod уходит на широкий dsp_rate даже
когда приёмник остался на 48 кГц.

Заодно исправлен WDSP_SAM: было 12, а RXA_SAM = 10. Раньше 12 было вне
диапазона и WDSP молча игнорировал (SAM работал как DSB); после появления
RXA_WFM = 12 это включало бы WFM-демодулятор вместо SAM. txaMode
расходится с rxaMode после DRM (WFM: RXA 12, TXA 14) — отсюда ModeToWDSPTX.

DIGI-U/DIGI-L получили свою таблицу фильтров (3.0k…300) и полосу от нуля,
а не от среза на 100 Гц, как у SSB. В CAT они замаплены на коды Kenwood 6
(FSK) и 9 (FSK-R) — раньше эти коды сваливались в USB/LSB.

Новые индексы дописаны в конец (DIGU=8, DIGL=9, WFM=10): индекс режима
уходит в settings.json, band-cache, CAT и web-API. В VfoOverlay пришлось
развести хит-коды — режимы кодировались как -(I+1) и налезли на HIT_NR/
HIT_NB/HIT_SNB, а полосы кодировались значением BW, и WFM-овские
120000/160000/200000 налезли на HIT_AGC_PICK_BASE/HIT_DEV_BASE.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 16:59:27 +03:00
ew8bakandClaude Opus 4.8 388687d684 fix(macos): масштаб канвы берём у окна контрола, а не у главного экрана
backingScaleFactor главного экрана врёт, когда окно лежит на другом
мониторе. Спрашиваем масштаб у NSWindow того NSView, которому принадлежит
паинтбокс: это ровно то число, в котором Cocoa рисует эту канву, и оно
меняется само при перетаскивании окна между мониторами.

Objective-C по-прежнему живёт только в MacScale; наружу торчит
кроссплатформенная GetControlScale, которая на Windows/Linux сворачивается
в Result := 1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 21:20:53 +03:00
ew8bakandClaude Opus 4.8 fd8769898a fix(macos): S-метр, линейка и зумбар больше не мылятся на Retina
Cocoa рисует канву в физических пикселях, TBitmap всегда 1x, поэтому кадр,
собранный в offscreen-битмап логического размера, растягивался вдвое.

PlatformUtils.GetScreenScale возвращает 2 на Retina и 1 на остальных
платформах. Масштаб — обычная переменная, а не условная компиляция: на
Windows/Linux умножение на 1 даёт прежние числа, а на канву кадр кладётся
через Draw, как и раньше (StretchDraw только при масштабе > 1).

В SMeterView, RulerView и PanZoomBar битмап растёт в S раз, пиксельные
константы, размеры шрифтов и толщина пера умножаются на S. Перо важно
отдельно: иначе на Retina все риски стали бы вдвое тоньше.

RulerView кэширует битмап, поэтому смена масштаба сбрасывает кэш.
PanZoomBar.ThumbGeom получил параметр AScale: отрисовка зовёт его с
физической шириной, хит-тест мыши — с логической, код мыши не менялся.

Objective-C изолирован в MacScale.pas: {$MODESWITCH OBJECTIVEC1} несовместим
с {$MODE Delphi}, а DWARF-3 (-gw3, Debug-режим lazbuild) роняет FPC 3.2.4 с
internal error 200609171 на любых Objective-C типах — отсюда {$DEBUGINFO OFF}.

Замер после правки: 37.5% CPU против 38% базовых, отрисовка этих трёх
элементов ниже уровня шума в профиле.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 19:09:53 +03:00
ew8bakandClaude Opus 4.8 406f32b52c feat(platform): --opengl можно включить переменной EWSDR_OPENGL
Бандл под LaunchServices не может передать argv, поэтому GL-режим
включался через bash-обёртку в CFBundleExecutable. Теперь тот же
переключатель читается из окружения, что позволяет задать его в
Info.plist через LSEnvironment и обойтись без обёртки.

Разбор аргументов командной строки не изменён.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 18:31:15 +03:00
ew8bakandClaude Opus 4.8 80bab842d7 perf(dsp): удешевлён горячий цикл PushIQItemToDSP
На каждый сэмпл (576к/с при 576 кГц) цикл делал заметно больше работы, чем
требовалось:

- IR * SCALE и QR * SCALE вычислялись ТРИЖДЫ — в аргументы FeedDisplaySample,
  в FBeaconDec.Feed и при записи в FRXAcc;
- FeedDisplaySample был невстроенным вызовом метода ради двух записей в буфер,
  то есть 576 тысяч вызовов в секунду;
- FAnalyzerOpen и FBeaconDec перечитывались из полей на каждой итерации, хотя
  внутри цикла не меняются;
- индекс считался умножением Pos := i * 6.

Теперь DI/DQ считаются один раз, FeedDisplaySample развёрнут в цикл (и удалён
как мёртвый код — других вызывающих не было), флаг анализатора и декодер маяка
лежат в локальных, а по данным идёт бегущий указатель.

Замерено зонным профайлером в режиме CPU-времени потока: dsp.push_iq avg
12.5 -> 9.3 мкс, доля ядра 3.0% -> 2.3%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 16:29:06 +03:00
ew8bakandClaude Opus 4.8 7a554eb04e fix(pluto): телеметрия больше не блокирует UI-поток
ReadTelemetry делал 5-6 синхронных iio_channel_attr_read_* — каждое это USB
round-trip, вместе ~30 мс. Звался из MeterTimerTick, то есть прямо в главном
потоке, дважды в секунду (POLL_MS=500). Замер зонным профайлером: тик метра
занимал 5633 мкс настенного времени при пиках до 51 мс, тогда как CPU-времени
в нём было всего 140 мкс — чистое ожидание USB, ронявшее кадры.

Опрос переехал в TPlutoTeleThread: он раз в 500 мс читает те же атрибуты и
публикует снимок под FTeleLock. ReadTelemetry теперь только отдаёт снимок и
никогда не блокирует, поэтому RadioController.ServicePlutoTelemetry и
MainForm.MeterTimerTick не менялись — вся фильтрация температуры на месте.
Прежнее блокирующее тело стало PollTelemetryBlocking (только из потока).

Конкуренция за контекст libiio не выросла: UI-поток и раньше читал атрибуты
параллельно с iio_buffer_refill в RX-потоке. Сменился лишь тот, кто ждёт.

StopTelemetry идёт первой строкой Disconnect — до iio_context_destroy, иначе
поток продолжил бы читать атрибуты разрушенного контекста.

Результат: ui.meter_tick 5633 -> 110 мкс. Значение телеметрии теперь может
отставать до секунды (троттл контроллера + период потока) — на 10-герцовом
индикаторе температуры это незаметно.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 16:28:45 +03:00
ew8bak 66c2c09656 add to macos bundle libiio and ad9361 2026-07-08 22:06:14 +03:00
ew8bakandClaude Opus 4.8 67c2ebc774 chore: ignore .DS_Store and stop tracking it
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 22:04:08 +03:00
ew8bakandClaude Opus 4.8 cf67a66120 feat(slices): маркеры фильтров окрашиваются в цвет бейджа своего слайса
Полоса фильтра, края и линия несущей теперь берут цвет из
SliceColor(SliceLetter) вместо захардкоженного янтарного, который
совпадал с бейджем слайса B. Каждый слайс (B/C/D…) получает свой оттенок.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 15:37:03 +03:00
ew8bakandClaude Opus 4.8 b2b3339a2a feat(vfo): кнопка SQL + ползунок FM-squelch в DSP-меню флага (main + слайсы)
В fly-out DSP появляется ряд SQL (тумблер + порог 0..100) только в режиме FM.
Squelch работает per-slice: у слайсов свои WDSP-каналы, поэтому добавлены
поля/сеттеры FMSQ в TSliceChan/TCtrlSlice, ApplyFMSQToChan и восстановление
при переоткрытии канала. Роутинг события по SliceId (0=RXA, иначе слайс).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 12:51:02 +03:00
ew8bak ce9cfd730f Revert "fix(opengl): use Lazarus OpenGLContext"
This reverts commit 004c363df8.
2026-07-08 11:56:09 +03:00
ew8bak 004c363df8 fix(opengl): use Lazarus OpenGLContext
Replace OpenGLContextEx with OpenGLContext in MainForm, SpectrumViewOpengl, WaterfallViewOpengl, and WidebandView.

Switch the Lazarus project/program dependencies from LazOpenGLContextEx to LazOpenGLContext in ewsdr.lpi and ewsdr.lpr.

PixelScale was introduced in 092a202; restore the previous viewport/texture path: glViewport(0, 0, W, H), EnsureTexture(W, H), and UploadCurrentRow(W).
2026-07-07 23:30:35 +03:00
ew8bakandClaude Opus 4.8 e13d610a23 feat(audio): раздельная громкость RX и TX-монитора + фикс синка слайдера
Две сохраняемые громкости: FVolume (RX) и FTxMonVolume (self-monitor
даунлинка на передаче, дефолт 40). Контекст монитора = TX + DUP + RX MUTE
off (тот же гейт, что аудио в движке). В этом контексте слайдер/SetVolume
правят FTxMonVolume, иначе FVolume; ActiveVolume — активная под контекст.
Автопереключение громкости RX<->TX-монитор на T/R (SetMOX) и при смене
RX MUTE / DUP во время передачи (ApplyActiveVolume). Обе персистятся
(tx_mon_volume в конфиге). Веб выровнен на ActiveVolume.

Фикс: слайдер громкости не синхронизировался с загруженным значением после
подключения (в rfDevice синкался только drive, volume пропущен) → слайдер
оставался на 70, движок брал сохранённое → «прыжок» при первом касании.
Добавлен TrkVolume.Position := ActiveVolume в rfDevice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 16:24:57 +03:00
ew8bakandClaude Opus 4.8 ff2082ab04 feat(tx): self-monitor RX-аудио на TX в любом DUP + меньше TX pre-roll
RX MUTE (self-monitor даунлинка на передаче): кнопка теперь доступна на
ВСЕХ бэкендах, а не только Pluto/QO-100. Активна только в DUP; без DUP
кнопка disabled и звук на TX не проходит (движок гейтит по
FKeepRXDuringTX=FDisplayDuplex — двойная защита: аудио-гейт + RXA не
кормится). Добавлен RadioController.DisplayDuplex. TFlatButton теперь
рисует disabled-состояние приглушённым (текст/рамка к фону).

TX pre-roll 8144->6096 (2 блока подушки вместо 3): обоснование «нужно 3
блока» опиралось на щелчок ~0.5с после старта, который на деле оказался
bfo-глитчом тона (устранён f2d0519), а не underrun'ом подушки. Латентность
старта TX ~-10мс; startup-щелчков под нагрузкой DUP не слышно (подтверждено).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 16:09:26 +03:00
ew8bakandClaude Opus 4.8 f2d0519c9e fix(tx): bfo=1 в OpenChannel TXA — устранён фазовый разрыв TUN-тона
Всплески на водопаде + щелчки в аудио при TX (openHPSDR TUN/DUP):
периодический ~72° фазовый разрыв передаваемого PostGen-тона на границе
TX-блока, в среднем ~5 раз за сессию, привязан к фазе тона.

Причина: TX-канал открывался с bfo=0 (13-й параметр OpenChannel). При
bfo=0 fexchange0 читает выход из кольца r2 асинхронно (заполняет DSP-поток),
а r2_outidx продвигается на out_size каждый вызов; при рассинхроне DSP-потока
блок изредка читается со швом → разрыв фазы тона (err=0, амплитуда постоянна).
В DUP этот сплаттер принимается обратно = широкополосная строка на водопаде
и слышимый щелчок.

Диагностика A/B: pihpsdr на том же WDSP/радио и на той же частоте 750 Гц —
чист; единственное отличие в открытии TX-канала — bfo=1 (transmitter.c:1316).
При bfo=1 fexchange0 ждёт Sem_OutReady и отдаёт полный выходной блок
синхронно/фазонепрерывно (wdsp/iobuffs.c). Продюсер даёт ровно один вход-блок
на вызов → стойла нет.

Исключено прямыми зондами: рендер, NB/NB2, перегруз ADC, потеря пакетов DDC
(seq), переполнение RX-очереди, временно́й разрыв в принятом IQ, burst
catch-up продюсера, TX-пейсинг.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:35:31 +03:00
ew8bakandClaude Opus 4.8 69717c2eda fix(tx): убраны инъекции данных в DUC IQ-поток — всплески на водопаде при TX
Два источника фабрикации данных в TX IQ-поток рисовали всплески на водопаде
при передаче (openHPSDR, особенно TUN/DUP):

1. HPSDRNetwork (sender): анти-старв zero-fill при пустой очереди впрыскивал
   нулевые пакеты = 1.25мс тишины прямо в поток = разрыв данных = всплеск.
   Теперь пустая очередь → просто ждём следующий блок (модель dl1ycf pihpsdr
   txiq_thread: данные не инжектируются никогда; короткий разрыв покрывает
   pre-roll в FPGA-FIFO радио). Убраны DUC_FIFO_LOW/REANCHOR/ZeroPkt.

2. WDSPEngine (продюсер TTXDSPThread): silence-инъекция при стойле mic
   впрыскивала лишний блок сверх mic-темпа (для TUN он нёс PostGen-тон →
   боковые/разрыв темпа). Продюсер теперь строго mic-гейтед.

Замерено на эфире: всплески при TUN 5-6/сессию → ~1. Остаточный редкий клик
по прямому замеру НЕ из TX-пейсинга (sender ровно на радиоклоке 800 пак/с
через supply-limiting, дропов/underrun нет) — источник отдельный (дисплей/RX),
разбор позже.

Windows-ветка sender'а не тронута. Pluto — свой TX-тракт (TPlutoTXThread +
libiio DMA), задета только общая silence-removal (push-поток сам добивает
нулями). Обе не перепроверены на железе.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 20:43:17 +03:00
ew8bakandClaude Fable 5 577b8add9d fix(tx): чистый openHPSDR TX-тракт — задержка DUP, всплески TUN, фриз PTT-off
Диагностика временным TXLog (снят) вскрыла цепочку проблем TX-тракта:

- Задержка ~200мс своего сигнала в DUP: за время приёма ринг PortAudio-
  микрофона наполнялся до упора (9600 сэмплов) и на старте TX бёрстом
  оседал стоячим запасом в DUC-очереди. Фикс: TAudioInput.Flush на RX→TX
  (заодно убрана передача в эфир аудио, записанного до нажатия PTT).

- Всплески на TUN: (1) старт — радио начинало с пустого DUC-FIFO; (2) по
  ходу — пейсинг со строгой каденцией держал запас FIFO у нуля, джиттер
  3-6мс давал underrun; (3) клип: голос из бэклога складывался с PostGen-
  тоном (стоит после ALC) поверх шкалы, а сам тон при mag=1.0 давал
  выброс Гиббса x1.18 на старте. Фиксы: pre-roll PrimeDUCIQ (THROTTLE +
  3 блока подушки в очереди — sender метрит непрерывно, FIFO радио прижат
  2000..2400), анти-старв доливка нулями до REANCHOR при просадке,
  TUN_TONE_MAG=0.83, мьют mic-входа TXA при активном тоне.

- Огрызок TUN-тона в эфир на первом блоке следующего TX: стоп канала
  dmode=1 ждал фейд, который некому прокрутить (продюсер уже остановлен) —
  канал стопился по таймауту Sleep(1)x100 с недобранным сигналом в
  буферах. Это же было и «остаточным фризом ~106мс» GUI на отпускании
  PTT: чистый таймаут, фейд никогда не исполнялся. Фикс: dmode=0 +
  синхронный слив/продувка канала 4 нулевыми fexchange0 на стопе и
  старте (<1мс, штатные down-slew и flush).

- Дисплей: ResetPixelBuffers(TX_DISP_ID) на старте TX — усредняющая
  история TX-анализатора показывала спектр тона прошлой сессии.

- StopRunning при активном TUN не чистил DUC-очередь и не сбрасывал
  FTuning/тон — закрыто.

Латентность тракта mic→радио теперь ~43мс (WDSP 11 + подушка 21 + FIFO
10.4). Проверено на эфире: q=0..30, fill/drops/underrun=0, clip=0,
клоки радио/ПК без дрейфа (micRx 48000/с).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 22:46:19 +03:00
ew8bakandClaude Opus 4.8 98493f08b3 perf(tr): устранение GUI-фриза ~100мс на TX→RX (живой TX-DSP поток)
TX-DSP поток (TTXDSPThread) больше не пересоздаётся на каждом T/R — он
создаётся один раз и живёт весь сеанс, на приём/передачу переключается
флагом FTXActive (поток при False просто Continue, не трогает канал/ring).
Тердаун перенесён в TWDSPEngine.Close. Раньше Terminate+WaitFor+Free на
каждом отпускании PTT давал фиксированные ~100мс пустого join-оверхеда
pthread_join, блокируя GUI-поток. Итог: 206→106мс, крупные фризы ушли.
Остаток ~106мс = плавный WDSP fade-out TXA (SetChannelState dmode=1) —
оставлен как есть (dmode=0 дал бы trailing key-click в эфир).

Попутно:
- MainForm: убраны прямые PbSpectrum.Invalidate из drag/wheel VFO/центра —
  кадр рисует таймер по FSpectrumDirty (FPS-гейт; прямой Invalidate давал
  GL-кадр на каждое событие мыши мимо гейта → треск в HDMI-звуке AMD APU).
- AudioOutput: const-секция после {$ENDIF} блока PA-констант.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 16:32:35 +03:00
ew8bakandClaude Fable 5 e260995218 feat(display): скорость водопада с max-hold накоплением + MSAA спектра
- настройка Speed (wf_speed_div 1/2/4/8, Waterfall→Rendering): замедление
  накапливает кадры max-hold'ом в SetWaterfallData — короткие посылки (CW)
  не выпадают из строки; двойная децимация MainForm убрана
  (EffectiveWfInterval, CPU-путь не быстрее полукадровой)
- настройка Anti-aliasing (spec_msaa 1/2/4/8, дефолт 4x, Spectrum→Rendering):
  MultiSampling на GL-контроле спектра; смена в рантайме пересоздаёт
  контекст → ResetGLCache обнуляет текстурные кэши без glDelete

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:48:55 +03:00
ew8bakandClaude Fable 5 092a202f5f feat(waterfall): палитры Inferno/Turbo + gamma, разрешение до 4096, HiDPI
- SPECTRUM_PIXELS 1024→4096 + настройка display_pixels (лимит точек
  анализатора, SetDisplayResLimit); web-зеркало остаётся 1024 —
  max-децимация в SnapshotPixels
- палитры водопада Classic/Inferno/Turbo + регулятор gamma (в LUT),
  настройки wf_palette/wf_gamma, страница Waterfall → группа Rendering
- GL-водопад переведён на общий LUT/AGC-уровни базового класса
  (убраны дубли ColorForDB/UpdateLevels)
- явные glViewport в GL-вьюхах умножаются на PixelScale (HiDPI),
  текстура водопада — в физической ширине

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:11:58 +03:00
ew8bakandClaude Fable 5 4733ddab58 feat(opengl): переход на LazOpenGLContextEx — GL-рендер в нативном Wayland
Пакет LazOpenGLContext заменён на LazOpenGLContextEx (форк в
../lazOpengl): Qt6-бэкенд работает поверх настоящего QOpenGLWidget
(своя C++-либа libqlclglwidget) вместо GLX-контекста на winId(),
поэтому --opengl теперь работает в нативной Wayland-сессии, а под
ws=qt6 открывается путь на Windows/macOS.

- uses OpenGLContext -> OpenGLContextEx (класс TOpenGLControl тот же)
- удалена заглушка QtPlatformAllowsOpenGLControls с советом про
  XWayland: больше не нужна
- рантайм-зависимость: libqlclglwidget.so рядом с бинарником
  (сборка: make -C ../lazOpengl/csrc install-app APPDIR=bin/x86_64-linux)

Проверено на живом эфире (QO-100): спектр/водопад через GL под
Wayland и xcb, прозрачность FBO-альфы починена в обёртке (forceOpaque).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:56:46 +03:00
ew8bakandClaude Fable 5 01d78d148f chore: strip temporary PerfLog instrumentation
Профилирование завершено (кадр спектра 8.3мс -> 1.7мс, UI 45% -> 26% ядра):
удаляем PerfLog.pas, doc/PERF_PROFILING.md и все // PERF-замеры из
WDSPEngine/HPSDRNetwork/PlutoBackend/AudioOutput/SpectrumView(+GL)/
WaterfallViewOpengl/WidebandView/MainForm. Сами оптимизации (full-raw
рендерер, дворд-блендеры, порог бэндплана) остаются.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 00:36:03 +03:00
ew8bakandClaude Fable 5 0adaff2d21 perf(spectrum): full-raw CPU renderer + dword blenders (frame 8.3ms -> 1.7ms)
Canvas на битмапе кадра больше не используется вообще (кроме редкого
ADC-overload пути с восстановлением альфы) — убраны все raw<->canvas
переходы, каждый из которых синкал весь битмап на Qt6 (~2мс):

- RawBegin/RawEnd: прямой доступ к пикселям через RawImage.Data +
  BytesPerLine (bottom-up DIB win32 учтён отрицательным шагом)
- RawVLine/RawHLine (с пунктиром), RawFillRect, RawTriangleDown,
  RawCurve (кривая = связные вертикальные сегменты по колонкам)
- кэш текстовых масок (TRawTextMask, LRU 48): строка рендерится canvas'ом
  один раз белым-на-чёрном в свой мини-битмап, блитится raw с цветом;
  все тексты кадра теперь Courier New
- конвертированы: маркер (метка без случайной цветной плашки), бикон-
  маркеры, буквы слайсов, слайс-линии, AGC (пунктир 4/2 и 1/2, подпись
  с фоном SpecFilter как раньше), края/VFO/TX-курсоры с треугольниками
- пофреймовый альфа-OR проход удалён: альфа чинится один раз в кэше
  СЕТКИ после ребилда (canvas-текст там), кадр наследует её через memcpy

Дворд-блендеры (два 16-бит лейна на умножение, /256 вместо /255,
расхождение <0.4%) вместо побайтовых с div 255:
- BandPlanOverlay.CompositeStrip (~1мс -> ~0.2мс)
- SampleRateOverlay.CompositeCache (per-px альфа)
- VfoOverlay.BlendBitmapKey (keyed-магента дворд-сравнением)
- SpectrumView.DrawSpectrumGradient (source-лейны 1 раз на строку,
  ~1.6мс -> ~0.8мс)

Порог перестройки бэндплана: полпикселя вместо 1 Гц (на QO-100 с
decoder-lock центр подтюнивается непрерывно — был canvas-ребилд полоски
каждый кадр). Композиты внутри raw-лока (их BeginUpdate вложенные).
PerfLog: зона ui.composites отделена от ui.spec_alpha (=RawEnd).

Замер на эфире (Pluto, 576k, 52fps): кадр 8.3мс -> 1.67мс (5x),
со слайсом 2.1-2.3мс; UI-поток ~45% -> ~26% ядра, из них 15% — блиты
paint_spectrum/paint_waterfall (потолок Qt6-вывода). Визуально проверено.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 00:11:31 +03:00
ew8bakandClaude Fable 5 0b4d126dac perf: zone CPU profiler (PerfLog) + phase-restructured CPU spectrum render
Инструментация (ВРЕМЕННАЯ, не мержить в main):
- PerfLog.pas: зонные таймеры, отчёт раз в 5с в stderr (core% = доля ядра),
  EWSDR_PERF=0 выкл, EWSDR_PERF_FILE=путь — дублировать в файл
- Замеры // PERF: сеть (DDC IQ/wideband), Pluto (rx_conv/tx_resamp/tx_fill),
  DSP (push_iq/fexchange/slices/tx), аудио, UI (тики/draw/paint/gl_swap,
  разбивка draw_spectrum по фазам)
- doc/PERF_PROFILING.md: карта зон, методика, выводы

Оптимизация CPU-рендера спектра (по результатам замеров на эфире):
диагноз — дорога не пиксельная работа, а чередование raw(ScanLine)/
canvas(QPainter) доступа к битмапу на Qt6 (~6 переходов за кадр, каждый
синкает весь битмап; полоса фильтра в тысячи пикселей стоила 4x дороже
полного memcpy кадра). DrawSpectrum перестроен в фазы calc->raw->canvas->raw
(2 перехода): FillBandRaw вместо Canvas.FillRect, DrawSliceFilterMarkers
разделён на raw-полосы + canvas-линии, композиты флагов и альфа-OR в
финальной raw-фазе. Кадр 8.3мс -> 6.1мс; spec_bands 1.87мс -> 0.03мс.
Альфа-OR проход на Qt6 подтверждён нужным (без него canvas-пиксели теряют
альфу и пропадают при блите), сам цикл ~0.08мс — оставлен; тумблер
EWSDR_ALPHA_FIX=0 только для экспериментов. Кисть перед AGC-подписями
теперь ставится явно (была остаточной после перестройки фаз).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 22:07:36 +03:00
ew8bakandClaude Opus 4.8 b2fa2756cf docs(slices): draft Stage 3 notes (HW DDC design + UI concept)
Record grounded data-path analysis, per-DDC/RX2 deltas, the soft-vs-hard
WDSP channel split, preliminary decisions (4-6 hard DDCs, static first),
and the UI concept (edge markers, slices rail, ADC badge). Marked as a
work-in-progress draft.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:36:31 +03:00
ew8bakandClaude Opus 4.8 db2aafaef9 docs(slices): record flag UI polish (packing, band letters, theming)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:20:58 +03:00
ew8bakandClaude Opus 4.8 a3ac459abc feat(overlay): flat themed buttons + full theme support for slice flags
Share one button paint routine: extract TFlatButton.Paint into
PaintFlatButton(canvas, rect, colors) and call it from both TFlatButton
and VfoOverlay.DrawButton — flag buttons now render identically to the
left panel (flat fill + border, no gloss), using theme Btn* colors.

Theme the whole flag card: the structural CLR_* palette (card bg,
border, text, dim, accents, freq, meter bg) is now derived from the
active TAppTheme via ApplyThemeColors, so flags follow light/dark like
the rest of the UI. Status accents (TX/SPLIT) stay fixed on purpose and
use a fixed dark text over their bright badges. Theme is pushed to
flags from ApplyDarkTheme and on creation via WireOverlayEvents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:04:21 +03:00
ew8bakandClaude Opus 4.8 3049f919a3 fix(slices): center badge letter via widgetset TextRect
Manual TextWidth/TextHeight centering pushed the glyph up-left on the
substituted monospace font (Linux). Let the widgetset center it with a
taCenter/tlCenter TTextStyle, fixing the A/×/SPLIT/TX badges.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 13:26:12 +03:00
ew8bakandClaude Opus 4.8 30a6616dbe feat(slices): non-overlapping flag packing + per-slice colored letters
Flags (A + B+) now lay out in one pass: each sits beside its own filter
band as before, but a left neighbour pushes the next flag right so they
never cross (forward pack + backward pull-in on right-edge overflow).
LayoutFlags replaces the per-flag positioning; PositionVfoOverlay/
PositionSliceFlags are thin wrappers.

Identity is shown by a letter drawn at the top of each filter band in
the spectrum (both CPU + GL renderers), so a flag pushed away from its
band is still traceable. Letters and the flag letter-badge share one
per-slice palette (SliceColor); F is violet, not red, to avoid clashing
with the TX indicator.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 13:19:50 +03:00
ew8bakandClaude Opus 4.8 3fbde19b9f fix(slices): align all VFO flags to same top (Top=35)
Slice flags (B+) were staggered by i*12 which barely helped with the
96px-tall card and looked untidy. Put every flag — main A and slices —
on one row. Overlap of near-frequency flags to be handled next (leader
lines).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 12:02:23 +03:00
ew8bakandClaude Opus 4.8 a53c12b5aa docs(slices): mark Stages 1+2 done, record what shipped
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 23:51:12 +03:00
ew8bakandClaude Opus 4.8 1527b0f849 feat(slices): multi-slice receivers (FlexRadio-style) — soft fan-out + per-slice flag/audio
Independent RX slices sharing one panadapter: each has its own
freq/mode/filter/AGC/NR-NB-SNB-ANF, S-meter, volume and sound card.
VFO A = main receiver; B+ are soft fan-out WDSP channels within the
captured span (ideal for Pluto/QO-100; HW DDC path is Stage 3).

- WDSPEngine: soft fan-out (TSliceChan, ProcessSlices in DSP thread,
  per-slice NCO/mode/filter/AGC/NR/NB/SNB/ANF + S-meter, OnSliceAudio),
  FSliceLock serialises add/remove/set vs DSP; reopened on rate change.
- RadioController: TCtrlSlice with its own TAudioOutput/device,
  Add/Remove/SetSlice*, RefreshSliceShifts keeps slices on target Hz
  across centre changes. Slice letters start at 'B' (A = main receiver).
- UI: per-slice flags (VfoOverlay) with letter badge/close, filter-band
  markers in BOTH GL and CPU renderers, drag-retune, wheel; flags placed
  beside the filter band with flip, like the main flag. Ctrl+click adds.
- Main flag (slice A) visible whenever the left panel is hidden OR any
  slice exists; synced with panel-driven DSP/mode/AGC changes.
- Perf: S-meter decoupled from flag chrome cache (FMeterDirty +
  meter-only RefreshMeter via EnsureRendered); InvalidateVfoOverlay
  avoids global overlay-cache churn on meter ticks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 23:46:30 +03:00
ew8bakandClaude Opus 4.8 a04c592f1d feat(overlay): scrollable audio device list in AUD fly-out
Список устройств вывода ограничен AUD_MAX_VIS=6 видимыми строками — панель
больше не растёт бесконечно и не уезжает за низ спектра. При большем числе
устройств справа появляется полоса прокрутки ▲/▼ (строки сужаются под
колонку стрелок), клик листает FAudScroll не закрывая панель; стрелки гаснут
на краях. ≤6 устройств — как раньше, без стрелок.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 17:40:31 +03:00
ew8bakandClaude Opus 4.8 737af0d227 feat(overlay): glassy buttons (zoom-bar style gloss gradient)
DrawButton теперь рисует стеклянную кнопку как ползунок зум-бара: тёмная
скруглённая база-фаска + вертикальный глянцевый градиент (ярче вверху,
темнее внизу) + блик сверху и тень снизу. Хелпер GlossColor масштабирует
яркость цвета. Только при ребилде кэша — CPU-паритет сохранён.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 17:17:46 +03:00
ew8bakandClaude Opus 4.8 08c71c47ad feat(overlay): clickable TX badge with slice-select groundwork
TX-индикатор теперь кликабельный (хит HIT_TX → колбэк OnTxSelect) — задел
под выбор TX-слайса в мультислайсах. Три состояния цвета:
- передача идёт → красный;
- слайс выбран для TX → янтарный (CLR_TX_SEL);
- не выбран → нейтральный.

Новое состояние FTxSel прокидывается через SetExtState (пока True — один
слайс всегда TX-слайс). MainForm.OnVfoOverlayTxSelect — заглушка с TODO под
мультислайсы.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 17:10:34 +03:00
ew8bakandClaude Opus 4.8 6ad5f29657 feat(overlay): flip VFO overlay to left side when it doesn't fit on right
PositionVfoOverlay считает обе кромки полосы фильтра и ставит накладку справа
от неё по умолчанию; если справа не влезает (маркер у правого края) — рисует
слева от левой кромки. Возврат на правую сторону автоматически, когда снова
помещается. Убран прежний clamp-оверлап с маркером.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 14:18:29 +03:00
ew8bakandClaude Opus 4.8 43dbd2b829 fix(overlay): S-meter scale + header badge polish
- S-метр: убрана метка +60 (вылезала за правый край), шрифт подписей
  5→7 (читаемость), подписи сдвинуты ниже тика. Бар оставлен компактным,
  ряду добавлено 3px под крупные метки.
- Градиент S-метра привязан к уровню dBm (S1→S7→S9→S9+18), а не к длине
  бара — сильные сигналы уходят в красный раньше.
- Бейджи A/SPLIT/TX: высота 15→12px (верх на месте, низ приподнят) —
  текст по центру, больше зазор до S-метра.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 14:14:16 +03:00
ew8bakandClaude Opus 4.8 4a92256e72 feat(overlay): redesign VfoOverlay in SmartSDR slice-flag style
Полный редизайн накладки поверх спектра: шапка (слайс-бейдж A/B, ширина
фильтра, кликабельный SPLIT, индикатор TX), метр-ряд (индикаторы NR/NB/ANF/
SNB + сигнал-бар), крупная частота + S, нижний бар с fly-out пикерами.

- Fly-out движок MODE/DSP/AUD (раскрываются под баром, карточка растёт):
  MODE — сетка режимов 4×2 + фильтры; DSP — NR/NB/SNB/ANF + AGC; AUD —
  выбор аудио-устройства вывода (задел под слайсы).
- Слайдер громкости (click+drag) + mute; SPLIT-toggle; live TX-индикатор.
- Все контролы подключены к RadioController (SetVolume/ToggleMute/SetSplit/
  EnumOutputDevices→ApplyAudioDevice); wire в MainForm + HandleMouseUp, чтобы
  клик по накладке не уходил в спектр.
- FormatFreq на Int64 (double накапливал ошибку в десятки Гц на ~10 ГГц QO-100).
- S-метр ниже по высоте + плавный градиент по уровню dBm: тёмно-зелёный→
  зелёный→жёлтый→красный (красный к ~S9+18).
- Кэш+dirty рендер сохранён (CPU-паритет со старой накладкой), GL-путь через
  DrawOverlayBitmap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 14:00:59 +03:00
ew8bakandClaude Opus 4.8 5b7eda291e fix(spectrum): сохранение/восстановление зума для трансверторов (XVTR)
Зум был per-band только для HF (TBandSettings). XVTR-слоты хранятся отдельно
(TXvtrEntry) и зум туда не попадал — при входе в трансвертер не восстанавливался.

- TXvtrEntry: LastZoomFactor/LastPanSlider + Default/Load/Save (JSON).
- SaveCurrentBand (XVTR-ветка): пишет зум/пан в слот.
- ActivateXvtr: восстанавливает зум слота + SetZoomPan (re-arm анализатора).
  Покрывает все входы (кнопка, старт по LastXvtr, CAT/web).
- ApplyZoom: кэширует в активный слот — XVTR при активном трансверторе,
  иначе HF-band.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 21:27:08 +03:00
ew8bakandClaude Opus 4.8 371b2858bd feat(spectrum): zoom + pan для спектра и водопада (WDSP span-clip)
Зум через нативный span-clip WDSP (fscLin/fscHin в SetAnalyzer): clp=0,
видимое окно сужается клипом, при зуме 0 полоса == sample rate (старое
поведение сохранено). Конвенция как в Thetis: ZoomFactor 0=без зума..1=макс.

- WDSPEngine: SetZoomPan + расчёт span-clip, ViewLowHz/ViewHighHz.
- RadioController: GetViewWindow (единая истина видимого окна для оверлеев и
  мыши), ApplyZoom, ZoomIn/Out по лестнице кратностей, ZoomDefault. Якорь
  зума кнопками — на маркере активного VFO. rfZoom.
- Per-band персист зума/пана (TBandSettings + Save/Load/Restore).
- MainForm: маршрутизация оверлеев/кликов через GetViewWindow (покрывает CPU
  и OpenGL), резерв строки PANZOOM_H в layout + сплиттере, rfZoom-рендер.
- WebAdapter: web-спектр/наведение на view-окно (делит те же WDSP-пиксели).
- PanZoomBar (новый): нижняя полоса = линейка полного диапазона (частоты +
  деления), поверх окно-селектор «стекло» (полупрозрачное, объёмная фаска).
  Середина=пан, края=зум, клик мимо=центрировать, двойной клик=сброс.

Сборка ewsdr (--ws=qt6) и ewsdrd — ОК. На железе не проверено.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 21:18:24 +03:00
ew8bakandClaude Opus 4.8 0e550dd9f9 fix(cat): align Andromeda panel mapping with real G2 hardware (Thetis)
Button/encoder indices follow Thetis MakeNewAndromedaDataset (our 0-based
index = Thetis Number - 1), verified against andromeda_test/AndDecode.pas.
The old map assumed sequential 0,1,2.. and truncated at 32; the real panel
sends sparse indices up to 47.

- AndromedaMap: AND_MAX_BUTTONS 32->48, renumbered button/encoder tables;
  new actions abVFOAtoB/abVFOBtoA/abVFOLock/abStartStop/abShift.
- RadioController: VFO Lock (FVfoLock, rfVfoLock, SetVfoLock, gate in
  TuneActiveBy).
- AndromedaPanel: wire A>B/B>A/SDR-ON/Lock; Shift band-keypad layer
  (#28 latch, #29..39 -> SetBand 160m..6m, non-sticky); aiVFOLock/aiShift
  indicators.
- Filter High/Low (#4/#5) left as width approximation per decision.
- doc/ANDROMEDA.md updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 16:11:12 +03:00
ew8bakandClaude Opus 4.8 2d7290e44d feat(cat): Andromeda/G2 front panel support (serial, LED indicators)
Bidirectional Apache Labs Andromeda/G2 front-panel protocol on top of CAT.
Panel logic lives in dedicated units; existing files get only thin hooks.

New units:
- AndromedaMap.pas   — data only: action enums + default button/encoder
  layout tables and LED (ZZZI) numbers (mirroring the Thetis defaults)
- AndromedaPanel.pas — TAndromedaPanel: inbound panel events -> controller
  actions (marshalled via Invoke), state subscription -> ZZZI push via SendProc

Hooks:
- CATEngine: parse ZZZD/ZZZU/ZZZE/ZZZP/ZZZS into generic TCATContext callbacks
- CATAdapter: creates the panel, routes engine callbacks to it, supplies the
  SendProc to the Andromeda port, AddStateListener, ZZZS handshake
- CATSerial: Andromeda flag in port config + HasAndromeda/SendToAndromeda
- RadioController: AddStateListener (multicast, does not steal MainForm's
  OnStateChanged)
- Settings/SettingsForm/MainForm: CATSerialAndromeda[0..3] + persistence + checkbox

First version: serial transport, hardcoded default mapping, LED indicators
(MOX/Tune/CTUN/VFO A-B/Split/NB/NR/SNB/ANF/Squelch). Doc: doc/ANDROMEDA.md.

TODO: default button mapping does not match the physical panel (hardcoded) —
to be fixed later; also ZZMF/LCD text, TCP G2V2 transport, configurable mapping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 11:40:10 +03:00
ew8bakandClaude Opus 4.8 4a92624e9b feat(cat): wire split/FM/CTUN/AGC-T CAT commands to controller
Реализованы команды, ранее бывшие заглушками — функционал уже был в
TRadioController, но не пробрасывался в CAT:

- Split TX: ZZSP/FT/FR + split-байт в IF (новый RadioController.SetSplit)
- FM Squelch: SQ (0–255), ZZSQ (0–100%), ZZSO (on/off)
- FM CTCSS: CT/ZZTA (on), CN (1-based)/ZZTB (0-based тон)
- FM-репитер: OF (offset), OS (направление, с трансляцией Kenwood↔RPT_*)
- FM step: ZZST (00–03)
- CTUN: ZZCN; AGC-T/RF gain: ZZAR
- ANF: ZZNT (раньше ошибочно алиас NB)
- Шаги VFO: ZZAU/ZZBP (исправлен баг — были алиасы ZZFA/ZZAP), ZZSU

TCATContext расширен callback'ами (split, squelch, CTCSS, repeater, step,
AGC-T, CTUN); CATAdapter — геттеры/сеттеры/sync с маршалингом через Invoke.
Добавлен doc/CAT_STATUS.md — полный статус CAT и план работ.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 10:35:35 +03:00