source: ntrip/trunk/BNC/RTCM3/RTCM3Decoder.cpp@ 1218

Last change on this file since 1218 was 1218, checked in by mervart, 15 years ago

Zdenek Lukes:
a) changed logic how the ephemerides are stored for decoding of message 20/21 RTCM 2.3
b) added some debugging output (enabled is macro DEBUG_RTCM2_2021 is defined)

File size: 13.6 KB
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters.
3//
4// Copyright (C) 2007
5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: RTCM3Decoder
30 *
31 * Purpose: RTCM3 Decoder
32 *
33 * Author: L. Mervart
34 *
35 * Created: 24-Aug-2006
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include <math.h>
43#include <string.h>
44
45#include "RTCM3Decoder.h"
46#include "RTCM3coDecoder.h"
47#include "bncconst.h"
48#include "bncapp.h"
49#include "bncutils.h" /* Weber, for latencies */
50
51using namespace std;
52
53#ifndef isinf
54# define isinf(x) 0
55#endif
56
57// Error Handling
58////////////////////////////////////////////////////////////////////////////
59void RTCM3Error(const char*, ...) {
60}
61
62// Constructor
63////////////////////////////////////////////////////////////////////////////
64RTCM3Decoder::RTCM3Decoder(const QString& staID) : GPSDecoder() {
65
66 QSettings settings;
67 _checkMountPoint = settings.value("messTypes").toString();
68 _staID = staID;
69
70 // Latency
71 _numLat = 0;
72 _minLat = 1000.;
73 _maxLat = -1000.;
74 _sumLat = 0.;
75 _sumLatQ = 0.;
76 _followSec = false;
77 _meanDiff = 0.;
78 _diffSecGPS= 0.;
79 _numGaps = 0;
80 _oldSecGPS = 0.;
81 _newSecGPS = 0.;
82 _curLat = 0.;
83 _perfIntr = 86400;
84 if ( settings.value("perfIntr").toString().isEmpty() ) { _perfIntr = 0; }
85 if ( settings.value("perfIntr").toString().indexOf("1 min") != -1 ) { _perfIntr = 60; }
86 if ( settings.value("perfIntr").toString().indexOf("5 min") != -1 ) { _perfIntr = 300; }
87 if ( settings.value("perfIntr").toString().indexOf("15 min") != -1 ) { _perfIntr = 900; }
88 if ( settings.value("perfIntr").toString().indexOf("1 hour") != -1 ) { _perfIntr = 3600; }
89 if ( settings.value("perfIntr").toString().indexOf("6 hours") != -1 ) { _perfIntr = 21600; }
90 if ( settings.value("perfIntr").toString().indexOf("1 day") != -1 ) { _perfIntr = 86400; }
91
92 // Ensure, that the Decoder uses the "old" convention for the data structure for Rinex2. Perlt
93 _Parser.rinex3 = 0;
94
95 memset(&_Parser, 0, sizeof(_Parser));
96
97 double secGPS;
98 currentGPSWeeks(_Parser.GPSWeek, secGPS);
99 _Parser.GPSTOW = int(secGPS);
100
101 connect(this, SIGNAL(newGPSEph(gpsephemeris*)),
102 (bncApp*) qApp, SLOT(slotNewGPSEph(gpsephemeris*)));
103 connect(this, SIGNAL(newGlonassEph(glonassephemeris*)),
104 (bncApp*) qApp, SLOT(slotNewGlonassEph(glonassephemeris*)));
105
106 // Sub-Decoder for Clock and Orbit Corrections
107 // -------------------------------------------
108 _coDecoder = new RTCM3coDecoder(staID);
109
110 // Mode can be either observations or corrections
111 // ----------------------------------------------
112 _mode = unknown;
113}
114
115// Destructor
116////////////////////////////////////////////////////////////////////////////
117RTCM3Decoder::~RTCM3Decoder() {
118 delete _coDecoder;
119}
120
121//
122////////////////////////////////////////////////////////////////////////////
123t_irc RTCM3Decoder::Decode(char* buffer, int bufLen, vector<string>& errmsg) {
124
125 errmsg.clear();
126
127 bool decoded = false;
128
129 // Try to decode Clock and Orbit Corrections
130 // -----------------------------------------
131 if (_mode == unknown || _mode == corrections) {
132 if ( _coDecoder->Decode(buffer, bufLen, errmsg) == success ) {
133 decoded = true;
134
135 // Latency
136 // -------
137 if (_perfIntr>0) {
138 if (0<_coDecoder->_epochList.size()) {
139 for (int ii=0;ii<_coDecoder->_epochList.size();ii++) {
140 int week;
141 double sec;
142 _newSecGPS = _coDecoder->_epochList[ii];
143 currentGPSWeeks(week, sec);
144 double dt = fabs(sec - _newSecGPS);
145 const double secPerWeek = 7.0 * 24.0 * 3600.0;
146 if (dt > 0.5 * secPerWeek) {
147 if (sec > _newSecGPS) {
148 sec -= secPerWeek;
149 } else {
150 sec += secPerWeek;
151 }
152 }
153 if (_newSecGPS != _oldSecGPS) {
154 if (int(_newSecGPS) % _perfIntr < int(_oldSecGPS) % _perfIntr) {
155 if (_numLat>0) {
156 QString late;
157 if (_meanDiff>0.) {
158 late = QString(": Mean latency %1 sec, min %2, max %3, rms %4, %5 epochs, %6 gaps")
159 .arg(int(_sumLat/_numLat*100)/100.)
160 .arg(int(_minLat*100)/100.)
161 .arg(int(_maxLat*100)/100.)
162 .arg(int((sqrt((_sumLatQ - _sumLat * _sumLat / _numLat)/_numLat))*100)/100.)
163 .arg(_numLat)
164 .arg(_numGaps);
165 emit(newMessage(QString(_staID + late ).toAscii() ) );
166 } else {
167 late = QString(": Mean latency %1 sec, min %2, max %3, rms %4, %5 epochs")
168 .arg(int(_sumLat/_numLat*100)/100.)
169 .arg(int(_minLat*100)/100.)
170 .arg(int(_maxLat*100)/100.)
171 .arg(int((sqrt((_sumLatQ - _sumLat * _sumLat / _numLat)/_numLat))*100)/100.)
172 .arg(_numLat);
173 emit(newMessage(QString(_staID + late ).toAscii() ) );
174 }
175 }
176 _meanDiff = int(_diffSecGPS)/_numLat;
177 _diffSecGPS = 0.;
178 _numGaps = 0;
179 _sumLat = 0.;
180 _sumLatQ = 0.;
181 _numLat = 0;
182 _minLat = 1000.;
183 _maxLat = -1000.;
184 }
185 if (_followSec) {
186 _diffSecGPS += _newSecGPS - _oldSecGPS;
187 if (_meanDiff>0.) {
188 if (_newSecGPS - _oldSecGPS > 1.5 * _meanDiff) {
189 _numGaps += 1;
190 }
191 }
192 }
193 _curLat = sec - _newSecGPS;
194 _sumLat += _curLat;
195 _sumLatQ += _curLat * _curLat;
196 if (_curLat < _minLat) {_minLat = _curLat;}
197 if (_curLat >= _maxLat) {_maxLat = _curLat;}
198 _numLat += 1;
199 _oldSecGPS = _newSecGPS;
200 _followSec = true;
201 }
202 }
203 }
204 }
205 _coDecoder->_epochList.clear();
206
207 if (_mode == unknown) {
208 _mode = corrections;
209 }
210 }
211 }
212
213 // Remaining part decodes the Observations
214 // ---------------------------------------
215 if (_mode == unknown || _mode == observations || _checkMountPoint == _staID || _checkMountPoint == "ALL") {
216
217 for (int ii = 0; ii < bufLen; ii++) {
218 _Parser.Message[_Parser.MessageSize++] = buffer[ii];
219
220 if (_Parser.MessageSize >= _Parser.NeedBytes) {
221
222 // RTCMv3 message types
223 // --------------------
224 for (int kk = 0; kk < _Parser.typeSize; kk++) {
225 _typeList.push_back(_Parser.typeList[kk]);
226 }
227 _Parser.typeSize = 0;
228
229 // RTCMv3 antenna descriptor
230 // -------------------------
231 for (int kk = 0; kk < _Parser.antSize; kk++) {
232 _antType.push_back(_Parser.antType[kk]);
233 }
234 _Parser.antSize = 0;
235
236 // RTCMv3 antenna XYZ
237 // ------------------
238 for (int kk = 0; kk < _Parser.antSize5; kk += 3) {
239 _antList5.push_back(_Parser.antList5[kk + 0]);
240 _antList5.push_back(_Parser.antList5[kk + 1]);
241 _antList5.push_back(_Parser.antList5[kk + 2]);
242 }
243 _Parser.antSize5 = 0;
244
245 // RTCMv3 antenna XYZ-H
246 // --------------------
247 for (int kk = 0; kk < _Parser.antSize6; kk += 4) {
248 _antList6.push_back(_Parser.antList6[kk + 0]);
249 _antList6.push_back(_Parser.antList6[kk + 1]);
250 _antList6.push_back(_Parser.antList6[kk + 2]);
251 _antList6.push_back(_Parser.antList6[kk + 3]);
252 }
253 _Parser.antSize6 = 0;
254
255 while(int rr = RTCM3Parser(&_Parser)) {
256
257 // GNSS Observations
258 // -----------------
259 if (rr == 1 || rr == 2) {
260 decoded = true;
261
262 if (!_Parser.init) {
263 HandleHeader(&_Parser);
264 _Parser.init = 1;
265 }
266
267 if (rr == 2) {
268 emit(newMessage( (_staID + ": No valid RINEX! All values are modulo 299792.458!").toAscii() ));
269 }
270
271 for (int ii = 0; ii < _Parser.Data.numsats; ii++) {
272 p_obs obs = new t_obs();
273 _obsList.push_back(obs);
274 if (_Parser.Data.satellites[ii] <= PRN_GPS_END) {
275 obs->_o.satSys = 'G';
276 obs->_o.satNum = _Parser.Data.satellites[ii];
277 }
278 else if (_Parser.Data.satellites[ii] <= PRN_GLONASS_END) {
279 obs->_o.satSys = 'R';
280 obs->_o.satNum = _Parser.Data.satellites[ii] - PRN_GLONASS_START + 1;
281 }
282 else {
283 obs->_o.satSys = 'S';
284 obs->_o.satNum = _Parser.Data.satellites[ii] - PRN_WAAS_START + 20;
285 }
286 obs->_o.GPSWeek = _Parser.Data.week;
287 obs->_o.GPSWeeks = _Parser.Data.timeofweek / 1000.0;
288
289 for (int jj = 0; jj < _Parser.numdatatypesGPS; jj++) {
290 int v = 0;
291 // sepearated declaration and initalization of df and pos. Perlt
292 int df;
293 int pos;
294 df = _Parser.dataflag[jj];
295 pos = _Parser.datapos[jj];
296 if ( (_Parser.Data.dataflags[ii] & df)
297 && !isnan(_Parser.Data.measdata[ii][pos])
298 && !isinf(_Parser.Data.measdata[ii][pos])) {
299 v = 1;
300 }
301 else {
302 df = _Parser.dataflagGPS[jj];
303 pos = _Parser.dataposGPS[jj];
304 if ( (_Parser.Data.dataflags[ii] & df)
305 && !isnan(_Parser.Data.measdata[ii][pos])
306 && !isinf(_Parser.Data.measdata[ii][pos])) {
307 v = 1;
308 }
309 }
310 if (!v) {
311 continue;
312 }
313 else
314 {
315 int isat = (_Parser.Data.satellites[ii] < 120
316 ? _Parser.Data.satellites[ii]
317 : _Parser.Data.satellites[ii] - 80);
318
319 // variables df and pos are used consequently. Perlt
320 if (df & GNSSDF_C1DATA) {
321 obs->_o.C1 = _Parser.Data.measdata[ii][pos];
322 }
323 else if (df & GNSSDF_C2DATA) {
324 obs->_o.C2 = _Parser.Data.measdata[ii][pos];
325 }
326 else if (df & GNSSDF_P1DATA) {
327 obs->_o.P1 = _Parser.Data.measdata[ii][pos];
328 }
329 else if (df & GNSSDF_P2DATA) {
330 obs->_o.P2 = _Parser.Data.measdata[ii][pos];
331 }
332 else if (df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA)) {
333 obs->_o.L1 = _Parser.Data.measdata[ii][pos];
334 obs->_o.SNR1 = _Parser.Data.snrL1[ii];
335 obs->_o.lock_timei_L1 = _Parser.lastlockl1[isat];
336 }
337 else if (df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA)) {
338 obs->_o.L2 = _Parser.Data.measdata[ii][pos];
339 obs->_o.SNR2 = _Parser.Data.snrL2[ii];
340 obs->_o.lock_timei_L2 = _Parser.lastlockl2[isat];
341 }
342 else if (df & (GNSSDF_S1CDATA|GNSSDF_S1PDATA)) {
343 obs->_o.S1 = _Parser.Data.measdata[ii][pos];
344 }
345 else if (df & (GNSSDF_S2CDATA|GNSSDF_S2PDATA)) {
346 obs->_o.S2 = _Parser.Data.measdata[ii][pos];
347 }
348 }
349 }
350 }
351 }
352
353 // GPS Ephemeris
354 // -------------
355 else if (rr == 1019) {
356 decoded = true;
357 gpsephemeris* ep = new gpsephemeris(_Parser.ephemerisGPS);
358
359#ifdef DEBUG_RTCM2_2021
360 QString msg = QString("%1: got eph %2 IODC %3 GPSweek %4 TOC %5 TOE %6")
361 .arg(_staID)
362 .arg(ep->satellite, 2)
363 .arg(ep->IODC, 4)
364 .arg(ep->GPSweek, 4)
365 .arg(ep->TOC, 6)
366 .arg(ep->TOE, 6);
367 emit(newMessage(msg.toAscii()));
368#endif
369
370 emit newGPSEph(ep);
371 }
372
373 // GLONASS Ephemeris
374 // -----------------
375 else if (rr == 1020) {
376 decoded = true;
377 glonassephemeris* ep = new glonassephemeris(_Parser.ephemerisGLONASS);
378 emit newGlonassEph(ep);
379 }
380 }
381 }
382 }
383 if (_mode == unknown && decoded) {
384 _mode = observations;
385 }
386 }
387
388 if (decoded) {
389 return success;
390 }
391 else {
392 return failure;
393 }
394}
Note: See TracBrowser for help on using the repository browser.