diff options
Diffstat (limited to 'driver_rtcm2.h')
-rw-r--r-- | driver_rtcm2.h | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/driver_rtcm2.h b/driver_rtcm2.h new file mode 100644 index 00000000..fe2fdfe4 --- /dev/null +++ b/driver_rtcm2.h @@ -0,0 +1,497 @@ +/* $Id$ */ +#ifndef _GPSD_RTCM2_H_ +#define _GPSD_RTCM2_H_ + +/***************************************************************************** + +This is a decoder for RTCM-104 2.x, an obscure and complicated serial +protocol used for broadcasting pseudorange corrections from +differential-GPS reference stations. The applicable +standard is + +RTCM RECOMMENDED STANDARDS FOR DIFFERENTIAL NAVSTAR GPS SERVICE, +RTCM PAPER 194-93/SC 104-STD + +Ordering instructions are accessible from <http://www.rtcm.org/> +under "Publications". This describes version 2.1 of the RTCM specification. +RTCM-104 was later incrementally revised up to a 2.3 level before being +completely redesigned as level 3.0. + +Also applicable is ITU-R M.823: "Technical characteristics of +differential transmissions for global navigation satellite systems +from maritime radio beacons in the frequency band 283.5 - 315 kHz in +region 1 and 285 - 325 kHz in regions 2 & 3." + +The RTCM 2.x protocol uses as a transport layer the GPS satellite +downlink protocol described in IS-GPS-200, the Navstar GPS Interface +Specification. This code relies on the lower-level packet-assembly +code for that protocol in isgps.c. + +The lower layer's job is done when it has assembled a message of up to +33 words of clean parity-checked data. At this point this upper layer +takes over. struct rtcm2_msg_t is overlaid on the buffer and the bitfields +are used to extract pieces of it. Those pieces are copied and (where +necessary) reassembled into a struct rtcm2_t. + +This code and the contents of isgps.c are evolved from code by Wolfgang +Rupprecht. Wolfgang's decoder was loosely based on one written by +John Sager in 1999 (in particular the dump function emits a close +descendant of Sager's dump format). Here are John Sager's original +notes: + +The RTCM decoder prints a legible representation of the input data. +The RTCM SC-104 specification is copyrighted, so I cannot +quote it - in fact, I have never read it! Most of the information +used to develop the decoder came from publication ITU-R M.823. +This is a specification of the data transmitted from LF DGPS +beacons in the 300kHz band. M.823 contains most of those parts of +RTCM SC-104 directly relevant to the air interface (there +are one or two annoying and vital omissions!). Information +about the serial interface format was gleaned from studying +the output of a beacon receiver test program made available on +Starlink's website. + +*****************************************************************************/ + +/* + * Structures for interpreting words in an RTCM-104 2.x message (after + * parity checking and removing inversion). Note, these structures + * are overlayed on the raw data in order to decode them into + * bitfields; this will fail horribly if your C compiler ever + * introduces padding between or before bit fields, or between + * 8-bit-aligned bitfields and character arrays. + * + * (In practice, the only class of machines on which this is likely + * to fail are word-aligned architectures without barrel shifters. + * Very few of these are left in 2008.) + * + * The RTCM 2.1 standard is less explicit than it should be about signed-integer + * representations. Two's complement is specified for prc and rrc (msg1wX), + * but not everywhere. + */ + +#define ZCOUNT_SCALE 0.6 /* sec */ +#define PCSMALL 0.02 /* meters */ +#define PCLARGE 0.32 /* meters */ +#define RRSMALL 0.002 /* meters/sec */ +#define RRLARGE 0.032 /* meters/sec */ + +#define MAXPCSMALL (0x7FFF * PCSMALL) /* 16-bits signed */ +#define MAXRRSMALL (0x7F * RRSMALL) /* 8-bits signed */ + +#define XYZ_SCALE 0.01 /* meters */ +#define DXYZ_SCALE 0.1 /* meters */ +#define LA_SCALE (90.0/32767.0) /* degrees */ +#define LO_SCALE (180.0/32767.0) /* degrees */ +#define FREQ_SCALE 0.1 /* kHz */ +#define FREQ_OFFSET 190.0 /* kHz */ +#define CNR_OFFSET 24 /* dB */ +#define TU_SCALE 5 /* minutes */ + +#pragma pack(1) + +#ifndef WORDS_BIGENDIAN /* little-endian, like x86 */ + +struct rtcm2_msg_t { + struct rtcm2_msghw1 { /* header word 1 */ + uint parity:6; + uint refstaid:10; /* reference station ID */ + uint msgtype:6; /* RTCM message type */ + uint preamble:8; /* fixed at 01100110 */ + uint _pad:2; + } w1; + + struct rtcm2_msghw2 { /* header word 2 */ + uint parity:6; + uint stathlth:3; /* station health */ + uint frmlen:5; + uint sqnum:3; + uint zcnt:13; + uint _pad:2; + } w2; + + union { + /* msg 1 - differential gps corrections */ + struct rtcm2_msg1 { + struct b_correction_t { + struct { /* msg 1 word 3 */ + uint parity:6; + int pc1:16; + uint satident1:5; /* satellite ID */ + uint udre1:2; + uint scale1:1; + uint _pad:2; + } w3; + + struct { /* msg 1 word 4 */ + uint parity:6; + uint satident2:5; /* satellite ID */ + uint udre2:2; + uint scale2:1; + uint issuedata1:8; + int rangerate1:8; + uint _pad:2; + } w4; + + struct { /* msg 1 word 5 */ + uint parity:6; + int rangerate2:8; + int pc2:16; + uint _pad:2; + } w5; + + struct { /* msg 1 word 6 */ + uint parity:6; + int pc3_h:8; + uint satident3:5; /* satellite ID */ + uint udre3:2; + uint scale3:1; + uint issuedata2:8; + uint _pad:2; + } w6; + + struct { /* msg 1 word 7 */ + uint parity:6; + uint issuedata3:8; + int rangerate3:8; + uint pc3_l:8; /* NOTE: uint for low byte */ + uint _pad:2; + } w7; + } corrections[(RTCM2_WORDS_MAX - 2) / 5]; + } type1; + + /* msg 3 - reference station parameters */ + struct rtcm2_msg3 { + struct { + uint parity:6; + uint x_h:24; + uint _pad:2; + } w3; + struct { + uint parity:6; + uint y_h:16; + uint x_l:8; + uint _pad:2; + } w4; + struct { + uint parity:6; + uint z_h:8; + uint y_l:16; + uint _pad:2; + } w5; + + struct { + uint parity:6; + uint z_l:24; + uint _pad:2; + } w6; + } type3; + + /* msg 4 - reference station datum */ + struct rtcm2_msg4 { + struct { + uint parity:6; + uint datum_alpha_char2:8; + uint datum_alpha_char1:8; + uint spare:4; + uint dat:1; + uint dgnss:3; + uint _pad:2; + } w3; + struct { + uint parity:6; + uint datum_sub_div_char2:8; + uint datum_sub_div_char1:8; + uint datum_sub_div_char3:8; + uint _pad:2; + } w4; + struct { + uint parity:6; + uint dy_h:8; + uint dx:16; + uint _pad:2; + } w5; + struct { + uint parity:6; + uint dz:24; + uint dy_l:8; + uint _pad:2; + } w6; + } type4; + + /* msg 5 - constellation health */ + struct rtcm2_msg5 { + struct b_health_t { + uint parity:6; + uint unassigned:2; + uint time_unhealthy:4; + uint loss_warn:1; + uint new_nav_data:1; + uint health_enable:1; + uint cn0:5; + uint data_health:3; + uint issue_of_data_link:1; + uint sat_id:5; + uint reserved:1; + uint _pad:2; + } health[MAXHEALTH]; + } type5; + + /* msg 6 - null message */ + + /* msg 7 - beacon almanac */ + struct rtcm2_msg7 { + struct b_station_t { + struct { + uint parity:6; + int lon_h:8; + int lat:16; + uint _pad:2; + } w3; + struct { + uint parity:6; + uint freq_h:6; + uint range:10; + uint lon_l:8; + uint _pad:2; + } w4; + struct { + uint parity:6; + uint encoding:1; + uint sync_type:1; + uint mod_mode:1; + uint bit_rate:3; + /* + * ITU-R M.823-2 page 9 and RTCM-SC104 v2.1 pages + * 4-21 and 4-22 are in conflict over the next two + * field sizes. ITU says 9+3, RTCM says 10+2. + * The latter correctly decodes the USCG station + * id's so I'll use that one here. -wsr + */ + uint station_id:10; + uint health:2; + uint freq_l:6; + uint _pad:2; + } w5; + } almanac[(RTCM2_WORDS_MAX - 2)/3]; + } type7; + + /* msg 16 - text msg */ + struct rtcm2_msg16 { + struct { + uint parity:6; + uint byte3:8; + uint byte2:8; + uint byte1:8; + uint _pad:2; + } txt[RTCM2_WORDS_MAX-2]; + } type16; + + /* unknown message */ + isgps30bits_t rtcm2_msgunk[RTCM2_WORDS_MAX-2]; + } msg_type; +}; + +#endif /* LITTLE_ENDIAN */ + +#ifdef WORDS_BIGENDIAN +/* This struct was generated from the above using invert-bitfields.pl */ +#ifndef S_SPLINT_S /* splint thinks it's a duplicate definition */ + +struct rtcm2_msg_t { + struct rtcm2_msghw1 { /* header word 1 */ + uint _pad:2; + uint preamble:8; /* fixed at 01100110 */ + uint msgtype:6; /* RTCM message type */ + uint refstaid:10; /* reference station ID */ + uint parity:6; + } w1; + + struct rtcm2_msghw2 { /* header word 2 */ + uint _pad:2; + uint zcnt:13; + uint sqnum:3; + uint frmlen:5; + uint stathlth:3; /* station health */ + uint parity:6; + } w2; + + union { + /* msg 1 - differential gps corrections */ + struct rtcm2_msg1 { + struct b_correction_t { + struct { /* msg 1 word 3 */ + uint _pad:2; + uint scale1:1; + uint udre1:2; + uint satident1:5; /* satellite ID */ + int pc1:16; + uint parity:6; + } w3; + + struct { /* msg 1 word 4 */ + uint _pad:2; + int rangerate1:8; + uint issuedata1:8; + uint scale2:1; + uint udre2:2; + uint satident2:5; /* satellite ID */ + uint parity:6; + } w4; + + struct { /* msg 1 word 5 */ + uint _pad:2; + int pc2:16; + int rangerate2:8; + uint parity:6; + } w5; + + struct { /* msg 1 word 6 */ + uint _pad:2; + uint issuedata2:8; + uint scale3:1; + uint udre3:2; + uint satident3:5; /* satellite ID */ + int pc3_h:8; + uint parity:6; + } w6; + + struct { /* msg 1 word 7 */ + uint _pad:2; + uint pc3_l:8; /* NOTE: uint for low byte */ + int rangerate3:8; + uint issuedata3:8; + uint parity:6; + } w7; + } corrections[(RTCM2_WORDS_MAX - 2) / 5]; + } type1; + + /* msg 3 - reference station parameters */ + struct rtcm2_msg3 { + struct { + uint _pad:2; + uint x_h:24; + uint parity:6; + } w3; + struct { + uint _pad:2; + uint x_l:8; + uint y_h:16; + uint parity:6; + } w4; + struct { + uint _pad:2; + uint y_l:16; + uint z_h:8; + uint parity:6; + } w5; + + struct { + uint _pad:2; + uint z_l:24; + uint parity:6; + } w6; + } type3; + + /* msg 4 - reference station datum */ + struct rtcm2_msg4 { + struct { + uint _pad:2; + uint dgnss:3; + uint dat:1; + uint spare:4; + uint datum_alpha_char1:8; + uint datum_alpha_char2:8; + uint parity:6; + } w3; + struct { + uint _pad:2; + uint datum_sub_div_char3:8; + uint datum_sub_div_char1:8; + uint datum_sub_div_char2:8; + uint parity:6; + } w4; + struct { + uint _pad:2; + uint dx:16; + uint dy_h:8; + uint parity:6; + } w5; + struct { + uint _pad:2; + uint dy_l:8; + uint dz:24; + uint parity:6; + } w6; + } type4; + + /* msg 5 - constellation health */ + struct rtcm2_msg5 { + struct b_health_t { + uint _pad:2; + uint reserved:1; + uint sat_id:5; + uint issue_of_data_link:1; + uint data_health:3; + uint cn0:5; + uint health_enable:1; + uint new_nav_data:1; + uint loss_warn:1; + uint time_unhealthy:4; + uint unassigned:2; + uint parity:6; + } health[MAXHEALTH]; + } type5; + + /* msg 6 - null message */ + + /* msg 7 - beacon almanac */ + struct rtcm2_msg7 { + struct b_station_t { + struct { + uint _pad:2; + int lat:16; + int lon_h:8; + uint parity:6; + } w3; + struct { + uint _pad:2; + uint lon_l:8; + uint range:10; + uint freq_h:6; + uint parity:6; + } w4; + struct { + uint _pad:2; + uint freq_l:6; + uint health:2; + uint station_id:10; + /* see comments in LE struct above. */ + uint bit_rate:3; + uint mod_mode:1; + uint sync_type:1; + uint encoding:1; + uint parity:6; + } w5; + } almanac[(RTCM2_WORDS_MAX - 2)/3]; + } type7; + + /* msg 16 - text msg */ + struct rtcm2_msg16 { + struct { + uint _pad:2; + uint byte1:8; + uint byte2:8; + uint byte3:8; + uint parity:6; + } txt[RTCM2_WORDS_MAX-2]; + } type16; + + /* unknown message */ + isgps30bits_t rtcm2_msgunk[RTCM2_WORDS_MAX-2]; + } msg_type; +}; + +#endif /* S_SPLINT_S */ +#endif /* BIG ENDIAN */ +#endif /* _GPSD_RTCM2_H_ */ |