source: ntrip/trunk/BNC/src/RTCM3/RTCM3coDecoder.cpp@ 6467

Last change on this file since 6467 was 6467, checked in by mervart, 9 years ago
File size: 12.2 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: RTCM3coDecoder
30 *
31 * Purpose: RTCM3 Clock Orbit Decoder
32 *
33 * Author: L. Mervart
34 *
35 * Created: 05-May-2008
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <stdio.h>
42#include <math.h>
43
44#include "RTCM3coDecoder.h"
45#include "bncutils.h"
46#include "bncrinex.h"
47#include "bnccore.h"
48#include "bncsettings.h"
49#include "rtcm3torinex.h"
50#include "bnctime.h"
51
52using namespace std;
53
54// Constructor
55////////////////////////////////////////////////////////////////////////////
56RTCM3coDecoder::RTCM3coDecoder(const QString& staID) {
57
58 _staID = staID;
59
60 // File Output
61 // -----------
62 bncSettings settings;
63 QString path = settings.value("corrPath").toString();
64 if (!path.isEmpty()) {
65 expandEnvVar(path);
66 if ( path.length() > 0 && path[path.length()-1] != QDir::separator() ) {
67 path += QDir::separator();
68 }
69 _fileNameSkl = path + staID;
70 }
71 _out = 0;
72
73 qRegisterMetaType<bncTime>("bncTime");
74 qRegisterMetaType< QList<t_orbCorr> >("QList<t_orbCorr>");
75 qRegisterMetaType< QList<t_clkCorr> >("QList<t_clkCorr>");
76
77 connect(this, SIGNAL(newOrbCorrections(QList<t_orbCorr>)),
78 BNC_CORE, SLOT(slotNewOrbCorrections(QList<t_orbCorr>)));
79
80 connect(this, SIGNAL(newClkCorrections(QList<t_clkCorr>)),
81 BNC_CORE, SLOT(slotNewClkCorrections(QList<t_clkCorr>)));
82
83 connect(this, SIGNAL(providerIDChanged(QString)),
84 BNC_CORE, SIGNAL(providerIDChanged(QString)));
85
86 connect(this, SIGNAL(newMessage(QByteArray,bool)),
87 BNC_CORE, SLOT(slotMessage(const QByteArray,bool)));
88
89 reset();
90
91 _providerID[0] = -1;
92 _providerID[1] = -1;
93 _providerID[2] = -1;
94}
95
96// Destructor
97////////////////////////////////////////////////////////////////////////////
98RTCM3coDecoder::~RTCM3coDecoder() {
99 delete _out;
100}
101
102//
103////////////////////////////////////////////////////////////////////////////
104void RTCM3coDecoder::reset() {
105 memset(&_clkOrb, 0, sizeof(_clkOrb));
106 memset(&_codeBias, 0, sizeof(_codeBias));
107 memset(&_phaseBias, 0, sizeof(_phaseBias));
108 memset(&_vTEC, 0, sizeof(_vTEC));
109}
110
111// Reopen Output File
112////////////////////////////////////////////////////////////////////////
113void RTCM3coDecoder::reopen() {
114
115 if (!_fileNameSkl.isEmpty()) {
116
117 bncSettings settings;
118
119 QDateTime datTim = currentDateAndTimeGPS();
120
121 QString hlpStr = bncRinex::nextEpochStr(datTim,
122 settings.value("corrIntr").toString());
123
124 QString fileNameHlp = _fileNameSkl
125 + QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0'))
126 + hlpStr + datTim.toString(".yyC");
127
128 if (_fileName == fileNameHlp) {
129 return;
130 }
131 else {
132 _fileName = fileNameHlp;
133 }
134
135 delete _out;
136 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked) {
137 _out = new ofstream( _fileName.toAscii().data(), ios_base::out | ios_base::app );
138 }
139 else {
140 _out = new ofstream( _fileName.toAscii().data() );
141 }
142 }
143}
144
145//
146////////////////////////////////////////////////////////////////////////////
147t_irc RTCM3coDecoder::Decode(char* buffer, int bufLen, vector<string>& errmsg) {
148
149 errmsg.clear();
150
151 _buffer.append(QByteArray(buffer,bufLen));
152
153 t_irc retCode = failure;
154
155 while(_buffer.size()) {
156
157 struct ClockOrbit clkOrbSav;
158 struct CodeBias codeBiasSav;
159 struct PhaseBias phaseBiasSav;
160 struct VTEC vTECSav;
161 memcpy(&clkOrbSav, &_clkOrb, sizeof(clkOrbSav)); // save state
162 memcpy(&codeBiasSav, &_codeBias, sizeof(codeBiasSav));
163 memcpy(&phaseBiasSav, &_phaseBias, sizeof(phaseBiasSav));
164 memcpy(&vTECSav, &_vTEC, sizeof(vTECSav));
165
166 int bytesused = 0;
167 GCOB_RETURN irc = GetSSR(&_clkOrb, &_codeBias, &_vTEC, &_phaseBias,
168 _buffer.data(), _buffer.size(), &bytesused);
169
170 if (irc <= -30) { // not enough data - restore state and exit loop
171 memcpy(&_clkOrb, &clkOrbSav, sizeof(clkOrbSav));
172 memcpy(&_codeBias, &codeBiasSav, sizeof(codeBiasSav));
173 memcpy(&_phaseBias, &phaseBiasSav, sizeof(phaseBiasSav));
174 memcpy(&_vTEC, &vTECSav, sizeof(vTECSav));
175 break;
176 }
177
178 else if (irc < 0) { // error - skip 1 byte and retry
179 reset();
180 _buffer = _buffer.mid(bytesused ? bytesused : 1);
181 }
182
183 else { // OK or MESSAGEFOLLOWS
184 _buffer = _buffer.mid(bytesused);
185
186 if (irc == GCOBR_OK || irc == GCOBR_MESSAGEFOLLOWS ) {
187
188 setEpochTime(); // sets _lastTime
189
190 if (_lastTime.valid()) {
191 reopen();
192 checkProviderID();
193 sendResults();
194 retCode = success;
195 }
196 else {
197 retCode = failure;
198 }
199
200 reset();
201 }
202 }
203 }
204
205 return retCode;
206}
207
208//
209////////////////////////////////////////////////////////////////////////////
210void RTCM3coDecoder::sendResults() {
211
212 QList<t_orbCorr>& orbCorrections = _orbCorrections[_lastTime];
213 QList<t_clkCorr>& clkCorrections = _clkCorrections[_lastTime];
214
215 // Orbit and clock corrections of all satellites
216 // ---------------------------------------------
217 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS + _clkOrb.NumberOfSat[CLOCKORBIT_SATGLONASS]; ii++) {
218 char sysCh = ' ';
219 if (ii < _clkOrb.NumberOfSat[CLOCKORBIT_SATGPS]) {
220 sysCh = 'G';
221 }
222 else if (ii >= CLOCKORBIT_NUMGPS) {
223 sysCh = 'R';
224 }
225 else {
226 continue;
227 }
228
229 // Orbit correction
230 // ----------------
231 if ( _clkOrb.messageType == COTYPE_GPSCOMBINED ||
232 _clkOrb.messageType == COTYPE_GLONASSCOMBINED ||
233 _clkOrb.messageType == COTYPE_GPSORBIT ||
234 _clkOrb.messageType == COTYPE_GLONASSORBIT ) {
235
236 t_orbCorr orbCorr;
237 orbCorr._prn.set(sysCh, _clkOrb.Sat[ii].ID);
238 orbCorr._staID = _staID.toAscii().data();
239 orbCorr._iod = _clkOrb.Sat[ii].IOD;
240 orbCorr._time = _lastTime;
241 orbCorr._system = 'R';
242 orbCorr._xr[0] = _clkOrb.Sat[ii].Orbit.DeltaRadial;
243 orbCorr._xr[1] = _clkOrb.Sat[ii].Orbit.DeltaAlongTrack;
244 orbCorr._xr[2] = _clkOrb.Sat[ii].Orbit.DeltaCrossTrack;
245 orbCorr._dotXr[0] = _clkOrb.Sat[ii].Orbit.DotDeltaRadial;
246 orbCorr._dotXr[1] = _clkOrb.Sat[ii].Orbit.DotDeltaAlongTrack;
247 orbCorr._dotXr[2] = _clkOrb.Sat[ii].Orbit.DotDeltaCrossTrack;
248
249 orbCorrections.push_back(orbCorr);
250
251 _IODs[orbCorr._prn.toString()] = _clkOrb.Sat[ii].IOD;
252 }
253
254 // Clock Corrections
255 // -----------------
256 if ( _clkOrb.messageType == COTYPE_GPSCOMBINED ||
257 _clkOrb.messageType == COTYPE_GLONASSCOMBINED ||
258 _clkOrb.messageType == COTYPE_GPSCLOCK ||
259 _clkOrb.messageType == COTYPE_GLONASSCLOCK ) {
260
261 t_clkCorr clkCorr;
262 clkCorr._prn.set(sysCh, _clkOrb.Sat[ii].ID);
263 clkCorr._staID = _staID.toAscii().data();
264 clkCorr._time = _lastTime;
265 clkCorr._dClk = _clkOrb.Sat[ii].Clock.DeltaA0 / t_CST::c;
266 clkCorr._dotDClk = _clkOrb.Sat[ii].Clock.DeltaA1 / t_CST::c;
267 clkCorr._dotDotDClk = _clkOrb.Sat[ii].Clock.DeltaA2 / t_CST::c;
268
269 if (_IODs.contains(clkCorr._prn.toString())) {
270 clkCorr._iod = _IODs[clkCorr._prn.toString()];
271 clkCorrections.push_back(clkCorr);
272 }
273 }
274
275 // High-Resolution Clocks
276 // ----------------------
277 if ( _clkOrb.messageType == COTYPE_GPSHR ||
278 _clkOrb.messageType == COTYPE_GLONASSHR ) {
279 }
280 }
281
282 // Code Biases
283 // -----------
284 QList<t_satCodeBias> satCodeBiases;
285 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS + _codeBias.NumberOfSat[CLOCKORBIT_SATGLONASS]; ii++) {
286 char sysCh = ' ';
287 if (ii < _codeBias.NumberOfSat[CLOCKORBIT_SATGPS]) {
288 sysCh = 'G';
289 }
290 else if (ii >= CLOCKORBIT_NUMGPS) {
291 sysCh = 'R';
292 }
293 else {
294 continue;
295 }
296 t_satCodeBias satCodeBias;
297 satCodeBias._prn.set(sysCh, _codeBias.Sat[ii].ID);
298 satCodeBias._time = _lastTime;
299 for (unsigned jj = 0; jj < _codeBias.Sat[ii].NumberOfCodeBiases; jj++) {
300 }
301 }
302
303 // Dump all older epochs
304 // ---------------------
305 QMutableMapIterator<bncTime, QList<t_orbCorr> > itOrb(_orbCorrections);
306 while (itOrb.hasNext()) {
307 itOrb.next();
308 if (itOrb.key() < _lastTime) {
309 emit newOrbCorrections(itOrb.value());
310 t_orbCorr::writeEpoch(_out, itOrb.value());
311 itOrb.remove();
312 }
313 }
314 QMutableMapIterator<bncTime, QList<t_clkCorr> > itClk(_clkCorrections);
315 while (itClk.hasNext()) {
316 itClk.next();
317 if (itClk.key() < _lastTime) {
318 emit newClkCorrections(itClk.value());
319 t_clkCorr::writeEpoch(_out, itClk.value());
320 itClk.remove();
321 }
322 }
323}
324
325//
326////////////////////////////////////////////////////////////////////////////
327void RTCM3coDecoder::checkProviderID() {
328
329 if (_clkOrb.SSRProviderID == 0 && _clkOrb.SSRSolutionID == 0 && _clkOrb.SSRIOD == 0) {
330 return;
331 }
332
333 int newProviderID[3];
334 newProviderID[0] = _clkOrb.SSRProviderID;
335 newProviderID[1] = _clkOrb.SSRSolutionID;
336 newProviderID[2] = _clkOrb.SSRIOD;
337
338 bool alreadySet = false;
339 bool different = false;
340
341 for (unsigned ii = 0; ii < 3; ii++) {
342 if (_providerID[ii] != -1) {
343 alreadySet = true;
344 }
345 if (_providerID[ii] != newProviderID[ii]) {
346 different = true;
347 }
348 _providerID[ii] = newProviderID[ii];
349 }
350
351 if (alreadySet && different) {
352 emit newMessage("RTCM3coDecoder: Provider Changed " + _staID.toAscii() + "\n", true);
353 emit providerIDChanged(_staID);
354 }
355}
356
357
358//
359////////////////////////////////////////////////////////////////////////////
360void RTCM3coDecoder::setEpochTime() {
361
362 _lastTime.reset();
363
364 int epoSecGPS = -1;
365 int epoSecGlo = -1;
366 if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
367 epoSecGPS = _clkOrb.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
368 }
369 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
370 epoSecGPS = _clkOrb.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
371 }
372 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
373 epoSecGlo = _codeBias.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s (86400 for leap second)
374 }
375 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
376 epoSecGlo = _codeBias.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s (86400 for leap second)
377 }
378
379 // Retrieve current time
380 // ---------------------
381 int currentWeek = 0;
382 double currentSec = 0.0;
383 currentGPSWeeks(currentWeek, currentSec);
384 bncTime currentTime(currentWeek, currentSec);
385
386 // Set _lastTime close to currentTime
387 // ----------------------------------
388 if (epoSecGPS != -1) {
389 _lastTime.set(currentWeek, epoSecGPS);
390 while (_lastTime < currentTime - 7 * 86400.0) {
391 _lastTime = _lastTime + 7 * 86400.0;
392 }
393 while (_lastTime > currentTime + 7 * 86400.0) {
394 _lastTime = _lastTime - 7 * 86400.0;
395 }
396 }
397 else if (epoSecGlo != -1) {
398 QDate date = dateAndTimeFromGPSweek(currentTime.gpsw(), currentTime.gpssec()).date();
399 epoSecGlo = epoSecGlo - 3 * 3600 + gnumleap(date.year(), date.month(), date.day());
400 _lastTime.set(currentWeek, epoSecGlo);
401 while (_lastTime < currentTime - 86400.0) {
402 _lastTime = _lastTime + 86400.0;
403 }
404 while (_lastTime > currentTime + 86400.0) {
405 _lastTime = _lastTime - 86400.0;
406 }
407 }
408}
Note: See TracBrowser for help on using the repository browser.