Rusty HAM tools
  • Rust 99.4%
  • Shell 0.3%
  • Just 0.3%
Find a file
2026-08-18 23:45:40 -04:00
crates add OpenAPI documentation support 2026-08-18 23:39:36 -04:00
docs docs(plans): fix correctness bugs in tune-and-listen plan 2026-08-06 14:47:37 -04:00
scripts feat: add IC-7100 voice console MVP 2026-08-04 17:34:03 -04:00
vendor chore(vendor): track js8call and wsjtx as reference submodules 2026-08-07 00:46:53 -04:00
.gitignore restore ham-rs ignore rules 2026-08-18 23:45:40 -04:00
.gitmodules chore(vendor): track js8call and wsjtx as reference submodules 2026-08-07 00:46:53 -04:00
Cargo.lock add OpenAPI documentation support 2026-08-18 23:39:36 -04:00
Cargo.toml feat(ham-cli): complete hamd hardware-owner migration 2026-08-07 14:36:45 -04:00
Justfile docs: document hamd-only operator workflow 2026-08-07 14:37:47 -04:00
LICENSE Initial commit 2026-08-04 14:51:13 -04:00
README.md docs: document hamd-only operator workflow 2026-08-07 14:37:47 -04:00

ham-rs

Pure Rust tools for amateur-radio control.

Workspace

Crate Purpose
ham-audio Linux PipeWire device discovery and gated voice-audio bridge
ham-radio Vendor-neutral radio types, state, capabilities, and async control trait
icom-civ Icom CI-V frames, streaming decoder, BCD frequencies, and mode encoding
ic7100 IC-7100 command construction and exclusive async serial controller
mfj-226 MFJ-226 PC Mode serial client and documented wire-format types
mfj-226-cli MFJ-226 interactive TUI and one-shot text/JSON automation CLI
ham-cli ham command-line utility and interactive terminal UI
ham-api Reusable Axum router and the hamd HTTP server
nwr-same NOAA Weather Radio channels, stations, and SAME/EAS alert parsing

The dependency direction is intentionally one-way: applications depend on the radio abstractions and protocol codec, while neither library depends on a UI or network server.

IC-7100 voice console and hamd

The MVP targets Linux with PipeWire and an Icom IC-7100 connected over USB. On Debian-family systems, install the native build dependency first:

sudo apt install libpipewire-0.3-dev

hamd is the sole owner of the IC-7100 serial port. Start it before using the TUI or command-line radio controls:

just api

In another terminal, start the TUI:

just run

just run has no Hamlib serial preflight or postflight; it is an HTTP client of hamd. just validate likewise only reads hamd's health and current radio snapshot. Neither command is evidence that a live radio or audio path has been verified.

First-run TUI setup selects only PipeWire audio endpoints and stores stable audio IDs in ~/.config/ham-rs/config.toml. It does not discover, select, or open a serial port. Older config files may retain a [radio] table; it is ignored for compatibility. Run ham tui --setup to repeat audio selection.

Inside the console, W applies and reads back the WX4EMA VHF FM preset (147.015 MHz, +600 kHz, 88.5 Hz), A arms transmit, Space toggles PTT, and X forces receive. PTT remains opt-in on the hamd host and requires a live WebSocket control session; hamd enforces a 60-second continuous key-down ceiling. See the ham-api README for the API and PTT requirements.

Press Tab to open the receive-only NWR / SAME tab. Use Up/Down and Enter to tune and save one of the seven NOAA Weather Radio channels, or press S to scan all seven and save the channel with the strongest reading from hamd's GET /v1/radio/s-meter endpoint. The saved channel is restored when the tab is opened on a later run. The tab records the IC-7100 receive audio in durable 12-second WAV chunks and shows a slightly delayed, local Whisper transcription. It also demodulates the SAME AFSK data directly: watch alerts turn the NWR outline yellow, warnings turn it red, and the SAME end-of-message clears the alert outline.

NWR sessions are stored under $XDG_STATE_HOME/ham-rs/recordings (or ~/.local/state/ham-rs/recordings) with chunk-NNN.wav, transcript.md, and alerts.jsonl files. The first chunk triggers a one-time download of the checksum-verified base.en Whisper model. Set HAM_RS_WHISPER_MODEL to use a local model; MEETRS_MODEL and a verified model in ~/.meetrs/models are also reused automatically.

The receive-only Digital / FT8 tab starts the local FT8/FT4 decoder on the saved IC-7100 PipeWire input, shows 15-second-cycle diagnostics and recent decodes, and releases the capture stream when the tab is left. C clears the decode history. Automated tests use fakes and local test servers; they do not verify a live radio, audio path, decode, or transmission.

ham scan and ham tune

Alongside the interactive console, ham exposes commands for sweeping and tuning through the running hamd hardware owner. There is no direct-serial fallback and no --direct option.

ham scan <BAND>

Asks hamd to sweep one of ten HF band presets (160m, 80m, 60m, 40m, 30m, 20m, 17m, 15m, 12m, 10m) in --step-hz increments (default 5000, range 1–1000000). Progress and terminal results arrive through the scan SSE stream:

cargo run -p ham-cli -- scan 20m
cargo run -p ham-cli -- scan 20m --step-hz 2000 --json

S-meter readings are the radio's raw 0-255 scale, not the S1-S9+ scale printed on the front panel. --threshold (default 15) flags readings above the sweep's mean. Ctrl-C asks hamd to cancel the scan; because hamd owns the transaction, it performs scan cleanup and restoration server-side.

ham scan <BAND> --listen [--listen-above N]

--listen asks hamd to stop at the first reading above --listen-above (default 60) and tune there.

cargo run -p ham-cli -- scan 20m --listen
cargo run -p ham-cli -- scan 20m --listen --listen-above 80

--listen-above is an absolute raw S-meter floor (0-255), unlike --threshold, which is relative to the sweep's mean. hamd classifies hits and reports whether it snapped onto a digital dial frequency. A successful listen hit is deliberately left tuned; other terminal scan outcomes are handled by the daemon's cleanup path.

ham tune <FREQ_HZ> [--mode MODE]

Asks hamd to tune to a frequency, in hertz, and leaves the radio there:

cargo run -p ham-cli -- tune 14074000 --mode usb-data
cargo run -p ham-cli -- tune 1840000

The client defaults to http://127.0.0.1:8080. Override it with HAM_API_ADDR (an address or full base URL) and set HAM_API_TOKEN when hamd requires bearer authentication. The same values can be stored in the config file:

[api]
address = "radio-host:8080"
token = "replace-with-the-shared-token"

Environment variables take priority over the config file. ham scan, ham tune, and the TUI all use this API client; none opens the configured serial port.

--mode accepts lsb, usb, am, cw, rtty, fm, wfm, cw-r, rtty-r, dv, usb-data, and lsb-data. With no mode, mode selection and any digital-dial snapping are server-side decisions. ham tune deliberately leaves the radio tuned where requested.

Development

cargo fmt --all --check
cargo clippy --workspace --all-targets
cargo test --workspace

Try the command-line tools:

cargo run -p ham-cli -- info
cargo run -p ham-cli -- tui --help

Run the API server on its default loopback address, 127.0.0.1:8080:

cargo run -p ham-api --bin hamd
curl http://127.0.0.1:8080/health
curl http://127.0.0.1:8080/v1/radio

Override the listener with HAM_API_ADDR.