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

Last change on this file since 1132 was 1130, checked in by weber, 16 years ago

* empty log message *

File size: 12.7 KB
RevLine 
[297]1// Part of BNC, a utility for retrieving decoding and
[464]2// converting GNSS data streams from NTRIP broadcasters.
[297]3//
[464]4// Copyright (C) 2007
[297]5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
[464]7// Czech Technical University Prague, Department of Geodesy
[297]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.
[296]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>
[585]43#include <string.h>
[296]44
45#include "RTCM3Decoder.h"
[880]46#include "RTCM3coDecoder.h"
[296]47#include "bncconst.h"
[511]48#include "bncapp.h"
[1035]49#include "bncutils.h" /* Weber, for latencies */
[296]50
51using namespace std;
52
53#ifndef isinf
54# define isinf(x) 0
55#endif
56
[320]57// Error Handling
58////////////////////////////////////////////////////////////////////////////
[504]59void RTCM3Error(const char*, ...) {
[505]60}
[320]61
[296]62// Constructor
63////////////////////////////////////////////////////////////////////////////
[970]64RTCM3Decoder::RTCM3Decoder(const QString& staID) : GPSDecoder() {
[505]65
66 const int LEAPSECONDS = 14; /* only needed for approx. time */
67
[1033]68 QSettings settings;
69 _checkMountPoint = settings.value("messTypes").toString();
[1022]70 _staID = staID;
71
[1095]72 // Latency
73 _numLat = 0;
74 _minLat = 1000.;
75 _maxLat = -1000.;
76 _sumLat = 0.;
77 _sumLatQ = 0.;
78 _followSec = false;
79 _meanDiff = 0.;
80 _diffSecGPS= 0.;
81 _numGaps = 0;
82 _oldSecGPS = 0.;
83 _newSecGPS = 0.;
84 _curLat = 0.;
85 _perfIntr = 86400;
86 if ( settings.value("perfIntr").toString().isEmpty() ) { _perfIntr = 0; }
87 if ( settings.value("perfIntr").toString().indexOf("1 min") != -1 ) { _perfIntr = 60; }
88 if ( settings.value("perfIntr").toString().indexOf("5 min") != -1 ) { _perfIntr = 300; }
89 if ( settings.value("perfIntr").toString().indexOf("15 min") != -1 ) { _perfIntr = 900; }
90 if ( settings.value("perfIntr").toString().indexOf("1 hour") != -1 ) { _perfIntr = 3600; }
91 if ( settings.value("perfIntr").toString().indexOf("6 hours") != -1 ) { _perfIntr = 21600; }
92 if ( settings.value("perfIntr").toString().indexOf("1 day") != -1 ) { _perfIntr = 86400; }
93
[1022]94 // Ensure, that the Decoder uses the "old" convention for the data structure for Rinex2. Perlt
[689]95 _Parser.rinex3 = 0;
96
[296]97 time_t tim;
98 tim = time(0) - ((10*365+2+5)*24*60*60 + LEAPSECONDS);
[505]99
100 memset(&_Parser, 0, sizeof(_Parser));
[296]101 _Parser.GPSWeek = tim/(7*24*60*60);
102 _Parser.GPSTOW = tim%(7*24*60*60);
[880]103
[939]104 connect(this, SIGNAL(newGPSEph(gpsephemeris*)),
105 (bncApp*) qApp, SLOT(slotNewGPSEph(gpsephemeris*)));
106 connect(this, SIGNAL(newGlonassEph(glonassephemeris*)),
107 (bncApp*) qApp, SLOT(slotNewGlonassEph(glonassephemeris*)));
108
[880]109 // Sub-Decoder for Clock and Orbit Corrections
110 // -------------------------------------------
[970]111 _coDecoder = new RTCM3coDecoder(staID);
[1021]112
113 // Mode can be either observations or corrections
114 // ----------------------------------------------
115 _mode = unknown;
[296]116}
117
118// Destructor
119////////////////////////////////////////////////////////////////////////////
120RTCM3Decoder::~RTCM3Decoder() {
[880]121 delete _coDecoder;
[296]122}
123
124//
125////////////////////////////////////////////////////////////////////////////
[649]126t_irc RTCM3Decoder::Decode(char* buffer, int bufLen) {
[508]127
[913]128 bool decoded = false;
129
[880]130 // Try to decode Clock and Orbit Corrections
131 // -----------------------------------------
[1021]132 if (_mode == unknown || _mode == corrections) {
133 if ( _coDecoder->Decode(buffer, bufLen) == success ) {
134 decoded = true;
[1035]135
[1095]136 // Latency
[1035]137 // -------
[1095]138 if (_perfIntr>0) {
[1035]139 if (0<_coDecoder->_epochList.size()) {
140 for (int ii=0;ii<_coDecoder->_epochList.size();ii++) {
141 int week;
142 double sec;
[1095]143 _newSecGPS = _coDecoder->_epochList[ii];
[1035]144 leapsecGPSWeeks(week, sec);
[1095]145 double dt = fabs(sec - _newSecGPS);
[1035]146 const double secPerWeek = 7.0 * 24.0 * 3600.0;
147 if (dt > 0.5 * secPerWeek) {
[1095]148 if (sec > _newSecGPS) {
[1035]149 sec -= secPerWeek;
150 } else {
151 sec += secPerWeek;
152 }
153 }
[1095]154 if (_newSecGPS != _oldSecGPS) {
155 if (int(_newSecGPS) % _perfIntr < int(_oldSecGPS) % _perfIntr) {
156 if (_numLat>0) {
157 QString late;
158 if (_meanDiff>0.) {
159 late = QString(": Mean latency %1 sec, min %2, max %3, rms %4, %5 epochs, %6 gaps")
160 .arg(int(_sumLat/_numLat*100)/100.)
161 .arg(int(_minLat*100)/100.)
162 .arg(int(_maxLat*100)/100.)
163 .arg(int((sqrt((_sumLatQ - _sumLat * _sumLat / _numLat)/_numLat))*100)/100.)
164 .arg(_numLat)
165 .arg(_numGaps);
166 emit(newMessage(QString(_staID + late ).toAscii() ) );
167 } else {
168 late = QString(": Mean latency %1 sec, min %2, max %3, rms %4, %5 epochs")
169 .arg(int(_sumLat/_numLat*100)/100.)
170 .arg(int(_minLat*100)/100.)
171 .arg(int(_maxLat*100)/100.)
172 .arg(int((sqrt((_sumLatQ - _sumLat * _sumLat / _numLat)/_numLat))*100)/100.)
173 .arg(_numLat);
174 emit(newMessage(QString(_staID + late ).toAscii() ) );
175 }
176 }
177 _meanDiff = int(_diffSecGPS)/_numLat;
178 _diffSecGPS = 0.;
179 _numGaps = 0;
180 _sumLat = 0.;
181 _sumLatQ = 0.;
182 _numLat = 0;
183 _minLat = 1000.;
184 _maxLat = -1000.;
185 }
186 if (_followSec) {
187 _diffSecGPS += _newSecGPS - _oldSecGPS;
188 if (_meanDiff>0.) {
189 if (_newSecGPS - _oldSecGPS > 1.5 * _meanDiff) {
190 _numGaps += 1;
191 }
192 }
193 }
194 _curLat = sec - _newSecGPS;
195 _sumLat += _curLat;
196 _sumLatQ += _curLat * _curLat;
197 if (_curLat < _minLat) {_minLat = _curLat;}
198 if (_curLat >= _maxLat) {_maxLat = _curLat;}
199 _numLat += 1;
200 _oldSecGPS = _newSecGPS;
201 _followSec = true;
[1035]202 }
203 }
204 }
205 }
206 _coDecoder->_epochList.clear();
207
[1021]208 if (_mode == unknown) {
209 _mode = corrections;
210 }
211 }
[913]212 }
[880]213
214 // Remaining part decodes the Observations
215 // ---------------------------------------
[1033]216 if (_mode == unknown || _mode == observations || _checkMountPoint == _staID || _checkMountPoint == "ALL") {
[1127]217
[1021]218 for (int ii = 0; ii < bufLen; ii++) {
219 _Parser.Message[_Parser.MessageSize++] = buffer[ii];
[1127]220
[1021]221 if (_Parser.MessageSize >= _Parser.NeedBytes) {
222
[1030]223 // RTCM message types
224 // ------------------
[1127]225 for (int kk = 0; kk < _Parser.typeSize; kk++) {
226 _typeList.push_back(_Parser.typeList[kk]);
227 }
228 _Parser.typeSize = 0;
[1130]229
230 // Antenna XYZ-H
231 // -------------
232 for (int kk = 0; kk < _Parser.antSize; kk += 4) {
233 _antList.push_back(_Parser.antList[kk + 0]);
234 _antList.push_back(_Parser.antList[kk + 1]);
235 _antList.push_back(_Parser.antList[kk + 2]);
236 _antList.push_back(_Parser.antList[kk + 3]);
237 }
238 _Parser.antSize = 0;
[1021]239
[1033]240 while(int rr = RTCM3Parser(&_Parser)) {
241
[1021]242 // GNSS Observations
243 // -----------------
244 if (rr == 1 || rr == 2) {
[1127]245 decoded = true;
[1021]246
247 if (!_Parser.init) {
248 HandleHeader(&_Parser);
249 _Parser.init = 1;
250 }
251
252 if (rr == 2) {
[1033]253 emit(newMessage( (_staID + ": No valid RINEX! All values are modulo 299792.458!").toAscii() ));
[1021]254 }
255
256 for (int ii = 0; ii < _Parser.Data.numsats; ii++) {
257 p_obs obs = new t_obs();
258 _obsList.push_back(obs);
259 if (_Parser.Data.satellites[ii] <= PRN_GPS_END) {
260 obs->_o.satSys = 'G';
261 obs->_o.satNum = _Parser.Data.satellites[ii];
[366]262 }
[1021]263 else if (_Parser.Data.satellites[ii] <= PRN_GLONASS_END) {
264 obs->_o.satSys = 'R';
265 obs->_o.satNum = _Parser.Data.satellites[ii] - PRN_GLONASS_START + 1;
266 }
[511]267 else {
[1021]268 obs->_o.satSys = 'S';
269 obs->_o.satNum = _Parser.Data.satellites[ii] - PRN_WAAS_START + 20;
270 }
271 obs->_o.GPSWeek = _Parser.Data.week;
272 obs->_o.GPSWeeks = _Parser.Data.timeofweek / 1000.0;
273
274 for (int jj = 0; jj < _Parser.numdatatypesGPS; jj++) {
275 int v = 0;
276 // sepearated declaration and initalization of df and pos. Perlt
277 int df;
278 int pos;
279 df = _Parser.dataflag[jj];
280 pos = _Parser.datapos[jj];
[511]281 if ( (_Parser.Data.dataflags[ii] & df)
282 && !isnan(_Parser.Data.measdata[ii][pos])
283 && !isinf(_Parser.Data.measdata[ii][pos])) {
[1021]284 v = 1;
[511]285 }
[1021]286 else {
287 df = _Parser.dataflagGPS[jj];
288 pos = _Parser.dataposGPS[jj];
289 if ( (_Parser.Data.dataflags[ii] & df)
290 && !isnan(_Parser.Data.measdata[ii][pos])
291 && !isinf(_Parser.Data.measdata[ii][pos])) {
[1126]292 v = 1;
[1021]293 }
[627]294 }
[1021]295 if (!v) {
296 continue;
[627]297 }
[1021]298 else
299 {
[1126]300 int isat = (_Parser.Data.satellites[ii] < 120
301 ? _Parser.Data.satellites[ii]
302 : _Parser.Data.satellites[ii] - 80);
303
[1021]304 // variables df and pos are used consequently. Perlt
305 if (df & GNSSDF_C1DATA) {
306 obs->_o.C1 = _Parser.Data.measdata[ii][pos];
307 }
308 else if (df & GNSSDF_C2DATA) {
309 obs->_o.C2 = _Parser.Data.measdata[ii][pos];
310 }
311 else if (df & GNSSDF_P1DATA) {
312 obs->_o.P1 = _Parser.Data.measdata[ii][pos];
313 }
314 else if (df & GNSSDF_P2DATA) {
315 obs->_o.P2 = _Parser.Data.measdata[ii][pos];
316 }
317 else if (df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA)) {
[1044]318 obs->_o.L1 = _Parser.Data.measdata[ii][pos];
319 obs->_o.SNR1 = _Parser.Data.snrL1[ii];
[1126]320 obs->_o.lock_timei_L1 = _Parser.lastlockl1[isat];
[1021]321 }
322 else if (df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA)) {
[1044]323 obs->_o.L2 = _Parser.Data.measdata[ii][pos];
324 obs->_o.SNR2 = _Parser.Data.snrL2[ii];
[1126]325 obs->_o.lock_timei_L2 = _Parser.lastlockl2[isat];
[1021]326 }
327 else if (df & (GNSSDF_S1CDATA|GNSSDF_S1PDATA)) {
328 obs->_o.S1 = _Parser.Data.measdata[ii][pos];
329 }
330 else if (df & (GNSSDF_S2CDATA|GNSSDF_S2PDATA)) {
331 obs->_o.S2 = _Parser.Data.measdata[ii][pos];
332 }
[627]333 }
[511]334 }
[366]335 }
[296]336 }
[1021]337
338 // GPS Ephemeris
339 // -------------
340 else if (rr == 1019) {
341 decoded = true;
342 gpsephemeris* ep = new gpsephemeris(_Parser.ephemerisGPS);
343 emit newGPSEph(ep);
344 }
345
346 // GLONASS Ephemeris
347 // -----------------
348 else if (rr == 1020) {
349 decoded = true;
350 glonassephemeris* ep = new glonassephemeris(_Parser.ephemerisGLONASS);
351 emit newGlonassEph(ep);
352 }
[296]353 }
354 }
355 }
[1021]356 if (_mode == unknown && decoded) {
357 _mode = observations;
358 }
[296]359 }
[1021]360
361 if (decoded) {
362 return success;
[658]363 }
364 else {
[1021]365 return failure;
[658]366 }
[296]367}
Note: See TracBrowser for help on using the repository browser.