P25 Phase I trunked-radio receiver in Rust. Equalizes the channel before differential detection — the difference that matters on simulcast systems.
- Decodes P25 Phase I trunked radio (any network) to audio
- Desktop app (macOS, Windows) + CLI
- Pre-alpha, but decodes real off-air P25 end to end
curl -fsSL https://raw.githubusercontent.com/duderayuh/HoosierSDR/main/tools/install-mac.sh | bashOr double-click install-mac.command.
Installs Xcode CLT, Homebrew, Rust, the SDR libraries (airspy libusb soapysdr soapyrtlsdr librtlsdr pkg-config ffmpeg), and tauri-cli (prebuilt via cargo-binstall, not a source compile); clones to ~/HoosierSDR; builds the CLI; verifies it with a no-hardware demo decode. Idempotent and self-healing — re-run any time to repair or update.
-
The installer exits right after "Xcode command-line tools". That's expected on a fresh Mac — it pops Apple's dialog, you click Install and wait for it to finish, then re-run the installer. It picks up where it left off.
-
cargo tauri --version→no such command: tauri.tauri-cliisn't installed yet. Don't reach forcargo install tauri-cli(it compiles ~500 crates and can OOM an 8 GB machine). Use the prebuilt route instead:brew install cargo-binstall cargo binstall tauri-cli -y
-
The desktop app is a separate workspace under
app/.cargo tauri devfrom~/HoosierSDRfails withCouldn't recognize the current folder as a Tauri project. Run it from inside the app folder:cd ~/HoosierSDR/app && cargo tauri dev
-
8 GB machines (MacBook Neo, A18 Pro). The first
cargo tauri devis the big compile — it can beach-ball or OOM on 8 GB. Let it churn; if it OOMs, retry withCARGO_BUILD_JOBS=2 cargo tauri dev. -
brew install …changes only take effect in a new terminal. After the installer finishes, open a fresh window before runninghoosier-sdrorcargo tauri.
cargo run -p hs-cli -- --demo # synthesized decode, no hardware needed- P25 Phase I — C4FM + CQPSK modem, frame sync, BCH/Golay/trellis FEC, TSBK/MBT parsing
- Trunking — control-channel following, grant tracking, alternate-channel hunting
- IMBE voice — vendored ISC-licensed mbelib to 8 kHz PCM
- Encryption gate — encrypted traffic flagged and skipped, never decoded
- Equalizer-first CQPSK — adaptive equalizer before differential detection (the core idea)
- Radios — Airspy R2 (10 MSPS, whole-site), RTL-SDR (2.4 MSPS)
- Other protocols — AM, NBFM, DCS; more on the roadmap
- Desktop app — live decode, spectrum waterfall, record IQ (Tauri v2)
- Tripwires — one kind of rule for everything that watches the radio: when (words on a channel, an emergency, a radio keying up, a conversation ending, or a timer), check (nothing, an AI yes/no question, or extracting named details like ECPR candidacy), send (Telegram, with the audio, at most once per quiet window, with later traffic arriving as replies in the same thread). The editor previews a draft against the calls you already have — how often it would have fired, which ones it would have caught, and which phrases are never actually said on those channels, with what the transcriber writes instead. Rules can be shared as files (size-capped, stripped of hidden characters, and arriving switched off)
- ECPR, in one place — Settings → ECPR holds every part of the ED-ECPR process: which tripwire is the screen that pages the team (and the names of the fields research reads off it), the survival score's criteria, estimate table, age exclusion and wording, the word lists that read a crew's "unwitnessed" as no and "hospice" as end-stage, and whether the score goes in the case message. A try-it box scores a made-up report by the draft rules as you type, and Reset to defaults brings back the program's gate
- Cases, in one place — Settings → Cases holds everything that shapes the cardiac arrest thread on Telegram: what makes a run a case and which spoken words are events (a reorderable list of rules, with a box to try a transmission against them), how an event is placed on a run when nothing names it (every window, with the measured default and its reason), where cases go, what the message says (icons, the banner per state, the facts shown, the limits, which events reply by email), and what the crew's report to the hospital is asked for. The newest cases can be previewed as the draft would word them before anything is saved
- Places and runs — a book of hospitals, stations and landmarks, with what each can do and the channels that belong to it; it can fill itself in from the hospital channels your catalog already names. A tripwire can watch the dispatch map instead of the radio: a kind of run, near a place or near the nearest one with a cath lab, and — if you want to wait for it — where the patient actually went, because the crew's hospital report is joined back to the run that started it by the callsign they say.
- Addresses that would not geocode — the grid reference the dispatcher reads out is learned from the calls that did place, and then used both to pin a call and to tell a mis-heard street name from the real one. On one real library it took the unplaced share from 30 % to 6 %. Distances can come from a router running on your own machine (OSRM in a container, one state's map) instead of a straight line.
- Dispatch map — mark your dispatch talkgroups and each dispatched call becomes a live incident: the model extracts the address, units and call type and picks the emoji, the address is geocoded on OpenStreetMap (Nominatim), and calls about the same incident are grouped and updated in place on a Leaflet map
# decode a recording
cargo run -p hs-cli -- --rate 240000 --offset 50k --cqpsk capture.cf32
# find P25 channels in a recording
hoosier-sdr --rate 240000 --freq 858.9375M --scan capture.cf32
# follow a whole site live (Airspy R2)
cargo run --release -p hs-cli --features airspy -- --sdr --source airspy \
--rate 10000000 --freq 855M --follow --control 851.5375M
# decode one channel live (RTL-SDR)
cargo run --release -p hs-cli --features rtlsdr -- --sdr --freq 851.0125M --cqpskcargo build --workspace
cargo test --workspace
cd app && cargo tauri dev # desktop appThe IMBE vocoder compiles vendored C (ISC mbelib), so a C compiler is required.
docs/ARCHITECTURE.md— design and roadmapdocs/RECEPTION.md— improving simulcast reception with the app's metersresults/baselines.md— measured decode qualityCONTRIBUTING.md— code provenance policy
- No decryption. Encrypted traffic is detected and skipped. Architectural, not a setting. (18 U.S.C. § 2511)
- No RadioReference data committed. Fixtures are synthetic.
- No GPL-derived code. Apache-2.0. See
CONTRIBUTING.md.
Apache-2.0 — see LICENSE.