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

Last change on this file since 6177 was 6177, checked in by mervart, 10 years ago
File size: 12.0 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)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: RTCM3coDecoder
30 *
31 * Purpose: RTCM3 Clock Orbit Decoder
32 *
33 * Author: L. Mervart
34 *
35 * Created: 05-May-2008
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
[868]41#include <stdio.h>
[920]42#include <math.h>
[868]43
[866]44#include "RTCM3coDecoder.h"
[918]45#include "bncutils.h"
[934]46#include "bncrinex.h"
[5070]47#include "bnccore.h"
[1535]48#include "bncsettings.h"
[1834]49#include "rtcm3torinex.h"
[4428]50#include "bnctime.h"
[866]51
52using namespace std;
53
54// Constructor
55////////////////////////////////////////////////////////////////////////////
[970]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
[5124]73 qRegisterMetaType<bncTime>("bncTime");
[6141]74 qRegisterMetaType< QList<t_orbCorr> >("QList:t_orbCorr");
75 qRegisterMetaType< QList<t_clkCorr> >("QList:t_clkCorr");
[5124]76
[6141]77 connect(this, SIGNAL(newOrbCorrections(QList<t_orbCorr>)),
78 BNC_CORE, SLOT(slotNewOrbCorrections(QList<t_orbCorr>)));
[1828]79
[6141]80 connect(this, SIGNAL(newClkCorrections(QList<t_clkCorr>)),
81 BNC_CORE, SLOT(slotNewClkCorrections(QList<t_clkCorr>)));
82
[5577]83 connect(this, SIGNAL(providerIDChanged(QString)),
84 BNC_CORE, SIGNAL(providerIDChanged(QString)));
85
[4428]86 connect(this, SIGNAL(newMessage(QByteArray,bool)),
[5068]87 BNC_CORE, SLOT(slotMessage(const QByteArray,bool)));
[4428]88
[1828]89 memset(&_co, 0, sizeof(_co));
[3077]90 memset(&_bias, 0, sizeof(_bias));
[5576]91
92 _providerID[0] = -1;
93 _providerID[1] = -1;
94 _providerID[2] = -1;
[866]95}
96
97// Destructor
98////////////////////////////////////////////////////////////////////////////
99RTCM3coDecoder::~RTCM3coDecoder() {
[935]100 delete _out;
[866]101}
102
[934]103// Reopen Output File
104////////////////////////////////////////////////////////////////////////
[6141]105void RTCM3coDecoder::reopen() {
[934]106
[6141]107 if (!_fileNameSkl.isEmpty()) {
[934]108
[1535]109 bncSettings settings;
[934]110
[1154]111 QDateTime datTim = currentDateAndTimeGPS();
[934]112
113 QString hlpStr = bncRinex::nextEpochStr(datTim,
114 settings.value("corrIntr").toString());
115
[6141]116 QString fileNameHlp = _fileNameSkl
[934]117 + QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0'))
[938]118 + hlpStr + datTim.toString(".yyC");
[934]119
[6141]120 if (_fileName == fileNameHlp) {
[934]121 return;
122 }
123 else {
[6141]124 _fileName = fileNameHlp;
[934]125 }
126
[6141]127 delete _out;
[1727]128 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked) {
[6141]129 _out = new ofstream( _fileName.toAscii().data(), ios_base::out | ios_base::app );
[1727]130 }
131 else {
[6141]132 _out = new ofstream( _fileName.toAscii().data() );
[1727]133 }
[934]134 }
135}
136
[866]137//
138////////////////////////////////////////////////////////////////////////////
[1227]139t_irc RTCM3coDecoder::Decode(char* buffer, int bufLen, vector<string>& errmsg) {
[868]140
[1218]141 errmsg.clear();
142
[1227]143 _buffer.append(QByteArray(buffer,bufLen));
[868]144
[1023]145 t_irc retCode = failure;
146
[1832]147 while(_buffer.size()) {
148
[879]149 int bytesused = 0;
[1832]150 struct ClockOrbit co_sav;
151 memcpy(&co_sav, &_co, sizeof(co_sav)); // save state
[1829]152
[5665]153 GCOB_RETURN irc = GetSSR(&_co, &_bias, 0, 0, _buffer.data(),
[879]154 _buffer.size(), &bytesused);
155
[1833]156 if (irc <= -30) { // not enough data - restore state and exit loop
[1832]157 memcpy(&_co, &co_sav, sizeof(co_sav));
[1833]158 break;
[869]159 }
[1832]160
[1833]161 else if (irc < 0) { // error - skip 1 byte and retry
162 memset(&_co, 0, sizeof(_co));
[1842]163 memset(&_bias, 0, sizeof(_bias));
164 _buffer = _buffer.mid(bytesused ? bytesused : 1);
[1833]165 }
166
167 else { // OK or MESSAGEFOLLOWS
[1828]168 _buffer = _buffer.mid(bytesused);
169
[4900]170 if ( (irc == GCOBR_OK || irc == GCOBR_MESSAGEFOLLOWS ) &&
[5665]171 (_co.NumberOfSat[CLOCKORBIT_SATGPS] > 0 || _co.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0 ||
172 _bias.NumberOfSat[CLOCKORBIT_SATGPS] > 0 || _bias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) ) {
[2435]173
[6141]174 reopen();
[1835]175
176 // Guess GPS week and sec using system time
177 // ----------------------------------------
[1829]178 int GPSweek;
[1835]179 double GPSweeksHlp;
180 currentGPSWeeks(GPSweek, GPSweeksHlp);
181
182 // Correction Epoch from GPSEpochTime
183 // ----------------------------------
[5665]184 if (_co.NumberOfSat[CLOCKORBIT_SATGPS] > 0 || _bias.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
185 int GPSEpochTime = (_co.NumberOfSat[CLOCKORBIT_SATGPS] > 0) ?
186 _co.EpochTime[CLOCKORBIT_SATGPS] : _bias.EpochTime[CLOCKORBIT_SATGPS];
[3427]187 if (GPSweeksHlp > GPSEpochTime + 86400.0) {
[919]188 GPSweek += 1;
189 }
[3427]190 else if (GPSweeksHlp < GPSEpochTime - 86400.0) {
[919]191 GPSweek -= 1;
192 }
[6141]193 _lastTime.set(GPSweek, double(GPSEpochTime));
[919]194 }
[1835]195
196 // Correction Epoch from Glonass Epoch
197 // -----------------------------------
[5665]198 else if (_co.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0 || _bias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0){
199 int GLONASSEpochTime = (_co.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) ?
200 _co.EpochTime[CLOCKORBIT_SATGLONASS] : _bias.EpochTime[CLOCKORBIT_SATGLONASS];
[1834]201
202 // Second of day (GPS time) from Glonass Epoch
203 // -------------------------------------------
[1835]204 QDate date = dateAndTimeFromGPSweek(GPSweek, GPSweeksHlp).date();
[1834]205 int leapSecond = gnumleap(date.year(), date.month(), date.day());
[3427]206 int GPSDaySec = GLONASSEpochTime - 3 * 3600 + leapSecond;
[1834]207
[1835]208 int weekDay = int(GPSweeksHlp/86400.0);
209 int GPSDaySecHlp = int(GPSweeksHlp) - weekDay * 86400;
[1834]210
211 // Handle the difference between system clock and correction epoch
212 // ---------------------------------------------------------------
213 if (GPSDaySec < GPSDaySecHlp - 3600) {
[1829]214 weekDay += 1;
[1835]215 if (weekDay > 6) {
216 weekDay = 0;
217 GPSweek += 1;
218 }
[1829]219 }
[1834]220 else if (GPSDaySec > GPSDaySecHlp + 3600) {
[1829]221 weekDay -= 1;
[1835]222 if (weekDay < 0) {
223 weekDay = 6;
224 GPSweek -= 1;
225 }
[1834]226 }
[6141]227 _lastTime.set(GPSweek, weekDay * 86400.0 + GPSDaySec);
[1829]228 }
[918]229
[5576]230 checkProviderID();
231
[6141]232 sendResults();
[3022]233
[6141]234 retCode = success;
[1852]235
[1829]236 memset(&_co, 0, sizeof(_co));
[1842]237 memset(&_bias, 0, sizeof(_bias));
[869]238 }
[1829]239 }
[1833]240 }
[1832]241
[1829]242 return retCode;
[866]243}
[934]244
245//
246////////////////////////////////////////////////////////////////////////////
[6141]247void RTCM3coDecoder::sendResults() {
[934]248
[6141]249 QList<t_orbCorr> orbCorrections;
250 QList<t_clkCorr> clkCorrections;
[4428]251
[3022]252 // Loop over all satellites (GPS and Glonass)
253 // ------------------------------------------
[6141]254 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS + _co.NumberOfSat[CLOCKORBIT_SATGLONASS]; ii++) {
[3022]255 char sysCh = ' ';
[6141]256 if (ii < _co.NumberOfSat[CLOCKORBIT_SATGPS]) {
[3022]257 sysCh = 'G';
258 }
259 else if (ii >= CLOCKORBIT_NUMGPS) {
260 sysCh = 'R';
261 }
[6141]262 else {
263 continue;
264 }
[3024]265
[6141]266 // Orbit correction
267 // ----------------
268 if ( _co.messageType == COTYPE_GPSCOMBINED ||
269 _co.messageType == COTYPE_GLONASSCOMBINED ||
270 _co.messageType == COTYPE_GPSORBIT ||
271 _co.messageType == COTYPE_GLONASSORBIT ) {
[3022]272
[6141]273 t_orbCorr orbCorr;
274 orbCorr._prn.set(sysCh, _co.Sat[ii].ID);
275 orbCorr._staID = _staID.toAscii().data();
276 orbCorr._iod = _co.Sat[ii].IOD;
277 orbCorr._time = _lastTime;
278 orbCorr._system = 'R';
279 orbCorr._xr[0] = _co.Sat[ii].Orbit.DeltaRadial;
280 orbCorr._xr[1] = _co.Sat[ii].Orbit.DeltaAlongTrack;
281 orbCorr._xr[2] = _co.Sat[ii].Orbit.DeltaCrossTrack;
282 orbCorr._dotXr[0] = _co.Sat[ii].Orbit.DotDeltaRadial;
283 orbCorr._dotXr[1] = _co.Sat[ii].Orbit.DotDeltaAlongTrack;
284 orbCorr._dotXr[2] = _co.Sat[ii].Orbit.DotDeltaCrossTrack;
[3022]285
[6141]286 orbCorrections.push_back(orbCorr);
[3022]287
[6141]288 _IODs[orbCorr._prn.toString()] = _co.Sat[ii].IOD;
289 }
[3022]290
[6141]291 if ( _co.messageType == COTYPE_GPSCOMBINED ||
292 _co.messageType == COTYPE_GLONASSCOMBINED ||
293 _co.messageType == COTYPE_GPSCLOCK ||
294 _co.messageType == COTYPE_GLONASSCLOCK ) {
[3022]295
[6141]296 t_clkCorr clkCorr;
297 clkCorr._prn.set(sysCh, _co.Sat[ii].ID);
298 clkCorr._staID = _staID.toAscii().data();
299 clkCorr._time = _lastTime;
[6142]300 clkCorr._dClk = _co.Sat[ii].Clock.DeltaA0 / t_CST::c;
301 clkCorr._dotDClk = _co.Sat[ii].Clock.DeltaA1 / t_CST::c;
302 clkCorr._dotDotDClk = _co.Sat[ii].Clock.DeltaA2 / t_CST::c;
[6141]303 clkCorr._clkPartial = 0.0;
[3022]304
[6141]305 if (_IODs.contains(clkCorr._prn.toString())) {
306 clkCorr._iod = _IODs[clkCorr._prn.toString()];
307 clkCorrections.push_back(clkCorr);
[3022]308 }
309 }
[6141]310
311 // High-Resolution Clocks
312 // ----------------------
313 if ( _co.messageType == COTYPE_GPSHR ||
314 _co.messageType == COTYPE_GLONASSHR ) {
315 }
[3022]316 }
317
318 // Loop over all satellites (GPS and Glonass)
319 // ------------------------------------------
[6141]320 QList<t_satBias> satBiases;
321 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS + _bias.NumberOfSat[CLOCKORBIT_SATGLONASS]; ii++) {
322 char sysCh = ' ';
323 if (ii < _bias.NumberOfSat[CLOCKORBIT_SATGPS]) {
324 sysCh = 'G';
[3022]325 }
[6141]326 else if (ii >= CLOCKORBIT_NUMGPS) {
327 sysCh = 'R';
[3022]328 }
[6141]329 else {
330 continue;
331 }
332 t_satBias satBias;
333 satBias._prn.set(sysCh, _bias.Sat[ii].ID);
334 satBias._time = _lastTime;
335 satBias._nx = 0;
336 satBias._jumpCount = 0;
337 for (unsigned jj = 0; jj < _bias.Sat[ii].NumberOfCodeBiases; jj++) {
338 }
[3022]339 }
340
[6141]341 if (orbCorrections.size() > 0) {
342 emit newOrbCorrections(orbCorrections);
343 }
344 if (clkCorrections.size() > 0) {
345 emit newClkCorrections(clkCorrections);
346 }
347 if (_out) {
348 QListIterator<t_orbCorr> itOrb(orbCorrections);
349 while (itOrb.hasNext()) {
350 const t_orbCorr& orbCorr = itOrb.next();
[6177]351 *_out << orbCorr.toLine();
[6141]352 }
353 QListIterator<t_clkCorr> itClk(clkCorrections);
354 while (itClk.hasNext()) {
355 const t_clkCorr& clkCorr = itClk.next();
[6177]356 *_out << clkCorr.toLine();
[6141]357 }
358 _out->flush();
359 }
[3022]360}
[5576]361
362//
363////////////////////////////////////////////////////////////////////////////
364void RTCM3coDecoder::checkProviderID() {
365
366 if (_co.SSRProviderID == 0 && _co.SSRSolutionID == 0 && _co.SSRIOD == 0) {
367 return;
368 }
369
370 int newProviderID[3];
371 newProviderID[0] = _co.SSRProviderID;
372 newProviderID[1] = _co.SSRSolutionID;
373 newProviderID[2] = _co.SSRIOD;
374
375 bool alreadySet = false;
376 bool different = false;
377
378 for (unsigned ii = 0; ii < 3; ii++) {
379 if (_providerID[ii] != -1) {
380 alreadySet = true;
381 }
382 if (_providerID[ii] != newProviderID[ii]) {
383 different = true;
384 }
385 _providerID[ii] = newProviderID[ii];
386 }
387
388 if (alreadySet && different) {
[5580]389 emit newMessage("RTCM3coDecoder: Provider Changed " + _staID.toAscii() + "\n", true);
[5577]390 emit providerIDChanged(_staID);
[5576]391 }
392}
Note: See TracBrowser for help on using the repository browser.