-
The Hunt, Part 10: Offline vs Live Surveys — Hunting a Recording
How GopherTrunk replays a recorded IQ capture through the exact same sweep, classify, identify, and accumulate pipeline it runs on the air — offline carrier detection with signed offsets, a shared per-candidate routing body, and why a find reproduces from a .cfile byte-for-byte.
-
Running It For Real, Part 10: Broadcast Backends II — RdioScanner, OpenMHz, Icecast
Operating the other three call destinations on a 24/7 daemon — RdioScanner and OpenMHz credentials and endpoints riding the shared retry loop, and why Icecast is the odd one out that drops instead of retrying, reconnects on its own, and needs a source password kept off disk.
-
Recording, Composition & Streaming, Part 13: Outbound Streaming — The Broadcast Manager
How GopherTrunk ships a finished call to the outside world — one bus subscriber that gates on stream/duration, encodes MP3 exactly once, and fans out through a bounded worker pool with drop-on-full and exponential-backoff retry so a wedged aggregator can never back-pressure the decode path.
-
The Operator's Cockpit, Part 10: Write Mode — Mutating Config Safely
How GopherTrunk lets a browser or terminal change a running daemon without lying about what took effect — the mutation-capability gate, pointer-field PATCH semantics that preserve leave-alone, the hot-reload vs restart-required split, an mtime conflict guard, and the validate-then-activate config swap.
-
The Hunt, Part 9: Wideband Multi-Site P25 — Watching Many Channels at Once
How GopherTrunk pins one wideband SDR to a band centre, splits its IQ into a narrowband stream per control channel with a tuner bank, and runs a per-channel P25 (or DMR) state machine on each — so a whole multi-site system's control channels are watched simultaneously off a single dongle.
-
Running It For Real, Part 9: Broadcast Backends I — Broadcastify
Operating a Broadcastify Calls feed on a 24/7 daemon — where the API key and system ID live, how the two-leg upload retries with exponential backoff, how a rejection surfaces, and the counters that tell you a feed went quiet before your listeners do.
-
Recording, Composition & Streaming, Part 12: Live Listening — The Local Audio Path
How GopherTrunk lets you hear a call the instant it decodes — a lock-free AudioPublisher fan-out, an open-ended WAV HTTP stream that even Safari will play, a gRPC StreamAudio path, and a host speaker player that deliberately refuses digital PCM to avoid an echo.
-
The Operator's Cockpit, Part 9: The Map — Plotting Sites & Emitters
How GopherTrunk plots P25 sites and position-bearing emitters — APRS, AIS, ADS-B, DSC — on one shared Leaflet map, patching markers in place from the daemon's locations and sites REST endpoints as fixes arrive, with an auto-fitting camera and a merged discovered-plus-configured site table.
-
The Hunt, Part 8: DMR LCN Correlation — Rebuilding a Channel Map
How GopherTrunk learns a DMR Tier III band plan that is never broadcast — correlating granted logical channel numbers to the RF carriers that key up in response, confirming each pairing by decoding a DMR sync, and fitting a base-plus-spacing grid it hot-swaps into the live control channel.
-
Running It For Real, Part 8: The Opt-In Feature Matrix
How GopherTrunk decides what runs by default versus what stays off until you ask — the three kinds of feature gate, why headless-safe defaults matter, and the one config rule that keeps optional subsystems from surprising a 24/7 daemon.
-
Recording, Composition & Streaming, Part 11: Retention & Housekeeping
How GopherTrunk bounds disk and database growth with one idempotent background sweeper — call-row age, an allow-listed set of decoder-log tables, and mtime-based deletion of only .wav and .raw artifacts under an opt-in files root, each lane gated independently by config.
-
The Operator's Cockpit, Part 8: Constellation, Eye Diagram & Symbol Scope
How one WebSocket symbol stream off the daemon feeds three browser DSP scopes — a complex constellation, a folded C4FM eye diagram, and a rolling symbol oscilloscope — with server-side offset tuning to dodge the DC spike and a soft-vs-dibit frame shape shared across all three canvases.
-
The Hunt, Part 7: Locking a P25 System — Candidate to Confirmed
How GopherTrunk turns a locked P25 control channel into a confirmed DiscoveredSystem — folding WACN and System ID into an identity, recovering the IDEN_UP band plan, resolving neighbour frequencies, and honestly reporting when the NSB that carries the WACN never decoded.
-
Running It For Real, Part 7: SDR Doctor & Preflight
How GopherTrunk catches a bad dongle, wrong USB driver, or broken config before it costs a call — the read-only sdr doctor that inspects per-device driver binding, the preflight that validates directories and TLS files before the listener binds, and the gain-sanity warnings.
-
Recording, Composition & Streaming, Part 10: The Call Log — SQLite Persistence & Never-Downgrade Updates
How GopherTrunk indexes every call into a CGO-free SQLite call_log by subscribing to the bus — an INSERT on start, an UPDATE on end keyed by device and timestamp, and a COALESCE/NULLIF discipline that backfills late RID and encryption without ever clobbering a value it already knew.
-
The Operator's Cockpit, Part 7: Live Spectrum & Waterfall in the Browser
How GopherTrunk streams FFT frames from the SDR broker over a WebSocket and paints a scrolling waterfall plus analyzer trace on a canvas — a per-request FFT producer, a rate-clamped frame protocol, ImageData row rendering, and an FFT-shifted x-to-frequency mapping that powers hover readout and click-to-tune.
-
The Hunt, Part 6: Control-Channel Hunting — The Supervisor
How GopherTrunk's cchunt supervisor multiplexes per-system control-channel hunts over one shared SDR, dwelling on candidates, parking on locks, backing off failures exponentially, and publishing HuntProgress so the cockpit can watch every system at once.
-
Running It For Real, Part 6: The Diagnostics Reporter
How GopherTrunk prepends a host/SDR snapshot to every error surface — the boxed boot banner, the memoized Collector that enumerates dongles at most once, the cheap-versus-costly split in SysInfo, the full error-chain verbose trace, and the non-TTY-safe reporter.
-
Recording, Composition & Streaming, Part 9: CallComplete — The Seam to Everything Downstream
How GopherTrunk's single CallComplete event decouples recording from streaming and persistence — what finalizeLocked builds, the identity and file metadata it carries, the per-call VoiceStats quality log emitted alongside it, and why the demod signal, EVM, and SNR figures ride the earlier CallEnd instead.
-
The Operator's Cockpit, Part 6: Client-Side Resampling
How GopherTrunk plays 8 kHz voice on a 48 kHz browser AudioContext — a windowed-sinc polyphase resampler that carries a history tail and fractional cursor across network chunks, per-phase unity-gain normalized, band-limiting the images that linear interpolation leaks, with a split-feed-equals-whole-feed test as its keystone.
-
The Hunt, Part 5: Autogain & Autotune — Settling the Front End
How GopherTrunk sweeps front-end gain to minimize the decode error rate before committing to a control channel, and how a running-average autotune corrects each dongle's crystal offset so a decoder's carrier loop starts already near lock.
-
Running It For Real, Part 5: Structured Logs — Event, Message & Power
How GopherTrunk writes three purpose-built logs off one event bus — the JSONL event log for machines, the human-readable decoded-message log, and the decode-gated power log — plus the panic-recovery guard that turns a crashing goroutine into a logged, survivable event.
-
Recording, Composition & Streaming, Part 8: Loudness at the Output Stage
Where and when GopherTrunk applies loudness leveling to a finished call — an atomic per-call rewrite of the on-disk WAV, an independent in-memory gain on the distributed MP3 copy, and an optional real-time AGC on the live browser stream — each a separate config switch, none re-deriving the BS.1770 math.
-
The Operator's Cockpit, Part 5: The Live Audio Cockpit
How GopherTrunk streams live decoded voice to the browser — a publisher that fans PCM to bounded per-subscriber channels, a continuous open-ended WAV body served over fetch so the auth header rides along, and an AudioWorklet ring buffer that emits silence on underrun for gapless playback.
-
The Hunt, Part 4: Classifying a Signal — Analog, Digital, Encrypted
How GopherTrunk cheaply classifies a bare carrier into analog, digital, paging, or encrypted using envelope, discriminator, and cyclostationary features before spending an expensive protocol identify, and how the encryption triage tells structured traffic from random.
-
Running It For Real, Part 4: Metrics That Matter — Prometheus & SDR Tiles
How GopherTrunk's Prometheus registry is built — bus-driven counters versus scrape-time snapshot collectors, the SDR tiles worth alerting on (IQ power, clip ratio, gain, lock state), why calls_started beats calls_total, and the opt-in FEC histograms.
-
Recording, Composition & Streaming, Part 7: Correctness Guards — Cross-Call Fencing, Encryption Skip & Runtime Toggles
The subtle safety machinery in GopherTrunk's recorder and audio publisher — a CallID fence that stops a reused voice-tap serial bleeding one call's tail into the next, mid-stream encryption abort-and-delete, grant backfill for late-resolving IDs, and runtime record on/off that never drops an in-flight call.
-
The Operator's Cockpit, Part 4: The Event Stream — SSE to React
How GopherTrunk fans every internal bus event to clients as one JSON envelope — Server-Sent Events for the terminal and curl, a WebSocket twin for the browser that can't set an auth header — with jittered reconnect backoff, frame coalescing, and interval poll hooks that only re-render on real change.
-
The Hunt, Part 3: Peaks & Occupancy — Finding Carriers in the Noise
How GopherTrunk estimates a robust noise floor, picks true carrier peaks without triple-counting one emitter, snaps them onto the land-mobile channel raster, and separates narrow carriers from wide OFDM plateaus in one spectrum frame.
-
Running It For Real, Part 3: TLS & Sitting Behind a Reverse Proxy
How GopherTrunk terminates TLS on its HTTP and gRPC listeners, why plain TCP stays the default, the both-or-neither cert/key rule, the permissive-by-default CORS allow-list, and the loopback-upstream reverse-proxy pattern with nginx or Caddy.
-
Recording, Composition & Streaming, Part 6: Segmentation, Naming & Raw Sidecars
How a trunked call maps to the filesystem in GopherTrunk — the system/talkgroup directory scheme, timezone-aware timestamped filenames tagged with frequency, source and timeslot, per-transmission file rolls, and the .raw sidecar written for DMR, ProVoice and TETRA.
-
The Operator's Cockpit, Part 3: The Connect Screen & Auth Handshake
How a browser pairs with a GopherTrunk daemon — the connect screen that probes health before saving, the three-mode bearer-token policy with loopback trust, the mutation gate, and the capability probe that lets a front-end grey out write controls before it ever tries them.
-
The Hunt, Part 2: The Wideband Sweep Engine
How GopherTrunk steps a wide SDR receiver across megahertz of spectrum, estimates a power spectrum from short IQ grabs, and stitches overlapping tiles into one occupancy picture without dropping a carrier at a step boundary.
-
Running It For Real, Part 2: Auth Posture — Closed-LAN, Auto, Required
How GopherTrunk's mutation-endpoint auth works — the disabled/auto/required modes, why the default flipped to disabled for closed-LAN deployments, the loopback and trusted-network bypasses, constant-time token comparison, and hot token rotation without a restart.
-
Recording, Composition & Streaming, Part 5: WAV on Disk — Crash-Safety, the Tolerant Reader & Clean Cuts
How GopherTrunk's recorder turns decoded PCM into a WAV that survives a crash — placeholder-then-patch RIFF headers, a chunk-walking reader that clamps a truncated final chunk, an end-of-call fade tail, and dead-key suppression that removes empty files.
-
The Operator's Cockpit, Part 2: A React SPA Inside a Go Binary
How GopherTrunk embeds its built Vite/React bundle into the daemon with go:embed all:dist, serves it at the root with a client-side-routing SPA fallback, degrades to a helpful message when the embed is empty, and stays a plain API client so browser and standalone deployments are identical.
-
The Hunt, Part 1: What Discovery Means — From a Blank Band to a Known System
How GopherTrunk turns an empty stretch of spectrum into a named, mapped trunked system — the sweep, identify, and map pipeline behind the hunt engine, and the one discovery contract that the CLI, the daemon, and the web cockpit all drive.
-
Running It For Real, Part 1: From a Laptop Demo to a 24/7 Service
What actually changes when GopherTrunk stops being a laptop demo and becomes an unattended 24/7 service — the daemon lifecycle, dependency-ordered construction and teardown, graceful shutdown, the supervised spawn model, and the operator mindset behind the whole series.
-
Recording, Composition & Streaming, Part 4: The Recording Session
How GopherTrunk's per-call recording session opens files lazily on the first write so dead-keys leave nothing on disk, carries identity forward through dormant post-segment parks, and runs decode-only when no recordings directory is configured.
-
The Operator's Cockpit, Part 1: One Engine, Many Front-Ends
How one running GopherTrunk daemon exposes a single REST + Server-Sent-Events contract that both a React SPA in the browser and a Bubbletea terminal TUI render, kept honest by an api package that talks only to interfaces and never imports the SDR pool.
-
Recording, Composition & Streaming, Part 3: Assembling a Call
How GopherTrunk turns a burst of separate overs into one continuous call — hangtime, talkgroup gating and per-transmission splitting surfacing as segment events that roll the recorder's files, from the output side rather than the DSP.
-
Recording, Composition & Streaming, Part 2: The Composition Contract
How composed audio crosses from GopherTrunk's demod composer into its recorder through three consumer-owned interfaces, why the recorder is the one place a call is decoded, and how the PCM path and the raw-vocoder-frame path differ.
-
Recording, Composition & Streaming, Part 1: The Output Half
How GopherTrunk turns a decoded call into files, feeds, and uploads — four independent, config-gated subsystems that subscribe to a handful of bus events instead of calling each other, so recording, persistence, live audio, and streaming never block one another.
-
Voice Coding, Part 12: Calibrating & Testing Vocoders Against References
How GopherTrunk proves its pure-Go IMBE and AMBE+2 decoders are correct — the voice-calibrate harness, golden-frame regression, streaming decode, and cross-correlation against DSD-FME and OP25.
-
Trunking Engine, Part 12: Control-Channel Hunting, the Call Watchdog & Testing With a Fake Bus
How GopherTrunk finds a control channel and backs off when it can't, how a 500 ms watchdog reaps calls that go silent, and how the whole engine is tested by publishing synthetic grants to a fake bus with no radio attached.
-
Protocol Decoders, Part 12: Testing Decoders Without Radios
How GopherTrunk tests every protocol decoder with no SDR and no live system — synthesized control channels modulated through the real TX chain, a decoder registry, golden fixtures, and the regression discipline that makes 'verified' mean something.
-
Voice Coding, Part 11: Recording & Encoding — WAV, MP3, Tone-Out & Hardware
How GopherTrunk writes crash-safe WAVs, encodes MP3 in pure Go with a Xing/LAME header, detects paging tones with Goertzel, and offers an optional DVSI hardware vocoder behind a build tag.
-
Trunking Engine, Part 11: Encrypted-Mode Handling — Follow, Metadata, or Ignore
How GopherTrunk decides what to do with an encrypted trunked call — hold the tuner, grab metadata and release, or ignore it — with a per-system policy, a configured-key exemption, and a metadata-follow window that frees scarce voice SDRs.
-
Protocol Decoders, Part 11: The Alias Hunt II — The Keystream, Dead Ends & Ethics
The clean-room cryptanalysis of the Motorola P25 talker-alias cipher — the per-character affine keystream, every ruled-out hypothesis, the low-byte observability floor that keeps it uncracked, and the ethics that gate it all.
-
Voice Coding, Part 10: Enhancement & Loudness — Making It Sound Right
The post-synthesis audio chain in GopherTrunk's MBE decoders — spectral enhancement, DC blocking, AGC, tone tilt, an opt-in voice enhancer, and per-call EBU R128 loudness normalization.
-
Trunking Engine, Part 10: Sites, Topology & Multi-Site Roaming
How GopherTrunk accumulates a P25 system's site map from control-channel status broadcasts, tracks a radio roaming between sites, and renders an SDRtrunk-style network configuration report — all derived from the event stream.
-
Protocol Decoders, Part 10: The Alias Hunt I — Framing the Unsolved Cipher
The Motorola P25 talker-alias field carries an encrypted display name. Part 1 of the capstone frames it correctly — the SUID header, the critical strip-the-CRC lesson, the verified per-byte decode model, and the recovered 256-entry LUT.
-
Voice Coding, Part 9: The Composer — Wiring Frames to the Right Vocoder
How GopherTrunk's composer turns a CallStart event into PCM — per-protocol demod chains, front-end decimation, boundary handling, and how the recorder maps each protocol to its vocoder.
-
Trunking Engine, Part 9: Patches, Supergroups & Physical-Channel RID Recovery
How GopherTrunk tracks P25 patches and dynamic-regroup supergroups, and how folding a source RID by physical channel recovers the transmitter and kills a phantom duplicate call from a mis-aliased compressed grant.
-
Protocol Decoders, Part 9: Conventional, Wideband & the Symbol Scope
How GopherTrunk decodes what isn't a trunked control channel — fixed-frequency conventional scanning with tone squelch, wideband multi-carrier Phase 2, DMR LCN band-plan learning, and the symbol-scope diagnostic.
-
Voice Coding, Part 8: AMBE+2 FEC & the Knox Path
Where AMBE+2 error correction actually lives, how GopherTrunk conceals bad frames with replay and adaptive smoothing, and what the vendor-specific knox tone path really is — and isn't.
-
Trunking Engine, Part 8: Affiliation Tracking — Building the Roster From the Event Stream
How GopherTrunk builds a live "which radio is on which talkgroup" roster entirely from the trunking event stream — grants, affiliation responses, and unit registrations — with no extra radio I/O.
-
Protocol Decoders, Part 8: The Legacy Family — EDACS, LTR & MPT-1327
How GopherTrunk follows the pre-digital trunking systems — EDACS 9600-baud CCWs, LTR's central-control-free per-repeater status words, and MPT-1327 FFSK codewords — and why they decode nothing like a modern digital control channel.
-
Voice Coding, Part 7: AMBE+2 — One Decoder, Two Rates
How GopherTrunk's pure-Go AMBE+2 decoder unpacks 49 information bits into shared MBE parameters, and why P25 Phase 2, DMR, and NXDN all run through one Go decoder with two rate tables.
-
Trunking Engine, Part 7: Recovering the Source Radio ID (Issue #915)
A current-work deep dive into how GopherTrunk backfills the source radio ID onto calls that bound from a source-less P25 Phase 2 grant, republishing it through the source-update path so nearly every call reports who keyed up.
-
Protocol Decoders, Part 7: TETRA — π/4-DQPSK, Channel Coding & the Sub-Target-Rate Fix
How GopherTrunk decodes TETRA — π/4-DQPSK framing, the type-1 to type-5 channel-coding chain, CMCE grant PDUs, and the recent fix that interpolates a narrowband capture up to the 144 kHz channel rate so the receiver locks.
-
Voice Coding, Part 6: The Call-Startup Acquisition Squelch
A real bug in GopherTrunk — fresh P25 recordings opened with a full-scale noise burst while the receiver acquired lock, because the FEC resolved marginal dibits to valid-but-wrong IMBE frames. Here's the heuristic that mutes it.
-
Trunking Engine, Part 6: Talkgroups, Aliases & Scan Modes
How GopherTrunk's talkgroup database gives numeric IDs names and policy, how hold and lockout gate a call, and how the engine flips between scan-all and scan-list at runtime from the cockpit without a restart.
-
Protocol Decoders, Part 6: NXDN & dPMR — The Narrowband FDMA Family
How GopherTrunk decodes NXDN and dPMR — the 6.25 kHz FDMA narrowband modes — their 80 ms frames, LICH and CAC signalling, CSBK trunking blocks, and convolutional FEC, and how they contrast with the TDMA modes.
-
Voice Coding, Part 5: IMBE FEC & De-Interleave — Recovering the Bit Soup
How GopherTrunk turns 144 noisy on-air IMBE channel bits into 88 clean information bits — the Golay and Hamming FEC on the eight u-vectors, the channel layout, and why de-interleave must run before descramble.
-
Trunking Engine, Part 5: Priority & Preemption When Calls Outnumber Radios
How GopherTrunk decides which call to drop when active calls exceed voice SDRs — the priority ranking, strict-higher preemption rule, emergency override, and the thrash and starvation it is tuned to avoid.
-
Protocol Decoders, Part 5: DMR Tier 2/3 — Bursts, EMB & FLC
How GopherTrunk decodes DMR's two-slot TDMA — the 132-dibit burst, the sync words closed under polarity flip, the slot-type Hamming code, embedded signalling and Full Link Control, and the reverse channel.
-
Voice Coding, Part 4: IMBE — Decoding P25 Phase 1 Voice
How GopherTrunk turns 88 IMBE information bits into MBE parameters — the b_0 pitch codeword, the PRBS scrambler that whitens the spectrum, and the table-driven PRBA and DCT quantization that reconstruct the spectral envelope.
-
Trunking Engine, Part 4: The Voice Pool — Allocating Scarce Radios
How GopherTrunk's voice pool allocates a handful of Voice-role SDRs across many talkgroups, binds a call, retunes for handoffs, and detects when a wideband rig's tuning window doesn't cover the granted repeater.
-
Protocol Decoders, Part 4: P25 Phase 2 TDMA — The MAC Layer
How GopherTrunk decodes P25 Phase 2's two-slot TDMA — the ISCH slot-type field, the 360 ms superframe, the MAC PDU layer, and the compressed source-less grant that forces a source-RID backfill downstream.
-
Voice Coding, Part 3: MBE Synthesis — Voiced Sinusoids + Unvoiced Noise
How GopherTrunk grows 160 samples of speech from an MBE parameter set — summed sinusoids for the voiced bands, FFT-shaped noise for the unvoiced bands, and the cross-frame phase and overlap-add smoothing that kills clicks.
-
Trunking Engine, Part 3: Grants — The Engine's Only Input
A field-by-field tour of GopherTrunk's protocol-agnostic Grant struct, source-bearing versus source-less grants, and the duplicate-grant guard that stops a repeated control-channel TSBK from binding a second radio.
-
Protocol Decoders, Part 3: P25 Phase 1 TSBKs & Link Control
How GopherTrunk parses P25 Phase 1 Trunking Signaling Blocks — the CRC-checked 12-byte TSBK, its OSP opcode taxonomy, vendor Motorola extensions, TDULC and Link Control — and turns a grant PDU into the Grant the trunking engine records.
-
Voice Coding, Part 2: The MBE Model — Pitch, Voicing & Spectral Envelope
The Multi-Band Excitation parameter set at the heart of IMBE and AMBE+2 — fundamental frequency, per-band voiced/unvoiced decisions, and spectral amplitudes, as the Go structs both codecs synthesize from.
-
Trunking Engine, Part 2: The Event Bus — Typed Pub/Sub That Decouples Everything
How GopherTrunk's in-process event bus fans typed events from the trunking engine to every subscriber, with async delivery and overflow protection so one slow consumer can never stall the decode path.
-
Protocol Decoders, Part 2: P25 Phase 1 — NID, Sync & the FEC That Gates Lock
A field-level tour of P25 Phase 1's physical layer in GopherTrunk — the 48-bit frame sync, the BCH-protected NID with its NAC and DUID, C4FM 4-level symbols, and the trellis plus Hamming FEC that decide whether a control channel locks.
-
Voice Coding, Part 1: What a Vocoder Is & the Pluggable Registry
How GopherTrunk turns 2400-bit-per-second radio data back into speech — what a vocoder actually models, and the Go Vocoder interface + registry that lets IMBE and AMBE+2 plug in behind one seam.
-
Trunking Engine, Part 1: From Grant to Recorded Call
A tour of GopherTrunk's trunking engine — the single-goroutine state machine that subscribes to control-channel grants, allocates a voice SDR, starts a call, and publishes events, without ever importing the code that records or displays them.
-
Protocol Decoders, Part 1: Anatomy of a Control-Channel Decoder
How every GopherTrunk control-channel decoder shares one shape — symbols to framing to FEC to PDU to opcode to bus event — behind a single pipeline interface and a protocol-keyed factory registry.
-
RF Front End, Part 14: Diagnostics, Metrics & the Pure-Go Payoff
The finale of RF Front End. How GopherTrunk makes the front end observable — sdr list --probe, the RTLSDR_DEBUG_USB control-transfer trace, and the iq_underruns_total metric that turned silent IQ loss into something an operator can see — and then the payoff the whole series argued for: one static binary, CGO_ENABLED=0, no librtlsdr, no libusb, cross-compiled everywhere.
-
RF Front End, Part 13: Testing Radios Without Radios
How GopherTrunk's USB driver code is tested in CI with no hardware attached — replaying captured control-transfer sequences through a scripted mock transport, pinning the pure-Go sample conversion bit-for-bit against librtlsdr with a golden-master test, and an opt-in real-hardware tier gated behind environment flags with bias-tee safety resets.
-
RF Front End, Part 12: The SDR Pool & USB Hotplug Watchdog
How GopherTrunk manages a fleet of opened dongles behind one pool — assigning control, voice, and wideband roles, running a USB watchdog that re-enumerates every 30 seconds to catch hotplug, and reacquiring a device after the kernel hands it a new bus address. Plus the re-open race that taught us to serialize retune behind stream teardown.
-
RF Front End, Part 11: HackRF One — Signed 8-Bit IQ End to End
The HackRF One driver end to end — the simplest IQ format of the three, signed 8-bit interleaved I,Q scaled to complex64; enumeration across One/Jawbreaker/Rad1o PIDs; and the open-time board-ID readback that fixed empty probe gains by establishing identity and the gain ladder before streaming.
-
RF Front End, Part 10: Airspy R2/Mini & HF+ — Real Samples to Complex Baseband
How GopherTrunk turns the Airspy R2/Mini's bare real ADC stream into complex baseband entirely on the host — a leaky DC blocker, a multiplier-free Fs/4 mix, and a stateful half-band Hilbert pair — then folds in the Airspy HF+, whose native int16 IQ needs none of it.
-
RF Front End, Part 9: RTL-SDR III — IQ Streaming & the GC-Churn Bug
Sustained IQ streaming from the RTL2832U in pure Go — 32 async USB buffers, a deep consumer channel, and a bit-identical U8-to-complex64 lookup table. Plus the headline bug: per-chunk allocations whose GC churn shed a quarter of the control channel's live IQ, and the zero-allocation reuse ring that fixed it.
-
RF Front End, Part 8: RTL-SDR II — The R82xx Tuner & the Blog V4 Deafness
GopherTrunk's pure-Go R820T/R828D tuner driver — PLL tuning, a shadow-register cache that makes read-modify-write free, and tuner auto-detection. Plus the headline bug: why the RTL-SDR Blog V4 came up deaf and mistuned by 1.8×, and how a manual override plus per-band input switching fixed it.
-
RF Front End, Part 7: RTL-SDR I — Bringing Up the RTL2832U
How GopherTrunk brings up the RTL2832U demodulator in pure Go — the order-sensitive init sequence captured verbatim from librtlsdr, the I2C bridge to the tuner, GPIO and bias-tee, and the USB register transport underneath it all.
-
RF Front End, Part 6: USB on macOS & Windows
How GopherTrunk reaches the same Transport contract through macOS IOKit (via purego, with OS-thread-pinned reader goroutines) and Windows WinUSB (with overlapped I/O), and why macOS forced us to own the calling thread.
-
RF Front End, Part 5: USB on Linux — USBDEVFS & Async URBs
How GopherTrunk's Linux USB backend hand-rolls USBDEVFS ioctl encoding, submits a ring of async URBs, and reaps them in a single goroutine for sustained IQ throughput — all in pure Go behind a safe Transport API.
-
RF Front End, Part 4: Talking to USB Without libusb
How GopherTrunk speaks to RTL-SDR hardware over raw kernel USB interfaces instead of linking libusb, and the single Transport contract that lets one driver run on three wildly different OS USB stacks.
-
Rebuilding GopherTrunk from Source: Update to the Latest Version with Git and GitHub
A copy-paste guide to rebuilding GopherTrunk from source with the Git CLI and GitHub — clone the repo, check out the latest version or a specific branch, build the pure-Go binary, verify it, and keep an existing clone up to date.
-
RF Front End, Part 3: The Driver Registry & Enumeration
How GopherTrunk's self-registering driver registry keeps the core hardware-agnostic — drivers register at init(), the binary's import set chooses the hardware, and EnumerateAll walks every backend to list attached dongles while staying resilient when one driver fails.
-
RF Front End, Part 2: The Device Contract
A method-by-method tour of GopherTrunk's Device interface — the one abstraction four very different radios hide behind — and the optional, type-asserted extension interfaces that expose RTL-SDR-only quirks without polluting the universal contract.
-
RF Front End, Part 1: Why Drive Radios in Pure Go?
The opening post of RF Front End, a 14-part deep dive into GopherTrunk's RF source layer — the pure-Go USB drivers that turn RTL-SDR, Airspy, and HackRF hardware into IQ samples without libusb, librtlsdr, or any C dependency.
-
SDR in Pure Go, Part 14: APIs, Testing & the Pure-Go Story
How GopherTrunk exposes the engine through gRPC, REST, WebSocket and a TUI, observes it with Prometheus and SQLite, and proves it works with synthesized-IQ integration tests — a ports-and-adapters finale.
-
SDR in Pure Go, Part 13: Recording, Composition & Streaming
How GopherTrunk records calls to WAV, drives a per-call demodulation chain with the composer, and streams audio to Broadcastify and RdioScanner — all from optional, config-driven subsystems.
-
SDR in Pure Go, Part 12: Voice Coding — IMBE, AMBE+2 & MBE
How GopherTrunk turns digital voice frames into audio with pure-Go IMBE and AMBE+2 vocoders sharing one MBE synthesis core, all behind a pluggable Vocoder registry.
-
SDR in Pure Go, Part 11: The Trunking Engine & Event Bus
How GopherTrunk's trunking engine turns channel grants into recorded calls, and how an in-process pub/sub event bus decouples the core from the API, storage, and streaming subsystems.
-
SDR in Pure Go, Part 10: Protocol Decoders as State Machines
How GopherTrunk decodes P25, DMR, NXDN, TETRA and a dozen more trunking protocols in pure Go — each a stateful receiver behind a uniform Grant contract, an adapter pattern that keeps the engine protocol-agnostic.
-
SDR in Pure Go, Part 9: Framing & Forward Error Correction
How GopherTrunk recovers clean data from noisy symbols using pure-Go forward error correction — Golay, BCH, Hamming, Reed-Solomon, BPTC, trellis, and Viterbi — built as deterministic, table-driven codecs.
-
SDR in Pure Go, Part 8: Equalization, Diversity & the FFT
How GopherTrunk fights simulcast distortion with adaptive equalizers, combines multiple receivers with diversity, and drives the live waterfall with a rate-limited FFT — all in pure Go.
-
SDR in Pure Go, Part 7: Symbol Timing & Sync Recovery
How GopherTrunk recovers the symbol clock from oversampled signals with a Mueller-Muller timing loop and finds frame boundaries with a sync correlator — feedback state machines implemented in pure Go.
-
SDR in Pure Go, Part 6: Demodulation — FM, C4FM, GFSK & More
How GopherTrunk turns baseband IQ into symbols with pure-Go demodulators for FM, C4FM, GFSK, FFSK, and π/4-DQPSK — each a focused, single-responsibility type composed from DSP primitives.
-
SDR in Pure Go, Part 5: Tuning & Channelization — DDC vs. Polyphase
How GopherTrunk extracts many narrowband channels from one wideband SDR capture using a digital down-converter or a polyphase channelizer, selected at runtime through a Go Strategy interface.
-
SDR in Pure Go, Part 4: DSP Foundations — Filters, NCO & AGC
The building blocks of GopherTrunk's signal chain in Go — FIR/CIC filters, a numerically-controlled oscillator, automatic gain control, and resamplers — and the zero-allocation streaming design behind them.
-
SDR in Pure Go, Part 3: The SDR Pool & Streaming Concurrency
How GopherTrunk streams IQ samples through Go channels and goroutines, manages a fleet of SDR dongles with a device pool, and fans one stream to many consumers without blocking the decode path.
-
SDR in Pure Go, Part 2: SDR Devices & the Driver Registry
How GopherTrunk talks to RTL-SDR, HackRF, and Airspy hardware in pure Go behind one Device interface, and how a self-registering driver registry keeps the core hardware-agnostic.
-
SDR in Pure Go, Part 1: What Is Software-Defined Radio?
A pure-Go tour of software-defined radio — what SDR is, the GopherTrunk signal pipeline from RF to audio, and the layered architecture behind a single static binary.