diff --git a/HPSDRNetwork.pas b/HPSDRNetwork.pas index 1a4c234..418f3e7 100644 --- a/HPSDRNetwork.pas +++ b/HPSDRNetwork.pas @@ -139,6 +139,7 @@ type FCurrentTXFreq: Double; FCurrentDrive: Byte; FIsTransmitting: Boolean; + FPTTActive: Boolean; // фактический PTT в HP-пакете (отдельно от Alex T/R) FPAEnabled: Boolean; FAlexEnabled: Boolean; FAlexConfig: TAlexSettings; // per-band antenna + routing config @@ -215,6 +216,9 @@ type procedure SetXvtrMode(AEnable, AUseRxDDCIn, ADisablePA: Boolean; ARxAnt: Byte); procedure SendFullHP; + // Отдельная отправка PTT: переключает реле (bit27) и drive ДО, потом PTT. + // Не меняет FIsTransmitting — вызывать после UpdateState+SendFullHP. + procedure SendPTT(Active: Boolean); procedure SendDDCAudio(const LeftRight: array of SmallInt); procedure SendDUCIQ(const IData, QData: array of Integer); procedure ClearDUCIQQueue; @@ -946,13 +950,14 @@ begin FSocket := DoCreateSocket; if FSocket = SOCK_INVALID then Exit; - FConnected := True; - FSeqGeneral := 0; - FSeqDDCSpec := 0; - FSeqDUCSpec := 0; - FSeqHP := 0; - FSeqAudio := 0; - FSeqDUCIQ := 0; + FConnected := True; + FPTTActive := False; + FSeqGeneral := 0; + FSeqDDCSpec := 0; + FSeqDUCSpec := 0; + FSeqHP := 0; + FSeqAudio := 0; + FSeqDUCIQ := 0; ResetDUCIQQueue; StartThreads; @@ -970,6 +975,7 @@ begin StopThreads; DoCloseSocket(FSocket); FConnected := False; + FPTTActive := False; FDevice.Valid := False; FCachedDDCValid := False; FCachedDUCValid := False; @@ -1365,7 +1371,7 @@ begin if FRunning then begin 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; // DDC base: ORION/ORION2/ANGELIA/SATURN начинают с DDC2 @@ -1424,6 +1430,9 @@ end; procedure THPSDRNetwork.SetRunAndFreq(Run: Boolean; DDC0FreqHz, DUCFreqHz: Double; DriveLevel: Byte); begin + // При Run=1 аппаратура сбрасывает счётчик HP-последовательности. + // Синхронизируем свой счётчик чтобы не получить SEQ ERROR на первом пакете. + if Run then FSeqHP := 0; FRunning := Run; FCurrentRXFreq := DDC0FreqHz; FCurrentTXFreq := DUCFreqHz; @@ -1431,6 +1440,12 @@ begin SendFullHP; end; +procedure THPSDRNetwork.SendPTT(Active: Boolean); +begin + FPTTActive := Active; + if FConnected then SendFullHP; +end; + procedure THPSDRNetwork.SendDDCAudio(const LeftRight: array of SmallInt); var Pkt: TDDCAudioPacket; diff --git a/MainForm.pas b/MainForm.pas index 41bbfa9..5dfbdf3 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -4571,7 +4571,8 @@ begin FNetwork.ClearDUCIQQueue; FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FDriveLevel, True, True, True); - FNetwork.SendFullHP; + FNetwork.SendFullHP; // 1й пакет: Alex bit27=1 (T/R relay), drive — без PTT + FNetwork.SendPTT(True); // 2й пакет: PTT=1 после переключения реле end; if FWDSPReady then begin @@ -4615,10 +4616,11 @@ begin end; if (not FTransmitting) and FNetwork.Connected and FNetwork.Running then begin + FNetwork.SendPTT(False); // 1й пакет: PTT=0 — сначала снимаем PTT FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FDriveLevel, - FTransmitting, True, True); + False, True, True); FNetwork.ClearDUCIQQueue; - FNetwork.SendFullHP; + FNetwork.SendFullHP; // 2й пакет: Alex bit27=0 (T/R relay RX), drive=0 end; end; @@ -5632,11 +5634,9 @@ begin end; procedure TMainForm.RebuildXvtrButtons; -const - BTN_H_LOC = 24; var i, Pos, XvtrRows: Integer; - W: Integer; + W, BtnH, RowH, MaxBottom: Integer; B: TFlatButton; Cap: string; begin @@ -5648,6 +5648,21 @@ begin BtnXvtrBand[i] := nil; end; 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; Pos := 0; // позиция среди enabled слотов for i := 0 to CFG_XVTR_COUNT - 1 do @@ -5660,20 +5675,23 @@ begin B.Parent := PanelBands; B.Caption := Cap; 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.Height := BTN_H_LOC; + B.Height := BtnH; B.OnClick := BtnXvtrBandClick; B.Tag := -(i + 1); // отрицательное значение = XVTR индекс BtnXvtrBand[i] := B; StyleButton(B, i = FCurrentXvtr); Inc(Pos); end; - // Динамически подгоняем высоту PanelBands под реальное число XVTR-рядов + // Динамически подгоняем высоту PanelBands под реальное содержимое if Pos = 0 then XvtrRows := 0 else if Pos <= 6 then XvtrRows := 1 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; end;