CCSDS TM/TC Transfer Frames¶
Overview¶
The Transfer Frame layer provides reliable, synchronized framing for the space data link. TM Transfer Frames (CCSDS 132.0-B-3) carry telemetry downlink as fixed-length frames with attached sync markers, while TC Transfer Frames (CCSDS 232.0-B-4) carry telecommands uplink encoded as CLTUs (Communications Link Transmission Units) with BCH error protection.
Key Facts
- TM Frame: Fixed-length (typ. 1115 bytes), ASM-synchronized
- TC Frame: Variable-length (≤1024 bytes), CLTU-encoded
- TM ASM: 0x1ACFFC1D (32-bit Attached Sync Marker)
- TC CLTU Start: 0xEB90 (16-bit start sequence)
- Virtual Channels: TM supports 8 (3-bit VCID), TC supports 64 (6-bit)
- Error Detection: FECF (CRC-16-CCITT) on both TM and TC
TM Transfer Frame¶
Frame Structure with ASM¶
The TM Transfer Frame is prepended with an Attached Sync Marker for frame synchronization at the receiver:
Complete TM Channel Access Data Unit:
┌──────────────┬──────────────────────────────────────────────────────┐
│ ASM │ TM Transfer Frame │
│ (4 bytes) │ (fixed length, e.g. 1115 bytes) │
│ 0x1ACFFC1D │ │
└──────────────┴──────────────────────────────────────────────────────┘
│ │
▼ │
┌──────────────────────┬───────────────────────────────────┬──────────┤
│ Primary Header │ Data Field │ FECF │
│ (6 bytes) │ (variable, fills frame) │ (2 bytes)│
└──────────────────────┴───────────────────────────────────┴──────────┘
TM Primary Header (6 bytes / 48 bits)¶
Byte: 0 1 2 3 4 5
Bit: [7......0] [7......0] [7......0] [7......0] [7......0] [7......0]
├──┬────────────┬───┬────────────────────────┬──────────────────┤
│Vr│ SCID │VCF│ Master Ch Frame Cnt │ VC Frame Count │
│2b│ 10 bits │3b │ 8 bits │ 8 bits │
└──┴────────────┴───┴────────────────────────┴──────────────────┘
│ │
│ Data Field Status (2 bytes after header) │
└────────────────────────────────────────────┘
TM Header Fields¶
| Field | Bits | Description |
|---|---|---|
| Version | 2 | Transfer Frame version (00 for TM) |
| SCID | 10 | Spacecraft Identifier (0–1023) |
| VCID | 3 | Virtual Channel ID (0–7) |
| OCF Flag | 1 | Operational Control Field present |
| Master Ch Frame Count | 8 | Counter across all VCs (0–255, wraps) |
| VC Frame Count | 8 | Counter per VC (0–255, wraps) |
| TF Data Field Status | 16 | Secondary header flag, sync flag, packet order, segment length ID, first header pointer |
First Header Pointer¶
The First Header Pointer (11 bits) indicates where the first Space Packet begins within the frame's data zone:
Frame N: Frame N+1:
┌──────────────────────────────┐ ┌──────────────────────────────┐
│Hdr│...Pkt A tail│Pkt B│Pkt C│ │Hdr│Pkt C tail│Pkt D│ Pkt E │
│ │ │ │(spl)│ │ │ │ │ │
└───┴─────────────┴─────┴─────┘ └───┴──────────┴─────┴─────────┘
↑
First Header Pointer = offset to Pkt D start
Special values:
| Value | Meaning |
|---|---|
| 0–2035 | Offset to first packet header in data zone |
0x7FE | No packet starts in this frame (all continuation) |
0x7FF | Frame contains only idle data |
TM Attached Sync Marker (ASM)¶
Pattern: 0x1ACFFC1D¶
Binary: 0001 1010 1100 1111 1111 1100 0001 1101
Properties:
- 32 bits long
- Excellent autocorrelation (low sidelobes)
- Low cross-correlation with random data
- Chosen for robust detection at low Eb/N₀
Frame Synchronization State Machine¶
stateDiagram-v2
[*] --> SEARCH: Power on
SEARCH --> CHECK: ASM pattern detected
CHECK --> VERIFY: Second ASM at expected offset
VERIFY --> LOCK: Third consecutive ASM confirmed
LOCK --> LOCK: Continuous ASMs at frame_length intervals
LOCK --> FLYWHEEL: ASM missed (1 frame)
FLYWHEEL --> LOCK: ASM recovered at expected position
FLYWHEEL --> SEARCH: N consecutive ASMs missed (N=4 typical) Why Flywheel?
The space link has brief signal dropouts (antenna handover, atmospheric scintillation). Flywheel state continues frame extraction at the known frame boundary without the ASM, preventing unnecessary resynchronization. This avoids data loss during brief outages.
TC Transfer Frame¶
Frame Structure¶
TC Transfer Frame (variable length, max 1024 bytes):
┌──────────────────────┬───────────────────────────────────┬──────────┐
│ Primary Header │ Data Field │ FECF │
│ (5 bytes) │ (variable, ≤1019 bytes) │ (2 bytes)│
└──────────────────────┴───────────────────────────────────┴──────────┘
TC Primary Header (5 bytes / 40 bits)¶
Byte: 0 1 2 3 4
Bit: [7......0] [7......0] [7......0] [7......0] [7......0]
├──┬──┬────────────┬──────┬──┬───────────────────────┤
│Vr│Bp│ SCID │ VCID │FS│ Frame Seq (N(S)) │
│2b│1 │ 10 bits │ 6b │1b│ 8 bits │
└──┴──┴────────────┴──────┴──┴───────────────────────┘
TC Header Fields¶
| Field | Bits | Description |
|---|---|---|
| Version | 2 | Transfer Frame version (00 for TC) |
| Bypass | 1 | 0 = sequenced (COP-1), 1 = expedited (bypass) |
| Ctrl Cmd | 1 | 0 = data frame, 1 = control command |
| SCID | 10 | Spacecraft Identifier |
| VCID | 6 | Virtual Channel ID (0–63) |
| Frame Length | 10 | Frame length - 1 (in octets) |
| Frame Seq (N(S)) | 8 | Sequence number for COP-1 ARQ |
CLTU Encoding¶
Communications Link Transmission Unit¶
TC Transfer Frames are transmitted within CLTUs specially encoded units that provide bit-level error detection:
CLTU Structure:
┌────────────┬──────────────┬──────────────┬─────┬──────────────┬──────────┐
│Start Seq │ Codeblock 1 │ Codeblock 2 │ ... │ Codeblock N │ Tail Seq │
│ (2 bytes) │ (8 bytes) │ (8 bytes) │ │ (8 bytes) │ (8 bytes)│
│ 0xEB90 │ 7 data + 1BCH│ 7 data + 1BCH│ │ 7 data + 1BCH│ 0x55...79│
└────────────┴──────────────┴──────────────┴─────┴──────────────┴──────────┘
Start Sequence¶
0xEB90 = 1110 1011 1001 0000
Properties:
- 16 bits, easily detectable
- Marks beginning of CLTU
- Ground station starts BCH decoding after this
BCH Codeblock Structure¶
Each codeblock is 8 bytes: 7 information bytes + 1 parity byte (BCH(63,56) shortened to 8 octets):
Codeblock (64 bits = 8 bytes):
┌─────────────────────────────────────────────────┬────────┐
│ Information (56 bits / 7 bytes) │Parity │
│ │(8 bits)│
└─────────────────────────────────────────────────┴────────┘
BCH code: (63,56) with d_min = 4
- Corrects: 1 bit error per codeblock
- Detects: 2+ bit errors per codeblock
CLTU Tail Sequence
The tail sequence 0xC5C5C5C5C5C5C579 (fill pattern 0x55 with valid BCH parity 0x79) signals end-of-CLTU. The receiver stops BCH decoding when it detects this pattern.
CLTU Encoding Process¶
graph TD
A[TC Transfer Frame<br>with FECF] --> B[Split into 7-byte<br>information blocks]
B --> C[Compute BCH parity<br>for each block]
C --> D[Form codeblocks<br>7 data + 1 parity]
D --> E[Prepend 0xEB90<br>start sequence]
E --> F[Append tail sequence<br>0xC5...79]
F --> G[CLTU ready for<br>transmission] Frame Error Control Field (FECF)¶
Both TM and TC frames use CRC-16-CCITT as the Frame Error Control Field:
Polynomial: x¹⁶ + x¹² + x⁵ + 1 (0x1021)
Initial value: 0xFFFF
Covers: Entire frame from first header byte to last data byte
Position: Last 2 bytes of frame
Verification: Receiver computes CRC over frame + FECF → result should be 0x0000
| Property | TM FECF | TC FECF |
|---|---|---|
| Algorithm | CRC-16-CCITT | CRC-16-CCITT |
| Scope | Entire frame (header + data) | Entire frame (header + data) |
| Mandatory | Optional (recommended) | Mandatory |
| Position | Last 2 bytes of TM frame | Last 2 bytes before CLTU encoding |
Virtual Channel Multiplexing¶
TM Virtual Channels (3-bit VCID: 0–7)¶
Spacecraft downlink with 3 virtual channels:
VC 0 (Realtime HK): ─────■───────■───────■───────■──────
VC 1 (Science): ──■■■──■■■──■■■──■■■──■■■──■■■──■■■
VC 2 (Stored/Replay): ────────────■──────────────■─────────
Physical downlink: ─0─1─1─1─0─1─1─1─2─0─1─1─1─0─1─1─1─2─
↑ ↑
HK frame Replay frame inserted
(periodic) (when VC 0,1 idle)
Priority: VC 0 (highest) > VC 1 > VC 2 (lowest)
TC Virtual Channels (6-bit VCID: 0–63)¶
TC virtual channels support MAP (Multiplexer Access Point) sublayers:
| TC VC | Usage | COP-1 |
|---|---|---|
| VC 0 | Critical commands (flight safety) | Sequenced |
| VC 1 | Nominal operations | Sequenced |
| VC 2 | File uploads (CFDP) | Sequenced |
| VC 63 | Bypass channel (emergency) | No (expedited) |
Idle Frames¶
Fill Pattern 0x55¶
When no data is available for transmission, the spacecraft generates idle frames to maintain frame synchronization at the receiver:
Idle TM Frame:
┌─────────────────┬──────────────────────────────────────┬──────┐
│ Header │ Data Field (all 0x55 fill) │ FECF │
│ VCID=7 (idle) │ 0x55 0x55 0x55 0x55 0x55 ... │ │
│ FHP=0x7FF │ (idle frame indicator) │ │
└─────────────────┴──────────────────────────────────────┴──────┘
Why Transmit Idle Frames?
The ground station receiver needs a continuous stream to maintain bit/frame synchronization. If the transmitter goes silent, the receiver loses lock and takes time to re-acquire. Idle frames keep the link synchronized even during data gaps.
Frame Synchronization¶
TM Acquisition Sequence¶
sequenceDiagram
participant SC as Spacecraft TX
participant GS as Ground Station RX
SC->>GS: ASM + Frame 1 (VC 0)
SC->>GS: ASM + Frame 2 (VC 1)
SC->>GS: ASM + Frame 3 (VC 1)
Note over GS: SEARCH: scanning for 0x1ACFFC1D
SC->>GS: ASM + Frame 4 (VC 0)
Note over GS: CHECK: found ASM, expect next at +frame_length
SC->>GS: ASM + Frame 5 (VC 1)
Note over GS: VERIFY: confirmed! 2nd ASM at expected offset
SC->>GS: ASM + Frame 6 (VC 2)
Note over GS: LOCK: 3 consecutive → extracting frames
SC->>GS: ASM + Frame 7 (VC 1)
SC->>GS: [noise burst - no valid ASM]
Note over GS: FLYWHEEL: missed ASM, using predicted boundary
SC->>GS: ASM + Frame 9 (VC 0)
Note over GS: LOCK: recovered Detection Performance¶
| Eb/N₀ (dB) | ASM Detection Prob | False Alarm Rate | Lock Time (frames) |
|---|---|---|---|
| 3.0 | 0.999 | 10⁻¹² | 3–4 |
| 1.0 | 0.99 | 10⁻¹⁰ | 4–6 |
| 0.0 | 0.95 | 10⁻⁸ | 6–10 |
| -1.0 | 0.85 | 10⁻⁶ | 10–20 |
API Reference¶
TM Frame Types¶
#include "ccsds_tm.h"
typedef struct {
uint8_t version; // 00
uint16_t scid; // Spacecraft ID (0–1023)
uint8_t vcid; // Virtual Channel ID (0–7)
bool ocf_flag; // Operational Control Field present
uint8_t master_frame_count; // Master channel counter
uint8_t vc_frame_count; // VC counter
uint16_t first_hdr_pointer; // Offset to first packet start
bool sec_hdr_present; // Secondary header flag
bool sync_flag; // Synchronization flag
} tm_header_t;
typedef struct {
tm_header_t header;
uint8_t *data; // Frame data field
size_t data_size; // Data field length
uint16_t fecf; // CRC-16 (if present)
bool fecf_valid; // CRC verification
} tm_frame_t;
// Configuration
typedef struct {
uint16_t scid;
size_t frame_length; // Total frame length (typ. 1115)
bool fecf_present; // Include 2-byte CRC
bool ocf_present; // Include 4-byte OCF
uint8_t num_vcs; // Number of virtual channels used
} tm_config_t;
TM Functions¶
// Initialize TM frame encoder
void tm_init(tm_context_t *ctx, const tm_config_t *config);
// Build TM frame containing Space Packets
// Packs as many complete packets as fit; returns bytes consumed from input
size_t tm_build_frame(tm_context_t *ctx, uint8_t vcid,
const uint8_t *packets, size_t pkt_len,
uint8_t *frame_out);
// Build idle frame (fill pattern 0x55)
void tm_build_idle_frame(tm_context_t *ctx, uint8_t *frame_out);
// Prepend ASM to frame
void tm_attach_sync_marker(const uint8_t *frame, size_t frame_len,
uint8_t *output);
// Frame synchronization (receiver side)
typedef enum {
TM_SYNC_SEARCH, TM_SYNC_CHECK, TM_SYNC_VERIFY,
TM_SYNC_LOCK, TM_SYNC_FLYWHEEL
} tm_sync_state_t;
tm_sync_state_t tm_sync_feed(tm_sync_ctx_t *ctx,
const uint8_t *stream, size_t len);
// Extract frame at current sync position
bool tm_sync_extract_frame(tm_sync_ctx_t *ctx, tm_frame_t *frame);
// Decode frame primary header
void tm_decode_header(const uint8_t *frame, tm_header_t *header);
// Verify FECF (CRC)
bool tm_verify_fecf(const uint8_t *frame, size_t frame_len);
TC Frame Types¶
#include "ccsds_tc.h"
typedef struct {
uint8_t version; // 00
bool bypass; // Bypass flag (expedited)
bool ctrl_cmd; // Control command flag
uint16_t scid; // Spacecraft ID (0–1023)
uint8_t vcid; // Virtual Channel ID (0–63)
uint16_t frame_length; // Frame length - 1
uint8_t frame_seq; // Sequence number N(S)
} tc_header_t;
typedef struct {
tc_header_t header;
uint8_t *data; // Frame data field
size_t data_size; // Data field length
uint16_t fecf; // CRC-16 (mandatory for TC)
bool fecf_valid;
} tc_frame_t;
TC / CLTU Functions¶
// Build TC Transfer Frame
ssize_t tc_build_frame(uint16_t scid, uint8_t vcid, uint8_t seq,
bool bypass, const uint8_t *data, size_t data_len,
uint8_t *frame_out, size_t frame_max);
// Encode TC frame into CLTU (adds start seq, BCH codeblocks, tail)
ssize_t tc_cltu_encode(const uint8_t *frame, size_t frame_len,
uint8_t *cltu_out, size_t cltu_max);
// Decode CLTU: validate start seq, BCH, extract TC frame
// Returns frame length, or -1 if BCH errors uncorrectable
ssize_t tc_cltu_decode(const uint8_t *cltu, size_t cltu_len,
uint8_t *frame_out, size_t frame_max);
// Compute BCH parity for 7-byte information block
uint8_t tc_bch_parity(const uint8_t info[7]);
// Verify and correct single-bit errors in codeblock
// Returns: 0 = no error, 1 = corrected, -1 = uncorrectable
int tc_bch_check(uint8_t codeblock[8]);
// CLTU detection: scan bitstream for 0xEB90 start sequence
ssize_t tc_cltu_find_start(const uint8_t *bitstream, size_t len);
Frame Counter Management¶
// Master channel frame counter (shared across all VCs)
typedef struct {
uint8_t master_count; // Wraps 0–255
uint8_t vc_counts[8]; // Per-VC counters (TM: 8 VCs)
} tm_counter_t;
void tm_counter_init(tm_counter_t *ctr);
uint8_t tm_counter_next_master(tm_counter_t *ctr);
uint8_t tm_counter_next_vc(tm_counter_t *ctr, uint8_t vcid);
Build & Run¶
# Build TM module
make -C src/satellite/ccsds_tm
# Build TC module
make -C src/satellite/ccsds_tc
# Run demos
./build/ccsds_tm_demo
./build/ccsds_tc_demo
TM Demo Output¶
=== CCSDS TM Transfer Frame Demo ===
Standard: CCSDS 132.0-B-3 | Frame: 1115 bytes | ASM: 0x1ACFFC1D
--- Frame Construction ---
SCID: 0x1A4 | VCID: 0 | Frame Count: 0
Inserting 3 Space Packets into frame...
Packet 1 (APID 0x001): 128 bytes → offset 0
Packet 2 (APID 0x010): 512 bytes → offset 128
Packet 3 (APID 0x002): 256 bytes → offset 640
First Header Pointer: 0
Remaining space: 219 bytes (fill with 0x55)
FECF (CRC-16): 0x7E3A ✓
--- ASM + Frame ---
Output: 1ACFFC1D [frame bytes...] (1119 bytes total)
--- Idle Frame ---
VCID: 7 | FHP: 0x7FF | Data: all 0x55
FECF: 0x1D2C ✓
--- Frame Synchronization ---
Feeding 10 frames with random gaps...
State: SEARCH (scanning for 0x1ACFFC1D)
State: CHECK (ASM found at offset 234)
State: VERIFY (2nd ASM at offset 234+1119)
State: LOCK (3 consecutive extracting)
Extracted 8/10 frames (2 in initial search)
State: FLYWHEEL (frame 7: ASM corrupted)
State: LOCK (frame 8: recovered)
--- Virtual Channel Mux ---
VC 0: 5 frames (realtime HK)
VC 1: 12 frames (science data)
VC 2: 2 frames (stored replay)
Master frame count: 0→18 (continuous)
=== RESULTS: 22 passed, 0 failed ===
=== ALL TESTS PASSED ===
TC Demo Output¶
=== CCSDS TC Transfer Frame Demo ===
Standard: CCSDS 232.0-B-4 | CLTU Start: 0xEB90 | BCH(63,56)
--- TC Frame Construction ---
SCID: 0x1A4 | VCID: 0 | Bypass: No | Seq: 0
Payload: 12 bytes (SET_MODE command)
Frame size: 19 bytes (5 hdr + 12 data + 2 FECF)
FECF: 0x5C91 ✓
--- CLTU Encoding ---
Input frame: 19 bytes
BCH codeblocks: 3 (ceil(19/7))
Block 1: [7 info bytes] + parity 0x4A
Block 2: [7 info bytes] + parity 0xB3
Block 3: [5 info + 2 fill] + parity 0x67
CLTU size: 34 bytes (2 start + 24 codeblocks + 8 tail)
Output: EB90 [codeblocks...] C5C5C5C5C5C5C579
--- CLTU Decode + Error Correction ---
Clean CLTU: decoded OK, 19 bytes recovered ✓
1-bit error in block 2: CORRECTED (BCH) ✓
2-bit error in block 1: DETECTED (uncorrectable) ✓
Start sequence 0xEB90 detection: found at offset 0 ✓
--- Sequence Control (COP-1) ---
Frame seq 0: accepted (N(S) == V(R))
Frame seq 1: accepted
Frame seq 3: REJECTED (gap: expected 2)
Frame seq 2: accepted (retransmit)
=== RESULTS: 20 passed, 0 failed ===
=== ALL TESTS PASSED ===
References¶
- CCSDS 132.0-B-3: TM Space Data Link Protocol (Blue Book, Sept 2015)
- CCSDS 232.0-B-4: TC Space Data Link Protocol (Blue Book, Oct 2019)
- CCSDS 131.0-B-4: TM Synchronization and Channel Coding
- CCSDS 231.0-B-4: TC Synchronization and Channel Coding
- CCSDS 232.1-B-2: Communications Operation Procedure-1 (COP-1)