Request preparation
Feature Request: TCI (Transceiver Control Interface) client for integration with modern SDR radios and software
What
Add a built-in TCI client to TLF that connects to any TCI-capable SDR or radio software over the standard TCI protocol (WebSocket on a configurable TCP port, default 40001).
From the user's perspective: you add a TCI=<host>:<port> line to logcfg.dat, and TLF gets full CAT control, PTT, S-meter readings, CW keying, and spot injection — all over a single WebSocket connection, with zero additional configuration of virtual serial ports, rigctld processes, or PulseAudio routing.
Why
Problem 1 — Too many moving parts for a simple integration
Today, connecting TLF to a modern SDR (e.g. a FlexRadio running AetherSDR, or an Expert Electronics SunSDR) requires setting up multiple independent channels:
- CAT control — via hamlib / 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
- CW keying — via cwdaemon or winkeyer daemon as a separate process
- Spots — DX cluster telnet connection managed separately
Each of these is a separate failure point. If one breaks (PulseAudio module doesn't load, PTY disappears, rigctld port conflict, cwdaemon crashes), the whole chain falls apart — right in the middle of a contest. Linux users are especially affected because DAX audio routing 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 well beyond the Expert Electronics / SunSDR world. Software and radios that already support TCI natively — and that TLF users are likely running:
- AetherSDR — the open-source FlexRadio client for Linux, recently added a built-in TCI server
- ExpertSDR3 (Expert Electronics / SunSDR) — the reference TCI implementation
- SDC (by Yuri) — TCI server bridging FlexRadio's SmartSDR API to TCI clients
- JTDX / MSHV — TCI for rig control and audio (common companion apps alongside TLF)
- WSJT-X (via TCI-Hamlib Adapter by DL3NEY) — bridges TCI ↔ Hamlib
- Log4OM v2 — full TCI client built in, proving the pattern works for loggers
- Not1MM and TRlinux — fellow Linux contest loggers with open TCI client feature requests
- HamDeck — Stream Deck automation via TCI
- Various ESP32/Arduino hardware controllers — TCI for physical knobs and buttons
By adding a TCI client, TLF becomes compatible with all of these without requiring each SDR vendor to add TLF-specific support.
Problem 3 — The hamlib/rigctld path is functional but limited
hamlib works well for basic frequency/mode control, but it was designed for traditional rigs. It doesn't carry audio, doesn't handle spot injection natively, and adds latency through an extra process hop (rigctld). TCI gives TLF a direct, richer channel to the radio — a single connection that covers CAT, PTT, CW keying, S-meter, and spots.
Problem 4 — TLF already runs the CW/keyer and cluster as separate daemons
TLF's existing architecture requires cwdaemon or a Winkeyer server running alongside it for CW, and a separate telnet connection for DX cluster spots. For radios that support TCI, all of these can be unified into a single WebSocket connection — simplifying setup significantly, especially for contest operators who set up and tear down quickly.
How Other Software Does It
AetherSDR (FlexRadio client for Linux)
AetherSDR recently shipped a built-in TCI server specifically to enable zero-configuration integration with loggers and digital mode software. It exposes frequency, mode, PTT, S-meter, audio, IQ, CW keying, and spot injection — all over one WebSocket. TLF adding a TCI client would complete that loop for FlexRadio + Linux contest operators immediately.
Log4OM v2
Log4OM already implements a full TCI client — CAT control, audio, IQ, and spot injection to the panorama display — demonstrating that a logger can integrate TCI cleanly and to great effect.
Not1MM and TRlinux
Both Linux-native contest loggers have open feature requests for TCI client support for the same reasons outlined here. Momentum is building across the Linux contesting ecosystem toward TCI as the standard radio interface.
TCI-Hamlib Adapter (DL3NEY)
For software that doesn't speak TCI natively, Florian DL3NEY wrote tciadapter — a Go program translating TCI ↔ Hamlib rigctld. That workaround exists precisely because demand for TCI bridging is high. Building native support directly into TLF eliminates the need for this extra process.
Suggested Behavior
Configuration (logcfg.dat)
TCI radio interface (replaces HAMLIB= for TCI-capable radios)
TCI=127.0.0.1:40001
TCI transceiver index (default 0, for multi-TRX servers)
TCI_TRX=0
Use TCI for CW keying (replaces cwdaemon for supported radios)
TCI_CW=TRUE
Use TCI for spot injection to bandmap (optional)
TCI_SPOTS=TRUE
Startup behavior
- TLF reads
TCI= from logcfg.dat and opens a WebSocket connection to ws://<host>:<port>
- The TCI server sends its initialization burst (
PROTOCOL:, DEVICE:, VFO:, MODULATION:, RX_ENABLE:, READY;)
- TLF parses the init sequence to populate its internal radio state (frequency, mode, TX capability)
- TLF logs the connection to the console:
TCI connected: FlexRadio FLEX-6600 on 127.0.0.1:40001
- If the connection drops, TLF attempts to reconnect automatically with a configurable interval
Runtime behavior
| TCI event / command |
TLF action |
VFO:trx,channel,freq; received |
→ Update displayed frequency |
MODULATION:trx,mode; received |
→ Update mode |
TRX:trx,true/false; received |
→ Update TX indicator |
RX_SMETER:trx,channel,value; received |
→ Update S-meter display |
SPOT:callsign,mode,freq,...; received |
→ Inject into bandmap (if TCI_SPOTS=TRUE) |
| User changes frequency (band change, spot click) |
→ Send VFO:0,0,<freq>; |
| User changes mode |
→ Send MODULATION:0,<mode>; |
| PTT activated (F-key macro, footswitch) |
→ Send TX_ENABLE:0,true; / TX_ENABLE:0,false; |
CW message sent (if TCI_CW=TRUE) |
→ Send CW_MSG:<text>; instead of cwdaemon |
| CW speed change |
→ Send CW_MACROS_SPEED:<wpm>; |
Connection resilience
- Auto-reconnect with configurable retry interval if the server goes away
- Graceful handling of
READY; — do not consider the connection active until READY; is received
- Fall back to hamlib/cwdaemon if TCI connection fails and
TCI_FALLBACK=TRUE is set
- Ignore unknown TCI commands silently (forward compatibility with newer protocol versions)
Protocol Hints
TCI client side (needs implementation in TLF)
- WebSocket client —
libwebsockets (C library, already packaged in all major distros: apt install libwebsockets-dev) is the natural fit for TLF's C codebase. Alternatively, libcurl has WebSocket support since 7.86.0
- TCI protocol parser — ASCII commands terminated by
;, trivial to parse: strtok() on : for command name, strtok() on , for arguments — a few dozen lines of C
- Connection sequence — connect → receive init burst → wait for
READY; → begin normal operation
- Reference spec — Full protocol at github.com/ExpertSDR3/TCI, protocol version 1.5+ recommended
- Reference Python client — github.com/ars-ka0s/eesdr-tci — useful for testing and understanding message flow
TLF side (already available)
TLF already maintains all the state needed to drive and respond to TCI:
- Frequency / mode — already managed via hamlib; same data feeds TCI with a different transport
- PTT / TX — already triggered by F-key macros and footswitch input
- CW keying — already abstracted behind cwdaemon; TCI keying becomes an alternative backend
- Bandmap / spots — already receives DX cluster spots via telnet; TCI
SPOT: injection is an additional source
- S-meter — already polled via hamlib; TCI pushes it unsolicited, reducing polling overhead
Suggested implementation phases
- Phase 1 — Core CAT: WebSocket client + parse init burst + VFO/mode read-write + PTT → enough for basic contesting with a TCI-capable radio, no hamlib needed
- Phase 2 — CW keying: Send
CW_MSG: and CW_MACROS_SPEED: → replaces cwdaemon for radios with built-in keyers (SunSDR, FlexRadio)
- Phase 3 — Spot injection: Receive
SPOT: from TCI server and push to bandmap → supplements or replaces the DX cluster telnet connection
- Phase 4 — S-meter push: Receive
RX_SMETER: unsolicited → eliminates hamlib polling for meter updates
Additional Context
- The TCI protocol is open source and MIT-licensed — no legal or licensing concerns
- AetherSDR recently shipped a built-in TCI server specifically to enable this kind of zero-configuration logger integration — TLF adding TCI client support would complete that loop for FlexRadio + Linux contest operators immediately
libwebsockets is a mature, widely packaged C library that fits naturally into TLF's existing build system — the implementation footprint is small
- TLF already abstracts its radio interface (hamlib) and keyer interface (cwdaemon) behind configuration directives; TCI follows the exact same pattern with a new backend
- This would make TLF one of the very few contest loggers on any platform with native TCI support — a meaningful advantage for operators running modern SDR hardware on Linux
- Fellow Linux contest loggers Not1MM and TRlinux have open feature requests for the same capability, signalling that this is a shared priority across the Linux contesting community
Request preparation
Feature Request: TCI (Transceiver Control Interface) client for integration with modern SDR radios and software
What
Add a built-in TCI client to TLF that connects to any TCI-capable SDR or radio software over the standard TCI protocol (WebSocket on a configurable TCP port, default
40001).From the user's perspective: you add a
TCI=<host>:<port>line tologcfg.dat, and TLF gets full CAT control, PTT, S-meter readings, CW keying, and spot injection — all over a single WebSocket connection, with zero additional configuration of virtual serial ports, rigctld processes, or PulseAudio routing.Why
Problem 1 — Too many moving parts for a simple integration
Today, connecting TLF to a modern SDR (e.g. a FlexRadio running AetherSDR, or an Expert Electronics SunSDR) 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, cwdaemon crashes), the whole chain falls apart — right in the middle of a contest. Linux users are especially affected because DAX audio routing 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 well beyond the Expert Electronics / SunSDR world. Software and radios that already support TCI natively — and that TLF users are likely running:
By adding a TCI client, TLF becomes compatible with all of these without requiring each SDR vendor to add TLF-specific support.
Problem 3 — The hamlib/rigctld path is functional but limited
hamlib works well for basic frequency/mode control, but it was designed for traditional rigs. It doesn't carry audio, doesn't handle spot injection natively, and adds latency through an extra process hop (rigctld). TCI gives TLF a direct, richer channel to the radio — a single connection that covers CAT, PTT, CW keying, S-meter, and spots.
Problem 4 — TLF already runs the CW/keyer and cluster as separate daemons
TLF's existing architecture requires cwdaemon or a Winkeyer server running alongside it for CW, and a separate telnet connection for DX cluster spots. For radios that support TCI, all of these can be unified into a single WebSocket connection — simplifying setup significantly, especially for contest operators who set up and tear down quickly.
How Other Software Does It
AetherSDR (FlexRadio client for Linux)
AetherSDR recently shipped a built-in TCI server specifically to enable zero-configuration integration with loggers and digital mode software. It exposes frequency, mode, PTT, S-meter, audio, IQ, CW keying, and spot injection — all over one WebSocket. TLF adding a TCI client would complete that loop for FlexRadio + Linux contest operators immediately.
Log4OM v2
Log4OM already implements a full TCI client — CAT control, audio, IQ, and spot injection to the panorama display — demonstrating that a logger can integrate TCI cleanly and to great effect.
Not1MM and TRlinux
Both Linux-native contest loggers have open feature requests for TCI client support for the same reasons outlined here. Momentum is building across the Linux contesting ecosystem toward TCI as the standard radio interface.
TCI-Hamlib Adapter (DL3NEY)
For software that doesn't speak TCI natively, Florian DL3NEY wrote
tciadapter— a Go program translating TCI ↔ Hamlib rigctld. That workaround exists precisely because demand for TCI bridging is high. Building native support directly into TLF eliminates the need for this extra process.Suggested Behavior
Configuration (
logcfg.dat)TCI radio interface (replaces HAMLIB= for TCI-capable radios)
TCI=127.0.0.1:40001
TCI transceiver index (default 0, for multi-TRX servers)
TCI_TRX=0
Use TCI for CW keying (replaces cwdaemon for supported radios)
TCI_CW=TRUE
Use TCI for spot injection to bandmap (optional)
TCI_SPOTS=TRUE
Startup behavior
TCI=fromlogcfg.datand opens a WebSocket connection tows://<host>:<port>PROTOCOL:,DEVICE:,VFO:,MODULATION:,RX_ENABLE:,READY;)TCI connected: FlexRadio FLEX-6600 on 127.0.0.1:40001Runtime behavior
VFO:trx,channel,freq;receivedMODULATION:trx,mode;receivedTRX:trx,true/false;receivedRX_SMETER:trx,channel,value;receivedSPOT:callsign,mode,freq,...;receivedTCI_SPOTS=TRUE)VFO:0,0,<freq>;MODULATION:0,<mode>;TX_ENABLE:0,true;/TX_ENABLE:0,false;TCI_CW=TRUE)CW_MSG:<text>;instead of cwdaemonCW_MACROS_SPEED:<wpm>;Connection resilience
READY;— do not consider the connection active untilREADY;is receivedTCI_FALLBACK=TRUEis setProtocol Hints
TCI client side (needs implementation in TLF)
libwebsockets(C library, already packaged in all major distros:apt install libwebsockets-dev) is the natural fit for TLF's C codebase. Alternatively,libcurlhas WebSocket support since 7.86.0;, trivial to parse:strtok()on:for command name,strtok()on,for arguments — a few dozen lines of CREADY;→ begin normal operationTLF side (already available)
TLF already maintains all the state needed to drive and respond to TCI:
SPOT:injection is an additional sourceSuggested implementation phases
CW_MSG:andCW_MACROS_SPEED:→ replaces cwdaemon for radios with built-in keyers (SunSDR, FlexRadio)SPOT:from TCI server and push to bandmap → supplements or replaces the DX cluster telnet connectionRX_SMETER:unsolicited → eliminates hamlib polling for meter updatesAdditional Context
libwebsocketsis a mature, widely packaged C library that fits naturally into TLF's existing build system — the implementation footprint is small