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

Last change on this file since 11040 was 11040, checked in by stuerze, 4 days ago

updates regarding RTCM-SSR

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