feat: QO-100 self-monitor (RX MUTE) + gate beacon/RX-mute buttons to QO-100

Add a per-operator toggle to hear your own downlink off the satellite
while transmitting (full-duplex self-monitor), and restrict QO-100-only
controls to the QO-100 mode.

- WDSPEngine: new MonitorRXDuringTX flag; audio gate becomes
  `not FTXActive or (FKeepRXDuringTX and FMonitorRXDuringTX)` so RX audio
  can pass to speakers during TX in full-duplex.
- Controller: FRxMuteOnTx (default True = mute RX on TX), SetRxMuteOnTx/
  ApplyRxMuteToEngine, rfRxMuteOnTx notify; new InQO100 predicate
  (Pluto + full-duplex XVTR slot) as the single gate for QO-100 UI.
- Settings: global RxMuteOnTx (rx_mute_on_tx, default True), persisted.
- MainForm: new RX MUTE button in TX panel next to DUP, visible only in
  QO-100; BEACON button visibility tightened from "any transverter" to
  InQO100 so it no longer shows in plain VHF/UHF modes.
- doc: plan updated (RF-AGC done, two temps, TX/RX locked split,
  self-monitor, phase 6 done; remaining TODOs incl. web wiring).

Web intentionally left unchanged for now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 19:50:30 +03:00
co-authored by Claude Opus 4.8
parent 6375092741
commit 3bd37b956e
5 changed files with 117 additions and 11 deletions
+35 -1
View File
@@ -237,6 +237,7 @@ type
BtnCTun: TFlatButton;
BtnBeacon: TFlatButton; // QO-100 beacon lock (видим только на Pluto в трансвертере)
BtnDUP: TFlatButton;
BtnRxMute: TFlatButton; // QO-100 self-monitor: RX-аудио на TX (видим только Pluto+full-duplex)
PanelFMSQ: TPanel;
BtnFMSQ: TFlatButton;
TrkFMSQ: TFlatSlider;
@@ -387,6 +388,8 @@ type
procedure UpdateBeaconButton;
procedure BtnDUPClick(Sender: TObject);
procedure ApplyDUP(Active: Boolean);
procedure BtnRxMuteClick(Sender: TObject);
procedure UpdateRxMuteButton; // видимость (Pluto+full-duplex) + стиль кнопки RX MUTE
procedure BtnTUNClick(Sender: TObject);
procedure ApplyTUN(Active: Boolean);
procedure UpdateFilterButtons;
@@ -1212,9 +1215,12 @@ begin
// openHPSDR смысла не имеет (нет дрейфующего LNB → прячем).
if BtnBeacon <> nil then
begin
BtnBeacon.Visible := FController.IsPluto and (FController.FCurrentXvtr >= 0);
// Только Pluto + full-duplex транспондер (QO-100) — beacon-lock завязан
// на дрейф LNB, в обычных диапазонах/трансвертерах смысла нет.
BtnBeacon.Visible := FController.InQO100;
UpdateBeaconButton;
end;
UpdateRxMuteButton; // RX MUTE — только Pluto + full-duplex (QO-100)
// Wideband-вид + web-зеркало xvtr (ранее в обёртках Activate/Deactivate).
// rfXvtr эмитят ТОЛЬКО ActivateXvtr/DeactivateXvtr — состояние финальное.
UpdateWidebandFrequencyView;
@@ -1313,6 +1319,8 @@ begin
PbWaterfall.Invalidate;
end;
end;
rfRxMuteOnTx:
UpdateRxMuteButton; // QO-100 self-monitor toggle: подсветка кнопки RX MUTE
rfWfAGC:
FSpecView.WfAGCEnabled := FController.FWfAGCEnabled;
rfWfNF:
@@ -1707,6 +1715,15 @@ begin
BtnDUP.Tag := 0;
StyleButton(BtnDUP, FController.FDisplayDuplex);
// QO-100 self-monitor: рядом с DUP, col1. Виден только на Pluto в full-duplex
// транспондере. ON (подсвечена, умолч.) = RX-аудио глушится на TX; OFF = слышим
// свой downlink со спутника.
BtnRxMute := MakeBtn(PanelTX, 'RX MUTE',
LeftPanelButtonLeft(LEFT_W, 4, 1), 44,
LeftPanelButtonWidth(LEFT_W, 4, 1), BTN_SM, BtnRxMuteClick);
BtnRxMute.Visible := False;
StyleButton(BtnRxMute, FController.FRxMuteOnTx);
LblDrv := TLabel.Create(Self);
LblDrv.Parent := PanelTX; LblDrv.Left := 4; LblDrv.Top := 77;
LblDrv.Caption := 'DRV'; LblDrv.Font.Color := CLR_TEXTDIM;
@@ -3697,6 +3714,7 @@ begin
// Отдельный Pluto RF-AGC блок под AGC: показываем и сдвигаем панели ниже.
LayoutLeftPanel(Caps.HasHWGain);
if Caps.HasHWGain then UpdateRxGainUI;
UpdateRxMuteButton; // RX MUTE — видимость по Pluto + full-duplex (если QO-100 уже активен)
end;
procedure TMainForm.DoConnectDevice(const Dev: THPSDRDevice);
@@ -4032,6 +4050,22 @@ begin
ApplyDUP(not FController.FDisplayDuplex);
end;
procedure TMainForm.BtnRxMuteClick(Sender: TObject);
begin
FController.SetRxMuteOnTx(not FController.FRxMuteOnTx); // рендер через rfRxMuteOnTx
end;
procedure TMainForm.UpdateRxMuteButton;
// Кнопка RX MUTE видна только на Pluto в full-duplex транспондере (QO-100).
// ON (подсвечена) = RX-аудио глушится на TX; OFF = self-monitor (слышим себя).
var Vis: Boolean;
begin
if BtnRxMute = nil then Exit;
Vis := FController.InQO100;
BtnRxMute.Visible := Vis;
if Vis then StyleButton(BtnRxMute, FController.FRxMuteOnTx);
end;
// ---------------------------------------------------------------------------
// TUN — Thetis-style тон: WDSP TXA PostGen + MOX с отдельным уровнем Drive
// ---------------------------------------------------------------------------