Request preparation
What would you like?
Feature Request: TCI (Transceiver Control Interface) server for integration with logging and digital mode software
What
Add a built-in TCI server to AetherSDR that exposes radio state (frequency, mode, S-meter, TX status, audio streams, IQ data, spots) over the standard TCI protocol (WebSocket on a configurable TCP port, default 40001).
From the user's perspective: you go to Settings → TCI (or a new tab in Radio Setup), enable the TCI server, and any TCI-capable logging or digital mode software on the same machine (or LAN) can connect to AetherSDR — getting CAT control, RX/TX audio, IQ streaming, CW macros, and spot injection — all over a single WebSocket connection, with zero additional configuration of virtual serial ports, DAX audio pipes, or PulseAudio routing.
Why
Problem 1 — Too many moving parts for a simple integration
Today, connecting AetherSDR to a contest logger (e.g. N1MM Logger+) or digital mode software (e.g. JTDX, MSHV, fldigi) requires setting up multiple independent channels:
- CAT control — via rigctld TCP or a PTY virtual serial port
- RX audio — via DAX PulseAudio pipe modules (or JACK routing)
- TX audio — via a second DAX pipe in the reverse direction
- Spots — no unified mechanism; each app has its own cluster setup
Each of these is a separate failure point. If one breaks (PulseAudio module doesn't load, PTY disappears, rigctld port conflict), the whole chain falls apart. Linux users are especially affected because DAX on Linux is inherently more fragile than on Windows (pipe modules, PipeWire compatibility, buffer sizing).
Problem 2 — Growing TCI ecosystem
TCI has become a de facto standard beyond the Expert Electronics / SunSDR world. Software that already supports TCI natively:
- Log4OM v2 — full TCI support (CAT, audio, IQ, spots on panorama)
- Swisslog — TCI as a transceiver interface option
- MSHV — TCI for rig control and audio
- JTDX — TCI support
- SDC (by Yuri) — TCI client for FlexRadio (the existing bridge solution)
- HamDeck — Stream Deck automation via TCI
- TCI-Hamlib Adapter (DL3NEY) — bridges TCI ↔ Hamlib for WSJT-X/fldigi/CQRLog
- Various ESP32/Arduino projects — hardware controllers via TCI
By offering a TCI server, AetherSDR becomes a first-class citizen in this ecosystem without requiring each application to add FlexRadio-specific API support.
Problem 3 — SDC is the current workaround, but it's redundant
Operators who want TCI with a FlexRadio currently run SDC (by Yuri/ten9876) as a bridge between the FlexRadio API and TCI clients. With AetherSDR already connected to the radio and maintaining full state, having a separate SDC instance is redundant — it's a second client consuming radio resources. A built-in TCI server eliminates this duplication.
How Other Clients Do It
ExpertSDR3 (Expert Electronics)
ExpertSDR3 is the reference TCI implementation. The SDR software acts as the TCI server — any number of clients connect via WebSocket to ws://<ip>:40001. The settings panel has a simple enable/disable toggle and port configuration. On connection, the server sends an initialization sequence (PROTOCOL:, DEVICE:, VFO:, MODULATION:, RX_ENABLE:, etc.) so the client gets the complete radio state immediately. Audio and IQ are streamed as binary WebSocket frames.
SDC (by Yuri — SmartSDR for Linux)
SDC connects to the FlexRadio via the SmartSDR TCP/UDP protocol and then exposes a TCI server on a local port. This is exactly the architecture proposed here, but built into AetherSDR rather than running as a separate application.
TCI-Hamlib Adapter (DL3NEY)
For software that doesn't speak TCI natively (like WSJT-X), Florian DL3NEY wrote tciadapter — a Go program that translates between TCI and Hamlib rigctld protocol. This demonstrates the demand for bridging between ecosystems and also shows that TCI → Hamlib is a solved problem at the adapter level.
Suggested Behavior
Configuration (Settings → TCI or Radio Setup → TCI tab)
- Enable TCI server — checkbox (default: off)
- Listen port — spinbox, default
40001
- Listen address — dropdown:
127.0.0.1 (localhost only) / 0.0.0.0 (all interfaces)
- Audio sample rate — dropdown:
48000 / 24000 Hz (for RX_AUDIO_STREAM / TX_AUDIO_STREAM)
- IQ sample rate — dropdown:
48000 / 96000 / 192000 Hz (for IQ_STREAM, if enabled)
- IQ enable — checkbox (default: off, because IQ streaming uses significant bandwidth)
- Connected clients — read-only list showing currently connected TCI clients (IP, software name if provided)
Startup behavior
- User enables TCI server in settings
- AetherSDR opens a WebSocket server (using
QWebSocketServer from Qt WebSockets module) on the configured port
- Status bar shows a TCI indicator (e.g. "TCI: 40001" or a small icon) when active, with client count badge
Connection sequence (what happens when a client connects)
- Client opens WebSocket to
ws://<ip>:<port>
- AetherSDR sends the initialization burst:
PROTOCOL:ExpertSDR3,1.5;DEVICE:FlexRadio FLEX-8600;RECEIVE_ONLY:false;TRXS_COUNT:1;CHANNELS_COUNT:2;VFO:0,0,14225000;IF:0,0,0;MODULATION:0,USB;RX_ENABLE:0,true;TX_ENABLE:0,true;DRIVE:50;TUNE_DRIVE:10;IQ_SAMPLERATE:48000;AUDIO_SAMPLERATE:48000;CW_MACROS_SPEED:25;...READY;
- Client can then send commands (
VFO:0,0,14226000; to change frequency, TX_ENABLE:0,true; for PTT, etc.)
- AetherSDR translates TCI commands to FlexRadio API calls and vice versa
Runtime behavior
| TCI command/event |
AetherSDR action |
| VFO:trx,channel,freq; |
→ slice tune <freq_mhz> |
| MODULATION:trx,mode; |
→ slice set mode= |
| TX_ENABLE:trx,true; |
→ xmit 1 |
| DRIVE:value; |
→ transmit set rfpower= |
| RX_AUDIO_STREAM (binary) |
← Feed from AudioEngine (same data as DAX RX) |
| TX_AUDIO_STREAM (binary) |
→ Feed into AudioEngine TX path |
| IQ_STREAM (binary) |
← Feed from DAX IQ channel (when #124 is implemented) |
| SPOT:callsign,mode,freq,...; |
→ Forward to SpotHub for display on spectrum |
| CW_MACROS_SPEED:wpm; |
→ cw wpm |
| CW_MSG:text; |
→ cw send |
| Slice status change |
→ Broadcast VFO:, MODULATION:, etc. to all connected clients |
| Meter update (S-meter) |
→ Broadcast RX_SMETER:trx,channel,value; |
| TX state change |
→ Broadcast TRX:trx,true/false; |
Audio streaming
- RX audio: AetherSDR taps the same audio pipeline that feeds DAX RX channels (PCC 0x0123 int16 data or 0x03E3 float32 data), converts to the TCI binary frame format (little-endian float32, per the TCI spec), and sends as WebSocket binary messages
- TX audio: Client sends binary frames → AetherSDR feeds them into the TX audio path (same routing as DAX TX)
Multi-slice mapping
The FlexRadio can have multiple slices. TCI uses trx (transceiver index) and channel (sub-receiver). Suggested mapping:
- Slice A → TRX 0, channel 0
- Slice B → TRX 0, channel 1
- (If Multi-Flex with 2 independent TX) → TRX 1
Applet integration
A small TCI toggle button could be added to the AppletPanel row (alongside ANLG, RX, TX, etc.) that opens a minimal TCI status applet showing: server on/off, port, connected clients count, and data rates.
Protocol Hints
FlexRadio side (already implemented in AetherSDR)
AetherSDR already maintains all the state needed to serve TCI:
- Frequency/mode/filter —
SliceModel (RF_frequency, mode, filter_lo, filter_hi)
- TX state —
TransmitModel (xmit, rfpower, tunepower)
- S-meter —
MeterModel (LEVEL meter from SLC source)
- Audio RX —
AudioEngine / PipeWireAudioBridge DAX pipeline
- Audio TX —
AudioEngine TX path
- Spots — SpotHub system
- CW —
cw send, cw wpm commands via RadioConnection
TCI side (needs implementation)
- WebSocket server — Qt provides
QWebSocketServer in the Qt::WebSockets module (add find_package(Qt6 COMPONENTS WebSockets) to CMakeLists.txt)
- TCI protocol parser — ASCII commands terminated by
;, very simple to parse (split on : for command name, split on , for arguments)
- Binary audio frames — TCI audio uses a small header (type, sample rate, codec, CRC, length) followed by float32 PCM samples in little-endian byte order
- Reference implementation — Full protocol spec at github.com/ExpertSDR3/TCI, protocol version 1.5+ recommended
- Reference Python client — github.com/ars-ka0s/eesdr-tci — useful for testing
Implementation phases (suggested)
- Phase 1 — Core CAT: WebSocket server + VFO/mode/filter/TX commands + status broadcast → enough for loggers
- Phase 2 — Audio: RX audio streaming + TX audio input → enough for JTDX/MSHV/fldigi
- Phase 3 — Extended: IQ streaming, spot injection, CW macros, S-meter broadcast → full feature parity
- Phase 4 — Settings UI: Radio Setup tab with configuration options
Additional context
- The TCI protocol is open source and documented (MIT license)
- This feature would make AetherSDR the first FlexRadio client with built-in TCI — even SmartSDR for Windows doesn't have it
- On Linux, where DAX audio routing is inherently more complex than on Windows, TCI's all-in-one-WebSocket approach is especially valuable
- Since AetherSDR already has
RigctlServer as a precedent for serving a third-party protocol from internal state, TCI follows the same architectural pattern — just with a different wire format and richer feature set
# Feature Request: TCI (Transceiver Control Interface) server for integration with logging and digital mode software
What
Add a built-in TCI server to AetherSDR that exposes radio state (frequency, mode, S-meter, TX status, audio streams, IQ data, spots) over the standard [TCI protocol](https://github.com/ExpertSDR3/TCI) (WebSocket on a configurable TCP port, default 40001).
From the user's perspective: you go to Settings → TCI (or a new tab in Radio Setup), enable the TCI server, and any TCI-capable logging or digital mode software on the same machine (or LAN) can connect to AetherSDR — getting CAT control, RX/TX audio, IQ streaming, CW macros, and spot injection — all over a single WebSocket connection, with zero additional configuration of virtual serial ports, DAX audio pipes, or PulseAudio routing.
Why
Problem 1 — Too many moving parts for a simple integration
Today, connecting AetherSDR to a contest logger (e.g. N1MM Logger+) or digital mode software (e.g. JTDX, MSHV, fldigi) requires setting up multiple independent channels:
- CAT control — via rigctld TCP or a PTY virtual serial port
- RX audio — via DAX PulseAudio pipe modules (or JACK routing)
- TX audio — via a second DAX pipe in the reverse direction
- Spots — no unified mechanism; each app has its own cluster setup
Each of these is a separate failure point. If one breaks (PulseAudio module doesn't load, PTY disappears, rigctld port conflict), the whole chain falls apart. Linux users are especially affected because DAX on Linux is inherently more fragile than on Windows (pipe modules, PipeWire compatibility, buffer sizing).
Problem 2 — Growing TCI ecosystem
TCI has become a de facto standard beyond the Expert Electronics / SunSDR world. Software that already supports TCI natively:
- Log4OM v2 — full TCI support (CAT, audio, IQ, spots on panorama)
- Swisslog — TCI as a transceiver interface option
- MSHV — TCI for rig control and audio
- JTDX — TCI support
- SDC (by Yuri) — TCI client for FlexRadio (the existing bridge solution)
- HamDeck — Stream Deck automation via TCI
- TCI-Hamlib Adapter (DL3NEY) — bridges TCI ↔ Hamlib for WSJT-X/fldigi/CQRLog
- Various ESP32/Arduino projects — hardware controllers via TCI
By offering a TCI server, AetherSDR becomes a first-class citizen in this ecosystem without requiring each application to add FlexRadio-specific API support.
Problem 3 — SDC is the current workaround, but it's redundant
Operators who want TCI with a FlexRadio currently run SDC (by Yuri/ten9876) as a bridge between the FlexRadio API and TCI clients. With AetherSDR already connected to the radio and maintaining full state, having a separate SDC instance is redundant — it's a second client consuming radio resources. A built-in TCI server eliminates this duplication.
How Other Clients Do It
ExpertSDR3 (Expert Electronics)
ExpertSDR3 is the reference TCI implementation. The SDR software acts as the TCI server — any number of clients connect via WebSocket to ws://<ip>:40001. The settings panel has a simple enable/disable toggle and port configuration. On connection, the server sends an initialization sequence (PROTOCOL:, DEVICE:, VFO:, MODULATION:, RX_ENABLE:, etc.) so the client gets the complete radio state immediately. Audio and IQ are streamed as binary WebSocket frames.
SDC (by Yuri — SmartSDR for Linux)
SDC connects to the FlexRadio via the SmartSDR TCP/UDP protocol and then exposes a TCI server on a local port. This is exactly the architecture proposed here, but built into AetherSDR rather than running as a separate application.
TCI-Hamlib Adapter (DL3NEY)
For software that doesn't speak TCI natively (like WSJT-X), Florian DL3NEY wrote tciadapter — a Go program that translates between TCI and Hamlib rigctld protocol. This demonstrates the demand for bridging between ecosystems and also shows that TCI → Hamlib is a solved problem at the adapter level.
Suggested Behavior
Configuration (Settings → TCI or Radio Setup → TCI tab)
- Enable TCI server — checkbox (default: off)
- Listen port — spinbox, default
40001
- Listen address — dropdown:
127.0.0.1 (localhost only) / 0.0.0.0 (all interfaces)
- Audio sample rate — dropdown:
48000 / 24000 Hz (for RX_AUDIO_STREAM / TX_AUDIO_STREAM)
- IQ sample rate — dropdown:
48000 / 96000 / 192000 Hz (for IQ_STREAM, if enabled)
- IQ enable — checkbox (default: off, because IQ streaming uses significant bandwidth)
- Connected clients — read-only list showing currently connected TCI clients (IP, software name if provided)
Startup behavior
- User enables TCI server in settings
- AetherSDR opens a WebSocket server (using
QWebSocketServer from Qt WebSockets module) on the configured port
- Status bar shows a TCI indicator (e.g. "TCI: 40001" or a small icon) when active, with client count badge
Connection sequence (what happens when a client connects)
- Client opens WebSocket to
ws://<ip>:<port>
- AetherSDR sends the initialization burst:
PROTOCOL:ExpertSDR3,1.5;
DEVICE:FlexRadio FLEX-8600;
RECEIVE_ONLY:false;
TRXS_COUNT:1;
CHANNELS_COUNT:2;
VFO:0,0,14225000;
IF:0,0,0;
MODULATION:0,USB;
RX_ENABLE:0,true;
TX_ENABLE:0,true;
DRIVE:50;
TUNE_DRIVE:10;
IQ_SAMPLERATE:48000;
AUDIO_SAMPLERATE:48000;
CW_MACROS_SPEED:25;
...
READY;
- Client can then send commands (
VFO:0,0,14226000; to change frequency, TX_ENABLE:0,true; for PTT, etc.)
- AetherSDR translates TCI commands to FlexRadio API calls and vice versa
Runtime behavior
| TCI command/event |
AetherSDR action |
VFO:trx,channel,freq; |
→ slice tune <id> <freq_mhz> |
MODULATION:trx,mode; |
→ slice set <id> mode=<mode> |
TX_ENABLE:trx,true; |
→ xmit 1 |
DRIVE:value; |
→ transmit set rfpower=<value> |
RX_AUDIO_STREAM (binary) |
← Feed from AudioEngine (same data as DAX RX) |
TX_AUDIO_STREAM (binary) |
→ Feed into AudioEngine TX path |
IQ_STREAM (binary) |
← Feed from DAX IQ channel (when #124 is implemented) |
SPOT:callsign,mode,freq,...; |
→ Forward to SpotHub for display on spectrum |
CW_MACROS_SPEED:wpm; |
→ cw wpm <wpm> |
CW_MSG:text; |
→ cw send <text> |
| Slice status change |
→ Broadcast VFO:, MODULATION:, etc. to all connected clients |
| Meter update (S-meter) |
→ Broadcast RX_SMETER:trx,channel,value; |
| TX state change |
→ Broadcast TRX:trx,true/false; |
Audio streaming
- RX audio: AetherSDR taps the same audio pipeline that feeds DAX RX channels (PCC 0x0123 int16 data or 0x03E3 float32 data), converts to the TCI binary frame format (little-endian float32, per the TCI spec), and sends as WebSocket binary messages
- TX audio: Client sends binary frames → AetherSDR feeds them into the TX audio path (same routing as DAX TX)
Multi-slice mapping
The FlexRadio can have multiple slices. TCI uses trx (transceiver index) and channel (sub-receiver). Suggested mapping:
- Slice A → TRX 0, channel 0
- Slice B → TRX 0, channel 1
- (If Multi-Flex with 2 independent TX) → TRX 1
Applet integration
A small TCI toggle button could be added to the AppletPanel row (alongside ANLG, RX, TX, etc.) that opens a minimal TCI status applet showing: server on/off, port, connected clients count, and data rates.
Protocol Hints
FlexRadio side (already implemented in AetherSDR)
AetherSDR already maintains all the state needed to serve TCI:
- Frequency/mode/filter —
SliceModel (RF_frequency, mode, filter_lo, filter_hi)
- TX state —
TransmitModel (xmit, rfpower, tunepower)
- S-meter —
MeterModel (LEVEL meter from SLC source)
- Audio RX —
AudioEngine / PipeWireAudioBridge DAX pipeline
- Audio TX —
AudioEngine TX path
- Spots — SpotHub system
- CW —
cw send, cw wpm commands via RadioConnection
TCI side (needs implementation)
- WebSocket server — Qt provides
QWebSocketServer in the Qt::WebSockets module (add find_package(Qt6 COMPONENTS WebSockets) to CMakeLists.txt)
- TCI protocol parser — ASCII commands terminated by
;, very simple to parse (split on : for command name, split on , for arguments)
- Binary audio frames — TCI audio uses a small header (type, sample rate, codec, CRC, length) followed by float32 PCM samples in little-endian byte order
- Reference implementation — Full protocol spec at [github.com/ExpertSDR3/TCI](https://github.com/ExpertSDR3/TCI), protocol version 1.5+ recommended
- Reference Python client — [github.com/ars-ka0s/eesdr-tci](https://github.com/ars-ka0s/eesdr-tci) — useful for testing
Implementation phases (suggested)
- Phase 1 — Core CAT: WebSocket server + VFO/mode/filter/TX commands + status broadcast → enough for loggers
- Phase 2 — Audio: RX audio streaming + TX audio input → enough for JTDX/MSHV/fldigi
- Phase 3 — Extended: IQ streaming, spot injection, CW macros, S-meter broadcast → full feature parity
- Phase 4 — Settings UI: Radio Setup tab with configuration options
Additional context
- The TCI protocol is [open source and documented](https://github.com/ExpertSDR3/TCI) (MIT license)
- This feature would make AetherSDR the first FlexRadio client with built-in TCI — even SmartSDR for Windows doesn't have it
- On Linux, where DAX audio routing is inherently more complex than on Windows, TCI's all-in-one-WebSocket approach is especially valuable
- Since AetherSDR already has
RigctlServer as a precedent for serving a third-party protocol from internal state, TCI follows the same architectural pattern — just with a different wire format and richer feature set
Request preparation
What would you like?
Feature Request: TCI (Transceiver Control Interface) server for integration with logging and digital mode software
What
Add a built-in TCI server to AetherSDR that exposes radio state (frequency, mode, S-meter, TX status, audio streams, IQ data, spots) over the standard TCI protocol (WebSocket on a configurable TCP port, default
40001).From the user's perspective: you go to Settings → TCI (or a new tab in Radio Setup), enable the TCI server, and any TCI-capable logging or digital mode software on the same machine (or LAN) can connect to AetherSDR — getting CAT control, RX/TX audio, IQ streaming, CW macros, and spot injection — all over a single WebSocket connection, with zero additional configuration of virtual serial ports, DAX audio pipes, or PulseAudio routing.
Why
Problem 1 — Too many moving parts for a simple integration
Today, connecting AetherSDR to a contest logger (e.g. N1MM Logger+) or digital mode software (e.g. JTDX, MSHV, fldigi) requires setting up multiple independent channels:
Each of these is a separate failure point. If one breaks (PulseAudio module doesn't load, PTY disappears, rigctld port conflict), the whole chain falls apart. Linux users are especially affected because DAX on Linux is inherently more fragile than on Windows (pipe modules, PipeWire compatibility, buffer sizing).
Problem 2 — Growing TCI ecosystem
TCI has become a de facto standard beyond the Expert Electronics / SunSDR world. Software that already supports TCI natively:
By offering a TCI server, AetherSDR becomes a first-class citizen in this ecosystem without requiring each application to add FlexRadio-specific API support.
Problem 3 — SDC is the current workaround, but it's redundant
Operators who want TCI with a FlexRadio currently run SDC (by Yuri/ten9876) as a bridge between the FlexRadio API and TCI clients. With AetherSDR already connected to the radio and maintaining full state, having a separate SDC instance is redundant — it's a second client consuming radio resources. A built-in TCI server eliminates this duplication.
How Other Clients Do It
ExpertSDR3 (Expert Electronics)
ExpertSDR3 is the reference TCI implementation. The SDR software acts as the TCI server — any number of clients connect via WebSocket to
ws://<ip>:40001. The settings panel has a simple enable/disable toggle and port configuration. On connection, the server sends an initialization sequence (PROTOCOL:,DEVICE:,VFO:,MODULATION:,RX_ENABLE:, etc.) so the client gets the complete radio state immediately. Audio and IQ are streamed as binary WebSocket frames.SDC (by Yuri — SmartSDR for Linux)
SDC connects to the FlexRadio via the SmartSDR TCP/UDP protocol and then exposes a TCI server on a local port. This is exactly the architecture proposed here, but built into AetherSDR rather than running as a separate application.
TCI-Hamlib Adapter (DL3NEY)
For software that doesn't speak TCI natively (like WSJT-X), Florian DL3NEY wrote
tciadapter— a Go program that translates between TCI and Hamlib rigctld protocol. This demonstrates the demand for bridging between ecosystems and also shows that TCI → Hamlib is a solved problem at the adapter level.Suggested Behavior
Configuration (Settings → TCI or Radio Setup → TCI tab)
40001127.0.0.1(localhost only) /0.0.0.0(all interfaces)48000/24000Hz (forRX_AUDIO_STREAM/TX_AUDIO_STREAM)48000/96000/192000Hz (forIQ_STREAM, if enabled)Startup behavior
QWebSocketServerfrom Qt WebSockets module) on the configured portConnection sequence (what happens when a client connects)
ws://<ip>:<port>VFO:0,0,14226000;to change frequency,TX_ENABLE:0,true;for PTT, etc.)Runtime behavior
Audio streaming
Multi-slice mapping
The FlexRadio can have multiple slices. TCI uses
trx(transceiver index) andchannel(sub-receiver). Suggested mapping:Applet integration
A small TCI toggle button could be added to the AppletPanel row (alongside ANLG, RX, TX, etc.) that opens a minimal TCI status applet showing: server on/off, port, connected clients count, and data rates.
Protocol Hints
FlexRadio side (already implemented in AetherSDR)
AetherSDR already maintains all the state needed to serve TCI:
SliceModel(RF_frequency,mode,filter_lo,filter_hi)TransmitModel(xmit,rfpower,tunepower)MeterModel(LEVEL meter from SLC source)AudioEngine/PipeWireAudioBridgeDAX pipelineAudioEngineTX pathcw send,cw wpmcommands viaRadioConnectionTCI side (needs implementation)
QWebSocketServerin theQt::WebSocketsmodule (addfind_package(Qt6 COMPONENTS WebSockets)to CMakeLists.txt);, very simple to parse (split on:for command name, split on,for arguments)Implementation phases (suggested)
Additional context
- The TCI protocol is open source and documented (MIT license)
- This feature would make AetherSDR the first FlexRadio client with built-in TCI — even SmartSDR for Windows doesn't have it
- On Linux, where DAX audio routing is inherently more complex than on Windows, TCI's all-in-one-WebSocket approach is especially valuable
- Since AetherSDR already has
# Feature Request: TCI (Transceiver Control Interface) server for integration with logging and digital mode softwareRigctlServeras a precedent for serving a third-party protocol from internal state, TCI follows the same architectural pattern — just with a different wire format and richer feature setWhat
Add a built-in TCI server to AetherSDR that exposes radio state (frequency, mode, S-meter, TX status, audio streams, IQ data, spots) over the standard [TCI protocol](https://github.com/ExpertSDR3/TCI) (WebSocket on a configurable TCP port, default
40001).From the user's perspective: you go to Settings → TCI (or a new tab in Radio Setup), enable the TCI server, and any TCI-capable logging or digital mode software on the same machine (or LAN) can connect to AetherSDR — getting CAT control, RX/TX audio, IQ streaming, CW macros, and spot injection — all over a single WebSocket connection, with zero additional configuration of virtual serial ports, DAX audio pipes, or PulseAudio routing.
Why
Problem 1 — Too many moving parts for a simple integration
Today, connecting AetherSDR to a contest logger (e.g. N1MM Logger+) or digital mode software (e.g. JTDX, MSHV, fldigi) requires setting up multiple independent channels:
Each of these is a separate failure point. If one breaks (PulseAudio module doesn't load, PTY disappears, rigctld port conflict), the whole chain falls apart. Linux users are especially affected because DAX on Linux is inherently more fragile than on Windows (pipe modules, PipeWire compatibility, buffer sizing).
Problem 2 — Growing TCI ecosystem
TCI has become a de facto standard beyond the Expert Electronics / SunSDR world. Software that already supports TCI natively:
By offering a TCI server, AetherSDR becomes a first-class citizen in this ecosystem without requiring each application to add FlexRadio-specific API support.
Problem 3 — SDC is the current workaround, but it's redundant
Operators who want TCI with a FlexRadio currently run SDC (by Yuri/ten9876) as a bridge between the FlexRadio API and TCI clients. With AetherSDR already connected to the radio and maintaining full state, having a separate SDC instance is redundant — it's a second client consuming radio resources. A built-in TCI server eliminates this duplication.
How Other Clients Do It
ExpertSDR3 (Expert Electronics)
ExpertSDR3 is the reference TCI implementation. The SDR software acts as the TCI server — any number of clients connect via WebSocket to
ws://<ip>:40001. The settings panel has a simple enable/disable toggle and port configuration. On connection, the server sends an initialization sequence (PROTOCOL:,DEVICE:,VFO:,MODULATION:,RX_ENABLE:, etc.) so the client gets the complete radio state immediately. Audio and IQ are streamed as binary WebSocket frames.SDC (by Yuri — SmartSDR for Linux)
SDC connects to the FlexRadio via the SmartSDR TCP/UDP protocol and then exposes a TCI server on a local port. This is exactly the architecture proposed here, but built into AetherSDR rather than running as a separate application.
TCI-Hamlib Adapter (DL3NEY)
For software that doesn't speak TCI natively (like WSJT-X), Florian DL3NEY wrote
tciadapter— a Go program that translates between TCI and Hamlib rigctld protocol. This demonstrates the demand for bridging between ecosystems and also shows that TCI → Hamlib is a solved problem at the adapter level.Suggested Behavior
Configuration (Settings → TCI or Radio Setup → TCI tab)
40001127.0.0.1(localhost only) /0.0.0.0(all interfaces)48000/24000Hz (forRX_AUDIO_STREAM/TX_AUDIO_STREAM)48000/96000/192000Hz (forIQ_STREAM, if enabled)Startup behavior
QWebSocketServerfrom Qt WebSockets module) on the configured portConnection sequence (what happens when a client connects)
ws://<ip>:<port>VFO:0,0,14226000;to change frequency,TX_ENABLE:0,true;for PTT, etc.)Runtime behavior
VFO:trx,channel,freq;slice tune <id> <freq_mhz>MODULATION:trx,mode;slice set <id> mode=<mode>TX_ENABLE:trx,true;xmit 1DRIVE:value;transmit set rfpower=<value>RX_AUDIO_STREAM(binary)TX_AUDIO_STREAM(binary)IQ_STREAM(binary)SPOT:callsign,mode,freq,...;CW_MACROS_SPEED:wpm;cw wpm <wpm>CW_MSG:text;cw send <text>VFO:,MODULATION:, etc. to all connected clientsRX_SMETER:trx,channel,value;TRX:trx,true/false;Audio streaming
Multi-slice mapping
The FlexRadio can have multiple slices. TCI uses
trx(transceiver index) andchannel(sub-receiver). Suggested mapping:Applet integration
A small TCI toggle button could be added to the AppletPanel row (alongside ANLG, RX, TX, etc.) that opens a minimal TCI status applet showing: server on/off, port, connected clients count, and data rates.
Protocol Hints
FlexRadio side (already implemented in AetherSDR)
AetherSDR already maintains all the state needed to serve TCI:
SliceModel(RF_frequency,mode,filter_lo,filter_hi)TransmitModel(xmit,rfpower,tunepower)MeterModel(LEVEL meter from SLC source)AudioEngine/PipeWireAudioBridgeDAX pipelineAudioEngineTX pathcw send,cw wpmcommands viaRadioConnectionTCI side (needs implementation)
QWebSocketServerin theQt::WebSocketsmodule (addfind_package(Qt6 COMPONENTS WebSockets)to CMakeLists.txt);, very simple to parse (split on:for command name, split on,for arguments)Implementation phases (suggested)
Additional context
RigctlServeras a precedent for serving a third-party protocol from internal state, TCI follows the same architectural pattern — just with a different wire format and richer feature set