mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat(pans): выбор аппаратного DDC для панадаптера
Клик по «NNN kHz · DDCn» в шапке пана — кроме сетки rate теперь есть пункты «→ DDC N»: пан переезжает на другой аппаратный DDC (MovePanDDC), при этом движок, анализатор и слайсы не пересоздаются — перепрошивается только hw-индекс. Пригодилось при отладке: конкретный DDC платы может вести себя хуже соседей, и пан можно просто увести на другой. Диапазон ограничен реальными DDC железа: MaxDDCIndex = 7 (DDC8+ openHPSDR enable-бит принимает, но поток не отдаёт). Ограничение действует и в меню, и в DDCFree, и в самом MovePanDDC. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+18
-2
@@ -47,6 +47,9 @@ uses
|
|||||||
RadioController, ChannelController;
|
RadioController, ChannelController;
|
||||||
|
|
||||||
const
|
const
|
||||||
|
// Меню шапки пана: теги ниже — rate в кГц, от DDC_MENU_TAG — выбор hw-DDC.
|
||||||
|
DDC_MENU_TAG = 1000;
|
||||||
|
|
||||||
CLR_BG = TColor($00101010);
|
CLR_BG = TColor($00101010);
|
||||||
CLR_PANEL = TColor($00181818);
|
CLR_PANEL = TColor($00181818);
|
||||||
CLR_BORDER = TColor($00303030);
|
CLR_BORDER = TColor($00303030);
|
||||||
@@ -5626,7 +5629,7 @@ procedure TMainForm.OnPanRateClick(Sender: TObject);
|
|||||||
// (фильтр PanRateAllowed — кратные 48 кГц). Текущий rate отмечен галкой.
|
// (фильтр PanRateAllowed — кратные 48 кГц). Текущий rate отмечен галкой.
|
||||||
var
|
var
|
||||||
P: TPanafallPanel;
|
P: TPanafallPanel;
|
||||||
i, kHz, Cur: Integer;
|
i, kHz, Cur, CurDDC: Integer;
|
||||||
begin
|
begin
|
||||||
if not (Sender is TPanafallPanel) then Exit;
|
if not (Sender is TPanafallPanel) then Exit;
|
||||||
P := TPanafallPanel(Sender);
|
P := TPanafallPanel(Sender);
|
||||||
@@ -5645,6 +5648,11 @@ begin
|
|||||||
if not FController.PanRateAllowed(Word(kHz)) then Continue;
|
if not FController.PanRateAllowed(Word(kHz)) then Continue;
|
||||||
FPanRateMenu.AddItem(Format('%d kHz', [kHz]), kHz, kHz = Cur);
|
FPanRateMenu.AddItem(Format('%d kHz', [kHz]), kHz, kHz = Cur);
|
||||||
end;
|
end;
|
||||||
|
// Аппаратный DDC пана: свободные индексы платы + текущий (отмечен галкой).
|
||||||
|
CurDDC := FController.PanDDCIndex(P.PanId);
|
||||||
|
for i := FController.PanDDCIndex(0) + 1 to FController.MaxDDCIndex do
|
||||||
|
if (i = CurDDC) or FController.DDCFree(i) then
|
||||||
|
FPanRateMenu.AddItem(Format('→ DDC %d', [i]), DDC_MENU_TAG + i, i = CurDDC);
|
||||||
FPanRateMenuPanId := P.PanId;
|
FPanRateMenuPanId := P.PanId;
|
||||||
FPanRateMenu.PopupBelow(P.HeaderRateLabel); // дочерний контрол формы
|
FPanRateMenu.PopupBelow(P.HeaderRateLabel); // дочерний контрол формы
|
||||||
end;
|
end;
|
||||||
@@ -5659,6 +5667,12 @@ begin
|
|||||||
if (PanId < 1) or (PanId >= MAX_PANS) then Exit;
|
if (PanId < 1) or (PanId >= MAX_PANS) then Exit;
|
||||||
P := FPans[PanId];
|
P := FPans[PanId];
|
||||||
if P = nil then Exit;
|
if P = nil then Exit;
|
||||||
|
// Теги DDC_MENU_TAG+ — переезд пана на другой hw DDC (движок не трогаем).
|
||||||
|
if Tag >= DDC_MENU_TAG then
|
||||||
|
begin
|
||||||
|
if FController.MovePanDDC(PanId, Tag - DDC_MENU_TAG) then UpdatePanHeaders;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
if not FController.SetPanDDCRate(PanId, Word(Tag)) then Exit;
|
if not FController.SetPanDDCRate(PanId, Word(Tag)) then Exit;
|
||||||
// Вьюха/шапка/флаги под новый span (слайсы могли клампнуться к краям).
|
// Вьюха/шапка/флаги под новый span (слайсы могли клампнуться к краям).
|
||||||
SyncPanViews;
|
SyncPanViews;
|
||||||
@@ -6098,7 +6112,9 @@ begin
|
|||||||
begin
|
begin
|
||||||
P.SetHeaderText(Format('PAN %d · %.6f MHz ·',
|
P.SetHeaderText(Format('PAN %d · %.6f MHz ·',
|
||||||
[i, FController.PanDDCFreq(i) / 1e6]));
|
[i, FController.PanDDCFreq(i) / 1e6]));
|
||||||
P.SetHeaderRate(Format('%d kHz', [FController.PanDDCRateKHz(i)]));
|
// hw-индекс DDC в шапке: по клику там же выбирается rate и DDC пана.
|
||||||
|
P.SetHeaderRate(Format('%d kHz · DDC%d',
|
||||||
|
[FController.PanDDCRateKHz(i), FController.PanDDCIndex(i)]));
|
||||||
end;
|
end;
|
||||||
// Бейдж диапазона (3.6): только паны N на «настоящих КВ»; клик = меню.
|
// Бейдж диапазона (3.6): только паны N на «настоящих КВ»; клик = меню.
|
||||||
if (i > 0) and PanBandSelectorVisible then
|
if (i > 0) and PanBandSelectorVisible then
|
||||||
|
|||||||
@@ -596,6 +596,13 @@ type
|
|||||||
// Смена rate живого пана: движок переоткрывает аккумулятор/анализатор/слайсы,
|
// Смена rate живого пана: движок переоткрывает аккумулятор/анализатор/слайсы,
|
||||||
// DDC реконфигурируется; слайсы вне новой полосы клампятся к её краям.
|
// DDC реконфигурируется; слайсы вне новой полосы клампятся к её краям.
|
||||||
function SetPanDDCRate(PanId: Integer; RateKHz: Word): Boolean;
|
function SetPanDDCRate(PanId: Integer; RateKHz: Word): Boolean;
|
||||||
|
// Переезд пана на другой аппаратный DDC (пан/слайсы/движок не пересоздаются,
|
||||||
|
// меняется только hw-индекс): бывает, что конкретный DDC платы ведёт себя
|
||||||
|
// хуже соседей — тогда пан можно просто увести на другой.
|
||||||
|
function MovePanDDC(PanId, NewDDC: Integer): Boolean;
|
||||||
|
function PanDDCIndex(PanId: Integer): Integer; // hw-индекс DDC пана
|
||||||
|
function MaxDDCIndex: Integer; // последний DDC железа
|
||||||
|
function DDCFree(DDCIdx: Integer): Boolean; // индекс свободен?
|
||||||
function PanDDCActive(PanId: Integer): Boolean;
|
function PanDDCActive(PanId: Integer): Boolean;
|
||||||
function PanDDCFreq(PanId: Integer): Double;
|
function PanDDCFreq(PanId: Integer): Double;
|
||||||
function PanDDCRateKHz(PanId: Integer): Word;
|
function PanDDCRateKHz(PanId: Integer): Word;
|
||||||
@@ -1311,6 +1318,53 @@ begin
|
|||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TRadioController.MovePanDDC(PanId, NewDDC: Integer): Boolean;
|
||||||
|
// Тот же пан (движок/анализатор/слайсы не трогаем) — только другой аппаратный
|
||||||
|
// DDC: старый гасим, новый включаем с теми же freq/rate/ADC. Короткий разрыв IQ
|
||||||
|
// на время реконфига — норма.
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
if not PanDDCActive(PanId) then Exit;
|
||||||
|
if not Assigned(FNetwork) then Exit;
|
||||||
|
if (NewDDC <= FActiveDDC) or (NewDDC > MaxDDCIndex) then Exit;
|
||||||
|
if FPanDDCIdx[PanId] = NewDDC then Exit(True);
|
||||||
|
if FDDCPanMap[NewDDC] >= 0 then Exit; // занят другим паном
|
||||||
|
|
||||||
|
FNetwork.SetPanDDC(FPanDDCIdx[PanId], False, 0, 0, 0);
|
||||||
|
FDDCPanMap[FPanDDCIdx[PanId]] := -1;
|
||||||
|
// Seq-трекинг обоих индексов начинаем заново (новый поток — новый счётчик).
|
||||||
|
if FPanDDCIdx[PanId] <= High(FDDCSeqValid) then
|
||||||
|
FDDCSeqValid[FPanDDCIdx[PanId]] := False;
|
||||||
|
if NewDDC <= High(FDDCSeqValid) then
|
||||||
|
FDDCSeqValid[NewDDC] := False;
|
||||||
|
|
||||||
|
FPanDDCIdx[PanId] := NewDDC;
|
||||||
|
FDDCPanMap[NewDDC] := PanId;
|
||||||
|
FNetwork.SetPanDDC(NewDDC, True, XvtrTranslate(FPanFreqHz[PanId]),
|
||||||
|
FPanRateKHz[PanId], FPanADC[PanId]);
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRadioController.PanDDCIndex(PanId: Integer): Integer;
|
||||||
|
begin
|
||||||
|
if (PanId >= 1) and (PanId < MAX_PANS) then Result := FPanDDCIdx[PanId]
|
||||||
|
else if PanId = 0 then Result := FActiveDDC
|
||||||
|
else Result := -1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRadioController.MaxDDCIndex: Integer;
|
||||||
|
// Железо openHPSDR (Orion/Saturn) поднимает DDC0..DDC7 — DDC8 и выше молчат
|
||||||
|
// (проверено на плате: enable-бит ставится, поток не идёт).
|
||||||
|
begin
|
||||||
|
Result := 7;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRadioController.DDCFree(DDCIdx: Integer): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (DDCIdx > FActiveDDC) and (DDCIdx <= MaxDDCIndex)
|
||||||
|
and (FDDCPanMap[DDCIdx] < 0);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TRadioController.RemovePanDDC(PanId: Integer);
|
procedure TRadioController.RemovePanDDC(PanId: Integer);
|
||||||
var ddc, i: Integer;
|
var ddc, i: Integer;
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
<UseVersionInfo Value="True"/>
|
<UseVersionInfo Value="True"/>
|
||||||
<AutoIncrementBuild Value="True"/>
|
<AutoIncrementBuild Value="True"/>
|
||||||
<MinorVersionNr Value="9"/>
|
<MinorVersionNr Value="9"/>
|
||||||
<BuildNr Value="272"/>
|
<BuildNr Value="274"/>
|
||||||
</VersionInfo>
|
</VersionInfo>
|
||||||
<MacroValues Count="91">
|
<MacroValues Count="95">
|
||||||
<Macro1 Name="LCLWidgetType" Value="qt6"/>
|
<Macro1 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro2 Name="LCLWidgetType" Value="qt6"/>
|
<Macro2 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro3 Name="LCLWidgetType" Value="qt6"/>
|
<Macro3 Name="LCLWidgetType" Value="qt6"/>
|
||||||
@@ -111,6 +111,10 @@
|
|||||||
<Macro89 Name="LCLWidgetType" Value="qt6"/>
|
<Macro89 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro90 Name="LCLWidgetType" Value="qt6"/>
|
<Macro90 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro91 Name="LCLWidgetType" Value="qt6"/>
|
<Macro91 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro92 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro93 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro94 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro95 Name="LCLWidgetType" Value="qt6"/>
|
||||||
</MacroValues>
|
</MacroValues>
|
||||||
<BuildModes>
|
<BuildModes>
|
||||||
<Item Name="Debug" Default="True"/>
|
<Item Name="Debug" Default="True"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user