1 /*****************************************************************************
3 This is a decoder for RTCM-104 2.x, an obscure and complicated serial
4 protocol used for broadcasting pseudorange corrections from
5 differential-GPS reference stations. The applicable
8 RTCM RECOMMENDED STANDARDS FOR DIFFERENTIAL NAVSTAR GPS SERVICE,
9 RTCM PAPER 194-93/SC 104-STD
11 Ordering instructions are accessible from <http://www.rtcm.org/>
12 under "Publications". This describes version 2.1 of the RTCM specification.
13 RTCM-104 was later incrementally revised up to a 2.3 level before being
14 completely redesigned as level 3.0.
16 Also applicable is ITU-R M.823: "Technical characteristics of
17 differential transmissions for global navigation satellite systems
18 from maritime radio beacons in the frequency band 283.5 - 315 kHz in
19 region 1 and 285 - 325 kHz in regions 2 & 3."
21 The RTCM 2.x protocol uses as a transport layer the GPS satellite
22 downlink protocol described in IS-GPS-200, the Navstar GPS Interface
23 Specification. This code relies on the lower-level packet-assembly
24 code for that protocol in isgps.c.
26 The lower layer's job is done when it has assembled a message of up to
27 33 words of clean parity-checked data. At this point this upper layer
28 takes over. struct rtcm2_msg_t is overlaid on the buffer and the bitfields
29 are used to extract pieces of it. Those pieces are copied and (where
30 necessary) reassembled into a struct rtcm2_t.
32 This code and the contents of isgps.c are evolved from code by Wolfgang
33 Rupprecht. Wolfgang's decoder was loosely based on one written by
34 John Sager in 1999 (in particular the dump function emits a close
35 descendant of Sager's dump format). Here are John Sager's original
38 The RTCM decoder prints a legible representation of the input data.
39 The RTCM SC-104 specification is copyrighted, so I cannot
40 quote it - in fact, I have never read it! Most of the information
41 used to develop the decoder came from publication ITU-R M.823.
42 This is a specification of the data transmitted from LF DGPS
43 beacons in the 300kHz band. M.823 contains most of those parts of
44 RTCM SC-104 directly relevant to the air interface (there
45 are one or two annoying and vital omissions!). Information
46 about the serial interface format was gleaned from studying
47 the output of a beacon receiver test program made available on
50 This file is Copyright (c) 2010 by the GPSD project
51 BSD terms apply: see the file COPYING in the distribution root for details.
53 *****************************************************************************/
55 #ifndef _GPSD_RTCM2_H_
56 #define _GPSD_RTCM2_H_
59 * Structures for interpreting words in an RTCM-104 2.x message (after
60 * parity checking and removing inversion). Note, these structures
61 * are overlayed on the raw data in order to decode them into
62 * bitfields; this will fail horribly if your C compiler ever
63 * introduces padding between or before bit fields, or between
64 * 8-bit-aligned bitfields and character arrays.
66 * (In practice, the only class of machines on which this is likely
67 * to fail are word-aligned architectures without barrel shifters.
68 * Very few of these are left in 2008.)
70 * The RTCM 2.1 standard is less explicit than it should be about signed-integer
71 * representations. Two's complement is specified for prc and rrc (msg1wX),
75 #define ZCOUNT_SCALE 0.6 /* sec */
76 #define PCSMALL 0.02 /* meters */
77 #define PCLARGE 0.32 /* meters */
78 #define RRSMALL 0.002 /* meters/sec */
79 #define RRLARGE 0.032 /* meters/sec */
81 #define MAXPCSMALL (0x7FFF * PCSMALL) /* 16-bits signed */
82 #define MAXRRSMALL (0x7F * RRSMALL) /* 8-bits signed */
84 #define XYZ_SCALE 0.01 /* meters */
85 #define DXYZ_SCALE 0.1 /* meters */
86 #define LA_SCALE (90.0/32767.0) /* degrees */
87 #define LO_SCALE (180.0/32767.0) /* degrees */
88 #define FREQ_SCALE 0.1 /* kHz */
89 #define FREQ_OFFSET 190.0 /* kHz */
90 #define CNR_OFFSET 24 /* dB */
91 #define TU_SCALE 5 /* minutes */
95 #ifndef WORDS_BIGENDIAN /* little-endian, like x86 */
98 struct rtcm2_msghw1 { /* header word 1 */
100 uint refstaid:10; /* reference station ID */
101 uint msgtype:6; /* RTCM message type */
102 uint preamble:8; /* fixed at 01100110 */
106 struct rtcm2_msghw2 { /* header word 2 */
108 uint stathlth:3; /* station health */
116 /* msg 1 - differential gps corrections */
118 struct b_correction_t {
119 struct { /* msg 1 word 3 */
122 uint satident1:5; /* satellite ID */
128 struct { /* msg 1 word 4 */
130 uint satident2:5; /* satellite ID */
138 struct { /* msg 1 word 5 */
145 struct { /* msg 1 word 6 */
148 uint satident3:5; /* satellite ID */
155 struct { /* msg 1 word 7 */
159 uint pc3_l:8; /* NOTE: uint for low byte */
162 } corrections[(RTCM2_WORDS_MAX - 2) / 5];
165 /* msg 3 - reference station parameters */
192 /* msg 4 - reference station datum */
196 uint datum_alpha_char2:8;
197 uint datum_alpha_char1:8;
205 uint datum_sub_div_char2:8;
206 uint datum_sub_div_char1:8;
207 uint datum_sub_div_char3:8;
224 /* msg 5 - constellation health */
229 uint time_unhealthy:4;
232 uint health_enable:1;
235 uint issue_of_data_link:1;
242 /* msg 6 - null message */
244 /* msg 7 - beacon almanac */
267 * ITU-R M.823-2 page 9 and RTCM-SC104 v2.1 pages
268 * 4-21 and 4-22 are in conflict over the next two
269 * field sizes. ITU says 9+3, RTCM says 10+2.
270 * The latter correctly decodes the USCG station
271 * id's so I'll use that one here. -wsr
278 } almanac[(RTCM2_WORDS_MAX - 2)/3];
281 /* msg 16 - text msg */
289 } txt[RTCM2_WORDS_MAX-2];
292 /* unknown message */
293 isgps30bits_t rtcm2_msgunk[RTCM2_WORDS_MAX-2];
297 #endif /* LITTLE_ENDIAN */
299 #ifdef WORDS_BIGENDIAN
300 /* This struct was generated from the above using invert-bitfields.pl */
301 #ifndef S_SPLINT_S /* splint thinks it's a duplicate definition */
304 struct rtcm2_msghw1 { /* header word 1 */
306 uint preamble:8; /* fixed at 01100110 */
307 uint msgtype:6; /* RTCM message type */
308 uint refstaid:10; /* reference station ID */
312 struct rtcm2_msghw2 { /* header word 2 */
317 uint stathlth:3; /* station health */
322 /* msg 1 - differential gps corrections */
324 struct b_correction_t {
325 struct { /* msg 1 word 3 */
329 uint satident1:5; /* satellite ID */
334 struct { /* msg 1 word 4 */
340 uint satident2:5; /* satellite ID */
344 struct { /* msg 1 word 5 */
351 struct { /* msg 1 word 6 */
356 uint satident3:5; /* satellite ID */
361 struct { /* msg 1 word 7 */
363 uint pc3_l:8; /* NOTE: uint for low byte */
368 } corrections[(RTCM2_WORDS_MAX - 2) / 5];
371 /* msg 3 - reference station parameters */
398 /* msg 4 - reference station datum */
405 uint datum_alpha_char1:8;
406 uint datum_alpha_char2:8;
411 uint datum_sub_div_char3:8;
412 uint datum_sub_div_char1:8;
413 uint datum_sub_div_char2:8;
430 /* msg 5 - constellation health */
436 uint issue_of_data_link:1;
439 uint health_enable:1;
442 uint time_unhealthy:4;
448 /* msg 6 - null message */
450 /* msg 7 - beacon almanac */
471 /* see comments in LE struct above. */
478 } almanac[(RTCM2_WORDS_MAX - 2)/3];
481 /* msg 16 - text msg */
489 } txt[RTCM2_WORDS_MAX-2];
492 /* unknown message */
493 isgps30bits_t rtcm2_msgunk[RTCM2_WORDS_MAX-2];
497 #endif /* S_SPLINT_S */
498 #endif /* BIG ENDIAN */
499 #endif /* _GPSD_RTCM2_H_ */