Summary
TransmitModel::setAmCarrierLevel(int level) sends the radio command but never updates its local member m_amCarrierLevel. It is the only TX setter missing the optimistic local-cache update that all its siblings perform, so transmitModel().amCarrierLevel() returns a stale value until the radio's asynchronous status echo arrives.
Location
src/models/TransmitModel.cpp, ~line 618:
void TransmitModel::setAmCarrierLevel(int level) {
level = qBound(0, level, 100);
emit commandReady(QString("transmit set am_carrier=%1").arg(level)); // <-- m_amCarrierLevel never set
}
Compare the sibling setters in the same file, which all cache locally before/with the signal:
setRfPower → sets m_rfPower, then emit stateChanged()
setMicLevel → sets m_micLevel, then emit micStateChanged()
setDexpLevel → sets m_dexpLevel (+ m_companderLevel), then emit phoneStateChanged()
FlexLib's own Radio.cs AMCarrierLevel property setter also caches locally before SendCommand.
Impact
After the GUI (or a TCI client, or the #3646 automation bridge's get transmit) changes AM carrier level, amCarrierLevel() stays stale until the radio echoes am_carrier_level= back (parsed in applyTransmitStatus, ~line 143). Any consumer that reads the value right after a change gets the old number.
Severity: low/cosmetic — the command itself is sent correctly and the radio applies it; the model just lags behind the widget instead of being immediately consistent.
Steps to reproduce
- Connect to a radio.
- Change the AM carrier level via the Phone applet slider (or
transmit set am_carrier=N).
- Immediately read
transmitModel().amCarrierLevel().
Observed: the value does not reflect the change until the radio's status echo arrives. Measured live on a FLEX-8400M: did not converge within a 2 s poll window, whereas RF power / mic gain / DEXP converge in ~0 ms because they update optimistically.
Expected: amCarrierLevel() reflects the new value immediately, like every other TX setpoint.
Suggested fix
Mirror the sibling pattern (AM carrier is a phone/VOX-group property, so emit phoneStateChanged()):
void TransmitModel::setAmCarrierLevel(int level) {
level = qBound(0, level, 100);
if (m_amCarrierLevel != level) {
m_amCarrierLevel = level;
emit phoneStateChanged();
}
emit commandReady(QString("transmit set am_carrier=%1").arg(level));
}
Notes for the fix:
- The command keyword
am_carrier is correct (matches FlexLib Radio.cs:8384) — do not change it.
- Verify no GUI feedback loop is introduced: the PhoneApplet AM-carrier slider's
valueChanged lambda (src/gui/PhoneApplet.cpp ~line 123) only calls setAmCarrierLevel when !m_updatingFromModel, and the model→widget sync (~line 398) uses a QSignalBlocker. Confirm a single user change does not produce repeated transmit set am_carrier commands.
How it was found
Surfaced during live QA on a FLEX-8400M using the #3646 agent automation bridge — model-level validation via get transmit caught the AM carrier slider not converging while every other TX control did.
Summary
TransmitModel::setAmCarrierLevel(int level)sends the radio command but never updates its local memberm_amCarrierLevel. It is the only TX setter missing the optimistic local-cache update that all its siblings perform, sotransmitModel().amCarrierLevel()returns a stale value until the radio's asynchronous status echo arrives.Location
src/models/TransmitModel.cpp, ~line 618:Compare the sibling setters in the same file, which all cache locally before/with the signal:
setRfPower→ setsm_rfPower, thenemit stateChanged()setMicLevel→ setsm_micLevel, thenemit micStateChanged()setDexpLevel→ setsm_dexpLevel(+m_companderLevel), thenemit phoneStateChanged()FlexLib's own
Radio.csAMCarrierLevelproperty setter also caches locally beforeSendCommand.Impact
After the GUI (or a TCI client, or the #3646 automation bridge's
get transmit) changes AM carrier level,amCarrierLevel()stays stale until the radio echoesam_carrier_level=back (parsed inapplyTransmitStatus, ~line 143). Any consumer that reads the value right after a change gets the old number.Severity: low/cosmetic — the command itself is sent correctly and the radio applies it; the model just lags behind the widget instead of being immediately consistent.
Steps to reproduce
transmit set am_carrier=N).transmitModel().amCarrierLevel().Observed: the value does not reflect the change until the radio's status echo arrives. Measured live on a FLEX-8400M: did not converge within a 2 s poll window, whereas RF power / mic gain / DEXP converge in ~0 ms because they update optimistically.
Expected:
amCarrierLevel()reflects the new value immediately, like every other TX setpoint.Suggested fix
Mirror the sibling pattern (AM carrier is a phone/VOX-group property, so emit
phoneStateChanged()):Notes for the fix:
am_carrieris correct (matches FlexLibRadio.cs:8384) — do not change it.valueChangedlambda (src/gui/PhoneApplet.cpp~line 123) only callssetAmCarrierLevelwhen!m_updatingFromModel, and the model→widget sync (~line 398) uses aQSignalBlocker. Confirm a single user change does not produce repeatedtransmit set am_carriercommands.How it was found
Surfaced during live QA on a FLEX-8400M using the #3646 agent automation bridge — model-level validation via
get transmitcaught the AM carrier slider not converging while every other TX control did.