Advanced & power-user features
This is the rest of GopherTrunk — the parts you reach for once you’re running a serious setup or want to integrate it with other tooling. The same single binary that’s been recording your calls also carries a terminal cockpit, a bench of signal scopes, an offline analysis workbench, a dozen more decoders, and typed APIs.
Before you start. This guide assumes Going further — comfort with
config.yaml, the terminal, and a multi-dongle pool. It’s comfortable with command-line subcommands and a little signal-processing vocabulary.
The terminal cockpit and signal scopes
The web console isn’t the only front end. The TUI is a full-screen terminal cockpit with the same panels — ideal over SSH or on a headless box. It also exposes GopherTrunk’s signal scopes, the tools for seeing why a signal does or doesn’t decode:
- Constellation — the IQ scatter plot; tight clusters mean a clean signal.
- Eye diagram and Symbol scope — watch the demodulated symbols and how open the “eye” is.
- Plots, Symbol histogram, and Tuning meters — spectrum, symbol distribution, and receiver health at a glance.
Use these to chase down a marginal site: too much gain, a frequency-error offset, or a simulcast signal that needs a different demodulator.
Offline analysis: SigLab and the workbench
Beyond the live daemon, the binary carries a workbench of subcommands for working with recorded captures instead of a live radio:
gophertrunk capturerecords raw IQ off a live dongle to a file.gophertrunk replay/analyze/identifydecode a capture offline, auto-detect its protocol, and export the results to JSON / YAML / CSV.gophertrunk testgrades a decode against expected results.
SigLab wraps this workbench in a terminal and a browser
console (gophertrunk siglab / siglab serve) so you can replay, inspect, and
grade decodes without a radio attached — the natural home for diagnosing a
tricky capture or building a regression fixture. The
Architecture reference describes the decode pipeline these
tools drive.
Many more receivers
Trunked voice is just the start. GopherTrunk also decodes, each as an opt-in receiver with its own log and console panel:
- ADS-B — aircraft transponders, with a live map.
- AIS — marine vessel positions.
- APRS / AX.25 — amateur packet, beacons, and messages.
- DSC — marine digital selective calling, including distress.
- MDC1200 — Motorola in-band signaling (PTT IDs, emergency).
- FleetSync — Kenwood in-band signalling (fleet / unit ANI).
- ACARS — the VHF air-band aircraft data link, off a scanner AM channel.
- M17 — the open digital-voice link layer.
Which of these are on by default, and how to enable the rest, lives in Opt-in features.
Following multiple systems and sites
GopherTrunk can follow several trunked systems at once, but how they map onto SDRs depends on the path:
- One control channel per SDR (classic path). Each
systemin your config is followed by its own control receiver, so following N systems — or N sites of the same network, since each site is added as its ownsystemwith its own control-channel frequency — needs N SDRs withrole: control. - Many systems on one wideband SDR. A
role: widebanddevice can follow several carriers at once from a single dongle, as long as they all fit in its IQ band. This wideband multi-system path covers DMR (Tier II/III), P25 (Phase 1/2), and TETRA control channels — so multiple TETRA sites/systems can now share one wideband SDR. A TETRA channel is channelized to its own 144 kHz tap (DMR/P25 use 48 kHz), and each wideband TETRA control channel also gets four per-timeslot same-carrier voice taps on that tap (the wideband twin of the control SDR’scc:same-carriertaps), so its voice follows on the same dongle through the shared per-carrier demux — norole: voiceSDR needed. This is the supported way to monitor two TETRA systems at once from one SDR: with a singlerole: control/autotuner the hunter is a time multiplexer that camps on the first system that locks, and the daemon now warns at startup when several systems share one control SDR. -
Many conventional channels on one wideband SDR, all at once. List them under the device’s
conventional:key (the same fields as ascanner.conventionalchannel, and every scan-list mode:fm,nfm,am,p25,dmr,nxdn,nxdn48,dstar,ysf). Each channel gets its own tap, squelch, tone gate and hangtime, so overlapping transmissions on different channels record as separate, simultaneous calls; nothing scans, so a long call on one channel never hides another. They can sit on the same dongle as trunkedchannels:entries, and they need no trunking system:sdr: devices: - serial: "00000008" role: wideband center_freq_hz: 460_500_000 conventional: - { label: "Fire Dispatch", frequency_hz: 460_100_000, mode: nfm, squelch_dbfs: -50 } - { label: "EMS", frequency_hz: 460_200_000, mode: nfm, tone: { mode: ctcss, ctcss_hz: 123.0 } }An AM channel (air band) squelches on its carrier-to-noise ratio (
squelch_cn_db, default 12 dB) measured from its own tap, exactly as on the scan list, sosquelch_dbfsdoes not apply to it and the threshold does not move with the dongle’s gain.decoders: [acars]works on an AM channel here too. An airport’s tower, ground and ATIS on one dongle at 2.4 MS/s:center_freq_hz: 119_000_000 conventional: - { label: "Tower", frequency_hz: 118_300_000, mode: am } - { label: "Ground", frequency_hz: 119_900_000, mode: am } - { label: "ATIS", frequency_hz: 119_450_000, mode: am, squelch_cn_db: 15 }Each recording starts where the carrier came up, not where the call was declared: a CTCSS / DCS channel opens only once its tone is confirmed (up to about half a second into the transmission), so each channel keeps the last second of its IQ and the recording picks up from the start of the transmission. An untoned channel opens on its first chunk above squelch, so its recordings gain no lead-in of noise.
Several entries may share one frequency when each has a tone gate that tells its transmissions apart, for example two agencies on one repeater output, one on CTCSS 100.0 Hz and one on DCS 023. The carrier is extracted once, and each entry records only the transmissions carrying its own tone:
conventional: - { label: "Fire North", frequency_hz: 460_400_000, mode: nfm, tone: { mode: ctcss, ctcss_hz: 100.0 } } - { label: "Fire South", frequency_hz: 460_400_000, mode: nfm, tone: { mode: dcs, dcs_code: "023" } }Config validation refuses a shared frequency it could not tell apart: an entry with no tone (it would open on every transmission), the same tone twice, CTCSS tones under 2 Hz apart (150.0 / 151.4 Hz leak into each other), a DCS alias (023N is the same bits on air as 047I), different modes, and
decoderson more than one of the entries (data decoders ignore the tone gate, so two would decode every burst twice). Each entry’s calls run under the frequency’s serial plus its tone, e.g.wb:<dongle serial>:conv:460400000:ctcss100.0; a channel alone on its frequency keeps the plain serial. Two transmitters keying up on the same frequency at the same moment still collide on air: tones decide which channel a transmission belongs to, they cannot separate two at once.The web and TUI Scanner panels list these channels in a section of their own, Wideband conventional channels, with each channel’s mode, tone, dongle, active/idle state and last call. That section is read-only: dwell and lockout are scan-list controls, and these channels never scan. The API carries them as
conventional.wideband_channelsinGET /api/v1/scanner, next to (not inside) the scan list’schannels, so the scan list’s indexes are unchanged. Their calls appear in the call list and history like any other, under the serialwb:<dongle serial>:conv:<frequency>.The digital modes work as they do on the scan list, only continuously: a
p25channel takesnacandp25_phase1_demod_modeand opens only on its own NAC (#1262), admrchannel opens only on a call, not on a repeater’s idle beacons, aysfchannel only on a System Fusion frame sync, not on an analog carrier (#1261), and each call runs the same voice chain as a scan-list call. P25 channels may share one frequency when each sets its ownnac(not F7E / F7F), the P25 counterpart of a tone gate: an operator’s own units and another agency’s on one frequency record as two channels. Their serials end in the NAC (…:conv:460100000:nac293). The other digital modes have nothing to tell transmissions apart, so they cannot share a frequency.If the dongle’s stream stops (USB loss, a wedged driver), every open call on its conventional channels ends within about 3 s with end reason
errorrather than staying open with no audio, and the wideband engine reopens the dongle as it does for its trunked channels./metricscarriesgophertrunk_conventional_channels_configured/_activeby kind and_stalledfor these channels; each channel’s IQ-flowhealth(ok,stalled,suspended,no_iq— never derived from the air, so a quiet channel staysok) shows on the Scanner page and inGET /api/v1/scanner; and an external consumer can catch up on finished recordings after downtime fromGET /api/v1/recordings(see the API events reference).Per-channel
gainanddevicedo not apply: every tap shares the dongle’s gain. Issue #1288.
Either way, when the same call is heard on several networked or simulcast sites,
cross-site call deduplication saves it once instead of once per site: enable
recordings.dedup (a call with the same talkgroup + source already recorded from
another monitored system within the window — default 60 s — is skipped). Live
follow and monitoring are unaffected; the gate is recording-only.
Remote and recorded sources
Your dongle doesn’t have to be on the same machine — or even a physical radio:
- Remote SDRs — drive a dongle on another host over
rtl_tcp, or professional hardware (USRP, LimeSDR, bladeRF, SDRplay) over SoapyRemote. - Baseband IQ record / replay — capture the wideband IQ stream to disk and later mount the recording as a virtual dongle, so you can re-run decodes against the exact same RF.
APIs and integrations
The daemon is built to be driven by other tools. Everything the consoles do runs over public APIs:
- HTTP REST + Server-Sent Events + WebSocket — the same API the web console uses; point your own scripts and dashboards at it.
- gRPC — typed clients for calls, talkgroups, and radio IDs.
- Prometheus
/metrics— scrape GopherTrunk into your monitoring stack. - rigctld integration — speak the Hamlib wire protocol so amateur-radio logging tools (Cloudlog, GridTracker, satellite trackers) can read and set frequency.
Squeeze out every decode
When you’re chasing the last few percent of a difficult system:
- Vocoders and Voice calibration — how GopherTrunk turns digital voice frames into audio, and how to tune it.
- DMR encryption — supply keys to decode protected DMR traffic you’re authorised to monitor.
- FEC opt-outs — per-protocol error-correction toggles, documented in Opt-in features, for matching pre-stripped captures.
You now have the complete picture
From “what is this?” to driving the APIs, you’ve seen the whole of GopherTrunk: the conceptual map, a first call, everyday operation, a richer setup, and the power-user surface. Where to from here:
- Architecture — the full design: the multi-consumer IQ fan-out, the DSP chain, the voice pipeline.
- Status and Roadmap — what ships today and what’s coming.
- Support — where to get help and how to report issues.
← Back to the start: What is GopherTrunk?