source: ntrip/trunk/BNC/RTCM/RTCM2.cpp@ 219

Last change on this file since 219 was 219, checked in by mervart, 18 years ago

* empty log message *

File size: 25.4 KB
Line 
1//------------------------------------------------------------------------------
2//
3// RTCM2.cpp
4//
5// Purpose:
6//
7// Module for extraction of RTCM2 messages
8//
9// Notes:
10//
11// - The host computer is assumed to use little endian (Intel) byte order
12//
13// Last modified:
14//
15// 2006/09/17 OMO Created
16// 2006/09/19 OMO Fixed getHeader() methods
17// 2006/09/21 OMO Reduced phase ambiguity to 2^23 cycles
18//
19// (c) DLR/GSOC
20//
21//------------------------------------------------------------------------------
22
23#include <cmath>
24#include <fstream>
25#include <iomanip>
26#include <iostream>
27#include <string>
28#include <vector>
29
30#include "RTCM2.h"
31
32#include "../bncutils.h"
33
34using namespace std;
35
36
37// GPS constants
38
39const double c_light = 299792458.0; // Speed of light [m/s]; IAU 1976
40const double f_L1 = 1575.42e6; // L1 frequency [Hz] (10.23MHz*154)
41const double f_L2 = 1227.60e6; // L2 frequency [Hz] (10.23MHz*120)
42
43const double lambda_L1 = c_light/f_L1; // L1 wavelength [m] (0.1903m)
44const double lambda_L2 = c_light/f_L2; // L2 wavelength [m]
45
46//
47// Bits for message availability checks
48//
49
50const int bit_L1rngGPS = 0;
51const int bit_L2rngGPS = 1;
52const int bit_L1cphGPS = 2;
53const int bit_L2cphGPS = 3;
54const int bit_L1rngGLO = 4;
55const int bit_L2rngGLO = 5;
56const int bit_L1cphGLO = 6;
57const int bit_L2cphGLO = 7;
58
59
60//
61// namespace rtcm2
62//
63
64namespace rtcm2 {
65
66
67//------------------------------------------------------------------------------
68//
69// class ThirtyBitWord (implementation)
70//
71// Purpose:
72//
73// Handling of RTCM2 30bit words
74//
75//------------------------------------------------------------------------------
76
77// Constructor
78
79ThirtyBitWord::ThirtyBitWord() : W(0) {
80};
81
82// Clear entire 30-bit word and 2-bit parity from previous word
83
84void ThirtyBitWord::clear() {
85 W = 0;
86};
87
88// Failure indicator for input operations
89
90bool ThirtyBitWord::fail() const {
91 return failure;
92};
93
94// Parity check
95
96bool ThirtyBitWord::validParity() const {
97
98 // Parity stuff
99
100 static const unsigned int PARITY_25 = 0xBB1F3480;
101 static const unsigned int PARITY_26 = 0x5D8F9A40;
102 static const unsigned int PARITY_27 = 0xAEC7CD00;
103 static const unsigned int PARITY_28 = 0x5763E680;
104 static const unsigned int PARITY_29 = 0x6BB1F340;
105 static const unsigned int PARITY_30 = 0x8B7A89C0;
106
107 // Look-up table for parity of eight bit bytes
108 // (parity=0 if the number of 0s and 1s is equal, else parity=1)
109 static unsigned char byteParity[] = {
110 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
111 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
112 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
113 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
114 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
115 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
116 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
117 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
118 };
119
120 // Local variables
121
122 unsigned int t, w, p;
123
124 // The sign of the data is determined by the D30* parity bit
125 // of the previous data word. If D30* is set, invert the data
126 // bits D01..D24 to obtain the d01..d24 (but leave all other
127 // bits untouched).
128
129 w = W;
130 if ( w & 0x40000000 ) w ^= 0x3FFFFFC0;
131
132 // Compute the parity of the sign corrected data bits d01..d24
133 // as described in the ICD-GPS-200
134
135 t = w & PARITY_25;
136 p = ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
137 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
138
139 t = w & PARITY_26;
140 p = (p<<1) |
141 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
142 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
143
144 t = w & PARITY_27;
145 p = (p<<1) |
146 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
147 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
148
149 t = w & PARITY_28;
150 p = (p<<1) |
151 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
152 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
153
154 t = w & PARITY_29;
155 p = (p<<1) |
156 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
157 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
158
159 t = w & PARITY_30;
160 p = (p<<1) |
161 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
162 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
163
164 return ( (W!=0) && ((W &0x3f) == p));
165
166};
167
168
169// Check preamble
170
171bool ThirtyBitWord::isHeader() const {
172
173 const unsigned char Preamble = 0x66;
174
175 unsigned char b = (value()>>22) & 0xFF;
176
177 return ( b==Preamble );
178
179};
180
181
182// Return entire 32-bit (current word and previous parity)
183
184unsigned int ThirtyBitWord::all() const {
185 return W;
186};
187
188
189// Return sign-corrected 30-bit (or zero if parity mismatch)
190
191unsigned int ThirtyBitWord::value() const {
192
193 unsigned int w = W;
194
195 if (validParity()) {
196 // Return data and current parity bits. Invert data bits if D30*
197 // is set and discard old parity bits.
198 if ( w & 0x40000000 ) w ^= 0x3FFFFFC0;
199 return (w & 0x3FFFFFFF);
200 }
201 else {
202 // Error; invalid parity
203 return 0;
204 };
205
206};
207
208
209
210// Append a byte with six data bits
211
212void ThirtyBitWord::append(unsigned char b) {
213
214 // Look up table for swap (left-right) of 6 data bits
215 static const unsigned char
216 swap[] = {
217 0,32,16,48, 8,40,24,56, 4,36,20,52,12,44,28,60,
218 2,34,18,50,10,42,26,58, 6,38,22,54,14,46,30,62,
219 1,33,17,49, 9,41,25,57, 5,37,21,53,13,45,29,61,
220 3,35,19,51,11,43,27,59, 7,39,23,55,15,47,31,63
221 };
222
223 // Bits 7 and 6 (of 0..7) must be "01" for valid data bytes
224 if ( (b & 0x40) != 0x40 ) {
225 failure = true;
226 return;
227 };
228
229 // Swap bits 0..5 to restore proper bit order for 30bit words
230 b = swap[ b & 0x3f];
231
232 // Fill word
233 W = ( (W <<6) | (b & 0x3f) ) ;
234
235};
236
237
238// Get next 30bit word from string
239
240void ThirtyBitWord::get(string& buf) {
241
242 // Check if string is long enough
243
244 if (buf.size()<5) {
245 failure = true;
246 return;
247 };
248
249 // Process 5 bytes and remove them from the input
250
251 for (int i=0; i<5; i++) append(buf[i]);
252 buf.erase(0,5);
253
254 failure = false;
255
256};
257
258// Get next 30bit word from file
259
260void ThirtyBitWord::get(istream& inp) {
261
262 unsigned char b;
263
264 for (int i=0; i<5; i++) {
265 inp >> b;
266 if (inp.fail()) { clear(); return; };
267 append(b);
268 };
269
270 failure = false;
271
272};
273
274// Get next header word from string
275
276void ThirtyBitWord::getHeader(string& buf) {
277
278 unsigned int W_old = W;
279 unsigned int i;
280
281 i=0;
282 while (!isHeader() || i<5 ) {
283 // Check if string is long enough; if not restore old word and exit
284 if (buf.size()-1<i) {
285 W = W_old;
286 failure = true;
287 return;
288 };
289 // Process byte
290 append(buf[i]); i++;
291 };
292
293 // Remove processed bytes from buffer
294
295 buf.erase(0,i);
296
297 failure = false;
298
299};
300
301// Get next header word from file
302
303void ThirtyBitWord::getHeader(istream& inp) {
304
305 unsigned char b;
306 unsigned int i;
307
308 i=0;
309 while ( !isHeader() || i<5 ) {
310 inp >> b;
311 if (inp.fail()) { clear(); return; };
312 append(b); i++;
313 };
314
315 failure = false;
316
317};
318
319
320//------------------------------------------------------------------------------
321//
322// RTCM2packet (class implementation)
323//
324// Purpose:
325//
326// A class for handling RTCM2 data packets
327//
328//------------------------------------------------------------------------------
329
330// Constructor
331
332RTCM2packet::RTCM2packet() {
333 clear();
334};
335
336// Initialization
337
338void RTCM2packet::clear() {
339
340 W.clear();
341
342 H1=0;
343 H2=0;
344
345 DW.resize(0,0);
346
347};
348
349// Complete packet, valid parity
350
351bool RTCM2packet::valid() const {
352
353 // The methods for creating a packet (get,">>") ensure
354 // that a packet has a consistent number of data words
355 // and a valid parity in all header and data words.
356 // Therefore a packet is either empty or valid.
357
358 return (H1!=0);
359
360};
361
362
363//
364// Gets the next packet from the buffer
365//
366
367void RTCM2packet::getPacket(std::string& buf) {
368
369 int n;
370 ThirtyBitWord W_old = W;
371 string buf_old = buf;
372
373 // Try to read a full packet. If the input buffer is too short
374 // clear all data and restore the latest 30-bit word prior to
375 // the getPacket call. The empty header word will indicate
376 // an invalid message, which signals an unsuccessful getPacket()
377 // call.
378
379 W.getHeader(buf);
380 H1 = W.value();
381 if (W.fail()) { clear(); W=W_old; buf=buf_old; return; }
382
383 W.get(buf);
384 H2 = W.value();
385 if (W.fail()) { clear(); W=W_old; buf=buf_old; return; }
386
387 n = nDataWords();
388 DW.resize(n);
389 for (int i=0; i<n; i++) {
390 W.get(buf);
391 DW[i] = W.value();
392 if (W.fail()) { clear(); W=W_old; buf=buf_old; return; }
393 };
394
395 return;
396
397};
398
399
400//
401// Gets the next packet from the input stream
402//
403
404void RTCM2packet::getPacket(std::istream& inp) {
405
406 int n;
407
408 W.getHeader(inp);
409 H1 = W.value();
410 if (W.fail()) { clear(); return; }
411
412 W.get(inp);
413 H2 = W.value();
414 if (W.fail()) { clear(); return; }
415
416 n = nDataWords();
417 DW.resize(n);
418 for (int i=0; i<n; i++) {
419 W.get(inp);
420 DW[i] = W.value();
421 if (W.fail()) { clear(); return; }
422 };
423
424 return;
425
426};
427
428//
429// Input operator
430//
431// Reads an RTCM3 packet from the input stream.
432//
433
434istream& operator >> (istream& is, RTCM2packet& p) {
435
436 p.getPacket(is);
437
438 return is;
439
440};
441
442// Access methods
443
444unsigned int RTCM2packet::header1() const {
445 return H1;
446};
447
448unsigned int RTCM2packet::header2() const {
449 return H2;
450};
451
452unsigned int RTCM2packet::dataWord(int i) const {
453 if ( (unsigned int)i < DW.size() ) {
454 return DW[i];
455 }
456 else {
457 return 0;
458 }
459};
460
461unsigned int RTCM2packet::msgType() const {
462 return ( H1>>16 & 0x003F );
463};
464
465unsigned int RTCM2packet::stationID() const {
466 return ( H1>> 6 & 0x03FF );
467};
468
469unsigned int RTCM2packet::modZCount() const {
470 return ( H2>>17 & 0x01FFF );
471};
472
473unsigned int RTCM2packet::seqNumber() const {
474 return ( H2>>14 & 0x0007 );
475};
476
477unsigned int RTCM2packet::nDataWords() const {
478 return ( H2>> 9 & 0x001F );
479};
480
481unsigned int RTCM2packet::staHealth() const {
482 return ( H2>> 6 & 0x0003 );
483};
484
485
486//
487// Get unsigned bit field
488//
489// Bits are numbered from left (msb) to right (lsb) starting at bit 0
490//
491
492unsigned int RTCM2packet::getUnsignedBits ( unsigned int start,
493 unsigned int n ) const {
494
495 unsigned int iFirst = start/24; // Index of first data word
496 unsigned int iLast = (start+n-1)/24; // Index of last data word
497 unsigned int bitField = 0;
498 unsigned int tmp;
499
500 // Checks
501
502 if (n>32) {
503 cerr << "Error: can't handle >32 bits in RTCM2packet::getUnsignedBits"
504 << endl;
505 exit(-1);
506 };
507
508 if ( 24*DW.size() < start+n-1 ) {
509 cerr << "Error: Packet too short in RTCM2packet::getUnsignedBits" << endl;
510 exit(-1);
511 }
512
513 // Handle initial data word
514 // Get all data bits. Strip parity and unwanted leading bits.
515 // Store result in 24 lsb bits of tmp.
516
517 tmp = (DW[iFirst]>>6) & 0xFFFFFF;
518 tmp = ( ( tmp << start%24) & 0xFFFFFF ) >> start%24 ;
519
520 // Handle central data word
521
522 if ( iFirst<iLast ) {
523 bitField = tmp;
524 for (unsigned int iWord=iFirst+1; iWord<iLast; iWord++) {
525 tmp = (DW[iWord]>>6) & 0xFFFFFF;
526 bitField = (bitField << 24) | tmp;
527 };
528 tmp = (DW[iLast]>>6) & 0xFFFFFF;
529 };
530
531 // Handle last data word
532
533 tmp = tmp >> (23-(start+n-1)%24);
534 bitField = (bitField << ((start+n-1)%24+1)) | tmp;
535
536 // Done
537
538 return bitField;
539
540};
541
542//
543// Get signed bit field
544//
545// Bits are numbered from left (msb) to right (lsb) starting at bit 0
546//
547
548int RTCM2packet::getBits ( unsigned int start,
549 unsigned int n ) const {
550
551
552 // Checks
553
554 if (n>32) {
555 cerr << "Error: can't handle >32 bits in RTCM2packet::getBits"
556 << endl;
557 exit(-1);
558 };
559
560 if ( 24*DW.size() < start+n-1 ) {
561 cerr << "Error: Packet too short in RTCM2packet::getBits" << endl;
562 exit(-1);
563 }
564
565 return ((int)(getUnsignedBits(start,n)<<(32-n))>>(32-n));
566
567};
568
569
570//------------------------------------------------------------------------------
571//
572// RTCM2_03 (class implementation)
573//
574// Purpose:
575//
576// A class for handling RTCM 2 GPS Reference Station Parameters messages
577//
578//------------------------------------------------------------------------------
579
580void RTCM2_03::extract(const RTCM2packet& P) {
581
582 // Check validity and packet type
583
584 validMsg = (P.valid());
585 if (!validMsg) return;
586
587 validMsg = (P.ID()==03);
588 if (!validMsg) return;
589
590 // Antenna reference point coordinates
591
592 x = P.getBits( 0,32)*0.01; // X [m]
593 y = P.getBits(32,32)*0.01; // Y [m]
594 z = P.getBits(64,32)*0.01; // Z [m]
595
596};
597
598//------------------------------------------------------------------------------
599//
600// RTCM2_23 (class implementation)
601//
602// Purpose:
603//
604// A class for handling RTCM 2 Antenna Type Definition messages
605//
606//------------------------------------------------------------------------------
607
608void RTCM2_23::extract(const RTCM2packet& P) {
609
610 int nad, nas;
611
612 // Check validity and packet type
613
614 validMsg = (P.valid());
615 if (!validMsg) return;
616
617 validMsg = (P.ID()==23);
618 if (!validMsg) return;
619
620 // Antenna descriptor
621 antType = "";
622 nad = P.getUnsignedBits(3,5);
623 for (int i=0;i<nad;i++)
624 antType += (char)P.getUnsignedBits(8+i*8,8);
625
626 // Optional antenna serial numbers
627 if (P.getUnsignedBits(2,1)==1) {
628 nas = P.getUnsignedBits(19+8*nad,5);
629 antSN = "";
630 for (int i=0;i<nas;i++)
631 antSN += (char)P.getUnsignedBits(24+8*nas+i*8,8);
632 };
633
634};
635
636
637//------------------------------------------------------------------------------
638//
639// RTCM2_24 (class implementation)
640//
641// Purpose:
642//
643// A class for handling RTCM 2 Reference Station Antenna
644// Reference Point Parameter messages
645//
646//------------------------------------------------------------------------------
647
648void RTCM2_24::extract(const RTCM2packet& P) {
649
650 double dx,dy,dz;
651
652 // Check validity and packet type
653
654 validMsg = (P.valid());
655 if (!validMsg) return;
656
657 validMsg = (P.ID()==24);
658 if (!validMsg) return;
659
660 // System indicator
661
662 isGPS = (P.getUnsignedBits(118,1)==0);
663 isGLONASS = (P.getUnsignedBits(118,1)==1);
664
665 // Antenna reference point coordinates
666
667 x = 64.0*P.getBits( 0,32);
668 y = 64.0*P.getBits(40,32);
669 z = 64.0*P.getBits(80,32);
670 dx = P.getUnsignedBits( 32,6);
671 dy = P.getUnsignedBits( 72,6);
672 dz = P.getUnsignedBits(112,6);
673 x = 0.0001*( x + (x<0? -dx:+dx) );
674 y = 0.0001*( y + (y<0? -dy:+dy) );
675 z = 0.0001*( z + (z<0? -dz:+dz) );
676
677 // Antenna Height
678
679 if (P.getUnsignedBits(119,1)==1) {
680 h= P.getUnsignedBits(120,18)*0.0001;
681 };
682
683
684};
685
686
687//------------------------------------------------------------------------------
688//
689// RTCM2_Obs (class definition)
690//
691// Purpose:
692//
693// A class for handling blocks of RTCM2 18 & 19 packets that need to be
694// combined to get a complete set of measurements
695//
696// Notes:
697//
698// The class collects L1/L2 code and phase measurements for GPS and GLONASS.
699// Since the Multiple Message Indicator is inconsistently handled by various
700// receivers we simply require code and phase on L1 and L2 for a complete
701// set ob observations at a given epoch. GLONASS observations are optional,
702// but all four types (code+phase,L1+L2) must be provided, if at least one
703// is given. Also, the GLONASS message must follow the corresponding GPS
704// message.
705//
706//------------------------------------------------------------------------------
707
708// Constructor
709
710RTCM2_Obs::RTCM2_Obs() {
711
712 clear();
713
714};
715
716// Reset entire block
717
718void RTCM2_Obs::clear() {
719
720 secs=0.0; // Seconds of hour (GPS time)
721 nSat=0; // Number of space vehicles
722 PRN.resize(0); // Pseudorange [m]
723 rng_C1.resize(0); // Pseudorange [m]
724 rng_P1.resize(0); // Pseudorange [m]
725 rng_P2.resize(0); // Pseudorange [m]
726 cph_L1.resize(0); // Carrier phase [m]
727 cph_L2.resize(0); // Carrier phase [m]
728
729 availability.reset(); // Message status flags
730 pendingMsg = true; // Multiple message indicator
731
732};
733
734// Availability checks
735
736bool RTCM2_Obs::anyGPS() {
737
738 return availability.test(bit_L1rngGPS) ||
739 availability.test(bit_L2rngGPS) ||
740 availability.test(bit_L1cphGPS) ||
741 availability.test(bit_L2cphGPS);
742
743};
744
745bool RTCM2_Obs::anyGLONASS() {
746
747 return availability.test(bit_L1rngGLO) ||
748 availability.test(bit_L2rngGLO) ||
749 availability.test(bit_L1cphGLO) ||
750 availability.test(bit_L2cphGLO);
751
752};
753
754bool RTCM2_Obs::allGPS() {
755
756 return availability.test(bit_L1rngGPS) &&
757 availability.test(bit_L2rngGPS) &&
758 availability.test(bit_L1cphGPS) &&
759 availability.test(bit_L2cphGPS);
760
761};
762
763bool RTCM2_Obs::allGLONASS() {
764
765 return availability.test(bit_L1rngGLO) &&
766 availability.test(bit_L2rngGLO) &&
767 availability.test(bit_L1cphGLO) &&
768 availability.test(bit_L2cphGLO);
769
770};
771
772// Validity
773
774bool RTCM2_Obs::valid() {
775
776 return ( allGPS() && (allGLONASS() || !anyGLONASS()) && !pendingMsg );
777
778};
779
780
781//
782// Extract RTCM2 18 & 19 messages and store relevant data for future use
783//
784
785void RTCM2_Obs::extract(const RTCM2packet& P) {
786
787 bool isGPS,isCAcode,isL1,isOth;
788 int NSat,idx;
789 int sid,prn;
790 double t,rng,cph;
791
792 // Check validity and packet type
793
794 if (!P.valid()) return;
795
796 // Clear previous data if block was already complete
797
798 if (valid()) clear();
799
800 // Process carrier phase message
801
802 if ( P.ID()==18 ) {
803
804 // Number of satellites in current message
805 NSat = (P.nDataWords()-1)/2;
806
807 // Current epoch (mod 3600 sec)
808 t = 0.6*P.modZCount()
809 + P.getUnsignedBits(4,20)*1.0e-6;
810
811 // Frequency (exit if neither L1 nor L2)
812 isL1 = ( P.getUnsignedBits(0,1)==0 );
813 isOth = ( P.getUnsignedBits(1,1)==1 );
814 if (isOth) return;
815
816 // Constellation (for first satellite in message)
817 isGPS = ( P.getUnsignedBits(26,1)==0 );
818
819 // Multiple Message Indicator (only checked for first satellite)
820 pendingMsg = ( P.getUnsignedBits(24,1)==1 );
821
822 // Handle epoch: store epoch of first GPS message and
823 // check consistency of subsequent messages. GLONASS time tags
824 // are different and have to be ignored
825 if (isGPS) {
826 if ( nSat==0 ) {
827 secs = t; // Store epoch
828 }
829 else if (t!=secs) {
830 clear(); secs = t; // Clear all data, then store epoch
831 };
832 };
833
834 // Discard GLONASS obseravtions if no prior GPS observations
835 // are available
836 if (!isGPS && !anyGPS() ) return;
837
838 // Set availability flags
839
840 if ( isL1 && isGPS) availability.set(bit_L1cphGPS);
841 if (!isL1 && isGPS) availability.set(bit_L2cphGPS);
842 if ( isL1 && !isGPS) availability.set(bit_L1cphGLO);
843 if (!isL1 && !isGPS) availability.set(bit_L2cphGLO);
844
845 // Process all satellites
846
847 for (int iSat=0;iSat<NSat;iSat++){
848
849 // Code type
850 isCAcode = ( P.getUnsignedBits(iSat*48+25,1)==0 );
851
852 // Satellite
853 sid = P.getUnsignedBits(iSat*48+27,5);
854 prn = (isGPS? sid : sid+200 );
855
856 // Carrier phase measurement (mod 2^23 [cy]; sign matched to range)
857 cph = -P.getBits(iSat*48+40,32)/256.0;
858
859 // Is this a new PRN?
860 idx=-1;
861 for (unsigned int i=0;i<PRN.size();i++) {
862 if (PRN[i]==prn) { idx=i; break; };
863 };
864 if (idx==-1) {
865 // Insert new sat at end of list
866 nSat++; idx = nSat-1;
867 PRN.push_back(prn);
868 rng_C1.push_back(0.0);
869 rng_P1.push_back(0.0);
870 rng_P2.push_back(0.0);
871 cph_L1.push_back(0.0);
872 cph_L2.push_back(0.0);
873 };
874
875 // Store measurement
876 if (isL1) {
877 cph_L1[idx] = cph;
878 }
879 else {
880 cph_L2[idx] = cph;
881 };
882
883 };
884
885 };
886
887
888 // Process pseudorange message
889
890 if ( P.ID()==19 ) {
891
892 // Number of satellites in current message
893 NSat = (P.nDataWords()-1)/2;
894
895 // Current epoch (mod 3600 sec)
896 t = 0.6*P.modZCount()
897 + P.getUnsignedBits(4,20)*1.0e-6;
898
899 // Frequency (exit if neither L1 nor L2)
900 isL1 = ( P.getUnsignedBits(0,1)==0 );
901 isOth = ( P.getUnsignedBits(1,1)==1 );
902 if (isOth) return;
903
904 // Constellation (for first satellite in message)
905 isGPS = ( P.getUnsignedBits(26,1)==0 );
906
907 // Multiple Message Indicator (only checked for first satellite)
908 pendingMsg = ( P.getUnsignedBits(24,1)==1 );
909
910 // Handle epoch: store epoch of first GPS message and
911 // check consistency of subsequent messages. GLONASS time tags
912 // are different and have to be ignored
913 if (isGPS) {
914 if ( nSat==0 ) {
915 secs = t; // Store epoch
916 }
917 else if (t!=secs) {
918 clear(); secs = t; // Clear all data, then store epoch
919 };
920 };
921
922 // Discard GLONASS obseravtions if nor prior GPS observations
923 // are available
924 if (!isGPS && !anyGPS() ) return;
925
926 // Set availability flags
927 if ( isL1 && isGPS) availability.set(bit_L1rngGPS);
928 if (!isL1 && isGPS) availability.set(bit_L2rngGPS);
929 if ( isL1 && !isGPS) availability.set(bit_L1rngGLO);
930 if (!isL1 && !isGPS) availability.set(bit_L2rngGLO);
931
932 // Process all satellites
933
934 for (int iSat=0;iSat<NSat;iSat++){
935
936 // Code type
937 isCAcode = ( P.getUnsignedBits(iSat*48+25,1)==0 );
938
939 // Satellite
940 sid = P.getUnsignedBits(iSat*48+27,5);
941 prn = (isGPS? sid : sid+200 );
942
943 // Pseudorange measurement [m]
944 rng = P.getUnsignedBits(iSat*48+40,32)*0.02;
945
946 // Is this a new PRN?
947 idx=-1;
948 for (unsigned int i=0;i<PRN.size();i++) {
949 if (PRN[i]==prn) { idx=i; break; };
950 };
951 if (idx==-1) {
952 // Insert new sat at end of list
953 nSat++; idx = nSat-1;
954 PRN.push_back(prn);
955 rng_C1.push_back(0.0);
956 rng_P1.push_back(0.0);
957 rng_P2.push_back(0.0);
958 cph_L1.push_back(0.0);
959 cph_L2.push_back(0.0);
960 };
961
962 // Store measurement
963 if (isL1) {
964 if (isCAcode) rng_C1[idx] = rng;
965 rng_P1[idx] = rng;
966 }
967 else {
968 rng_P2[idx] = rng;
969 };
970
971 };
972
973 };
974
975};
976
977//
978// Resolution of 2^24 cy carrier phase ambiguity
979// caused by 32-bit data field restrictions
980//
981// Note: the RTCM standard specifies an ambiguity of +/-2^23 cy.
982// However, numerous receivers generate data in the +/-2^22 cy range.
983// A reduced ambiguity of 2^23 cy appears compatible with both cases.
984//
985
986double RTCM2_Obs::resolvedPhase_L1(int i){
987
988//const double ambig = pow(2.0,24); // as per RTCM2 spec
989 const double ambig = pow(2.0,23); // used by many receivers
990
991 double rng;
992 double n;
993
994 if (!valid() || i<0 || i>nSat-1) return 0.0;
995
996 rng = rng_C1[i];
997 if (rng==0.0) return 0.0;
998
999 n = floor( (rng/lambda_L1-cph_L1[i]) / ambig + 0.5 );
1000
1001 return cph_L1[i] + n*ambig;
1002
1003};
1004
1005double RTCM2_Obs::resolvedPhase_L2(int i){
1006
1007//const double ambig = pow(2.0,24); // as per RTCM2 spec
1008 const double ambig = pow(2.0,23); // used by many receivers
1009
1010 double rng;
1011 double n;
1012
1013 if (!valid() || i<0 || i>nSat-1) return 0.0;
1014
1015 rng = rng_C1[i];
1016 if (rng==0.0) return 0.0;
1017
1018 n = floor( (rng/lambda_L2-cph_L2[i]) / ambig + 0.5 );
1019
1020 return cph_L2[i] + n*ambig;
1021
1022};
1023
1024//
1025// Resolution of epoch using reference date (GPS week and secs)
1026//
1027
1028void RTCM2_Obs::resolveEpoch (int refWeek, double refSecs,
1029 int& epochWeek, double& epochSecs ) {
1030
1031 const double secsPerWeek = 604800.0;
1032
1033 epochWeek = refWeek;
1034 epochSecs = secs + 3600.0*(floor((refSecs-secs)/3600.0+0.5));
1035
1036 if (epochSecs<0 ) { epochWeek--; epochSecs+=secsPerWeek; };
1037 if (epochSecs>secsPerWeek) { epochWeek++; epochSecs-=secsPerWeek; };
1038
1039};
1040
1041}; // End of namespace rtcm2
1042
1043// ---------------- begin added by LM --------------------------------------
1044
1045// Constructor
1046////////////////////////////////////////////////////////////////////////////
1047RTCM2::RTCM2() {
1048
1049}
1050
1051// Destructor
1052////////////////////////////////////////////////////////////////////////////
1053RTCM2::~RTCM2() {
1054
1055}
1056
1057//
1058////////////////////////////////////////////////////////////////////////////
1059void RTCM2::Decode(char* buffer, int bufLen) {
1060
1061 _buffer.append(buffer, bufLen);
1062
1063 while(true) {
1064 _PP.getPacket(_buffer);
1065 if (!_PP.valid()) {
1066 return;
1067 }
1068
1069 if ( _PP.ID()==18 || _PP.ID()==19 ) {
1070
1071 _ObsBlock.extract(_PP);
1072
1073 if (_ObsBlock.valid()) {
1074
1075 int refWeek;
1076 double refSecs;
1077 currentGPSWeeks(refWeek, refSecs);
1078 int epochWeek;
1079 double epochSecs;
1080 _ObsBlock.resolveEpoch(refWeek, refSecs, epochWeek, epochSecs);
1081
1082 for (int iSat=0; iSat < _ObsBlock.nSat; iSat++) {
1083 if (_ObsBlock.PRN[iSat] <= 32) {
1084 Observation* obs = new Observation();
1085
1086 obs->SVPRN = _ObsBlock.PRN[iSat];
1087 obs->GPSWeek = epochWeek;
1088 obs->GPSWeeks = int(floor(epochSecs+0.5));
1089 obs->sec = _ObsBlock.secs;
1090 obs->pCodeIndicator = 0;
1091 obs->C1 = _ObsBlock.rng_C1[iSat];
1092 obs->P2 = _ObsBlock.rng_P2[iSat];
1093 obs->L1 = _ObsBlock.resolvedPhase_L1(iSat);
1094 obs->L2 = _ObsBlock.resolvedPhase_L2(iSat);
1095
1096 m_lObsList.push_back(obs);
1097 }
1098 }
1099 _ObsBlock.clear();
1100 }
1101 }
1102 }
1103}
1104
1105// ----------------- end added by LM ---------------------------------------
Note: See TracBrowser for help on using the repository browser.