feat(oc): OC Control — Open Collector выходы Penny/Alex (эталон Thetis)

Byte 1401 High Priority packet: per-band (HF 160m-6m) и per-slot (XVTR)
RX/TX-маски на 7 пинов + TX pin action (MOX/TUNE/2TON и комбинации).
Только openHPSDR — у Pluto/AD936x такого выхода нет, вкладка Settings
скрывается на этом бэкенде. Настройки — вкладка "OC Control" в SettingsForm.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 13:47:04 +03:00
co-authored by Claude Sonnet 5
parent b6d2256416
commit 041bc6ba7a
8 changed files with 547 additions and 26 deletions
+98 -5
View File
@@ -169,6 +169,11 @@ type
FAlexEnabled: Boolean;
FAlexConfig: TAlexSettings; // per-band antenna + routing config
FStepAtten: Byte; // ADC0 step attenuator 0-31 dB
// ---- OC Control (Open Collector выходы Penny/Alex, byte 1401) ----
FOCConfig: TOCSettings;
FTuning: Boolean; // TUN активен (для TX pin action)
FTwoTone: Boolean; // 2TON активен (для TX pin action)
FXvtrSlot: Integer; // активный слот XVTR (0..7) или -1 = HF-группа
// ---- PureSignal ----
// FPSEnabled — фича вооружена (кнопка PS). FPSTXActive — активная PTT-фаза:
// RebuildDDCSpecific включает feedback-DDC0 (ADC0) + sync DDC1 (TX DAC),
@@ -261,16 +266,21 @@ type
procedure SetRunAndFreq(Run: Boolean; DDC0FreqHz, DUCFreqHz: Double;
DriveLevel: Byte = 100); override;
procedure UpdateState(RXFreqHz, TXFreqHz: Double; DriveLevel: Byte;
Transmitting, PAEnabled, AlexEnabled: Boolean); override;
Transmitting, PAEnabled, AlexEnabled: Boolean;
Tuning: Boolean = False; TwoTone: Boolean = False); override;
procedure SetStepAtten(dB: Byte); override;
procedure SetFreqCalPPM(P: Double); override;
// Частота с поправкой опорника — для частотного слова DDC/DUC.
function CalFreq(Hz: Double): Double;
procedure SetAlexConfig(const A: TAlexSettings); override;
// OC Control (Open Collector выходы) — конфиг применяется мгновенно.
procedure SetOCConfig(const O: TOCSettings); override;
// Включение/настройка XVTR-режима. Все параметры применяются мгновенно
// (отправляется HP-пакет). Когда AEnable=False, XVTR-bit гасится,
// антенна и Alex routing возвращаются к per-band дефолту.
procedure SetXvtrMode(AEnable, ADisablePA: Boolean; ARxAnt: Byte); override;
// антенна и Alex routing возвращаются к per-band дефолту. ASlot — активный
// слот трансвертера (0..7), для per-slot OC-масок; -1 если не применимо.
procedure SetXvtrMode(AEnable, ADisablePA: Boolean; ARxAnt: Byte;
ASlot: Integer = -1); override;
procedure SendFullHP; override;
// Отдельная отправка PTT: переключает реле (bit27) и drive ДО, потом PTT.
// Не меняет FIsTransmitting — вызывать после UpdateState+SendFullHP.
@@ -750,6 +760,10 @@ begin
FPAEnabled := True;
FAlexEnabled := True;
TSettingsManager.DefaultAlex(FAlexConfig);
TSettingsManager.DefaultOC(FOCConfig);
FTuning := False;
FTwoTone := False;
FXvtrSlot := -1;
FSendLock := TCriticalSection.Create;
FHPSendLock := TCriticalSection.Create;
FDUCIQLock := TCriticalSection.Create;
@@ -1510,7 +1524,8 @@ begin
if FConnected then SendFullHP;
end;
procedure THPSDRNetwork.SetXvtrMode(AEnable, ADisablePA: Boolean; ARxAnt: Byte);
procedure THPSDRNetwork.SetXvtrMode(AEnable, ADisablePA: Boolean; ARxAnt: Byte;
ASlot: Integer);
begin
FXvtrEnable := AEnable;
FXvtrDisablePA := AEnable and ADisablePA;
@@ -1518,9 +1533,79 @@ begin
FXvtrRxAntOverride := ARxAnt
else
FXvtrRxAntOverride := 0;
if AEnable and (ASlot >= 0) then
FXvtrSlot := ASlot
else
FXvtrSlot := -1;
if FConnected then SendFullHP;
end;
procedure THPSDRNetwork.SetOCConfig(const O: TOCSettings);
begin
FOCConfig := O;
if FConnected then SendFullHP;
end;
// Строит 8-битное слово OC (byte 1401 HP-пакета, биты 0..6 = пины 1..7).
// Портировано из Thetis (Penny.UpdateExtCtrl/adjustForTXAction), урезано:
// без PA-override и split-pins VFO A/B (см. project_oc_control память).
// RX: маска банда/слота как есть. TX: маска банда/слота, каждый включённый
// пин дополнительно гейтится своим TX pin action (MOX/TUNE/TWOTONE и их
// комбинации) — тот же tx-флаг остаётся True на всём протяжении TUN/2TON
// (см. TRadioController.SetTune/SetTwoTone), поэтому "чистый MOX" явно
// исключает Tuning/TwoTone.
function CalcOCBits(RXFreqHz, TXFreqHz: Double;
Transmitting, Tuning, TwoTone: Boolean;
XvtrSlot: Integer;
const OC: TOCSettings): Byte;
var
RxMask, TxMask: Byte;
Actions: TOCPinActions;
i: Integer;
Fire: Boolean;
Band: Integer;
begin
Result := 0;
if not OC.Enabled then Exit;
if (XvtrSlot >= 0) and (XvtrSlot < CFG_XVTR_COUNT) then
begin
RxMask := OC.RxMaskXvtr[XvtrSlot];
TxMask := OC.TxMaskXvtr[XvtrSlot];
Actions := OC.ActionXvtr;
end
else
begin
if Transmitting then Band := FreqToBandIndex(TXFreqHz)
else Band := FreqToBandIndex(RXFreqHz);
RxMask := OC.RxMaskHF[Band];
TxMask := OC.TxMaskHF[Band];
Actions := OC.ActionHF;
end;
if not Transmitting then
begin
Result := RxMask;
Exit;
end;
for i := 0 to OC_PIN_COUNT - 1 do
begin
if (TxMask and (1 shl i)) = 0 then Continue;
case Actions[i] of
OCA_MOX: Fire := (not Tuning) and (not TwoTone);
OCA_TUNE: Fire := Tuning;
OCA_TWOTONE: Fire := TwoTone;
OCA_MOX_TUNE: Fire := not TwoTone;
OCA_MOX_TWOTONE: Fire := not Tuning;
OCA_TUNE_TWOTONE: Fire := Tuning or TwoTone;
OCA_MOX_TUNE_TWOTONE: Fire := True;
else Fire := False;
end;
if Fire then Result := Result or (1 shl i);
end;
end;
function THPSDRNetwork.DDCBaseIndex: Integer;
begin
// Для ANGELIA/ORION/ORION2/SATURN DDC начинается с индекса 2 (DDC0/1 — PureSignal)
@@ -1690,7 +1775,8 @@ end;
procedure THPSDRNetwork.UpdateState(RXFreqHz, TXFreqHz: Double;
DriveLevel: Byte;
Transmitting, PAEnabled, AlexEnabled: Boolean);
Transmitting, PAEnabled, AlexEnabled: Boolean;
Tuning: Boolean; TwoTone: Boolean);
begin
FCurrentRXFreq := RXFreqHz;
FCurrentTXFreq := TXFreqHz;
@@ -1698,6 +1784,8 @@ begin
FIsTransmitting := Transmitting;
FPAEnabled := PAEnabled;
FAlexEnabled := AlexEnabled;
FTuning := Tuning;
FTwoTone := TwoTone;
end;
function THPSDRNetwork.CalFreq(Hz: Double): Double;
@@ -1847,6 +1935,11 @@ begin
if not FSpeakerAudioEnabled then
Buf[1400] := Buf[1400] or $02;
// OC Control — Open Collector outputs (byte 1401)
if FOCConfig.Enabled then
Buf[1401] := CalcOCBits(FCurrentRXFreq, FCurrentTXFreq, FIsTransmitting,
FTuning, FTwoTone, FXvtrSlot, FOCConfig);
// Step attenuators ADC0/ADC1 (bytes 1443/1442)
// 0 dB = 0, max 31 dB
Buf[1443] := FStepAtten; // ADC0 attenuation