Also known as: D-STAR PCH, D-STAR header, DV header FEC
The D-STAR header FEC is the coding chain that protects the DV-mode Preamble + Header (PCH) — the 41-byte block that opens every D-STAR transmission and names the source, destination, and repeater-routing callsigns.1 The header is transmitted just once at the head of a transmission, so it cannot rely on repetition the way the voice frames do; instead a heavy FEC chain — a convolutional code, a PN15 scrambler, and a block interleaver — expands its 328 information bits into 660 on-wire channel bits so a receiver can recover the routing even under a fading GMSK channel.2
The FEC chain
The encoder packs the 41-byte information field into 328 bits and appends a 4-bit flush tail (K−1 for K=5), then runs the chain:
- Convolutional encode. A K=5, rate-½ code with polynomials G1 = 0x19 (1 + x³ + x⁴) and G2 = 0x17 (1 + x + x² + x⁴) — the same pair MMDVMHost, DSDcc, and OpenDV use for the D-STAR header — turns 332 input bits into 664 channel bits.
- Puncture. The four trailing channel bits are dropped to land on the JARL-spec 660-bit on-wire header window.
- Scramble. A 15-bit PN15 LFSR (polynomial x¹⁵ + x + 1, initial register 0x0001) XORs a keystream over the 660 bits, breaking up long runs that would stress GMSK clock recovery.
- Interleave. A 22 × 30 block interleaver (660 cells, an exact fit) writes column-major and reads row-major, spreading a channel burst across the codeword.
The decoder reverses the chain — deinterleave, descramble (the XOR is self-inverse), depuncture with erasure marks, and a K=5 Viterbi decode — and then checks that the recovered flush tail bits are zero. A non-zero tail means the survivor path did not terminate in the encoder’s zero state, so the payload is rejected as an unrecoverable error burst.
Header fields
After the FEC is stripped, the 41-byte header carries:
| Bytes | Field | Meaning |
|---|---|---|
| 0 | FLAG1 | Data / Repeater / Interrupted / Control / Urgent / EMR / Break-In flags |
| 1–2 | FLAG2, FLAG3 | Supplementary flags |
| 3–10 | RPT2 | Destination repeater callsign (8 chars, space-padded) |
| 11–18 | RPT1 | Gateway / source repeater callsign |
| 19–26 | UR | Destination station (“CQCQCQ” = group call, “/…” = routing) |
| 27–34 | MY1 | Source / own-station callsign |
| 35–38 | MY2 | 4-character short suffix |
| 39–40 | CRC | CRC-16-CCITT (poly 0x1021, init 0xFFFF) over bytes 0–38 |
The UR field drives dispatch: a CQCQCQ tag or any /-prefixed repeater routing marks a
group transmission; a specific callsign marks a directed call. FLAG1 carries the emergency
(EMR) and break-in bits a trunking-style follower surfaces.
In practice
The 24-bit Header Frame Sync is 0xEAA060; a sliding detector locks onto it (tolerating a couple of mismatched bits) before the adapter slices the 660-bit FEC-encoded payload. The convolutional polynomials match the open-source decoders exactly, but GopherTrunk flags the scrambler and interleaver as self-consistent encode/decode pairs whose exact permutation tables still need calibrating against a captured live transmission — a best-effort caveat worth respecting before trusting a marginal off-air header decode. The chain’s structure is the familiar burst-defence recipe: interleaving to disperse fades, a rate-½ code to correct what disperses, scrambling to keep the clock, and a CRC as the final integrity gate.
Relevance to SDR
internal/radio/framing/dstar_header.go implements the full chain
(EncodeDStarHeaderFEC / DecodeDStarHeaderFEC, the PN15 scrambler, the 22×30 interleaver),
and internal/radio/dstar/header.go holds the 41-byte field parse and the CRC-16-CCITT
(ParseHeader, ComputeCRC). Together they let GopherTrunk recover D-STAR routing metadata —
who is calling whom, through which repeaters — from the single header frame that opens each
transmission.
Sources
-
D-STAR — Wikipedia, on the JARL D-STAR digital voice/data protocol and its header. ↩
-
Convolutional code — Wikipedia, on the rate-½ coding the header FEC uses. ↩