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