mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Improve radio status bar
This commit is contained in:
+243
-101
@@ -241,6 +241,12 @@ type
|
||||
FActiveDDC: Integer; // DDC index для текущей платы (0 или 2)
|
||||
FLastDDCSeq: LongWord; // последний seq (пишется из сетевого потока)
|
||||
FLastDDCIndex: Integer; // последний DDC index
|
||||
FDDCLastSeq: array[0..6] of LongWord;
|
||||
FDDCSeqValid: array[0..6] of Boolean;
|
||||
FSeqErrorCount: LongWord;
|
||||
FLastSeqErrorDDC: Integer;
|
||||
FLastSeqErrorDelta: Int64;
|
||||
FSeqOkStreak: Integer;
|
||||
FLastFwdW: Double;
|
||||
FLastSWR: Double;
|
||||
// Эти значения приходят с HP Status пакетами (50..200 раз/с). UI обновляется
|
||||
@@ -427,7 +433,9 @@ type
|
||||
PbWaterfall: TPaintBox;
|
||||
|
||||
// ---- Status bar ----
|
||||
StatusBar1: TStatusBar;
|
||||
StatusPanel: TPanel;
|
||||
StatusCells: array[0..7] of TPanel;
|
||||
StatusLabels: array[0..7] of TLabel;
|
||||
|
||||
// ---- Helpers ----
|
||||
procedure BuildUI;
|
||||
@@ -435,6 +443,9 @@ type
|
||||
procedure SetLightTheme(V: Boolean);
|
||||
procedure StyleButton(B: TFlatButton; Active: Boolean = False);
|
||||
procedure StyleSpanButton(B: TFlatButton; Active: Boolean = False);
|
||||
procedure SetStatusText(Index: Integer; const Text: string);
|
||||
procedure SetRadioOfflineStatus(const ConnText: string; ClearDevice: Boolean = False);
|
||||
procedure ApplyStatusTheme(const T: TAppTheme);
|
||||
procedure PositionSpanOverlayButtons;
|
||||
procedure UpdateVfoDisplay;
|
||||
function FormatFreq(Hz: Double): string;
|
||||
@@ -1299,6 +1310,12 @@ begin
|
||||
FActiveDDC := 0;
|
||||
FLastDDCSeq := 0;
|
||||
FLastDDCIndex := 0;
|
||||
FillChar(FDDCLastSeq, SizeOf(FDDCLastSeq), 0);
|
||||
FillChar(FDDCSeqValid, SizeOf(FDDCSeqValid), 0);
|
||||
FSeqErrorCount := 0;
|
||||
FLastSeqErrorDDC := -1;
|
||||
FLastSeqErrorDelta:= 0;
|
||||
FSeqOkStreak := 0;
|
||||
FLastFwdW := 0;
|
||||
FLastSWR := 1;
|
||||
FLastSupplyV:= -1;
|
||||
@@ -1507,6 +1524,30 @@ var
|
||||
L.Font.Size := 7;
|
||||
end;
|
||||
|
||||
procedure MakeStatusCell(Index, CellWidth: Integer; const Cap: string);
|
||||
begin
|
||||
StatusCells[Index] := TPanel.Create(Self);
|
||||
StatusCells[Index].Parent := StatusPanel;
|
||||
StatusCells[Index].BevelOuter := bvNone;
|
||||
StatusCells[Index].Align := alLeft;
|
||||
StatusCells[Index].Width := CellWidth;
|
||||
StatusCells[Index].BorderSpacing.Left := 1;
|
||||
StatusCells[Index].BorderSpacing.Top := 1;
|
||||
StatusCells[Index].BorderSpacing.Bottom := 1;
|
||||
|
||||
StatusLabels[Index] := TLabel.Create(Self);
|
||||
StatusLabels[Index].Parent := StatusCells[Index];
|
||||
StatusLabels[Index].AutoSize := False;
|
||||
StatusLabels[Index].Align := alClient;
|
||||
StatusLabels[Index].BorderSpacing.Left := 8;
|
||||
StatusLabels[Index].BorderSpacing.Right := 8;
|
||||
StatusLabels[Index].Alignment := taLeftJustify;
|
||||
StatusLabels[Index].Layout := tlCenter;
|
||||
StatusLabels[Index].Caption := Cap;
|
||||
StatusLabels[Index].Font.Name := 'Courier New';
|
||||
StatusLabels[Index].Font.Size := 8;
|
||||
end;
|
||||
|
||||
begin
|
||||
// ---- Toolbar ----
|
||||
PanelToolbar := TPanel.Create(Self);
|
||||
@@ -1537,19 +1578,23 @@ begin
|
||||
// ---- Separator line ----
|
||||
|
||||
// ---- Status bar ----
|
||||
StatusBar1 := TStatusBar.Create(Self);
|
||||
StatusBar1.Parent := Self;
|
||||
StatusBar1.Align := alBottom;
|
||||
StatusBar1.SimplePanel := False;
|
||||
with StatusBar1.Panels do
|
||||
begin
|
||||
Add; Items[0].Width := 150; Items[0].Text := 'IP: --';
|
||||
Add; Items[1].Width := 120; Items[1].Text := 'Board: --';
|
||||
Add; Items[2].Width := 200; Items[2].Text := 'Supply: --';
|
||||
Add; Items[3].Width := 250; Items[3].Text := 'RX: waiting...';
|
||||
Add; Items[4].Width := 200; Items[4].Text := 'Not connected';
|
||||
Add; Items[5].Width := 280; Items[5].Text := 'TX: --';
|
||||
end;
|
||||
StatusPanel := TPanel.Create(Self);
|
||||
StatusPanel.Parent := Self;
|
||||
StatusPanel.Align := alBottom;
|
||||
StatusPanel.Height := 26;
|
||||
StatusPanel.BevelOuter := bvNone;
|
||||
|
||||
// alLeft controls are arranged by Z-order in LCL; create them in reverse
|
||||
// visual order so the final bar reads left-to-right as intended.
|
||||
MakeStatusCell(6, 130, 'SEQ --');
|
||||
MakeStatusCell(5, 180, 'TX idle');
|
||||
MakeStatusCell(4, 190, 'RX idle');
|
||||
MakeStatusCell(7, 90, 'PLL --');
|
||||
MakeStatusCell(3, 150, 'Supply --');
|
||||
MakeStatusCell(1, 120, 'IP --');
|
||||
MakeStatusCell(0, 220, 'Board --');
|
||||
MakeStatusCell(2, 170, 'Disconnected');
|
||||
StatusCells[6].Align := alClient;
|
||||
|
||||
// ---- Left panel ----
|
||||
PanelLeft := TPanel.Create(Self);
|
||||
@@ -2493,6 +2538,7 @@ begin
|
||||
PbWaterfall.Color := T.BG;
|
||||
if PanelSMeterRight <> nil then PanelSMeterRight.Color := T.Panel;
|
||||
if PbSMeterRight <> nil then PbSMeterRight.Color := T.Panel;
|
||||
ApplyStatusTheme(T);
|
||||
|
||||
// Метки
|
||||
DL(LblAGCTop, False);
|
||||
@@ -2555,6 +2601,62 @@ begin
|
||||
UpdateVfoDisplay;
|
||||
end;
|
||||
|
||||
procedure TMainForm.SetStatusText(Index: Integer; const Text: string);
|
||||
begin
|
||||
if (Index < Low(StatusLabels)) or (Index > High(StatusLabels)) then Exit;
|
||||
if StatusLabels[Index] = nil then Exit;
|
||||
if StatusLabels[Index].Caption <> Text then
|
||||
StatusLabels[Index].Caption := Text;
|
||||
end;
|
||||
|
||||
procedure TMainForm.SetRadioOfflineStatus(const ConnText: string; ClearDevice: Boolean);
|
||||
begin
|
||||
SetStatusText(2, ConnText);
|
||||
SetStatusText(3, 'Supply --');
|
||||
SetStatusText(4, 'RX idle');
|
||||
SetStatusText(5, 'TX idle');
|
||||
SetStatusText(6, 'SEQ --');
|
||||
SetStatusText(7, 'PLL --');
|
||||
FillChar(FDDCSeqValid, SizeOf(FDDCSeqValid), 0);
|
||||
FSeqErrorCount := 0;
|
||||
FLastSeqErrorDDC := -1;
|
||||
FLastSeqErrorDelta := 0;
|
||||
FSeqOkStreak := 0;
|
||||
if ClearDevice then
|
||||
begin
|
||||
SetStatusText(0, 'Board --');
|
||||
SetStatusText(1, 'IP --');
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyStatusTheme(const T: TAppTheme);
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
if StatusPanel = nil then Exit;
|
||||
StatusPanel.Color := T.Border;
|
||||
for I := Low(StatusCells) to High(StatusCells) do
|
||||
begin
|
||||
if StatusCells[I] <> nil then
|
||||
begin
|
||||
StatusCells[I].Color := T.Panel;
|
||||
StatusCells[I].Font.Color := T.Text;
|
||||
end;
|
||||
if StatusLabels[I] <> nil then
|
||||
begin
|
||||
if I in [4, 5] then
|
||||
StatusLabels[I].Font.Color := T.TextDim
|
||||
else if I = 6 then
|
||||
StatusLabels[I].Font.Color := T.Amber
|
||||
else if I = 2 then
|
||||
StatusLabels[I].Font.Color := T.TbStartText
|
||||
else
|
||||
StatusLabels[I].Font.Color := T.Text;
|
||||
StatusLabels[I].Color := T.Panel;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.SetLightTheme(V: Boolean);
|
||||
begin
|
||||
if FLightTheme = V then Exit;
|
||||
@@ -2878,22 +2980,17 @@ begin
|
||||
// HP Status пакеты идут ~150 раз/с, при таком rate цифры дёргаются.
|
||||
UpdateTXMeters;
|
||||
|
||||
// Диагностика TX mic-пути — в отдельной панели [5], чтобы её не перетирали
|
||||
// другие источники (DDC seq, audio-логи и т.п.).
|
||||
if FWDSPReady then
|
||||
begin
|
||||
if FTransmitting then
|
||||
begin
|
||||
if FDSPEngine.TXMicSource = txmsSoundCard then
|
||||
StatusBar1.Panels[5].Text :=
|
||||
Format('TX sc: avail=%d ring=%d',
|
||||
[FAudioIn.Available, FDSPEngine.TXMicRingAvail])
|
||||
SetStatusText(5, 'TX sound card')
|
||||
else
|
||||
StatusBar1.Panels[5].Text :=
|
||||
Format('TX hw: ring=%d', [FDSPEngine.TXMicRingAvail]);
|
||||
SetStatusText(5, 'TX radio mic');
|
||||
end
|
||||
else
|
||||
StatusBar1.Panels[5].Text := 'TX: idle';
|
||||
SetStatusText(5, 'TX idle');
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -2929,7 +3026,7 @@ begin
|
||||
StyleButton(BtnStartStop, False);
|
||||
FRunning := False;
|
||||
FNetwork.SetRunAndFreq(False, XvtrTranslate(FCenterFreq), XvtrTranslate(FCenterFreq), 0);
|
||||
StatusBar1.Panels[4].Text := 'ТРАНСИВЕР НЕДОСТУПЕН';
|
||||
SetRadioOfflineStatus('Hardware timeout');
|
||||
BtnMOX.Enabled := False;
|
||||
Exit;
|
||||
end;
|
||||
@@ -2940,7 +3037,7 @@ begin
|
||||
StyleButton(BtnStartStop, False);
|
||||
FRunning := False;
|
||||
FNetwork.SetRunAndFreq(False, XvtrTranslate(FCenterFreq), XvtrTranslate(FCenterFreq), 0);
|
||||
StatusBar1.Panels[4].Text := 'ПОТЕРЯ СВЯЗИ С ТРАНСИВЕРОМ';
|
||||
SetRadioOfflineStatus('Connection lost');
|
||||
BtnMOX.Enabled := False;
|
||||
Exit;
|
||||
end;
|
||||
@@ -2948,10 +3045,12 @@ begin
|
||||
|
||||
if FRunning then
|
||||
begin
|
||||
// Обновляем StatusBar из таймера — без Synchronize в сетевом потоке
|
||||
StatusBar1.Panels[3].Text :=
|
||||
Format('RX DDC%d | seq=%d | pkts=%d',
|
||||
[FLastDDCIndex, FLastDDCSeq, FRXPacketCount]);
|
||||
// Обновляем статус из таймера — без Synchronize в сетевом потоке.
|
||||
SetStatusText(4, 'RX running');
|
||||
if FSeqErrorCount > 0 then
|
||||
SetStatusText(6, Format('SEQ ERR DDC%d', [FLastSeqErrorDDC]))
|
||||
else
|
||||
SetStatusText(6, 'SEQ OK');
|
||||
|
||||
if FWDSPReady then
|
||||
begin
|
||||
@@ -3082,7 +3181,7 @@ begin
|
||||
if Assigned(FDeviceDialog) then
|
||||
FDeviceDialog.AddDiscovered(Dev.IPAddress, Entry, Dev.BoardType);
|
||||
|
||||
StatusBar1.Panels[4].Text := Format('Found: %s', [Dev.IPAddress]);
|
||||
SetStatusText(2, Format('Found: %s', [Dev.IPAddress]));
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnHPStatusCB(const Status: THighPriorityStatus);
|
||||
@@ -3101,22 +3200,27 @@ begin
|
||||
ExcPwr := (Status.ExciterPwr0Hi shl 8) or Status.ExciterPwr0Lo;
|
||||
FwdPwr := (Status.FwdPwrAlex0Hi shl 8) or Status.FwdPwrAlex0Lo;
|
||||
RevPwr := (Status.RevPwrAlex0Hi shl 8) or Status.RevPwrAlex0Lo;
|
||||
SupplyV := -1.0;
|
||||
SupplyA := -1.0;
|
||||
|
||||
// Board 5 (Orion MkII): voltage on UserADC0 (bytes 57-58),
|
||||
// current on UserADC1 (bytes 55-56) — matching Thetis behaviour.
|
||||
if FNetwork.Device.BoardType = 5 then
|
||||
// Other supported boards report voltage in SupplyVolts bytes and no current.
|
||||
if BoardSupportsSupplyVoltage(FNetwork.Device.BoardType) then
|
||||
begin
|
||||
SupplyV := ADCToSupplyVolts(
|
||||
(Status.UserADC0Hi shl 8) or Status.UserADC0Lo,
|
||||
FNetwork.Device.BoardType);
|
||||
SupplyA := ADCToSupplyCurrent(
|
||||
(Status.UserADC1Hi shl 8) or Status.UserADC1Lo,
|
||||
FNetwork.Device.BoardType);
|
||||
end else
|
||||
begin
|
||||
SupplyV := ADCToSupplyVolts(
|
||||
(Status.SupplyVoltsHi shl 8) or Status.SupplyVoltsLo,
|
||||
FNetwork.Device.BoardType);
|
||||
SupplyA := -1.0;
|
||||
if FNetwork.Device.BoardType = 5 then
|
||||
SupplyV := ADCToSupplyVolts(
|
||||
(Status.UserADC0Hi shl 8) or Status.UserADC0Lo,
|
||||
FNetwork.Device.BoardType)
|
||||
else
|
||||
SupplyV := ADCToSupplyVolts(
|
||||
(Status.SupplyVoltsHi shl 8) or Status.SupplyVoltsLo,
|
||||
FNetwork.Device.BoardType);
|
||||
|
||||
if BoardSupportsSupplyCurrent(FNetwork.Device.BoardType) then
|
||||
SupplyA := ADCToSupplyCurrent(
|
||||
(Status.UserADC1Hi shl 8) or Status.UserADC1Lo,
|
||||
FNetwork.Device.BoardType);
|
||||
end;
|
||||
// FLastSMeter обновляется только из WDSP (GetSMeterDBm) в SpectrumTimerTick —
|
||||
// ExciterPwr это мощность TX, не уровень принятого сигнала.
|
||||
@@ -3188,14 +3292,17 @@ begin
|
||||
FLastSupplyV := SupplyV // первое значение — без сглаживания
|
||||
else
|
||||
FLastSupplyV := ALPHA_SUPPLY * SupplyV + (1.0 - ALPHA_SUPPLY) * FLastSupplyV;
|
||||
end;
|
||||
end else
|
||||
FLastSupplyV := -1.0;
|
||||
|
||||
if SupplyA >= 0 then
|
||||
begin
|
||||
if FLastSupplyA < 0 then
|
||||
FLastSupplyA := SupplyA
|
||||
else
|
||||
FLastSupplyA := ALPHA_SUPPLY * SupplyA + (1.0 - ALPHA_SUPPLY) * FLastSupplyA;
|
||||
end;
|
||||
end else
|
||||
FLastSupplyA := -1.0;
|
||||
FLastPLLLock := PLLLock;
|
||||
|
||||
// Hardware PTT (foot switch / mic PTT) — обнаружение фронта (нужно делать
|
||||
@@ -3229,33 +3336,84 @@ end;
|
||||
|
||||
procedure TMainForm.UpdateTXMeters;
|
||||
// Вызывается из MeterTimerTick (10 Гц). Использует FLastFwdW/FLastSWR/
|
||||
// FLastSupplyV/FLastPLLLock — они обновляются на rate HP Status (~150/с)
|
||||
// FLastSupplyV/FLastSupplyA обновляются на rate HP Status (~150/с)
|
||||
// в DoUpdateStatus.
|
||||
var
|
||||
PLLStr: string;
|
||||
begin
|
||||
if FLastPLLLock then PLLStr := 'PLL OK' else PLLStr := 'PLL?';
|
||||
if not FRunning then
|
||||
begin
|
||||
SetStatusText(3, 'Supply --');
|
||||
SetStatusText(7, 'PLL --');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if FLastPLLLock then
|
||||
SetStatusText(7, 'PLL OK')
|
||||
else
|
||||
SetStatusText(7, 'PLL?');
|
||||
|
||||
if not BoardSupportsSupplyVoltage(FNetwork.Device.BoardType) then
|
||||
begin
|
||||
SetStatusText(3, 'Supply n/a');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if FLastSupplyV >= 0 then
|
||||
begin
|
||||
if FLastSupplyA >= 0 then
|
||||
StatusBar1.Panels[2].Text :=
|
||||
Format('Supply: %.1fV / %.1fA | %s', [FLastSupplyV, FLastSupplyA, PLLStr])
|
||||
SetStatusText(3,
|
||||
Format('Supply %.1fV %.1fA', [FLastSupplyV, FLastSupplyA]))
|
||||
else
|
||||
StatusBar1.Panels[2].Text :=
|
||||
Format('Supply: %.1fV | %s', [FLastSupplyV, PLLStr]);
|
||||
SetStatusText(3,
|
||||
Format('Supply %.1fV', [FLastSupplyV]));
|
||||
end else
|
||||
StatusBar1.Panels[2].Text := PLLStr;
|
||||
SetStatusText(3, 'Supply --');
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnDDCIQCB(DDCIndex: Integer; const Data: TDDCIQPacket);
|
||||
var
|
||||
SamplesPerFrame: Integer;
|
||||
Seq, ExpectedSeq: LongWord;
|
||||
Delta: Int64;
|
||||
begin
|
||||
// Вызывается из сетевого потока — UI не трогаем напрямую
|
||||
|
||||
// Счётчик принятых пакетов
|
||||
Inc(FRXPacketCount);
|
||||
FRXLastPktTime := GetTickCount64; // фиксируем время последнего пакета
|
||||
Seq := (LongWord(Data.Seq[0]) shl 24) or (LongWord(Data.Seq[1]) shl 16)
|
||||
or (LongWord(Data.Seq[2]) shl 8) or LongWord(Data.Seq[3]);
|
||||
|
||||
if (DDCIndex >= Low(FDDCLastSeq)) and (DDCIndex <= High(FDDCLastSeq)) then
|
||||
begin
|
||||
if Seq <> 0 then
|
||||
begin
|
||||
ExpectedSeq := FDDCLastSeq[DDCIndex] + 1;
|
||||
if FDDCSeqValid[DDCIndex] and (Seq <> ExpectedSeq) then
|
||||
begin
|
||||
Inc(FSeqErrorCount);
|
||||
FLastSeqErrorDDC := DDCIndex;
|
||||
Delta := Int64(Seq) - Int64(ExpectedSeq);
|
||||
FLastSeqErrorDelta := Delta;
|
||||
FSeqOkStreak := 0;
|
||||
end
|
||||
else if FDDCSeqValid[DDCIndex] then
|
||||
begin
|
||||
if FSeqErrorCount > 0 then
|
||||
begin
|
||||
Inc(FSeqOkStreak);
|
||||
if FSeqOkStreak >= 20 then
|
||||
begin
|
||||
FSeqErrorCount := 0;
|
||||
FLastSeqErrorDDC := -1;
|
||||
FLastSeqErrorDelta := 0;
|
||||
FSeqOkStreak := 0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
FDDCLastSeq[DDCIndex] := Seq;
|
||||
FDDCSeqValid[DDCIndex] := True;
|
||||
end;
|
||||
|
||||
// 1. Подаём IQ данные в DSP — только с активного DDC
|
||||
if (DDCIndex = FActiveDDC) and FWDSPReady then
|
||||
@@ -3266,16 +3424,14 @@ begin
|
||||
FDSPEngine.PushDDCPacket(Data.IQData, 0, SamplesPerFrame);
|
||||
end;
|
||||
|
||||
// 2. Запоминаем последний seq — StatusBar обновит таймер (без Synchronize в горячем пути)
|
||||
FLastDDCSeq := (LongWord(Data.Seq[0]) shl 24) or (LongWord(Data.Seq[1]) shl 16)
|
||||
or (LongWord(Data.Seq[2]) shl 8) or LongWord(Data.Seq[3]);
|
||||
// 2. Запоминаем последний seq — статус обновит таймер (без Synchronize в горячем пути)
|
||||
FLastDDCSeq := Seq;
|
||||
FLastDDCIndex := DDCIndex;
|
||||
end;
|
||||
|
||||
procedure TMainForm.DoUpdateDDCSeq(DDCIdx: Integer; Seq: LongWord);
|
||||
begin
|
||||
StatusBar1.Panels[3].Text :=
|
||||
Format('RX DDC%d | seq=%d | pkts=%d', [DDCIdx, Seq, FRXPacketCount]);
|
||||
SetStatusText(4, 'RX running');
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnMicPacketCB(const Data: TMicDataPacket);
|
||||
@@ -3494,15 +3650,15 @@ procedure TMainForm.DoUpdateDDCSeqOrNoDevice(DDCIdx: Integer; Seq: LongWord);
|
||||
begin
|
||||
if DDCIdx = -1 then
|
||||
begin
|
||||
if Assigned(FDeviceDialog) then
|
||||
begin
|
||||
FDeviceDialog.ClearDiscovered;
|
||||
FDeviceDialog.AddDiscovered('', '-- no device found --');
|
||||
end;
|
||||
StatusBar1.Panels[4].Text := 'No hardware found';
|
||||
end
|
||||
if Assigned(FDeviceDialog) then
|
||||
begin
|
||||
FDeviceDialog.ClearDiscovered;
|
||||
FDeviceDialog.AddDiscovered('', '-- no device found --');
|
||||
end;
|
||||
SetStatusText(2, 'No hardware found');
|
||||
end
|
||||
else
|
||||
StatusBar1.Panels[3].Text := Format('DDC%d seq=%d', [DDCIdx, Seq]);
|
||||
SetStatusText(4, 'RX running');
|
||||
end;
|
||||
|
||||
procedure TMainForm.RecreateDSPEngine(ASampleRate: Integer);
|
||||
@@ -3546,7 +3702,7 @@ begin
|
||||
end;
|
||||
|
||||
BtnStartStop.Enabled := False;
|
||||
StatusBar1.Panels[3].Text := 'Creating WDSP wisdom...';
|
||||
SetStatusText(2, 'Creating WDSP wisdom...');
|
||||
|
||||
BuildThread := TWisdomBuildThread.Create(WisdomDir);
|
||||
try
|
||||
@@ -3577,9 +3733,9 @@ begin
|
||||
end;
|
||||
|
||||
if Result then
|
||||
StatusBar1.Panels[3].Text := 'WDSP wisdom ready'
|
||||
SetStatusText(2, 'DSP ready')
|
||||
else
|
||||
StatusBar1.Panels[3].Text := 'WDSP wisdom missing';
|
||||
SetStatusText(2, 'WDSP wisdom missing');
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnDiscoverClick(Sender: TObject);
|
||||
@@ -3601,7 +3757,7 @@ procedure TMainForm.BtnDiscoverFromDialog(Sender: TObject);
|
||||
begin
|
||||
SetLength(FDevices, 0);
|
||||
FDeviceCount := 0;
|
||||
StatusBar1.Panels[4].Text := 'Discovering...';
|
||||
SetStatusText(2, 'Discovering...');
|
||||
FNetwork.DirectIP := '';
|
||||
TDiscoverThread.Create(FNetwork, Self);
|
||||
end;
|
||||
@@ -3632,7 +3788,6 @@ begin
|
||||
end;
|
||||
FRXPacketCount := 0;
|
||||
FActiveDDC := 0;
|
||||
StatusBar1.Panels[3].Text := 'RX: waiting...';
|
||||
// Сохраняем текущую частоту/настройки чтобы следующий START восстановил их
|
||||
if FDevConnected then
|
||||
begin
|
||||
@@ -3652,9 +3807,7 @@ begin
|
||||
FNetwork.Disconnect;
|
||||
BtnStartStop.Caption := 'START';
|
||||
StyleButton(BtnStartStop, False);
|
||||
StatusBar1.Panels[4].Text := 'Not connected';
|
||||
StatusBar1.Panels[0].Text := 'IP: --';
|
||||
StatusBar1.Panels[1].Text := 'Board: --';
|
||||
SetRadioOfflineStatus('Disconnected', True);
|
||||
BtnMOX.Enabled := False;
|
||||
Exit;
|
||||
end;
|
||||
@@ -3727,7 +3880,7 @@ begin
|
||||
// --- Открываем WDSP асинхронно чтобы не блокировать UI ---
|
||||
FPendingDev := Dev;
|
||||
BtnStartStop.Enabled := False;
|
||||
StatusBar1.Panels[3].Text := 'Opening WDSP...';
|
||||
SetStatusText(2, 'Opening DSP...');
|
||||
if FWDSPReady then
|
||||
// WDSP уже открыт — сразу подключаемся
|
||||
DoConnectDevice(Dev)
|
||||
@@ -3742,7 +3895,7 @@ begin
|
||||
FWDSPReady := Success;
|
||||
if not Success then
|
||||
begin
|
||||
StatusBar1.Panels[3].Text := 'WDSP open failed';
|
||||
SetStatusText(2, 'DSP failed');
|
||||
BtnStartStop.Enabled := True;
|
||||
BtnStartStop.Caption := 'START';
|
||||
StyleButton(BtnStartStop, False);
|
||||
@@ -3889,8 +4042,8 @@ begin
|
||||
and FXvtrSettings.Entries[G_Settings.LastXvtr].Enabled then
|
||||
ActivateXvtrBand(G_Settings.LastXvtr);
|
||||
|
||||
StatusBar1.Panels[0].Text := 'IP: ' + FNetwork.Device.IPAddress;
|
||||
StatusBar1.Panels[1].Text := 'Board: ' + BoardTypeName(FNetwork.Device.BoardType);
|
||||
SetStatusText(1, 'IP: ' + FNetwork.Device.IPAddress);
|
||||
SetStatusText(0, 'Board: ' + BoardTypeName(FNetwork.Device.BoardType));
|
||||
|
||||
// General packet
|
||||
FillChar(GenPkt, SizeOf(GenPkt), 0);
|
||||
@@ -3937,6 +4090,13 @@ begin
|
||||
FRunning := True;
|
||||
FRXStartTime := GetTickCount64;
|
||||
FRXLastPktTime := 0;
|
||||
FRXPacketCount := 0;
|
||||
FillChar(FDDCSeqValid, SizeOf(FDDCSeqValid), 0);
|
||||
FSeqErrorCount := 0;
|
||||
FLastSeqErrorDDC := -1;
|
||||
FLastSeqErrorDelta := 0;
|
||||
FSeqOkStreak := 0;
|
||||
SetStatusText(6, 'SEQ OK');
|
||||
|
||||
// DDC и DUC Specific — теперь потоки эмулятора слушают на своих портах.
|
||||
// DUC Specific содержит mic-конфигурацию (boost/bias/line/PTT) из FTXSettings.
|
||||
@@ -3952,7 +4112,7 @@ begin
|
||||
|
||||
BtnStartStop.Caption := 'STOP';
|
||||
StyleButton(BtnStartStop, True);
|
||||
StatusBar1.Panels[4].Text := 'RUNNING';
|
||||
SetStatusText(2, 'Running');
|
||||
BtnMOX.Enabled := True;
|
||||
end;
|
||||
|
||||
@@ -6678,13 +6838,8 @@ begin
|
||||
FAudioOut.DeviceIndex := DevIndex;
|
||||
FAudioOutDevName := DevName;
|
||||
try
|
||||
if not FAudioOut.Open then
|
||||
StatusBar1.Panels[3].Text := 'Audio out: ' + FAudioOut.LastError
|
||||
else
|
||||
StatusBar1.Panels[3].Text := 'Audio out: ' + IfThen(DevName = '', 'Default', DevName);
|
||||
FAudioOut.Open;
|
||||
except
|
||||
on E: Exception do
|
||||
StatusBar1.Panels[3].Text := 'Audio out err: ' + E.Message;
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -6697,17 +6852,10 @@ begin
|
||||
if DevIndex >= 0 then
|
||||
begin
|
||||
try
|
||||
if not FAudioIn.Open then
|
||||
StatusBar1.Panels[3].Text := 'Mic: ' + FAudioIn.LastError
|
||||
else
|
||||
StatusBar1.Panels[3].Text := 'Mic: ' + DevName;
|
||||
FAudioIn.Open;
|
||||
except
|
||||
on E: Exception do
|
||||
StatusBar1.Panels[3].Text := 'Mic err: ' + E.Message;
|
||||
end;
|
||||
end
|
||||
else
|
||||
StatusBar1.Panels[3].Text := 'Mic: none';
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyVisibility(ShowSpectrum, ShowWaterfall: Boolean);
|
||||
@@ -6830,15 +6978,9 @@ begin
|
||||
// Вызывается один раз через 200 мс после старта формы
|
||||
FAfterShowTimer.Enabled := False;
|
||||
|
||||
// Открываем PortAudio — теперь FPC уже перехватывает сигналы
|
||||
try
|
||||
if not FAudioOut.Open then
|
||||
StatusBar1.Panels[3].Text := 'Audio: ' + FAudioOut.LastError
|
||||
else
|
||||
StatusBar1.Panels[3].Text := 'Audio OK (PortAudio)';
|
||||
FAudioOut.Open;
|
||||
except
|
||||
on E: Exception do
|
||||
StatusBar1.Panels[3].Text := 'Audio: ' + E.Message;
|
||||
end;
|
||||
|
||||
EnsureWDSPWisdom;
|
||||
|
||||
Reference in New Issue
Block a user