No description
  • Rust 78.2%
  • Svelte 16.4%
  • TypeScript 4.3%
  • CSS 0.8%
  • Shell 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Renovate 7c2d43055f Update dependency @types/node to v26.6.5 (#5)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node) ([source](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)) | [`26.6.4` → `26.6.5`](https://renovatebot.com/diffs/npm/@types%2fnode/26.6.4/26.6.5) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2fnode/26.6.5?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2fnode/26.6.4/26.6.5?slim=true) |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNDguNiIsInVwZGF0ZWRJblZlciI6IjQ0LjE0OC42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: #5
2026-10-09 14:32:26 -07:00
crates Update Rust crate rusqlite to 0.40 (#10) 2026-10-09 14:32:00 -07:00
docs Docs: M2 status, vocoder feature, automatic tuners, replay demo 2026-10-02 22:30:40 -07:00
scripts P25 Phase 1: demodulator, framing, FEC and TSBK parsing 2026-10-02 19:22:10 -07:00
web Update dependency @types/node to v26.6.5 (#5) 2026-10-09 14:32:26 -07:00
.gitignore P25 Phase 1: demodulator, framing, FEC and TSBK parsing 2026-10-02 19:22:10 -07:00
Cargo.lock Update Rust crate tokio to v1.53.2 (#8) 2026-10-09 14:32:08 -07:00
Cargo.toml Tuner scheduler v1: automatic tuners follow what needs covering 2026-10-02 22:30:40 -07:00
LICENSE M0: hardware layer, live waterfall and web UI skeleton 2026-10-02 18:39:22 -07:00
README.md Docs: M2 status, vocoder feature, automatic tuners, replay demo 2026-10-02 22:30:40 -07:00
renovate.json chore(reposyncer): update repo baseline (#1) 2026-10-03 11:03:45 -07:00

Trunk8

A trunking-first SDR scanner you run headless and control from a browser. It aims to decode every trunking protocol SDRTrunk does (P25 Phase 1/2, DMR Tier III / Capacity Plus / Connect Plus / Capacity Max / Hytera XPT, NXDN, MPT 1327, LTR, LTR-Net, Passport), with HackRF and PlutoSDR as first-class hardware.

Status: M2 (P25 Phase 1 trunking) working. Add a system by its control channel and Trunk8 detects the site, follows grants onto voice channels on any tuner that covers them, decodes IMBE voice, records calls and streams them to the browser. Conventional analog channels (NBFM/AM with CTCSS/DCS) work too. Validated against real off-air C4FM and CQPSK (simulcast) recordings; not yet tested on live hardware. See docs/PLAN.md for the roadmap and docs/ui-sketch.html for where the UI is headed.

Build

Requires Rust 1.90+ and Node 22+. SoapySDR is optional at runtime; it's used for devices without a native driver (Airspy, SDRplay, LimeSDR) and for a PlutoSDR on the network.

(cd web && npm ci && npm run build)   # the UI is embedded into the binary
cargo build --release                      # digital voice calls are logged, but silent
cargo build --release --features vocoder   # also decode P25 voice (see below)

About --features vocoder: digital voice decoding uses the blip25-vocoder crate, whose synthesis core was reverse-engineered from the reference vocoder. Its full-rate (IMBE, P25 Phase 1) half covers expired patents; its half-rate (AMBE+2) half reads on US 8,359,197, in force until 2028-05-20. It is off by default; decide whether it is acceptable where you build and run Trunk8.

Run

./target/release/trunk8                      # every attached SDR, or a synthetic signal if none
./target/release/trunk8 --list-devices
./target/release/trunk8 -s 'driver=hackrf#center=852e6,rate=16e6,gain=30'
./target/release/trunk8 -s 'driver=pluto#center=852e6,rate=4e6'
./target/release/trunk8 -s 'driver=soapy,soapy_driver=plutosdr,hostname=192.168.2.1#rate=4e6'
./target/release/trunk8 -s 'file:capture.sigmf-meta'
./target/release/trunk8 -s 'file:capture.iq?format=cs8&center=852e6&rate=8e6'
./target/release/trunk8 -s synthetic

Then open http://127.0.0.1:8088. There is no authentication yet, so the server only listens on localhost by default; change it with --listen at your own risk.

Channels and the call log are stored in SQLite under --data-dir (default ~/.local/share/trunk8), with one Ogg Opus file per call. Calls older than --retention-days (default 30) are deleted.

Tuners

Tuners opened without an explicit #center= are automatic: when idle, Trunk8 retunes them to cover channels and systems that no tuner covers, and to pick up voice channels a system recently missed. Set a center (on the command line or in the UI) to pin a tuner.

Test recordings

scripts/fetch-testdata.sh downloads real P25 recordings used by the decoder tests (they're skipped when absent). To try trunking without hardware, replay the control channel on one "tuner" and the voice channel it grants on another:

./target/release/trunk8 -s 'file:testdata/p25p1-cqpsk-cc.wav?center=851262500' \
                        -s 'file:testdata/p25p1-cqpsk-vc.wav?center=851387500'

Then add a system with control channel 851.2625 MHz; about 20 seconds into the recording a call to talkgroup 20182 is granted on 851.3875 MHz and followed onto the second source.

Hardware notes

  • HackRF One: 2–20 MS/s, 8-bit. It has a DC spike at the center, so keep signals of interest off the exact center frequency.
  • PlutoSDR: about 4 MS/s is gap-free over USB. A stock unit tunes 325 MHz–3.8 GHz; VHF needs the AD9364 firmware setting (70 MHz–6 GHz).

Develop

cargo run -- -s synthetic          # backend on :8088
(cd web && npm run dev)            # UI with hot reload on :5173, proxied to the backend
cargo test && cargo clippy --all-targets
(cd web && npm run check)
Path What it is
crates/t8-hw Source trait; seify (HackRF, Pluto, RTL-SDR, Soapy), file replay and synthetic sources; tuner thread with sample fan-out
crates/t8-dsp Protocol-agnostic DSP: polyphase channelizer, resampler, filters, FM/AM demodulators, squelch, spectrum
crates/t8-core Engine: places channels on tuners, tuner scheduler, conventional channel pipelines, P25 systems (control channel + traffic workers), call events and audio
crates/t8-p25 P25 Phase 1: C4FM/CQPSK demodulator, framing, NID BCH, trellis, TSBK and LDU/link control decoding
crates/t8-vocoder IMBE decoding (opt-in, see above)
crates/trunk8 The trunk8 binary: axum REST + WebSocket API, Opus encoding, SQLite store, call recorder, embedded UI
web/ SvelteKit UI

License

AGPL-3.0-or-later.