Also known as: MAC PDU, Phase 2 MAC message, MAC opcode
The P25 MAC PDU (Medium Access Control Protocol Data Unit) is the Phase 2 signalling unit that does the job the TSBK does on Phase 1.1 Where Phase 1 puts trunking blocks on a dedicated control channel, Phase 2 folds signalling into the same two-slot TDMA traffic structure: MAC PDUs ride the MAC slots — the sub-frames the ISCH types as MAC rather than voice — and carry the channel grants, status broadcasts, and call-state transitions that keep a trunked system coordinated.2 After forward-error-correction removal each PDU is an opcode followed by an opcode-specific payload.
Standard opcodes
GopherTrunk enumerates the subset of TIA-102.AABF / BBAB standard opcodes the follow-along engine needs:
| Opcode | Name | Purpose |
|---|---|---|
| 0x01 | GroupVoiceChannelUser (abbreviated) | In-call source-radio + service options |
| 0x02 | MAC_END | End of transmission |
| 0x03 | MAC_IDLE | Channel idle |
| 0x05 | MAC_HANGTIME | Hang-time |
| 0x06 | MAC_ACTIVE | Late-grant active update |
| 0x21 | GroupVoiceChannelUser (extended) | In-call user, carries SUID |
| 0x40 | GroupVoiceChannelGrantUpdate | Grant update |
| 0x44 | GroupVoiceChannelGrant | Group voice grant |
| 0x46 | UnitToUnitGrantUpdate (abbreviated) | Private-call grant update |
| 0x48 | UnitToUnitVoiceChannelGrant | Private-call grant |
| 0x49 | UnitToUnitVoiceChannelGrantUpdate | Private-call grant update |
| 0x4C | GroupAffiliationResponse | Affiliation response |
| 0x4D | UnitRegistrationResponse | Registration response |
| 0x70 | EncryptionSync | ALGID / KID / MI |
| 0x7D | IdentifierUpdate | Band-plan definition |
| 0xFA | RFSSStatusBroadcastUpdate | RFSS status |
| 0xFB | NetworkStatusBroadcastUpdate | WACN / System ID / Color Code |
A few of these carry state that the rest of the decoder depends on. The Network Status Broadcast –
Update (0xFB) publishes the WACN, System ID and Color Code that seed
the PN44 scrambler. IdentifierUpdate (0x7D) supplies the band plan that
turns a grant’s channel number into a downlink frequency. And the encryption sync a follower needs is
not a distinct opcode on the grant — it arrives in the MAC_PTT message that begins a transmission,
which the ISCH marks with the MAC_PTT slot type, so a caller telling PTT signalling from ordinary
signalling must read the slot type alongside the PDU. The GroupVoiceChannelUser broadcasts (0x01 /
0x21) backfill the source RID and encryption flag in-call, because real systems often issue the initial
grant in a compressed form with those fields zeroed.
Parsing and FEC
The MAC slot’s coded burst is descrambled, de-interleaved, trellis-decoded and (optionally) checked
against the outer Reed-Solomon RS(24,16,9) code before the 18 information
bytes reach ParseMACPDU. The parser reads byte 0 as the opcode; if the opcode is in the
manufacturer-specific range 0x80–0xBF it consumes byte 1 as the MFID and hands off to the
vendor accessors, otherwise the payload begins at byte 1. Callers then
dispatch on the opcode to a typed accessor — AsGroupVoiceChannelGrant, AsNetworkStatusBroadcast,
AsIdentifierUpdate, and so on — each of which validates the payload length before unpacking. A strict
mode drops any PDU whose opcode is outside the recognised set, which matters because the outer FEC’s
trellis corrector can occasionally hand up a plausible-looking but
spurious burst.
Relevance to SDR
internal/radio/p25/phase2/mac.go defines the MACPDU type, the Opcode enum, ParseMACPDU, and the
typed accessors for grants, network status, and in-call user broadcasts. It is the layer that turns a
decoded Phase 2 MAC slot into a trunking event — a grant to follow, a band plan to store, a call to end.
The spec is TIA-102.AABF (message content) and TIA-102.BBAB (Phase 2 framing).
Sources
-
Project 25 — Wikipedia, on P25 Phase 2 trunking signalling. ↩
-
Protocol data unit — Wikipedia, on the PDU as a self-contained protocol message. ↩