mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Phase 5 (batch 29): move Run=1 go-live (StartRunning) into the controller
Move the device bring-up tail of DoConnectDevice into TRadioController, symmetric with StopRunning: - Relocate four pure DSP/network helpers into the controller (BuildMicLineSelectByte, ApplyNoiseFilterButtonsToDSP, SendDUCSpecificFromSettings, ApplyTXSettingsToDSP); external callers (OnTXSettingsChange) now call FController.*. - New StartRunning(SpectrumWidth): General packet, wideband/DDC config, WDSP sample-rate sync, DSP restore (mode/volume/filter/NR/AGC), Run=1 sequence, seq reset, DDC/DUC Specific + TX chain, AGC lines. Emits Changed(rfRunning) so the run button / MOX enable / sleep inhibit render through OnControllerState. DoConnectDevice's ~80-line Phase C collapses to one call; only UI bits (FSpecView.AGCTop, status text, ResizeSpectrumPanels) stay in the wrapper. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
1fdbe27b96
commit
04f621bf3d
+13
-178
@@ -430,7 +430,6 @@ type
|
||||
procedure UpdateNBButton;
|
||||
procedure UpdateSNBButton;
|
||||
procedure UpdateANFButton;
|
||||
procedure ApplyNoiseFilterButtonsToDSP;
|
||||
procedure BtnNRClick(Sender: TObject);
|
||||
procedure BtnNBClick(Sender: TObject);
|
||||
procedure BtnSNBClick(Sender: TObject);
|
||||
@@ -593,11 +592,8 @@ type
|
||||
procedure ApplyAudioInputDevice(DevIndex: Integer; const DevName: string);
|
||||
procedure ApplyAudioBufferSize(BufferSize: Integer);
|
||||
procedure ApplySendAudioToRadio(Enabled: Boolean);
|
||||
// TX settings: применить FTXSettings к WDSP и переслать DUC Specific
|
||||
// (mic-биты Boost/Bias/LineIn/PTT попадают в byte 50 DUCSpecific).
|
||||
procedure ApplyTXSettingsToDSP;
|
||||
procedure SendDUCSpecificFromSettings;
|
||||
function BuildMicLineSelectByte: Byte;
|
||||
// TX settings (ApplyTXSettingsToDSP/SendDUCSpecificFromSettings/
|
||||
// BuildMicLineSelectByte) переехали в TRadioController.
|
||||
procedure ApplyVisibility(ShowSpectrum, ShowWaterfall, ShowWideband,
|
||||
WidebandFill, SpectrumFill: Boolean);
|
||||
procedure ApplyFPS(FPS: Integer);
|
||||
@@ -3324,55 +3320,8 @@ end;
|
||||
// TX settings — применение к WDSP, сборка DUC Specific, sound-card pull
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function TMainForm.BuildMicLineSelectByte: Byte;
|
||||
// openHPSDR Ethernet Protocol v4.3, DUC Specific byte 50:
|
||||
// bit 0 — Line In (1 = line-in вместо mic-in)
|
||||
// bit 1 — Mic Boost (+20 dB); не ставим когда Line In
|
||||
// bit 2 — 0 = Orion mic PTT enabled, 1 = disabled (инверсия!)
|
||||
// bit 3 — Tip/Ring (0=Tip, 1=Ring; Orion/OrionMkII)
|
||||
// bit 4 — Orion mic bias (1 = enable +5V bias)
|
||||
// bit 5 — Saturn XLR/balanced (не используем)
|
||||
begin
|
||||
Result := 0;
|
||||
if FController.FTXSettings.MicLineIn then
|
||||
Result := Result or $01 // bit 0: Line In
|
||||
else if FController.FTXSettings.MicBoost then
|
||||
Result := Result or $02; // bit 1: Boost только при Mic In
|
||||
if not FController.FTXSettings.MicPTTEnabled then Result := Result or $04; // bit 2: инверсия
|
||||
if FController.FTXSettings.MicTipRing then Result := Result or $08; // bit 3: Ring
|
||||
if FController.FTXSettings.MicBias then Result := Result or $10; // bit 4: bias
|
||||
end;
|
||||
|
||||
procedure TMainForm.SendDUCSpecificFromSettings;
|
||||
var
|
||||
DUCPkt: TDUCSpecificPacket;
|
||||
RateKsps: Word;
|
||||
begin
|
||||
if not (FController.FNetwork.Connected and FController.FNetwork.Running) then Exit;
|
||||
FillChar(DUCPkt, SizeOf(DUCPkt), 0);
|
||||
// DUC0 rate в ksps берём из WDSP-движка (фиксированный TX rate, не RX).
|
||||
RateKsps := FController.FDSPEngine.TXSampleRate div 1000;
|
||||
DUCPkt.NumDACs := 1;
|
||||
DUCPkt.SidetoneLevel := 50;
|
||||
DUCPkt.SidetoneFreqHi := Hi(600);
|
||||
DUCPkt.SidetoneFreqLo := Lo(600);
|
||||
DUCPkt.KeyerSpeed := 20;
|
||||
DUCPkt.KeyerWeight := 50;
|
||||
DUCPkt.DUC0RateHi := Hi(RateKsps);
|
||||
DUCPkt.DUC0RateLo := Lo(RateKsps);
|
||||
DUCPkt.DUC0Bits := 24;
|
||||
DUCPkt.MicLineSelect := BuildMicLineSelectByte;
|
||||
// Line In Gain (byte 51): 0=-34.5dB .. 31=+12dB (шаг 1.5 dB, формула Thetis).
|
||||
// При Mic In значение игнорируется железом, но шлём корректное для Line In.
|
||||
DUCPkt.LineInGain := Byte(EnsureRange(Round((FController.FTXSettings.LineInGainDB + 34.5) / 1.5), 0, 31));
|
||||
// ATT on TX — RX-ADC step attenuator во время передачи (Thetis-style protection).
|
||||
// Дублируем значение во все три ADC-байта: на однопотоковых платах активен только
|
||||
// ADC0, на Saturn/Hermes Lite 2 — могут использоваться ADC1/ADC2.
|
||||
DUCPkt.StepAtten0 := Byte(EnsureRange(FController.FTXSettings.AttOnTX, 0, 31));
|
||||
DUCPkt.StepAtten1 := DUCPkt.StepAtten0;
|
||||
DUCPkt.StepAtten2 := DUCPkt.StepAtten0;
|
||||
FController.FNetwork.SendDUCSpecific(DUCPkt);
|
||||
end;
|
||||
// BuildMicLineSelectByte / SendDUCSpecificFromSettings переехали в
|
||||
// TRadioController (чистые над FTXSettings/движком; нужны headless StartRunning).
|
||||
|
||||
function TMainForm.DefaultMicSource: TTXMicSource;
|
||||
// Mic source для MOX-кнопки и Web-TX: если настроена звуковая карта — берём с неё,
|
||||
@@ -3383,38 +3332,7 @@ begin
|
||||
else Result := txmsRadio;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyTXSettingsToDSP;
|
||||
begin
|
||||
if not FController.FWDSPReady then Exit;
|
||||
// Mic source — выставляем значение по умолчанию для MOX-кнопки;
|
||||
// при реальном PTT ApplyMOX скорректирует источник.
|
||||
FController.FDSPEngine.SetTXMicSource(DefaultMicSource);
|
||||
FController.FDSPEngine.SetMicGain(FController.FTXSettings.MicGainDB);
|
||||
FController.FDSPEngine.SetTXFilterFull(FController.FTXSettings.FilterLow, FController.FTXSettings.FilterHigh,
|
||||
FController.FTXSettings.FilterNC, FController.FTXSettings.FilterMP,
|
||||
FController.FTXSettings.FilterWindow);
|
||||
FController.FDSPEngine.SetTXCompressor(FController.FTXSettings.CompressorOn, FController.FTXSettings.CompressorGain);
|
||||
FController.FDSPEngine.SetTXLeveler(FController.FTXSettings.LevelerOn, FController.FTXSettings.LevelerTop,
|
||||
FController.FTXSettings.LevelerDecay);
|
||||
FController.FDSPEngine.SetTXALC(FController.FTXSettings.ALCOn, FController.FTXSettings.ALCMaxGain,
|
||||
FController.FTXSettings.ALCDecay);
|
||||
FController.FDSPEngine.SetTXPhaseRot(FController.FTXSettings.PhaseRotOn, FController.FTXSettings.PhaseRotStages,
|
||||
FController.FTXSettings.PhaseRotFreq);
|
||||
FController.FDSPEngine.SetTXEQ(FController.FTXSettings.EQOn, FController.FTXSettings.EQNumBands,
|
||||
FController.FTXSettings.EQGains, FController.FTXSettings.EQFreqs);
|
||||
FController.FDSPEngine.SetTXAMCarrierLevel(FController.FTXSettings.AMCarrierLevel);
|
||||
FController.FDSPEngine.SetTXFMParams(FController.FTXSettings.FMDeviation, FController.FTXSettings.FMLowCut,
|
||||
FController.FTXSettings.FMHighCut, FController.FTXSettings.FMEmphPosition);
|
||||
FController.FDSPEngine.SetTXCTCSS(FController.FTXSettings.CTCSSOn, FController.FTXSettings.CTCSSFreq);
|
||||
// TX display
|
||||
FController.FDSPEngine.SetTXFFTParams(FController.FTXSettings.TXFFTSize, FController.FTXSettings.TXWindowType);
|
||||
FController.FDSPEngine.SetTXSpectrumDisplay(FController.FTXSettings.TXSpecDetector,
|
||||
FController.FTXSettings.TXSpecAvgMode,
|
||||
FController.FTXSettings.TXSpecAvgTimeMS);
|
||||
FController.FDSPEngine.SetTXWaterfallDisplay(FController.FTXSettings.TXWfDetector,
|
||||
FController.FTXSettings.TXWfAvgMode,
|
||||
FController.FTXSettings.TXWfAvgTimeMS);
|
||||
end;
|
||||
// ApplyTXSettingsToDSP переехал в TRadioController (вся TX-цепь над FTXSettings).
|
||||
|
||||
// ===========================================================================
|
||||
// Button handlers
|
||||
@@ -3761,7 +3679,6 @@ end;
|
||||
|
||||
procedure TMainForm.DoConnectDevice(const Dev: THPSDRDevice);
|
||||
var
|
||||
GenPkt: TGeneralPacket;
|
||||
G_Settings: TGlobalSettings;
|
||||
i: Integer;
|
||||
begin
|
||||
@@ -3915,87 +3832,12 @@ begin
|
||||
SetStatusText(1, 'IP: ' + FController.FNetwork.Device.IPAddress);
|
||||
SetStatusText(0, 'Board: ' + BoardTypeName(FController.FNetwork.Device.BoardType));
|
||||
|
||||
// General packet
|
||||
FillChar(GenPkt, SizeOf(GenPkt), 0);
|
||||
GenPkt.Command := CMD_GENERAL;
|
||||
GenPkt.Flags37 := $08;
|
||||
GenPkt.Flags38 := $01;
|
||||
GenPkt.PAConfig := $01;
|
||||
GenPkt.WBPort[0] := (PORT_WIDEBAND_ADC0 shr 8) and $FF;
|
||||
GenPkt.WBPort[1] := PORT_WIDEBAND_ADC0 and $FF;
|
||||
GenPkt.WBEnable := IfThen(FController.FShowWideband, 1, 0);
|
||||
GenPkt.WBSamplesPerPkt[0] := 512 shr 8;
|
||||
GenPkt.WBSamplesPerPkt[1] := 512 and $FF;
|
||||
GenPkt.WBSampleSize := 16;
|
||||
GenPkt.WBUpdateRate := 70;
|
||||
GenPkt.WBPacketsPerFrame := 32;
|
||||
if FController.FNetwork.Device.BoardType = 5 then
|
||||
GenPkt.AlexEnable := $03
|
||||
else
|
||||
GenPkt.AlexEnable := $01;
|
||||
FController.FNetwork.SendGeneralPacket(GenPkt);
|
||||
FController.FNetwork.ConfigureWideband(0, FController.FShowWideband, 512, 16, 70, 32);
|
||||
|
||||
if FController.FNetwork.Device.BoardType in [3, 4, 5] then
|
||||
FController.FActiveDDC := 2
|
||||
else
|
||||
FController.FActiveDDC := 0;
|
||||
|
||||
// Синхронизируем samplerate WDSP если нужно
|
||||
if FController.FWDSPReady and (FController.FDSPEngine.SampleRate <> FController.FSampleRate) then
|
||||
begin
|
||||
FController.FWDSPReady := False;
|
||||
FController.FDSPEngine.ChangeSampleRate(FController.FSampleRate);
|
||||
FController.FWDSPReady := FController.FDSPEngine.Initialized;
|
||||
end;
|
||||
|
||||
if FController.FWDSPReady then
|
||||
begin
|
||||
FController.FDSPEngine.SetMode(FController.FMode);
|
||||
FController.FDSPEngine.SetVolume(FController.FVolume / 100.0);
|
||||
FController.ApplyModeFilter;
|
||||
ApplyNoiseFilterButtonsToDSP;
|
||||
// ChangeSampleRate пересоздаёт WDSP-канал — восстанавливаем все настройки
|
||||
FController.FDSPEngine.SetAGCTop(FController.FAGCTop);
|
||||
FController.FDSPEngine.SetAGC(TWDSPAGCMode(FController.FAGCMode), 50.0);
|
||||
end;
|
||||
// «Go-live» Run=1 (General/DDC/DUC + DSP restore) — в контроллере; рендер
|
||||
// run-кнопки/MOX/sleep идёт через OnControllerState(rfRunning).
|
||||
FController.StartRunning(FSpectrumWidth);
|
||||
FSpecView.AGCTop := FController.FAGCTop;
|
||||
|
||||
// Сначала отправляем Run=1 — эмулятор/железо создают ddc_specific_thread
|
||||
// (порт 1025) и rx_thread (порт 1035+) только после получения HP Run=1.
|
||||
// DDC Specific и DUC Specific отправляем ПОСЛЕ, иначе порты ещё не открыты.
|
||||
FController.FNetwork.UpdateState(XvtrTranslate(FController.FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FController.FDriveLevel, False, True, True);
|
||||
FController.FNetwork.SetRunAndFreq(True, XvtrTranslate(FController.FCenterFreq), XvtrTranslate(FController.FCenterFreq), FController.FDriveLevel);
|
||||
FController.FRunning := True;
|
||||
InhibitSleep;
|
||||
FController.FRXStartTime := GetTickCount64;
|
||||
FController.FRXLastPktTime := 0;
|
||||
FController.FRXPacketCount := 0;
|
||||
FillChar(FController.FDDCSeqValid, SizeOf(FController.FDDCSeqValid), 0);
|
||||
FController.FSeqErrorCount := 0;
|
||||
FController.FLastSeqErrorDDC := -1;
|
||||
FController.FLastSeqErrorDelta := 0;
|
||||
FController.FSeqOkStreak := 0;
|
||||
SetStatusText(6, 'SEQ OK');
|
||||
|
||||
// DDC и DUC Specific — теперь потоки эмулятора слушают на своих портах.
|
||||
// DUC Specific содержит mic-конфигурацию (boost/bias/line/PTT) из FController.FTXSettings.
|
||||
FController.FNetwork.ConfigureDDCs(1, FController.FSampleRate div 1000, 0, FController.FDitherEnabled, FController.FRandomEnabled);
|
||||
// Применяем сохранённое состояние динамика/отправки аудио (мьют byte 1400 bit1).
|
||||
FController.FNetwork.SetSpeakerAudio(FController.FSendAudioToRadio);
|
||||
SendDUCSpecificFromSettings;
|
||||
// Применяем TX-цепь (фильтр, mic gain, EQ, leveler, ALC, comp, ...).
|
||||
ApplyTXSettingsToDSP;
|
||||
FController.ApplyModeFilter;
|
||||
|
||||
// Принудительно обновляем AGC линии — гарантированно после всех SetAGC вызовов
|
||||
if FController.FWDSPReady then
|
||||
FController.FDSPEngine.UpdateAGCLines(FSpectrumWidth); // ещё не получили ни одного пакета
|
||||
|
||||
BtnStartStop.Caption := 'STOP';
|
||||
StyleButton(BtnStartStop, True);
|
||||
SetStatusText(2, 'Running');
|
||||
BtnMOX.Enabled := True;
|
||||
ResizeSpectrumPanels;
|
||||
end;
|
||||
|
||||
@@ -5091,14 +4933,7 @@ begin
|
||||
BtnANF.Invalidate;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyNoiseFilterButtonsToDSP;
|
||||
begin
|
||||
if not FController.FWDSPReady then Exit;
|
||||
FController.FDSPEngine.SetNRMode(FController.FNRMode);
|
||||
FController.FDSPEngine.SetNBMode(FController.FNBMode);
|
||||
FController.FDSPEngine.SetSNB(FController.FSNB);
|
||||
FController.FDSPEngine.SetANF(FController.FANF);
|
||||
end;
|
||||
// ApplyNoiseFilterButtonsToDSP переехал в TRadioController (NR/NB/SNB/ANF → WDSP).
|
||||
|
||||
procedure TMainForm.BtnNRClick(Sender: TObject);
|
||||
begin
|
||||
@@ -5779,7 +5614,7 @@ var
|
||||
OldAtt, OldTUNLevel, OldTUNFreq: Integer;
|
||||
GridChanged: Boolean;
|
||||
begin
|
||||
OldMicByte := BuildMicLineSelectByte;
|
||||
OldMicByte := FController.BuildMicLineSelectByte;
|
||||
OldAtt := FController.FTXSettings.AttOnTX;
|
||||
OldTUNLevel := FController.FTXSettings.TUNLevel;
|
||||
OldTUNFreq := FController.FTXSettings.TUNFreq;
|
||||
@@ -5787,7 +5622,7 @@ begin
|
||||
or (FController.FTXSpecRange <> T.TXSpecRange)
|
||||
or (FController.FTXSpecGridStep <> T.TXSpecGridStep);
|
||||
FController.FTXSettings := T;
|
||||
NewMicByte := BuildMicLineSelectByte;
|
||||
NewMicByte := FController.BuildMicLineSelectByte;
|
||||
// TX-grid в момент правки — обновляем рабочие поля и (если на передаче) пушим в FSpecView
|
||||
FController.FTXSpecRefLevel := FController.FTXSettings.TXSpecRefLevel;
|
||||
FController.FTXSpecRange := FController.FTXSettings.TXSpecRange;
|
||||
@@ -5795,9 +5630,9 @@ begin
|
||||
FController.FTXSpecGridStep := FController.FTXSettings.TXSpecGridStep;
|
||||
if GridChanged and FController.FTransmitting then
|
||||
ApplySpecViewGridFromState;
|
||||
ApplyTXSettingsToDSP;
|
||||
FController.ApplyTXSettingsToDSP;
|
||||
if (OldMicByte <> NewMicByte) or (OldAtt <> FController.FTXSettings.AttOnTX) then
|
||||
SendDUCSpecificFromSettings;
|
||||
FController.SendDUCSpecificFromSettings;
|
||||
// TUN-параметры live: если идёт tune — обновить тон/drive, иначе просто запомнить.
|
||||
if FController.FTuning then
|
||||
begin
|
||||
|
||||
@@ -287,6 +287,12 @@ type
|
||||
// если настроена, иначе HW mic-стрим трансивера. HW PTT → txmsRadio в SetMOX.
|
||||
function DefaultMicSource: TTXMicSource;
|
||||
|
||||
// ---- TX/DSP-цепь (чистые над состоянием: читают F*/FTXSettings, пишут в движок) ----
|
||||
function BuildMicLineSelectByte: Byte; // DUC Specific byte 50 (mic/line биты)
|
||||
procedure ApplyNoiseFilterButtonsToDSP; // NR/NB/SNB/ANF → WDSP
|
||||
procedure SendDUCSpecificFromSettings; // DUC Specific (mic/keyer/atten) в сеть
|
||||
procedure ApplyTXSettingsToDSP; // TX-цепь (фильтр/gain/EQ/comp/...) → WDSP
|
||||
|
||||
// ---- Управление диапазонами (состояние + DSP; рендер через события) ----
|
||||
// MakeBandSettings — снимок текущего состояния в запись диапазона.
|
||||
// SaveCurrentBand — сохраняет текущее состояние в кэш+конфиг (или в XVTR-слот).
|
||||
@@ -388,6 +394,7 @@ type
|
||||
// Жизненный цикл движка / устройства
|
||||
procedure StartStop;
|
||||
procedure SetRun(On_: Boolean);
|
||||
procedure StartRunning(SpectrumWidth: Integer); // Run=1 bring-up: General/DDC/DUC + DSP restore
|
||||
procedure StopRunning; // Run=0: graceful-стоп RX-потока + сброс TX/телеметрии
|
||||
procedure ConnectDevice(const Dev: THPSDRDevice);
|
||||
procedure Discover;
|
||||
@@ -1635,6 +1642,98 @@ begin
|
||||
else Result := txmsRadio;
|
||||
end;
|
||||
|
||||
function TRadioController.BuildMicLineSelectByte: Byte;
|
||||
// openHPSDR Ethernet Protocol v4.3, DUC Specific byte 50:
|
||||
// bit 0 — Line In (1 = line-in вместо mic-in)
|
||||
// bit 1 — Mic Boost (+20 dB); не ставим когда Line In
|
||||
// bit 2 — 0 = Orion mic PTT enabled, 1 = disabled (инверсия!)
|
||||
// bit 3 — Tip/Ring (0=Tip, 1=Ring; Orion/OrionMkII)
|
||||
// bit 4 — Orion mic bias (1 = enable +5V bias)
|
||||
// bit 5 — Saturn XLR/balanced (не используем)
|
||||
begin
|
||||
Result := 0;
|
||||
if FTXSettings.MicLineIn then
|
||||
Result := Result or $01 // bit 0: Line In
|
||||
else if FTXSettings.MicBoost then
|
||||
Result := Result or $02; // bit 1: Boost только при Mic In
|
||||
if not FTXSettings.MicPTTEnabled then Result := Result or $04; // bit 2: инверсия
|
||||
if FTXSettings.MicTipRing then Result := Result or $08; // bit 3: Ring
|
||||
if FTXSettings.MicBias then Result := Result or $10; // bit 4: bias
|
||||
end;
|
||||
|
||||
procedure TRadioController.ApplyNoiseFilterButtonsToDSP;
|
||||
begin
|
||||
if not FWDSPReady then Exit;
|
||||
FDSPEngine.SetNRMode(FNRMode);
|
||||
FDSPEngine.SetNBMode(FNBMode);
|
||||
FDSPEngine.SetSNB(FSNB);
|
||||
FDSPEngine.SetANF(FANF);
|
||||
end;
|
||||
|
||||
procedure TRadioController.SendDUCSpecificFromSettings;
|
||||
var
|
||||
DUCPkt: TDUCSpecificPacket;
|
||||
RateKsps: Word;
|
||||
begin
|
||||
if not (FNetwork.Connected and FNetwork.Running) then Exit;
|
||||
FillChar(DUCPkt, SizeOf(DUCPkt), 0);
|
||||
// DUC0 rate в ksps берём из WDSP-движка (фиксированный TX rate, не RX).
|
||||
RateKsps := FDSPEngine.TXSampleRate div 1000;
|
||||
DUCPkt.NumDACs := 1;
|
||||
DUCPkt.SidetoneLevel := 50;
|
||||
DUCPkt.SidetoneFreqHi := Hi(600);
|
||||
DUCPkt.SidetoneFreqLo := Lo(600);
|
||||
DUCPkt.KeyerSpeed := 20;
|
||||
DUCPkt.KeyerWeight := 50;
|
||||
DUCPkt.DUC0RateHi := Hi(RateKsps);
|
||||
DUCPkt.DUC0RateLo := Lo(RateKsps);
|
||||
DUCPkt.DUC0Bits := 24;
|
||||
DUCPkt.MicLineSelect := BuildMicLineSelectByte;
|
||||
// Line In Gain (byte 51): 0=-34.5dB .. 31=+12dB (шаг 1.5 dB, формула Thetis).
|
||||
// При Mic In значение игнорируется железом, но шлём корректное для Line In.
|
||||
DUCPkt.LineInGain := Byte(EnsureRange(Round((FTXSettings.LineInGainDB + 34.5) / 1.5), 0, 31));
|
||||
// ATT on TX — RX-ADC step attenuator во время передачи (Thetis-style protection).
|
||||
// Дублируем значение во все три ADC-байта: на однопотоковых платах активен только
|
||||
// ADC0, на Saturn/Hermes Lite 2 — могут использоваться ADC1/ADC2.
|
||||
DUCPkt.StepAtten0 := Byte(EnsureRange(FTXSettings.AttOnTX, 0, 31));
|
||||
DUCPkt.StepAtten1 := DUCPkt.StepAtten0;
|
||||
DUCPkt.StepAtten2 := DUCPkt.StepAtten0;
|
||||
FNetwork.SendDUCSpecific(DUCPkt);
|
||||
end;
|
||||
|
||||
procedure TRadioController.ApplyTXSettingsToDSP;
|
||||
begin
|
||||
if not FWDSPReady then Exit;
|
||||
// Mic source — выставляем значение по умолчанию для MOX-кнопки;
|
||||
// при реальном PTT SetMOX скорректирует источник.
|
||||
FDSPEngine.SetTXMicSource(DefaultMicSource);
|
||||
FDSPEngine.SetMicGain(FTXSettings.MicGainDB);
|
||||
FDSPEngine.SetTXFilterFull(FTXSettings.FilterLow, FTXSettings.FilterHigh,
|
||||
FTXSettings.FilterNC, FTXSettings.FilterMP,
|
||||
FTXSettings.FilterWindow);
|
||||
FDSPEngine.SetTXCompressor(FTXSettings.CompressorOn, FTXSettings.CompressorGain);
|
||||
FDSPEngine.SetTXLeveler(FTXSettings.LevelerOn, FTXSettings.LevelerTop,
|
||||
FTXSettings.LevelerDecay);
|
||||
FDSPEngine.SetTXALC(FTXSettings.ALCOn, FTXSettings.ALCMaxGain,
|
||||
FTXSettings.ALCDecay);
|
||||
FDSPEngine.SetTXPhaseRot(FTXSettings.PhaseRotOn, FTXSettings.PhaseRotStages,
|
||||
FTXSettings.PhaseRotFreq);
|
||||
FDSPEngine.SetTXEQ(FTXSettings.EQOn, FTXSettings.EQNumBands,
|
||||
FTXSettings.EQGains, FTXSettings.EQFreqs);
|
||||
FDSPEngine.SetTXAMCarrierLevel(FTXSettings.AMCarrierLevel);
|
||||
FDSPEngine.SetTXFMParams(FTXSettings.FMDeviation, FTXSettings.FMLowCut,
|
||||
FTXSettings.FMHighCut, FTXSettings.FMEmphPosition);
|
||||
FDSPEngine.SetTXCTCSS(FTXSettings.CTCSSOn, FTXSettings.CTCSSFreq);
|
||||
// TX display
|
||||
FDSPEngine.SetTXFFTParams(FTXSettings.TXFFTSize, FTXSettings.TXWindowType);
|
||||
FDSPEngine.SetTXSpectrumDisplay(FTXSettings.TXSpecDetector,
|
||||
FTXSettings.TXSpecAvgMode,
|
||||
FTXSettings.TXSpecAvgTimeMS);
|
||||
FDSPEngine.SetTXWaterfallDisplay(FTXSettings.TXWfDetector,
|
||||
FTXSettings.TXWfAvgMode,
|
||||
FTXSettings.TXWfAvgTimeMS);
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetMOX(On_: Boolean);
|
||||
var
|
||||
WasTransmitting: Boolean;
|
||||
@@ -1841,6 +1940,91 @@ begin SetRun(not FRunning); end;
|
||||
procedure TRadioController.SetRun(On_: Boolean);
|
||||
begin FRunning := On_; Changed(rfRunning); { TODO wiring: логика BtnStartStopClick } end;
|
||||
|
||||
procedure TRadioController.StartRunning(SpectrumWidth: Integer);
|
||||
// «Go-live» последовательность Run=1: General packet, wideband/DDC-конфиг,
|
||||
// синхронизация WDSP sample rate, восстановление DSP (mode/volume/filter/NR/AGC),
|
||||
// Run=1 → seq-сброс → DDC/DUC Specific + TX-цепь. Рендер run-кнопки/sleep — UI
|
||||
// через OnControllerState(rfRunning); статус-бар/FSpecView.AGCTop/resize — обёртка.
|
||||
var
|
||||
GenPkt: TGeneralPacket;
|
||||
begin
|
||||
// General packet
|
||||
FillChar(GenPkt, SizeOf(GenPkt), 0);
|
||||
GenPkt.Command := CMD_GENERAL;
|
||||
GenPkt.Flags37 := $08;
|
||||
GenPkt.Flags38 := $01;
|
||||
GenPkt.PAConfig := $01;
|
||||
GenPkt.WBPort[0] := (PORT_WIDEBAND_ADC0 shr 8) and $FF;
|
||||
GenPkt.WBPort[1] := PORT_WIDEBAND_ADC0 and $FF;
|
||||
GenPkt.WBEnable := IfThen(FShowWideband, 1, 0);
|
||||
GenPkt.WBSamplesPerPkt[0] := 512 shr 8;
|
||||
GenPkt.WBSamplesPerPkt[1] := 512 and $FF;
|
||||
GenPkt.WBSampleSize := 16;
|
||||
GenPkt.WBUpdateRate := 70;
|
||||
GenPkt.WBPacketsPerFrame := 32;
|
||||
if FNetwork.Device.BoardType = 5 then
|
||||
GenPkt.AlexEnable := $03
|
||||
else
|
||||
GenPkt.AlexEnable := $01;
|
||||
FNetwork.SendGeneralPacket(GenPkt);
|
||||
FNetwork.ConfigureWideband(0, FShowWideband, 512, 16, 70, 32);
|
||||
|
||||
if FNetwork.Device.BoardType in [3, 4, 5] then
|
||||
FActiveDDC := 2
|
||||
else
|
||||
FActiveDDC := 0;
|
||||
|
||||
// Синхронизируем samplerate WDSP если нужно
|
||||
if FWDSPReady and (FDSPEngine.SampleRate <> FSampleRate) then
|
||||
begin
|
||||
FWDSPReady := False;
|
||||
FDSPEngine.ChangeSampleRate(FSampleRate);
|
||||
FWDSPReady := FDSPEngine.Initialized;
|
||||
end;
|
||||
|
||||
if FWDSPReady then
|
||||
begin
|
||||
FDSPEngine.SetMode(FMode);
|
||||
FDSPEngine.SetVolume(FVolume / 100.0);
|
||||
ApplyModeFilter;
|
||||
ApplyNoiseFilterButtonsToDSP;
|
||||
// ChangeSampleRate пересоздаёт WDSP-канал — восстанавливаем все настройки
|
||||
FDSPEngine.SetAGCTop(FAGCTop);
|
||||
FDSPEngine.SetAGC(TWDSPAGCMode(FAGCMode), 50.0);
|
||||
end;
|
||||
|
||||
// Сначала отправляем Run=1 — эмулятор/железо создают ddc_specific_thread
|
||||
// (порт 1025) и rx_thread (порт 1035+) только после получения HP Run=1.
|
||||
// DDC Specific и DUC Specific отправляем ПОСЛЕ, иначе порты ещё не открыты.
|
||||
FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FDriveLevel, False, True, True);
|
||||
FNetwork.SetRunAndFreq(True, XvtrTranslate(FCenterFreq), XvtrTranslate(FCenterFreq), FDriveLevel);
|
||||
FRunning := True;
|
||||
FRXStartTime := GetTickCount64;
|
||||
FRXLastPktTime := 0;
|
||||
FRXPacketCount := 0;
|
||||
FillChar(FDDCSeqValid, SizeOf(FDDCSeqValid), 0);
|
||||
FSeqErrorCount := 0;
|
||||
FLastSeqErrorDDC := -1;
|
||||
FLastSeqErrorDelta := 0;
|
||||
FSeqOkStreak := 0;
|
||||
|
||||
// DDC и DUC Specific — теперь потоки эмулятора слушают на своих портах.
|
||||
// DUC Specific содержит mic-конфигурацию (boost/bias/line/PTT) из FTXSettings.
|
||||
FNetwork.ConfigureDDCs(1, FSampleRate div 1000, 0, FDitherEnabled, FRandomEnabled);
|
||||
// Применяем сохранённое состояние динамика/отправки аудио (мьют byte 1400 bit1).
|
||||
FNetwork.SetSpeakerAudio(FSendAudioToRadio);
|
||||
SendDUCSpecificFromSettings;
|
||||
// Применяем TX-цепь (фильтр, mic gain, EQ, leveler, ALC, comp, ...).
|
||||
ApplyTXSettingsToDSP;
|
||||
ApplyModeFilter;
|
||||
|
||||
// Принудительно обновляем AGC линии — гарантированно после всех SetAGC вызовов
|
||||
if FWDSPReady then
|
||||
FDSPEngine.UpdateAGCLines(SpectrumWidth); // ещё не получили ни одного пакета
|
||||
|
||||
Changed(rfRunning); // UI: caption STOP / MOX.Enabled / InhibitSleep
|
||||
end;
|
||||
|
||||
procedure TRadioController.StopRunning;
|
||||
// Graceful-останов RX-потока (Run=0) + сброс TX и RX-телеметрии. Сеть остаётся
|
||||
// Connected — Disconnect отдельно (UI-обёртка делает это после persistence).
|
||||
|
||||
Reference in New Issue
Block a user