mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
feat(cat): CAT-порт на каждый слайс + Auto TX (эталон SmartSDR CAT)
Внешняя программа управляет отдельным слайсом как отдельным трансивером
через свой TCP-порт. COM-порты и 19090 остаются за главным приёмником
(слайс A) и не тронуты.
Протокол не дублируется: TCATEngine — чистый парсер поверх записи
callback'ов TCATContext, TCATTcpServer — транспорт поверх движка, поэтому
слайс-CAT = тот же движок с другим контекстом. Новый TCATSliceEndpoint
(движок + TCP-сервер на слот), массивом владеет TCATAdapter. Привязка к
СЛОТУ (буква B..G), не к Id: порт живёт, даже когда слайса нет (PS0).
Auto TX = «Auto Switch TX Slice» из SmartSDR CAT. Вся логика в одной точке
— TRadioController.RequestSliceTx, исполняется в потоке контроллера:
• пока кто-то уже в эфире (любой источник) — заявка игнорируется,
перехвата передачи нет никогда;
• без Auto TX слайс передаёт, только если уже выбран TX-источником;
• RX; снимает только СВОЮ передачу;
• TX-источник после отпускания остаётся на слайсе (как в SmartSDR).
На флаге слайса бейдж TX → AutoTX.
Частота слайса — TuneSliceInBand: свобода в пределах ВКЛЮЧЁННОГО диапазона
(трансвертер → его FreqBegin/FreqEnd, иначе band-план), другой диапазон —
отказ. Вне захваченной полосы окно DDC переезжает: доп. пан — центром на
цель (rfPanFreq → UI перекладывает флаги/шапку/зум-бар), пан 0 — центр
посередине между целью и главным VFO и только если оба влезают (общее
железное окно, главный приёмник не оглушаем).
Настройки: вкладка Slices (enable/порт 19091../Auto TX на слайс), персист
в секции cat + device-blob.
Попутно:
• ZZFL/ZZFH больше не заглушки — новые callback'и кромок фильтра
(у главного nil → прежний дефолт режима), хелпер SignedPad;
• FilterIdxFor, AGCModeToUI, BoardUtils.BandEdges;
• DSP-состояние слайса (NR/NB/SNB/ANF) зеркалится в TCtrlSlice — флаг
слайса рисовал нули и AGC главного;
• FUIReady в TMainForm.OnControllerState: адаптеры, создаваемые по ходу
FormCreate, больше не могут уронить старт рендером до постройки
виджетов (на этом падал Auto TX из настроек).
Проверено вживую: все порты 19091..19096 слушают, PS;/ZZFA;/MD;/ID;/SM0;/
ZZTX; отвечают; старт со всеми включёнными слайсами чист под gdb.
Документ — doc/CAT_SLICES.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+34
-2
@@ -20,8 +20,8 @@ interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,
|
||||
RadioController, CATEngine, CATSerial, CATTcp, Settings, WDSPEngine,
|
||||
AndromedaPanel;
|
||||
RadioController, CATEngine, CATSerial, CATTcp, CATSliceEndpoint, Settings,
|
||||
WDSPEngine, AndromedaPanel;
|
||||
|
||||
type
|
||||
TCATAdapter = class
|
||||
@@ -30,6 +30,9 @@ type
|
||||
FEngine: TCATEngine;
|
||||
FSerial: TCATSerialManager;
|
||||
FTcp: TCATTcpServer;
|
||||
// CAT дополнительных слайсов: свой движок+TCP-порт на слот (B..). Порты
|
||||
// главного (serial + FTcp) остаются за главным приёмником — слайс A.
|
||||
FSliceEps: array[0..CAT_SLICE_SLOTS-1] of TCATSliceEndpoint;
|
||||
FPanel: TAndromedaPanel; // передняя панель Andromeda/G2 (если включена)
|
||||
// Параметры команды для маршалинга в поток контроллера (через Invoke).
|
||||
FSyncFreq: Double;
|
||||
@@ -130,6 +133,7 @@ type
|
||||
procedure SyncFMStep;
|
||||
procedure SyncAGCTop;
|
||||
procedure SyncCTun;
|
||||
procedure ApplySliceSettings(const G: TGlobalSettings); // CAT-порты слайсов
|
||||
public
|
||||
constructor Create(AController: TRadioController);
|
||||
destructor Destroy; override;
|
||||
@@ -142,6 +146,7 @@ implementation
|
||||
constructor TCATAdapter.Create(AController: TRadioController);
|
||||
var
|
||||
Ctx: TCATContext;
|
||||
i: Integer;
|
||||
begin
|
||||
inherited Create;
|
||||
FController := AController;
|
||||
@@ -211,13 +216,18 @@ begin
|
||||
FSerial := TCATSerialManager.Create(FEngine);
|
||||
FTcp := TCATTcpServer.Create(FEngine);
|
||||
|
||||
for i := 0 to CAT_SLICE_SLOTS - 1 do
|
||||
FSliceEps[i] := TCATSliceEndpoint.Create(FController, i);
|
||||
|
||||
// Передняя панель: отправляет наружу через Andromeda-порт, слушает состояние.
|
||||
FPanel := TAndromedaPanel.Create(FController, @FSerial.SendToAndromeda);
|
||||
FController.AddStateListener(@FPanel.OnControllerState);
|
||||
end;
|
||||
|
||||
destructor TCATAdapter.Destroy;
|
||||
var i: Integer;
|
||||
begin
|
||||
for i := 0 to CAT_SLICE_SLOTS - 1 do FreeAndNil(FSliceEps[i]);
|
||||
if Assigned(FTcp) then begin FTcp.Stop; FreeAndNil(FTcp); end;
|
||||
if Assigned(FSerial) then begin FSerial.StopAll; FreeAndNil(FSerial); end;
|
||||
FreeAndNil(FEngine);
|
||||
@@ -253,6 +263,28 @@ begin
|
||||
FTcp.Port := G.CATTcpPort;
|
||||
FTcp.Start;
|
||||
end;
|
||||
ApplySliceSettings(G);
|
||||
end;
|
||||
|
||||
procedure TCATAdapter.ApplySliceSettings(const G: TGlobalSettings);
|
||||
// CAT слайсов: Auto TX — в контроллер (его читают TX-логика и флаг слайса),
|
||||
// порт — в свой эндпоинт. Совпадающие порты не поднимаем: второй bind всё
|
||||
// равно упадёт, а так поведение предсказуемо (выигрывает слот меньшей буквы).
|
||||
var
|
||||
i, j: Integer;
|
||||
Enable: Boolean;
|
||||
begin
|
||||
for i := 0 to CAT_SLICE_SLOTS - 1 do
|
||||
begin
|
||||
FController.SetSliceSlotAutoTx(i, G.CATSliceAutoTX[i]);
|
||||
Enable := G.CATSliceEnabled[i] and (G.CATSlicePort[i] > 0);
|
||||
if Enable and G.CATTcpEnabled and (G.CATSlicePort[i] = G.CATTcpPort) then
|
||||
Enable := False;
|
||||
for j := 0 to i - 1 do
|
||||
if G.CATSliceEnabled[j] and (G.CATSlicePort[j] = G.CATSlicePort[i]) then
|
||||
Enable := False;
|
||||
FSliceEps[i].Apply(Enable, G.CATSlicePort[i]);
|
||||
end;
|
||||
end;
|
||||
|
||||
// ── Геттеры ──────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user