Skip to content
1 change: 1 addition & 0 deletions docs/user/docs/before-you-transmit.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The checks are written so you can do them without putting a signal on the air. W
- Controller buttons can be bound to PTT, MOX or TUNE: [USB Control Surfaces](./usb-control-surfaces.md) (including serial PTT and foot switches), [MIDI Controller Mapping](./midi-controller-mapping.md), [Ulanzi Dial](./ulanzi-dial.md), [StreamDeck](./streamdeck.md) and the [FlexControl Tuning Knob](./flexcontrol-tuning-knob.md).
- CAT and TCI clients can key the radio. See [CAT Control](./cat-control.md) and [TCI Server](./tci-server.md).
- The automation bridge cannot key the transmitter unless **Allow TX via MCP** is ticked, which is off by default. Leave it off unless you need it. See [Automation Bridge and MCP](./automation-bridge-and-mcp.md).
- [ ] **(FlexRadio, firmware v4.3 and later)** **You know what your footswitch transmits.** A hardware PTT now sends the selected TX source, DAX or PC audio included, unless **PTT Mic Override** is on. See [Hardware PTT and the TX source](./tx-controls.md#hardware-ptt-and-the-tx-source).
- [ ] **(FlexRadio)** **The radio's transmit time-out and interlocks are set:** **Timeout (sec):** and the **Interlocks - TX REQ** group on the **Transmit** page of Radio Setup. See [Radio Setup](./radio-setup.md).
- [ ] **You can see when you are transmitting.** A green `M:SS` transmit timer appears in the title bar, just left of **PC Audio**, for each of your own transmissions, and the VFO marker turns orange/red. If an interlock blocks transmit, a notification says why. See [TX Controls](./tx-controls.md).

Expand Down
2 changes: 1 addition & 1 deletion docs/user/docs/radio-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ their nicknames on this computer.
| Page | What it covers |
|------|----------------|
| **Audio** | The radio's Line Out, Headphone and Front Speaker outputs; audio compression for SmartLink and tailnet connections; packet-loss smoothing; **Prevent system sleep while connected**; PC audio devices, Audio Boost and Audio Buffer; recording. See [Audio Settings](./audio-settings.md). |
| **Transmit** | TX timings (ACC TX, TX delay, timeout), TX REQ interlock polarity (RCA, Accessory), Max Power, Show TX in Waterfall, Slice/TX Follow, and **TX Band Settings** (per-band RF/tune power, PTT inhibit and interlocks). The Show TX in Waterfall choice is remembered per [Hermes-Lite 2](./hermes-lite-2.md); a FlexRadio owns and reports its setting. See [TX Controls](./tx-controls.md). |
| **Transmit** | TX timings (ACC TX, TX delay, timeout), TX REQ interlock polarity (RCA, Accessory), **PTT Mic Override** (firmware v4.3 and later; see [TX Controls](./tx-controls.md#hardware-ptt-and-the-tx-source)), Max Power, Show TX in Waterfall, Slice/TX Follow, and **TX Band Settings** (per-band RF/tune power, PTT inhibit and interlocks). The Show TX in Waterfall choice is remembered per [Hermes-Lite 2](./hermes-lite-2.md); a FlexRadio owns and reports its setting. See [TX Controls](./tx-controls.md). |
| **Phone & CW** | Microphone bias and +20 dB boost; CW iambic mode, paddle swap, sideband and CWX sync, and CW decoder RX/TX decode; Digital (RTTY mark default). See [CW Decoder](./cw-decoder.md) and [CWX Panel](./cwx-panel.md). |
| **Receive** | Frequency offset (GPSDO detection, manual calibration) and the 10 MHz reference source |
| **Filters** | Voice, CW and Digital filter sharpness (Low Latency ↔ Sharp Filters) with Auto buttons, and **Use Low Latency Filters for Digital Modes** |
Expand Down
19 changes: 19 additions & 0 deletions docs/user/docs/tx-controls.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,25 @@ CW is excluded, and the card is not available on the Hermes-Lite 2.
not allowed) appear as notifications, only when transmit is actually
blocked

### Hardware PTT and the TX source

**(FlexRadio)** A hardware PTT is a footswitch or keying line on the RCA PTT
jack, the ACC connector or a supported mic-jack PTT input. On firmware before
SmartSDR v4.3, a hardware PTT always transmits the analog microphone. **From
v4.3, a hardware PTT transmits whatever TX source is selected**, just as MOX
does. If DAX is on for a digital-mode program, or the mic source is PC, a
footswitch press puts that audio on the air, not your microphone.

To restore the old behavior, turn on **PTT Mic Override** in the
**Interlocks - TX REQ** group of **Settings → Radio Setup... → Transmit**.
With it on, a hardware PTT transmits the analog mic input you last used, even
while DAX or PC audio is selected. It changes nothing when an analog input
(MIC, BAL, LINE or ACC) is already selected. The radio stores the setting and
shares it with every client connected to it. With several clients connected
(Multi-Flex), FlexRadio says the override applies when the client whose
hardware PTT is pressed is also the transmitting client. On firmware before
v4.3 the control is grayed out.

### Transmit timer

While you transmit, a green `M:SS` timer (`H:MM:SS` after an hour) appears in
Expand Down
1 change: 1 addition & 0 deletions docs/user/docs/wsjt-x-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ AetherSDR can listen to WSJT-X's UDP decode messages and put the stations it dec
- FT8 transmitted on slice B can show heavy ALC and be decoded far less often than the same signal on slice A ([#5340](https://github.com/aethersdr/AetherSDR/issues/5340)).
- Over TCI, the mic profile, **MIC** level and **PROC** in the Phone/CW applet change the transmitted digital signal ([#5844](https://github.com/aethersdr/AetherSDR/issues/5844)).
- Over TCI, the transmitted FT8 signal can show random jumps ([#5133](https://github.com/aethersdr/AetherSDR/issues/5133)).
- **(FlexRadio, firmware v4.3 and later)** A footswitch or other hardware PTT transmits the selected TX source, so with DAX on it sends WSJT-X's audio, not your microphone. Turn on **PTT Mic Override** to make a hardware PTT use the microphone instead. See [Hardware PTT and the TX source](./tx-controls.md#hardware-ptt-and-the-tx-source).
- On macOS, DAX transmit can stop sending audio to the radio until AetherSDR is restarted ([#5870](https://github.com/aethersdr/AetherSDR/issues/5870)).

## Troubleshooting
Expand Down
4 changes: 4 additions & 0 deletions src/core/AutomationServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@
#include <QLocalServer>
#include <QScopeGuard>
#include <QLocalSocket>
#include <QApplication>

Check warning on line 38 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QApplication) — tracked legacy (baseline 20); the count may only shrink
#include <QScreen>
#include <QWidget>

Check warning on line 40 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QWidget) — tracked legacy (baseline 20); the count may only shrink
#include <QMainWindow>

Check warning on line 41 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QMainWindow) — tracked legacy (baseline 20); the count may only shrink
#include <QMenu>

Check warning on line 42 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QMenu) — tracked legacy (baseline 20); the count may only shrink
#include <QMenuBar>

Check warning on line 43 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QMenuBar) — tracked legacy (baseline 20); the count may only shrink
#include <QTabBar>

Check warning on line 44 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QTabBar) — tracked legacy (baseline 20); the count may only shrink
#include <QEnterEvent>
#include <QMouseEvent>
#include <QWheelEvent>
Expand Down Expand Up @@ -78,12 +78,12 @@
#include <utility>

// Best-effort value extraction for common control types.
#include <QAbstractButton>

Check warning on line 81 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QAbstractButton) — tracked legacy (baseline 20); the count may only shrink
#include <QAbstractSlider>

Check warning on line 82 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QAbstractSlider) — tracked legacy (baseline 20); the count may only shrink
#include <QAbstractItemView>

Check warning on line 83 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QAbstractItemView) — tracked legacy (baseline 20); the count may only shrink
#include <QPersistentModelIndex>
#include <QItemSelectionModel>
#include <QComboBox>

Check warning on line 86 in src/core/AutomationServer.cpp

View workflow job for this annotation

GitHub Actions / Static checks

EB2-known

src/core/AutomationServer.cpp uses QtWidgets (QComboBox) — tracked legacy (baseline 20); the count may only shrink
#include <QLineEdit>
#include "AutomationSensitiveLineEdit.h"
#include <QLabel>
Expand Down Expand Up @@ -1922,6 +1922,10 @@
snapshot.insert(QStringLiteral("txFilterLow"), t->txFilterLow());
snapshot.insert(QStringLiteral("txFilterHigh"), t->txFilterHigh());
}
// Absent until the radio reports it: firmware before v4.3 has no such key.
if (t->havePttMicOverride()) {
snapshot.insert(QStringLiteral("pttMicOverride"), t->pttMicOverride());
}
return snapshot;
}

Expand Down
4 changes: 3 additions & 1 deletion src/core/backends/ModelControlRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct TransmitControlRequest {
ExpanderEnabled, ExpanderLevel, Filter, CwSpeed, CwPitch, CwBreakIn,
CwDelay, CwSidetone, CwIambic, CwIambicMode, CwSwap, CwlEnabled,
CwMonitorGain, CwMonitorPan, TxProfile, MicProfile, ApdEnabled,
ApdSampler, ApdReset, AtuMemories, AtuClear, Count
ApdSampler, ApdReset, AtuMemories, AtuClear, PttMicOverride, Count
};
using Value = std::variant<bool, int, QString, ProcessorSetting, VoxSetting,
MonitorSetting, TxPassband, ApdSamplerSetting>;
Expand Down Expand Up @@ -158,6 +158,7 @@ inline bool TransmitControlRequest::valid() const
case Field::ExpanderEnabled: case Field::CwBreakIn: case Field::CwSidetone:
case Field::CwIambic: case Field::CwSwap: case Field::CwlEnabled:
case Field::ApdEnabled: case Field::ApdReset: case Field::AtuMemories: case Field::AtuClear:
case Field::PttMicOverride:
return std::holds_alternative<bool>(value);
case Field::Count: return false;
}
Expand Down Expand Up @@ -238,6 +239,7 @@ inline QString TransmitControlRequest::label() const
case Field::ApdSampler: return QStringLiteral("apd sampler");
case Field::ApdReset: return QStringLiteral("apd reset");
case Field::AtuMemories: return QStringLiteral("atu memories");
case Field::PttMicOverride: return QStringLiteral("ptt mic override");
case Field::AtuClear: return QStringLiteral("atu clear");
case Field::Count: break;
}
Expand Down
1 change: 1 addition & 0 deletions src/core/backends/TransmitDelta.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct TransmitDelta {
std::optional<QString> txSliceMode;
std::optional<bool> showTxInWaterfall;
std::optional<bool> metInRx;
std::optional<bool> pttMicOverride; // v4.3+ firmware only

// ── Mic / monitor / processor ──
std::optional<QString> micSelection; // uppercased
Expand Down
5 changes: 5 additions & 0 deletions src/core/backends/flex/FlexBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,11 @@ void FlexBackend::decodeTransmitStatus(const QMap<QString, QString>& kvs)
carry(kvs, "mic_boost", d.micBoost);
carry(kvs, "mic_bias", d.micBias);
carry(kvs, "met_in_rx", d.metInRx);
// FlexLib 4.3.16.42034 rejects anything but 0/1 (Radio.cs:11151-11163):
// a malformed value must not confirm "off" or mark the key as reported.
if (const std::optional<int> v = parseInt(kvs, "ptt_mic_override"); v && (*v == 0 || *v == 1)) {
d.pttMicOverride = (*v == 1);
}
carry(kvs, "synccwx", d.syncCwx);
carryClamp(kvs, "am_carrier_level", d.amCarrierLevel, 0, 100);
// dexp / noise_gate_level alias compander / compander_level, but only when
Expand Down
2 changes: 2 additions & 0 deletions src/core/backends/flex/FlexModelControls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ ReceiveDispatch FlexBackend::requestTransmitControl(const TransmitControlRequest
command = QStringLiteral("apd enable=") + QString::number(int(std::get<bool>(request.value))); break;
case Field::AtuMemories:
command = QStringLiteral("atu set memories_enabled=") + QString::number(int(std::get<bool>(request.value))); break;
case Field::PttMicOverride:
command = QStringLiteral("transmit set ptt_mic_override=") + QString::number(int(std::get<bool>(request.value))); break;
case Field::ProcessorEnabled: case Field::ProcessorLevel: {
const ProcessorSetting setting = std::get<ProcessorSetting>(request.value);
if (request.field == Field::ProcessorLevel && setting.level > 2) {
Expand Down
3 changes: 2 additions & 1 deletion src/core/backends/hl2/Hl2Backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3338,7 +3338,8 @@ ReceiveDispatch Hl2Backend::requestTransmitControl(const TransmitControlRequest&
case Field::MicBias: case Field::AmCarrier: case Field::ExpanderEnabled:
case Field::ExpanderLevel: case Field::CwlEnabled: case Field::TxProfile:
case Field::MicProfile: case Field::ApdEnabled: case Field::ApdSampler:
case Field::ApdReset: case Field::AtuMemories: case Field::AtuClear: case Field::Count:
case Field::ApdReset: case Field::AtuMemories: case Field::AtuClear:
case Field::PttMicOverride: case Field::Count:
return ReceiveDispatch::Unsupported;
}
return ReceiveDispatch::Dispatched;
Expand Down
3 changes: 2 additions & 1 deletion src/core/backends/icom/IcomCivBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4521,7 +4521,8 @@ ReceiveDispatch IcomCivBackend::requestTransmitControl(const TransmitControlRequ
case Field::CwIambicMode: case Field::CwSwap: case Field::CwlEnabled:
case Field::CwMonitorGain: case Field::CwMonitorPan: case Field::TxProfile:
case Field::MicProfile: case Field::ApdEnabled: case Field::ApdSampler:
case Field::ApdReset: case Field::AtuMemories: case Field::AtuClear: case Field::Count:
case Field::ApdReset: case Field::AtuMemories: case Field::AtuClear:
case Field::PttMicOverride: case Field::Count:
return ReceiveDispatch::Unsupported;
}
return ReceiveDispatch::Dispatched;
Expand Down
46 changes: 45 additions & 1 deletion src/gui/RadioSetupDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,7 @@
addPage(signalCategory, QStringLiteral("Audio"),
QStringLiteral("speaker microphone device sample rate latency sound dax"), [this] { return buildAudioTab(); });
addPage(signalCategory, QStringLiteral("Transmit"),
QStringLiteral("tx transmit rf power tune ptt band settings"), [this] { return buildTxTab(); });
QStringLiteral("tx transmit rf power tune ptt mic override band settings"), [this] { return buildTxTab(); });
addPage(signalCategory, QStringLiteral("Phone & CW"),
QStringLiteral("phone cw keyer break-in sidetone microphone voice"), [this] { return buildPhoneCwTab(); });
addPage(signalCategory, QStringLiteral("Receive"),
Expand Down Expand Up @@ -2636,7 +2636,7 @@
// make that visible rather than letting a toggle silently no-op.
if (AutomationBridgeSettings::envForced()) {
mcpBtn->setEnabled(false);
mcpBtn->setToolTip(mcpBtn->toolTip()

Check warning on line 2639 in src/gui/RadioSetupDialog.cpp

View workflow job for this annotation

GitHub Actions / Static checks

a11y-disabled-reason-not-announced

`mcpBtn` is disabled and given a tooltip reason, but no accessibleDescription (widget) or statusTip (QAction) nearby in the same block. Put the reason on the accessible channel as well as the tooltip. (#5262 M3a doctrine, #4896)
+ "\n\nForced on by the AETHER_AUTOMATION launch environment variable.");
}
m_automationBridgeBtn = mcpBtn;
Expand Down Expand Up @@ -2724,11 +2724,11 @@
+ DocsLinks::automationBridge());
if (envBlocksTx) {
txCheck->setEnabled(false);
txCheck->setToolTip(txCheck->toolTip()

Check warning on line 2727 in src/gui/RadioSetupDialog.cpp

View workflow job for this annotation

GitHub Actions / Static checks

a11y-disabled-reason-not-announced

`txCheck` is disabled and given a tooltip reason, but no accessibleDescription (widget) or statusTip (QAction) nearby in the same block. Put the reason on the accessible channel as well as the tooltip. (#5262 M3a doctrine, #4896)
+ "\n\nPinned off by the AETHER_AUTOMATION_NO_TX launch variable.");
} else if (envForcesTx) {
txCheck->setEnabled(false);
txCheck->setToolTip(txCheck->toolTip()

Check warning on line 2731 in src/gui/RadioSetupDialog.cpp

View workflow job for this annotation

GitHub Actions / Static checks

a11y-disabled-reason-not-announced

`txCheck` is disabled and given a tooltip reason, but no accessibleDescription (widget) or statusTip (QAction) nearby in the same block. Put the reason on the accessible channel as well as the tooltip. (#5262 M3a doctrine, #4896)
+ "\n\nForced on by the AETHER_AUTOMATION_ALLOW_TX launch variable.");
}
connect(txCheck, &QCheckBox::toggled, this, [this, txCheck](bool on) {
Expand Down Expand Up @@ -2799,7 +2799,7 @@
+ DocsLinks::automationBridge());
if (envForcesRo) {
roCheck->setEnabled(false);
roCheck->setToolTip(roCheck->toolTip()

Check warning on line 2802 in src/gui/RadioSetupDialog.cpp

View workflow job for this annotation

GitHub Actions / Static checks

a11y-disabled-reason-not-announced

`roCheck` is disabled and given a tooltip reason, but no accessibleDescription (widget) or statusTip (QAction) nearby in the same block. Put the reason on the accessible channel as well as the tooltip. (#5262 M3a doctrine, #4896)
+ "\n\nForced on by the AETHER_AUTOMATION_READONLY launch variable.");
}
connect(roCheck, &QCheckBox::toggled, this, [this](bool on) {
Expand Down Expand Up @@ -2949,7 +2949,7 @@
dhcpBtn->setCheckable(true);
dhcpBtn->setChecked(!isStatic);
dhcpBtn->setEnabled(canConfigure);
dhcpBtn->setToolTip(canConfigure ? QString() : unavailableTip);

Check warning on line 2952 in src/gui/RadioSetupDialog.cpp

View workflow job for this annotation

GitHub Actions / Static checks

a11y-disabled-reason-not-announced

`dhcpBtn` is disabled and given a tooltip reason, but no accessibleDescription (widget) or statusTip (QAction) nearby in the same block. Put the reason on the accessible channel as well as the tooltip. (#5262 M3a doctrine, #4896)
setButtonRole(dhcpBtn, ButtonRole::Select);
btnRow->addWidget(dhcpBtn);

Expand All @@ -2958,7 +2958,7 @@
staticBtn->setCheckable(true);
staticBtn->setChecked(isStatic);
staticBtn->setEnabled(canConfigure);
staticBtn->setToolTip(dhcpBtn->toolTip());

Check warning on line 2961 in src/gui/RadioSetupDialog.cpp

View workflow job for this annotation

GitHub Actions / Static checks

a11y-disabled-reason-not-announced

`staticBtn` is disabled and given a tooltip reason, but no accessibleDescription (widget) or statusTip (QAction) nearby in the same block. Put the reason on the accessible channel as well as the tooltip. (#5262 M3a doctrine, #4896)
setButtonRole(staticBtn, ButtonRole::Select);
btnRow->addWidget(staticBtn);

Expand Down Expand Up @@ -3242,6 +3242,50 @@
AetherSDR::applyComboStyle(accCmb);
grid->addWidget(accCmb, 0, 3);

// PTT Mic Override (SmartSDR v4.3, SMART-9340): from 4.3 a hardware
// PTT transmits the selected TX source, DAX and remote audio included;
// on, it forces the analog mic as firmware before 4.3 always did.
// Radio-wide, and only a 4.3 radio reports it (#6442).
auto* pttOvrLbl = new QLabel("PTT Mic Override:");
applyLabelStyle(pttOvrLbl);
grid->addWidget(pttOvrLbl, 1, 0);
auto* pttOvrBtn = new QPushButton;
pttOvrBtn->setCheckable(true);
setButtonRole(pttOvrBtn, ButtonRole::Select);
pttOvrBtn->setAccessibleName(tr("PTT Mic Override"));
grid->addWidget(pttOvrBtn, 1, 1, Qt::AlignLeft);
const auto syncPttOverride = [this, pttOvrBtn]() {
const auto& t = m_model->transmitModel();
const bool reported = t.havePttMicOverride();
QSignalBlocker block(pttOvrBtn);
pttOvrBtn->setChecked(t.pttMicOverride());
pttOvrBtn->setText(t.pttMicOverride() ? "Enabled" : "Disabled");
pttOvrBtn->setEnabled(reported);
const QString tip = reported
? tr("Enabled: a hardware PTT (RCA PTT jack, ACC or mic-jack PTT) "
"transmits the analog mic, even when DAX or PC audio is the TX source.\n"
"Disabled (firmware 4.3 default): a hardware PTT transmits the "
"selected TX source, as MOX does.\n"
"This setting is shared by every client on the radio.")
: tr("Requires SmartSDR v4.3 firmware or later. Earlier firmware "
"always transmits the analog mic on a hardware PTT.");
pttOvrBtn->setToolTip(tip);
pttOvrBtn->setAccessibleDescription(tip);
};
syncPttOverride();
// The button shows the radio's value: a click only requests the change
// and snaps back, and the transmit-status echo moves it.
connect(pttOvrBtn, &QPushButton::toggled, this, [this, syncPttOverride](bool on) {
m_model->transmitModel().setPttMicOverride(on);
syncPttOverride();
});
connect(&tx, &TransmitModel::stateChanged, pttOvrBtn, syncPttOverride);
// resetState() on disconnect announces through micStateChanged, not
// stateChanged; without this the page keeps the last session's value.
connect(&tx, &TransmitModel::micStateChanged, pttOvrBtn, syncPttOverride);
// A family switch clears the report without either signal.
connect(m_model, &RadioModel::backendRebuilt, pttOvrBtn, syncPttOverride);

vbox->addWidget(group);
}

Expand Down Expand Up @@ -5054,14 +5098,14 @@
// Static text, so a name is safe here -- and needed: "Apply" and
// "Discard" alone say nothing about what is being applied or discarded.
applyBtn->setAccessibleName(QStringLiteral("Apply the measured droop correction"));
applyBtn->setToolTip(QStringLiteral(

Check warning on line 5101 in src/gui/RadioSetupDialog.cpp

View workflow job for this annotation

GitHub Actions / Static checks

a11y-disabled-reason-not-announced

`applyBtn` is disabled and given a tooltip reason, but no accessibleDescription (widget) or statusTip (QAction) nearby in the same block. Put the reason on the accessible channel as well as the tooltip. (#5262 M3a doctrine, #4896)
"Push the measured tables live and save them for this radio"));

auto* cancelBtn = new QPushButton("Discard");
cancelBtn->setFixedWidth(90);
cancelBtn->setEnabled(false);
cancelBtn->setAccessibleName(QStringLiteral("Discard the measured droop correction"));
cancelBtn->setToolTip(QStringLiteral("Drop the measured (not yet applied) result"));

Check warning on line 5108 in src/gui/RadioSetupDialog.cpp

View workflow job for this annotation

GitHub Actions / Static checks

a11y-disabled-reason-not-announced

`cancelBtn` is disabled and given a tooltip reason, but no accessibleDescription (widget) or statusTip (QAction) nearby in the same block. Put the reason on the accessible channel as well as the tooltip. (#5262 M3a doctrine, #4896)

auto* applyRow = new QHBoxLayout;
applyRow->addWidget(applyBtn);
Expand Down Expand Up @@ -6643,7 +6687,7 @@
resumeDelayCheck->setEnabled(!profile.keepAudioDuringTx);
resumeDelayCheck->setAccessibleName(
"Resume KiwiSDR audio after transmit delay");
resumeDelayCheck->setToolTip(

Check warning on line 6690 in src/gui/RadioSetupDialog.cpp

View workflow job for this annotation

GitHub Actions / Static checks

a11y-disabled-reason-not-announced

`resumeDelayCheck` is disabled and given a tooltip reason, but no accessibleDescription (widget) or statusTip (QAction) nearby in the same block. Put the reason on the accessible channel as well as the tooltip. (#5262 M3a doctrine, #4896)
"After unkeying, wait out this receiver's stream delay "
"before unmuting, so you rejoin on audio received after "
"your transmission ended instead of hearing your own "
Expand Down
4 changes: 4 additions & 0 deletions src/gui/SliceTroubleshootingDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,10 @@ QString SliceTroubleshootingDialog::buildSummary(const QJsonObject& snapshot)
.arg(mic["am_carrier_level"].toInt())
.arg(mic["tx_filter_low"].toInt())
.arg(mic["tx_filter_high"].toInt());
if (mic.contains("ptt_mic_override")) {
lines << QString("- PTT mic override: `%1`")
.arg(yesNo(mic["ptt_mic_override"].toBool()));
}
lines << QString("- VOX: enabled `%1`, level `%2`, delay `%3`")
.arg(yesNo(vox["enabled"].toBool()))
.arg(vox["level"].toInt())
Expand Down
4 changes: 4 additions & 0 deletions src/models/RadioModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1736,6 +1736,7 @@ void RadioModel::teardownBackend()
// radio's confirmed drive. resetPowerProvenance(), not resetState(): one caller
// is ~RadioModel(), and resetState() emits TX signals.
m_transmitModel.resetPowerProvenance();
m_transmitModel.resetPttMicOverrideReport();
m_backend.reset();
m_cwPitchHandedToBackend = -1; // the next backend has been handed nothing
acknowledgeTxTransportTeardown(m_txOperation);
Expand Down Expand Up @@ -13028,6 +13029,9 @@ QJsonObject RadioModel::troubleshootingSnapshot() const
mic["mic_boost"] = m_transmitModel.micBoost();
mic["mic_bias"] = m_transmitModel.micBias();
mic["met_in_rx"] = m_transmitModel.metInRx();
if (m_transmitModel.havePttMicOverride()) {
mic["ptt_mic_override"] = m_transmitModel.pttMicOverride();
}
mic["sync_cwx"] = m_transmitModel.syncCwx();
mic["am_carrier_level"] = m_transmitModel.amCarrierLevel();
mic["dexp_on"] = m_transmitModel.dexpOn();
Expand Down
18 changes: 18 additions & 0 deletions src/models/TransmitModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ void TransmitModel::resetState()
m_memoriesEnabled = false;
m_usingMemory = false;
m_showTxInWaterfall = false;
resetPttMicOverrideReport();
// Radio-reported; a new session re-reports it. A radio with no Flex command
// plane never echoes dax=, so a Flex session's DAX=on must not survive into
// it and hold the client TX chain's MIC-ready indicator off (#5871).
Expand Down Expand Up @@ -206,6 +207,13 @@ void TransmitModel::applyChanges(const TransmitDelta& d)
if (provenanceMoved) emit powerProvenanceChanged();
changed |= assign(d.tuneMode, m_tuneMode);
changed |= assign(d.showTxInWaterfall, m_showTxInWaterfall);
// Latch on presence: pre-4.3 firmware never sends the key, and a 4.3 radio
// reporting the 0 default leaves the value unchanged.
if (d.pttMicOverride && !m_havePttMicOverride) {
m_havePttMicOverride = true;
changed = true;
}
changed |= assign(d.pttMicOverride, m_pttMicOverride);
if (assign(d.txSliceMode, m_txSliceMode)) { changed = true; emit txSliceModeChanged(m_txSliceMode); }

// ── Interlock (no emit — plain state, matching applyInterlockStatus) ──
Expand Down Expand Up @@ -909,6 +917,16 @@ void TransmitModel::setMicBias(bool on)
emit controlRequested({field, on});
}

void TransmitModel::setPttMicOverride(bool on)
{
if (refuseControlOffThread()) { return; }
const auto field = TransmitControlRequest::Field::PttMicOverride;
captureControlIntent(field);
// Not optimistic: the setting is radio-wide and the radio echoes it in
// transmit status, so the model changes only on that echo.
emit controlRequested({field, on});
}

void TransmitModel::setAmCarrierLevel(int level)
{
if (refuseControlOffThread()) { return; }
Expand Down
16 changes: 16 additions & 0 deletions src/models/TransmitModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ class TransmitModel : public QObject {
m_haveMaxPowerLevel = false;
m_rfPowerFromRadio = false;
}
// The radio-reported PTT mic override belongs to the radio that reported it,
// so a family switch clears it too (#6442). Non-emitting, like
// resetPowerProvenance() and for the same caller (teardownBackend(), from
// ~RadioModel()); RadioModel::backendRebuilt tells an open view.
void resetPttMicOverrideReport() {
m_pttMicOverride = false;
m_havePttMicOverride = false;
}
int tunePower() const { return m_tunePower; }
bool isTuning() const { return m_tune; }
// CW admission while TUNE is active (#5422; FLEX-8400 fw 4.2.20): `cw key 1`
Expand Down Expand Up @@ -175,6 +183,11 @@ class TransmitModel : public QObject {
int interlockTimeout() const { return m_interlockTimeout; }
int accTxReqPolarity() const { return m_accTxReqPolarity; }
int rcaTxReqPolarity() const { return m_rcaTxReqPolarity; }
// Hardware PTT (RCA/ACC/mic jack) forces the analog mic even while DAX or
// remote audio is the TX source. Radio-wide; firmware v4.3+ only, so
// havePttMicOverride() says whether this radio has reported it (#6442).
bool pttMicOverride() const { return m_pttMicOverride; }
bool havePttMicOverride() const { return m_havePttMicOverride; }
int maxPowerLevel() const { return m_maxPowerLevel; }
// Latches haveMaxPowerLevel() on PRESENCE, not on change: a radio reporting
// 100 into a model already at the 100 default must still count as reported,
Expand Down Expand Up @@ -393,6 +406,7 @@ class TransmitModel : public QObject {
void setVoxDelay(int delay);
void setMicBoost(bool on);
void setMicBias(bool on);
void setPttMicOverride(bool on);
void setAmCarrierLevel(int level);
void setDexp(bool on);
void setDexpLevel(int level);
Expand Down Expand Up @@ -646,6 +660,8 @@ class TransmitModel : public QObject {
int m_interlockTimeout{0};
int m_accTxReqPolarity{0};
int m_rcaTxReqPolarity{0};
bool m_pttMicOverride{false}; // v4.3 firmware default
bool m_havePttMicOverride{false};
int m_maxPowerLevel{100};
QString m_tuneMode{"single_tone"};
bool m_tuneAvailable = true;
Expand Down
Loading
Loading