mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
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>
This commit is contained in:
@@ -205,6 +205,7 @@ type
|
||||
FLastVfoScrolled: Boolean; // последний SetVfoA прокрутил центр (для водопада)
|
||||
FAtten: Integer;
|
||||
FPAMaxPower: Double;
|
||||
FPlutoTxMaxAttDb: Double; // Pluto: TX-аттенюация на drive=100% (потолок, дБ<0)
|
||||
FRunning: Boolean;
|
||||
FTransmitting: Boolean;
|
||||
FTuning: Boolean;
|
||||
@@ -453,6 +454,12 @@ type
|
||||
procedure DriveBy(Delta: Integer);
|
||||
procedure SetAtten(Idx: Integer);
|
||||
|
||||
// Pluto TX-мощность через аттенюацию: drive% → дБ (потолок FPlutoTxMaxAttDb на
|
||||
// 100%, выкл на приёме). Логика/маппинг здесь; бэкенд лишь пишет hardwaregain.
|
||||
function PlutoTxAttForDrive: Double; // дБ<0 под текущий FDrivePercent
|
||||
procedure ApplyPlutoTxAtten; // ставит att по FTransmitting/FTuning
|
||||
procedure SetPlutoTxMaxAtt(Db: Double); // потолок на drive=100% (внешний усилитель)
|
||||
|
||||
// Диапазоны / трансвертеры / спан
|
||||
procedure SetBand(Idx: Integer);
|
||||
procedure BandUp;
|
||||
@@ -560,6 +567,7 @@ begin
|
||||
FCurrentBand := 5; FCurrentXvtr := -1;
|
||||
FSpectrumBufCount := 1024; FWaterfallBufCount := 1024;
|
||||
FPAMaxPower := 100.0;
|
||||
FPlutoTxMaxAttDb := -10.0; // ADI-дефолт: линейный режим выходных каскадов
|
||||
FWfAGCEnabled := True; FDitherEnabled := True; FRandomEnabled := True;
|
||||
FFMStepOn := True;
|
||||
FLastSMeter := -130; FLastSWR := 1; FLastSupplyV := -1; FLastSupplyA := -1;
|
||||
@@ -1485,6 +1493,7 @@ begin
|
||||
Result.Volume := FVolume;
|
||||
Result.DriveLevel := FDrivePercent;
|
||||
Result.PAMaxPower := FPAMaxPower;
|
||||
Result.PlutoTxMaxAttDb := FPlutoTxMaxAttDb;
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do Result.PABandCal[i] := FPABandCal[i];
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do Result.VHFBandCal[i] := FVHFBandCal[i];
|
||||
Result.ActiveVfo := FActiveVfo;
|
||||
@@ -2076,6 +2085,7 @@ begin
|
||||
FDrivePercent := V;
|
||||
FDriveLevel := CalcDriveByte;
|
||||
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetDriveLevel(FDrivePercent / 100.0);
|
||||
ApplyPlutoTxAtten; // Pluto: drive живьём меняет TX-аттенюацию во время передачи
|
||||
PushNetworkState; // протолкнуть новый drive в радио (если подключено+Running)
|
||||
Changed(rfDrive);
|
||||
end;
|
||||
@@ -2083,6 +2093,39 @@ end;
|
||||
procedure TRadioController.DriveBy(Delta: Integer);
|
||||
begin SetDrive(FDrivePercent + Delta); end;
|
||||
|
||||
function TRadioController.PlutoTxAttForDrive: Double;
|
||||
const
|
||||
TX_OFF = -89.75; // макс. аттенюация AD9361 (0% → практически выкл)
|
||||
var
|
||||
Pct: Integer;
|
||||
begin
|
||||
// На тюне (TUN) уровень берём из TX-настроек (TUNLevel), иначе из drive%.
|
||||
if FTuning then Pct := FTXSettings.TUNLevel else Pct := FDrivePercent;
|
||||
if Pct < 0 then Pct := 0 else if Pct > 100 then Pct := 100;
|
||||
// dB-линейно: 0% → TX_OFF, 100% → FPlutoTxMaxAttDb (потолок под внешний тракт).
|
||||
Result := TX_OFF + (Pct / 100.0) * (FPlutoTxMaxAttDb - TX_OFF);
|
||||
if Result > FPlutoTxMaxAttDb then Result := FPlutoTxMaxAttDb;
|
||||
if Result < TX_OFF then Result := TX_OFF;
|
||||
end;
|
||||
|
||||
procedure TRadioController.ApplyPlutoTxAtten;
|
||||
const
|
||||
TX_OFF = -89.75;
|
||||
begin
|
||||
if (FNetwork = nil) or not IsPluto then Exit;
|
||||
// На передаче (MOX/TUN) — мощность от drive; на приёме — макс. аттенюация (выкл).
|
||||
if FTransmitting or FTuning then FNetwork.SetTxAtten(PlutoTxAttForDrive)
|
||||
else FNetwork.SetTxAtten(TX_OFF);
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetPlutoTxMaxAtt(Db: Double);
|
||||
begin
|
||||
if Db > 0 then Db := 0 else if Db < -50 then Db := -50;
|
||||
FPlutoTxMaxAttDb := Db;
|
||||
ApplyPlutoTxAtten; // применить живьём, если сейчас передаём
|
||||
SaveGlobalSettings; // персист потолка (per-device)
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetAtten(Idx: Integer);
|
||||
begin
|
||||
if Idx < 0 then Idx := 0 else if Idx > 2 then Idx := 2;
|
||||
@@ -2510,6 +2553,7 @@ begin
|
||||
FNetwork.ClearDUCIQQueue;
|
||||
FNetwork.SendFullHP; // 2й пакет: Alex bit27=0 (T/R relay RX)
|
||||
end;
|
||||
ApplyPlutoTxAtten; // Pluto: TX-мощность по drive на передаче, OFF на приёме
|
||||
Changed(rfTransmitting);
|
||||
end;
|
||||
|
||||
@@ -2549,6 +2593,7 @@ begin
|
||||
FNetwork.SendFullHP;
|
||||
end;
|
||||
end;
|
||||
ApplyPlutoTxAtten; // финальное состояние att по FTuning/FTransmitting (Pluto)
|
||||
Changed(rfTuning);
|
||||
end;
|
||||
|
||||
@@ -2780,6 +2825,7 @@ begin
|
||||
FVolume := FLoadedGlobal.Volume;
|
||||
FActiveVfo := EnsureRange(FLoadedGlobal.ActiveVfo, 0, 1); // битый конфиг не должен дать невалидный VFO
|
||||
FPAMaxPower := FLoadedGlobal.PAMaxPower;
|
||||
FPlutoTxMaxAttDb := EnsureRange(FLoadedGlobal.PlutoTxMaxAttDb, -50.0, 0.0);
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
FPABandCal[i] := FLoadedGlobal.PABandCal[i];
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||
|
||||
Reference in New Issue
Block a user