mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-26 04:47:35 +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 UpdateNBButton;
|
||||||
procedure UpdateSNBButton;
|
procedure UpdateSNBButton;
|
||||||
procedure UpdateANFButton;
|
procedure UpdateANFButton;
|
||||||
procedure ApplyNoiseFilterButtonsToDSP;
|
|
||||||
procedure BtnNRClick(Sender: TObject);
|
procedure BtnNRClick(Sender: TObject);
|
||||||
procedure BtnNBClick(Sender: TObject);
|
procedure BtnNBClick(Sender: TObject);
|
||||||
procedure BtnSNBClick(Sender: TObject);
|
procedure BtnSNBClick(Sender: TObject);
|
||||||
@@ -593,11 +592,8 @@ type
|
|||||||
procedure ApplyAudioInputDevice(DevIndex: Integer; const DevName: string);
|
procedure ApplyAudioInputDevice(DevIndex: Integer; const DevName: string);
|
||||||
procedure ApplyAudioBufferSize(BufferSize: Integer);
|
procedure ApplyAudioBufferSize(BufferSize: Integer);
|
||||||
procedure ApplySendAudioToRadio(Enabled: Boolean);
|
procedure ApplySendAudioToRadio(Enabled: Boolean);
|
||||||
// TX settings: применить FTXSettings к WDSP и переслать DUC Specific
|
// TX settings (ApplyTXSettingsToDSP/SendDUCSpecificFromSettings/
|
||||||
// (mic-биты Boost/Bias/LineIn/PTT попадают в byte 50 DUCSpecific).
|
// BuildMicLineSelectByte) переехали в TRadioController.
|
||||||
procedure ApplyTXSettingsToDSP;
|
|
||||||
procedure SendDUCSpecificFromSettings;
|
|
||||||
function BuildMicLineSelectByte: Byte;
|
|
||||||
procedure ApplyVisibility(ShowSpectrum, ShowWaterfall, ShowWideband,
|
procedure ApplyVisibility(ShowSpectrum, ShowWaterfall, ShowWideband,
|
||||||
WidebandFill, SpectrumFill: Boolean);
|
WidebandFill, SpectrumFill: Boolean);
|
||||||
procedure ApplyFPS(FPS: Integer);
|
procedure ApplyFPS(FPS: Integer);
|
||||||
@@ -3324,55 +3320,8 @@ end;
|
|||||||
// TX settings — применение к WDSP, сборка DUC Specific, sound-card pull
|
// TX settings — применение к WDSP, сборка DUC Specific, sound-card pull
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function TMainForm.BuildMicLineSelectByte: Byte;
|
// BuildMicLineSelectByte / SendDUCSpecificFromSettings переехали в
|
||||||
// openHPSDR Ethernet Protocol v4.3, DUC Specific byte 50:
|
// TRadioController (чистые над FTXSettings/движком; нужны headless StartRunning).
|
||||||
// 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;
|
|
||||||
|
|
||||||
function TMainForm.DefaultMicSource: TTXMicSource;
|
function TMainForm.DefaultMicSource: TTXMicSource;
|
||||||
// Mic source для MOX-кнопки и Web-TX: если настроена звуковая карта — берём с неё,
|
// Mic source для MOX-кнопки и Web-TX: если настроена звуковая карта — берём с неё,
|
||||||
@@ -3383,38 +3332,7 @@ begin
|
|||||||
else Result := txmsRadio;
|
else Result := txmsRadio;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.ApplyTXSettingsToDSP;
|
// ApplyTXSettingsToDSP переехал в TRadioController (вся TX-цепь над FTXSettings).
|
||||||
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;
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// Button handlers
|
// Button handlers
|
||||||
@@ -3761,7 +3679,6 @@ end;
|
|||||||
|
|
||||||
procedure TMainForm.DoConnectDevice(const Dev: THPSDRDevice);
|
procedure TMainForm.DoConnectDevice(const Dev: THPSDRDevice);
|
||||||
var
|
var
|
||||||
GenPkt: TGeneralPacket;
|
|
||||||
G_Settings: TGlobalSettings;
|
G_Settings: TGlobalSettings;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
@@ -3915,87 +3832,12 @@ begin
|
|||||||
SetStatusText(1, 'IP: ' + FController.FNetwork.Device.IPAddress);
|
SetStatusText(1, 'IP: ' + FController.FNetwork.Device.IPAddress);
|
||||||
SetStatusText(0, 'Board: ' + BoardTypeName(FController.FNetwork.Device.BoardType));
|
SetStatusText(0, 'Board: ' + BoardTypeName(FController.FNetwork.Device.BoardType));
|
||||||
|
|
||||||
// General packet
|
// «Go-live» Run=1 (General/DDC/DUC + DSP restore) — в контроллере; рендер
|
||||||
FillChar(GenPkt, SizeOf(GenPkt), 0);
|
// run-кнопки/MOX/sleep идёт через OnControllerState(rfRunning).
|
||||||
GenPkt.Command := CMD_GENERAL;
|
FController.StartRunning(FSpectrumWidth);
|
||||||
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;
|
|
||||||
FSpecView.AGCTop := FController.FAGCTop;
|
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');
|
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');
|
SetStatusText(2, 'Running');
|
||||||
BtnMOX.Enabled := True;
|
|
||||||
ResizeSpectrumPanels;
|
ResizeSpectrumPanels;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -5091,14 +4933,7 @@ begin
|
|||||||
BtnANF.Invalidate;
|
BtnANF.Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.ApplyNoiseFilterButtonsToDSP;
|
// ApplyNoiseFilterButtonsToDSP переехал в TRadioController (NR/NB/SNB/ANF → WDSP).
|
||||||
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;
|
|
||||||
|
|
||||||
procedure TMainForm.BtnNRClick(Sender: TObject);
|
procedure TMainForm.BtnNRClick(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
@@ -5779,7 +5614,7 @@ var
|
|||||||
OldAtt, OldTUNLevel, OldTUNFreq: Integer;
|
OldAtt, OldTUNLevel, OldTUNFreq: Integer;
|
||||||
GridChanged: Boolean;
|
GridChanged: Boolean;
|
||||||
begin
|
begin
|
||||||
OldMicByte := BuildMicLineSelectByte;
|
OldMicByte := FController.BuildMicLineSelectByte;
|
||||||
OldAtt := FController.FTXSettings.AttOnTX;
|
OldAtt := FController.FTXSettings.AttOnTX;
|
||||||
OldTUNLevel := FController.FTXSettings.TUNLevel;
|
OldTUNLevel := FController.FTXSettings.TUNLevel;
|
||||||
OldTUNFreq := FController.FTXSettings.TUNFreq;
|
OldTUNFreq := FController.FTXSettings.TUNFreq;
|
||||||
@@ -5787,7 +5622,7 @@ begin
|
|||||||
or (FController.FTXSpecRange <> T.TXSpecRange)
|
or (FController.FTXSpecRange <> T.TXSpecRange)
|
||||||
or (FController.FTXSpecGridStep <> T.TXSpecGridStep);
|
or (FController.FTXSpecGridStep <> T.TXSpecGridStep);
|
||||||
FController.FTXSettings := T;
|
FController.FTXSettings := T;
|
||||||
NewMicByte := BuildMicLineSelectByte;
|
NewMicByte := FController.BuildMicLineSelectByte;
|
||||||
// TX-grid в момент правки — обновляем рабочие поля и (если на передаче) пушим в FSpecView
|
// TX-grid в момент правки — обновляем рабочие поля и (если на передаче) пушим в FSpecView
|
||||||
FController.FTXSpecRefLevel := FController.FTXSettings.TXSpecRefLevel;
|
FController.FTXSpecRefLevel := FController.FTXSettings.TXSpecRefLevel;
|
||||||
FController.FTXSpecRange := FController.FTXSettings.TXSpecRange;
|
FController.FTXSpecRange := FController.FTXSettings.TXSpecRange;
|
||||||
@@ -5795,9 +5630,9 @@ begin
|
|||||||
FController.FTXSpecGridStep := FController.FTXSettings.TXSpecGridStep;
|
FController.FTXSpecGridStep := FController.FTXSettings.TXSpecGridStep;
|
||||||
if GridChanged and FController.FTransmitting then
|
if GridChanged and FController.FTransmitting then
|
||||||
ApplySpecViewGridFromState;
|
ApplySpecViewGridFromState;
|
||||||
ApplyTXSettingsToDSP;
|
FController.ApplyTXSettingsToDSP;
|
||||||
if (OldMicByte <> NewMicByte) or (OldAtt <> FController.FTXSettings.AttOnTX) then
|
if (OldMicByte <> NewMicByte) or (OldAtt <> FController.FTXSettings.AttOnTX) then
|
||||||
SendDUCSpecificFromSettings;
|
FController.SendDUCSpecificFromSettings;
|
||||||
// TUN-параметры live: если идёт tune — обновить тон/drive, иначе просто запомнить.
|
// TUN-параметры live: если идёт tune — обновить тон/drive, иначе просто запомнить.
|
||||||
if FController.FTuning then
|
if FController.FTuning then
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -287,6 +287,12 @@ type
|
|||||||
// если настроена, иначе HW mic-стрим трансивера. HW PTT → txmsRadio в SetMOX.
|
// если настроена, иначе HW mic-стрим трансивера. HW PTT → txmsRadio в SetMOX.
|
||||||
function DefaultMicSource: TTXMicSource;
|
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; рендер через события) ----
|
// ---- Управление диапазонами (состояние + DSP; рендер через события) ----
|
||||||
// MakeBandSettings — снимок текущего состояния в запись диапазона.
|
// MakeBandSettings — снимок текущего состояния в запись диапазона.
|
||||||
// SaveCurrentBand — сохраняет текущее состояние в кэш+конфиг (или в XVTR-слот).
|
// SaveCurrentBand — сохраняет текущее состояние в кэш+конфиг (или в XVTR-слот).
|
||||||
@@ -388,6 +394,7 @@ type
|
|||||||
// Жизненный цикл движка / устройства
|
// Жизненный цикл движка / устройства
|
||||||
procedure StartStop;
|
procedure StartStop;
|
||||||
procedure SetRun(On_: Boolean);
|
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 StopRunning; // Run=0: graceful-стоп RX-потока + сброс TX/телеметрии
|
||||||
procedure ConnectDevice(const Dev: THPSDRDevice);
|
procedure ConnectDevice(const Dev: THPSDRDevice);
|
||||||
procedure Discover;
|
procedure Discover;
|
||||||
@@ -1635,6 +1642,98 @@ begin
|
|||||||
else Result := txmsRadio;
|
else Result := txmsRadio;
|
||||||
end;
|
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);
|
procedure TRadioController.SetMOX(On_: Boolean);
|
||||||
var
|
var
|
||||||
WasTransmitting: Boolean;
|
WasTransmitting: Boolean;
|
||||||
@@ -1841,6 +1940,91 @@ begin SetRun(not FRunning); end;
|
|||||||
procedure TRadioController.SetRun(On_: Boolean);
|
procedure TRadioController.SetRun(On_: Boolean);
|
||||||
begin FRunning := On_; Changed(rfRunning); { TODO wiring: логика BtnStartStopClick } end;
|
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;
|
procedure TRadioController.StopRunning;
|
||||||
// Graceful-останов RX-потока (Run=0) + сброс TX и RX-телеметрии. Сеть остаётся
|
// Graceful-останов RX-потока (Run=0) + сброс TX и RX-телеметрии. Сеть остаётся
|
||||||
// Connected — Disconnect отдельно (UI-обёртка делает это после persistence).
|
// Connected — Disconnect отдельно (UI-обёртка делает это после persistence).
|
||||||
|
|||||||
Reference in New Issue
Block a user