Skip to content

CWX macro / Fx key TX leaves radio stuck in TX >60 s before returning to RX #2450

Description

@Juanjo-EA1CJ

Report preparation

  • I used the AI-assisted bug report tool (Help → Support → File an Issue)
  • I have attached a support bundle or log file

What happened?

After transmitting a CW macro — either via the CWX window or by pressing an Fx function key — the FLEX-6700 does not return to RX when the macro finishes sending. The radio remains stuck in TX state for more than 60 seconds before it eventually recovers on its own. There is no way to force it back to RX promptly from the UI during this window. This regression is reproducible since v0.9.6 and affects all amateur bands.

At the time of the diagnostic snapshot, the active TX slice (Slice 2) is in CW mode on 24.898 MHz (12m) with:

  • QSK = Yes
  • break_in = Yes
  • break_in_delay = 0 ms
  • sync_cwx = Yes
  • CW speed = 27 WPM

The radio correctly transmits the full macro content — the bug is exclusively in the TX teardown path after the last character is sent.

What did you expect?

After the last character of a CW macro is sent, the radio should immediately drop TX and return to RX. With break_in = Yes and break_in_delay = 0 ms, the transition should be instantaneous — this is the radio's normal QSK/break-in behaviour and it works correctly when keying with a hardware paddle. The transmitting flag should return to No and the interlock should clear within a fraction of a second of macro completion.

Steps to reproduce

  1. Connect to a FLEX-6700 (firmware 4.2.18.41174) via LAN.
  2. Set a slice to CW mode. Confirm QSK = Yes, Break-In = Yes, Break-In Delay = 0 ms.
  3. Open the CWX window and enter any macro text (e.g. CQ CQ DE <CALL> K), OR assign a macro to an Fx key.
  4. Trigger the macro via the CWX Send button or the Fx key.
  5. Observe the radio transmitting the macro correctly.
  6. When the last character finishes sending, observe that the radio does not return to RX.
  7. Time the delay — the radio remains in TX for more than 60 seconds before self-recovering.
  8. Repeat on other bands — issue is band-independent.

Regression introduced: v0.9.6
Last known-good version: v0.9.5 (or earlier)


Radio model & firmware

Field Value
Model FLEX-6700
Firmware 4.2.18.41174
Protocol 1.4.0.0

OS & version

Field Value
OS Windows 11 Version 25H2
AetherSDR 0.9.8
Qt 6.8.3 (x86_64)

Diagnostic snapshot (captured 2026-05-07T16:11:18)

Connection and ownership are healthy — this is not a multi-client or network issue.

Parameter Value
Connection LAN, RTT 5 ms (max 11 ms)
TX owned by us Yes
Multiple clients No
MOX (current) No
Transmitting (current) No
Interlock timeout 0 (disabled)
CW break-in Yes
CW break-in delay 0 ms
QSK (Slice 2) Yes
sync_cwx Yes
CW speed 27 WPM
TX forward power (idle) 0.00 W

All TX pipeline meters (TX-/8 *) are at −150 dBFS (floor), confirming the radio is in RX. The snapshot was captured after self-recovery.


Developer Notes

⚠️ Critical protocol constraints (from CLAUDE.md)

"The radio never sends mox= in transmit status messages. Use isTransmitting() (interlock state machine), NOT isMox()."

"cw key immediate not supported — use netcw UDP stream for CW keying."

"Correct break-in command: cw break_in 1 — NOT transmit set break_in=1."

These constraints are central to the root cause analysis below.


Suspected source files and functions

Primary suspects:

  • src/models/CwxModel.cpp / CwxModel.h
    The CWX model sends CW macros and must monitor the radio's cwx status for queue-empty events. Check whether the handler for the cwx status update (queue becoming empty or erase=1) correctly triggers TX teardown. If the model issues C<seq>|cwx send 2 "<text>" but never acts on the S<handle>|cwx ... status echo indicating completion, TX is never released.

  • src/models/TransmitModel.cpp / TransmitModel.h
    Check whether setMox(false) / the MOX-release path is called after CWX completion. Per the protocol note, isTransmitting() (interlock state) is authoritative — NOT isMox(). If CWX teardown was refactored in v0.9.6 to use isMox() as the guard, that would silently fail since MOX state is never echoed in status messages.

  • src/models/InterlockModel.cpp / InterlockModel.h
    The interlock state machine drives isTransmitting(). After CWX macro completion, the client must release the interlock. Verify that applyStatus() correctly parses reason= and tx_client_handle= fields and that the CWX completion path triggers a proper interlock release. A 60-second self-recovery time is consistent with the radio's hardware interlock safety timeout firing when the client holds the interlock indefinitely.

  • src/gui/CwxWindow.cpp (or equivalent applet)
    Verify that the CWX window Send button and the Fx key handler share the same code path. If Fx keys dispatch macros via a different slot that bypasses the CWX completion callback registration, that would explain the bug affecting both trigger methods equally since v0.9.6.

  • src/core/RadioCommandQueue.cpp (if present)
    Check whether a command batching or debounce change introduced in v0.9.6 delays the mox 0 or interlock-release command past the radio's guard timer.


Logging categories to enable

In Help → Support, enable the following before reproducing:

FlexTCP      — raw TCP send/receive (cwx, mox, interlock commands)
CWX          — CWX model state and queue events
Transmit     — MOX and transmit state transitions
Interlock    — interlock acquire/release and reason codes
SliceModel   — slice TX state changes

Reproduce the issue, wait for the 60-second self-recovery, then collect the full log.

Expected healthy log sequence:

[FlexTCP]   >> C42|cwx send 2 "CQ CQ DE <CALL> K"
[FlexTCP]   << R42|00000000|
[FlexTCP]   << S<handle>|cwx queue=   ← empty queue = macro done on radio
[CWX]       queue empty — triggering TX teardown
[FlexTCP]   >> C43|mox 0              ← this line MUST appear
[Interlock] reason= (cleared)
[Transmit]  isTransmitting() → false
  • If mox 0 never appears after CWX queue empties → TX teardown callback is broken client-side.
  • If mox 0 is sent but the radio does not respond → attach a Wireshark capture of the TCP session.

Potential root causes (ranked by likelihood)

  1. Missing mox 0 after CWX queue empty (most likely)
    A v0.9.6 change broke or removed the callback that sends mox 0 when the radio signals CWX macro completion (empty queue= field in the cwx status). The radio's own break-in timer does not fire because the client's mox is still asserted. The radio self-recovers via its hardware interlock safety timeout (~60 s).

  2. isTransmitting() vs isMox() confusion
    The radio never echoes mox= in status messages. If the v0.9.6 refactor introduced a guard like if (isMox()) { sendMox(false); } in the teardown path, it will never evaluate true and the TX release is silently skipped.

  3. sync_cwx=Yes missing paired MOX release
    The snapshot shows sync_cwx=Yes. If AetherSDR explicitly asserts mox 1 when sync_cwx is active, it must also explicitly send mox 0 on CWX completion. A missing paired release in this code path is a clean fit for the v0.9.6 regression.

  4. Interlock not released by client
    If InterlockModel is not issuing the correct interlock-release sequence, the radio holds TX until its own guard timer fires. With interlock timeout=0 (disabled in the snapshot), the ~60-second recovery is likely a firmware-internal safety watchdog.

  5. CWX / Fx key dispatch path divergence
    If both the CWX window and Fx keys exhibit the same symptom, they either share the broken code path or both register the same broken completion callback. Confirm that the Fx key handler calls the same CwxModel::send() entry point as the CWX window button.

aethersdr-slice-troubleshooting-20260507-161124.json

AetherSDR version

0.9.8

Radio model & firmware

Flex 6700 v4.2.18.41174

Operating system

Windows

OS version and hardware

Windows 11 25H2

Metadata

Metadata

Assignees

No one assigned

    Labels

    CWCW keying, decode, and operationWindowsWindows-specific issuebugSomething isn't workingmaintainer-reviewRequires maintainer review before any action is takenpriority: highHigh priorityprotocolSmartSDR protocolsafetyEquipment protection concern

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions