GopherTrunk v0.2.2 — social announcement drafts

Copy-paste drafts for posting the v0.2.2 release. Two versions below: a longer one for Reddit and a tighter one for Discord.

Release: https://github.com/MattCheramie/GopherTrunk/releases/tag/v0.2.2


Reddit

Title: GopherTrunk v0.2.2 — USB-disconnect self-healing, P25 TDMA band-plan, ALGID/KID encryption surfaced

Body:

GopherTrunk v0.2.2 is out. GopherTrunk is a pure-Go digital-trunking radio scanner for RTL-SDR / HackRF / Airspy / Airspy HF+ — P25 (Phase 1 + 2), DMR (with AMBE+2 voice), NXDN, Motorola Type II, EDACS, LTR, MPT 1327, dPMR, D-STAR, YSF. No CGO, no librtlsdr / libhackrf / libairspy / libusb at build or runtime, single ~10 MB static binary for Linux, macOS, and Windows, with a headless daemon, a Bubbletea TUI cockpit, and a browser-based web operator console.

This is the operational-recovery + Mt Anakie follow-up to v0.2.1. v0.2.1 finally made the Mt Anakie P25 capture decode end-to-end on the bench, but the live deployment surfaced two new failure modes: a NESDR dropping off the USB bus multiple times per day (silently stalling the decoder), and grants arriving on channel IDs the site never broadcasts an IDEN_UP for. Both are fixed now.

What’s new since v0.2.1:

  • Full USB-disconnect self-healing (#345). The bulk-IN reaper-death channel surfaces silent stalls through the ccdecoder retry loop (the daemon used to go idle at 0% CPU, alive but inert, with frozen event counters). Control SDRs reacquire by serial on disconnect — best-effort close of the dead handle, driver re-enumerate, fresh Open() by the new USB index, per-device hint (PPM / gain / bias-tee) re-applied, Device swapped in place in the pool entry, KindSDRDetached + KindSDRAttached events republished. Voice SDRs reacquire on grant-time tune failure. A new SDR-pool watchdog (sdr.watchdog_interval_ms, default 30 s, opt-out via -1) re-enumerates registered drivers periodically and re-binds the moment a previously-missing serial reappears, so the next consumer touches a live handle instead of paying the reacquire round-trip mid-use. All recovery is in-process — no daemon restart, no systemd / docker bounce.
  • P25 TDMA IdentifierUpdate (TSBK opcode 0x33) wired into the dispatcher. v0.2.1 only wired the VUHF variant (0x34 — channel IDs 2 / 3 / 4 / 6 / 7 / 8 / 14 / 15); the Mt Anakie site survey confirmed it broadcasts IDEN_UP for id=10 only as the TDMA variant (0x33 — covers ids 0 / 1 / 5 / 9 / 11 / 12 / 13). Every Phase 2 grant on a TDMA id used to black-hole with decode.error stage=no-bandplan. Mt Anakie id=10 + num=176 now resolves to 468.6125 MHz.
  • Per-channel-ID deferred-grant queue + config-driven band-plan seed. Grants that reference a channel ID before the matching IDEN_UP lands are now held in a bounded ring (cap 4 per ID, 5 s TTL) and re-published against the freshly-applied slot when IDEN_UP arrives — covers the race where IDEN_UP cadence is slower than the first grant after CC lock. A new p25_band_plan list on SystemConfig (channel_id / base_hz / spacing_hz / tx_offset_hz / bandwidth_hz) seeds the band plan at startup so sites that never broadcast IDEN_UP for a given ID can still resolve grants — over-the-air IDEN_UPs override seeded entries.
  • P25 ALGID / KID encryption metadata surfaced end-to-end (#353). P25 calls used to carry an opaque enc=true flag; operators triaging encrypted traffic had no way to tell DES-OFB from AES-256 from ADP without running SDRtrunk on the side. The voice composer now publishes a call.encryption event the instant the LDU2 Encryption Sync lands, and a new P25 algorithm-name registry renders 0x84 (AES-256) / 0x81 (DES-OFB) / 0xAA (ADP/RC4) uniformly across the log line, the TUI active-call flag column, and both web panels’ pills + detail views.
  • Web operator-console polish. Empty WACN / SystemID / RFSS / Site fields on the systems detail modal used to show a bare em-dash, leaving operators unable to tell config mistakes from “not yet decoded”. The scanner snapshot (hunting / locked / other) now drives per-field hint copy so the modal explains why those fields are empty.
  • Repo + docs cleanup. README trimmed from 2,826 → ~210 lines — the long-form Status and Roadmap chapters moved into their own pages, and the docs nav surfaces previously-orphan pages (launcher, live-edits, DMR encryption, release process). Dockerfile bumps golang:1.24golang:1.25 so builds stop silently downloading the newer toolchain at every run.

Downloads (Linux / macOS / Windows, x64 + ARM64): https://github.com/MattCheramie/GopherTrunk/releases/tag/v0.2.2

Project & docs: https://gophertrunk.org

Heads-up: the v0.x line is still flagged prerelease — actively developed, and feedback / captures / bug reports are very welcome.


Discord

GopherTrunk v0.2.2 is out

Pure-Go digital-trunking scanner for RTL-SDR / HackRF / Airspy — P25, DMR, NXDN, analog trunked, single static binary, zero CGO.

Operational-recovery + Mt Anakie follow-up to v0.2.1.

What’s new since v0.2.1:

  • Full USB-disconnect self-healing (#345) — reaper-death surfaced to the decoder so the daemon no longer goes idle at 0% CPU on a silent stall; control + voice SDRs both reacquire by serial in-process (no daemon restart); new pool watchdog re-binds missing serials the moment they reappear.
  • P25 TDMA IDEN_UP (opcode 0x33) wired — v0.2.1 only had the VUHF variant (0x34); Mt Anakie’s id=10 is TDMA-only and used to black-hole every grant. Now resolves to 468.6125 MHz.
  • Deferred-grant queue + config band-plan seed — grants arriving before the matching IDEN_UP are held in a bounded ring and re-published on apply; p25_band_plan config list seeds the band plan at startup for sites that never broadcast some IDs.
  • ALGID / KID encryption metadata end-to-end (#353) — log lines, TUI, and both web panels render 0x84 (AES-256) / 0x81 (DES-OFB) / 0xAA (ADP/RC4) uniformly the instant the LDU2 Encryption Sync lands.
  • Web systems detail modal explains empty WACN/SysID/RFSS/Site — per-field hint copy driven by the scanner hunt state instead of a bare em-dash.
  • README trimmed 2,826 → ~210 lines; status + roadmap extracted to their own pages, orphan docs surfaced in the nav.
  • Dockerfile bumped to golang:1.25 so builds stop downloading the newer toolchain at every run.

Download: https://github.com/MattCheramie/GopherTrunk/releases/tag/v0.2.2 Docs: https://gophertrunk.org