fix(dmr): block MOX and tune on receive mode

This commit is contained in:
2026-07-14 20:35:20 +03:00
parent e5451b7843
commit d794805081
2 changed files with 36 additions and 4 deletions
+18 -4
View File
@@ -416,6 +416,7 @@ type
// Public UI update (called from sync objects) // Public UI update (called from sync objects)
procedure UpdateTXMeters; procedure UpdateTXMeters;
procedure UpdateTXControlAvailability;
procedure UpdateStatusField7; // поле 7: PLL (HPSDR) или beacon (Pluto) procedure UpdateStatusField7; // поле 7: PLL (HPSDR) или beacon (Pluto)
procedure UpdateStatusField3; // поле 3: Supply (HPSDR) или Temp/RSSI (Pluto) procedure UpdateStatusField3; // поле 3: Supply (HPSDR) или Temp/RSSI (Pluto)
function BeaconStatusText: string; // компактный статус QO-100 beacon lock function BeaconStatusText: string; // компактный статус QO-100 beacon lock
@@ -1362,6 +1363,7 @@ begin
(FController.FTxSliceId = 0); (FController.FTxSliceId = 0);
ApplySpecViewGridFromState; // сетка спектра под активный тракт ApplySpecViewGridFromState; // сетка спектра под активный тракт
RefreshTxIndicators; // TX-бейджи флагов (какой слайс передаёт) RefreshTxIndicators; // TX-бейджи флагов (какой слайс передаёт)
UpdateTXControlAvailability;
end; // (DUC-очередь сбрасывает SetMOX) end; // (DUC-очередь сбрасывает SetMOX)
rfTuning: rfTuning:
StyleButton(BtnTUN, FController.FTuning); StyleButton(BtnTUN, FController.FTuning);
@@ -1374,7 +1376,7 @@ begin
InhibitSleep; InhibitSleep;
BtnStartStop.Caption := 'STOP'; BtnStartStop.Caption := 'STOP';
StyleButton(BtnStartStop, True); StyleButton(BtnStartStop, True);
BtnMOX.Enabled := True; UpdateTXControlAvailability;
UpdateAddPanButton; // «⊞» доступна только в Run UpdateAddPanButton; // «⊞» доступна только в Run
ResizeSpectrumPanels; ResizeSpectrumPanels;
RestorePanWorkspace; // паны+слайсы прошлой сессии RestorePanWorkspace; // паны+слайсы прошлой сессии
@@ -1384,7 +1386,7 @@ begin
UninhibitSleep; UninhibitSleep;
BtnStartStop.Caption := 'START'; BtnStartStop.Caption := 'START';
StyleButton(BtnStartStop, False); StyleButton(BtnStartStop, False);
BtnMOX.Enabled := False; UpdateTXControlAvailability;
// Снимок панов уже сделан хуком OnBeforeStop=SavePanWorkspace (до // Снимок панов уже сделан хуком OnBeforeStop=SavePanWorkspace (до
// гашения DDC в StopRunning). Здесь только разрешаем повторный // гашения DDC в StopRunning). Здесь только разрешаем повторный
// restore на следующем старте. // restore на следующем старте.
@@ -1460,6 +1462,7 @@ begin
FController.FFilterBW := SavedFilterBW; FController.FFilterBW := SavedFilterBW;
for i := 0 to FILT_COUNT - 1 do StyleButton(BtnFilter[i], i = FController.FFilter); for i := 0 to FILT_COUNT - 1 do StyleButton(BtnFilter[i], i = FController.FFilter);
SyncSpecViewFreq; // иначе полоса фильтра рисуется под старый режим SyncSpecViewFreq; // иначе полоса фильтра рисуется под старый режим
UpdateTXControlAvailability;
end; end;
rfFilter: rfFilter:
begin begin
@@ -1945,6 +1948,7 @@ begin
BtnTUN := MakeBtn(PanelTX, 'TUN', BtnTUN := MakeBtn(PanelTX, 'TUN',
LeftPanelButtonLeft(LEFT_W, 4, 1), 16, LeftPanelButtonLeft(LEFT_W, 4, 1), 16,
LeftPanelButtonWidth(LEFT_W, 4, 1), BTN_SM, BtnTUNClick); LeftPanelButtonWidth(LEFT_W, 4, 1), BTN_SM, BtnTUNClick);
UpdateTXControlAvailability;
BtnDUP := MakeBtn(PanelTX, 'DUP', BtnDUP := MakeBtn(PanelTX, 'DUP',
LeftPanelButtonLeft(LEFT_W, 4, 0), 44, LeftPanelButtonLeft(LEFT_W, 4, 0), 44,
@@ -3369,7 +3373,7 @@ begin
UninhibitSleep; UninhibitSleep;
FController.FNetwork.SetRunAndFreq(False, XvtrTranslate(FController.FCenterFreq), XvtrTranslate(FController.FCenterFreq), 0); FController.FNetwork.SetRunAndFreq(False, XvtrTranslate(FController.FCenterFreq), XvtrTranslate(FController.FCenterFreq), 0);
SetRadioOfflineStatus('Hardware timeout'); SetRadioOfflineStatus('Hardware timeout');
BtnMOX.Enabled := False; UpdateTXControlAvailability;
Exit; Exit;
end; end;
// После первого пакета — следим чтобы поток не прерывался более 3 сек // После первого пакета — следим чтобы поток не прерывался более 3 сек
@@ -3381,7 +3385,7 @@ begin
UninhibitSleep; UninhibitSleep;
FController.FNetwork.SetRunAndFreq(False, XvtrTranslate(FController.FCenterFreq), XvtrTranslate(FController.FCenterFreq), 0); FController.FNetwork.SetRunAndFreq(False, XvtrTranslate(FController.FCenterFreq), XvtrTranslate(FController.FCenterFreq), 0);
SetRadioOfflineStatus('Connection lost'); SetRadioOfflineStatus('Connection lost');
BtnMOX.Enabled := False; UpdateTXControlAvailability;
Exit; Exit;
end; end;
end; end;
@@ -3516,6 +3520,16 @@ begin
UpdateStatusField3; // Supply (openHPSDR) или Temp/RSSI (Pluto) UpdateStatusField3; // Supply (openHPSDR) или Temp/RSSI (Pluto)
end; end;
procedure TMainForm.UpdateTXControlAvailability;
var Allowed: Boolean;
begin
if (BtnMOX = nil) or (BtnTUN = nil) or (FController = nil) then Exit;
Allowed := FController.FRunning and
(FController.ActiveTXMode <> MODE_DMR);
BtnMOX.Enabled := Allowed;
BtnTUN.Enabled := Allowed;
end;
procedure TMainForm.UpdateStatusField3; procedure TMainForm.UpdateStatusField3;
// Поле 3 статус-бара. openHPSDR — supply V/A (HP status). Pluto — температура // Поле 3 статус-бара. openHPSDR — supply V/A (HP status). Pluto — температура
// чипа и RSSI приёмника (нет PA → supply неприменим). Значения берём из // чипа и RSSI приёмника (нет PA → supply неприменим). Значения берём из
+18
View File
@@ -2145,6 +2145,13 @@ begin
if S.Mode = MODE_DMR then Exit; if S.Mode = MODE_DMR then Exit;
end; end;
if FTxSliceId = SliceId then Exit; if FTxSliceId = SliceId then Exit;
// Selecting main A while it is in DMR is allowed as an RX selection, but it
// cannot inherit an active carrier from a previously selected TX slice.
if (SliceId = 0) and (FMode = MODE_DMR) then
begin
if FTuning then SetTune(False)
else if FTransmitting then SetMOX(False);
end;
FTxSliceId := SliceId; FTxSliceId := SliceId;
// Передающий тракт под режим нового источника (idle-канал, применится к PTT). // Передающий тракт под режим нового источника (idle-канал, применится к PTT).
if FWDSPReady and Assigned(FDSPEngine) then if FWDSPReady and Assigned(FDSPEngine) then
@@ -3143,6 +3150,13 @@ end;
procedure TRadioController.SetMode(M: Integer); procedure TRadioController.SetMode(M: Integer);
begin begin
FMode := M; FMode := M;
// Entering receive-only DMR on the selected main TX source immediately
// releases an existing carrier. SetTune(False) also releases MOX.
if ActiveTXMode = MODE_DMR then
begin
if FTuning then SetTune(False)
else if FTransmitting then SetMOX(False);
end;
if Assigned(FDMRDec) then FDMRDec.SetEnabled(FMode = MODE_DMR); if Assigned(FDMRDec) then FDMRDec.SetEnabled(FMode = MODE_DMR);
ApplyModeDefaults; // дефолтный фильтр/девиация под режим ApplyModeDefaults; // дефолтный фильтр/девиация под режим
FBandCache[FCurrentBand].Mode := FMode; FBandCache[FCurrentBand].Mode := FMode;
@@ -4026,6 +4040,9 @@ procedure TRadioController.SetMOX(On_: Boolean);
var var
WasTransmitting: Boolean; WasTransmitting: Boolean;
begin begin
// DMR support is receive-only. This guard also covers CAT, web and hardware
// PTT. A selected non-DMR TX slice remains valid while main A receives DMR.
if On_ and (ActiveTXMode = MODE_DMR) then Exit;
// Safety: блокируем TX на бэндах с DoNotTx (Alex) и на RX-only трансвертере. // Safety: блокируем TX на бэндах с DoNotTx (Alex) и на RX-only трансвертере.
if On_ and FDevConnected and (FCurrentXvtr < 0) if On_ and FDevConnected and (FCurrentXvtr < 0)
and FAlexSettings.DoNotTx[EnsureRange(TxBandIdx, 0, 10)] then and FAlexSettings.DoNotTx[EnsureRange(TxBandIdx, 0, 10)] then
@@ -4128,6 +4145,7 @@ end;
procedure TRadioController.SetTune(On_: Boolean); procedure TRadioController.SetTune(On_: Boolean);
begin begin
if On_ = FTuning then Exit; if On_ = FTuning then Exit;
if On_ and (ActiveTXMode = MODE_DMR) then Exit;
// Safety: те же блокировки, что и в SetMOX — TUN это TX через WDSP PostGen-тон, // Safety: те же блокировки, что и в SetMOX — TUN это TX через WDSP PostGen-тон,
// он тоже должен молчать на бэндах с DoNotTx и на RX-only XVTR. // он тоже должен молчать на бэндах с DoNotTx и на RX-only XVTR.
if On_ and FDevConnected and (FCurrentXvtr < 0) if On_ and FDevConnected and (FCurrentXvtr < 0)