Field Guide · algorithm

Also known as: CAC, common access channel, RCCH

The NXDN Common Access Channel (CAC) is the signalling block an NXDN control channel transmits to coordinate a trunked system — the RCCH messages that announce the site, register radios, and grant voice and data calls onto traffic channels.1 GopherTrunk models it at two layers: a message layer, an 8-bit RCCH opcode plus a 64-bit payload protected by a 16-bit CRC (88 bits total), and a channel-coding layer, the full outbound chain that wraps a 155-bit information block in convolutional FEC, puncturing, and interleaving to survive the air.2

155 info +CRC+tail K=5 R=1/2 → 350 puncture drop 50 → 300 25×12 interleave 300 bits = 150 dibits decode reverses it: deinterleave → depuncture → Viterbi (175 stages) → strip tail → CRC verify
The CAC outbound coding chain turns a 155-bit information block into 300 on-air bits (150 dibits): CRC and tail bits are appended, the result is convolutionally encoded at half rate, punctured from 350 down to 300 bits, and block-interleaved; the receiver runs the exact inverse and Viterbi-decodes.

RCCH message types

The 8-bit opcode that opens the message names the RCCH function. GopherTrunk enumerates the subset the trunking state machine acts on:

Opcode Name Purpose
0x01 VCALL voice call setup
0x02 VCALL_ACK voice call acknowledgement
0x04 VCALL_ASSGN voice channel assignment (grant)
0x09 DCALL data call setup
0x0A DCALL_ACK data call acknowledgement
0x0D DCALL_ASSGN data channel assignment
0x38 SDCALL short-data call
0x3C SITE_INFO site identification broadcast
0x3D SRV_INFO service information
0x3F CCH control-channel announcement

A VCALL_ASSGN or DCALL_ASSGN is the channel grant the engine follows to a traffic channel; SITE_INFO tells it which system and site it is watching. The message payload interpretation depends on the opcode — GopherTrunk parses the VCALL and SITE_INFO variants into typed group/source/system fields.

The coding chain

The channel-coding layer takes a 155-bit information block (8 SR bits plus 144 layer-3 data bits, padded with 3 null zeros), appends a 16-bit CRC-CCITT (polynomial 0x1021, init 0xFFFF, computed bit-level because 155 is not byte-aligned) and 4 zero tail bits to flush the encoder, giving 175 input bits. Those are encoded by a constraint-length-5, rate-½ convolutional code — generators g1 = 1+D³+D⁴ (octal 31) and g2 = 1+D+D²+D⁴ (octal 27), the same primitive the SACCH uses — producing 350 bits. A fixed puncture matrix of period 7 (keep every G1, drop G2 at two of seven positions) removes 50 bits to land on 300, and a 25-row by 12-column block interleaver — written row-by-row, read column-by-column — spreads adjacent bits apart so a channel burst becomes scattered single errors. The result is 300 channel bits, 150 dibits, carried in the CAC slot of the RCCH outbound frame (FSW 20 + LICH 16 + CAC 300 + E 24 + Post 24).

The receiver runs the exact inverse: deinterleave, depuncture (inserting a zero-cost sentinel at the 50 dropped positions so the metric ignores them), then a Viterbi decode over 175 stages constrained to end in state 0, strip the tail, and verify the CRC. A CRC match is the gate — only a clean CAC is ingested.

Relevance to SDR

internal/radio/nxdn/cac.go holds the message layer (ParseCAC, the RCCHType opcode enum, and typed payload parsers) and internal/radio/nxdn/cac_channel.go holds the coding chain (EncodeCACChannel / DecodeCACChannel) with the puncture positions and interleave permutation computed and self-checked at package load. Getting the CAC right is what lets GopherTrunk read an NXDN control channel at all: every grant it follows and every site it identifies arrives as a CAC message, so the FEC chain — convolution, puncture, interleave, Viterbi — sits directly on the critical path between a noisy control channel and a decoded call.

Sources

  1. NXDN — Wikipedia, on the NXDN standard and its control-channel signalling. 

  2. Convolutional code — Wikipedia, on the encoder family the CAC uses and its Viterbi decoding. 

See also