Skip to content

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

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)