P25 conventional is unsupported — "P25" always means trunked, so White Plains PD (Toughny) can never decode #24

Closed
opened 2026-10-04 15:28:06 -04:00 by logan · 3 comments
Owner

Found 2026-10-04 diagnosing why Toughny (online, approved, updater checking in) has never recorded a call.

Cause: the "White Plains" system (server, id 84db8d52…) is type: P25 with control channels 460.4, 460.425. Per RadioReference (forum thread Feb 2021 + Westchester County DB), White Plains PD is P25 conventional: 460.400 = PD1 dispatch, 460.425 = PD3 tac. There is no trunking control channel. op25_controller.py (P25 branch, ~L181-204) always builds a tk_p25.py trunking config with control_channel_list = those frequencies and demod_type=cqpsk, so OP25 hunts forever for TSBK control data that never comes.

Needed: a P25 conventional decode mode — fixed frequency, no trunking section, C4FM (fsk4) demod, optional NAC; and a way to cover two channels (460.400 / 460.425 are 25 kHz apart, one SDR can carry both as two OP25 channels). Attribution: P25 conventional voice carries a TGID in LDU1 link control, so calls may be attributable — verify what OP25's terminal reports for conventional, because metadata_watcher drops any call with no talkgroup (see #20, same failure family for analog).

Server side: system editor needs a conventional option so admins don't enter voice frequencies as control channels; ideally warn when a P25 "control channel" is in a band/list that RadioReference marks conventional.

Unverified: whether WPPD encrypts (would make this moot); RadioReference wiki snippet also mentions White Plains PD on Westchester County P25 TG 28 — check whether that's current. Interim option: point Toughny at the Westchester County PD (trunked) system, which works on RPI-Node-01.

Found 2026-10-04 diagnosing why Toughny (online, approved, updater checking in) has **never recorded a call**. **Cause:** the "White Plains" system (server, id 84db8d52…) is `type: P25` with control channels `460.4, 460.425`. Per RadioReference (forum thread Feb 2021 + Westchester County DB), White Plains PD is **P25 conventional**: 460.400 = PD1 dispatch, 460.425 = PD3 tac. There is no trunking control channel. `op25_controller.py` (P25 branch, ~L181-204) always builds a `tk_p25.py` trunking config with `control_channel_list` = those frequencies and `demod_type=cqpsk`, so OP25 hunts forever for TSBK control data that never comes. **Needed:** a `P25 conventional` decode mode — fixed frequency, no trunking section, C4FM (`fsk4`) demod, optional NAC; and a way to cover two channels (460.400 / 460.425 are 25 kHz apart, one SDR can carry both as two OP25 channels). Attribution: P25 conventional voice carries a TGID in LDU1 link control, so calls may be attributable — verify what OP25's terminal reports for conventional, because `metadata_watcher` drops any call with no talkgroup (see #20, same failure family for analog). **Server side:** system editor needs a conventional option so admins don't enter voice frequencies as control channels; ideally warn when a P25 "control channel" is in a band/list that RadioReference marks conventional. **Unverified:** whether WPPD encrypts (would make this moot); RadioReference wiki snippet also mentions White Plains PD on Westchester County P25 TG 28 — check whether that's current. Interim option: point Toughny at the Westchester County PD (trunked) system, which works on RPI-Node-01.
Author
Owner

PRs open, not merged:

  • Server: logan/server-26#205. Merge first; merging auto-deploys prod.
  • Node: #27. This one also fixes #20 (analog recording).

Simultaneous traffic on two channels is filed as #26.

White Plains editor values after deploy

  • Type: P25 conventional.
  • Channel 1: 460.4000, name "PD1 Dispatch", NAC blank.
  • Channel 2: 460.4250, name "PD3 Tac", NAC blank.
  • Talkgroups: none.
  • Then re-assign the system to Toughny, which pushes the config.

Leave NAC blank until the node's dashboard shows the NAC it actually hears. Toughny's Decoding check will show either "NAC 0x…" or "Encrypted — AES-256 …".

Unverified on hardware.

PRs open, not merged: - Server: https://git.vpn.cusano.net/logan/server-26/pulls/205. Merge first; merging auto-deploys prod. - Node: https://git.vpn.cusano.net/logan/node-26/pulls/27. This one also fixes #20 (analog recording). Simultaneous traffic on two channels is filed as #26. **White Plains editor values after deploy** - Type: P25 conventional. - Channel 1: 460.4000, name "PD1 Dispatch", NAC blank. - Channel 2: 460.4250, name "PD3 Tac", NAC blank. - Talkgroups: none. - Then re-assign the system to Toughny, which pushes the config. Leave NAC blank until the node's dashboard shows the NAC it actually hears. Toughny's Decoding check will show either "NAC 0x…" or "Encrypted — AES-256 …". Unverified on hardware.
Author
Owner

Post-merge check (2026-10-04): GO to roll to nodes. No code fix was needed, so there's no PR.

  • Server: d57738a is live on prod (/health git_sha). c2-core 525 pass.
  • Client main 80a0e88: edge-node 287 pass, 9 skipped (host-updater tests need flock, which macOS doesn't have). flake8 is clean. op25-container 18 pass.
  • Images: op25-client:80a0e88 = :stable and edge-node:80a0e88 = :latest, both built 17:22. v1 already points at 80a0e88, so a node picks this up on its next "Update Node" request. drb-update.sh fetches --force --tags, checks out refs/tags/v1, pulls :stable/:latest and force-recreates.
  • I traced the whole path: C2 system_config.normalize, then the MQTT push, then radio_config.build_generate_payload, then conventional_config (it matches upstream p25_conventional_example.json, and audio.py -2 binds 23456/23457), then tk_drb_conv, then conventional.normalize/attribution, then upload, where the synthetic tgid resolves to the channel name on C2.
  • I ran tk_drb_conv against the real upstream gr310 tk_p25.py with simulated frames. The NAC filter is applied, tgid/voice/NAC/encryption are reported, there's one call_log entry per call, and encrypted calls are skipped. The image's OP25 clone is unpinned, which I filed as #29.

#26 does not block the rollout. Trunked and single-channel nodes are unaffected. For White Plains, start Toughny on PD1 Dispatch only. With one channel, every sound is attributed (sole-channel rule) and #26 can't happen. Add PD3 Tac once #26 is fixed or overlap has been measured on the hardware.

Still unverified: real decode on hardware, and whether WPPD encrypts. The node's Decoding check will answer the encryption question.

**Post-merge check (2026-10-04): GO to roll to nodes. No code fix was needed, so there's no PR.** - Server: d57738a is live on prod (`/health` git_sha). c2-core 525 pass. - Client main 80a0e88: edge-node 287 pass, 9 skipped (host-updater tests need `flock`, which macOS doesn't have). flake8 is clean. op25-container 18 pass. - Images: `op25-client:80a0e88` = `:stable` and `edge-node:80a0e88` = `:latest`, both built 17:22. `v1` already points at 80a0e88, so a node picks this up on its next "Update Node" request. drb-update.sh fetches `--force --tags`, checks out `refs/tags/v1`, pulls `:stable`/`:latest` and force-recreates. - I traced the whole path: C2 `system_config.normalize`, then the MQTT push, then `radio_config.build_generate_payload`, then `conventional_config` (it matches upstream `p25_conventional_example.json`, and audio.py -2 binds 23456/23457), then tk_drb_conv, then `conventional.normalize`/attribution, then upload, where the synthetic tgid resolves to the channel name on C2. - I ran tk_drb_conv against the real upstream gr310 `tk_p25.py` with simulated frames. The NAC filter is applied, tgid/voice/NAC/encryption are reported, there's one call_log entry per call, and encrypted calls are skipped. The image's OP25 clone is unpinned, which I filed as #29. **#26 does not block the rollout.** Trunked and single-channel nodes are unaffected. For White Plains, start Toughny on **PD1 Dispatch only**. With one channel, every sound is attributed (sole-channel rule) and #26 can't happen. Add PD3 Tac once #26 is fixed or overlap has been measured on the hardware. Still unverified: real decode on hardware, and whether WPPD encrypts. The node's Decoding check will answer the encryption question.
logan added the area/sdr-radio
priority
p2
type
feature
labels 2026-10-05 02:05:11 -04:00
Author
Owner

Shipped in PR #27 (merge 80a0e88) and rolled out to the nodes on v1. Follow-ups are tracked in #26 (two conventional channels share one stream) and #33 (a wrong NAC silently records nothing).

Shipped in PR #27 (merge 80a0e88) and rolled out to the nodes on v1. Follow-ups are tracked in #26 (two conventional channels share one stream) and #33 (a wrong NAC silently records nothing).
logan closed this issue 2026-10-05 02:08:58 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: logan/node-26#24