Report preparation
What happened?
A TCI vfo:<trx>,0,<hz> SET tunes the radio correctly, but the vfo:
confirmation broadcast back to clients carries the frequency the slice was
already on, not the one it moved to. The stale value is echoed to the sending
client as well as observers.
Any client that accumulates a relative change — a rotary encoder, a band
stepper, anything doing "current + delta" — has its local value reset by that
echo and recomputes the next step from the same starting point. The radio
oscillates around one frequency instead of walking.
Observed with the bundled Elgato Stream Deck plugin's VFO Tuning encoder. Nine
detents produced nine distinct frequencies on the wire and ten identical echoes:
14365ms TX->tci vfo:1,0,28057600; <- plugin commands 28.0576
14453ms RX<-tci vfo:1,0,28058600 <- server confirms 28.0586 (unchanged)
15244ms TX->tci vfo:1,0,28056600;
15262ms RX<-tci vfo:1,0,28058600 <- unchanged again
...
18091ms TX->tci vfo:1,0,28049600; <- 9 kHz below where it started
18124ms RX<-tci vfo:1,0,28058600 <- still 28.0586
The same echo is what WSJT-X's do_frequency() waits on, so this is not
specific to control surfaces.
What did you expect?
The confirmation to carry the accepted frequency, so a client's mirror
converges on what the radio actually did.
Steps to reproduce
- Connect to a radio with at least one slice.
- Connect any TCI client to
ws://localhost:50001.
- Send
vfo:0,0,<current_hz - 2000>;
- Observe the broadcast that comes back.
Expected: vfo:0,0,<current_hz - 2000>;
Actual: vfo:0,0,<current_hz>; — the pre-tune value.
Repeat with a decreasing frequency each time and the confirmation never moves,
even though the radio does.
Root cause
TciServer::tuneSliceAndConfirm() (src/core/TciServer.cpp) writes
slice tune <id> <mhz> [autopan=0] straight at the connection via
RadioModel::sendCmdPublic(), then treats the command reply as a completion
barrier — re-reading settled->frequency() and broadcasting that:
// Flex status precedes this response. The reply is the completion
// barrier; publish the accepted coordinate to sender and observers.
SliceModel* settled = self->m_model ? self->m_model->slice(sliceId) : nullptr;
const long long acceptedHz = TciProtocol::mhzToHz(settled->frequency());
Two things defeat that:
- The raw command never touches
SliceModel, so m_frequency is not updated
by this path. Only the setters setFrequency() / tuneAndRecenter() do
that, and the GUI is what calls them.
- The comment's premise — "Flex status precedes this response" — does not hold
on this radio. It never emits a slice status carrying the new
RF_frequency at all (see evidence below).
So settled->frequency() can only ever observe the pre-tune value, and the
confirmation is stale by construction.
Evidence
Every captured session in ~/.config/AetherSDR/logs/ was checked — local TCP
and SmartLink, ~270 slice tune commands — with sub slice all active and
transmit / display / atu statuses flowing normally throughout.
Not one slice tune was ever followed by an RF_frequency status update.
A single tune, end to end, with aether.connection at debug:
19:21:57.164 TCI rx: "vfo:0,0,28422500;" <- client request
19:21:57.165 TX: "C1555|slice tune 0 28.422500 autopan=0" <- correct command
19:21:57.183 RX: "R1555|0|" <- radio replies SUCCESS
19:21:57.183 TCI tx→all: vfo:0,0,28424500; <- pre-tune value echoed
In one 25-minute session: 89 slice tune commands, 12 RF_frequency status
lines — all 12 from slice creation at startup. Slices 0/1/2 never changed
frequency in the model, though the radio physically moved each time.
The GUI is unaffected because SliceModel::setFrequency() updates
m_frequency locally and emits frequencyChanged, which is what reaches TCI
clients via wireSlice()'s broadcastSliceFrequencies().
Regression
Introduced by #4407 (05c5b805, refactor(tci): serialize split routing and
power replies). Before it, cmdVfo tuned through SliceModel::setFrequency()
/ tuneAndRecenter(), so the model updated and the notification carried the new
value. #4407 replaced that with the raw command plus the read-back barrier.
Worth noting for anyone bisecting: the underlying "radio never confirms a tune"
behaviour predates #4407. The optimistic model update was masking it, so this
surfaces as a #4407 regression but the missing status echo is older and is a
separate concern.
AetherSDR version
v26.7.3 (c9a2a5c)
Radio model & firmware
FLEX-6600, firmware v4.2.20
Operating system
Linux
OS version and hardware
Manjaro Linux
Report preparation
What happened?
A TCI
vfo:<trx>,0,<hz>SET tunes the radio correctly, but thevfo:confirmation broadcast back to clients carries the frequency the slice was
already on, not the one it moved to. The stale value is echoed to the sending
client as well as observers.
Any client that accumulates a relative change — a rotary encoder, a band
stepper, anything doing "current + delta" — has its local value reset by that
echo and recomputes the next step from the same starting point. The radio
oscillates around one frequency instead of walking.
Observed with the bundled Elgato Stream Deck plugin's VFO Tuning encoder. Nine
detents produced nine distinct frequencies on the wire and ten identical echoes:
The same echo is what WSJT-X's
do_frequency()waits on, so this is notspecific to control surfaces.
What did you expect?
The confirmation to carry the accepted frequency, so a client's mirror
converges on what the radio actually did.
Steps to reproduce
ws://localhost:50001.vfo:0,0,<current_hz - 2000>;Expected:
vfo:0,0,<current_hz - 2000>;Actual:
vfo:0,0,<current_hz>;— the pre-tune value.Repeat with a decreasing frequency each time and the confirmation never moves,
even though the radio does.
Root cause
TciServer::tuneSliceAndConfirm()(src/core/TciServer.cpp) writesslice tune <id> <mhz> [autopan=0]straight at the connection viaRadioModel::sendCmdPublic(), then treats the command reply as a completionbarrier — re-reading
settled->frequency()and broadcasting that:Two things defeat that:
SliceModel, som_frequencyis not updatedby this path. Only the setters
setFrequency()/tuneAndRecenter()dothat, and the GUI is what calls them.
on this radio. It never emits a slice status carrying the new
RF_frequencyat all (see evidence below).So
settled->frequency()can only ever observe the pre-tune value, and theconfirmation is stale by construction.
Evidence
Every captured session in
~/.config/AetherSDR/logs/was checked — local TCPand SmartLink, ~270
slice tunecommands — withsub slice allactive andtransmit/display/atustatuses flowing normally throughout.Not one
slice tunewas ever followed by anRF_frequencystatus update.A single tune, end to end, with
aether.connectionat debug:In one 25-minute session: 89
slice tunecommands, 12RF_frequencystatuslines — all 12 from slice creation at startup. Slices 0/1/2 never changed
frequency in the model, though the radio physically moved each time.
The GUI is unaffected because
SliceModel::setFrequency()updatesm_frequencylocally and emitsfrequencyChanged, which is what reaches TCIclients via
wireSlice()'sbroadcastSliceFrequencies().Regression
Introduced by #4407 (
05c5b805, refactor(tci): serialize split routing andpower replies). Before it,
cmdVfotuned throughSliceModel::setFrequency()/
tuneAndRecenter(), so the model updated and the notification carried the newvalue. #4407 replaced that with the raw command plus the read-back barrier.
Worth noting for anyone bisecting: the underlying "radio never confirms a tune"
behaviour predates #4407. The optimistic model update was masking it, so this
surfaces as a #4407 regression but the missing status echo is older and is a
separate concern.
AetherSDR version
v26.7.3 (c9a2a5c)
Radio model & firmware
FLEX-6600, firmware v4.2.20
Operating system
Linux
OS version and hardware
Manjaro Linux