1 /*****************************************************************************
2 
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
6 standard is
7 
8 RTCM RECOMMENDED STANDARDS FOR DIFFERENTIAL GNSS (GLOBAL NAVIGATION
9 SATELLITE) SERVICE, VERSION 2.3 (RTCM PAPER 136-2001/SC104-STD)
10 
11 Ordering instructions are accessible from <http://www.rtcm.org/>
12 under "Publications".  This describes version 2.3 of the RTCM specification.
13 RTCM-104 was later completely redesigned as level 3.0.
14 
15 Also applicable is ITU-R M.823: "Technical characteristics of
16 differential transmissions for global navigation satellite systems
17 from maritime radio beacons in the frequency band 283.5 - 315 kHz in
18 region 1 and 285 - 325 kHz in regions 2 & 3."
19 
20 The RTCM 2.x protocol uses as a transport layer the GPS satellite downlink
21 protocol described in IS-GPS-200, the Navstar GPS Interface
22 Specification.  This code relies on the lower-level packet-assembly
23 code for that protocol in isgps.c.
24 
25 The lower layer's job is done when it has assembled a message of up to
26 33 30-bit words of clean parity-checked data.  At this point this upper layer
27 takes over.  struct rtcm2_msg_t is overlaid on the buffer and the bitfields
28 are used to extract pieces of it.  Those pieces are copied and (where
29 necessary) reassembled into a struct rtcm2_t.
30 
31 This code and the contents of isgps.c are evolved from code by
32 Wolfgang Rupprecht.  Wolfgang's decoder was loosely based on one
33 written by John Sager in 1999.  Here are John Sager's original notes:
34 
35 The RTCM decoder prints a legible representation of the input data.
36 The RTCM SC-104 specification is copyrighted, so I cannot
37 quote it - in fact, I have never read it! Most of the information
38 used to develop the decoder came from publication ITU-R M.823.
39 This is a specification of the data transmitted from LF DGPS
40 beacons in the 300kHz band. M.823 contains most of those parts of
41 RTCM SC-104 directly relevant to the air interface (there
42 are one or two annoying and vital omissions!). Information
43 about the serial interface format was gleaned from studying
44 the output of a beacon receiver test program made available on
45 Starlink's website.
46 
47 This code has been checked against ASCII dumps made by a proprietary
48 decoder running under Windows and is known to be consistent with it
49 with respect to message types 1, 3, 9, 14, 16, and 31.  Decoding of
50 message types 4, 5, 6, 7, and 13 has not been checked. Message types
51 8, 10-12, 15-27, 28-30 (undefined), 31-37, 38-58 (undefined), and
52 60-63 are not yet supported.
53 
54 This file is Copyright (c) 2010-2018 by the GPSD project
55 SPDX-License-Identifier: BSD-2-clause
56 
57 *****************************************************************************/
58 
59 #include "gpsd_config.h"  /* must be before all includes */
60 
61 #include <stdio.h>
62 #include <string.h>
63 
64 #include "gpsd.h"
65 
66 /*
67   __BYTE_ORDER__, __ORDER_BIG_ENDIAN__ and __ORDER_LITTLE_ENDIAN__ are
68   defined in some gcc versions only, probably depending on the
69   architecture. Try to use endian.h if the gcc way fails - endian.h also
70   does not seem to be available on all platforms.
71 */
72 
73 #if HAVE_BUILTIN_ENDIANNESS
74 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
75 #define WORDS_BIGENDIAN 1
76 #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
77 #undef WORDS_BIGENDIAN
78 #else
79 #error Unknown endianness!
80 #endif
81 
82 #else /* HAVE_BUILTIN_ENDIANNESS */
83 
84 #if defined(HAVE_ENDIAN_H)
85 #include <endian.h>
86 #elif defined(HAVE_SYS_ENDIAN_H)
87 #include <sys/endian.h>
88 #elif defined(HAVE_MACHINE_ENDIAN_H)
89 #include <machine/endian.h>
90 #endif
91 
92 /*
93  * Darwin (Mac OS X) uses special defines.
94  * This must precede the BSD case, since _BIG_ENDIAN may be incorrectly defined
95  */
96 #if !defined( __BYTE_ORDER) && defined(__DARWIN_BYTE_ORDER)
97 #define __BYTE_ORDER __DARWIN_BYTE_ORDER
98 #endif
99 #if !defined( __BIG_ENDIAN) && defined(__DARWIN_BIG_ENDIAN)
100 #define __BIG_ENDIAN __DARWIN_BIG_ENDIAN
101 #endif
102 #if !defined( __LITTLE_ENDIAN) && defined(__DARWIN_LITTLE_ENDIAN)
103 #define __LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
104 #endif
105 
106 /*
107  * BSD uses _BYTE_ORDER, and Linux uses __BYTE_ORDER.
108  */
109 #if !defined( __BYTE_ORDER) && defined(_BYTE_ORDER)
110 #define __BYTE_ORDER _BYTE_ORDER
111 #endif
112 #if !defined( __BIG_ENDIAN) && defined(_BIG_ENDIAN)
113 #define __BIG_ENDIAN _BIG_ENDIAN
114 #endif
115 #if !defined( __LITTLE_ENDIAN) && defined(_LITTLE_ENDIAN)
116 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
117 #endif
118 
119 #if !defined(__BYTE_ORDER) || !defined(__BIG_ENDIAN) || !defined(__LITTLE_ENDIAN)
120 #error endianness macros are not defined
121 #endif
122 
123 #if __BYTE_ORDER == __BIG_ENDIAN
124 #define WORDS_BIGENDIAN 1
125 #elif __BYTE_ORDER == __LITTLE_ENDIAN
126 #undef WORDS_BIGENDIAN
127 #else
128 #error Unknown endianness!
129 #endif /* __BYTE_ORDER */
130 
131 #endif /* HAVE_BUILTIN_ENDIANNESS */
132 
133 /*
134  * Structures for interpreting words in an RTCM-104 2.x message (after
135  * parity checking and removing inversion).  Note, these structures
136  * are overlayed on the raw data in order to decode them into
137  * bitfields; this will fail horribly if your C compiler introduces
138  * padding between or before bit fields, or between 8-bit-aligned
139  * bitfields and character arrays despite #pragma pack(1).  The right
140  * things happen under gcc 4.x on amd64, i386, ia64, all arm and mips
141  * variants, m68k, and powerpc)
142  *
143  * (In practice, the only class of machines on which this is likely
144  * to fail are word-aligned architectures without barrel shifters.
145  * Very few of these are left in 2012. By test, we know of s390, s390x,
146  * and sparc.)
147  *
148  * The RTCM 2.1 standard is less explicit than it should be about
149  * signed-integer representations.  Two's complement is specified for
150  * some but not all.
151  */
152 
153 #define ZCOUNT_SCALE    0.6     /* sec */
154 #define PRCSMALL        0.02    /* meters */
155 #define PRCLARGE        0.32    /* meters */
156 #define RRSMALL         0.002   /* meters/sec */
157 #define RRLARGE         0.032   /* meters/sec */
158 
159 #define MAXPCSMALL     (0x7FFF * PCSMALL)  /* 16-bits signed */
160 #define MAXRRSMALL     (0x7F   * RRSMALL)  /*  8-bits signed */
161 
162 #define XYZ_SCALE       0.01    /* meters */
163 #define DXYZ_SCALE      0.1     /* meters */
164 #define LA_SCALE        (90.0/32767.0)  /* degrees */
165 #define LO_SCALE        (180.0/32767.0) /* degrees */
166 #define FREQ_SCALE      0.1     /* kHz */
167 #define FREQ_OFFSET     190.0   /* kHz */
168 #define CNR_OFFSET      24      /* dB */
169 #define TU_SCALE        5       /* minutes */
170 
171 #define LATLON_SCALE    0.01    /* degrees */
172 #define RANGE_SCALE     4       /* kilometers */
173 
174 #pragma pack(1)
175 
176 /*
177  * Reminder: Emacs reverse-region is useful...
178  */
179 
180 #ifndef WORDS_BIGENDIAN /* little-endian, like x86 */
181 
182 struct rtcm2_msg_t {
183     struct rtcm2_msghw1 {                       /* header word 1 */
184         unsigned int            parity:6;
185         unsigned int            refstaid:10;    /* reference station ID */
186         unsigned int            msgtype:6;      /* RTCM message type */
187         unsigned int            preamble:8;     /* fixed at 01100110 */
188         unsigned int            _pad:2;
189     } w1;
190 
191     struct rtcm2_msghw2 {                       /* header word 2 */
192         unsigned int            parity:6;
193         unsigned int            stathlth:3;     /* station health */
194         unsigned int            frmlen:5;
195         unsigned int            sqnum:3;
196         unsigned int            zcnt:13;
197         unsigned int            _pad:2;
198     } w2;
199 
200     union {
201         /* msg 1 - differential gps corrections */
202         struct rtcm2_msg1 {
203             struct gps_correction_t {
204                 struct {                        /* msg 1 word 3 */
205                     unsigned int    parity:6;
206                     int             prc1:16;
207                     unsigned int    satident1:5;        /* satellite ID */
208                     unsigned int    udre1:2;
209                     unsigned int    scale1:1;
210                     unsigned int    _pad:2;
211                 } w3;
212 
213                 struct {                        /* msg 1 word 4 */
214                     unsigned int    parity:6;
215                     unsigned int    satident2:5;        /* satellite ID */
216                     unsigned int    udre2:2;
217                     unsigned int    scale2:1;
218                     unsigned int    iod1:8;
219                     int             rrc1:8;
220                     unsigned int    _pad:2;
221                 } w4;
222 
223                 struct {                        /* msg 1 word 5 */
224                     unsigned int    parity:6;
225                     int             rrc2:8;
226                     int             prc2:16;
227                     unsigned int    _pad:2;
228                 } w5;
229 
230                 struct {                        /* msg 1 word 6 */
231                     unsigned int    parity:6;
232                     int             prc3_h:8;
233                     unsigned int    satident3:5;        /* satellite ID */
234                     unsigned int    udre3:2;
235                     unsigned int    scale3:1;
236                     unsigned int    iod2:8;
237                     unsigned int    _pad:2;
238                 } w6;
239 
240                 struct {                        /* msg 1 word 7 */
241                     unsigned int    parity:6;
242                     unsigned int    iod3:8;
243                     int             rrc3:8;
244                     /* NOTE: unsigned int for low byte */
245                     unsigned int    prc3_l:8;
246                     unsigned int    _pad:2;
247                 } w7;
248             } corrections[(RTCM2_WORDS_MAX - 2) / 5];
249         } type1;
250 
251         /* msg 2 -  Pseudo-range corrections, referring to previous orbit
252          * data records (maximum 12 satellites) */
253 
254         /* msg 3 - reference station parameters */
255         struct rtcm2_msg3 {
256             struct {
257                 unsigned int        parity:6;
258                 unsigned int        x_h:24;
259                 unsigned int        _pad:2;
260             } w3;
261             struct {
262                 unsigned int        parity:6;
263                 unsigned int        y_h:16;
264                 unsigned int        x_l:8;
265                 unsigned int        _pad:2;
266             } w4;
267             struct {
268                 unsigned int        parity:6;
269                 unsigned int        z_h:8;
270                 unsigned int        y_l:16;
271                 unsigned int        _pad:2;
272             } w5;
273 
274             struct {
275                 unsigned int        parity:6;
276                 unsigned int        z_l:24;
277                 unsigned int        _pad:2;
278             } w6;
279         } type3;
280 
281         /* msg 4 - reference station datum */
282         struct rtcm2_msg4 {
283             struct {
284                 unsigned int        parity:6;
285                 unsigned int        datum_alpha_char2:8;
286                 unsigned int        datum_alpha_char1:8;
287                 unsigned int        spare:4;
288                 unsigned int        dat:1;
289                 unsigned int        dgnss:3;
290                 unsigned int        _pad:2;
291             } w3;
292             struct {
293                 unsigned int        parity:6;
294                 unsigned int        datum_sub_div_char2:8;
295                 unsigned int        datum_sub_div_char1:8;
296                 unsigned int        datum_sub_div_char3:8;
297                 unsigned int        _pad:2;
298             } w4;
299             struct {
300                 unsigned int        parity:6;
301                 unsigned int        dy_h:8;
302                 unsigned int        dx:16;
303                 unsigned int        _pad:2;
304             } w5;
305             struct {
306                 unsigned int        parity:6;
307                 unsigned int        dz:24;
308                 unsigned int        dy_l:8;
309                 unsigned int        _pad:2;
310             } w6;
311         } type4;
312 
313         /* msg 5 - constellation health */
314         struct rtcm2_msg5 {
315             struct b_health_t {
316                 unsigned int        parity:6;
317                 unsigned int        unassigned:2;
318                 unsigned int        time_unhealthy:4;
319                 unsigned int        loss_warn:1;
320                 unsigned int        new_nav_data:1;
321                 unsigned int        health_enable:1;
322                 unsigned int        cn0:5;
323                 unsigned int        data_health:3;
324                 unsigned int        issue_of_data_link:1;
325                 unsigned int        sat_id:5;
326                 unsigned int        reserved:1;
327                 unsigned int        _pad:2;
328             } health[MAXHEALTH];
329         } type5;
330 
331         /* msg 6 - null message */
332 
333         /* msg 7 - beacon almanac */
334         struct rtcm2_msg7 {
335             struct b_station_t {
336                 struct {
337                     unsigned int    parity:6;
338                     int             lon_h:8;
339                     int             lat:16;
340                     unsigned int    _pad:2;
341                 } w3;
342                 struct {
343                     unsigned int    parity:6;
344                     unsigned int    freq_h:6;
345                     unsigned int    range:10;
346                     unsigned int    lon_l:8;
347                     unsigned int    _pad:2;
348                 } w4;
349                 struct {
350                     unsigned int    parity:6;
351                     unsigned int    encoding:1;
352                     unsigned int    sync_type:1;
353                     unsigned int    mod_mode:1;
354                     unsigned int    bit_rate:3;
355                     /*
356                      * ITU-R M.823-2 page 9 and RTCM-SC104 v2.1 pages
357                      * 4-21 and 4-22 are in conflict over the next two
358                      * field sizes.  ITU says 9+3, RTCM says 10+2.
359                      * The latter correctly decodes the USCG station
360                      * id's so I'll use that one here. -wsr
361                      */
362                     unsigned int    station_id:10;
363                     unsigned int    health:2;
364                     unsigned int    freq_l:6;
365                     unsigned int    _pad:2;
366                 } w5;
367             } almanac[(RTCM2_WORDS_MAX - 2)/3];
368         } type7;
369 
370         // msg 8 - Pseudolite almanac
371 
372         // msg 9 - GPS Partial correction set
373 
374         // msg 10 - P-code differential corrections
375 
376         // msg 11 - C/A-code L1, L2 delta corrections
377 
378         // msg 12 - Pseudolite station parameters.
379 
380         /* msg 13 - Ground Transmitter Parameters (RTCM2.3 only) */
381         struct rtcm2_msg13 {
382             struct {
383                 unsigned int        parity:6;
384                 int                 lat:16;
385                 unsigned int        reserved:6;
386                 unsigned int        rangeflag:1;
387                 unsigned int        status:1;
388                 unsigned int        _pad:2;
389             } w1;
390             struct {
391                 unsigned int        parity:6;
392                 unsigned int        range:8;
393                 int                 lon:16;
394                 unsigned int        _pad:2;
395             } w2;
396         } type13;
397 
398         /* msg 14 - GPS Time of Week (RTCM2.3 only) */
399         struct rtcm2_msg14 {
400             struct {
401                 unsigned int        parity:6;
402                 unsigned int        leapsecs:6;
403                 unsigned int        hour:8;
404                 unsigned int        week:10;
405                 unsigned int        _pad:2;
406             } w1;
407         } type14;
408 
409         // msg 15 - Ionospheric delay message
410 
411         /* msg 16 - text msg */
412         struct rtcm2_msg16 {
413             struct {
414                 unsigned int        parity:6;
415                 unsigned int        byte3:8;
416                 unsigned int        byte2:8;
417                 unsigned int        byte1:8;
418                 unsigned int        _pad:2;
419             } txt[RTCM2_WORDS_MAX-2];
420         } type16;
421 
422         // msg 17 - GPS ephmerides.  RTCM 2.1
423 
424         // msg 18 - RTK uncorrected carrier phases.  RTCM 2.1
425 
426         // msg 19 - RTK uncorrected psuedoranges.  RTCM 2.1
427 
428         // msg 20 - RTK carrier phase corrections.  RTCM 2.1
429 
430         // msg 21 - RTK/high accuracy psuedorange corrections.  RTCM 2.1
431 
432         // msg 22 - Extended reference station parameters
433 
434         // msg 23 - Type of Antenna.  RTCM 2.3
435 
436         // msg 24 - Reference station ARP..  RTCM 2.3
437 
438         // msg 27 -  Extended almanac of DGPS.
439 
440         /* msg 31 - differential GLONASS corrections */
441         struct rtcm2_msg31 {
442             struct glonass_correction_t {
443                 struct {                        /* msg 1 word 3 */
444                     unsigned int    parity:6;
445                     int             prc1:16;
446                     unsigned int    satident1:5;        /* satellite ID */
447                     unsigned int    udre1:2;
448                     unsigned int    scale1:1;
449                     unsigned int    _pad:2;
450                 } w3;
451 
452                 struct {                        /* msg 1 word 4 */
453                     unsigned int    parity:6;
454                     unsigned int    satident2:5;        /* satellite ID */
455                     unsigned int    udre2:2;
456                     unsigned int    scale2:1;
457                     unsigned int    tod1:7;
458                     unsigned int    change1:1;
459                     int             rrc1:8;
460                     unsigned int    _pad:2;
461                 } w4;
462 
463                 struct {                        /* msg 1 word 5 */
464                     unsigned int    parity:6;
465                     int             rrc2:8;
466                     int             prc2:16;
467                     unsigned int    _pad:2;
468                 } w5;
469 
470                 struct {                        /* msg 1 word 6 */
471                     unsigned int    parity:6;
472                     int             prc3_h:8;
473                     unsigned int    satident3:5;        /* satellite ID */
474                     unsigned int    udre3:2;
475                     unsigned int    scale3:1;
476                     unsigned int    tod2:7;
477                     unsigned int    change2:1;
478                     unsigned int    _pad:2;
479                 } w6;
480 
481                 struct {                        /* msg 1 word 7 */
482                     unsigned int    parity:6;
483                     unsigned int    tod3:7;
484                     unsigned int    change3:1;
485                     int             rrc3:8;
486                     /* NOTE: unsigned int for low byte */
487                     unsigned int    prc3_l:8;
488                     unsigned int    _pad:2;
489                 } w7;
490             } corrections[(RTCM2_WORDS_MAX - 2) / 5];
491         } type31;
492 
493         // msg 32 - Differential GLONASS reference station parameters, RTCM 2.3
494 
495         // msg 33 - GLONASS constellation health, RTCM 2.3
496 
497         // msg 34 - DGLONASS corrections, RTCM 2.3
498 
499         // msg 35 - GLONASS radiobeacon almanac, RTCM 2.3
500 
501         // msg 36 - GLONASS special message, RTCM 2.3
502 
503         // msg 37 - GNSS system time offset, RTCM 2.3
504 
505         /* msg 59 -  Proprietary messages, for transmission of any
506          * required data */
507 
508         // msg 60-63 - Multipurpsoe usage
509 
510         /* unknown message */
511         isgps30bits_t   rtcm2_msgunk[RTCM2_WORDS_MAX-2];
512     } msg_type;
513 } __attribute__((__packed__));
514 
515 #endif /* LITTLE_ENDIAN */
516 
517 #ifdef WORDS_BIGENDIAN
518 
519 struct rtcm2_msg_t {
520     struct rtcm2_msghw1 {                       /* header word 1 */
521         unsigned int            _pad:2;
522         unsigned int            preamble:8;     /* fixed at 01100110 */
523         unsigned int            msgtype:6;      /* RTCM message type */
524         unsigned int            refstaid:10;    /* reference station ID */
525         unsigned int            parity:6;
526     } w1;
527 
528     struct rtcm2_msghw2 {                       /* header word 2 */
529         unsigned int            _pad:2;
530         unsigned int            zcnt:13;
531         unsigned int            sqnum:3;
532         unsigned int            frmlen:5;
533         unsigned int            stathlth:3;     /* station health */
534         unsigned int            parity:6;
535     } w2;
536 
537     union {
538         /* msg 1 - differential GPS corrections */
539         struct rtcm2_msg1 {
540             struct gps_correction_t {
541                 struct {                        /* msg 1 word 3 */
542                     unsigned int    _pad:2;
543                     unsigned int    scale1:1;
544                     unsigned int    udre1:2;
545                     unsigned int    satident1:5;  /* satellite ID */
546                     int             prc1:16;
547                     unsigned int    parity:6;
548                 } w3;
549 
550                 struct {                        /* msg 1 word 4 */
551                     unsigned int    _pad:2;
552                     int             rrc1:8;
553                     unsigned int    iod1:8;
554                     unsigned int    scale2:1;
555                     unsigned int    udre2:2;
556                     unsigned int    satident2:5;        /* satellite ID */
557                     unsigned int    parity:6;
558                 } w4;
559 
560                 struct {                        /* msg 1 word 5 */
561                     unsigned int    _pad:2;
562                     int             prc2:16;
563                     int             rrc2:8;
564                     unsigned int    parity:6;
565                 } w5;
566 
567                 struct {                        /* msg 1 word 6 */
568                     unsigned int    _pad:2;
569                     unsigned int    iod2:8;
570                     unsigned int    scale3:1;
571                     unsigned int    udre3:2;
572                     unsigned int    satident3:5;        /* satellite ID */
573                     int             prc3_h:8;
574                     unsigned int    parity:6;
575                 } w6;
576 
577                 struct {                        /* msg 1 word 7 */
578                     unsigned int    _pad:2;
579                     unsigned int    prc3_l:8;   // NOTE: unsigned for low byte
580                     int             rrc3:8;
581                     unsigned int    iod3:8;
582                     unsigned int    parity:6;
583                 } w7;
584             } corrections[(RTCM2_WORDS_MAX - 2) / 5];
585         } type1;
586 
587         /* msg 2 -  Pseudo-range corrections, referring to previous orbit
588          * data records (maximum 12 satellites) */
589 
590         /* msg 3 - reference station parameters */
591         struct rtcm2_msg3 {
592             struct {
593                 unsigned int        _pad:2;
594                 unsigned int        x_h:24;
595                 unsigned int        parity:6;
596             } w3;
597             struct {
598                 unsigned int        _pad:2;
599                 unsigned int        x_l:8;
600                 unsigned int        y_h:16;
601                 unsigned int        parity:6;
602             } w4;
603             struct {
604                 unsigned int        _pad:2;
605                 unsigned int        y_l:16;
606                 unsigned int        z_h:8;
607                 unsigned int        parity:6;
608             } w5;
609 
610             struct {
611                 unsigned int        _pad:2;
612                 unsigned int        z_l:24;
613                 unsigned int        parity:6;
614             } w6;
615         } type3;
616 
617         /* msg 4 - reference station datum */
618         struct rtcm2_msg4 {
619             struct {
620                 unsigned int        _pad:2;
621                 unsigned int        dgnss:3;
622                 unsigned int        dat:1;
623                 unsigned int        spare:4;
624                 unsigned int        datum_alpha_char1:8;
625                 unsigned int        datum_alpha_char2:8;
626                 unsigned int        parity:6;
627             } w3;
628             struct {
629                 unsigned int        _pad:2;
630                 unsigned int        datum_sub_div_char3:8;
631                 unsigned int        datum_sub_div_char1:8;
632                 unsigned int        datum_sub_div_char2:8;
633                 unsigned int        parity:6;
634             } w4;
635             struct {
636                 unsigned int        _pad:2;
637                 unsigned int        dx:16;
638                 unsigned int        dy_h:8;
639                 unsigned int        parity:6;
640             } w5;
641             struct {
642                 unsigned int        _pad:2;
643                 unsigned int        dy_l:8;
644                 unsigned int        dz:24;
645                 unsigned int        parity:6;
646             } w6;
647         } type4;
648 
649         /* msg 5 - constellation health */
650         struct rtcm2_msg5 {
651             struct b_health_t {
652                 unsigned int        _pad:2;
653                 unsigned int        reserved:1;
654                 unsigned int        sat_id:5;
655                 unsigned int        issue_of_data_link:1;
656                 unsigned int        data_health:3;
657                 unsigned int        cn0:5;
658                 unsigned int        health_enable:1;
659                 unsigned int        new_nav_data:1;
660                 unsigned int        loss_warn:1;
661                 unsigned int        time_unhealthy:4;
662                 unsigned int        unassigned:2;
663                 unsigned int        parity:6;
664             } health[MAXHEALTH];
665         } type5;
666 
667         // msg - 6 -  Null message, used as filler record during time-outs
668 
669         /* msg 7 - beacon almanac */
670         struct rtcm2_msg7 {
671             struct b_station_t {
672                 struct {
673                     unsigned int    _pad:2;
674                     int             lat:16;
675                     int             lon_h:8;
676                     unsigned int    parity:6;
677                 } w3;
678                 struct {
679                     unsigned int    _pad:2;
680                     unsigned int    lon_l:8;
681                     unsigned int    range:10;
682                     unsigned int    freq_h:6;
683                     unsigned int    parity:6;
684                 } w4;
685                 struct {
686                     unsigned int    _pad:2;
687                     unsigned int    freq_l:6;
688                     unsigned int    health:2;
689                     unsigned int    station_id:10;
690                              /* see comments in LE struct above. */
691                     unsigned int    bit_rate:3;
692                     unsigned int    mod_mode:1;
693                     unsigned int    sync_type:1;
694                     unsigned int    encoding:1;
695                     unsigned int    parity:6;
696                 } w5;
697             } almanac[(RTCM2_WORDS_MAX - 2)/3];
698         } type7;
699 
700         // msg 8 - Pseudolite almanac
701 
702         // msg 9 - GPS Partial correction set
703 
704         // msg 10 - P-code differential corrections
705 
706         // msg 11 - C/A-code L1, L2 delta corrections
707 
708         // msg 12 - Pseudolite station parameters.
709 
710         /* msg 13 - Ground Transmitter Parameters (RTCM2.3 only) */
711         struct rtcm2_msg13 {
712             struct {
713                 unsigned int        _pad:2;
714                 unsigned int        status:1;
715                 unsigned int        rangeflag:1;
716                 unsigned int        reserved:6;
717                 int                 lat:16;
718                 unsigned int        parity:6;
719             } w1;
720             struct {
721                 unsigned int        _pad:2;
722                 int                 lon:16;
723                 unsigned int        range:8;
724                 unsigned int        parity:6;
725             } w2;
726         } type13;
727 
728         /* msg 14 - GPS Time of Week (RTCM2.3 only) */
729         struct rtcm2_msg14 {
730             struct {
731                 unsigned int        _pad:2;
732                 unsigned int        week:10;
733                 unsigned int        hour:8;
734                 unsigned int        leapsecs:6;
735                 unsigned int        parity:6;
736             } w1;
737         } type14;
738 
739         // msg 15 - Ionospheric delay message
740 
741         /* msg 16 - text msg */
742         struct rtcm2_msg16 {
743             struct {
744                 unsigned int        _pad:2;
745                 unsigned int        byte1:8;
746                 unsigned int        byte2:8;
747                 unsigned int        byte3:8;
748                 unsigned int        parity:6;
749             } txt[RTCM2_WORDS_MAX-2];
750         } type16;
751 
752         // msg 17 - GPS ephmerides.  RTCM 2.1
753 
754         // msg 18 - RTK uncorrected carrier phases.  RTCM 2.1
755 
756         // msg 19 - RTK uncorrected psuedoranges.  RTCM 2.1
757 
758         // msg 20 - RTK carrier phase corrections.  RTCM 2.1
759 
760         // msg 21 - RTK/high accuracy psuedorange corrections.  RTCM 2.1
761 
762         // msg 22 - Extended reference station parameters
763 
764         // msg 23 - Type of Antenna.  RTCM 2.3
765 
766         // msg 24 - Reference station ARP..  RTCM 2.3
767 
768         // msg 27 -  Extended almanac of DGPS.
769 
770         /* msg 31 - differential GLONASS corrections */
771         struct rtcm2_msg31 {
772             struct glonass_correction_t {
773                 struct {                        /* msg 1 word 3 */
774                     unsigned int    _pad:2;
775                     unsigned int    scale1:1;
776                     unsigned int    udre1:2;
777                     unsigned int    satident1:5;        /* satellite ID */
778                     int             prc1:16;
779                     unsigned int    parity:6;
780                 } w3;
781 
782                 struct {                        /* msg 1 word 4 */
783                     unsigned int    _pad:2;
784                     int             rrc1:8;
785                     unsigned int    change1:1;
786                     unsigned int    tod1:7;
787                     unsigned int    scale2:1;
788                     unsigned int    udre2:2;
789                     unsigned int    satident2:5;        /* satellite ID */
790                     unsigned int    parity:6;
791                 } w4;
792 
793                 struct {                        /* msg 1 word 5 */
794                     unsigned int    _pad:2;
795                     int             prc2:16;
796                     int             rrc2:8;
797                     unsigned int    parity:6;
798                 } w5;
799 
800                 struct {                        /* msg 1 word 6 */
801                     unsigned int    _pad:2;
802                     unsigned int    change2:1;
803                     unsigned int    tod2:7;
804                     unsigned int    scale3:1;
805                     unsigned int    udre3:2;
806                     unsigned int    satident3:5;        /* satellite ID */
807                     int             prc3_h:8;
808                     unsigned int    parity:6;
809                 } w6;
810 
811                 struct {                        /* msg 1 word 7 */
812                     unsigned int    _pad:2;
813                     unsigned int    prc3_l:8;   // NOTE: unsigned for low byte
814                     int             rrc3:8;
815                     unsigned int    change3:1;
816                     unsigned int    tod3:7;
817                     unsigned int    parity:6;
818                 } w7;
819             } corrections[(RTCM2_WORDS_MAX - 2) / 5];
820         } type31;
821 
822         // msg 32 - Differential GLONASS reference station parameters, RTCM 2.3
823 
824         // msg 33 - GLONASS constellation health, RTCM 2.3
825 
826         // msg 34 - DGLONASS corrections, RTCM 2.3
827 
828         // msg 35 - GLONASS radiobeacon almanac, RTCM 2.3
829 
830         // msg 36 - GLONASS special message, RTCM 2.3
831 
832         // msg 37 - GNSS system time offset, RTCM 2.3
833 
834         /* msg 59 -  Proprietary messages, for transmission of any
835          * required data */
836 
837         // msg 60-63 - Multipurpsoe usage
838 
839         /* unknown message */
840         isgps30bits_t   rtcm2_msgunk[RTCM2_WORDS_MAX-2];
841     } msg_type;
842 } __attribute__((__packed__));
843 
844 #endif /* BIG ENDIAN */
845 
846 #ifdef RTCM104V2_ENABLE
847 
848 #define PREAMBLE_PATTERN 0x66
849 
850 static unsigned int tx_speed[] = { 25, 50, 100, 110, 150, 200, 250, 300 };
851 
852 #define DIMENSION(a) (unsigned)(sizeof(a)/sizeof(a[0]))
853 
rtcm2_unpack(struct rtcm2_t * tp,char * buf)854 void rtcm2_unpack(struct rtcm2_t *tp, char *buf)
855 /* break out the raw bits into the content fields */
856 {
857     int len;
858     unsigned int n, w;
859     struct rtcm2_msg_t *msg = (struct rtcm2_msg_t *)buf;
860 
861     tp->type = msg->w1.msgtype;
862     tp->length = msg->w2.frmlen;
863     tp->zcount = msg->w2.zcnt * ZCOUNT_SCALE;
864     tp->refstaid = msg->w1.refstaid;
865     tp->seqnum = msg->w2.sqnum;
866     tp->stathlth = msg->w2.stathlth;
867 
868     len = (int)tp->length;
869     n = 0;
870     switch (tp->type) {
871     case 1:
872     case 9:
873     {
874         struct gps_correction_t *m = &msg->msg_type.type1.corrections[0];
875 
876         while (len >= 0) {
877             if (len >= 2) {
878                 tp->gps_ranges.sat[n].ident = m->w3.satident1;
879                 tp->gps_ranges.sat[n].udre = m->w3.udre1;
880                 tp->gps_ranges.sat[n].iod = m->w4.iod1;
881                 tp->gps_ranges.sat[n].prc = m->w3.prc1 *
882                     (m->w3.scale1 ? PRCLARGE : PRCSMALL);
883                 tp->gps_ranges.sat[n].rrc = m->w4.rrc1 *
884                     (m->w3.scale1 ? RRLARGE : RRSMALL);
885                 n++;
886             }
887             if (len >= 4) {
888                 tp->gps_ranges.sat[n].ident = m->w4.satident2;
889                 tp->gps_ranges.sat[n].udre = m->w4.udre2;
890                 tp->gps_ranges.sat[n].iod = m->w6.iod2;
891                 tp->gps_ranges.sat[n].prc = m->w5.prc2 *
892                     (m->w4.scale2 ? PRCLARGE : PRCSMALL);
893                 tp->gps_ranges.sat[n].rrc = m->w5.rrc2 *
894                     (m->w4.scale2 ? RRLARGE : RRSMALL);
895                 n++;
896             }
897             if (len >= 5) {
898                 tp->gps_ranges.sat[n].ident = m->w6.satident3;
899                 tp->gps_ranges.sat[n].udre = m->w6.udre3;
900                 tp->gps_ranges.sat[n].iod = m->w7.iod3;
901                 tp->gps_ranges.sat[n].prc =
902                     ((m->w6.prc3_h << 8) | (m->w7.prc3_l)) *
903                     (m->w6.scale3 ? PRCLARGE : PRCSMALL);
904                 tp->gps_ranges.sat[n].rrc =
905                     m->w7.rrc3 * (m->w6.scale3 ? RRLARGE : RRSMALL);
906                 n++;
907             }
908             len -= 5;
909             m++;
910         }
911         tp->gps_ranges.nentries = n;
912     }
913         break;
914     case 3:
915     {
916         struct rtcm2_msg3 *m = &msg->msg_type.type3;
917 
918         if ((tp->ecef.valid = len >= 4)) {
919             tp->ecef.x = ((m->w3.x_h << 8) | (m->w4.x_l)) * XYZ_SCALE;
920             tp->ecef.y = ((m->w4.y_h << 16) | (m->w5.y_l)) * XYZ_SCALE;
921             tp->ecef.z = ((m->w5.z_h << 24) | (m->w6.z_l)) * XYZ_SCALE;
922         }
923     }
924         break;
925     case 4:
926         if ((tp->reference.valid = len >= 2)) {
927             struct rtcm2_msg4 *m = &msg->msg_type.type4;
928 
929             tp->reference.system =
930                 (m->w3.dgnss == 0) ? NAVSYSTEM_GPS :
931                 ((m->w3.dgnss == 1) ? NAVSYSTEM_GLONASS : NAVSYSTEM_UNKNOWN);
932             tp->reference.sense =
933                 (m->w3.dat != 0) ? SENSE_GLOBAL : SENSE_LOCAL;
934             if (m->w3.datum_alpha_char1) {
935                 tp->reference.datum[n++] = (char)(m->w3.datum_alpha_char1);
936             }
937             if (m->w3.datum_alpha_char2) {
938                 tp->reference.datum[n++] = (char)(m->w3.datum_alpha_char2);
939             }
940             if (m->w4.datum_sub_div_char1) {
941                 tp->reference.datum[n++] = (char)(m->w4.datum_sub_div_char1);
942             }
943             if (m->w4.datum_sub_div_char2) {
944                 tp->reference.datum[n++] = (char)(m->w4.datum_sub_div_char2);
945             }
946             if (m->w4.datum_sub_div_char3) {
947                 tp->reference.datum[n++] = (char)(m->w4.datum_sub_div_char3);
948             }
949             /* we used to say n++ here, but scan-build complains */
950             tp->reference.datum[n] = '\0';
951             if (len >= 4) {
952                 tp->reference.dx = m->w5.dx * DXYZ_SCALE;
953                 tp->reference.dy =
954                     ((m->w5.dy_h << 8) | m->w6.dy_l) * DXYZ_SCALE;
955                 tp->reference.dz = m->w6.dz * DXYZ_SCALE;
956             } else
957                 tp->reference.sense = SENSE_INVALID;
958         }
959         break;
960     case 5:
961         for (n = 0; n < (unsigned)len; n++) {
962             struct consat_t *csp = &tp->conhealth.sat[n];
963             struct b_health_t *m = &msg->msg_type.type5.health[n];
964 
965             csp->ident = m->sat_id;
966             csp->iodl = m->issue_of_data_link != 0;
967             csp->health = m->data_health;
968             csp->snr = (int)(m->cn0 ? (m->cn0 + CNR_OFFSET) : SNR_BAD);
969             csp->health_en = m->health_enable != 0;
970             csp->new_data = m->new_nav_data != 0;
971             csp->los_warning = m->loss_warn != 0;
972             csp->tou = m->time_unhealthy * TU_SCALE;
973         }
974         tp->conhealth.nentries = n;
975         break;
976     case 7:
977         for (w = 0; w < (unsigned)len; w++) {
978             struct station_t *np = &tp->almanac.station[n];
979             struct b_station_t *mp = &msg->msg_type.type7.almanac[w];
980 
981             np->latitude = mp->w3.lat * LA_SCALE;
982             np->longitude = ((mp->w3.lon_h << 8) | mp->w4.lon_l) * LO_SCALE;
983             np->range = mp->w4.range;
984             np->frequency =
985                 (((mp->w4.freq_h << 6) | mp->w5.freq_l) * FREQ_SCALE) +
986                 FREQ_OFFSET;
987             np->health = mp->w5.health;
988             np->station_id = mp->w5.station_id,
989                 np->bitrate = tx_speed[mp->w5.bit_rate];
990             n++;
991         }
992         tp->almanac.nentries = (unsigned)(len / 3);
993         break;
994     case 13:
995         tp->xmitter.status = (bool)msg->msg_type.type13.w1.status;
996         tp->xmitter.rangeflag = (bool)msg->msg_type.type13.w1.rangeflag;
997         tp->xmitter.lat = msg->msg_type.type13.w1.lat * LATLON_SCALE;
998         tp->xmitter.lon = msg->msg_type.type13.w2.lon * LATLON_SCALE;
999         tp->xmitter.range = msg->msg_type.type13.w2.range * RANGE_SCALE;
1000         if (tp->xmitter.range == 0)
1001             tp->xmitter.range = 1024;
1002         break;
1003     case 14:
1004         tp->gpstime.week = msg->msg_type.type14.w1.week;
1005         tp->gpstime.hour = msg->msg_type.type14.w1.hour;
1006         tp->gpstime.leapsecs = msg->msg_type.type14.w1.leapsecs;
1007         break;
1008     case 16:
1009         for (w = 0; w < (unsigned)len; w++) {
1010             if (!msg->msg_type.type16.txt[w].byte1) {
1011                 break;
1012             }
1013             tp->message[n++] = (char)(msg->msg_type.type16.txt[w].byte1);
1014             if (!msg->msg_type.type16.txt[w].byte2) {
1015                 break;
1016             }
1017             tp->message[n++] = (char)(msg->msg_type.type16.txt[w].byte2);
1018             if (!msg->msg_type.type16.txt[w].byte3) {
1019                 break;
1020             }
1021             tp->message[n++] = (char)(msg->msg_type.type16.txt[w].byte3);
1022         }
1023         tp->message[n] = '\0';
1024         break;
1025 
1026     case 31:
1027     {
1028         struct glonass_correction_t *m = &msg->msg_type.type31.corrections[0];
1029 
1030         while (len >= 0) {
1031             if (len >= 2) {
1032                 tp->glonass_ranges.sat[n].ident = m->w3.satident1;
1033                 tp->glonass_ranges.sat[n].udre = m->w3.udre1;
1034                 tp->glonass_ranges.sat[n].change = (bool)m->w4.change1;
1035                 tp->glonass_ranges.sat[n].tod = m->w4.tod1;
1036                 tp->glonass_ranges.sat[n].prc = m->w3.prc1 *
1037                     (m->w3.scale1 ? PRCLARGE : PRCSMALL);
1038                 tp->glonass_ranges.sat[n].rrc = m->w4.rrc1 *
1039                     (m->w3.scale1 ? RRLARGE : RRSMALL);
1040                 n++;
1041             }
1042             if (len >= 4) {
1043                 tp->glonass_ranges.sat[n].ident = m->w4.satident2;
1044                 tp->glonass_ranges.sat[n].udre = m->w4.udre2;
1045                 tp->glonass_ranges.sat[n].change = (bool)m->w6.change2;
1046                 tp->glonass_ranges.sat[n].tod = m->w6.tod2;
1047                 tp->glonass_ranges.sat[n].prc = m->w5.prc2 *
1048                     (m->w4.scale2 ? PRCLARGE : PRCSMALL);
1049                 tp->glonass_ranges.sat[n].rrc = m->w5.rrc2 *
1050                     (m->w4.scale2 ? RRLARGE : RRSMALL);
1051                 n++;
1052             }
1053             if (len >= 5) {
1054                 tp->glonass_ranges.sat[n].ident = m->w6.satident3;
1055                 tp->glonass_ranges.sat[n].udre = m->w6.udre3;
1056                 tp->glonass_ranges.sat[n].change = (bool)m->w7.change3;
1057                 tp->glonass_ranges.sat[n].tod = m->w7.tod3;
1058                 tp->glonass_ranges.sat[n].prc =
1059                     ((m->w6.prc3_h << 8) | (m->w7.prc3_l)) *
1060                     (m->w6.scale3 ? PRCLARGE : PRCSMALL);
1061                 tp->glonass_ranges.sat[n].rrc =
1062                     m->w7.rrc3 * (m->w6.scale3 ? RRLARGE : RRSMALL);
1063                 n++;
1064             }
1065             len -= 5;
1066             m++;
1067         }
1068         tp->glonass_ranges.nentries = n;
1069     }
1070         break;
1071 
1072     default:
1073         memcpy(tp->words, msg->msg_type.rtcm2_msgunk,
1074                (RTCM2_WORDS_MAX - 2) * sizeof(isgps30bits_t));
1075         break;
1076     }
1077 }
1078 
preamble_match(isgps30bits_t * w)1079 static bool preamble_match(isgps30bits_t * w)
1080 {
1081     return (((struct rtcm2_msghw1 *)w)->preamble == PREAMBLE_PATTERN);
1082 }
1083 
length_check(struct gps_lexer_t * lexer)1084 static bool length_check(struct gps_lexer_t *lexer)
1085 {
1086     return lexer->isgps.bufindex >= 2
1087         && lexer->isgps.bufindex >=
1088         ((struct rtcm2_msg_t *)lexer->isgps.buf)->w2.frmlen + 2u;
1089 }
1090 
rtcm2_decode(struct gps_lexer_t * lexer,unsigned int c)1091 enum isgpsstat_t rtcm2_decode(struct gps_lexer_t *lexer, unsigned int c)
1092 {
1093     return isgps_decode(lexer,
1094                         preamble_match, length_check, RTCM2_WORDS_MAX, c);
1095 }
1096 
1097 #endif /* RTCM104V2_ENABLE */
1098 
1099 // vim: set expandtab shiftwidth=4
1100