Commit Graph
50 Commits
Author SHA1 Message Date
ew8bakandClaude Opus 4.8 9dd38e1dd3 feat(pluto): выбор антенного разъёма RX/TX на диапазон (LibreSDR/AntSDR)
Второй разъём у AD936x-плат — это второй КАНАЛ чипа (не порт B первого), и в
1R1T-образе он выбирается мультиплексором AD9361: debug-параметры
adi,1rx-1tx-mode-use-rx-num/-tx-num + биты RX1/RX2, TX1/TX2 регистров 0x3/0x2
(как switch_rfinput.sh/switch_rfoutput.sh прошивки). rf_port_select тут ни при
чём — прошивка его к тому же блокирует.

- IIOBindings: debug-атрибуты + прямой доступ к регистрам.
- PlutoBackend: детект второго разъёма (2R2T-каналы либо мультиплексор + модель
  платы), SetAntPorts(RxPort,TxPort), ApplyRxMux/ApplyTxMux; Caps.HasAntSwitch.
  ⚠ApplyGain(Force): драйвер пропускает запись gain_control_mode, если считает
  режим неизменным, — а у нового канала AGC-регистры не запрограммированы (в
  железе крутится auto-AGC, hardwaregain отвергается EOPNOTSUPP). Форсируем
  перепрог через другой режим после смены разъёма и после ad9361_set_bb_rate.
- RadioBackend: TBackendCaps.HasAntSwitch + virtual SetAntPorts (HPSDR — no-op,
  там антеннами рулит Alex).
- Settings: секция ant936x (разъём RX/TX на диапазон и на слот трансвертера);
  hw-AGC (режим + manual gain) переехал в TBandSettings/TXvtrEntry — теперь он
  свой на каждом диапазоне и трансвертере.
- RadioController: FAnt936x + ApplyAntPorts (RestoreBand/ActivateXvtr/
  StartRunning); ApplyBandDSP восстанавливает hw-AGC диапазона.
- SettingsForm: вкладка Antenna — Alex-таблица (openHPSDR) либо таблица
  разъёмов AD936x по диапазонам/трансвертерам.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 21:26:18 +03:00
ew8bakandClaude Opus 4.8 3566f10191 feat(slices): per-pan дисплей — палитра/gamma/уровни на пан («◑»-поповер)
Кнопка «◑» в шапке каждого пана открывает компактный поповер настроек
отображения (палитра, gamma, ref/range спектра, авто-уровень водопада +
offset/ручные min-max). Модель «глобальный дефолт + override на пан»: пан 0
правит глобальные поля рендера (зеркалятся в контроллер), паны N ставят
DisplayOverride и персистятся в воркспейс раздельно КВ/трансвертер.

- PanDisplayPopup.pas (new): borderless fsStayOnTop форма, гаснет по
  OnDeactivate; Flat*-контролы; крестик «×» закрытия; дим-хинт «правки
  применяются и сохраняются сами»; кнопки «⟳ Reset»/«⇄ Copy to all».
- TPanafallPanel: FBtnDisplay + OnDisplayClick + DisplayOverride;
  PositionHeaderChildren каскадит [×][⧉][◑] справа по Visible.
- MainForm: OnPanDisplayClick/Applied/Reset/ApplyAll + ApplyGlobalRenderToView
  + MarkPanDisplayDirty. При смене палитры/сбросе чистим историю GL-водопада
  (TSpectrumView.ClearWaterfall) — GL хранит уже раскрашенные пиксели.
- Settings/TPanCfg: под-объект 'display' (палитра/gamma/ref/range/wf-уровни),
  пишется только при override.

Глобальными осознанно оставлены разрешение анализатора, MSAA, скорость
водопада, детектор/усреднение (движок/перф, не косметика).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 13:49:19 +03:00
ew8bakandClaude Opus 4.8 543453007e feat(slices): персист панов+слайсов, раздельно КВ/трансвертеры
Сохранение и восстановление панадаптеров, слайсов и раскладки per-device,
раздельно по контексту: КВ ('hf') и каждый трансвертер ('xvtr_N') — паны
одного контекста не имеют смысла в другом.

Settings: секция "pans"/<ctx> под MAC (grid-режим/доли, на пан —
freq/rate/adc/zoom/pan/доли стека+колонки+сплиттер спектр/водопад, на слайс —
freq/mode/фильтр/agc/vol/mute/squelch/аудиоустройство). TSliceCfg/TPanCfg/
TPansConfig + Default/Save/LoadPans(Ctx).

MainForm: CreatePanCore (вынос ядра из OnAddPanClick), SavePanWorkspaceCtx/
RestorePanWorkspaceCtx/TearDownWorkspace, PanContextKey. Хук контроллера
OnBeforeStop (снимок до гашения DDC в StopRunning). Переходы ActivateXvtrBand/
DeactivateXvtr обёрнуты save-старого/teardown/restore-нового (гейт FRunning);
restore XVTR-панов после ActivateXvtr (FCurrentXvtr целевой ⇒ XvtrTranslate
верный). PanafallPanel.DestroyAllSliceFlags. Смена КВ-банда контекст не меняет.

Round-trip сериализации и разделения контекстов проверены автономно; на
экране не проверено.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 23:06:12 +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 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 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 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 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 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 3bd37b956e feat: QO-100 self-monitor (RX MUTE) + gate beacon/RX-mute buttons to QO-100
Add a per-operator toggle to hear your own downlink off the satellite
while transmitting (full-duplex self-monitor), and restrict QO-100-only
controls to the QO-100 mode.

- WDSPEngine: new MonitorRXDuringTX flag; audio gate becomes
  `not FTXActive or (FKeepRXDuringTX and FMonitorRXDuringTX)` so RX audio
  can pass to speakers during TX in full-duplex.
- Controller: FRxMuteOnTx (default True = mute RX on TX), SetRxMuteOnTx/
  ApplyRxMuteToEngine, rfRxMuteOnTx notify; new InQO100 predicate
  (Pluto + full-duplex XVTR slot) as the single gate for QO-100 UI.
- Settings: global RxMuteOnTx (rx_mute_on_tx, default True), persisted.
- MainForm: new RX MUTE button in TX panel next to DUP, visible only in
  QO-100; BEACON button visibility tightened from "any transverter" to
  InQO100 so it no longer shows in plain VHF/UHF modes.
- doc: plan updated (RF-AGC done, two temps, TX/RX locked split,
  self-monitor, phase 6 done; remaining TODOs incl. web wiring).

Web intentionally left unchanged for now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 19:50:30 +03:00
ew8bakandClaude Opus 4.8 2ab1f4f9ac fix: restore per-band FM settings on startup (SQL/CTCSS/step/repeater)
LoadDevice (bulk startup band loader) parsed only freq/mode/filter/AGC/
CTun/center/span and skipped the FM fields, while SaveBand writes them and
LoadBand reads them. So FM squelch, CTCSS, step and repeater shift were
saved on exit but reset to defaults on the next start (band switching kept
working — that path goes through the in-memory band cache, not disk).

Added the missing fmsq_on/fmsq_level/ctcss_on/ctcss_idx/fmstep_on/
fmstep_idx/fmrpt_dir/fmrpt_offset reads to LoadDevice, mirroring LoadBand.
Affects all backends, not just Pluto.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 21:31:38 +03:00
ew8bakandClaude Opus 4.8 3fe5cf3fad feat: QO-100 mode — separate RX/TX LO + dedicated settings page
QO-100 reuses the transverter path (VFO/band-stack/beacon-lock untouched)
with a split LO for the geostationary transponder:
- TXvtrEntry += FullDuplexTx + TxLOOffset (persisted). Reserve the last
  XVTR slot (QO100_SLOT) for QO-100; migration restores the template when
  the slot is unset or has empty offsets (fixes old configs showing zeros).
- XvtrTranslateTX: TX LO = visible - TxLOOffset (no LNB LOError) for QO-100;
  identical to RX translate for normal transverters. Switched all TX-side
  translate calls (controller + MainForm).
- SetDuplex wired (live KeepRXDuringTX); auto display-duplex on QO-100 entry.
- New "QO-100" settings page (LNB LO / transponder offset / downlink edges /
  RX gain / TX ceiling + live RX-IF/TX readout); QO slot hidden from the
  transverter table. Reuses OnXvtrChange — no MainForm wiring needed.
- doc/PLUTO_INTEGRATION_PLAN.md: phase 5 done.

Builds clean (headless + qt6 GUI). Not yet verified on hardware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 15:30:23 +03:00
ew8bakandClaude Opus 4.8 d08fc17056 feat: Pluto TX path — attenuation-based power, full-duplex IQ stream
TX path for Pluto/AD936x (RX was already working):
- PlutoBackend: continuous full-duplex TX stream (cf-ad9361-dds-core-lpc)
  with FIFO + push thread; SendDUCIQ upsamples WDSP 192k -> device rate
  (integer, linear interp), 24->16 bit, Q inverted; zeros on underrun.
- Power via output attenuator (ADI-recommended): SetTxAtten writes
  hardwaregain on voltage0(out). Controller maps drive% -> dB
  (PlutoTxAttForDrive/ApplyPlutoTxAtten); -89.75 dB on RX (~off),
  ceiling PlutoTxMaxAttDb on 100% drive.
- Configurable max-att (default -10 dB, ADI-linear) for external amp:
  persisted in global settings, UI spin on PA page, routed through
  controller SetPlutoTxMaxAtt (UI stays decoupled from logic).
- RadioBackend: virtual SetTxAtten (no-op for HPSDR).
- Update doc/PLUTO_INTEGRATION_PLAN.md: phases 3/4/5 + risks.

Builds clean (headless + qt6 GUI). Not yet verified on hardware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 12:27:49 +03:00
ew8bakandClaude Opus 4.8 40dca01c40 fix: persist CTun center + save VHF/UHF bands (Pluto); QO-100 transverter template
CTun position was lost on band restore / restart, and VHF/UHF bands were
never saved on Pluto.

- SaveCurrentBand: the >61 MHz guard (HPSDR HF-only) skipped saving native
  Pluto VHF/UHF bands → 2m/70cm reverted to defaults. Now HPSDR-only; Pluto
  saves VU-plan bands (FreqToBandIdx guards cross-band pollution).
- Persist DDC center for CTun: new TBandSettings.CenterHz (+ JSON center_hz)
  and TXvtrEntry.LastCenterHz (+ last_center_hz). RestoreBand / ActivateXvtr
  restore the saved center when CTun is on and the offset fits the span,
  instead of forcing center := VFO (which re-centered the receiver).
- UpdateFreqDisplayMax: freq-display upper bound from active transverter's
  FreqEnd (lets QO-100 show 10 GHz past the 6 GHz Pluto cap).
- QO-100 transverter template (slot 2, disabled): downlink 10489.5–10490.0,
  LO 9750. MigrateXvtrTemplate injects it into the first free slot for
  devices that already have a saved xvtr config (template was otherwise
  masked by the loaded slots).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:02:01 +03:00
ew8bakandClaude Opus 4.8 24f74357cd feat: Pluto RX hw-gain control + AD9361 cold-init (FIR via libad9361)
- RX hw-gain (Pluto/AD936x): backend SetRxGain(ModeIdx, GainDb) — gain_control_mode
  (manual/fast_attack/slow_attack/hybrid) + hardwaregain. Controller FRxGainMode/
  FRxGainDb, commands SetRxGainMode/SetRxGain/RxGainBy, rfRxGain event, snapshot,
  applied in StartRunning. Persisted per-device (rx_gain_mode/rx_gain_db). HPSDR
  unaffected (backend no-op).
- UI: separate "RF AGC" panel below the (unchanged) WDSP AGC block, shown only for
  Pluto — FAST/SLOW/HYB/MAN mode buttons + manual GAIN slider. LayoutLeftPanel
  reflows lower panels via RelayoutBelowBands; no layout shift on HPSDR.
- Cold-init fix: direct sampling_frequency write doesn't load the AD9361 FIR
  decimation filter, so a cold-booted Pluto showed a wide centre spike that didn't
  track tuning (worked only after SDR Console pre-initialised it). Add optional
  libad9361 binding (dynamic) and call ad9361_set_bb_rate() in ApplySampleRate,
  which configures BBPLL + loads the FIR; falls back to direct write if absent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 12:06:59 +03:00
Uladzimir KarpenkaandClaude Opus 4.8 e09bc21bba Fix active-VFO desync; add bandstack-on-VFO-switch and per-XVTR VFO-B
Active-VFO desync (batch 15 follow-up): DoConnectDevice loaded
FActiveVfo from settings but never re-rendered the highlight (it was
drawn once in FormCreate while the field was still 0) nor re-tuned the
receiver. Result on reconnect with B last-active: the engine (spectrum,
filter band, mouse tuning) ran on VFO B while the UI showed A active.
Now the connect path brings both the receiver and the highlight to the
actually-active VFO via SetActiveVfo, and RestoreBand's final retune
follows the active VFO (A -> ApplyVfoA, B -> SetVfoB) instead of always A.

Bandstack on VFO switch: switching the active VFO to one parked on a
different ham band now restores that band's DSP state (mode/filter/AGC/
CTUN/FM). Extracted ApplyBandDSP (the DSP half of RestoreBand, without
the VFO frequencies) and reused it from both RestoreBand and SetActiveVfo.
VFO frequencies stay independent (each VFO carries its own band);
continuous tuning across a band edge still does not recall (band button
only) as on real radios. SaveCurrentBand no longer writes a VFO frequency
into a band's memory unless that VFO is actually within the band, so a
40m VFO-A no longer pollutes 30m's stored VfoA.

Per-transverter VFO-B: TXvtrEntry gains LastFreqB (load/save/default +
range clamp). ActivateXvtrBand restores VFO B, Deactivate/SaveAllAndExit
persist it, and SetVfoB clamps to the transverter range like SetVfoA.
The connect-time guard that forced VFO A in XVTR is dropped since B is now
a valid, in-range frequency there too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 12:45:11 +03:00
Uladzimir KarpenkaandClaude Opus 4.8 f12d2a69ad Phase 3 (batch 8): route desktop Mode/Filter through controller commands
- FILT_* таблицы (BW/DEF/DEV/COUNT) перенесены MainForm -> Settings.pas
  (нужны контроллеру для headless-выбора фильтра); UI-подписи FILT_*_NAMES
  остались в MainForm (ссылки разрешаются через uses Settings).
- ApplyModeFilter (чистый DSP) перенесён в TRadioController; все вызовы в
  MainForm -> FController.ApplyModeFilter.
- Контроллер: ApplyModeDefaults (дефолтный фильтр/девиация под FMode,
  зеркало state-части UpdateFilterButtons) + наполнены команды SetMode
  (FMode + дефолт + DSP SetMode/TUN + ApplyModeFilter + band cache) и
  SetFilterIdx (FFilterBW по таблицам режима + ApplyModeFilter + band cache).
- BtnModeClick/BtnFilterClick — тонкие обёртки к командам; рендер
  (StyleButton + UpdateFilterButtons + SyncSpecViewFreq) в
  OnControllerState(rfMode/rfFilter).

OnModeFilterSelect (VFO overlay), SyncWebMode/SyncWebFilter (web/CAT),
RestoreBand пока зовут FController.ApplyModeFilter инлайн — мигрируют
в следующих батчах (как и в прошлых: web/overlay позже).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 16:34:35 +03:00
Uladzimir KarpenkaandClaude Opus 4.8 aff17aa3a6 Add Audio tab toggle for transceiver built-in speaker
Adds a "Send audio stream to radio (built-in speaker)" checkbox on the
Settings → Audio tab. It is a single switch for the radio's built-in
speaker:

- ON  — RX audio is streamed to the radio via the DDC Audio packet
        (port 1028, 64 L/R pairs per packet) and the speaker is unmuted
        (High Priority byte 1400 bit1 = 0).
- OFF — speaker is muted (byte 1400 bit1 = 1, ANAN-8000DLE IO1 output)
        and no audio stream is sent.

The float->int16 conversion and 64-pair packet accumulation live in
THPSDRNetwork (SendSpeakerAudio/SetSpeakerAudio), next to SendDDCAudio;
MainForm only reads the setting and forwards the audio. State is
persisted per-MAC (send_audio_to_radio, default off) and re-applied on
each radio start.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 08:55:36 +03:00
Uladzimir KarpenkaandClaude Opus 4.8 655d242d02 Add Spectrum gradient fill toggle in settings
Mirror the existing Wideband gradient fill option for the main spectrum:
a "Spectrum gradient fill" checkbox on the Display settings tab gates the
under-curve gradient in TSpectrumView.DrawSpectrum. The curve, grid,
filter band and VFO markers always draw; only the gradient is optional.

Persisted as spectrum_fill in settings JSON (default True, preserving
current appearance). Wired through Settings -> SettingsForm visibility
event -> MainForm -> TSpectrumView.FillSpectrum, same path as
WidebandFill.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 15:24:33 +03:00
Uladzimir Karpenka 4f127a30ad fix macOS build 2026-05-28 15:59:49 +03:00
ew8bakandClaude Sonnet 4.6 1175e42516 Add channel memory: CH button, dropdown, editor form, smart CTCSS/RPT auto-clear
- New ChannelStore.pas: TChannel record + JSON persistence (channels.json)
- New ChannelsForm.pas: full channel editor (list + fields, pre-fills from current radio state)
- CH button in RX block: left-click opens dropdown, right-click opens editor
- Active channel: button highlights with channel name, deactivates on VFO move
- ApplyChannel: auto-switches XVTR/HF band based on channel frequency; saves old
  band state before switching to prevent cache corruption
- SaveCurrentBand: skip save when VFO > 61 MHz (prevents HF cache corruption
  from VHF channel application without XVTR)
- DeactivateXvtr: save full XVTR state (was only saving LastFreq)
- CTCSS/RPT from channel marked as auto: cleared automatically when tuning away
  from channel frequency; survives band switches via FXvtrSettings auto-flags
- TXvtrEntry: add LastCTCSSAutoActive, LastFMRptAutoActive fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:39:37 +03:00
ew8bak d08317e835 fix UpdateRptAutoState 2026-05-27 13:47:52 +03:00
ew8bak ae1a7d9a6d Add wideband spectrum fill option 2026-05-26 17:52:02 +03:00
ew8bak e0d49c7bfa Add wideband display pane 2026-05-26 16:24:07 +03:00
ew8bakandClaude Sonnet 4.6 9028a8dac0 Fix window geometry save/restore: DPI scaling, position drift, maximized state
- LFM: Position = poDesigned (was poScreenCenter, overriding our restore)
- RestoreWindowBounds: remove position scaling (L,T invariant across DPI);
  scale size correctly per backend: LCLWin32 uses CurDPI/SavedDPI (physical px),
  Qt6/GTK/Cocoa use SavedDPI/CurDPI (logical px, inverse); fix min-size
  inflation on Qt6 (was MulDiv(900,DPI,96) which exceeds logical screen width
  at 150%+ scale, forcing window to 0,0)
- SaveWindowBounds moved from FormDestroy to FormClose while window is still
  stable; add guard for bogus RestoredLeft/Top values on Qt6 when maximized
- RestoreWindowBounds stores FRestoreL/T and re-applies position in AfterShowTick
  (200ms after show) when WM frame extents are already known to Qt, fixing the
  systematic right/down drift caused by unknown frame extents at FormCreate time
- Save and restore WindowState (maximized flag); skip AfterShowTick position
  re-apply when window is maximized

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 11:56:56 +03:00
ew8bak 8624116f0c Fix window geometry scaling and close deadlock 2026-05-24 16:19:22 +03:00
ew8bak c5f225332b Add audio buffer setting and optimize overlays 2026-05-22 18:07:05 +03:00
ew8bakandClaude Sonnet 4.6 6932022177 Mic settings: auto PTT source, Mic In/Line In, Line In gain, Tip/Ring
- Remove manual "Mic Source" (Radio/SoundCard) setting from UI and storage;
  source is now determined automatically in ApplyMOX: HW PTT → txmsRadio,
  MOX button/CAT → txmsSoundCard if audio device configured, else txmsRadio
- Replace "Line in" checkbox with "Mic jack" combo (Mic In / Line In);
  when Line In is selected, Mic Boost is hidden and Line In Gain (-34.5..+12 dB,
  step 1.5 dB) is shown and sent as DUC Specific byte 51
- Add Tip/Ring connector selector (Orion/OrionMkII boards 4/5 only, byte 50 bit 3);
  control is hidden for other board types
- Fix byte 50 bit 1 (Mic Boost) suppressed when Line In is active
- Fix byte 51 comment polarity (was reversed: 0=+12dB; correct: 0=-34.5dB)
- New JSON fields: mic_line_in, mic_tip_ring, line_in_gain_db; mic_source removed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:32:19 +03:00
ew8bakandClaude Sonnet 4.6 d823106366 Add VHF XVTR PA calibration; fix TX drive formula and stale FDriveLevel
PA calibration per band (HF and VHF):
- Add VHFBandCal[0..7] in TGlobalSettings (saved as vhf_cal_0..7 in JSON)
- Default HF cal updated to Thetis HERMES defaults (38.8-41.3 dB per band)
- Default VHF cal = 56.2 dB (Thetis HERMES XVTR default)
- SettingsForm: second group in PA tab "VHF Calibration (Transverters)" with
  8 spinboxes VHF0..VHF7; labels dynamically show XVTR slot ButtonText
  when LoadXvtrSettings is called (e.g. "VHF0 (2m):")

TX drive formula (CalcDriveByte) rewritten to match Thetis exactly:
  drive_byte = min(sqrt(10^((10*log10(pwr_W*1000) - Cal)/10) * 0.05) / 0.8, 1.0) * 1.02 * 255
  Cal = PA gain in dB (not a percentage); matches Thetis verified output
  (Cal=63.1 + slider=100% + PAMax=100W → drive_byte=16, verified against Thetis)
  Old formula Pos/100*Cal/100*255 was wrong: treated dB gain as linear percent

Fix stale FDriveLevel not updated on band/XVTR switch:
- Startup: FCurrentBand must be set before CalcDriveByte (was reversed)
- RestoreBand: recalculate FDriveLevel before ApplyVfoA network update
- ActivateXvtrBand: recalculate after FCurrentXvtr changes
- ApplyVfoA: recalculate when VFO crosses HF band boundary
- FreqDispBChanged: same for VFO-B band changes
- ApplyMOX(True): safety recalculate at PTT engage time

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 11:49:12 +03:00
ew8bakandClaude Sonnet 4.6 a59501f2c4 Save/restore CTun, AGC, FM step per XVTR slot; add FM step to web
- Add LastCTun, LastAGCMode, LastAGCTop to TXvtrEntry; SaveCurrentBand
  now captures all three in the XVTR branch; ActivateXvtrBand restores
  them on slot switch/startup (previously CTun was always reset to False
  and AGC was never saved/restored for XVTR)
- WebServer: expose fmstep_idx in state JSON so web clients sync the
  FM step from desktop state
- WebPageHtml: swap stepSel options to FM steps (6.25k/12.5k/20k/25k)
  when mode=FM, restore HF steps when leaving FM; syncs fmstep_idx
  from server on connect and mode change

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:27:14 +03:00
ew8bakandClaude Sonnet 4.6 c4cd8afb06 Fix XVTR/FM frequency, mode and step persistence
- Fix web spectrum scroll resetting freq to XVTR minimum (same root
  cause as desktop: hardcoded 60 MHz clamp; now delegates to server)
- Save/restore FM mode, NFM/WFM filter, squelch, CTCSS per XVTR slot
  and per HF band (CTCSSOn/ToneIdx added to TBandSettings; full state
  added to TXvtrEntry; ActivateXvtrBand restores all on slot switch)
- Fix UpdateFilterButtons always resetting NFM/WFM to default on
  mode restore; now preserves saved filter index
- Add FM Step tuning: panel with STEP toggle + 6.25/12.5/20/25 kHz
  selector (popup); mouse wheel uses selected step in FM mode;
  state saved per band and XVTR slot

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:08:11 +03:00
ew8bakandClaude Sonnet 4.6 68d05657e6 Add FM mode improvements: NFM/FM filters, CTCSS, squelch; ADC and web settings
FM modulation:
- Replace 10 generic FM filter buttons with NFM (2.5kHz dev/11kHz BW) and FM
  (5.0kHz dev/16kHz BW); deviation applied to both RX and TX via WDSP
- Add FM squelch panel (SQL toggle + slider 0..100, per-band save/restore)
  with WDSP SetRXAFMSQRun/SetRXAFMSQThreshold (threshold = level/200.0)
- Add CTCSS panel with on/off toggle and custom flat-button tone picker popup
  (38 standard tones 67.0..250.3 Hz, default 67.0); tone selection and enable
  state saved per band via SetTXACTCSS*
- FM panels (SQL, CTCSS) shown only in FM mode, layout via RelayoutBelowBands
- PanelFilter height shrinks in FM mode so panels sit tight below filters
- FlatButton: handle CMTextChanged to invalidate on Caption change

ADC settings (Dither/Random):
- Add DitherEnabled/RandomEnabled to TGlobalSettings (default true)
- Pass as bitmask to ConfigureDDCs DDC Specific packet bytes 5/6
- Exposed in Settings → Advanced tab with live apply via ApplyADCSettings

Web server settings:
- Add TWebSettings (enabled, port, bind_addr, user, pass) stored globally
- WebServer: configurable port/bind IP via ParseIPv4; Reconfigure method
- Exposed in Settings → Advanced tab with live apply via ApplyWebSettings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 19:01:17 +03:00
ew8bakandClaude Sonnet 4.6 1368f249c4 Remove XVTR RF checkbox; fix XVTR Enable bit to match Thetis
XVTR RF (xvtr_rf in Thetis) is dead code — GetXVTRRF() is never called.
Remove the field, UI column, save/load from TXvtrEntry. UseDDCIn is now
always True when in XVTR mode (previous default behaviour, XVTRRF=False).

Byte 1400 bit 0 (XVTR Enable / VHF T/R relay output) now follows Thetis:
  - XVTR mode: set only when DisablePA=True (external T/R relay needed)
  - HF mode:   set when Alex.EnableXvtrHf is checked (Antenna tab)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 22:05:08 +03:00
ew8bakandClaude Sonnet 4.6 efc21b92e6 Add configurable VFO frequency range with GHz support
- Settings > Display: new "VFO Display" control to select max frequency
  range (999 MHz / 9.999 GHz / 99.999 GHz), persisted as freq_mhz_digits
- FreqDisplay: extend digit map [0..10] to support up to 11 digit positions;
  keyboard navigation adapts to MinMhzDigits dynamically
- MainForm/LayoutTopVfoBlock: VFO panel width scales automatically with
  selected digit count using dynamic text measurement
- Web VFO: fix broken HTML (class attr not closed before data-s — wheel and
  hover were completely non-functional); rewrite fmtVfo to use variable MHz
  digit count synced from server state; fix missing </span> for .vfo-hz
- WebServer: publish freq_mhz_digits in state JSON; updated from
  ApplyFreqMhzDigits so desktop and web stay in sync
- Fix Int32 overflow on frequencies above ~2.15 GHz: CATEngine.Pad V param
  Int64, FormatFreq/FormatFreqSV Mhz var Int64 (Mhz*1000000 overflowed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 13:13:52 +03:00
ew8bak 020b9422e0 add trancverter 2026-05-14 20:24:50 +03:00
ew8bak aea9f02df8 add Alex setup 2026-05-14 18:52:50 +03:00
ew8bak 006cf772b8 TUN button — Thetis-style тон через WDSP PostGen
- BtnTUN рядом с MOX. Включает SetTXAPostGenRun(TXA, 1) с тоном
  (mode=0, mag=1.0, freq из настроек) и активирует MOX. PTT/HW
  игнорируются во время tune.
- Drive в режиме TUN использует FTXSettings.TUNLevel вместо слайдера,
  per-band калибровка FPABandCal применяется одинаково.
- Settings → Transmit → Tune (TUN): TUNLevel 0..100% (def 10),
  TUNFreq 100..5000 Hz (def 750). Live-обновление во время tune.
2026-05-06 19:16:27 +03:00
ew8bak 88687b4e70 DUP (display duplex) + ATT on TX
- DUP: локальный режим отображения, при TX данные RX1, поверх рисуется
  TX-фильтр. Кнопка на левой панели рядом с CTUN. Аппаратной командой
  не является. Отдельный SetDisplaySourceTX в WDSPEngine, разделение
  TXMode (data) и TXOverlay (filter band) в SpectrumView.
- ATT on TX: 0..31 dB, default 31 (Thetis-style). UI на вкладке Transmit
  в группе Microphone. Передаётся в DUC Specific bytes 57/58/59
  (StepAtten0/1/2). Перепосылается при изменении.
2026-05-06 15:51:33 +03:00
ew8bakandClaude Opus 4.7 96d7e0c759 TX: фиксированный sample rate, per-device grid, CTUN-aware overlay, alpha-blend filter bands
Декаплинг TX от RX sample rate (как в Thetis):
- WDSPEngine.pas: константа TX_SAMPLE_RATE=192000, поля FTXSampleRate/FTXOutBufSize.
  TXA OpenChannel теперь использует FTXSampleRate как out_rate, TX-анализатор
  через SetDisplaySampleRate(TX_DISP_ID, FTXSampleRate). ProcessTXBlock работает
  с FTXOutBufSize вместо FBufSize. Public TXSampleRate для MainForm.
- MainForm.SendDUCSpecificFromSettings: DUC0Rate теперь берётся из
  FDSPEngine.TXSampleRate, а не из RX-настроек — TX всегда 192k независимо от
  выбранного RX-rate (48/96/192/384k).

DUC Specific cache + keepalive resend (HPSDRNetwork.pas):
- FCachedDUCSpec/FCachedDUCValid параллельно DDC-кэшу.
- KeepAlive thread в первые 5s после Run=1 переотправляет и DDC, и DUC
  Specific — устраняет гонку, когда DUC настройки терялись железом.
- Disconnect сбрасывает оба valid-флага.

Per-device TX grid settings (Thetis-style):
- Settings.pas: TXSpecRefLevel/TXSpecRange/TXSpecGridStep в TTXSettings
  (defaults 0.0/80.0/10.0). LoadTX/SaveTX — ключи tx_spec_ref_level/range/grid_step.
- SettingsForm.pas: новая группа \"TX Grid\" во вкладке Transmit
  (RefLevel edit, Range edit, GridStep combo). CollectTXFromUI читает значения,
  LoadTXSettings заполняет UI.
- MainForm.pas: поля FTXSpecRefLevel/Range/GridStep, ApplySpecViewGridFromState
  пушит в FSpecView либо TX, либо RX параметры в зависимости от FTransmitting.
  ApplyGridParams (RX-путь) уважает FTransmitting и не перебивает TX-grid.
  OnTXSettingsChange при активном TX моментально применяет новый grid.

TX-aware spectrum/waterfall с CTUN-выравниванием (SpectrumView.pas):
- Поля FTXMode/FTXFreq/FTXSpanHz/FTXVfoIndex. TXSpanHz=192000 при создании.
- DrawSpectrum/DrawWaterfall в FTXMode мапят данные TX-анализатора (192k вокруг
  FTXFreq) в RX-координаты FCenterFreq/FSpanHz. Формула:
    freq = FCenterFreq - FSpanHz/2 + x*FSpanHz/W
    idx  = (freq-FTXFreq + TXSpanHz/2)/TXSpanHz * (SrcCount-1)
  Вне диапазона — спектр уходит в -200 dB; водопад копирует пиксель из
  предыдущей строки (FWfPixels[X+W]) — вместо чёрной полосы продолжает
  скроллиться старая RX-картинка.
- Эффект: при CTUN ON TX-сигнал рисуется на полосе фильтра (на VFO), а не в
  центре. При RX rate ≠ 192k частотная сетка совпадает между RX и TX
  автоматически (ruler всегда в RX-координатах).
- MainForm.SyncSpecViewFreq/ApplyMOX обновляют TXFreq/TXVfoIndex/TXMode при
  каждом PTT и смене VFO; учитывается split (FSplitTxB → TXVfoIndex=1).

Alpha-blended filter bands (визуальный feedback TX/RX):
- SpectrumView: PixelFormat:=pf32bit, процедура BlendBand через ScanLine[Y]
  внутри BeginUpdate/EndUpdate. Альфа-смешение по формуле
  (a*src + (255-a)*dst) / 255 для каждого канала BGR.
- В FTXMode полоса фильтра становится полупрозрачно красной. Если split
  (FTXVfoIndex<>FActiveVfo): на RX-частоте полоса зелёная, на TX-частоте —
  красная (CalcFilterBandX вычисляет границы для произвольной VFO-freq).
- При FTXMode=False — старое поведение (сплошная заливка SpecFilter).

Build: lazbuild --ws=qt6 ewsdr.lpi — clean, 0 errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 14:17:49 +03:00
ew8bakandClaude Opus 4.7 ce97ee486c WIP: TX implementation — per-device settings, separate analyzer, sound-card mic
- Settings: TTXSettings record + LoadTX/SaveTX, JSON section "tx" per MAC
- WDSPEngine: separate TX_DISP_ID analyzer with own FFT/Window/Det/Avg
  parameters, ApplyTXAnalyzerSettings + setters
- WDSPEngine: full TX chain setters (Filter/Compressor/Leveler/ALC/
  PhaseRot/EQ/AMCarrier/FM/CTCSS) + ApplyTXChainSettings
- WDSPEngine: ProcessTXBlock now feeds TX analyzer in DISPLAY_BLOCK_SIZE
  chunks (was passing whole FTXOut → analyzer ignored most of it)
- WDSPEngine: ActiveDisplayID switches RX/TX in UpdateSpectrum
- WDSPEngine: RX audio muted while TX active to avoid local feedback
- WDSPEngine: default EQ frequencies in Create (zero freqs broke TX chain)
- WDSPEngine: PushTXMicSampleD + OnPullMicSamples for sound-card path
- AudioInput: Available counter for non-blocking pull
- MainForm: PullSoundCardMic, BuildMicLineSelectByte, SendDUCSpecific
  with mic bias/boost/line/PTT bits, OnTXSettingsChange
- MainForm: auto-switch MicSource on TX device select, TX diagnostic
  in StatusBar panel [5]
- SettingsForm: new Transmit nav page with Microphone, Filter, Dynamic
  processing, EQ, AM/FM/CTCSS, TX Display sections

NOT YET WORKING: sound-card mic produces ring activity but signal still
not visible on TX spectrum/waterfall — needs further investigation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 08:06:58 +03:00
ew8bakandClaude Sonnet 4.6 d9a2157719 add light/dark theme with global persistence
- AppTheme.pas: новый файл, TAppTheme record + DarkTheme()/LightTheme()
- FlatSlider: цвета через SetThemeColors вместо хардкода
- SpectrumView: все цвета из TAppTheme (SetTheme)
- SettingsForm: ApplyTheme(T) с рекурсивным обходом контролов
- DeviceForm: SetTheme(T) — перекраска всех элементов включая TEdit
- Settings: SaveTheme/LoadTheme в корневой секции preferences (не привязано к устройству)
- MainForm: тема загружается при старте, сохраняется при изменении

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 19:00:45 +03:00
ew8bakandClaude Sonnet 4.6 bcd045a1be Fix CAT settings: load before connect, default TCP port 19090
- Settings.pas: add root-level SaveCATSettings/LoadCATSettings so CAT
  config is stored independently of device MAC.
- MainForm.pas FormCreate: initialize CAT defaults, load from saved
  'cat' JSON section, and apply immediately after InitCATEngine — so
  SettingsForm shows correct values before the transceiver connects.
- MainForm.pas OnCATSettingsChange: always save to root 'cat' section
  (not only when device is connected) so changes persist immediately.
- Default TCP CAT port changed from 4992 to 19090 everywhere.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 21:58:49 +03:00
ew8bakandClaude Sonnet 4.6 36ae140cad Add full CAT support (serial + TCP)
New units: CATEngine (Kenwood + Thetis ZZ* commands), CATSerial
(up to 4 serial ports), CATTcp (multi-client TCP server on port 4992).
MainForm wired with TCATContext callbacks reusing existing WebOn* handlers.
SettingsForm gets a new CAT tab with 4 serial port groups and TCP section.
Settings.pas extended with CAT config fields (per-device, JSON-persisted).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:46:19 +03:00
ew8bak 537d288e1e refactoring SettingsForm 2026-04-25 14:50:52 +03:00
ew8bak 77d380acfd fix fft, waterfall 2026-04-22 22:09:42 +03:00
ew8bak ae532a33cd start work tx 2026-03-26 22:50:55 +03:00
ew8bak 01de71c60f add nb nr 2026-03-09 20:55:19 +03:00
ew8bak 7521a46bbc init 2026-03-05 16:19:26 +03:00