This guide configures one CatHub process to own a radio and optional WinKeyer while several applications connect through dedicated endpoints. The examples use Windows, a Kenwood TS-590, com0com virtual serial pairs, and common amateur-radio applications. Substitute the ports and clients used by your station.
Download the matching platform archive from the
GitHub Releases page.
Download the adjacent SHA-256 checksum.
Verify the archive with the checksum.
Extract the archive.
Put cathub or cathub.exe on PATH.
If Rust 1.88 or newer is already installed, the equivalent installation from crates.io is:
cargo install cathub --version 0.2.1To build from source instead:
git clone https://github.com/treitforge/cathub.git
Set-Location cathub
cargo build --release -p cathubThe installed daemon does not require the cathub-protocol Rust crate, the
CatHub.Protocol NuGet package, the .NET SDK, Buf, or a separate protoc installation.
Those tools and packages are for source builds or client development.
Confirm the executable:
cathub --version
cathub --helpRecord:
- the radio serial port and its configured CAT baud rate
- the physical WinKeyer port, if present
- every application that needs radio state, radio writes, PTT, or keying
- whether each application supports Hamlib NET, a vendor serial dialect, or WinKeyer serial
Only CatHub can open the physical radio and keyer ports.
Stop each program that currently owns either device.
These programs can include rigctld, serial bridges, loggers, and manufacturer utilities.
Remove startup tasks that can start an old bridge.
Do not proceed until the physical ports are free.
Applications that require a COM port need one dedicated null-modem pair each. CatHub opens one side and the application opens the other. Hamlib NET and typed gRPC clients use TCP and do not need a pair.
Example com0com pairs:
COM10 <-> COM11 SDR software through OmniRig
COM20 <-> COM21 contest logger radio CAT
COM30 <-> COM31 manufacturer control panel
COM40 <-> COM41 contest logger WinKeyer
COM42 <-> COM43 WinKeyer maintenance tool
With com0com's setupc utility:
install PortName=COM10 PortName=COM11
install PortName=COM20 PortName=COM21
install PortName=COM30 PortName=COM31
install PortName=COM40 PortName=COM41
install PortName=COM42 PortName=COM43
The lower, even port in this example is CatHub's transport. The other port is
application_transport. Never point an application at CatHub's side of the pair.
On Linux, use stable PTY or virtual-serial endpoints managed by the host. Ensure the CatHub service account can open the radio, keyer, and hub-side paths.
Copy the repository's sample configuration to the platform default:
- Windows:
%APPDATA%\cathub\cathub.toml - Linux:
$XDG_CONFIG_HOME/cathub/cathub.toml, or~/.config/cathub/cathub.toml
Set CATHUB_CONFIG_PATH or pass --config to use another location.
The standalone file uses these top-level tables:
[radio][poll][ptt][events][[serial_endpoint]][[hamlib_net]][winkeyer][[winkeyer_endpoint]]
Delete unused example endpoints. Replace each port with the station's actual value.
The radio baud must match the radio's menu setting. Virtual serial endpoint baud values describe the client-facing protocol and do not replace the physical radio baud.
CatHub also accepts the same tables beneath [cat_hub] in a larger managed TOML document.
Require that layout with --section cat_hub. To extract it into a standalone file:
cathub config migrate `
--from C:\station\managed-config.toml `
--output "$env:APPDATA\cathub\cathub.toml"Validation and effective-config printing do not open the radio or keyer:
cathub config validate
cathub config print-effective
cathub config print-effective --format jsonWhen running from a source checkout with the sample file:
cargo run -p cathub -- config validate --config config\cathub.toml
cargo run -p cathub -- config print-effective --config config\cathub.tomlCorrect every validation error before starting the daemon.
Start an installed daemon:
cathubFrom a source checkout, the helper builds and starts it:
.\scripts\Start-CatHub.ps1The rolling log is under %LOCALAPPDATA%\cathub\logs on Windows and
$XDG_STATE_HOME/cathub or ~/.local/state/cathub on Linux. From a source checkout:
.\scripts\Get-CatHubLog.ps1 -FollowStop with Ctrl+C. The repository stop helper requests confirmation before terminating a background CatHub process:
.\scripts\Stop-CatHub.ps1Add clients one at a time. Confirm read behavior before enabling writes or PTT.
Point any logger or monitor that supports Hamlib NET rigctl at the configured read-only
listener, such as 127.0.0.1:4532. It must receive frequency, mode, VFO, split, and power
data when the backend exposes them. Set commands must fail.
- Rig:
Hamlib NET rigctl - Network Server: the dedicated write/PTT listener, such as
127.0.0.1:4533 - PTT method:
CAT - Split Operation:
Fake Itwhen the endpoint usessingle_vfo = true - Mode:
Data/Pktfor normal digital operation
Give every simultaneously running digital-mode program its own listener. Separate listeners prevent one program's mode or PTT policy from affecting another.
Configure Hamlib NET rigctl with the dedicated Log4OM address, such as
127.0.0.1:4534. The sample enables single_vfo so Log4OM's VFO A polling follows the real
operating VFO.
- Radio:
Kenwood, application portCOM21, 115200 baud, 8-N-1 - WinKeyer: application port
COM41, 1200 baud
The sample radio endpoint uses TS-590 dialect, read/write/PTT permissions, and single-VFO
presentation for SO1V operation. The normal WinKeyer endpoint has status, send, control, and
PTT permissions but no config_write.
Configure OmniRig as Kenwood TS-2000 on application port COM11. The sample grants read and
frequency-write only, allowing click-to-tune while preventing mode and PTT changes.
Configure application port COM31. The sample grants full TS-590 read, write, PTT, and
configuration-write access because the manufacturer control panel needs commands outside the
modeled operating state.
Configure the maintenance utility on application port COM43. Keep maintenance permissions
on a separate endpoint that is normally unused. Close the utility when maintenance ends so
it releases the virtual port and lease.
Use the loopback gRPC address in [winkeyer].api_bind, normally
http://127.0.0.1:50071. Supply a stable client_name so cancellation and telemetry remain
scoped to that client.
An orchestrator can use --winkeyer-api-bind 127.0.0.1:0.
Windows or Linux then selects an available loopback port.
Use --runtime-info <FILE> to receive the effective endpoint and CatHub process ID.
Read the runtime file only after CatHub publishes it.
Validate the process ID before a client uses the endpoint.
Connect the transmitter to a suitable load. Make sure that an operator attends all transmit tests. Then do these tests:
- Verify read-only endpoints reject frequency, mode, and PTT writes.
- Key and unkey from one authorized CAT client.
- Confirm a second client cannot acquire PTT while the first owns it.
- Disconnect the active owner and confirm the station returns to receive.
- Send a short typed or virtual WinKeyer job and verify completion.
- Test scoped cancel, active-owner disconnect, and the transmit watchdog.
- Confirm graceful shutdown leaves both radio and keyer unkeyed.
| Symptom | Check |
|---|---|
| Physical port is busy | Stop every direct radio/keyer client and old bridge. CatHub must be the only physical owner. |
| Radio opens but does not answer | Match [radio].baud to the radio menu and verify the physical port. |
| Serial client cannot open a port | The client must open application_transport, not CatHub's transport. |
| Hamlib NET client cannot connect | Confirm the listener address, firewall policy, and that CatHub completed startup. |
| Writes return not supported | Check endpoint permissions and whether the command is modeled for that dialect. |
| Digital mode stops on VFO B | Enable single_vfo for that client and use fake split. |
| PTT is busy | Find the current lease owner in the log and confirm the previous client unkeyed. |
| Typed keyer API is unavailable | Verify [winkeyer].api_bind is loopback. An orchestrator can request port 0 and read --runtime-info. |
| Maintenance is rejected | Stop active and queued sends, then connect through the config_write endpoint. |
Set CATHUB_LOG=debug for verbose tracing. Narrow it to a module, such as
CATHUB_LOG=cathub::serial_endpoint=trace, when diagnosing one interface.