mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Add wideband display pane
This commit is contained in:
+129
-3
@@ -91,6 +91,9 @@ type
|
||||
const Data: TDDCIQPacket) of object;
|
||||
TOnMicPacket = procedure(const Data: TMicDataPacket) of object;
|
||||
TOnHPStatus = procedure(const Status: THighPriorityStatus) of object;
|
||||
TOnWidebandFrame = procedure(ADCIndex: Integer;
|
||||
const Samples: array of SmallInt;
|
||||
Count: Integer) of object;
|
||||
|
||||
{ THPSDRNetwork }
|
||||
THPSDRNetwork = class
|
||||
@@ -117,6 +120,7 @@ type
|
||||
FOnDDCIQ: TOnDDCIQPacket;
|
||||
FOnMic: TOnMicPacket;
|
||||
FOnHPStatus: TOnHPStatus;
|
||||
FOnWideband: TOnWidebandFrame;
|
||||
|
||||
FPortDDCSpec: Word;
|
||||
FPortDUCSpec: Word;
|
||||
@@ -124,6 +128,16 @@ type
|
||||
FPortDDCAudio: Word;
|
||||
FPortDUCIQ: Word;
|
||||
FDirectIP: string; // для unicast discovery
|
||||
FWidebandADC: Integer;
|
||||
FWidebandEnabled: Boolean;
|
||||
FWBPacketsPerFrame: Integer;
|
||||
FWBSamplesPerPacket: Integer;
|
||||
FWBSampleBits: Integer;
|
||||
FWBUpdateRateMS: Integer;
|
||||
FWBFrame: array of SmallInt;
|
||||
FWBFrameCount: Integer;
|
||||
FWBLastSeq: LongWord;
|
||||
FWBSeqValid: Boolean;
|
||||
|
||||
// Кэш DDC/DUC Specific — keepalive повторно шлёт первые 5 сек после старта.
|
||||
// duc_specific_thread эмулятора биндится на 1026 только после HP Run=1,
|
||||
@@ -178,6 +192,7 @@ type
|
||||
procedure HandleHPStatus(const Buf: array of Byte; Len: Integer);
|
||||
procedure HandleDDCIQ(const Buf: array of Byte; Len: Integer; DDCIdx: Integer);
|
||||
procedure HandleMicData(const Buf: array of Byte; Len: Integer);
|
||||
procedure HandleWidebandData(const Buf: array of Byte; Len: Integer; ADCIdx: Integer);
|
||||
procedure StartThreads;
|
||||
procedure StopThreads;
|
||||
procedure ResetDUCIQQueue;
|
||||
@@ -195,6 +210,9 @@ type
|
||||
procedure Disconnect;
|
||||
|
||||
procedure SendGeneralPacket(const Pkt: TGeneralPacket);
|
||||
procedure ConfigureWideband(ADCIndex: Integer; Enabled: Boolean;
|
||||
SamplesPerPacket: Integer = 512; SampleBits: Integer = 16;
|
||||
UpdateRateMS: Integer = 70; PacketsPerFrame: Integer = 32);
|
||||
procedure SendDDCSpecific(const Pkt: TDDCSpecificPacket);
|
||||
procedure ConfigureDDCs(NumDDCs: Byte; SampleRate: Word; ADCSource: Byte = 0;
|
||||
DitherEnabled: Boolean = True; RandomEnabled: Boolean = True);
|
||||
@@ -227,6 +245,7 @@ type
|
||||
property OnDDCIQ: TOnDDCIQPacket read FOnDDCIQ write FOnDDCIQ;
|
||||
property OnMicPacket: TOnMicPacket read FOnMic write FOnMic;
|
||||
property OnHPStatus: TOnHPStatus read FOnHPStatus write FOnHPStatus;
|
||||
property OnWideband: TOnWidebandFrame read FOnWideband write FOnWideband;
|
||||
property DirectIP: string read FDirectIP write FDirectIP; // unicast discovery
|
||||
end;
|
||||
|
||||
@@ -367,6 +386,8 @@ begin
|
||||
PORT_MIC_DATA:
|
||||
if Len >= 132 then
|
||||
FNet.HandleMicData(Buf, Len);
|
||||
PORT_WIDEBAND_ADC0 .. PORT_WIDEBAND_ADC0 + MAX_ADCS - 1:
|
||||
FNet.HandleWidebandData(Buf, Len, SrcPort - PORT_WIDEBAND_ADC0);
|
||||
PORT_DDC0_IQ .. PORT_DDC0_IQ + MAX_DDCS - 1:
|
||||
FNet.HandleDDCIQ(Buf, Len, SrcPort - PORT_DDC0_IQ);
|
||||
end;
|
||||
@@ -577,6 +598,14 @@ begin
|
||||
FPortHPFromPC := PORT_HP_FROM_PC;
|
||||
FPortDDCAudio := PORT_DDC_AUDIO;
|
||||
FPortDUCIQ := PORT_DUC_IQ;
|
||||
FWidebandADC := 0;
|
||||
FWidebandEnabled := False;
|
||||
FWBPacketsPerFrame := 32;
|
||||
FWBSamplesPerPacket := 512;
|
||||
FWBSampleBits := 16;
|
||||
FWBUpdateRateMS := 70;
|
||||
FWBFrameCount := 0;
|
||||
FWBSeqValid := False;
|
||||
FCurrentRXFreq := 7100000;
|
||||
FCurrentTXFreq := 7100000;
|
||||
FCurrentDrive := 0;
|
||||
@@ -1020,6 +1049,56 @@ begin
|
||||
FOnMic(Pkt); // прямой вызов из receive thread — TX обработка не касается UI
|
||||
end;
|
||||
|
||||
procedure THPSDRNetwork.HandleWidebandData(const Buf: array of Byte; Len: Integer;
|
||||
ADCIdx: Integer);
|
||||
var
|
||||
Seq: LongWord;
|
||||
I, SamplesInPacket, TargetCount, S: Integer;
|
||||
begin
|
||||
if (not FWidebandEnabled) or (ADCIdx <> FWidebandADC) or
|
||||
(FWBSampleBits <> 16) or (Len < 6) then Exit;
|
||||
|
||||
SamplesInPacket := (Len - 4) div 2;
|
||||
if SamplesInPacket <= 0 then Exit;
|
||||
if FWBSamplesPerPacket > 0 then
|
||||
SamplesInPacket := Min(SamplesInPacket, FWBSamplesPerPacket);
|
||||
|
||||
Seq := (LongWord(Buf[0]) shl 24) or (LongWord(Buf[1]) shl 16) or
|
||||
(LongWord(Buf[2]) shl 8) or LongWord(Buf[3]);
|
||||
if Seq = 0 then
|
||||
begin
|
||||
FWBFrameCount := 0;
|
||||
FWBSeqValid := True;
|
||||
end
|
||||
else if FWBSeqValid and (Seq <> FWBLastSeq + 1) then
|
||||
begin
|
||||
FWBFrameCount := 0;
|
||||
FWBSeqValid := False;
|
||||
Exit;
|
||||
end;
|
||||
FWBLastSeq := Seq;
|
||||
FWBSeqValid := True;
|
||||
|
||||
TargetCount := Max(1, FWBPacketsPerFrame) * Max(1, FWBSamplesPerPacket);
|
||||
if Length(FWBFrame) <> TargetCount then
|
||||
SetLength(FWBFrame, TargetCount);
|
||||
|
||||
for I := 0 to SamplesInPacket - 1 do
|
||||
begin
|
||||
if FWBFrameCount >= TargetCount then Break;
|
||||
S := (SmallInt(ShortInt(Buf[4 + I * 2])) shl 8) or Buf[5 + I * 2];
|
||||
FWBFrame[FWBFrameCount] := SmallInt(S);
|
||||
Inc(FWBFrameCount);
|
||||
end;
|
||||
|
||||
if (FWBFrameCount >= TargetCount) and Assigned(FOnWideband) then
|
||||
begin
|
||||
FOnWideband(ADCIdx, FWBFrame, FWBFrameCount);
|
||||
FWBFrameCount := 0;
|
||||
FWBSeqValid := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Отправка пакетов
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -1029,10 +1108,51 @@ var
|
||||
B: TGeneralPacket;
|
||||
begin
|
||||
B := Pkt;
|
||||
B.WBPort[0] := (PORT_WIDEBAND_ADC0 shr 8) and $FF;
|
||||
B.WBPort[1] := PORT_WIDEBAND_ADC0 and $FF;
|
||||
if FWidebandEnabled then
|
||||
B.WBEnable := 1 shl EnsureRange(FWidebandADC, 0, 7)
|
||||
else
|
||||
B.WBEnable := 0;
|
||||
B.WBSamplesPerPkt[0] := (FWBSamplesPerPacket shr 8) and $FF;
|
||||
B.WBSamplesPerPkt[1] := FWBSamplesPerPacket and $FF;
|
||||
B.WBSampleSize := FWBSampleBits;
|
||||
B.WBUpdateRate := FWBUpdateRateMS;
|
||||
B.WBPacketsPerFrame := FWBPacketsPerFrame;
|
||||
PackSeqBytes(B.Seq, NextSeq(FSeqGeneral));
|
||||
DoSendTo(FSocket, B, SizeOf(B), FDevice.IPAddress, PORT_COMMAND);
|
||||
end;
|
||||
|
||||
procedure THPSDRNetwork.ConfigureWideband(ADCIndex: Integer; Enabled: Boolean;
|
||||
SamplesPerPacket: Integer; SampleBits: Integer; UpdateRateMS: Integer;
|
||||
PacketsPerFrame: Integer);
|
||||
var
|
||||
Gen: TGeneralPacket;
|
||||
begin
|
||||
FWidebandADC := EnsureRange(ADCIndex, 0, 7);
|
||||
FWidebandEnabled := Enabled;
|
||||
FWBSamplesPerPacket := EnsureRange(SamplesPerPacket, 1, 4096);
|
||||
FWBSampleBits := EnsureRange(SampleBits, 1, 32);
|
||||
FWBUpdateRateMS := EnsureRange(UpdateRateMS, 0, 255);
|
||||
FWBPacketsPerFrame := EnsureRange(PacketsPerFrame, 1, 255);
|
||||
FWBFrameCount := 0;
|
||||
FWBSeqValid := False;
|
||||
if FConnected then
|
||||
begin
|
||||
FillChar(Gen, SizeOf(Gen), 0);
|
||||
Gen.Command := CMD_GENERAL;
|
||||
Gen.Flags37 := $08;
|
||||
Gen.Flags38 := $01;
|
||||
Gen.PAConfig := $01;
|
||||
if FDevice.BoardType = BOARD_ORION_MK2 then
|
||||
Gen.AlexEnable := $03
|
||||
else
|
||||
Gen.AlexEnable := $01;
|
||||
SendGeneralPacket(Gen);
|
||||
SendFullHP;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure THPSDRNetwork.SendDDCSpecific(const Pkt: TDDCSpecificPacket);
|
||||
var
|
||||
B: TDDCSpecificPacket;
|
||||
@@ -1078,12 +1198,16 @@ end;
|
||||
// XVTR без усиления.
|
||||
// XvtrActive — True когда активен XVTR-диапазон; разрешает биты 8+11
|
||||
// (стандарт) или 8+14 (Orion2) из Alex.RxOnly[IF_band]=3.
|
||||
// WidebandBypass — True когда открыт raw ADC wideband. Как Thetis, раскрываем
|
||||
// RX front-end через HF bypass, иначе видна только полоса
|
||||
// текущего HPF/BPF, а не весь ADC span.
|
||||
function CalcAlex0(RXFreqHz, TXFreqHz: Double;
|
||||
Transmitting, IsOrion2: Boolean;
|
||||
const Alex: TAlexSettings;
|
||||
XvtrRxAnt: Byte = 0;
|
||||
XvtrDisablePA: Boolean = False;
|
||||
XvtrActive: Boolean = False): LongWord;
|
||||
XvtrActive: Boolean = False;
|
||||
WidebandBypass: Boolean = False): LongWord;
|
||||
var
|
||||
txf: Double;
|
||||
BandIdx: Integer;
|
||||
@@ -1100,7 +1224,9 @@ begin
|
||||
Result := Result or $08000000; // bit 27: T/R relay
|
||||
|
||||
// HPF (ANAN-100/200) или BPF (ANAN-7000/8000/Saturn/G2) — по RX-частоте.
|
||||
if IsOrion2 then
|
||||
if WidebandBypass and (not Transmitting) then
|
||||
Result := Result or $00001000 // bit 12: HF/front-end bypass for WB
|
||||
else if IsOrion2 then
|
||||
begin
|
||||
// Band-pass filters — Orion MkII 5.2, ANAN-7000DLE, Saturn, ANAN-G2
|
||||
if RXFreqHz < 1500000 then Result := Result or $00001000 // bit 12: HF Bypass
|
||||
@@ -1402,7 +1528,7 @@ begin
|
||||
Alex0 := CalcAlex0(FCurrentRXFreq, FCurrentTXFreq,
|
||||
FIsTransmitting, IsOrion2, FAlexConfig,
|
||||
FXvtrRxAntOverride, FXvtrDisablePA,
|
||||
FXvtrEnable);
|
||||
FXvtrEnable, FWidebandEnabled);
|
||||
Buf[1432] := (Alex0 shr 24) and $FF;
|
||||
Buf[1433] := (Alex0 shr 16) and $FF;
|
||||
Buf[1434] := (Alex0 shr 8) and $FF;
|
||||
|
||||
Reference in New Issue
Block a user