mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Fix TX sequencing: PTT after Alex relay, SEQ error on startup
- Separate FPTTActive from FIsTransmitting so PTT bit in HP packet can be sent as a second packet after Alex bit27 (T/R relay) is set, matching Thetis behaviour: relay switches first, then PTT=1 - On TX stop: PTT=0 first, then Alex switches back to RX - Add SendPTT(Active) method to THPSDRNetwork - Reset FSeqHP to 0 in SetRunAndFreq(Run=True) to eliminate HP SEQ ERROR caused by intermediate SendFullHP calls before Run=1 packet - RebuildXvtrButtons: use dynamic BtnH/RowH/MaxBottom instead of hardcoded px values so XVTR buttons scale correctly on HiDPI Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+23
-8
@@ -139,6 +139,7 @@ type
|
|||||||
FCurrentTXFreq: Double;
|
FCurrentTXFreq: Double;
|
||||||
FCurrentDrive: Byte;
|
FCurrentDrive: Byte;
|
||||||
FIsTransmitting: Boolean;
|
FIsTransmitting: Boolean;
|
||||||
|
FPTTActive: Boolean; // фактический PTT в HP-пакете (отдельно от Alex T/R)
|
||||||
FPAEnabled: Boolean;
|
FPAEnabled: Boolean;
|
||||||
FAlexEnabled: Boolean;
|
FAlexEnabled: Boolean;
|
||||||
FAlexConfig: TAlexSettings; // per-band antenna + routing config
|
FAlexConfig: TAlexSettings; // per-band antenna + routing config
|
||||||
@@ -215,6 +216,9 @@ type
|
|||||||
procedure SetXvtrMode(AEnable, AUseRxDDCIn, ADisablePA: Boolean;
|
procedure SetXvtrMode(AEnable, AUseRxDDCIn, ADisablePA: Boolean;
|
||||||
ARxAnt: Byte);
|
ARxAnt: Byte);
|
||||||
procedure SendFullHP;
|
procedure SendFullHP;
|
||||||
|
// Отдельная отправка PTT: переключает реле (bit27) и drive ДО, потом PTT.
|
||||||
|
// Не меняет FIsTransmitting — вызывать после UpdateState+SendFullHP.
|
||||||
|
procedure SendPTT(Active: Boolean);
|
||||||
procedure SendDDCAudio(const LeftRight: array of SmallInt);
|
procedure SendDDCAudio(const LeftRight: array of SmallInt);
|
||||||
procedure SendDUCIQ(const IData, QData: array of Integer);
|
procedure SendDUCIQ(const IData, QData: array of Integer);
|
||||||
procedure ClearDUCIQQueue;
|
procedure ClearDUCIQQueue;
|
||||||
@@ -946,13 +950,14 @@ begin
|
|||||||
FSocket := DoCreateSocket;
|
FSocket := DoCreateSocket;
|
||||||
if FSocket = SOCK_INVALID then Exit;
|
if FSocket = SOCK_INVALID then Exit;
|
||||||
|
|
||||||
FConnected := True;
|
FConnected := True;
|
||||||
FSeqGeneral := 0;
|
FPTTActive := False;
|
||||||
FSeqDDCSpec := 0;
|
FSeqGeneral := 0;
|
||||||
FSeqDUCSpec := 0;
|
FSeqDDCSpec := 0;
|
||||||
FSeqHP := 0;
|
FSeqDUCSpec := 0;
|
||||||
FSeqAudio := 0;
|
FSeqHP := 0;
|
||||||
FSeqDUCIQ := 0;
|
FSeqAudio := 0;
|
||||||
|
FSeqDUCIQ := 0;
|
||||||
ResetDUCIQQueue;
|
ResetDUCIQQueue;
|
||||||
|
|
||||||
StartThreads;
|
StartThreads;
|
||||||
@@ -970,6 +975,7 @@ begin
|
|||||||
StopThreads;
|
StopThreads;
|
||||||
DoCloseSocket(FSocket);
|
DoCloseSocket(FSocket);
|
||||||
FConnected := False;
|
FConnected := False;
|
||||||
|
FPTTActive := False;
|
||||||
FDevice.Valid := False;
|
FDevice.Valid := False;
|
||||||
FCachedDDCValid := False;
|
FCachedDDCValid := False;
|
||||||
FCachedDUCValid := False;
|
FCachedDUCValid := False;
|
||||||
@@ -1365,7 +1371,7 @@ begin
|
|||||||
if FRunning then
|
if FRunning then
|
||||||
begin
|
begin
|
||||||
Buf[4] := HP_RUN;
|
Buf[4] := HP_RUN;
|
||||||
if FIsTransmitting then Buf[4] := Buf[4] or HP_PTT0;
|
if FPTTActive then Buf[4] := Buf[4] or HP_PTT0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// DDC base: ORION/ORION2/ANGELIA/SATURN начинают с DDC2
|
// DDC base: ORION/ORION2/ANGELIA/SATURN начинают с DDC2
|
||||||
@@ -1424,6 +1430,9 @@ end;
|
|||||||
procedure THPSDRNetwork.SetRunAndFreq(Run: Boolean; DDC0FreqHz, DUCFreqHz: Double;
|
procedure THPSDRNetwork.SetRunAndFreq(Run: Boolean; DDC0FreqHz, DUCFreqHz: Double;
|
||||||
DriveLevel: Byte);
|
DriveLevel: Byte);
|
||||||
begin
|
begin
|
||||||
|
// При Run=1 аппаратура сбрасывает счётчик HP-последовательности.
|
||||||
|
// Синхронизируем свой счётчик чтобы не получить SEQ ERROR на первом пакете.
|
||||||
|
if Run then FSeqHP := 0;
|
||||||
FRunning := Run;
|
FRunning := Run;
|
||||||
FCurrentRXFreq := DDC0FreqHz;
|
FCurrentRXFreq := DDC0FreqHz;
|
||||||
FCurrentTXFreq := DUCFreqHz;
|
FCurrentTXFreq := DUCFreqHz;
|
||||||
@@ -1431,6 +1440,12 @@ begin
|
|||||||
SendFullHP;
|
SendFullHP;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure THPSDRNetwork.SendPTT(Active: Boolean);
|
||||||
|
begin
|
||||||
|
FPTTActive := Active;
|
||||||
|
if FConnected then SendFullHP;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure THPSDRNetwork.SendDDCAudio(const LeftRight: array of SmallInt);
|
procedure THPSDRNetwork.SendDDCAudio(const LeftRight: array of SmallInt);
|
||||||
var
|
var
|
||||||
Pkt: TDDCAudioPacket;
|
Pkt: TDDCAudioPacket;
|
||||||
|
|||||||
+28
-10
@@ -4571,7 +4571,8 @@ begin
|
|||||||
FNetwork.ClearDUCIQQueue;
|
FNetwork.ClearDUCIQQueue;
|
||||||
FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FDriveLevel,
|
FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FDriveLevel,
|
||||||
True, True, True);
|
True, True, True);
|
||||||
FNetwork.SendFullHP;
|
FNetwork.SendFullHP; // 1й пакет: Alex bit27=1 (T/R relay), drive — без PTT
|
||||||
|
FNetwork.SendPTT(True); // 2й пакет: PTT=1 после переключения реле
|
||||||
end;
|
end;
|
||||||
if FWDSPReady then
|
if FWDSPReady then
|
||||||
begin
|
begin
|
||||||
@@ -4615,10 +4616,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
if (not FTransmitting) and FNetwork.Connected and FNetwork.Running then
|
if (not FTransmitting) and FNetwork.Connected and FNetwork.Running then
|
||||||
begin
|
begin
|
||||||
|
FNetwork.SendPTT(False); // 1й пакет: PTT=0 — сначала снимаем PTT
|
||||||
FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FDriveLevel,
|
FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FDriveLevel,
|
||||||
FTransmitting, True, True);
|
False, True, True);
|
||||||
FNetwork.ClearDUCIQQueue;
|
FNetwork.ClearDUCIQQueue;
|
||||||
FNetwork.SendFullHP;
|
FNetwork.SendFullHP; // 2й пакет: Alex bit27=0 (T/R relay RX), drive=0
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -5632,11 +5634,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.RebuildXvtrButtons;
|
procedure TMainForm.RebuildXvtrButtons;
|
||||||
const
|
|
||||||
BTN_H_LOC = 24;
|
|
||||||
var
|
var
|
||||||
i, Pos, XvtrRows: Integer;
|
i, Pos, XvtrRows: Integer;
|
||||||
W: Integer;
|
W, BtnH, RowH, MaxBottom: Integer;
|
||||||
B: TFlatButton;
|
B: TFlatButton;
|
||||||
Cap: string;
|
Cap: string;
|
||||||
begin
|
begin
|
||||||
@@ -5648,6 +5648,21 @@ begin
|
|||||||
BtnXvtrBand[i] := nil;
|
BtnXvtrBand[i] := nil;
|
||||||
end;
|
end;
|
||||||
if PanelBands = nil then Exit;
|
if PanelBands = nil then Exit;
|
||||||
|
|
||||||
|
// Измеряем фактический bottom последнего ряда обычных кнопок BAND
|
||||||
|
// (уже отмасштабированы LCL при показе формы)
|
||||||
|
MaxBottom := 0;
|
||||||
|
BtnH := 0;
|
||||||
|
for i := 0 to BAND_COUNT - 1 do
|
||||||
|
if BtnBand[i] <> nil then
|
||||||
|
begin
|
||||||
|
if BtnBand[i].Top + BtnBand[i].Height > MaxBottom then
|
||||||
|
MaxBottom := BtnBand[i].Top + BtnBand[i].Height;
|
||||||
|
BtnH := BtnBand[i].Height;
|
||||||
|
end;
|
||||||
|
if BtnH = 0 then BtnH := MulDiv(24, Screen.PixelsPerInch, 96);
|
||||||
|
RowH := BtnH + 3; // шаг ряда: высота кнопки + 3px зазор (как 27=24+3 при 1x)
|
||||||
|
|
||||||
W := (PanelBands.Width - 6) div 6;
|
W := (PanelBands.Width - 6) div 6;
|
||||||
Pos := 0; // позиция среди enabled слотов
|
Pos := 0; // позиция среди enabled слотов
|
||||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||||
@@ -5660,20 +5675,23 @@ begin
|
|||||||
B.Parent := PanelBands;
|
B.Parent := PanelBands;
|
||||||
B.Caption := Cap;
|
B.Caption := Cap;
|
||||||
B.Left := 2 + (Pos mod 6) * W;
|
B.Left := 2 + (Pos mod 6) * W;
|
||||||
B.Top := 16 + (2 + (Pos div 6)) * 27;
|
B.Top := MaxBottom + 4 + (Pos div 6) * RowH;
|
||||||
B.Width := W - 2;
|
B.Width := W - 2;
|
||||||
B.Height := BTN_H_LOC;
|
B.Height := BtnH;
|
||||||
B.OnClick := BtnXvtrBandClick;
|
B.OnClick := BtnXvtrBandClick;
|
||||||
B.Tag := -(i + 1); // отрицательное значение = XVTR индекс
|
B.Tag := -(i + 1); // отрицательное значение = XVTR индекс
|
||||||
BtnXvtrBand[i] := B;
|
BtnXvtrBand[i] := B;
|
||||||
StyleButton(B, i = FCurrentXvtr);
|
StyleButton(B, i = FCurrentXvtr);
|
||||||
Inc(Pos);
|
Inc(Pos);
|
||||||
end;
|
end;
|
||||||
// Динамически подгоняем высоту PanelBands под реальное число XVTR-рядов
|
// Динамически подгоняем высоту PanelBands под реальное содержимое
|
||||||
if Pos = 0 then XvtrRows := 0
|
if Pos = 0 then XvtrRows := 0
|
||||||
else if Pos <= 6 then XvtrRows := 1
|
else if Pos <= 6 then XvtrRows := 1
|
||||||
else XvtrRows := 2;
|
else XvtrRows := 2;
|
||||||
PanelBands.Height := 74 + XvtrRows * 27;
|
if XvtrRows = 0 then
|
||||||
|
PanelBands.Height := MaxBottom + 6
|
||||||
|
else
|
||||||
|
PanelBands.Height := MaxBottom + 4 + XvtrRows * RowH + 6;
|
||||||
RelayoutBelowBands;
|
RelayoutBelowBands;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user