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>
This commit is contained in:
2026-06-17 12:06:59 +03:00
co-authored by Claude Opus 4.8
parent a988849d3e
commit 24f74357cd
6 changed files with 228 additions and 3 deletions
+7
View File
@@ -218,6 +218,8 @@ type
LastBand: Integer;
LastXvtr: Integer; // -1 = HF, 0..CFG_XVTR_COUNT-1 = активный трансвертер при выходе
SampleRate: Integer; // глобальный — один для всех диапазонов
RxGainMode: Integer; // Pluto: 0=manual,1=fast,2=slow,3=hybrid
RxGainDb: Integer; // Pluto: manual gain дБ
WindowLeft: Integer;
WindowTop: Integer;
WindowWidth: Integer;
@@ -401,6 +403,7 @@ begin
G.WfAGCEnabled := True;
G.WfNFEnabled := False;
G.SampleRate := 192000;
G.RxGainMode := 2; G.RxGainDb := 40;
G.PAMaxPower := 100.0;
for i := 0 to CFG_BAND_COUNT-1 do G.PABandCal[i] := CFG_PA_BAND_CAL_DEFAULT[i];
for i := 0 to CFG_XVTR_COUNT-1 do G.VHFBandCal[i] := CFG_VHF_CAL_DEFAULT;
@@ -597,6 +600,8 @@ begin
G.LastBand := JI(GObj,'last_band',5);
G.LastXvtr := JI(GObj,'last_xvtr',-1);
G.SampleRate := JI(GObj,'sample_rate',192000);
G.RxGainMode := JI(GObj,'rx_gain_mode',2);
G.RxGainDb := JI(GObj,'rx_gain_db',40);
// Display settings
G.FFTSize := JI(GObj,'fft_size',131072);
G.WindowType := JI(GObj,'win_type',2);
@@ -712,6 +717,8 @@ begin
JW(O,'last_band',G.LastBand);
JW(O,'last_xvtr',G.LastXvtr);
JW(O,'sample_rate',G.SampleRate);
JW(O,'rx_gain_mode',G.RxGainMode);
JW(O,'rx_gain_db',G.RxGainDb);
// Display settings
JW(O,'fft_size',G.FFTSize);
JW(O,'win_type',G.WindowType);