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>
This commit is contained in:
2026-07-13 21:26:18 +03:00
co-authored by Claude Opus 4.8
parent a2e403af3d
commit 9dd38e1dd3
8 changed files with 673 additions and 32 deletions
+64
View File
@@ -324,6 +324,8 @@ type
// ---- Конфиги / устройство (per-MAC) ----
FTXSettings: TTXSettings;
FAlexSettings: TAlexSettings;
// Антенные разъёмы AD936x (Pluto/LibreSDR) на диапазон/трансвертер.
FAnt936x: TAD936xAnt;
FXvtrSettings: TXvtrSettings;
FBandCache: array[0..CFG_BAND_COUNT-1] of TBandSettings;
FPABandCal: array[0..CFG_BAND_COUNT-1] of Double;
@@ -599,6 +601,11 @@ type
function PanDDCRateKHz(PanId: Integer): Word;
// ADC-источник пана (3.4). PanId=0 = главный DDC (реконфиг ConfigureDDCs),
// N>0 = его пан-DDC (SetPanDDC). ADC ∈ [0..Caps.NumADCs-1].
// Антенные разъёмы AD936x: настройки (вкладка Antenna) + применение текущего
// контекста (диапазон | активный трансвертер) к железу.
procedure SetAnt936x(const A: TAD936xAnt);
procedure ApplyAntPorts;
property Ant936x: TAD936xAnt read FAnt936x;
function PanADC(PanId: Integer): Byte;
function SetPanADC(PanId: Integer; ADC: Byte): Boolean;
// ---- Зум/пан доп. панов (PanId=0 делегирует главному зуму) ----
@@ -1410,6 +1417,43 @@ begin
else Result := 0;
end;
procedure TRadioController.SetAnt936x(const A: TAD936xAnt);
// Новая таблица «диапазон → разъём» из настроек: сохранить + применить текущий.
begin
FAnt936x := A;
if FDevConnected then
begin
FSettings.SaveAnt936x(FDevMAC, FAnt936x);
FSettings.Save;
end;
ApplyAntPorts;
end;
procedure TRadioController.ApplyAntPorts;
// Антенна — свойство диапазона (как RxAnt/TxAnt у Alex): при смене диапазона или
// входе/выходе из трансвертера включаем разъёмы, выбранные для этого контекста.
var
Rx, Tx: Byte;
Bi: Integer;
begin
if not (Assigned(FNetwork) and FNetwork.Connected) then Exit;
if not FNetwork.Caps.HasAntSwitch then Exit;
if (FCurrentXvtr >= 0) and (FCurrentXvtr < CFG_XVTR_COUNT) then
begin
Rx := FAnt936x.XvtrRxAnt[FCurrentXvtr];
Tx := FAnt936x.XvtrTxAnt[FCurrentXvtr];
end
else
begin
// Диапазон — по ВИДИМОЙ частоте приёма (VU-план AD936x).
Bi := FreqToBandIdx(FCenterFreq, IsPluto);
if (Bi < 0) or (Bi >= CFG_BAND_COUNT) then Exit; // вне плана — не трогаем
Rx := FAnt936x.RxAnt[Bi];
Tx := FAnt936x.TxAnt[Bi];
end;
FNetwork.SetAntPorts(Rx, Tx);
end;
function TRadioController.PanADC(PanId: Integer): Byte;
begin
if PanId = 0 then Result := FMainADCSrc
@@ -2231,6 +2275,9 @@ begin
Result.FMStepIdx := FFMStepIdx;
Result.FMRptDir := FFMRptDir;
Result.FMRptOffsetHz := FFMRptOffsetHz;
// Аппаратный AGC AD936x — на диапазон (усиление тракта разное на 2м и QO-100).
Result.RxGainMode := FRxGainMode;
Result.RxGainDb := FRxGainDb;
// Waterfall AGC/NF — глобальные (не диапазонные)
end;
@@ -2267,6 +2314,8 @@ begin
FXvtrSettings.Entries[i].LastFMRptAutoActive := FFMRptAutoActive;
FXvtrSettings.Entries[i].LastZoomFactor := FZoomFactor;
FXvtrSettings.Entries[i].LastPanSlider := FPanSlider;
FXvtrSettings.Entries[i].LastRxGainMode := FRxGainMode;
FXvtrSettings.Entries[i].LastRxGainDb := FRxGainDb;
end;
FSettings.SaveXvtr(FDevMAC, FXvtrSettings);
Exit;
@@ -2386,6 +2435,13 @@ begin
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetAGCTop(FAGCTop);
ApplyAGCToEngine;
// --- Аппаратный AGC AD936x (Pluto/LibreSDR): режим + manual-гейн диапазона.
// У openHPSDR SetRxGain — no-op, поля просто ездят с диапазоном.
FRxGainMode := EnsureRange(B.RxGainMode, 0, 3);
FRxGainDb := EnsureRange(B.RxGainDb, 0, 73);
ApplyRxGainToBackend;
Changed(rfRxGain); // UI: кнопки FAST/SLOW/HYB/MAN + ползунок
// --- FM squelch / CTCSS / step / repeater ---
FFMSQOn := B.FMSQOn;
FFMSQLevel := B.FMSQLevel;
@@ -2471,6 +2527,7 @@ begin
// Иначе смена диапазона при активном B центрировала бы приёмник на A.
if FActiveVfo = 0 then SetVfoA(FVfoA)
else SetVfoB(FVfoB);
ApplyAntPorts; // AD936x: разъёмы, выбранные для этого диапазона
end;
function TRadioController.ActiveVfoHz: Double;
@@ -3089,6 +3146,8 @@ begin
B.FMStepIdx := E.LastFMStepIdx;
B.FMRptDir := E.LastFMRptDir;
B.FMRptOffsetHz := E.LastFMRptOffsetHz;
B.RxGainMode := E.LastRxGainMode; // hw-AGC слота (AD936x)
B.RxGainDb := E.LastRxGainDb;
B.VfoA := Vis;
B.VfoB := FVfoB;
ApplyBandDSP(B);
@@ -3120,6 +3179,7 @@ begin
if E.FullDuplexTx and not FDisplayDuplex then SetDuplex(True);
PushNetworkState;
RefreshPanDDCs; // живые паны — в диапазон XVTR, DDC — на IF
ApplyAntPorts; // AD936x: разъёмы, выбранные для этого трансвертера
Changed(rfXvtr);
Changed(rfActiveVfo);
@@ -3947,6 +4007,8 @@ begin
FNetwork.SetSpeakerAudio(FSendAudioToRadio);
// RX hw-gain в бэкенд (Pluto). HPSDR — no-op.
ApplyRxGainToBackend;
// Антенные разъёмы AD936x для текущего диапазона/трансвертера. HPSDR — no-op.
ApplyAntPorts;
// QO-100 self-monitor: RX-аудио на TX (full-duplex). По умолчанию заглушено.
ApplyRxMuteToEngine;
SendDUCSpecificFromSettings;
@@ -4076,6 +4138,7 @@ begin
// TX/Alex/XVTR per-device
FSettings.LoadTX(FDevMAC, FTXSettings);
FSettings.LoadAlex(FDevMAC, FAlexSettings);
FSettings.LoadAnt936x(FDevMAC, FAnt936x);
FNetwork.SetAlexConfig(FAlexSettings);
FSettings.LoadXvtr(FDevMAC, FXvtrSettings);
FCurrentXvtr := -1;
@@ -4247,6 +4310,7 @@ begin
SaveCurrentBand;
SaveGlobalSettings;
FSettings.SaveAlex(FDevMAC, FAlexSettings);
FSettings.SaveAnt936x(FDevMAC, FAnt936x);
// XVTR LastFreq → актуальная видимая частота в момент остановки.
if (FCurrentXvtr >= 0) and (FCurrentXvtr < CFG_XVTR_COUNT) then
FXvtrSettings.Entries[FCurrentXvtr].LastFreq := FVfoA;