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

Last change on this file since 11038 was 11038, checked in by stuerze, 2 weeks ago

updates regarding RTCM-SSR and bug fixed in RTCM3coDecoder

File size: 41.1 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://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#include <climits>
44
45#include "RTCM3coDecoder.h"
46#include "bncutils.h"
47#include "bncrinex.h"
48#include "bnccore.h"
49#include "bncsettings.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 connect(this, SIGNAL(newOrbCorrections(QList<t_orbCorr>)),
74 BNC_CORE, SLOT(slotNewOrbCorrections(QList<t_orbCorr>)));
75
76 connect(this, SIGNAL(newClkCorrections(QList<t_clkCorr>)),
77 BNC_CORE, SLOT(slotNewClkCorrections(QList<t_clkCorr>)));
78
79 connect(this, SIGNAL(newCodeBiases(QList<t_satCodeBias>)),
80 BNC_CORE, SLOT(slotNewCodeBiases(QList<t_satCodeBias>)));
81
82 connect(this, SIGNAL(newPhaseBiases(QList<t_satPhaseBias>)),
83 BNC_CORE, SLOT(slotNewPhaseBiases(QList<t_satPhaseBias>)));
84
85 connect(this, SIGNAL(newTec(t_vTec)),
86 BNC_CORE, SLOT(slotNewTec(t_vTec)));
87
88 connect(this, SIGNAL(newMetaData(t_metaData)),
89 BNC_CORE, SLOT(slotNewMetaData(t_metaData)));
90
91 connect(this, SIGNAL(newSatAntennas(QList<t_satAntenna>)),
92 BNC_CORE, SLOT(slotNewSatAntennas(QList<t_satAntenna>)));
93
94 connect(this, SIGNAL(providerIDChanged(QString)),
95 BNC_CORE, SIGNAL(providerIDChanged(QString)));
96
97 connect(this, SIGNAL(newMessage(QByteArray,bool)),
98 BNC_CORE, SLOT(slotMessage(const QByteArray,bool)));
99
100 reset();
101
102 _providerID[0] = -1;
103 _providerID[1] = -1;
104 _providerID[2] = -1;
105
106 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) {
107 _antennaSentIOD[s] = UINT_MAX; // "never sent"
108 }
109
110 _stateSnapshot = new t_stateSnapshot;
111 _ssrCorr = 0;
112
113}
114
115// Destructor
116////////////////////////////////////////////////////////////////////////////
117RTCM3coDecoder::~RTCM3coDecoder() {
118 delete _out;
119 delete _ssrCorr;
120 delete _stateSnapshot;
121 _IODs.clear();
122 _orbCorrections.clear();
123 _clkCorrections.clear();
124 _lastClkCorrections.clear();
125 _codeBiases.clear();
126 _phaseBiases.clear();
127 _vTecMap.clear();
128 _metaDataMap.clear();
129 _satAntennas.clear();
130}
131
132//
133////////////////////////////////////////////////////////////////////////////
134void RTCM3coDecoder::reset(bool resetPhaseBias) {
135 memset(&_clkOrb, 0, sizeof(_clkOrb));
136 memset(&_codeBias, 0, sizeof(_codeBias));
137 if (resetPhaseBias) {
138 memset(&_phaseBias, 0, sizeof(_phaseBias));
139 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) {
140 _phaseBiasSentEpoch[s] = UINT_MAX; // "never sent"
141 }
142 }
143 memset(&_vTEC, 0, sizeof(_vTEC));
144}
145
146// Reopen Output File
147////////////////////////////////////////////////////////////////////////
148void RTCM3coDecoder::reopen() {
149
150 if (!_fileNameSkl.isEmpty()) {
151
152 bncSettings settings;
153
154 QDateTime datTim = currentDateAndTimeGPS();
155
156 QString hlpStr = bncRinex::nextEpochStr(datTim,
157 settings.value("corrIntr").toString(), 3);
158
159 QString cntStr = (_fileNameSkl.contains("ION")) ? "_ION.ssr" : "_MC.ssr";
160
161 QString fileNameHlp = _fileNameSkl +
162 "_S_" + // stream
163 QString("%1").arg(datTim.date().year()) +
164 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) +
165 hlpStr + // HM_period
166 cntStr; // mixed ION or CLK
167
168 if (_fileName == fileNameHlp) {
169 return;
170 }
171 else {
172 _fileName = fileNameHlp;
173 }
174
175 delete _out;
176 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked) {
177 _out = new ofstream( _fileName.toLatin1().data(), ios_base::out | ios_base::app );
178 }
179 else {
180 _out = new ofstream( _fileName.toLatin1().data() );
181 }
182 }
183}
184
185//
186////////////////////////////////////////////////////////////////////////////
187t_irc RTCM3coDecoder::Decode(char* buffer, int bufLen, vector<string>& errmsg) {
188
189 errmsg.clear();
190
191 _buffer.append(QByteArray(buffer,bufLen));
192
193 t_irc retCode = failure;
194
195 while(_buffer.size()) {
196
197 // save state
198 memcpy(&_stateSnapshot->clkOrb, &_clkOrb, sizeof(_clkOrb));
199 memcpy(&_stateSnapshot->codeBias, &_codeBias, sizeof(_codeBias));
200 memcpy(&_stateSnapshot->phaseBias, &_phaseBias, sizeof(_phaseBias));
201 memcpy(&_stateSnapshot->vTEC, &_vTEC, sizeof(_vTEC));
202 memcpy(&_stateSnapshot->metaData, &_metaData, sizeof(_metaData));
203 memcpy(&_stateSnapshot->antenna, &_antenna, sizeof(_antenna));
204
205 int bytesused = 0;
206
207 GCOB_RETURN irc = _ssrCorr->GetSSR(&_clkOrb, &_codeBias, &_vTEC, &_phaseBias, &_metaData, &_antenna,
208 _buffer.data(), _buffer.size(), &bytesused);
209
210 if (irc <= -30) { // not enough data - restore state and exit loop
211 memcpy(&_clkOrb, &_stateSnapshot->clkOrb, sizeof(_clkOrb));
212 memcpy(&_codeBias, &_stateSnapshot->codeBias, sizeof(_codeBias));
213 memcpy(&_phaseBias, &_stateSnapshot->phaseBias, sizeof(_phaseBias));
214 memcpy(&_vTEC, &_stateSnapshot->vTEC, sizeof(_vTEC));
215 memcpy(&_metaData, &_stateSnapshot->metaData, sizeof(_metaData));
216 break;
217 }
218
219 else if (irc < 0) { // error - skip this message (or 1 byte if the
220 // frame itself couldn't be recognized) and retry
221 if (irc != GCOBR_UNKNOWNTYPE) {
222 // A recognized-but-unimplemented message (e.g. Tropospheric or
223 // Regional Ionospheric Correction) leaves _clkOrb/_codeBias/
224 // _phaseBias/_vTEC untouched, and bytesused is already reliably set
225 // from its CRC-validated frame length, so there is nothing to
226 // discard. Every other error code may have left inconsistent
227 // partial state (e.g. mid-satellite-loop) or an unreliable frame
228 // boundary, so reset defensively there. Without this, streams with
229 // frequent unimplemented messages (e.g. dense grid-based Regional
230 // Ionospheric traffic) would wipe unrelated, still-valid orbit/
231 // clock/bias/phase-bias state every time one is skipped.
232 reset();
233 }
234 _buffer = _buffer.mid(bytesused ? bytesused : 1);
235 }
236
237 else { // OK or MESSAGEFOLLOWS
238 _buffer = _buffer.mid(bytesused);
239
240 if (irc == GCOBR_OK || irc == GCOBR_MESSAGEFOLLOWS ) {
241 setEpochTime(); // sets _lastTime
242
243 if (_lastTime.valid()) {
244 reopen();
245 checkProviderID();
246 sendResults();
247 retCode = success;
248 }
249 else {
250 emit newMessage("RTCM3coDecoder: _lastTime invalid: " + _staID.toLatin1(), true);
251 retCode = failure;
252 }
253 // Keep _phaseBias intact: an Extended Phase Bias message (COBOFS_PBEXT)
254 // arriving later needs to correlate against the satellite/signal list
255 // just published by this Phase Bias message. clock_orbit_rtcm_new.cpp's
256 // COBOFS_PBIAS handling resets pb->NumberOfSat[s] itself before decoding
257 // a fresh message, so this doesn't cause stale data to accumulate.
258 reset(false);
259 }
260 }
261 }
262
263 return retCode;
264}
265
266//
267////////////////////////////////////////////////////////////////////////////
268void RTCM3coDecoder::sendResults() {
269
270 // Orbit and clock corrections of all satellites
271 // ---------------------------------------------
272 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS
273 + CLOCKORBIT_NUMGLONASS
274 + CLOCKORBIT_NUMGALILEO
275 + CLOCKORBIT_NUMQZSS
276 + CLOCKORBIT_NUMSBAS
277 + _clkOrb.NumberOfSat[CLOCKORBIT_SATBDS];
278 ii++) {
279 if (corrIsOutOfRange(_clkOrb.Sat[ii])) {
280 continue;
281 }
282 char sys = ' ';
283 int num = _clkOrb.Sat[ii].ID;
284 int flag = 0; // to force NAV type usage according SSR standard
285 if (ii < _clkOrb.NumberOfSat[CLOCKORBIT_SATGPS]) {
286 sys = 'G';
287 flag = t_eph::LNAV;
288 }
289 else if (ii >= CLOCKORBIT_OFFSETGLONASS &&
290 ii < CLOCKORBIT_OFFSETGLONASS + _clkOrb.NumberOfSat[CLOCKORBIT_SATGLONASS]) {
291 sys = 'R';
292 flag = t_eph::FDMA_M;
293 }
294 else if (ii >= CLOCKORBIT_OFFSETGALILEO &&
295 ii < CLOCKORBIT_OFFSETGALILEO + _clkOrb.NumberOfSat[CLOCKORBIT_SATGALILEO]) {
296 sys = 'E';
297 flag = t_eph::INAV;
298 }
299 else if (ii >= CLOCKORBIT_OFFSETQZSS &&
300 ii < CLOCKORBIT_OFFSETQZSS + _clkOrb.NumberOfSat[CLOCKORBIT_SATQZSS]) {
301 sys = 'J';
302 flag = t_eph::LNAV;
303 }
304 else if (ii >= CLOCKORBIT_OFFSETSBAS &&
305 ii < CLOCKORBIT_OFFSETSBAS + _clkOrb.NumberOfSat[CLOCKORBIT_SATSBAS]) {
306 sys = 'S';
307 flag = t_eph::SBASL1;
308 }
309 else if (ii >= CLOCKORBIT_OFFSETBDS &&
310 ii < CLOCKORBIT_OFFSETBDS + _clkOrb.NumberOfSat[CLOCKORBIT_SATBDS]) {
311 sys = 'C';
312 if (num < 6) {// GEO
313 flag = t_eph::D2;
314 }
315 else if (num > 58 && num < 63) { // GEO
316 flag = t_eph::D2;
317 }
318 else {
319 flag = t_eph::D1;
320 }
321 }
322 else {
323 continue;
324 }
325
326 // Orbit correction
327 // ----------------
328 if ( _clkOrb.messageType == _ssrCorr->COTYPE_GPSCOMBINED ||
329 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSCOMBINED ||
330 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOCOMBINED ||
331 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSCOMBINED ||
332 _clkOrb.messageType == _ssrCorr->COTYPE_SBASCOMBINED ||
333 _clkOrb.messageType == _ssrCorr->COTYPE_BDSCOMBINED ||
334 _clkOrb.messageType == _ssrCorr->COTYPE_GPSORBIT ||
335 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSORBIT ||
336 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOORBIT ||
337 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSORBIT ||
338 _clkOrb.messageType == _ssrCorr->COTYPE_SBASORBIT ||
339 _clkOrb.messageType == _ssrCorr->COTYPE_BDSORBIT ) {
340
341 t_orbCorr orbCorr;
342 orbCorr._prn.set(sys, num, flag);
343 orbCorr._staID = _staID.toStdString();
344 orbCorr._iod = _clkOrb.Sat[ii].IOD;
345 orbCorr._time = _lastTime;
346 orbCorr._updateInt = _clkOrb.UpdateInterval;
347 orbCorr._system = sys;
348 orbCorr._xr[0] = _clkOrb.Sat[ii].Orbit.DeltaRadial;
349 orbCorr._xr[1] = _clkOrb.Sat[ii].Orbit.DeltaAlongTrack;
350 orbCorr._xr[2] = _clkOrb.Sat[ii].Orbit.DeltaCrossTrack;
351 orbCorr._dotXr[0] = _clkOrb.Sat[ii].Orbit.DotDeltaRadial;
352 orbCorr._dotXr[1] = _clkOrb.Sat[ii].Orbit.DotDeltaAlongTrack;
353 orbCorr._dotXr[2] = _clkOrb.Sat[ii].Orbit.DotDeltaCrossTrack;
354 orbCorr._ssrFormat = (_type == RTCMssr) ? ssrRtcmOld :
355 (_type == RTCMnewssr) ? ssrRtcmNew : ssrUnknown;
356
357 _orbCorrections[_lastTime].append(orbCorr);
358
359 _IODs[orbCorr._prn] = _clkOrb.Sat[ii].IOD;
360 }
361
362 // Clock Corrections
363 // -----------------
364 if ( _clkOrb.messageType == _ssrCorr->COTYPE_GPSCOMBINED ||
365 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSCOMBINED ||
366 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOCOMBINED ||
367 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSCOMBINED ||
368 _clkOrb.messageType == _ssrCorr->COTYPE_SBASCOMBINED ||
369 _clkOrb.messageType == _ssrCorr->COTYPE_BDSCOMBINED ||
370 _clkOrb.messageType == _ssrCorr->COTYPE_GPSCLOCK ||
371 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSCLOCK ||
372 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOCLOCK ||
373 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSCLOCK ||
374 _clkOrb.messageType == _ssrCorr->COTYPE_SBASCLOCK ||
375 _clkOrb.messageType == _ssrCorr->COTYPE_BDSCLOCK) {
376
377 t_clkCorr clkCorr;
378 clkCorr._prn.set(sys, _clkOrb.Sat[ii].ID, flag);
379 clkCorr._staID = _staID.toStdString();
380 clkCorr._time = _lastTime;
381 clkCorr._updateInt = _clkOrb.UpdateInterval;
382 clkCorr._dClk = _clkOrb.Sat[ii].Clock.DeltaA0 / t_CST::c;
383 clkCorr._dotDClk = _clkOrb.Sat[ii].Clock.DeltaA1 / t_CST::c;
384 clkCorr._dotDotDClk = _clkOrb.Sat[ii].Clock.DeltaA2 / t_CST::c;
385
386 _lastClkCorrections[clkCorr._prn] = clkCorr;
387
388 if (_IODs.contains(clkCorr._prn)) {
389 clkCorr._iod = _IODs[clkCorr._prn];
390 _clkCorrections[_lastTime].append(clkCorr);
391 }
392 }
393
394 // High-Resolution Clocks
395 // ----------------------
396 if ( _clkOrb.messageType == _ssrCorr->COTYPE_GPSHR ||
397 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSHR ||
398 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOHR ||
399 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSHR ||
400 _clkOrb.messageType == _ssrCorr->COTYPE_SBASHR ||
401 _clkOrb.messageType == _ssrCorr->COTYPE_BDSHR) {
402 t_prn prn(sys, _clkOrb.Sat[ii].ID, flag);
403 if (_lastClkCorrections.contains(prn)) {
404 t_clkCorr clkCorr;
405 clkCorr = _lastClkCorrections[prn];
406 clkCorr._time = _lastTime;
407 clkCorr._updateInt = _clkOrb.UpdateInterval;
408 clkCorr._dClk += _clkOrb.Sat[ii].hrclock / t_CST::c;
409 if (_IODs.contains(clkCorr._prn)) {
410 clkCorr._iod = _IODs[clkCorr._prn];
411 _clkCorrections[_lastTime].append(clkCorr);
412 }
413 }
414 }
415 }
416
417 // Code Biases
418 // -----------
419 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS
420 + CLOCKORBIT_NUMGLONASS
421 + CLOCKORBIT_NUMGALILEO
422 + CLOCKORBIT_NUMQZSS
423 + CLOCKORBIT_NUMSBAS
424 + _codeBias.NumberOfSat[CLOCKORBIT_SATBDS];
425 ii++) {
426 char sys = ' ';
427 int num = _codeBias.Sat[ii].ID;
428 int flag = 0;
429 if (ii < _codeBias.NumberOfSat[CLOCKORBIT_SATGPS]) {
430 sys = 'G';
431 flag = t_eph::LNAV;
432 }
433 else if (ii >= CLOCKORBIT_OFFSETGLONASS &&
434 ii < CLOCKORBIT_OFFSETGLONASS + _codeBias.NumberOfSat[CLOCKORBIT_SATGLONASS]) {
435 sys = 'R';
436 flag = t_eph::FDMA_M;
437 }
438 else if (ii >= CLOCKORBIT_OFFSETGALILEO &&
439 ii < CLOCKORBIT_OFFSETGALILEO + _codeBias.NumberOfSat[CLOCKORBIT_SATGALILEO]) {
440 sys = 'E';
441 flag = t_eph::INAV;
442 }
443 else if (ii >= CLOCKORBIT_OFFSETQZSS &&
444 ii < CLOCKORBIT_OFFSETQZSS + _codeBias.NumberOfSat[CLOCKORBIT_SATQZSS]) {
445 sys = 'J';
446 flag = t_eph::LNAV;
447 }
448 else if (ii >= CLOCKORBIT_OFFSETSBAS &&
449 ii < CLOCKORBIT_OFFSETSBAS + _codeBias.NumberOfSat[CLOCKORBIT_SATSBAS]) {
450 sys = 'S';
451 flag = t_eph::SBASL1;
452 }
453 else if (ii >= CLOCKORBIT_OFFSETBDS &&
454 ii < CLOCKORBIT_OFFSETBDS + _codeBias.NumberOfSat[CLOCKORBIT_SATBDS]) {
455 sys = 'C';
456 if (num < 6) {// GEO
457 flag = t_eph::D2;
458 }
459 else if (num > 58 && num < 63) { // GEO
460 flag = t_eph::D2;
461 }
462 else {
463 flag = t_eph::D1;
464 }
465 }
466 else {
467 continue;
468 }
469 t_satCodeBias satCodeBias;
470 satCodeBias._prn.set(sys, num, flag);
471 satCodeBias._staID = _staID.toStdString();
472 satCodeBias._time = _lastTime;
473 satCodeBias._updateInt = _codeBias.UpdateInterval;
474 for (unsigned jj = 0; jj < _codeBias.Sat[ii].NumberOfCodeBiases; jj++) {
475 const SsrCorr::CodeBias::BiasSat::CodeBiasEntry& biasEntry = _codeBias.Sat[ii].Biases[jj];
476 t_frqCodeBias frqCodeBias;
477 frqCodeBias._rnxType2ch.assign(_ssrCorr->codeTypeToRnxType(sys, biasEntry.Type));
478 frqCodeBias._value = biasEntry.Bias;
479 if (!frqCodeBias._rnxType2ch.empty()) {
480 satCodeBias._bias.push_back(frqCodeBias);
481 }
482 }
483 _codeBiases[_lastTime].append(satCodeBias);
484 }
485
486 // Phase Biases
487 // -----------
488 // _phaseBias is no longer wiped between messages (kept alive so a later
489 // Extended Phase Bias message can correlate against it - see
490 // COBOFS_PBEXT), so without this guard the block below would re-append
491 // the same system's satellites into the output on every other message
492 // decoded in between two actual phase-bias messages. Only emit a
493 // system's satellites once per epoch, tracked per system by comparing
494 // against the epoch we last actually sent for it.
495 bool phaseBiasFresh[CLOCKORBIT_SATNUM];
496 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) {
497 phaseBiasFresh[s] = _phaseBias.NumberOfSat[s] > 0 &&
498 _phaseBias.EpochTime[s] != _phaseBiasSentEpoch[s];
499 if (phaseBiasFresh[s]) {
500 _phaseBiasSentEpoch[s] = _phaseBias.EpochTime[s];
501 }
502 }
503 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS
504 + CLOCKORBIT_NUMGLONASS
505 + CLOCKORBIT_NUMGALILEO
506 + CLOCKORBIT_NUMQZSS
507 + CLOCKORBIT_NUMSBAS
508 + _phaseBias.NumberOfSat[CLOCKORBIT_SATBDS];
509 ii++) {
510 char sys = ' ';
511 int num = _phaseBias.Sat[ii].ID;
512 int flag = 0;
513 if (ii < _phaseBias.NumberOfSat[CLOCKORBIT_SATGPS]) {
514 if (!phaseBiasFresh[CLOCKORBIT_SATGPS]) continue;
515 sys = 'G';
516 flag = t_eph::LNAV;
517 }
518 else if (ii >= CLOCKORBIT_OFFSETGLONASS &&
519 ii < CLOCKORBIT_OFFSETGLONASS + _phaseBias.NumberOfSat[CLOCKORBIT_SATGLONASS]) {
520 if (!phaseBiasFresh[CLOCKORBIT_SATGLONASS]) continue;
521 sys = 'R';
522 flag = t_eph::FDMA_M;
523 }
524 else if (ii >= CLOCKORBIT_OFFSETGALILEO &&
525 ii < CLOCKORBIT_OFFSETGALILEO + _phaseBias.NumberOfSat[CLOCKORBIT_SATGALILEO]) {
526 if (!phaseBiasFresh[CLOCKORBIT_SATGALILEO]) continue;
527 sys = 'E';
528 flag = t_eph::INAV;
529 }
530 else if (ii >= CLOCKORBIT_OFFSETQZSS &&
531 ii < CLOCKORBIT_OFFSETQZSS + _phaseBias.NumberOfSat[CLOCKORBIT_SATQZSS]) {
532 if (!phaseBiasFresh[CLOCKORBIT_SATQZSS]) continue;
533 sys = 'J';
534 flag = t_eph::LNAV;
535 }
536 else if (ii >= CLOCKORBIT_OFFSETSBAS &&
537 ii < CLOCKORBIT_OFFSETSBAS + _phaseBias.NumberOfSat[CLOCKORBIT_SATSBAS]) {
538 if (!phaseBiasFresh[CLOCKORBIT_SATSBAS]) continue;
539 sys = 'S';
540 flag = t_eph::SBASL1;
541 }
542 else if (ii >= CLOCKORBIT_OFFSETBDS &&
543 ii < CLOCKORBIT_OFFSETBDS + _phaseBias.NumberOfSat[CLOCKORBIT_SATBDS]) {
544 if (!phaseBiasFresh[CLOCKORBIT_SATBDS]) continue;
545 sys = 'C';
546 if (num < 6) {// GEO
547 flag = t_eph::D2;
548 }
549 else if (num > 58 && num < 63) { // GEO
550 flag = t_eph::D2;
551 }
552 else {
553 flag = t_eph::D1;
554 }
555 }
556 else {
557 continue;
558 }
559 t_satPhaseBias satPhaseBias;
560 satPhaseBias._prn.set(sys, num, flag);
561 satPhaseBias._staID = _staID.toStdString();
562 satPhaseBias._time = _lastTime;
563 satPhaseBias._updateInt = _phaseBias.UpdateInterval;
564 satPhaseBias._ssrFormat = (_type == RTCMssr) ? ssrRtcmOld :
565 (_type == RTCMnewssr) ? ssrRtcmNew : ssrUnknown;
566 if (satPhaseBias._ssrFormat == e_ssrFormat::ssrRtcmNew) {
567 satPhaseBias._satYawInfoInd = _phaseBias.SatelliteYawInformationIndicator;
568 satPhaseBias._extPBPhaseInd = _phaseBias.ExtendedPhaseBiasPropertyID;
569 }
570 else {
571 satPhaseBias._dispBiasConsistInd = _phaseBias.DispersiveBiasConsistencyIndicator;
572 satPhaseBias._MelbWuebConsistInd = _phaseBias.MWConsistencyIndicator;
573 }
574 satPhaseBias._yaw = _phaseBias.Sat[ii].YawAngle;
575 satPhaseBias._yawRate = _phaseBias.Sat[ii].YawRate;
576 for (unsigned jj = 0; jj < _phaseBias.Sat[ii].NumberOfPhaseBiases; jj++) {
577 const SsrCorr::PhaseBias::PhaseBiasSat::PhaseBiasEntry& biasEntry = _phaseBias.Sat[ii].Biases[jj];
578 t_frqPhaseBias frqPhaseBias;
579 frqPhaseBias._rnxType2ch.assign(_ssrCorr->codeTypeToRnxType(sys, biasEntry.Type));
580 frqPhaseBias._value = biasEntry.Bias;
581 frqPhaseBias._fixIndicator = biasEntry.IntegerIndicator;
582 if (satPhaseBias._ssrFormat == e_ssrFormat::ssrRtcmNew) {
583 if (satPhaseBias._extPBPhaseInd) {
584 frqPhaseBias._fixWideLaneIndicator = biasEntry.WidelaneGroupIndicator;
585 }
586 }
587 else {
588 frqPhaseBias._fixWideLaneIndicator = biasEntry.WidelaneGroupIndicator;
589 }
590 frqPhaseBias._jumpCounter = biasEntry.DiscontinuityCounter;
591 if (!frqPhaseBias._rnxType2ch.empty()) {
592 satPhaseBias._bias.push_back(frqPhaseBias);
593 }
594 }
595 _phaseBiases[_lastTime].append(satPhaseBias);
596 }
597
598 // Ionospheric Model
599 // -----------------
600 if (_vTEC.NumLayers > 0) {
601 _vTecMap[_lastTime]._time = _lastTime;
602 _vTecMap[_lastTime]._updateInt = _vTEC.UpdateInterval;
603 _vTecMap[_lastTime]._staID = _staID.toStdString();
604 for (unsigned ii = 0; ii < _vTEC.NumLayers; ii++) {
605 const SsrCorr::VTEC::IonoLayers& ionoLayer = _vTEC.Layers[ii];
606 t_vTecLayer layer;
607 layer._height = ionoLayer.Height;
608 layer._C.ReSize(ionoLayer.Degree+1, ionoLayer.Order+1);
609 layer._S.ReSize(ionoLayer.Degree+1, ionoLayer.Order+1);
610 for (unsigned iDeg = 0; iDeg <= ionoLayer.Degree; iDeg++) {
611 for (unsigned iOrd = 0; iOrd <= ionoLayer.Order; iOrd++) {
612 layer._C[iDeg][iOrd] = ionoLayer.Cosinus[iDeg][iOrd];
613 layer._S[iDeg][iOrd] = ionoLayer.Sinus[iDeg][iOrd];
614 }
615 }
616 _vTecMap[_lastTime]._layers.push_back(layer);
617 }
618 }
619
620 // Metadata (model correction information)
621 // ----------------------------------------
622 if (_metaData.NumEntries > 0) {
623 // Metadata carries no epoch field of its own (it is keyed here by
624 // _lastTime, inherited from whichever other message last set it), so a
625 // fresh, complete message must replace rather than accumulate onto
626 // whatever a previous message at the same _lastTime already stored.
627 _metaDataMap[_lastTime] = t_metaData();
628 _metaDataMap[_lastTime]._time = _lastTime;
629 _metaDataMap[_lastTime]._staID = _staID.toStdString();
630 _metaDataMap[_lastTime]._ssrIOD = _metaData.SSRIOD;
631 _metaDataMap[_lastTime]._providerID = _metaData.SSRProviderID;
632 _metaDataMap[_lastTime]._solutionID = _metaData.SSRSolutionID;
633 for (unsigned ii = 0; ii < _metaData.NumEntries; ii++) {
634 const SsrCorr::MetaData::ModelPart& part = _metaData.Entries[ii];
635 t_metaDataEntry entry;
636 entry._typeIndicator = part.TypeIndicator;
637 entry._applicationIndicator = part.ApplicationIndicator;
638 entry._nonDefaultIndicator = part.nonDefaultIndicator;
639 entry._nonDefaultIdentifier = part.nonDefaultIdentifier;
640 entry._dataIODIndicator = part.DataIODIndicator;
641 entry._dataIOD = part.DataIOD;
642 _metaDataMap[_lastTime]._entries.push_back(entry);
643 }
644 }
645
646 // Satellite Antenna corrections
647 // ------------------------------
648 // _antenna, like _metaData, carries no epoch field of its own and is never
649 // wiped by reset(), so each system's data persists across unrelated
650 // messages. _antennaSentIOD tracks the last SatelliteAntennaIOD actually
651 // emitted per system, so unrelated messages (and unchanged retransmissions
652 // of the same antenna data) don't cause duplicate output - the same
653 // freshness problem _phaseBiasSentEpoch solves for phase biases.
654 {
655 struct SysInfo { unsigned sysIdx; char sysChar; unsigned numSat; unsigned offset; };
656 const SysInfo sysInfos[] = {
657 { CLOCKORBIT_SATGPS, 'G', CLOCKORBIT_NUMGPS, CLOCKORBIT_OFFSETGPS },
658 { CLOCKORBIT_SATGLONASS, 'R', CLOCKORBIT_NUMGLONASS, CLOCKORBIT_OFFSETGLONASS },
659 { CLOCKORBIT_SATGALILEO, 'E', CLOCKORBIT_NUMGALILEO, CLOCKORBIT_OFFSETGALILEO },
660 { CLOCKORBIT_SATQZSS, 'J', CLOCKORBIT_NUMQZSS, CLOCKORBIT_OFFSETQZSS },
661 { CLOCKORBIT_SATBDS, 'C', CLOCKORBIT_NUMBDS, CLOCKORBIT_OFFSETBDS },
662 };
663 for (const SysInfo& si : sysInfos) {
664 unsigned s = si.sysIdx;
665 if (_antenna.SatelliteAntennaIOD[s] == _antennaSentIOD[s]) {
666 continue; // nothing new for this system since the last emit
667 }
668 if (_antenna.SatelliteMask[s] == 0) {
669 continue; // this system's antenna data was never decoded
670 }
671 for (unsigned k = 0; k < si.numSat; k++) {
672 if (!((_antenna.SatelliteMask[s] >> (63 - k)) & 1ULL)) {
673 continue;
674 }
675 int num = k + 1; // PRN within this system, DF394 MSB-first convention
676 int flag = 0;
677 switch (si.sysChar) {
678 case 'G': flag = t_eph::LNAV; break;
679 case 'R': flag = t_eph::FDMA_M; break;
680 case 'E': flag = t_eph::INAV; break;
681 case 'J': flag = t_eph::LNAV; break;
682 case 'C': flag = (num < 6 || (num > 58 && num < 63)) ? t_eph::D2 : t_eph::D1; break;
683 }
684
685 t_satAntenna satAntenna;
686 satAntenna._prn.set(si.sysChar, num, flag);
687 satAntenna._staID = _staID.toStdString();
688 satAntenna._time = _lastTime;
689 satAntenna._ssrProviderID = _antenna.SSRProviderID[s];
690 satAntenna._satelliteAntennaIOD = _antenna.SatelliteAntennaIOD[s];
691 satAntenna._phaseCenterInfoInd = _antenna.PhaseCenterInformationIndicator[s];
692 satAntenna._groupDelayInfoInd = _antenna.GroupDelayInformationIndicator[s];
693 satAntenna._nadirAngleDependentCorrInd = _antenna.NadirAngleDependentCorrectionIndicator[s];
694 satAntenna._maximumOffNadirAngle = _antenna.maximumOffNadirAngle[s];
695 satAntenna._nadirAngleRangeExtension = _antenna.NadirAngleDependentCorrectionRangeExtension[s];
696
697 const SsrCorr::Antenna::SatellitePart& satPart = _antenna.Sat[si.offset + k];
698 for (unsigned f = 0; f < ANT_MAXFREQUENCIES; f++) {
699 if (!((satPart.GnssFrequencyMask >> (ANT_MAXFREQUENCIES - 1 - f)) & 1U)) {
700 continue;
701 }
702 t_frqAntenna frqAntenna;
703 frqAntenna._freqIndex = f;
704 frqAntenna._nadirCorrectionIndicator = satPart.Freq[f].NadirCorrectionIndicator;
705 frqAntenna._nadirCorrection = satPart.Freq[f].NadirCorrection;
706 if (satAntenna._nadirAngleDependentCorrInd) {
707 unsigned count = satAntenna._maximumOffNadirAngle + 1;
708 for (unsigned deg = 0; deg < count && deg < ANT_MAXNADIRDEGREES; deg++) {
709 frqAntenna._nadirAngleCorrection.push_back(satPart.Freq[f].NadirAngleCorrection[deg]);
710 }
711 }
712 satAntenna._freq.push_back(frqAntenna);
713 }
714 _satAntennas[_lastTime].append(satAntenna);
715 }
716 _antennaSentIOD[s] = _antenna.SatelliteAntennaIOD[s];
717 }
718 }
719
720 // Dump all older epochs
721 // ---------------------
722 QMutableMapIterator<bncTime, QList<t_orbCorr> > itOrb(_orbCorrections);
723 while (itOrb.hasNext()) {
724 itOrb.next();
725 if (itOrb.key() < _lastTime) {
726 emit newOrbCorrections(itOrb.value());
727 t_orbCorr::writeEpoch(_out, itOrb.value());
728 itOrb.remove();
729 }
730 }
731 QMutableMapIterator<bncTime, QList<t_clkCorr> > itClk(_clkCorrections);
732 while (itClk.hasNext()) {
733 itClk.next();
734 if (itClk.key() < _lastTime) {
735 emit newClkCorrections(itClk.value());
736 t_clkCorr::writeEpoch(_out, itClk.value());
737 itClk.remove();
738 }
739 }
740 QMutableMapIterator<bncTime, QList<t_satCodeBias> > itCB(_codeBiases);
741 while (itCB.hasNext()) {
742 itCB.next();
743 if (itCB.key() < _lastTime) {
744 emit newCodeBiases(itCB.value());
745 t_satCodeBias::writeEpoch(_out, itCB.value());
746 itCB.remove();
747 }
748 }
749 QMutableMapIterator<bncTime, QList<t_satPhaseBias> > itPB(_phaseBiases);
750 while (itPB.hasNext()) {
751 itPB.next();
752 if (itPB.key() < _lastTime) {
753 emit newPhaseBiases(itPB.value());
754 t_satPhaseBias::writeEpoch(_out, itPB.value());
755 itPB.remove();
756 }
757 }
758 QMutableMapIterator<bncTime, t_vTec> itTec(_vTecMap);
759 while (itTec.hasNext()) {
760 itTec.next();
761 if (itTec.key() < _lastTime) {
762 emit newTec(itTec.value());
763 t_vTec::write(_out, itTec.value());
764 itTec.remove();
765 }
766 }
767 QMutableMapIterator<bncTime, t_metaData> itMD(_metaDataMap);
768 while (itMD.hasNext()) {
769 itMD.next();
770 if (itMD.key() < _lastTime) {
771 emit newMetaData(itMD.value());
772 t_metaData::write(_out, itMD.value());
773 itMD.remove();
774 }
775 }
776 QMutableMapIterator<bncTime, QList<t_satAntenna> > itAnt(_satAntennas);
777 while (itAnt.hasNext()) {
778 itAnt.next();
779 if (itAnt.key() < _lastTime) {
780 emit newSatAntennas(itAnt.value());
781 t_satAntenna::writeEpoch(_out, itAnt.value());
782 itAnt.remove();
783 }
784 }
785}
786
787//
788////////////////////////////////////////////////////////////////////////////
789void RTCM3coDecoder::checkProviderID() {
790
791 if (_clkOrb.SSRProviderID == 0 && _clkOrb.SSRSolutionID == 0 && _clkOrb.SSRIOD == 0) {
792 return;
793 }
794
795 int newProviderID[3];
796 newProviderID[0] = _clkOrb.SSRProviderID;
797 newProviderID[1] = _clkOrb.SSRSolutionID;
798 newProviderID[2] = _clkOrb.SSRIOD;
799 QString newProviderIDStr = QString(" [SSR Provider ID: %1 SSR Solution ID: %2 SSR IOD: %3]: ")
800 .arg(newProviderID[0]).arg(newProviderID[1]).arg(newProviderID[2]);
801
802 bool alreadySet = false;
803 bool different = false;
804
805 for (unsigned ii = 0; ii < 3; ii++) {
806 if (_providerID[ii] != -1) {
807 alreadySet = true;
808 }
809 if (_providerID[ii] != newProviderID[ii]) {
810 different = true;
811 }
812 _providerID[ii] = newProviderID[ii];
813 }
814
815 if (alreadySet && different) {
816 emit newMessage("RTCM3coDecoder: SSR Provider or Service changed " + newProviderIDStr.toLatin1() + _staID.toLatin1(), true);
817 emit providerIDChanged(_staID);
818 }
819}
820
821// Check corrections
822////////////////////////////////////////////////////////////////////////////
823bool RTCM3coDecoder::corrIsOutOfRange(const SsrCorr::ClockOrbit::SatData& coSat) {
824
825 QString ssrParStr;
826 QString ssrParValue;
827 bool corrIsOutOfRange = false;
828
829 switch (_type) {
830 // ======== //
831 // IGS SSR //
832 // ======== //
833 case IGSssr:
834 if (coSat.Clock.DeltaA0 < -209.7151 ||
835 coSat.Clock.DeltaA0 > +209.7151) {
836 ssrParStr = "Clock::DeltaA0";
837 ssrParValue = QString::number(coSat.Clock.DeltaA0, 'f', 4);
838 corrIsOutOfRange = true;
839 }
840 if (coSat.Clock.DeltaA1 < -1.048575 ||
841 coSat.Clock.DeltaA1 > +1.048575) {
842 ssrParStr = "Clock::DeltaA1";
843 ssrParValue = QString::number(coSat.Clock.DeltaA1, 'f', 6);
844 corrIsOutOfRange = true;
845 }
846 if (coSat.Clock.DeltaA2 < -1.3421772 ||
847 coSat.Clock.DeltaA2 > +1.3421772) {
848 ssrParStr = "Clock::DeltaA2";
849 ssrParValue = QString::number(coSat.Clock.DeltaA2, 'f', 7);
850 corrIsOutOfRange = true;
851 }
852
853 if (coSat.Orbit.DeltaRadial < -209.7151 ||
854 coSat.Orbit.DeltaRadial > +209.7151) {
855 ssrParStr = "Orbit::DeltaRadial";
856 ssrParValue = QString::number(coSat.Orbit.DeltaRadial, 'f', 4);
857 corrIsOutOfRange = true;
858 }
859
860 if (coSat.Orbit.DeltaAlongTrack < -209.7148 ||
861 coSat.Orbit.DeltaAlongTrack > +209.7148) {
862 ssrParStr = "Orbit::DeltaAlongTrack";
863 ssrParValue = QString::number(coSat.Orbit.DeltaAlongTrack, 'f', 4);
864 corrIsOutOfRange = true;
865 }
866 if (coSat.Orbit.DeltaCrossTrack < -209.7148 ||
867 coSat.Orbit.DeltaCrossTrack > +209.7148) {
868 ssrParStr = "Orbit::DeltaCrossTrack";
869 ssrParValue = QString::number(coSat.Orbit.DeltaCrossTrack, 'f', 4);
870 corrIsOutOfRange = true;
871 }
872
873 if (coSat.Orbit.DotDeltaRadial < -1.048575 ||
874 coSat.Orbit.DotDeltaRadial > +1.048575) {
875 ssrParStr = "Orbit::DotDeltaRadial";
876 ssrParValue = QString::number(coSat.Orbit.DotDeltaRadial, 'f', 6);
877 corrIsOutOfRange = true;
878 }
879 if (coSat.Orbit.DotDeltaAlongTrack < -1.048572 ||
880 coSat.Orbit.DotDeltaAlongTrack > +1.048572) {
881 ssrParStr = "Orbit::DotDeltaAlongTrack";
882 ssrParValue = QString::number(coSat.Orbit.DotDeltaAlongTrack, 'f', 6);
883 corrIsOutOfRange = true;
884 }
885 if (coSat.Orbit.DotDeltaCrossTrack < -1.048572 ||
886 coSat.Orbit.DotDeltaCrossTrack > +1.048572) {
887 ssrParStr = "Orbit::DotDeltaCrossTrack";
888 ssrParValue = QString::number(coSat.Orbit.DotDeltaCrossTrack, 'f', 6);
889 corrIsOutOfRange = true;
890 }
891 break;
892 //==========//
893 // RTCM SSR //
894 // =========//
895 case RTCMssr:
896 case RTCMnewssr:
897 if (coSat.Clock.DeltaA0 < -209.7151 ||
898 coSat.Clock.DeltaA0 > +209.7151) {
899 ssrParStr = "Clock::DeltaA0";
900 ssrParValue = QString::number(coSat.Clock.DeltaA0, 'f', 4);
901 corrIsOutOfRange = true;
902 }
903 if (coSat.Clock.DeltaA1 < -1.048575 ||
904 coSat.Clock.DeltaA1 > +1.048575) {
905 ssrParStr = "Clock::DeltaA1";
906 ssrParValue = QString::number(coSat.Clock.DeltaA1, 'f', 6);
907 corrIsOutOfRange = true;
908 }
909 if (coSat.Clock.DeltaA2 < -1.34217726 ||
910 coSat.Clock.DeltaA2 > +1.34217726) {
911 ssrParStr = "Clock::DeltaA2";
912 ssrParValue = QString::number(coSat.Clock.DeltaA2, 'f', 8);
913 corrIsOutOfRange = true;
914 }
915
916 if (coSat.Orbit.DeltaRadial < -209.7151 ||
917 coSat.Orbit.DeltaRadial > +209.7151) {
918 ssrParStr = "Orbit::DeltaRadial";
919 ssrParValue = QString::number(coSat.Orbit.DeltaRadial, 'f', 4);
920 corrIsOutOfRange = true;
921 }
922
923 if (coSat.Orbit.DeltaAlongTrack < -209.7148 ||
924 coSat.Orbit.DeltaAlongTrack > +209.7148) {
925 ssrParStr = "Orbit::DeltaAlongTrack";
926 ssrParValue = QString::number(coSat.Orbit.DeltaAlongTrack, 'f', 4);
927 corrIsOutOfRange = true;
928 }
929 if (coSat.Orbit.DeltaCrossTrack < -209.7148 ||
930 coSat.Orbit.DeltaCrossTrack > +209.7148) {
931 ssrParStr = "Orbit::DeltaCrossTrack";
932 ssrParValue = QString::number(coSat.Orbit.DeltaCrossTrack, 'f', 4);
933 corrIsOutOfRange = true;
934 }
935
936 if (coSat.Orbit.DotDeltaRadial < -1.048575 ||
937 coSat.Orbit.DotDeltaRadial > +1.048575) {
938 ssrParStr = "Orbit::DotDeltaRadial";
939 ssrParValue = QString::number(coSat.Orbit.DotDeltaRadial, 'f', 6);
940 corrIsOutOfRange = true;
941 }
942 if (coSat.Orbit.DotDeltaAlongTrack < -1.048572 ||
943 coSat.Orbit.DotDeltaAlongTrack > +1.048572) {
944 ssrParStr = "Orbit::DotDeltaAlongTrack";
945 ssrParValue = QString::number(coSat.Orbit.DotDeltaAlongTrack, 'f', 6);
946 corrIsOutOfRange = true;
947 }
948 if (coSat.Orbit.DotDeltaCrossTrack < -1.048572 ||
949 coSat.Orbit.DotDeltaCrossTrack > +1.048572) {
950 ssrParStr = "Orbit::DotDeltaCrossTrack";
951 ssrParValue = QString::number(coSat.Orbit.DotDeltaCrossTrack, 'f', 6);
952 corrIsOutOfRange = true;
953 }
954 break;
955 }
956
957 if (corrIsOutOfRange) {
958 emit newMessage("RTCM3coDecoder: Correction " + ssrParStr.toLatin1()
959 + " (" + ssrParValue.toLatin1() + ") "
960 + "is out of range " + _staID.toLatin1(), true);
961 }
962
963 return corrIsOutOfRange;
964}
965
966//
967////////////////////////////////////////////////////////////////////////////
968void RTCM3coDecoder::setEpochTime() {
969
970 // _phaseBias is no longer wiped between messages (kept alive so a later
971 // Extended Phase Bias message can correlate against it), so
972 // NumberOfSat[s] > 0 alone no longer means "phase bias was just decoded
973 // this cycle" - it can be stale from many messages ago. Gate each
974 // phase-bias fallback below on the same per-system freshness tracking
975 // sendResults() uses (_phaseBiasSentEpoch), so a stale leftover value
976 // never gets picked as this cycle's epoch.
977 bncTime prevTime = _lastTime;
978 _lastTime.reset();
979
980 double epoSecGPS = -1.0;
981 double epoSecGlo = -1.0;
982 double epoSecGal = -1.0;
983 double epoSecQzss = -1.0;
984 double epoSecSbas = -1.0;
985 double epoSecBds = -1.0;
986 if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
987 epoSecGPS = _clkOrb.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
988 }
989 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
990 epoSecGPS = _codeBias.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
991 }
992 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATGPS] > 0 &&
993 _phaseBias.EpochTime[CLOCKORBIT_SATGPS] != _phaseBiasSentEpoch[CLOCKORBIT_SATGPS]) {
994 epoSecGPS = _phaseBias.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
995 }
996 else if (_vTEC.NumLayers > 0) {
997 epoSecGPS = _vTEC.EpochTime; // 0 .. 604799 s
998 }
999 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
1000 epoSecGlo = _clkOrb.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s
1001 }
1002 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
1003 epoSecGlo = _codeBias.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s
1004 }
1005 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0 &&
1006 _phaseBias.EpochTime[CLOCKORBIT_SATGLONASS] != _phaseBiasSentEpoch[CLOCKORBIT_SATGLONASS]) {
1007 epoSecGlo = _phaseBias.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s
1008 }
1009 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0) {
1010 epoSecGal = _clkOrb.EpochTime[CLOCKORBIT_SATGALILEO];
1011 }
1012 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0) {
1013 epoSecGal = _codeBias.EpochTime[CLOCKORBIT_SATGALILEO];
1014 }
1015 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0 &&
1016 _phaseBias.EpochTime[CLOCKORBIT_SATGALILEO] != _phaseBiasSentEpoch[CLOCKORBIT_SATGALILEO]) {
1017 epoSecGal = _phaseBias.EpochTime[CLOCKORBIT_SATGALILEO];
1018 }
1019 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATQZSS] > 0) {
1020 epoSecQzss = _clkOrb.EpochTime[CLOCKORBIT_SATQZSS];
1021 }
1022 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATQZSS] > 0) {
1023 epoSecQzss = _codeBias.EpochTime[CLOCKORBIT_SATQZSS];
1024 }
1025 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATQZSS] > 0 &&
1026 _phaseBias.EpochTime[CLOCKORBIT_SATQZSS] != _phaseBiasSentEpoch[CLOCKORBIT_SATQZSS]) {
1027 epoSecQzss = _phaseBias.EpochTime[CLOCKORBIT_SATQZSS];
1028 }
1029 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATSBAS] > 0) {
1030 epoSecSbas = _clkOrb.EpochTime[CLOCKORBIT_SATSBAS];
1031 }
1032 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATSBAS] > 0) {
1033 epoSecSbas = _codeBias.EpochTime[CLOCKORBIT_SATSBAS];
1034 }
1035 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATSBAS] > 0 &&
1036 _phaseBias.EpochTime[CLOCKORBIT_SATSBAS] != _phaseBiasSentEpoch[CLOCKORBIT_SATSBAS]) {
1037 epoSecSbas = _phaseBias.EpochTime[CLOCKORBIT_SATSBAS];
1038 }
1039 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATBDS] > 0) {
1040 epoSecBds = _clkOrb.EpochTime[CLOCKORBIT_SATBDS];
1041 }
1042 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATBDS] > 0) {
1043 epoSecBds = _codeBias.EpochTime[CLOCKORBIT_SATBDS];
1044 }
1045 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATBDS] > 0 &&
1046 _phaseBias.EpochTime[CLOCKORBIT_SATBDS] != _phaseBiasSentEpoch[CLOCKORBIT_SATBDS]) {
1047 epoSecBds = _phaseBias.EpochTime[CLOCKORBIT_SATBDS];
1048 }
1049
1050 // Retrieve current time
1051 // ---------------------
1052 int currentWeek = 0;
1053 double currentSec = 0.0;
1054 currentGPSWeeks(currentWeek, currentSec);
1055 bncTime currentTime(currentWeek, currentSec);
1056
1057 // Set _lastTime close to currentTime
1058 // ----------------------------------
1059 if (epoSecGPS != -1) {
1060 _lastTime.set(currentWeek, epoSecGPS);
1061 }
1062 else if (epoSecGlo != -1) {
1063 QDate date = dateAndTimeFromGPSweek(currentTime.gpsw(), currentTime.gpssec()).date();
1064 if (_type == IGSssr) {
1065 epoSecGlo = epoSecGlo + gnumleap(date.year(), date.month(), date.day());
1066 }
1067 if (_type == RTCMssr || _type == RTCMnewssr) {
1068 // Same GLONASS epoch wire convention (UTC+3h) as RTCMssr
1069 epoSecGlo = epoSecGlo - 3 * 3600 + gnumleap(date.year(), date.month(), date.day());
1070 }
1071 _lastTime.set(currentWeek, epoSecGlo);
1072 }
1073 else if (epoSecGal != -1) {
1074 _lastTime.set(currentWeek, epoSecGal);
1075 }
1076 else if (epoSecQzss != -1) {
1077 _lastTime.set(currentWeek, epoSecQzss);
1078 }
1079 else if (epoSecSbas != -1) {
1080 _lastTime.set(currentWeek, epoSecSbas);
1081 }
1082 else if (epoSecBds != -1) {
1083 epoSecBds += 14.0;
1084 if (epoSecBds > 604800.0) {
1085 epoSecBds -= 7.0*24.0*60.0*60.0;
1086 }
1087 _lastTime.set(currentWeek, epoSecBds);
1088 }
1089 // Some message types (e.g. Metadata) carry no epoch field of their own,
1090 // and none of the above found anything fresh to use either - fall back
1091 // to the last known valid time rather than leaving _lastTime invalid
1092 // (which would silently drop the message's output entirely).
1093 else if (prevTime.valid()) {
1094 _lastTime = prevTime;
1095 }
1096
1097 if (_lastTime.valid()) {
1098 double maxDiff = 12 * 3600.0;
1099 while (_lastTime < currentTime - maxDiff) {
1100 _lastTime = _lastTime + maxDiff;
1101 }
1102 while (_lastTime > currentTime + maxDiff) {
1103 _lastTime = _lastTime - maxDiff;
1104 }
1105 }
1106}
Note: See TracBrowser for help on using the repository browser.