Architecture
How graywolf is built and how packets flow through the system
This page covers graywolf’s internal design. You don’t need any of this to operate a station — it’s here for anyone curious about how things work under the hood, or for developers who want to contribute.
Components
Graywolf is two cooperating processes that communicate over a Unix socket using length-prefixed protobuf messages:
| Component | Language | Responsibility |
|---|---|---|
graywolf-modem |
Rust | Audio I/O, AFSK/9600/PSK demodulation, HDLC framing, FEC encoding/decoding, PTT control, TX modulation |
graywolf |
Go | AX.25/APRS protocol handling, digipeater, iGate, beacon scheduler, KISS/AGWPE servers, TX governor, REST API, web UI |
| Web UI | Svelte | Dashboard, configuration forms, live packet logs. Built at compile time and embedded in the Go binary. |
| Config DB | SQLite | All configuration state (audio devices, channels, beacons, digi rules, iGate settings). Managed through the web UI’s REST API. |
Startup Sequence
- The Go process starts and opens the SQLite configuration database.
-
It launches
graywolf-modemas a child process. The modem creates a Unix socket and signals readiness by writing to stdout. - The Go process connects to the socket and sends configuration messages: audio devices, radio channels, and PTT settings.
-
A
StartAudiomessage begins audio processing. The modem starts reading from the sound card and demodulating. - The HTTP server starts, serving the web UI and REST API. The station is now operational.
Packet Receive Path
When a packet arrives over the air:
- The Rust modem captures audio from the sound card, runs it through the AFSK demodulator (or 9600/PSK decoder), and extracts HDLC frames.
- Valid AX.25 frames are sent over the Unix socket to the Go process as protobuf messages.
- The Go process decodes the AX.25 frame and parses the APRS info field (position, message, weather, telemetry, etc.).
-
The decoded packet is fanned out to all consumers simultaneously:
- Packet log — recorded in the ring buffer for the web UI and API
- Digipeater — evaluated against rules for possible retransmission
- iGate — checked against RF filters for gating to APRS-IS
- KISS/AGWPE clients — broadcast to connected TNC clients
Packet Transmit Path
Outbound packets can originate from several sources — the beacon scheduler, the digipeater, KISS/AGWPE clients, or the iGate (IS→RF). All transmissions flow through the TX governor:
- A packet is submitted to the TX governor’s priority queue. Priority order: beacon < digipeated < client (KISS/AGWPE) < iGate message.
- The governor checks for duplicates (same source + destination + info within 30 seconds) and per-channel rate limits.
- CSMA: the governor waits for DCD to clear (channel is quiet), then applies p-persistence to randomize access timing.
- The AX.25 frame is sent to the Rust modem over the Unix socket. The modem asserts PTT, generates the AFSK audio (with TX delay preamble), and transmits.
- After the frame and TX tail are sent, PTT is released.
Performance
The Rust modem is a port of the AFSK demodulator from Dire Wolf by WB2OSZ. It achieves identical decode counts on the WA8LMF test CD while running significantly faster:
=== Direwolf (atest) ===
982 packets decoded in 45.614 seconds. 34.0 x realtime
=== Graywolf (demod_bench) ===
982 packets decoded in 6.792s. 228.2 x realtime
The IPC overhead between the Rust modem and Go process is minimal — typically 10–50 μs per message round-trip. If the modem process crashes, the Go process restarts it automatically with exponential backoff.
Deployment Options
| OS packages recommended | Native packages for Debian/Ubuntu, RHEL/Fedora, and Arch Linux. Includes a hardened systemd service. Ideal for Raspberry Pi and dedicated station computers. |
| Standalone binary | Download a release binary for Linux (amd64, arm64) or build from source. |
| Docker | Container image with audio device passthrough for containerized deployments. |
| Build from source | Clone, build, and run — requires Rust toolchain, Go 1.22+, and Node.js 22+. |
Supported Protocols
| Protocol | Description |
|---|---|
| AX.25 | Amateur Radio Link Access Protocol (UI frames, unconnected mode) |
| APRS | Automatic Packet Reporting System (APRS101 specification) |
| KISS | Keep It Simple, Stupid TNC protocol (TCP, serial, Bluetooth) |
| AGWPE | AGW Packet Engine protocol (TCP) |
| APRS-IS | APRS Internet System gateway protocol (TCP, passcode auth) |
| HDLC | High-Level Data Link Control with NRZI encoding |
| FX.25 | Forward error correction (interleaved convolutional code) |
| IL2P | Improved Layer 2 Protocol (second generation FEC) |