Symptom
When MIDI straight-key or paddle keying triggers RadioModel::sendCwKey/sendCwPaddle, the radio does not transition to TX (no RF output, no state=TRANSMIT interlock status). This affects all CW keying via netCW UDP — straight key, paddle, and CWX-driven local keyer.
CWX text macros via cwx send work fine (different protocol path), and SmartSDR on Windows keys this same radio without issue, so this is AetherSDR-specific.
Reproduction
- Set slice 0 to mode=CW, break_in=1, qsk=1
- Connect a MIDI controller mapped to CW Straight Key
- Press the MIDI button
- Observe: no transmit, no interlock state change
Log evidence
Every TCP fallback of cw key/cw ptt returns 0x50001000 ("command not supported"):
TX: "C72|cw ptt 1 time=0xc5e56538 index=1 client_handle=0x70000d28"
TX: "C73|cw key 1 time=0xc5e56538 index=2 client_handle=0x70000d28"
RX: "R72|50001000|"
RX: "R73|50001000|"
This TCP rejection is expected — those decorated commands are netCW-UDP-only in FlexLib. But the UDP path also produces no observable effect:
- 4 redundant UDP packets are sent at 0/5/10/15 ms (
PanadapterStream::sendToRadio confirms sent=85 sent=85 sent=85 sent=85).
- Radio interlock state stays at
READY throughout — never PTT_REQUESTED, never TRANSMIT.
- Radio sends no status update of any kind in response.
What we ruled out
Several FlexLib-alignment fixes shipped in PR #1969 made the wire format byte-identical to FlexLib reference, but none changed the symptom:
- PTT pairing (
Radio.cs:8890-8965): sendCwKey now wraps cw key with cw ptt 1 on press and cw ptt 0 on release.
- No payload padding (
NetCWStream.cs:107-163): payload is now exact tx_data.Length bytes — 57-byte command produces an 85-byte datagram, not 88.
- Per-datagram unique packet_count: each of the 4 redundant UDP datagrams gets its own incrementing VITA-49 packet_count (N, N+1, N+2, N+3) instead of all four sharing N.
- Program name: tested both
client program AetherSDR (rejected as "unknown client program", error 10000002) and client program SmartSDR-Maestro (also rejected). Neither name unlocks the netCW path, so the 10000002 reply appears informational, not a gate.
VITA-49 packet structure verified against VitaOpusDataPacket.ToBytesTX:
- Word 0: pkt_type=ExtDataWithStream(3), C=1, T=0, TSI=Other(3), TSF=SampleCount(1), packet_count, packet_size
- Word 1: stream_id (assigned via
stream create netcw)
- Words 2-3: ClassID OUI=0x001C2D, ICC=0x534C, PCC=0x03E3
- Words 4-6: zeroed timestamps
- Then ASCII payload at offset 28
All match FlexLib byte-for-byte.
Hypotheses still open
- A subtle byte difference we haven't noticed — best resolved with a pcap diff between SmartSDR and AetherSDR keying the same radio.
- A missing pre-flight command the radio expects before honoring netCW from a given client (e.g. some
client set or interlock/transmit setup).
- netCW handler gated on something other than program name — e.g. client UUID whitelist or a feature flag we don't query.
Next step
Capture pcap (Linux side) while keying:
sudo tcpdump -i any -w /tmp/cw.pcap 'host <radio-ip> and (port 4991 or port 4992)'
Compare in Wireshark against a SmartSDR Windows capture of the same operation.
Workaround
None that meets latency requirements. xmit 1/xmit 0 over TCP works but adds round-trip latency unacceptable for CW keying.
Affected
- AetherSDR ≥ 0.8.21 on FLEX-8600 firmware 4.1.5 / protocol v1.4.0.0
- All netCW-UDP paths: straight key, paddle, CWX local keyer
Symptom
When MIDI straight-key or paddle keying triggers
RadioModel::sendCwKey/sendCwPaddle, the radio does not transition to TX (no RF output, nostate=TRANSMITinterlock status). This affects all CW keying via netCW UDP — straight key, paddle, and CWX-driven local keyer.CWX text macros via
cwx sendwork fine (different protocol path), and SmartSDR on Windows keys this same radio without issue, so this is AetherSDR-specific.Reproduction
Log evidence
Every TCP fallback of
cw key/cw pttreturns0x50001000("command not supported"):This TCP rejection is expected — those decorated commands are netCW-UDP-only in FlexLib. But the UDP path also produces no observable effect:
PanadapterStream::sendToRadioconfirmssent=85 sent=85 sent=85 sent=85).READYthroughout — neverPTT_REQUESTED, neverTRANSMIT.What we ruled out
Several FlexLib-alignment fixes shipped in PR #1969 made the wire format byte-identical to FlexLib reference, but none changed the symptom:
Radio.cs:8890-8965):sendCwKeynow wrapscw keywithcw ptt 1on press andcw ptt 0on release.NetCWStream.cs:107-163): payload is now exacttx_data.Lengthbytes — 57-byte command produces an 85-byte datagram, not 88.client program AetherSDR(rejected as "unknown client program", error10000002) andclient program SmartSDR-Maestro(also rejected). Neither name unlocks the netCW path, so the10000002reply appears informational, not a gate.VITA-49 packet structure verified against
VitaOpusDataPacket.ToBytesTX:stream create netcw)All match FlexLib byte-for-byte.
Hypotheses still open
client setor interlock/transmit setup).Next step
Capture pcap (Linux side) while keying:
Compare in Wireshark against a SmartSDR Windows capture of the same operation.
Workaround
None that meets latency requirements.
xmit 1/xmit 0over TCP works but adds round-trip latency unacceptable for CW keying.Affected