Remove XVTR RF checkbox; fix XVTR Enable bit to match Thetis

XVTR RF (xvtr_rf in Thetis) is dead code — GetXVTRRF() is never called.
Remove the field, UI column, save/load from TXvtrEntry. UseDDCIn is now
always True when in XVTR mode (previous default behaviour, XVTRRF=False).

Byte 1400 bit 0 (XVTR Enable / VHF T/R relay output) now follows Thetis:
  - XVTR mode: set only when DisablePA=True (external T/R relay needed)
  - HF mode:   set when Alex.EnableXvtrHf is checked (Antenna tab)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 22:05:08 +03:00
co-authored by Claude Sonnet 4.6
parent b00c0d02a0
commit 1368f249c4
4 changed files with 18 additions and 26 deletions
+15 -8
View File
@@ -145,9 +145,8 @@ type
FAlexConfig: TAlexSettings; // per-band antenna + routing config
FStepAtten: Byte; // ADC0 step attenuator 0-31 dB
// ---- XVTR (Transverter) state ----
// FXvtrEnable — устанавливает bit 0 байта 1400 HP-пакета: включает выход
// XVTR на трансивере (управляющий пин/реле). Обычно True, пока активный
// диапазон — трансвертер.
// FXvtrEnable — True когда активен XVTR-диапазон. Используется как
// XvtrActive в CalcAlex0 и для управления byte 1400 bit 0.
FXvtrEnable: Boolean;
// FXvtrRxAntOverride — если 1..3, использовать эту антенну вместо
// Alex.RxAnt[band] (per-XVTR RX antenna). 0 = не переопределять.
@@ -1417,12 +1416,20 @@ begin
Buf[1435] := Alex0 and $FF;
end;
// XVTR enable bit (byte 1400 bit 0)
// openHPSDR Ethernet Protocol v4.3: byte 1400 — Transverter/audio enable.
// bit 0 = XVTR enable, bit 1 = Audio Codec enable (на платах с поддержкой).
// Audio codec бит оставляем 0 — мы IQ-mic не используем.
// XVTR enable bit (byte 1400 bit 0) — управляет выходом VHF T/R relay платы.
// Логика как в Thetis:
// в XVTR-режиме: бит = DisablePA (внешний T/R relay нужен только если PA подавлен)
// в HF-режиме: бит = Alex.EnableXvtrHf (галочка "Enable XVTR HF" в Antenna tab)
if FXvtrEnable then
Buf[1400] := Buf[1400] or $01;
begin
if FXvtrDisablePA then
Buf[1400] := Buf[1400] or $01;
end
else
begin
if FAlexConfig.EnableXvtrHf then
Buf[1400] := Buf[1400] or $01;
end;
// Step attenuators ADC0/ADC1 (bytes 1443/1442)
// 0 dB = 0, max 31 dB
+1 -4
View File
@@ -5604,10 +5604,7 @@ begin
FXvtrSettings.Entries[FCurrentXvtr].Enabled then
begin
En := True;
// XVTRRF=True означает что трансвертер использует HF тракт — не нужно
// переключаться на отдельный XVTR DDC IN на Alex. Default False →
// подключаем XVTR-IF к выделенному пину XVTR DDC IN.
UseDDCIn := not FXvtrSettings.Entries[FCurrentXvtr].XVTRRF;
UseDDCIn := True;
DisablePA := FXvtrSettings.Entries[FCurrentXvtr].DisablePA;
RxAnt := FXvtrSettings.Entries[FCurrentXvtr].RXAntenna;
end
-5
View File
@@ -118,8 +118,6 @@ type
RXGain: Double; // dB, компенсация усиления RX тракта
RXOnly: Boolean; // True — запрещает TX на этом трансверторе
TXPower: Integer; // 0..100 % (drive level специально для XVTR)
XVTRRF: Boolean; // True — трансвертер использует основной HF RF путь
// (а не отдельный XVTR DDC IN на Alex)
DisablePA: Boolean; // True — отключить внутренний PA при TX (XVTR имеет свой)
RXAntenna: Byte; // 0=по-умолчанию(основной band), 1=ANT1, 2=ANT2, 3=ANT3
LastFreq: Double; // Hz — последняя tuned visible частота (BandStack)
@@ -1058,7 +1056,6 @@ begin
X.Entries[i].RXGain := 0.0;
X.Entries[i].RXOnly := False;
X.Entries[i].TXPower := 100;
X.Entries[i].XVTRRF := False;
X.Entries[i].DisablePA := False;
X.Entries[i].RXAntenna := 0;
X.Entries[i].LastFreq := 0.0;
@@ -1104,7 +1101,6 @@ begin
X.Entries[i].RXGain := JD(EObj, 'rx_gain', X.Entries[i].RXGain);
X.Entries[i].RXOnly := JB(EObj, 'rx_only', X.Entries[i].RXOnly);
X.Entries[i].TXPower := EnsureRange(JI(EObj, 'tx_pwr', X.Entries[i].TXPower), 0, 100);
X.Entries[i].XVTRRF := JB(EObj, 'xvtr_rf', X.Entries[i].XVTRRF);
X.Entries[i].DisablePA := JB(EObj, 'dis_pa', X.Entries[i].DisablePA);
X.Entries[i].RXAntenna := EnsureRange(JI(EObj, 'rx_ant', X.Entries[i].RXAntenna), 0, 3);
X.Entries[i].LastFreq := JD(EObj, 'last_freq', X.Entries[i].LastFreq);
@@ -1135,7 +1131,6 @@ begin
JW(EObj, 'rx_gain', X.Entries[i].RXGain);
JW(EObj, 'rx_only', X.Entries[i].RXOnly);
JW(EObj, 'tx_pwr', X.Entries[i].TXPower);
JW(EObj, 'xvtr_rf', X.Entries[i].XVTRRF);
JW(EObj, 'dis_pa', X.Entries[i].DisablePA);
JW(EObj, 'rx_ant', Integer(X.Entries[i].RXAntenna));
JW(EObj, 'last_freq', X.Entries[i].LastFreq);
+2 -9
View File
@@ -218,7 +218,6 @@ type
FXvtrRXGain: array[0..CFG_XVTR_COUNT-1] of TFloatSpinEdit; // dB
FXvtrRXOnly: array[0..CFG_XVTR_COUNT-1] of TCheckBox;
FXvtrPower: array[0..CFG_XVTR_COUNT-1] of TSpinEdit; // 0..100
FXvtrRF: array[0..CFG_XVTR_COUNT-1] of TCheckBox;
FXvtrDisPA: array[0..CFG_XVTR_COUNT-1] of TCheckBox;
FXvtrRXAnt: array[0..CFG_XVTR_COUNT-1] of TComboBox; // 0=def..3=ANT3
FChkXvtrTunPwr: TCheckBox;
@@ -2662,9 +2661,8 @@ const
GAIN_X = 504; GAIN_W = 62; // 1 десятичная, dB
RXO_X = 574; RXO_W = 56; // chk центрирован
PWR_X = 638; PWR_W = 58; // целое %
RF_X = 704; RF_W = 56;
PA_X = 768; PA_W = 66;
ANT_X = 842; ANT_W = 78; // combo default/ANT1/ANT2/ANT3
PA_X = 704; PA_W = 66;
ANT_X = 778; ANT_W = 78; // combo default/ANT1/ANT2/ANT3
GRP_W = ANT_X + ANT_W + 14; // 934
var
Grp, GrpOpts: TPanel;
@@ -2795,7 +2793,6 @@ begin
MakeHdr(Grp, 'RX Gain' + LineEnding + 'dB', GAIN_X, Y, GAIN_W);
MakeHdr(Grp, 'RX' + LineEnding + 'Only', RXO_X, Y, RXO_W);
MakeHdr(Grp, 'TX Pwr' + LineEnding + '%', PWR_X, Y, PWR_W);
MakeHdr(Grp, 'XVTR' + LineEnding + 'RF', RF_X, Y, RF_W);
MakeHdr(Grp, 'Disable' + LineEnding + 'PA', PA_X, Y, PA_W);
MakeHdr(Grp, 'RX' + LineEnding + 'Antenna', ANT_X, Y, ANT_W);
@@ -2814,7 +2811,6 @@ begin
// Чекбокс RX Only центрируем
FXvtrRXOnly[i]:= MakeChk(Grp, RXO_X + (RXO_W - 22) div 2, Y + 2);
FXvtrPower[i] := MakeInt(Grp, PWR_X, Y, PWR_W, 0, 100);
FXvtrRF[i] := MakeChk(Grp, RF_X + (RF_W - 22) div 2, Y + 2);
FXvtrDisPA[i] := MakeChk(Grp, PA_X + (PA_W - 22) div 2, Y + 2);
FXvtrRXAnt[i] := MakeCmb(Grp, ANT_X, Y, ANT_W);
FXvtrRXAnt[i].Items.Add('default');
@@ -2876,7 +2872,6 @@ begin
if FXvtrRXGain[Idx]<> nil then FXvtrRXGain[Idx].Enabled:= En;
if FXvtrRXOnly[Idx]<> nil then FXvtrRXOnly[Idx].Enabled:= En;
if FXvtrPower[Idx] <> nil then FXvtrPower[Idx].Enabled := En;
if FXvtrRF[Idx] <> nil then FXvtrRF[Idx].Enabled := En;
if FXvtrDisPA[Idx] <> nil then FXvtrDisPA[Idx].Enabled := En;
if FXvtrRXAnt[Idx] <> nil then FXvtrRXAnt[Idx].Enabled := En;
end;
@@ -2895,7 +2890,6 @@ begin
if FXvtrRXGain[i]<> nil then FXvtrConfig.Entries[i].RXGain := FXvtrRXGain[i].Value;
if FXvtrRXOnly[i]<> nil then FXvtrConfig.Entries[i].RXOnly := FXvtrRXOnly[i].Checked;
if FXvtrPower[i] <> nil then FXvtrConfig.Entries[i].TXPower := FXvtrPower[i].Value;
if FXvtrRF[i] <> nil then FXvtrConfig.Entries[i].XVTRRF := FXvtrRF[i].Checked;
if FXvtrDisPA[i] <> nil then FXvtrConfig.Entries[i].DisablePA := FXvtrDisPA[i].Checked;
if (FXvtrRXAnt[i]<> nil) and (FXvtrRXAnt[i].ItemIndex >= 0) then
FXvtrConfig.Entries[i].RXAntenna := Byte(FXvtrRXAnt[i].ItemIndex);
@@ -2938,7 +2932,6 @@ begin
if FXvtrRXGain[i]<> nil then FXvtrRXGain[i].Value := X.Entries[i].RXGain;
if FXvtrRXOnly[i]<> nil then FXvtrRXOnly[i].Checked:= X.Entries[i].RXOnly;
if FXvtrPower[i] <> nil then FXvtrPower[i].Value := X.Entries[i].TXPower;
if FXvtrRF[i] <> nil then FXvtrRF[i].Checked := X.Entries[i].XVTRRF;
if FXvtrDisPA[i] <> nil then FXvtrDisPA[i].Checked := X.Entries[i].DisablePA;
if FXvtrRXAnt[i] <> nil then
FXvtrRXAnt[i].ItemIndex := EnsureRange(X.Entries[i].RXAntenna, 0, 3);