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

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

updates regarding RTCM-SSR

File size: 41.2 KB
RevLine 
[866]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)
[11024]6// http://bkg.bund.de
[866]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 *
[6215]37 * Changes:
[866]38 *
39 * -----------------------------------------------------------------------*/
40
[868]41#include <stdio.h>
[920]42#include <math.h>
[11010]43#include <climits>
[868]44
[866]45#include "RTCM3coDecoder.h"
[918]46#include "bncutils.h"
[934]47#include "bncrinex.h"
[5070]48#include "bnccore.h"
[1535]49#include "bncsettings.h"
[4428]50#include "bnctime.h"
[866]51
52using namespace std;
53
54// Constructor
55////////////////////////////////////////////////////////////////////////////
[9048]56RTCM3coDecoder::RTCM3coDecoder(const QString& staID) {
[934]57
[970]58 _staID = staID;
59
[934]60 // File Output
61 // -----------
[1535]62 bncSettings settings;
[934]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 }
[970]69 _fileNameSkl = path + staID;
[934]70 }
[6141]71 _out = 0;
[934]72
[6215]73 connect(this, SIGNAL(newOrbCorrections(QList<t_orbCorr>)),
[6141]74 BNC_CORE, SLOT(slotNewOrbCorrections(QList<t_orbCorr>)));
[1828]75
[6215]76 connect(this, SIGNAL(newClkCorrections(QList<t_clkCorr>)),
[6141]77 BNC_CORE, SLOT(slotNewClkCorrections(QList<t_clkCorr>)));
78
[6486]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
[11008]88 connect(this, SIGNAL(newMetaData(t_metaData)),
89 BNC_CORE, SLOT(slotNewMetaData(t_metaData)));
90
[11038]91 connect(this, SIGNAL(newSatAntennas(QList<t_satAntenna>)),
92 BNC_CORE, SLOT(slotNewSatAntennas(QList<t_satAntenna>)));
93
[6215]94 connect(this, SIGNAL(providerIDChanged(QString)),
[5577]95 BNC_CORE, SIGNAL(providerIDChanged(QString)));
96
[6215]97 connect(this, SIGNAL(newMessage(QByteArray,bool)),
[5068]98 BNC_CORE, SLOT(slotMessage(const QByteArray,bool)));
[4428]99
[6467]100 reset();
[5576]101
102 _providerID[0] = -1;
103 _providerID[1] = -1;
104 _providerID[2] = -1;
[9025]105
[11038]106 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) {
107 _antennaSentIOD[s] = UINT_MAX; // "never sent"
108 }
109
110 _stateSnapshot = new t_stateSnapshot;
[9025]111 _ssrCorr = 0;
[10534]112
[866]113}
114
115// Destructor
116////////////////////////////////////////////////////////////////////////////
117RTCM3coDecoder::~RTCM3coDecoder() {
[935]118 delete _out;
[9025]119 delete _ssrCorr;
[11038]120 delete _stateSnapshot;
[7641]121 _IODs.clear();
122 _orbCorrections.clear();
123 _clkCorrections.clear();
124 _lastClkCorrections.clear();
125 _codeBiases.clear();
126 _phaseBiases.clear();
127 _vTecMap.clear();
[11008]128 _metaDataMap.clear();
[11038]129 _satAntennas.clear();
[866]130}
131
[7641]132//
[6467]133////////////////////////////////////////////////////////////////////////////
[11002]134void RTCM3coDecoder::reset(bool resetPhaseBias) {
[6467]135 memset(&_clkOrb, 0, sizeof(_clkOrb));
136 memset(&_codeBias, 0, sizeof(_codeBias));
[11002]137 if (resetPhaseBias) {
138 memset(&_phaseBias, 0, sizeof(_phaseBias));
[11010]139 for (unsigned s = 0; s < CLOCKORBIT_SATNUM; s++) {
140 _phaseBiasSentEpoch[s] = UINT_MAX; // "never sent"
141 }
[11002]142 }
[6467]143 memset(&_vTEC, 0, sizeof(_vTEC));
144}
145
[934]146// Reopen Output File
[6215]147////////////////////////////////////////////////////////////////////////
[6141]148void RTCM3coDecoder::reopen() {
[934]149
[6141]150 if (!_fileNameSkl.isEmpty()) {
[934]151
[1535]152 bncSettings settings;
[934]153
[1154]154 QDateTime datTim = currentDateAndTimeGPS();
[934]155
156 QString hlpStr = bncRinex::nextEpochStr(datTim,
[9771]157 settings.value("corrIntr").toString(), 3);
[934]158
[9941]159 QString cntStr = (_fileNameSkl.contains("ION")) ? "_ION.ssr" : "_MC.ssr";
160
[9771]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')) +
[9941]165 hlpStr + // HM_period
166 cntStr; // mixed ION or CLK
[934]167
[6141]168 if (_fileName == fileNameHlp) {
[934]169 return;
170 }
171 else {
[6141]172 _fileName = fileNameHlp;
[934]173 }
174
[6141]175 delete _out;
[1727]176 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked) {
[8204]177 _out = new ofstream( _fileName.toLatin1().data(), ios_base::out | ios_base::app );
[1727]178 }
179 else {
[8204]180 _out = new ofstream( _fileName.toLatin1().data() );
[1727]181 }
[934]182 }
183}
184
[6215]185//
[866]186////////////////////////////////////////////////////////////////////////////
[1227]187t_irc RTCM3coDecoder::Decode(char* buffer, int bufLen, vector<string>& errmsg) {
[868]188
[1218]189 errmsg.clear();
190
[1227]191 _buffer.append(QByteArray(buffer,bufLen));
[868]192
[1023]193 t_irc retCode = failure;
194
[1832]195 while(_buffer.size()) {
196
[11004]197 // save state
[11038]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));
[6454]204
[879]205 int bytesused = 0;
[9306]206
[11031]207 GCOB_RETURN irc = _ssrCorr->GetSSR(&_clkOrb, &_codeBias, &_vTEC, &_phaseBias, &_metaData, &_antenna,
[9306]208 _buffer.data(), _buffer.size(), &bytesused);
[1829]209
[1833]210 if (irc <= -30) { // not enough data - restore state and exit loop
[11038]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));
[11040]216 memcpy(&_antenna, &_stateSnapshot->antenna, sizeof(_antenna));
[1833]217 break;
[869]218 }
[1832]219
[11003]220 else if (irc < 0) { // error - skip this message (or 1 byte if the
[11004]221 // frame itself couldn't be recognized) and retry
[11003]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 }
[1842]235 _buffer = _buffer.mid(bytesused ? bytesused : 1);
[1833]236 }
237
238 else { // OK or MESSAGEFOLLOWS
[1828]239 _buffer = _buffer.mid(bytesused);
240
[6467]241 if (irc == GCOBR_OK || irc == GCOBR_MESSAGEFOLLOWS ) {
[6556]242 setEpochTime(); // sets _lastTime
[7641]243
244 if (_lastTime.valid()) {
[6467]245 reopen();
246 checkProviderID();
247 sendResults();
248 retCode = success;
[919]249 }
[6467]250 else {
[10527]251 emit newMessage("RTCM3coDecoder: _lastTime invalid: " + _staID.toLatin1(), true);
[6467]252 retCode = failure;
[1829]253 }
[11002]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);
[869]260 }
[1829]261 }
[1833]262 }
[1832]263
[1829]264 return retCode;
[866]265}
[934]266
[6215]267//
[934]268////////////////////////////////////////////////////////////////////////////
[6141]269void RTCM3coDecoder::sendResults() {
[934]270
[6455]271 // Orbit and clock corrections of all satellites
272 // ---------------------------------------------
[6854]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++) {
[10572]280 if (corrIsOutOfRange(_clkOrb.Sat[ii])) {
281 continue;
282 }
[10599]283 char sys = ' ';
284 int num = _clkOrb.Sat[ii].ID;
285 int flag = 0; // to force NAV type usage according SSR standard
[6454]286 if (ii < _clkOrb.NumberOfSat[CLOCKORBIT_SATGPS]) {
[10599]287 sys = 'G';
288 flag = t_eph::LNAV;
[3022]289 }
[6854]290 else if (ii >= CLOCKORBIT_OFFSETGLONASS &&
[6855]291 ii < CLOCKORBIT_OFFSETGLONASS + _clkOrb.NumberOfSat[CLOCKORBIT_SATGLONASS]) {
[10599]292 sys = 'R';
293 flag = t_eph::FDMA_M;
[3022]294 }
[6854]295 else if (ii >= CLOCKORBIT_OFFSETGALILEO &&
[6855]296 ii < CLOCKORBIT_OFFSETGALILEO + _clkOrb.NumberOfSat[CLOCKORBIT_SATGALILEO]) {
[10599]297 sys = 'E';
298 flag = t_eph::INAV;
[6854]299 }
300 else if (ii >= CLOCKORBIT_OFFSETQZSS &&
[6855]301 ii < CLOCKORBIT_OFFSETQZSS + _clkOrb.NumberOfSat[CLOCKORBIT_SATQZSS]) {
[10599]302 sys = 'J';
303 flag = t_eph::LNAV;
[6854]304 }
305 else if (ii >= CLOCKORBIT_OFFSETSBAS &&
[6855]306 ii < CLOCKORBIT_OFFSETSBAS + _clkOrb.NumberOfSat[CLOCKORBIT_SATSBAS]) {
[10599]307 sys = 'S';
308 flag = t_eph::SBASL1;
[6854]309 }
310 else if (ii >= CLOCKORBIT_OFFSETBDS &&
[6855]311 ii < CLOCKORBIT_OFFSETBDS + _clkOrb.NumberOfSat[CLOCKORBIT_SATBDS]) {
[10599]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 }
[6854]322 }
[6141]323 else {
324 continue;
325 }
[9025]326
[6141]327 // Orbit correction
328 // ----------------
[9025]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 ) {
[3022]341
[6141]342 t_orbCorr orbCorr;
[10599]343 orbCorr._prn.set(sys, num, flag);
[6564]344 orbCorr._staID = _staID.toStdString();
[6556]345 orbCorr._iod = _clkOrb.Sat[ii].IOD;
346 orbCorr._time = _lastTime;
347 orbCorr._updateInt = _clkOrb.UpdateInterval;
[10599]348 orbCorr._system = sys;
[6556]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;
[10998]355 orbCorr._ssrFormat = (_type == RTCMssr) ? ssrRtcmOld :
356 (_type == RTCMnewssr) ? ssrRtcmNew : ssrUnknown;
[3022]357
[7652]358 _orbCorrections[_lastTime].append(orbCorr);
[3022]359
[6471]360 _IODs[orbCorr._prn] = _clkOrb.Sat[ii].IOD;
[6141]361 }
[3022]362
[6455]363 // Clock Corrections
364 // -----------------
[9025]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) {
[3022]377
[6141]378 t_clkCorr clkCorr;
[10599]379 clkCorr._prn.set(sys, _clkOrb.Sat[ii].ID, flag);
[6564]380 clkCorr._staID = _staID.toStdString();
[6141]381 clkCorr._time = _lastTime;
[6556]382 clkCorr._updateInt = _clkOrb.UpdateInterval;
[7014]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;
[3022]386
[6471]387 _lastClkCorrections[clkCorr._prn] = clkCorr;
388
389 if (_IODs.contains(clkCorr._prn)) {
390 clkCorr._iod = _IODs[clkCorr._prn];
[7652]391 _clkCorrections[_lastTime].append(clkCorr);
[3022]392 }
393 }
[6141]394
395 // High-Resolution Clocks
396 // ----------------------
[9025]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) {
[10599]403 t_prn prn(sys, _clkOrb.Sat[ii].ID, flag);
[6471]404 if (_lastClkCorrections.contains(prn)) {
405 t_clkCorr clkCorr;
[6556]406 clkCorr = _lastClkCorrections[prn];
407 clkCorr._time = _lastTime;
408 clkCorr._updateInt = _clkOrb.UpdateInterval;
409 clkCorr._dClk += _clkOrb.Sat[ii].hrclock / t_CST::c;
[6471]410 if (_IODs.contains(clkCorr._prn)) {
411 clkCorr._iod = _IODs[clkCorr._prn];
[10536]412 _clkCorrections[_lastTime].append(clkCorr);
[6471]413 }
414 }
[6141]415 }
[3022]416 }
417
[6455]418 // Code Biases
419 // -----------
[6854]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++) {
[10599]427 char sys = ' ';
428 int num = _codeBias.Sat[ii].ID;
429 int flag = 0;
[6454]430 if (ii < _codeBias.NumberOfSat[CLOCKORBIT_SATGPS]) {
[10599]431 sys = 'G';
432 flag = t_eph::LNAV;
[3022]433 }
[6854]434 else if (ii >= CLOCKORBIT_OFFSETGLONASS &&
[6855]435 ii < CLOCKORBIT_OFFSETGLONASS + _codeBias.NumberOfSat[CLOCKORBIT_SATGLONASS]) {
[10599]436 sys = 'R';
437 flag = t_eph::FDMA_M;
[3022]438 }
[6854]439 else if (ii >= CLOCKORBIT_OFFSETGALILEO &&
[6855]440 ii < CLOCKORBIT_OFFSETGALILEO + _codeBias.NumberOfSat[CLOCKORBIT_SATGALILEO]) {
[10599]441 sys = 'E';
442 flag = t_eph::INAV;
[6854]443 }
444 else if (ii >= CLOCKORBIT_OFFSETQZSS &&
[6855]445 ii < CLOCKORBIT_OFFSETQZSS + _codeBias.NumberOfSat[CLOCKORBIT_SATQZSS]) {
[10599]446 sys = 'J';
447 flag = t_eph::LNAV;
[6854]448 }
449 else if (ii >= CLOCKORBIT_OFFSETSBAS &&
[6855]450 ii < CLOCKORBIT_OFFSETSBAS + _codeBias.NumberOfSat[CLOCKORBIT_SATSBAS]) {
[10599]451 sys = 'S';
452 flag = t_eph::SBASL1;
[6854]453 }
454 else if (ii >= CLOCKORBIT_OFFSETBDS &&
[6855]455 ii < CLOCKORBIT_OFFSETBDS + _codeBias.NumberOfSat[CLOCKORBIT_SATBDS]) {
[10599]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 }
[6854]466 }
[6141]467 else {
468 continue;
469 }
[6463]470 t_satCodeBias satCodeBias;
[10599]471 satCodeBias._prn.set(sys, num, flag);
[6564]472 satCodeBias._staID = _staID.toStdString();
[6556]473 satCodeBias._time = _lastTime;
474 satCodeBias._updateInt = _codeBias.UpdateInterval;
[6454]475 for (unsigned jj = 0; jj < _codeBias.Sat[ii].NumberOfCodeBiases; jj++) {
[9025]476 const SsrCorr::CodeBias::BiasSat::CodeBiasEntry& biasEntry = _codeBias.Sat[ii].Biases[jj];
[6472]477 t_frqCodeBias frqCodeBias;
[10599]478 frqCodeBias._rnxType2ch.assign(_ssrCorr->codeTypeToRnxType(sys, biasEntry.Type));
[6472]479 frqCodeBias._value = biasEntry.Bias;
[6474]480 if (!frqCodeBias._rnxType2ch.empty()) {
481 satCodeBias._bias.push_back(frqCodeBias);
482 }
[6141]483 }
[7652]484 _codeBiases[_lastTime].append(satCodeBias);
[3022]485 }
486
[6487]487 // Phase Biases
488 // -----------
[11010]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 }
[6854]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++) {
[10599]511 char sys = ' ';
512 int num = _phaseBias.Sat[ii].ID;
513 int flag = 0;
[6487]514 if (ii < _phaseBias.NumberOfSat[CLOCKORBIT_SATGPS]) {
[11010]515 if (!phaseBiasFresh[CLOCKORBIT_SATGPS]) continue;
[10599]516 sys = 'G';
517 flag = t_eph::LNAV;
[6487]518 }
[6854]519 else if (ii >= CLOCKORBIT_OFFSETGLONASS &&
[6855]520 ii < CLOCKORBIT_OFFSETGLONASS + _phaseBias.NumberOfSat[CLOCKORBIT_SATGLONASS]) {
[11010]521 if (!phaseBiasFresh[CLOCKORBIT_SATGLONASS]) continue;
[10599]522 sys = 'R';
523 flag = t_eph::FDMA_M;
[6487]524 }
[6854]525 else if (ii >= CLOCKORBIT_OFFSETGALILEO &&
[6855]526 ii < CLOCKORBIT_OFFSETGALILEO + _phaseBias.NumberOfSat[CLOCKORBIT_SATGALILEO]) {
[11010]527 if (!phaseBiasFresh[CLOCKORBIT_SATGALILEO]) continue;
[10599]528 sys = 'E';
529 flag = t_eph::INAV;
[6854]530 }
531 else if (ii >= CLOCKORBIT_OFFSETQZSS &&
[6855]532 ii < CLOCKORBIT_OFFSETQZSS + _phaseBias.NumberOfSat[CLOCKORBIT_SATQZSS]) {
[11010]533 if (!phaseBiasFresh[CLOCKORBIT_SATQZSS]) continue;
[10599]534 sys = 'J';
535 flag = t_eph::LNAV;
[6854]536 }
537 else if (ii >= CLOCKORBIT_OFFSETSBAS &&
[6855]538 ii < CLOCKORBIT_OFFSETSBAS + _phaseBias.NumberOfSat[CLOCKORBIT_SATSBAS]) {
[11010]539 if (!phaseBiasFresh[CLOCKORBIT_SATSBAS]) continue;
[10599]540 sys = 'S';
541 flag = t_eph::SBASL1;
[6854]542 }
543 else if (ii >= CLOCKORBIT_OFFSETBDS &&
[6855]544 ii < CLOCKORBIT_OFFSETBDS + _phaseBias.NumberOfSat[CLOCKORBIT_SATBDS]) {
[11010]545 if (!phaseBiasFresh[CLOCKORBIT_SATBDS]) continue;
[10599]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 }
[6854]556 }
[6487]557 else {
558 continue;
559 }
560 t_satPhaseBias satPhaseBias;
[10599]561 satPhaseBias._prn.set(sys, num, flag);
[6564]562 satPhaseBias._staID = _staID.toStdString();
[6488]563 satPhaseBias._time = _lastTime;
[6556]564 satPhaseBias._updateInt = _phaseBias.UpdateInterval;
[10998]565 satPhaseBias._ssrFormat = (_type == RTCMssr) ? ssrRtcmOld :
[10999]566 (_type == RTCMnewssr) ? ssrRtcmNew : ssrUnknown;
[11000]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 }
[8617]575 satPhaseBias._yaw = _phaseBias.Sat[ii].YawAngle;
576 satPhaseBias._yawRate = _phaseBias.Sat[ii].YawRate;
[6487]577 for (unsigned jj = 0; jj < _phaseBias.Sat[ii].NumberOfPhaseBiases; jj++) {
[9025]578 const SsrCorr::PhaseBias::PhaseBiasSat::PhaseBiasEntry& biasEntry = _phaseBias.Sat[ii].Biases[jj];
[6487]579 t_frqPhaseBias frqPhaseBias;
[10599]580 frqPhaseBias._rnxType2ch.assign(_ssrCorr->codeTypeToRnxType(sys, biasEntry.Type));
[11000]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;
[6487]592 if (!frqPhaseBias._rnxType2ch.empty()) {
593 satPhaseBias._bias.push_back(frqPhaseBias);
594 }
595 }
[7652]596 _phaseBiases[_lastTime].append(satPhaseBias);
[6487]597 }
598
[6490]599 // Ionospheric Model
600 // -----------------
601 if (_vTEC.NumLayers > 0) {
[6497]602 _vTecMap[_lastTime]._time = _lastTime;
[6556]603 _vTecMap[_lastTime]._updateInt = _vTEC.UpdateInterval;
[6564]604 _vTecMap[_lastTime]._staID = _staID.toStdString();
[6491]605 for (unsigned ii = 0; ii < _vTEC.NumLayers; ii++) {
[9025]606 const SsrCorr::VTEC::IonoLayers& ionoLayer = _vTEC.Layers[ii];
[6491]607 t_vTecLayer layer;
608 layer._height = ionoLayer.Height;
[6878]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++) {
[6491]613 layer._C[iDeg][iOrd] = ionoLayer.Cosinus[iDeg][iOrd];
614 layer._S[iDeg][iOrd] = ionoLayer.Sinus[iDeg][iOrd];
615 }
616 }
[6497]617 _vTecMap[_lastTime]._layers.push_back(layer);
[6491]618 }
[6490]619 }
620
[11008]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
[11038]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
[6455]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());
[6456]728 t_orbCorr::writeEpoch(_out, itOrb.value());
[6455]729 itOrb.remove();
[7641]730 }
[6141]731 }
[6455]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());
[6456]737 t_clkCorr::writeEpoch(_out, itClk.value());
[6455]738 itClk.remove();
[7641]739 }
[6141]740 }
[6474]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());
[6475]746 t_satCodeBias::writeEpoch(_out, itCB.value());
[6474]747 itCB.remove();
[7641]748 }
[6474]749 }
[6487]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();
[7641]757 }
[6487]758 }
[6490]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();
[7641]766 }
[6490]767 }
[11008]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 }
[11038]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 }
[3022]786}
[5576]787
[6215]788//
[5576]789////////////////////////////////////////////////////////////////////////////
790void RTCM3coDecoder::checkProviderID() {
791
[10553]792 if (_clkOrb.SSRProviderID == 0 && _clkOrb.SSRSolutionID == 0 && _clkOrb.SSRIOD == 0) {
793 return;
794 }
795
[5576]796 int newProviderID[3];
[6454]797 newProviderID[0] = _clkOrb.SSRProviderID;
798 newProviderID[1] = _clkOrb.SSRSolutionID;
799 newProviderID[2] = _clkOrb.SSRIOD;
[10534]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]);
[5576]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 }
[6215]815
[5576]816 if (alreadySet && different) {
[10768]817 emit newMessage("RTCM3coDecoder: SSR Provider or Service changed " + newProviderIDStr.toLatin1() + _staID.toLatin1(), true);
[5577]818 emit providerIDChanged(_staID);
[5576]819 }
820}
[6467]821
[10572]822// Check corrections
823////////////////////////////////////////////////////////////////////////////
824bool RTCM3coDecoder::corrIsOutOfRange(const SsrCorr::ClockOrbit::SatData& coSat) {
825
[10617]826 QString ssrParStr;
827 QString ssrParValue;
828 bool corrIsOutOfRange = false;
[10572]829
[10617]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 }
[10572]853
[10617]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:
[10754]897 case RTCMnewssr:
[10617]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;
[10572]965}
966
[6467]967//
968////////////////////////////////////////////////////////////////////////////
[6556]969void RTCM3coDecoder::setEpochTime() {
[6467]970
[11010]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;
[6467]979 _lastTime.reset();
980
[6854]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;
[6467]987 if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
[6553]988 epoSecGPS = _clkOrb.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
[6467]989 }
990 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
[7641]991 epoSecGPS = _codeBias.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
[6467]992 }
[11010]993 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATGPS] > 0 &&
994 _phaseBias.EpochTime[CLOCKORBIT_SATGPS] != _phaseBiasSentEpoch[CLOCKORBIT_SATGPS]) {
[7641]995 epoSecGPS = _phaseBias.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
[6470]996 }
997 else if (_vTEC.NumLayers > 0) {
[7641]998 epoSecGPS = _vTEC.EpochTime; // 0 .. 604799 s
[6470]999 }
[6467]1000 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
[6470]1001 epoSecGlo = _clkOrb.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s
[6467]1002 }
1003 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
[6470]1004 epoSecGlo = _codeBias.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s
[6467]1005 }
[11010]1006 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0 &&
1007 _phaseBias.EpochTime[CLOCKORBIT_SATGLONASS] != _phaseBiasSentEpoch[CLOCKORBIT_SATGLONASS]) {
[6470]1008 epoSecGlo = _phaseBias.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s
1009 }
[6854]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 }
[11010]1016 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0 &&
1017 _phaseBias.EpochTime[CLOCKORBIT_SATGALILEO] != _phaseBiasSentEpoch[CLOCKORBIT_SATGALILEO]) {
[6854]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 }
[11010]1026 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATQZSS] > 0 &&
1027 _phaseBias.EpochTime[CLOCKORBIT_SATQZSS] != _phaseBiasSentEpoch[CLOCKORBIT_SATQZSS]) {
[6854]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 }
[11010]1036 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATSBAS] > 0 &&
1037 _phaseBias.EpochTime[CLOCKORBIT_SATSBAS] != _phaseBiasSentEpoch[CLOCKORBIT_SATSBAS]) {
[6854]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 }
[11010]1046 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATBDS] > 0 &&
1047 _phaseBias.EpochTime[CLOCKORBIT_SATBDS] != _phaseBiasSentEpoch[CLOCKORBIT_SATBDS]) {
[6854]1048 epoSecBds = _phaseBias.EpochTime[CLOCKORBIT_SATBDS];
1049 }
[6467]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) {
[10534]1064 QDate date = dateAndTimeFromGPSweek(currentTime.gpsw(), currentTime.gpssec()).date();
1065 if (_type == IGSssr) {
[10826]1066 epoSecGlo = epoSecGlo + gnumleap(date.year(), date.month(), date.day());
[10534]1067 }
[11011]1068 if (_type == RTCMssr || _type == RTCMnewssr) {
1069 // Same GLONASS epoch wire convention (UTC+3h) as RTCMssr
[9025]1070 epoSecGlo = epoSecGlo - 3 * 3600 + gnumleap(date.year(), date.month(), date.day());
1071 }
[6467]1072 _lastTime.set(currentWeek, epoSecGlo);
[6468]1073 }
[6854]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) {
[10826]1084 epoSecBds += 14.0;
1085 if (epoSecBds > 604800.0) {
1086 epoSecBds -= 7.0*24.0*60.0*60.0;
[7711]1087 }
[6854]1088 _lastTime.set(currentWeek, epoSecBds);
1089 }
[11011]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 }
[6468]1097
1098 if (_lastTime.valid()) {
[6469]1099 double maxDiff = 12 * 3600.0;
1100 while (_lastTime < currentTime - maxDiff) {
1101 _lastTime = _lastTime + maxDiff;
[6467]1102 }
[6469]1103 while (_lastTime > currentTime + maxDiff) {
1104 _lastTime = _lastTime - maxDiff;
[6467]1105 }
1106 }
1107}
Note: See TracBrowser for help on using the repository browser.