Wiki / Protocols

CCSDS Space Packet and Transfer Frames

The layered framing almost every spacecraft link runs: Space Packets carried inside Transfer Frames carried inside coded blocks. Read a downlink, or forge an uplink, and these are the headers you parse first.

What a downlink octet belongs to
Coded stream (CADU)
ASM 0x1ACFFC1D (4 octets)
Coded block (255 octets)
TM Transfer Frame header (6)
Frame data field
Space Packet header (6)
Application data
Three nested layers, each with its own identifier. The coded block is found by its sync marker and repaired by Reed-Solomon; the Transfer Frame selects a Virtual Channel with its VCID; the Space Packet selects an on-board application with its APID. A packet may straddle two frames, which is why the frame carries a First Header Pointer.

CCSDS (Consultative Committee for Space Data Systems) is the family of standards that defines how spacecraft and ground stations frame data. Nearly every civil mission flying, from cubesats to deep-space probes, wraps its telemetry and its commands in these headers, so learning three fixed-size headers unlocks a very large fraction of space traffic.

What it is

CCSDS is layered, and the layers are the whole point. From the inside out:

Layer Standard Unit Identifier
Application 133.0-B Space Packet APID (11 bits)
Data link 132.0-B (TM) / 232.0-B (TC) Transfer Frame SCID + VCID
Channel coding 131.0-B CADU Attached Sync Marker

A Space Packet is what an instrument produces. Transfer Frames chop the link into fixed-length containers and multiplex several logical streams onto one radio. The coding layer adds a sync marker, a scrambler, and Reed-Solomon so the ground can find and repair blocks in noise. Nothing in the stack is secret; it is coded for the channel, not encrypted.

The Space Packet primary header

Six octets, big-endian, read as three 16-bit words:

word0 (octets 0..1)   version 3 bits | type 1 | sec-hdr flag 1 | APID 11
word1 (octets 2..3)   sequence flags 2 bits | sequence count 14
word2 (octets 4..5)   Packet Data Length = (data field octets) - 1

Type 0 is telemetry (space to ground), type 1 is telecommand (ground to space). Sequence flags are 00 continuation, 01 first, 10 last, 11 unsegmented. The stdlib is enough to walk it:

import struct

w0, w1, w2 = struct.unpack(">HHH", packet[:6])
apid      = w0 & 0x7FF
seq_flags = (w1 >> 14) & 0x3
seq_count = w1 & 0x3FFF
next_off  = 6 + (w2 + 1)          # note the plus one

The Transfer Frame

The TM frame primary header is also 6 octets: Transfer Frame Version Number (2 bits), Spacecraft Identifier (10), Virtual Channel Identifier (3), Operational Control Field flag (1), then a Master Channel Frame Count and a Virtual Channel Frame Count of one octet each, then a Frame Data Field Status word whose low 11 bits are the First Header Pointer, the offset of the first packet header that starts inside this frame.

The TC frame is a different shape: a 5-octet primary header carrying a Bypass Flag, a Control Command Flag, the SCID, a 6-bit VCID, a 10-bit Frame Length (again stored as the true octet count minus one) and an 8-bit Frame Sequence Number N(S), followed by a 1-octet segment header holding sequence flags and a MAP Identifier. Uplinks usually close with a Frame Error Control Field, a CRC-16-CCITT over everything before it.

Why it matters

The Virtual Channel is what separates real-time science from a playback of a stored orbit, and the APID is what separates one instrument from another. Get the demultiplex wrong and you concatenate two unrelated streams into confident nonsense. On the uplink side, the security story is thin by design: CCSDS 232.0-B gives you sequence control through COP-1 and its FARM-1 state machine, which tracks a single expected frame number V(R) and rejects anything out of order, so a straight replay fails. Authentication is a separate standard (352.0-B / 355.0-B) that many missions still do not fly, and a home-grown "MAC" that is only a checksum masked with a key is forgeable once you have two frames.

Pitfalls

  • The minus-one convention appears in both the Space Packet data length and the TC frame length. Advance your cursor by 6 + (length + 1). Forget the plus one and every packet after the first is garbage.
  • grep is not demultiplexing. Searching the raw capture for a string finds bytes that belong to no single channel, or that never existed until you stitched the right frames together.
  • The same APID can appear on several Virtual Channels, which is exactly how a replayed old orbit hides next to live telemetry. Choose the channel first, then filter the APID.
  • A secondary header sits between the primary header and the payload when bit 4 of word0 is set. Treat it as payload and you inject timestamps into the middle of your reassembled message.
  • A packet may straddle a frame boundary, so you must concatenate a channel's data fields before you parse packets, not parse each frame in isolation.

Further reading