AN-002: RTCM SC-104 Frame Structure & Message Type Reference

DOC_ID: KMX-AN-002 | REV: 1.1.0 | READ: 18 min

Document Scope

AN-002 is a field-level RTCM SC-104 / RTCM 3.x reference for engineers writing or validating RTCM binary parsers. It focuses on frame synchronization, CRC-24Q verification, non-byte-aligned payload extraction, MSM field layout, message type lookup, and base-station interoperability messages. The naming follows the RTCM SC-104 convention maintained by the Radio Technical Commission for Maritime Services.

This document is written as a dictionary-style Application Note. For RTK correction strategy, MSM selection, and field-debugging workflow, read RTCM Unpacked. For receiver-side ASCII output parsing, use AN-001 — NMEA 0183 Sentence Dictionary.

Part 1 — Protocol Architecture & Parsing Fundamentals

1.1 Data Type Conventions

RTCM 3.x payloads are encoded as a continuous, non-byte-aligned bit stream in big-endian (MSB first) order. All field positions and widths in this document are specified in bits, not bytes. Developers must use bit-level extraction functions (see Appendix A) to read fields that span byte boundaries.

RTCM 3.x payloads use non-byte-aligned bit streams constructed from three base binary data types:

Type Name Description
bit(n) Bit String Raw bit pattern of n bits. No numeric interpretation. Used for masks and indicators.
uint(n) Unsigned Integer Unsigned integer of n bits. Range: 0 to 2n−1.
int(n) Signed Integer Two's Complement signed integer of n bits. Range: −2n−1 to 2n−1−1.

Scale Factor Rule: Many DF fields encode physical quantities as scaled integers. The conversion is:

Physical Value = Extracted Integer × Resolution

Resolution values are specified in the Notes column of each field table throughout this document.

Invalid Value Convention: Certain DF fields use a designated bit pattern (typically all-ones or a specific hex value) to indicate that the observation is missing or invalid. These are marked in the Notes column of each field table (e.g., 255 = invalid, 0x4000 = invalid).

1.2 General Frame Structure

Every RTCM 3.x message is encapsulated in a fixed-format binary frame. Unlike NMEA 0183's ASCII sentences delimited by $ and <CR><LF>, RTCM frames have no human-readable delimiters. Frame boundaries must be established programmatically through preamble detection, length parsing, and CRC verification.

An RTCM 3.x frame has a fixed byte-level wrapper around a variable-length payload; a parser should validate the preamble, declared payload length, and CRC before dispatching the message type:

Preamble
8 bits
0xD3
Reserved
6 bits
000000
Length
10 bits
0–1023
Payload
Variable (0–1023 bytes)
First 12 bits = DF002
CRC-24Q
24 bits
3 bytes

The byte-level RTCM 3.x frame wrapper consists of the following fields:

Field Bits Description
Preamble 8 Fixed sync byte: 0xD3 (binary 11010011). Scan the incoming byte stream for this value to begin frame synchronization.
Reserved 6 Reserved bits. Must be 000000. If non-zero after a 0xD3 byte, this is a false preamble — resume scanning.
Length 10 Payload length in bytes (0–1023). Maximum frame size: 3 (header) + 1023 (payload) + 3 (CRC) = 1029 bytes.
Payload Variable Message content. The first 12 bits of the payload always contain DF002 (Message Type number, 0–4095).
CRC-24Q 24 24-bit CRC computed over all bytes from the Preamble through the end of the Payload (not including the CRC itself).

1.3 CRC-24Q Algorithm

The CRC-24Q is computed over all bytes from Preamble through the end of Payload. If the computed CRC does not match the 3-byte CRC field appended to the frame, the entire frame must be discarded.

RTCM 3.x uses CRC-24Q to protect the frame header and payload; parser implementations should reject the frame before decoding any message fields when the CRC check fails.

Parameter Value
Polynomial 0x1864CFB
Initial Value 0x000000
Input Range Byte 0 (Preamble) through last byte of Payload
Output 24-bit unsigned integer, transmitted MSB first

C language reference implementation:

#define CRC24Q_POLY 0x1864CFB

unsigned int crc24q(const unsigned char *buf, int len) {
    unsigned int crc = 0;
    int i, j;
    for (i = 0; i < len; i++) {
        crc ^= (unsigned int)buf[i] << 16;
        for (j = 0; j < 8; j++) {
            crc <<= 1;
            if (crc & 0x1000000) crc ^= CRC24Q_POLY;
        }
    }
    return crc & 0xFFFFFF;
}

1.4 Frame Synchronization

RTCM 3.x frames contain no line-ending characters or inter-frame delimiters. When reading from a TCP socket or serial port, incoming bytes arrive as an arbitrary continuous stream. The parser must implement a state machine to locate frame boundaries:

SYNC_PREAMBLE READ_HEADER READ_PAYLOAD VERIFY_CRC DISPATCH

A streaming RTCM parser should be implemented as a byte-level state machine because TCP, USB, and UART reads do not preserve RTCM frame boundaries:

State Action
SYNC_PREAMBLE Scan byte-by-byte for 0xD3. On match, advance to next state.
READ_HEADER Read next 2 bytes. Verify Reserved bits (upper 6 bits of byte 1) are zero. Extract 10-bit Length field. If Reserved ≠ 0, return to SYNC.
READ_PAYLOAD Buffer exactly Length bytes of payload data.
VERIFY_CRC Read 3 CRC bytes. Compute CRC-24Q over header + payload (3 + Length bytes). If mismatch, return to SYNC at the byte following the original preamble.
DISPATCH Extract DF002 (first 12 bits of payload) to determine Message Type. Route to the appropriate decoder.

*Remark: On CRC failure, do not skip the entire frame — the 0xD3 byte that triggered this attempt may have been a coincidental data byte, and a real preamble may exist within the bytes already consumed. Robust implementations rescan from preamble_position + 1.

TCP/Serial Buffer Handling: TCP delivers data in arbitrarily-sized chunks. A recv() call may return a partial frame, multiple frames, or a frame split across two calls. The parser must maintain a persistent ring buffer or byte queue across read operations and never assume a single read contains a complete frame.

Part 2 — Multiple Signal Messages (MSM), MT1071–MT1137

2.1 Constellation Assignment

MSM messages use a systematic numbering scheme: each constellation is assigned a block of 7 message types (MSM1 through MSM7). RTCM 3 Multiple Signal Messages group satellite observations by constellation, mapping message types MT1071 through MT1137 to specific GNSS signal families and time epochs:

MT Range Constellation Epoch Time Basis Notes
1071–1077 GPS Milliseconds of GPS week DF004, uint(30)
1081–1087 GLONASS Milliseconds of day (UTC+3) DF034, uint(27). 3-bit day-of-week prepended.
1091–1097 Galileo Milliseconds of Galileo week DF248, uint(30)
1101–1107 SBAS Milliseconds of GPS week DF004, uint(30)
1111–1117 QZSS Milliseconds of GPS week DF004, uint(30)
1121–1127 BeiDou Milliseconds of BDS week DF427, uint(30). BDT epoch: Jan 1, 2006.
1131–1137 NavIC/IRNSS Milliseconds of GPS week V3.3+

2.2 MSM Type Definitions (Last Digit → Content)

RTCM MSM message numbers use the last digit to identify the observation content level, while the first three digits identify the constellation family:

Last Digit MSM Type Observation Fields Included Parser Implication
1 MSM1 Compact pseudorange observations. Decode pseudorange cells only; no carrier phase.
2 MSM2 Compact carrier-phase observations. Decode phase cells without pseudorange pairing.
3 MSM3 Compact pseudorange and carrier-phase observations. Use both fine pseudorange and fine phase-range fields.
4 MSM4 Pseudorange, phase range, lock time, half-cycle flag, and CNR. Common full observation payload without Doppler.
5 MSM5 MSM4 fields plus rough and fine phase-range rate. Add Doppler/range-rate field extraction.
6 MSM6 High-resolution MSM4-style observations. Use high-resolution pseudorange, phase, and CNR scaling.
7 MSM7 High-resolution MSM5-style observations. Decode high-resolution observation fields plus Doppler/range-rate.

*Reference note: this table identifies payload content for parser implementation. For deployment-level MSM selection, see RTCM Unpacked.

2.3 MSM Payload Architecture

Every MSM message payload is organized in three consecutive segments. The Header is fixed-structure (though Cell Mask length varies). The Satellite Data and Signal Data segments have lengths determined dynamically by the mask values parsed from the Header.

An MSM payload is decoded in layers: fixed header fields first, then satellite and signal masks, then variable-length observation data derived from the active cell mask:

MSM Header
(fixed + masks)
Satellite Data × N_sat
(per-satellite block)
Signal Data × N_cell
(per-cell block)

The number of Satellite Data blocks (N_sat) and Signal Data blocks (N_cell) cannot be known until the three mask fields in the Header have been read and decoded. See Section 2.5 for the dynamic length calculation algorithm.

2.4 MSM Header (DF Field Reference)

The MSM header is a fixed field sequence followed by variable masks. Start Bit values in this table are measured from the first bit of the RTCM message payload, starting at DF002, not from the outer 0xD3 frame header:

DF# Field Name Type Bits Start Bit Notes
DF002 Message Number uint(12) 12 0 e.g., 1077 = GPS MSM7, 1124 = BDS MSM4.
DF003 Reference Station ID uint(12) 12 12 0–4095. Matches Station ID in MT1005/1006.
DF004 * GNSS Epoch Time uint(30) 30 24 Resolution: 1 ms. Time basis varies by constellation (see Section 2.1). * DF number varies by constellation.
DF393 Multiple Message Bit bit(1) 1 54 1 = additional MSM messages follow for the same epoch. 0 = last (or only) MSM for this epoch.
DF409 IODS (Issue of Data Station) uint(3) 3 55 Incremented when station parameters change.
Reserved bit(7) 7 58 Reserved for future use.
DF411 Clock Steering Indicator uint(2) 2 65 0=unknown, 1=not applied, 2=applied, 3=unknown.
DF412 External Clock Indicator uint(2) 2 67 0=internal, 1=external locked, 2=external unlocked, 3=unknown.
DF417 Divergence-free Smoothing bit(1) 1 69 0=not used, 1=divergence-free smoothing applied.
DF418 Smoothing Interval uint(3) 3 70 0=no smoothing. Values 1–7 map to intervals from <30s to unlimited.
Satellite Mask bit(64) 64 73 1 bit per satellite slot. Bit position maps to satellite PRN/slot number. See Section 2.5.
Signal Mask bit(32) 32 137 1 bit per signal type. Signal-mask index maps to a signal code (see Section 2.8). See Section 2.5.
Cell Mask bit(N_sat × N_sig) var 169 Presence matrix. Cell[i][j] = 1 → satellite i has observation data for signal j. See Section 2.5.

*Remark: Start Bit values in this table are measured from the first bit of the RTCM message payload, starting at DF002, not from the outer 0xD3 frame header. The fixed MSM header portion from DF002 through DF418 is 73 bits. After the 64-bit Satellite Mask and 32-bit Signal Mask, the Cell Mask begins at bit 169. Total MSM header length is 169 + (N_sat × N_sig) bits.

2.5 The Mask Matrix & Dynamic Length Calculation

The three mask fields in the MSM Header form a two-dimensional matrix that determines how many data blocks follow, and in what order. Incorrect mask handling is the primary source of buffer overrun and data misalignment bugs in RTCM parsers.

Step-by-step algorithm:

// Step 1: Count satellites with data in this frame
N_sat = popcount(Satellite_Mask);   // number of set bits in 64-bit mask

// Step 2: Count signal types present in this frame
N_sig = popcount(Signal_Mask);      // number of set bits in 32-bit mask

// Step 3: Read the Cell Mask (variable length)
Cell_Mask = read_bits(N_sat * N_sig);

// Step 4: Count actual observation cells
N_cell = popcount(Cell_Mask);       // total signal data blocks to parse

// Satellite Data segment: N_sat blocks, each containing per-satellite fields
// Signal Data segment:    N_cell blocks, each containing per-cell fields

Data ordering rules:

  • Satellite Data blocks are ordered by the set-bit positions in the Satellite Mask, from the lowest bit index to the highest.
  • Signal Data blocks are ordered in satellite-major order: iterate through each satellite (in Satellite Mask bit order), and within each satellite, iterate through its signal types (in Signal Mask bit order), including only cells where the corresponding Cell Mask bit is 1.

Worked example:

Satellite Mask: bits 2, 5, 11 are set  →  N_sat = 3  (PRN 3, 6, 12)
Signal Mask:    bits 1, 4 are set       →  N_sig = 2  (e.g., L1 C/A, L2C)

Cell Mask (3 × 2 = 6 bits):  read in transmission order →

MSM payload length is data-dependent because the Cell Mask determines how many satellite-signal observation cells are present in the message.

Cell Index Satellite Signal Mask Bit Result
0 PRN 3 (Sat Mask bit 2) L1 C/A (Sig Mask bit 1) 1 → Signal Data Cell 1
1 PRN 3 (Sat Mask bit 2) L2C (Sig Mask bit 4) 1 → Signal Data Cell 2
2 PRN 6 (Sat Mask bit 5) L1 C/A (Sig Mask bit 1) 1 → Signal Data Cell 3
3 PRN 6 (Sat Mask bit 5) L2C (Sig Mask bit 4) 0 — skipped (no observation)
4 PRN 12 (Sat Mask bit 11) L1 C/A (Sig Mask bit 1) 1 → Signal Data Cell 4
5 PRN 12 (Sat Mask bit 11) L2C (Sig Mask bit 4) 1 → Signal Data Cell 5
N_cell = popcount(Cell_Mask) = 5
Signal Data contains 5 blocks, transmitted in the Cell order shown above.

*Critical Limit: The RTCM standard dictates that N_sat × N_sig ≤ 64. If the product of set bits in the Satellite Mask and Signal Mask exceeds 64, the Cell Mask is invalid and the frame must be discarded. Parsers must check this boundary before attempting to allocate memory or read the Cell Mask to prevent severe buffer overflows.

2.6 MSM Satellite Data Fields

One block of Satellite Data fields is transmitted per satellite (repeated N_sat times). Not all fields are present in every MSM type — the "Present in" column indicates which MSM types include each field.

*Important: Within each MSM frame, all values for a given DF are transmitted contiguously before the next DF begins. For example, in MSM7 with N_sat = 3: all three DF397 values are sent first, then all three DF398, then all three DF399, then all three DF404.

Satellite data fields are transmitted once per active satellite and provide rough range, phase range, and range-rate information before per-cell signal observations are decoded.

DF# Field Name Type Bits Present in Notes
DF397 Rough Range Integer uint(8) 8 MSM1–7 Integer milliseconds of rough satellite range. Maximum representable distance ≈ 76,000 km (sufficient for MEO/GEO orbits). 255 = invalid (satellite excluded).
DF398 Extended Satellite Info uint(4) 4 MSM5, MSM7 Extended satellite information (constellation-specific). For GLONASS: frequency channel number offset.
DF399 Rough Range Modulo uint(10) 10 MSM1–7 Fractional milliseconds of rough range. Resolution: 2−10 ms ≈ 0.977 μs. Full rough range = DF397 + DF399 × 2−10 ms.
DF404 Rough PhaseRange Rate int(14) 14 MSM5, MSM7 (Satellite-level, rough). Resolution: 1 m/s. Range: ±8191 m/s. 0x2000 = invalid. See Section 2.7 for the signal-level fine Doppler (also labeled DF404, but int(15)).

2.7 MSM Signal Data Fields

One block of Signal Data fields is transmitted per observation cell (repeated N_cell times). As with Satellite Data, all values for a given DF are transmitted contiguously across all cells before the next DF begins.

Signal data fields are transmitted per active observation cell and carry the fine pseudorange, fine carrier phase, lock time, half-cycle, and CNR values used by a rover decoder.

DF# Field Name Type Bits Present in Notes
DF400 Fine Pseudorange int(15) 15 MSM1, 3, 4, 5 Resolution: 2−24 ms ≈ 17.9 mm in range domain. 0x4000 = invalid.
DF405 Fine Pseudorange (High-Res) int(20) 20 MSM6, MSM7 Resolution: 2−29 ms ≈ 0.558 mm in range domain. 0x80000 = invalid.
DF401 Fine PhaseRange int(22) 22 MSM2, 3, 4, 5 Resolution: 2−29 ms ≈ 0.558 mm in range domain. 0x200000 = invalid.
DF406 Fine PhaseRange (High-Res) int(24) 24 MSM6, MSM7 Resolution: 2−31 ms ≈ 0.140 mm in range domain. 0x800000 = invalid.
DF402 Lock Time Indicator uint(4) 4 MSM1–5 Phase lock duration indicator. 0 = <24 ms to 15 = ≥524 s. Non-linear scale.
DF407 Lock Time Indicator (Extended) uint(10) 10 MSM6, MSM7 Extended lock time with finer resolution. 10-bit encoding.
DF420 Half-cycle Ambiguity bit(1) 1 MSM2–7 0 = resolved, 1 = unresolved. Unresolved half-cycle will degrade RTK fix quality.
DF403 CNR (Carrier-to-Noise) uint(6) 6 MSM4, MSM5 dB-Hz. Resolution: 1 dB-Hz. Range: 0–63.
DF408 CNR (High-Res) uint(10) 10 MSM6, MSM7 dB-Hz. Resolution: 0.0625 dB-Hz (1/16). Range: 0–63.9375.
DF404 Fine PhaseRange Rate int(15) 15 MSM5, MSM7 (Signal-level, fine.) Resolution: 0.0001 m/s. 0x4000 = invalid. See Section 2.6 for the satellite-level rough Doppler (also labeled DF404, but int(14)).

*Remark on DF404: The RTCM standard reuses the DF404 identifier for two distinct Doppler fields at different data layers. In the Satellite Data segment (Section 2.6), DF404 is a 14-bit rough estimate at 1 m/s resolution. In the Signal Data segment (this section), DF404 is a 15-bit fine-resolution field at 0.0001 m/s. Parser implementations must extract the correct bit width depending on the payload segment currently being decoded.

2.8 Common MSM Signal IDs (RTKLIB Index & Mask Position)

Each MSM Signal Mask entry maps to a constellation-specific signal code. To avoid off-by-one ambiguity, the tables below show both the zero-based RTKLIB C array index and the equivalent one-based Signal Mask position:

*Indexing note: these compact tables follow the RTKLIB current-master msm_sig_*[32] arrays as an open-source implementation reference. RTKLIB Index is the zero-based C array slot used by decoder code; 1-Based Mask Position is RTKLIB Index + 1. The RTCM SC-104 standard remains the normative source for production implementations.

*Signal naming note: this section maps common RTCM MSM signal IDs to RTKLIB/RINEX-style observation codes. For the GNSS frequency background behind L1/L2/L5, E1/E5, B1/B2, QZSS, NavIC, and SBAS signals, see GNSS Signals Explained.

GPS Signal Codes

RTKLIB Index
0-based
1-Based Mask
Position
Code Signal Frequency Notes
1 2 1C L1 C/A 1575.42 MHz Primary civil signal.
2 3 1P L1 P 1575.42 MHz Precise code tracking where available.
3 4 1W L1 P(Y) 1575.42 MHz Semi-codeless P(Y) tracking.
14 15 2S L2C M 1227.60 MHz Modernized L2 civil medium-length code.
15 16 2L L2C L 1227.60 MHz Modernized L2 civil long code.
16 17 2X L2C M+L 1227.60 MHz Combined L2C tracking.
21 22 5I L5 I 1176.45 MHz L5 in-phase component.
22 23 5Q L5 Q 1176.45 MHz L5 quadrature component.
23 24 5X L5 I+Q 1176.45 MHz Combined L5 tracking.
29 30 1S L1C D 1575.42 MHz Modernized L1C data component.
30 31 1L L1C P 1575.42 MHz Modernized L1C pilot component.
31 32 1X L1C D+P 1575.42 MHz Combined L1C tracking.

GLONASS Signal Codes

RTKLIB Index
0-based
1-Based Mask
Position
Code Signal Frequency Notes
1 2 1C G1 C/A 1602 + k×0.5625 MHz FDMA civil signal; k is satellite channel number.
2 3 1P G1 P 1602 + k×0.5625 MHz FDMA P-code.
7 8 2C G2 C/A 1246 + k×0.4375 MHz FDMA L2 civil signal.
8 9 2P G2 P 1246 + k×0.4375 MHz FDMA L2 P-code.
10 11 3I G3 L3OC I 1202.025 MHz CDMA GLONASS-K signal; decoder support is implementation-dependent.
11 12 3Q G3 L3OC Q 1202.025 MHz CDMA GLONASS-K signal; decoder support is implementation-dependent.
12 13 3X G3 L3OC I+Q 1202.025 MHz Combined L3OC tracking.

*GLONASS note: G1/G2 use FDMA, so each satellite transmits on a channel-dependent frequency. MT1230 Code-Phase Biases (Part 3.4) help rovers handle inter-manufacturer bias differences on FDMA signals.

Galileo Signal Codes

RTKLIB Index
0-based
1-Based Mask
Position
Code Signal Frequency Notes
1 2 1C E1 C 1575.42 MHz E1 Open Service pilot.
2 3 1A E1 A 1575.42 MHz PRS / restricted signal component.
3 4 1B E1 B 1575.42 MHz E1 Open Service data.
4 5 1X E1 B+C 1575.42 MHz Combined E1 data+pilot tracking.
5 6 1Z E1 A+B+C 1575.42 MHz Combined E1 tracking mode.
7 8 6C E6 C 1278.75 MHz E6 pilot/ranging component.
8 9 6A E6 A 1278.75 MHz E6 restricted component.
9 10 6B E6 B 1278.75 MHz E6 data component.
10 11 6X E6 B+C 1278.75 MHz Combined E6 tracking.
11 12 6Z E6 A+B+C 1278.75 MHz Combined E6 tracking mode.
13 14 7I E5b I 1207.14 MHz E5b in-phase.
14 15 7Q E5b Q 1207.14 MHz E5b quadrature.
15 16 7X E5b I+Q 1207.14 MHz Combined E5b tracking.
17 18 8I E5 AltBOC I 1191.795 MHz Wideband E5 AltBOC in-phase.
18 19 8Q E5 AltBOC Q 1191.795 MHz Wideband E5 AltBOC quadrature.
19 20 8X E5 AltBOC I+Q 1191.795 MHz Combined E5 AltBOC tracking.
21 22 5I E5a I 1176.45 MHz E5a in-phase.
22 23 5Q E5a Q 1176.45 MHz E5a quadrature.
23 24 5X E5a I+Q 1176.45 MHz Combined E5a tracking.

BeiDou Signal Codes

RTKLIB Index
0-based
1-Based Mask
Position
Code Signal Frequency Notes
1 2 1I B1I I 1561.098 MHz RTKLIB current-master BeiDou B1I mapping.
2 3 1Q B1I Q 1561.098 MHz RTKLIB current-master BeiDou B1I mapping.
3 4 1X B1I I+Q 1561.098 MHz RTKLIB current-master BeiDou B1I mapping.
7 8 6I B3I I 1268.52 MHz BeiDou B3 in-phase.
8 9 6Q B3I Q 1268.52 MHz BeiDou B3 quadrature.
9 10 6X B3I I+Q 1268.52 MHz Combined B3 tracking.
13 14 7I B2I I 1207.14 MHz BeiDou B2 in-phase. Same RF band as Galileo E5b.
14 15 7Q B2I Q 1207.14 MHz BeiDou B2 quadrature.
15 16 7X B2I I+Q 1207.14 MHz Combined B2 tracking.

*BeiDou mapping note: this compact table follows RTKLIB current-master msm_sig_cmp[] for parser validation. BeiDou signal-code naming can differ across RTCM/RINEX revisions and decoder implementations; use the RTCM SC-104 revision required by your product as the normative source.

QZSS, NavIC, and SBAS MSM Families

QZSS, NavIC/IRNSS, and SBAS use dedicated MSM message ranges in RTCM 3.3+. In parser code, treat them as separate constellation families with their own epoch rules and signal-mask interpretation, even when some signal names overlap with GPS-style L1/L2/L5 notation.

Constellation MSM Range Epoch Field Implementation Note
SBAS MT1101–MT1107 DF004, GPS-week milliseconds Use the SBAS constellation branch; do not merge it into GPS solely because the epoch basis is GPS time.
QZSS MT1111–MT1117 DF004, GPS-week milliseconds QZSS shares several GPS-like signal names, but the message type range and satellite ID mapping are distinct.
NavIC / IRNSS MT1131–MT1137 RTCM 3.3+ constellation-specific epoch field Implement as a separate MSM family. Older decoder code may not support NavIC MSM messages.

Part 3 — Base Station & Interoperability Messages

3.1 Station Coordinates — MT1005

Transmits the Antenna Reference Point (ARP) position in ECEF coordinates. This message is mandatory for RTK operation — without base station coordinates, the rover cannot compute a baseline vector and will never achieve a fixed solution regardless of observation data quality.

MT1005 defines the reference station coordinate payload; these ECEF fields establish the base-station position used by downstream RTK solvers.

DF# Field Name Type Bits Start Bit Notes
DF002 Message Number uint(12) 12 0 1005
DF003 Reference Station ID uint(12) 12 12 0–4095.
DF021 ITRF Realization Year uint(6) 6 24 ITRF year indicator. 0 = unspecified. When zero, the rover's output coordinates inherit reference frame ambiguity — downstream systems cannot determine the correct frame for datum transformations. See Kalmix GNSS Handbook Vol. 4 (GCS) for frame alignment guidance.
DF022 GPS Indicator bit(1) 1 30 1 = station provides GPS observations.
DF023 GLONASS Indicator bit(1) 1 31 1 = station provides GLONASS observations.
DF024 Galileo Indicator bit(1) 1 32 1 = station provides Galileo observations.
Reference Station Indicator bit(1) 1 33 0 = real/physical reference station. 1 = non-physical (virtual/network-generated).
DF025 ARP ECEF-X int(38) 38 34 Resolution: 0.0001 m. Physical value = integer × 10−4 meters.
Single Receiver Oscillator bit(1) 1 72 0 = separate oscillators for L1/L2. 1 = single oscillator.
Reserved bit(1) 1 73 Reserved.
DF026 ARP ECEF-Y int(38) 38 74 Resolution: 0.0001 m.
Quarter Cycle Indicator bit(2) 2 112 Quarter-cycle alignment status for GLONASS.
DF027 ARP ECEF-Z int(38) 38 114 Resolution: 0.0001 m.

*Remark: Total payload: 152 bits (19 bytes). The three ECEF coordinate fields (DF025/026/027) together consume 114 of 152 bits — 75% of the message is coordinate data. The int(38) type provides a range of approximately ±13,744 km from the Earth's center, sufficient for any terrestrial antenna position.

3.2 Station Coordinates + Antenna Height — MT1006

Identical to MT1005 with one additional field appended:

MT1006 extends MT1005 by adding antenna height, allowing a rover or post-processing tool to reconstruct the antenna reference point more precisely.

DF# Field Name Type Bits Start Bit Notes
All MT1005 fields (DF002 through DF027) as defined in Section 3.1, followed by:
DF028 Antenna Height uint(16) 16 152 Height of antenna above the ARP marker. Resolution: 0.0001 m. Range: 0–6.5535 m.

*Remark: Total payload: 168 bits (21 bytes). MT1006 is preferred over MT1005 when the antenna is mounted on a known survey marker and the height tie is measured.

3.3 Receiver & Antenna Descriptors — MT1033

Carries human-readable text descriptions of the base station's receiver and antenna hardware. This message uses variable-length ASCII string fields, each preceded by a length indicator.

Field sequence (in transmission order):

MT1033 describes receiver, antenna, and serial-number metadata; it is useful for logging, traceability, and mixed-equipment base-station identification.

# Field Parsing Rule
1 Message Number (DF002) uint(12) = 1033.
2 Reference Station ID (DF003) uint(12).
3 Antenna Descriptor Length uint(8). Number of ASCII characters to follow (0–31).
4 Antenna Descriptor char(n). Read n bytes as ASCII. Matches IGS antenna naming convention (e.g., LEIAR25.R4    LEIT).
5 Antenna Setup ID uint(8). 0 = default.
6 Antenna Serial Number Length uint(8).
7 Antenna Serial Number char(n). ASCII string.
8 Receiver Type Descriptor Length uint(8).
9 Receiver Type Descriptor char(n). ASCII string (e.g., TRIMBLE ALLOY).
10 Receiver Firmware Version Length uint(8).
11 Receiver Firmware Version char(n). ASCII string.
12 Receiver Serial Number Length uint(8).
13 Receiver Serial Number char(n). ASCII string.

*Remark: The Antenna Descriptor string provides the antenna model name needed for Phase Center Offset (PCO) corrections. However, the rover must have a built-in antenna calibration database (e.g., derived from NGS/IGS calibration files) to act on this information. Low-cost GNSS modules without such a database will receive MT1033 but cannot apply PCO corrections from it.

3.4 GLONASS Code-Phase Biases — MT1230

GLONASS uses Frequency Division Multiple Access (FDMA), causing inter-frequency code-phase biases between receivers from different manufacturers. MT1230 provides bias correction values that enable the rover to compensate for these hardware differences.

MT1230 carries GLONASS code-phase bias information; decoders should parse it separately from MSM observations because it affects GLONASS interoperability rather than observation-cell layout.

DF# Field Name Type Bits Start Bit Notes
DF002 Message Number uint(12) 12 0 1230
DF003 Reference Station ID uint(12) 12 12
DF421 Code-Phase Bias Indicator bit(1) 1 24 0 = default biases (zero). 1 = explicit bias values follow.
Reserved bit(3) 3 25 Reserved.
DF423 FDMA Signals Mask bit(4) 4 28 Bit 0 = L1 C/A, Bit 1 = L1 P, Bit 2 = L2 C/A, Bit 3 = L2 P. Each set bit indicates a bias value follows.
DF424–427 Code-Phase Bias Values int(16) × N 16 each 32 Resolution: 0.02 m. N = popcount(DF423). One value per signal flagged in DF423, transmitted in mask bit order.

*Critical: Without MT1230 in the correction stream, the rover will observe GLONASS satellites but exclude them from the RTK solution without an explicit parser error because the inter-frequency biases cannot be resolved. This often appears in mixed-vendor base-rover combinations. Verify MT1230 whenever GLONASS satellites are visible but do not contribute to the fixed solution.

*Output validation note: if GLONASS satellites are visible but not used in the RTK solution, check both the RTCM MT1230 input and the receiver's NMEA output fields. For SCOUT PRO output behavior, see the SCOUT PRO protocol knowledge base.

Part 4 — Quick Reference Tables

4.1 Legacy Observation Messages (MT1001–MT1012)

Legacy observation messages predate the MSM framework and are limited to GPS and GLONASS on L1/L2 bands only. No message type numbers exist for Galileo or BeiDou in the Legacy scheme — this is a structural limitation of the standard, not a versioning gap, and is the fundamental reason MSM was created.

MT Constellation Bands Content Notes
1001 GPS L1 Code + Phase Minimal. Rarely used standalone.
1002 GPS L1 Code + Phase + Ambiguity + CNR Most common Legacy GPS single-freq.
1003 GPS L1+L2 Code + Phase (dual-freq) Dual-frequency without CNR.
1004 GPS L1+L2 Code + Phase + Ambiguity + CNR Full Legacy GPS. Recommended minimum for Legacy RTK.
1009 GLONASS L1 Code + Phase Minimal.
1010 GLONASS L1 Code + Phase + Ambiguity + CNR Common single-freq GLONASS.
1011 GLONASS L1+L2 Code + Phase (dual-freq) Dual-frequency without CNR.
1012 GLONASS L1+L2 Code + Phase + Ambiguity + CNR Full Legacy GLONASS.

*Remark: Legacy messages are still encountered in production, particularly from state CORS networks and older base stations. Some correction services (e.g., Swift Navigation Skylark) provide RTCM 3.1 fallback mountpoints using MT1004/1012. However, new deployments should use MSM (Part 2) for multi-constellation support.

4.2 Ephemeris Messages

Broadcast ephemeris data relayed from the base station's GNSS receiver. These messages duplicate information the rover can acquire directly from satellite signals.

Ephemeris messages carry satellite orbit and clock data; many real-time RTK links rely on rover-side navigation data, but parsers should still dispatch these message types correctly.

MT Constellation Introduced Notes
1019 GPS V3.1 GPS broadcast ephemeris parameters.
1020 GLONASS V3.1 GLONASS broadcast ephemeris parameters.
1042 BeiDou V3.3 BDS broadcast ephemeris parameters.
1044 QZSS V3.2 QZSS broadcast ephemeris parameters.
1045 Galileo (F/NAV) V3.2 E5a-based navigation message.
1046 Galileo (I/NAV) V3.3 E1-based navigation message.

*Remark: Ephemeris decoding is handled by the GNSS receiver's firmware. Developers typically do not need to parse these messages manually. Primary use cases: reducing Time-To-First-Fix (TTFF) for cold-start rovers, and providing ephemeris data in raw RTCM logs for Post-Processed Kinematic (PPK) workflows.

4.3 SSR Messages (Overview)

State Space Representation (SSR) messages carry modeled error components for Precise Point Positioning (PPP) and PPP-RTK. These are not used in standard Observation Space Representation (OSR) RTK workflows.

SSR message types are used for state-space correction workflows rather than conventional OSR RTK streams, so AN-002 lists them only as a parser-recognition reference.

MT Range Category
1057–1062 GPS SSR: orbit corrections, clock corrections, code biases.
1063–1068 GLONASS SSR: orbit, clock, and code bias corrections.
1240–1270 Multi-GNSS SSR: Galileo, QZSS, SBAS, BeiDou orbit/clock/bias corrections.
1264 VTEC (Vertical Total Electron Content): ionospheric model for single-frequency PPP.

*Remark: Standard OSR RTK correction streams (e.g., from CORS networks or services like Point One Polaris, Swift Skylark) do not contain SSR messages. SSR data is delivered via dedicated channels, often using the SPARTN format (e.g., u-blox PointPerfect) rather than RTCM encoding.

Common RTCM stream profiles are listed here for parser test coverage and log inspection, not for selecting a production RTK mountpoint. These profiles often appear in NTRIP mountpoints and base-station output streams; deployment choices such as MSM4 versus MSM7 should be handled in RTCM Unpacked:

Scenario Required Messages Optional
GPS-only RTK 1074 or 1075 (GPS MSM4/5) + 1005 1019, 1033
GPS + GLONASS RTK + 1084/1085 (GLO MSM4/5) + 1230 1020
4-constellation RTK + 1094/1095 (GAL) + 1124/1125 (BDS) + 1005 + 1230 1042, 1045/1046, 1033
PPK Logging MSM7 all constellations + 1005 + ephemeris (1019/1020/1042/1045) 1230, 1033
Sub-meter DGNSS 1071/1081 (MSM1) + 1005

*Critical: MT1230 is marked as required (not optional) whenever GLONASS MSM messages are included. Omitting it will cause the rover to discard GLONASS observations from the RTK solution without an explicit parser error.

4.5 Bandwidth Estimation

Approximate data rates for common message configurations at 1 Hz update rate. Actual values vary with satellite count and signal count.

RTCM stream bandwidth depends on constellation count, signal count, message rate, and MSM level; the table below gives practical parser/logging expectations rather than fixed protocol limits.

Configuration Approx. Rate 9600 bps Feasible?
GPS-only MSM4 @ 1 Hz (~12 sats) ~250 B/s Yes
GPS + GLONASS MSM4 @ 1 Hz ~450 B/s Yes
4-constellation MSM4 @ 1 Hz ~900 B/s Marginal (960 B/s limit)
4-constellation MSM7 @ 1 Hz ~1,300 B/s No — requires ≥19200 bps
+ ephemeris + MT1005 + MT1230 overhead +50–100 B/s

*Remark: 9600 bps (common for UHF radio links) provides a theoretical maximum throughput of 960 bytes/second, factoring in 8-N-1 serial framing overhead (10 bits per byte on the wire). In practice, protocol overhead reduces usable bandwidth to approximately 900 B/s. For 9600 baud deployments, GPS + GLONASS MSM4 is the practical upper limit.

4.6 RTCM ↔ RINEX 3

RTCM 3.x and RINEX 3 encode the same observation data in different representations: RTCM is a compact binary format designed for real-time streaming, while RINEX 3 is a human-readable text format designed for offline archival and post-processing.

MSM message structure was designed for conversion to and from RINEX 3 observation records. The signal-mask indices listed in Section 2.8 map to RTKLIB/RINEX-style observation codes, and the RTKLIB convbin utility performs this conversion.

*Remark: RINEX 2 does not support multi-constellation observation encoding and cannot represent the full range of MSM signal types. Always use RINEX 3.0x or later when converting from MSM data. A standard PPK workflow is: record raw RTCM stream → convert to RINEX 3 via convbin → process with PPK engine (e.g., RTKLIB rnx2rtkp).

4.7 Open-Source Reference Implementations

The following RTKLIB components serve as the open-source implementation references for RTCM 3.x parsing and are useful for parser comparison or debugging:

Open-source RTCM implementations are useful for cross-checking parser behavior, CRC handling, and field scaling against known decoder code paths.

Tool / Source Type Notes
rtcm.c / rtcm3.c C source Core RTCM decoder/encoder. getbitu() and getbits() (see Appendix A) are the bit extraction primitives underlying all DF field parsing in this codebase.
convbin CLI tool RTCM ↔ RINEX 3 format conversion. Essential for PPK workflows. Validates MSM-to-RINEX signal code mapping.
str2str CLI tool NTRIP client and stream relay (serial/TCP/UDP). Primary tool for real-time RTCM stream monitoring and debugging.

*Remark: RTKLIB's MSM decoding logic is concentrated in decode_msm_head() (mask parsing, Section 2.5) and decode_msm4() through decode_msm7() (observation extraction, Sections 2.6/2.7). Reading these functions is the most direct path to understanding how the Mask Matrix operates in practice.

*Reference-stream note: when comparing your parser against rtcm.c, capture repeatable binary input from known hardware before changing decoder logic. For module-level testing, see the Kalmix GUIDE Module.

Appendix A — Bit-Level Extraction Reference (C Language)

RTCM 3.x payloads are non-byte-aligned bit streams. The following two functions extract unsigned and signed integers of arbitrary bit width from any bit offset in a byte buffer. These are adapted from the RTKLIB open-source implementation and serve as the low-level primitives for all DF field extraction described in this document.

*Note: These functions handle byte-boundary crossing internally. Callers should not perform additional endianness conversions — the big-endian bit ordering of the RTCM stream is resolved within the extraction logic.

/* Extract unsigned integer of 'len' bits starting at bit position 'pos' */
unsigned int getbitu(const unsigned char *buff, int pos, int len) {
    unsigned int bits = 0;
    int i;
    for (i = pos; i < pos + len; i++) {
        bits = (bits << 1) + ((buff[i / 8] >> (7 - i % 8)) & 1u);
    }
    return bits;
}

/* Extract signed integer (Two's Complement) of 'len' bits */
int getbits(const unsigned char *buff, int pos, int len) {
    unsigned int bits = getbitu(buff, pos, len);
    if (len <= 0 || 32 <= len || !(bits & (1u << (len - 1)))) {
        return (int)bits;
    }
    return (int)(bits | (~0u << len));  /* sign extension */
}

Usage example — extracting the Message Type (DF002) from a frame payload:

/* payload points to the first byte of the RTCM payload (after the 3-byte header) */
unsigned int msg_type = getbitu(payload, 0, 12);   /* DF002: bits 0-11 */
unsigned int sta_id   = getbitu(payload, 12, 12);  /* DF003: bits 12-23 */
unsigned int epoch    = getbitu(payload, 24, 30);   /* DF004: bits 24-53 */

Part 5 — Frequently Asked Questions

Can I read RTCM 3.x messages using a standard serial terminal or text logger?

No. Unlike NMEA 0183, RTCM 3.x is a binary protocol, not a line-based ASCII protocol. A serial monitor may show unreadable characters because RTCM frames do not use printable delimiters or newline-separated sentences. Capture the raw byte stream to a .bin file, inspect 0xD3 preambles with a hex viewer, or feed the stream into a binary RTCM decoder.

After a CRC-24Q failure, how should an RTCM parser resynchronize?

Do not trust the declared frame length after a CRC failure. A robust parser should continue byte-wise scanning for the next plausible 0xD3 preamble, then validate the reserved bits, payload length, and CRC before accepting the next frame. Some implementations resume at preamble + 1; the key rule is to resynchronize by validation, not by blindly skipping the corrupted length.

Why can't an RTCM 3.x decoder use C structs to parse the payload?

RTCM payload fields are packed by bit offset, and many fields cross byte boundaries. A C struct depends on compiler layout, padding, endianness, and byte alignment, so it cannot safely represent RTCM payloads. Use explicit bit extraction functions such as getbitu() and getbits() with verified start offsets and field widths.

How do MSM masks locate one satellite-signal observation cell?

The Satellite Mask selects active satellites, the Signal Mask selects active signal types, and the Cell Mask marks valid satellite-signal pairs. Cells are decoded in satellite-major order: for each selected satellite, iterate through selected signals and consume one Cell Mask bit for each pair. If N_sat × N_sig exceeds 64, the frame should be rejected by implementations that follow the standard MSM cell-mask limit.

Zero Jiang - Founder of Kalmix

Zero Jiang

Founder, Kalmix

Dedicated to making high-precision GNSS positioning accessible and reliable for global developers. Focused on RTK receiver integration, autonomous systems, and practical hardware engineering.

Testing RTCM correction streams on real hardware?
Back to blog