source: ntrip/trunk/BNC/bncgetthread.cpp@ 1382

Last change on this file since 1382 was 1377, checked in by mervart, 16 years ago

* empty log message *

File size: 29.9 KB
RevLine 
[280]1// Part of BNC, a utility for retrieving decoding and
[464]2// converting GNSS data streams from NTRIP broadcasters.
[280]3//
[464]4// Copyright (C) 2007
[280]5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
[464]7// Czech Technical University Prague, Department of Geodesy
[280]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.
[35]24
25/* -------------------------------------------------------------------------
[93]26 * BKG NTRIP Client
[35]27 * -------------------------------------------------------------------------
28 *
29 * Class: bncGetThread
30 *
31 * Purpose: Thread that retrieves data from NTRIP caster
32 *
33 * Author: L. Mervart
34 *
35 * Created: 24-Dec-2005
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
[277]41#include <stdlib.h>
[1044]42#include <iomanip>
[1218]43#include <sstream>
[277]44
[35]45#include <QFile>
46#include <QTextStream>
47#include <QtNetwork>
[356]48#include <QTime>
[35]49
50#include "bncgetthread.h"
[192]51#include "bnctabledlg.h"
[243]52#include "bncapp.h"
[352]53#include "bncutils.h"
[408]54#include "bncrinex.h"
[423]55#include "bnczerodecoder.h"
[1377]56#include "bncnetquery.h"
[65]57
[243]58#include "RTCM/RTCM2Decoder.h"
[297]59#include "RTCM3/RTCM3Decoder.h"
[293]60#include "RTIGS/RTIGSDecoder.h"
[1310]61#include "GPSS/gpssDecoder.h"
[1318]62#include "serial/qextserialport.h"
[35]63
64using namespace std;
65
[1143]66// Constructor 1
[35]67////////////////////////////////////////////////////////////////////////////
[1138]68bncGetThread::bncGetThread(const QByteArray& rawInpFileName,
69 const QByteArray& format) {
70
[1141]71 _format = format;
[1139]72
[1159]73 int iSep = rawInpFileName.lastIndexOf(QDir::separator());
74 _staID = rawInpFileName.mid(iSep+1,4);
75
[1139]76 initialize();
77
78 _inspSegm = 0;
79
[1138]80 _rawInpFile = new QFile(rawInpFileName);
81 _rawInpFile->open(QIODevice::ReadOnly);
[1147]82
83 if (!_rnx) {
84 cerr << "no RINEX path specified" << endl;
85 ::exit(0);
86 }
[1138]87}
88
[1143]89// Constructor 2
90////////////////////////////////////////////////////////////////////////////
[278]91bncGetThread::bncGetThread(const QUrl& mountPoint,
[366]92 const QByteArray& format,
93 const QByteArray& latitude,
94 const QByteArray& longitude,
[1353]95 const QByteArray& nmea,
96 const QByteArray& ntripVersion, int iMount) {
[605]97
98 setTerminationEnabled(true);
99
[350]100 _mountPoint = mountPoint;
101 _staID = mountPoint.path().mid(1).toAscii();
102 _format = format;
[366]103 _latitude = latitude;
104 _longitude = longitude;
105 _nmea = nmea;
[1353]106 _ntripVersion = ntripVersion;
[1139]107 _iMount = iMount; // index in mountpoints array
108
109 initialize();
110}
111
[1143]112// Initialization
113////////////////////////////////////////////////////////////////////////////
[1139]114void bncGetThread::initialize() {
115
[1225]116
117 bncApp* app = (bncApp*) qApp;
[1299]118 app->connect(this, SIGNAL(newMessage(QByteArray,bool)),
119 app, SLOT(slotMessage(const QByteArray,bool)));
[1225]120
[1139]121 _decoder = 0;
[1377]122 _query = 0;
[1139]123 _timeOut = 20*1000; // 20 seconds
124 _nextSleep = 1; // 1 second
[1138]125 _rawInpFile = 0;
[1139]126 _rawOutFile = 0;
[1143]127 _staID_orig = _staID;
[255]128
129 // Check name conflict
130 // -------------------
131 QSettings settings;
132 QListIterator<QString> it(settings.value("mountPoints").toStringList());
133 int num = 0;
[278]134 int ind = -1;
[255]135 while (it.hasNext()) {
[278]136 ++ind;
[255]137 QStringList hlp = it.next().split(" ");
138 if (hlp.size() <= 1) continue;
139 QUrl url(hlp[0]);
140 if (_mountPoint.path() == url.path()) {
[1162]141 if (_iMount > ind || _iMount < 0) {
[278]142 ++num;
[255]143 }
144 }
145 }
[278]146
147 if (num > 0) {
148 _staID = _staID.left(_staID.length()-1) + QString("%1").arg(num).toAscii();
[255]149 }
[408]150
[658]151 // Notice threshold
152 // ----------------
[686]153 _inspSegm = 50;
154 if ( settings.value("obsRate").toString().isEmpty() ) { _inspSegm = 0; }
[692]155 if ( settings.value("obsRate").toString().indexOf("5 Hz") != -1 ) { _inspSegm = 2; }
[686]156 if ( settings.value("obsRate").toString().indexOf("1 Hz") != -1 ) { _inspSegm = 10; }
157 if ( settings.value("obsRate").toString().indexOf("0.5 Hz") != -1 ) { _inspSegm = 20; }
158 if ( settings.value("obsRate").toString().indexOf("0.2 Hz") != -1 ) { _inspSegm = 40; }
159 if ( settings.value("obsRate").toString().indexOf("0.1 Hz") != -1 ) { _inspSegm = 50; }
[668]160 _adviseFail = settings.value("adviseFail").toInt();
161 _adviseReco = settings.value("adviseReco").toInt();
[722]162 _makePause = false;
163 if ( Qt::CheckState(settings.value("makePause").toInt()) == Qt::Checked) {_makePause = true; }
[668]164 _adviseScript = settings.value("adviseScript").toString();
165 expandEnvVar(_adviseScript);
[658]166
[709]167 // Latency interval/average
168 // ------------------------
[728]169 _perfIntr = 86400;
170 if ( settings.value("perfIntr").toString().isEmpty() ) { _perfIntr = 0; }
171 if ( settings.value("perfIntr").toString().indexOf("1 min") != -1 ) { _perfIntr = 60; }
172 if ( settings.value("perfIntr").toString().indexOf("5 min") != -1 ) { _perfIntr = 300; }
173 if ( settings.value("perfIntr").toString().indexOf("15 min") != -1 ) { _perfIntr = 900; }
174 if ( settings.value("perfIntr").toString().indexOf("1 hour") != -1 ) { _perfIntr = 3600; }
175 if ( settings.value("perfIntr").toString().indexOf("6 hours") != -1 ) { _perfIntr = 21600; }
176 if ( settings.value("perfIntr").toString().indexOf("1 day") != -1 ) { _perfIntr = 86400; }
[709]177
[1030]178 // RTCM message types
179 // ------------------
[1307]180 _checkMountPoint = settings.value("miscMount").toString();
[1030]181
[408]182 // RINEX writer
183 // ------------
184 _samplingRate = settings.value("rnxSampl").toInt();
185 if ( settings.value("rnxPath").toString().isEmpty() ) {
186 _rnx = 0;
187 }
188 else {
[1353]189 _rnx = new bncRinex(_staID, _mountPoint, _format, _latitude,
190 _longitude, _nmea, _ntripVersion);
[408]191 }
[1044]192 _rnx_set_position = false;
[408]193
[1168]194 connect(((bncApp*)qApp), SIGNAL(newEphGPS(gpsephemeris)),
195 this, SLOT(slotNewEphGPS(gpsephemeris)));
196
[1327]197 if (settings.value("serialMountPoint").toString() == _staID) {
198 _serialPort = new QextSerialPort(
199 settings.value("serialPortName").toString() );
[1330]200 QString hlp = settings.value("serialBaudRate").toString();
201 if (hlp == "110") {
202 _serialPort->setBaudRate(BAUD110);
203 }
204 else if (hlp == "300") {
205 _serialPort->setBaudRate(BAUD300);
206 }
207 else if (hlp == "600") {
208 _serialPort->setBaudRate(BAUD600);
209 }
210 else if (hlp == "1200") {
211 _serialPort->setBaudRate(BAUD1200);
212 }
213 else if (hlp == "2400") {
214 _serialPort->setBaudRate(BAUD2400);
215 }
216 else if (hlp == "4800") {
217 _serialPort->setBaudRate(BAUD4800);
218 }
219 else if (hlp == "9600") {
220 _serialPort->setBaudRate(BAUD9600);
221 }
222 else if (hlp == "19200") {
223 _serialPort->setBaudRate(BAUD19200);
224 }
225 else if (hlp == "38400") {
226 _serialPort->setBaudRate(BAUD38400);
227 }
228 else if (hlp == "57600") {
229 _serialPort->setBaudRate(BAUD57600);
230 }
231 else if (hlp == "115200") {
232 _serialPort->setBaudRate(BAUD115200);
233 }
234 hlp = settings.value("serialParity").toString();
235 if (hlp == "NONE") {
236 _serialPort->setParity(PAR_NONE);
237 }
238 else if (hlp == "ODD") {
239 _serialPort->setParity(PAR_ODD);
240 }
241 else if (hlp == "EVEN") {
242 _serialPort->setParity(PAR_EVEN);
243 }
244 else if (hlp == "SPACE") {
245 _serialPort->setParity(PAR_SPACE);
246 }
247 hlp = settings.value("serialDataBits").toString();
248 if (hlp == "5") {
249 _serialPort->setDataBits(DATA_5);
250 }
251 else if (hlp == "6") {
252 _serialPort->setDataBits(DATA_6);
253 }
254 else if (hlp == "7") {
255 _serialPort->setDataBits(DATA_7);
256 }
257 else if (hlp == "8") {
258 _serialPort->setDataBits(DATA_8);
259 }
260 hlp = settings.value("serialStopBits").toString();
261 if (hlp == "1") {
262 _serialPort->setStopBits(STOP_1);
263 }
264 else if (hlp == "2") {
265 _serialPort->setStopBits(STOP_2);
266 }
[1326]267 _serialPort->open(QIODevice::ReadWrite|QIODevice::Unbuffered);
[1331]268 if (!_serialPort->isOpen()) {
269 delete _serialPort;
270 _serialPort = 0;
271 emit(newMessage((_staID + ": Cannot Open Serial Port\n"), true));
272 }
[1318]273 }
274 else {
275 _serialPort = 0;
276 }
277
[1137]278 // Raw Output
279 // ----------
[1140]280 // QByteArray rawOutFileName = "./" + _staID + ".raw";
281 // _rawOutFile = new QFile(rawOutFileName);
282 // _rawOutFile->open(QIODevice::WriteOnly);
[1137]283
[319]284 msleep(100); //sleep 0.1 sec
[35]285}
286
287// Destructor
288////////////////////////////////////////////////////////////////////////////
289bncGetThread::~bncGetThread() {
[1377]290 if (_query) {
291 _query->deleteLater();
[515]292 }
[617]293 delete _decoder;
[1044]294 delete _rnx;
[1138]295 delete _rawInpFile;
296 delete _rawOutFile;
[1328]297 delete _serialPort;
[35]298}
299
[136]300// Init Run
[35]301////////////////////////////////////////////////////////////////////////////
[138]302t_irc bncGetThread::initRun() {
[35]303
[1138]304 if (!_rawInpFile) {
[1377]305 delete _query;
306 _query = new bncNetQuery();
307 _query->startRequest(_mountPoint);
[35]308 }
309
310 // Instantiate the filter
311 // ----------------------
[423]312 if (!_decoder) {
[136]313 if (_format.indexOf("RTCM_2") != -1) {
[1299]314 emit(newMessage("Get Data: " + _staID + " in RTCM 2.x format", true));
[1044]315 _decoder = new RTCM2Decoder(_staID.data());
[136]316 }
317 else if (_format.indexOf("RTCM_3") != -1) {
[1299]318 emit(newMessage("Get Data: " + _staID + " in RTCM 3.x format", true));
[880]319 _decoder = new RTCM3Decoder(_staID);
[1299]320 connect((RTCM3Decoder*) _decoder, SIGNAL(newMessage(QByteArray,bool)),
321 this, SIGNAL(newMessage(QByteArray,bool)));
[136]322 }
323 else if (_format.indexOf("RTIGS") != -1) {
[1299]324 emit(newMessage("Get Data: " + _staID + " in RTIGS format", true));
[293]325 _decoder = new RTIGSDecoder();
[136]326 }
[1323]327 else if (_format.indexOf("GPSS") != -1 || _format.indexOf("BNC") != -1) {
[1310]328 emit(newMessage("Get Data: " + _staID + " in GPSS format", true));
329 _decoder = new gpssDecoder();
330 }
[867]331 else if (_format.indexOf("ZERO") != -1) {
[1299]332 emit(newMessage("Get Data: " + _staID + " in original format", true));
[424]333 _decoder = new bncZeroDecoder(_staID);
[406]334 }
[136]335 else {
[1299]336 emit(newMessage(_staID + ": Unknown data format " + _format, true));
[1144]337 if (_rawInpFile) {
[1145]338 cerr << "Uknown data format" << endl;
[1144]339 ::exit(0);
340 }
341 else {
342 return fatal;
343 }
[136]344 }
[60]345 }
[138]346 return success;
[136]347}
[59]348
[136]349// Run
350////////////////////////////////////////////////////////////////////////////
351void bncGetThread::run() {
352
[709]353 const double maxDt = 600.0; // Check observation epoch
[699]354 bool wrongEpoch = false;
355 bool decode = true;
356 int numSucc = 0;
357 int secSucc = 0;
358 int secFail = 0;
[709]359 int initPause = 30; // Initial pause for corrupted streams
[699]360 int currPause = 0;
361 bool begCorrupt = false;
362 bool endCorrupt = false;
[728]363 bool followSec = false;
[717]364 int oldSecGPS= 0;
365 int newSecGPS = 0;
[728]366 int numGaps = 0;
367 int diffSecGPS = 0;
[709]368 int numLat = 0;
369 double sumLat = 0.;
[1052]370 double sumLatQ = 0.;
[728]371 double meanDiff = 0.;
[709]372 double minLat = maxDt;
373 double maxLat = -maxDt;
374 double curLat = 0.;
[699]375
376 _decodeTime = QDateTime::currentDateTime();
377 _decodeSucc = QDateTime::currentDateTime();
[229]378 t_irc irc = initRun();
379
380 if (irc == fatal) {
[192]381 QThread::exit(1);
382 return;
383 }
[229]384 else if (irc != success) {
[1299]385 emit(newMessage(_staID + ": initRun failed, reconnecting", true));
[138]386 tryReconnect();
387 }
[136]388
[658]389 if (initPause < _inspSegm) {
390 initPause = _inspSegm;
391 }
[727]392 if(!_makePause) {initPause = 0;}
[658]393 currPause = initPause;
394
[35]395 // Read Incoming Data
396 // ------------------
397 while (true) {
[629]398 try {
[1377]399 if (_query && _query->status() != bncNetQuery::running) {
400 emit(newMessage(_staID + ": Internet query not running, reconnecting", true));
[629]401 tryReconnect();
402 }
[621]403
404 QListIterator<p_obs> it(_decoder->_obsList);
405 while (it.hasNext()) {
406 delete it.next();
407 }
408 _decoder->_obsList.clear();
409
[1138]410 qint64 nBytes = 0;
411
[1377]412 QByteArray data;
413
414 if (_query) {
415 _query->waitForReadyRead(data);
416 nBytes = data.size();
[1138]417 }
418 else if (_rawInpFile) {
[1146]419 const qint64 maxBytes = 1024;
[1138]420 nBytes = maxBytes;
421 }
422
[249]423 if (nBytes > 0) {
[567]424 emit newBytes(_staID, nBytes);
425
[1377]426 if (_rawInpFile) {
[1368]427 data = _rawInpFile->read(nBytes);
428 if (data.isEmpty()) {
[1138]429 cout << "no more data" << endl;
430 ::exit(0);
431 }
432 }
[1137]433
[1138]434 if (_rawOutFile) {
[1368]435 _rawOutFile->write(data);
[1138]436 _rawOutFile->flush();
437 }
438
[1318]439 if (_serialPort) {
[1368]440 _serialPort->write(data);
[1318]441 }
442
[940]443 if (_inspSegm<1) {
[1218]444 vector<string> errmsg;
[1368]445 _decoder->Decode(data.data(), data.size(), errmsg);
[1218]446#ifdef DEBUG_RTCM2_2021
447 for (unsigned ii = 0; ii < errmsg.size(); ii++) {
[1299]448 emit newMessage(_staID + ": " + errmsg[ii].c_str(), false);
[1218]449 }
450#endif
[940]451 }
452 else {
453
454 // Decode data
455 // -----------
456 if (!_decodePause.isValid() ||
457 _decodePause.secsTo(QDateTime::currentDateTime()) >= currPause ) {
458
459 if (decode) {
[1218]460 vector<string> errmsg;
[1368]461 if ( _decoder->Decode(data.data(), data.size(), errmsg) == success ) {
[940]462 numSucc += 1;
463 }
464 if ( _decodeTime.secsTo(QDateTime::currentDateTime()) > _inspSegm ) {
465 decode = false;
[658]466 }
[1218]467#ifdef DEBUG_RTCM2_2021
468 for (unsigned ii = 0; ii < errmsg.size(); ii++) {
[1299]469 emit newMessage(_staID + ": " + errmsg[ii].c_str(), false);
[1218]470 }
471#endif
[658]472 }
[940]473
474 // Check - once per inspect segment
475 // --------------------------------
476 if (!decode) {
477 _decodeTime = QDateTime::currentDateTime();
478 if (numSucc>0) {
479 secSucc += _inspSegm;
480 _decodeSucc = QDateTime::currentDateTime();
481 if (secSucc > _adviseReco * 60) {
482 secSucc = _adviseReco * 60 + 1;
483 }
484 numSucc = 0;
485 currPause = initPause;
486 _decodePause.setDate(QDate());
487 _decodePause.setTime(QTime());
[658]488 }
[940]489 else {
490 secFail += _inspSegm;
491 secSucc = 0;
492 if (secFail > _adviseFail * 60) {
493 secFail = _adviseFail * 60 + 1;
494 }
495 if (!_decodePause.isValid() || !_makePause) {
496 _decodePause = QDateTime::currentDateTime();
497 }
498 else {
499 _decodePause.setDate(QDate());
500 _decodePause.setTime(QTime());
501 secFail = secFail + currPause - _inspSegm;
502 currPause = currPause * 2;
503 if (currPause > 960) {
504 currPause = 960;
505 }
506 }
[658]507 }
[940]508
509 // End corrupt threshold
510 // ---------------------
511 if ( begCorrupt && !endCorrupt && secSucc > _adviseReco * 60 ) {
512 _endDateCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
513 _endTimeCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
[1299]514 emit(newMessage((_staID + ": Recovery threshold exceeded, corruption ended "
515 + _endDateCor + " " + _endTimeCor).toAscii(), true));
[940]516 callScript(("End_Corrupted " + _endDateCor + " " + _endTimeCor + " Begin was " + _begDateCor + " " + _begTimeCor).toAscii());
517 endCorrupt = true;
518 begCorrupt = false;
519 secFail = 0;
520 }
[658]521 else {
[940]522
523 // Begin corrupt threshold
524 // -----------------------
525 if ( !begCorrupt && secFail > _adviseFail * 60 ) {
526 _begDateCor = _decodeSucc.toUTC().date().toString("yy-MM-dd");
527 _begTimeCor = _decodeSucc.toUTC().time().toString("hh:mm:ss");
[1299]528 emit(newMessage((_staID + ": Failure threshold exceeded, corrupted since "
529 + _begDateCor + " " + _begTimeCor).toAscii(), true));
[940]530 callScript(("Begin_Corrupted " + _begDateCor + " " + _begTimeCor).toAscii());
531 begCorrupt = true;
532 endCorrupt = false;
533 secSucc = 0;
534 numSucc = 0;
[658]535 }
536 }
[940]537 decode = true;
[658]538 }
[650]539 }
540 }
[940]541
542 // End outage threshold
543 // --------------------
544 if ( _decodeStart.isValid() && _decodeStart.secsTo(QDateTime::currentDateTime()) > _adviseReco * 60 ) {
545 _decodeStart.setDate(QDate());
546 _decodeStart.setTime(QTime());
547 if (_inspSegm>0) {
548 _endDateOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
549 _endTimeOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
[1299]550 emit(newMessage((_staID + ": Recovery threshold exceeded, outage ended "
551 + _endDateOut + " " + _endTimeOut).toAscii(), true));
[940]552 callScript(("End_Outage " + _endDateOut + " " + _endTimeOut + " Begin was " + _begDateOut + " " + _begTimeOut).toAscii());
553 }
[686]554 }
[658]555
[1271]556 // RTCM scan output
557 // ----------------
558 if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
[1307]559 QSettings settings;
560 if ( Qt::CheckState(settings.value("scanRTCM").toInt()) == Qt::Checked) {
[1271]561
[1307]562 // RTCMv3 message types
563 // --------------------
564 if (0<_decoder->_typeList.size()) {
565 QString type;
566 for (int ii=0;ii<_decoder->_typeList.size();ii++) {
567 type = QString("%1 ").arg(_decoder->_typeList[ii]);
568 emit(newMessage(_staID + ": Received message type " + type.toAscii(), true));
569 }
[1271]570 }
[1307]571
572 // RTCMv3 antenna descriptor
573 // -------------------------
574 if (0<_decoder->_antType.size()) {
575 QString ant1;
576 for (int ii=0;ii<_decoder->_antType.size();ii++) {
577 ant1 = QString("%1 ").arg(_decoder->_antType[ii]);
578 emit(newMessage(_staID + ": Antenna descriptor " + ant1.toAscii(), true));
579 }
[1271]580 }
[1307]581
582 // Antenna XYZ
583 // ------------------
584 if (0<_decoder->_antList.size()) {
585 for (int ii=0;ii<_decoder->_antList.size();++ii) {
586 QByteArray ant1,ant2,ant3, antT;
587 ant1 = QString("%1 ").arg(_decoder->_antList[ii].xx,0,'f',4).toAscii();
588 ant2 = QString("%1 ").arg(_decoder->_antList[ii].yy,0,'f',4).toAscii();
589 ant3 = QString("%1 ").arg(_decoder->_antList[ii].zz,0,'f',4).toAscii();
590 switch (_decoder->_antList[ii].type) {
591 case GPSDecoder::t_antInfo::ARP: antT = "ARP"; break;
592 case GPSDecoder::t_antInfo::APC: antT = "APC"; break;
593 }
594 emit(newMessage(_staID + ": " + antT + " (ITRF) X " + ant1 + "m", true));
595 emit(newMessage(_staID + ": " + antT + " (ITRF) Y " + ant2 + "m", true));
596 emit(newMessage(_staID + ": " + antT + " (ITRF) Z " + ant3 + "m", true));
597 if (_decoder->_antList[ii].height_f) {
598 QByteArray ant4 = QString("%1 ").arg(_decoder->_antList[ii].height,0,'f',4).toAscii();
599 emit(newMessage(_staID + ": Antenna height above marker " + ant4 + "m", true));
600 }
601 emit(newAntCrd(_staID,
602 _decoder->_antList[ii].xx, _decoder->_antList[ii].yy, _decoder->_antList[ii].zz,
603 antT));
604 }
605 }
[1271]606 }
[1307]607 if ( _checkMountPoint == "ANTCRD_ONLY" && _decoder->_antList.size() ) {
608 for (int ii=0;ii<_decoder->_antList.size();++ii) {
609 QByteArray antT;
[1271]610 switch (_decoder->_antList[ii].type) {
611 case GPSDecoder::t_antInfo::ARP: antT = "ARP"; break;
612 case GPSDecoder::t_antInfo::APC: antT = "APC"; break;
613 }
614 emit(newAntCrd(_staID,
[1307]615 _decoder->_antList[ii].xx, _decoder->_antList[ii].yy, _decoder->_antList[ii].zz,
616 antT));
617 }
[1271]618 }
619 }
620
621 _decoder->_typeList.clear();
622 _decoder->_antType.clear();
623 _decoder->_antList.clear();
624
625 // Loop over all observations (observations output)
626 // ------------------------------------------------
[621]627 QListIterator<p_obs> it(_decoder->_obsList);
628 while (it.hasNext()) {
629 p_obs obs = it.next();
630
[351]631 // Check observation epoch
632 // -----------------------
[1320]633 if (!_rawInpFile && !dynamic_cast<gpssDecoder*>(_decoder)) {
[1142]634 int week;
635 double sec;
[1153]636 currentGPSWeeks(week, sec);
[1142]637 const double secPerWeek = 7.0 * 24.0 * 3600.0;
638
639 if (week < obs->_o.GPSWeek) {
640 week += 1;
641 sec -= secPerWeek;
[658]642 }
[1142]643 if (week > obs->_o.GPSWeek) {
644 week -= 1;
645 sec += secPerWeek;
646 }
647 double dt = fabs(sec - obs->_o.GPSWeeks);
648 if (week != obs->_o.GPSWeek || dt > maxDt) {
649 if (!wrongEpoch) {
[1299]650 emit( newMessage(_staID + ": Wrong observation epoch(s)", true) );
[1142]651 wrongEpoch = true;
652 }
653 delete obs;
654 continue;
655 }
656 else {
657 wrongEpoch = false;
658
659 // Latency and completeness
660 // ------------------------
661 if (_perfIntr>0) {
[1307]662 if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
663 newSecGPS = static_cast<int>(obs->_o.GPSWeeks);
664 if (newSecGPS != oldSecGPS) {
665 if (newSecGPS % _perfIntr < oldSecGPS % _perfIntr) {
666 if (numLat>0) {
667 if (meanDiff>0.) {
668 emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs, %7 gaps")
669 .arg(_staID.data())
670 .arg(int(sumLat/numLat*100)/100.)
671 .arg(int(minLat*100)/100.)
672 .arg(int(maxLat*100)/100.)
673 .arg(int((sqrt((sumLatQ - sumLat * sumLat / numLat)/numLat))*100)/100.)
674 .arg(numLat)
675 .arg(numGaps)
676 .toAscii(), true) );
677 } else {
678 emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs")
679 .arg(_staID.data())
680 .arg(int(sumLat/numLat*100)/100.)
681 .arg(int(minLat*100)/100.)
682 .arg(int(maxLat*100)/100.)
683 .arg(int((sqrt((sumLatQ - sumLat * sumLat / numLat)/numLat))*100)/100.)
684 .arg(numLat)
685 .toAscii(), true) );
686 }
[1142]687 }
[1307]688 meanDiff = diffSecGPS/numLat;
689 diffSecGPS = 0;
690 numGaps = 0;
691 sumLat = 0.;
692 sumLatQ = 0.;
693 numLat = 0;
694 minLat = maxDt;
695 maxLat = -maxDt;
[728]696 }
[1307]697 if (followSec) {
698 diffSecGPS += newSecGPS - oldSecGPS;
699 if (meanDiff>0.) {
700 if (newSecGPS - oldSecGPS > 1.5 * meanDiff) {
701 numGaps += 1;
702 }
[1142]703 }
[728]704 }
[1307]705 curLat = sec - obs->_o.GPSWeeks;
706 sumLat += curLat;
707 sumLatQ += curLat * curLat;
708 if (curLat < minLat) minLat = curLat;
709 if (curLat >= maxLat) maxLat = curLat;
710 numLat += 1;
711 oldSecGPS = newSecGPS;
712 followSec = true;
[728]713 }
714 }
[709]715 }
716 }
[658]717 }
[351]718
[408]719 // RINEX Output
720 // ------------
721 if (_rnx) {
[1044]722 bool dump = true;
723
[1268]724 //// // RTCMv2 XYZ
725 //// // ----------
726 //// RTCM2Decoder* decoder2 = dynamic_cast<RTCM2Decoder*>(_decoder);
727 //// if ( decoder2 && !_rnx_set_position ) {
728 //// double stax, stay, staz;
729 //// double dL1[3], dL2[3];
730 //// if ( decoder2->getStaCrd(stax, stay, staz,
731 //// dL1[0], dL1[1], dL1[2],
732 //// dL2[0], dL2[1], dL2[2]) == success ) {
733 ////
734 //// if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
735 //// QString ant1;
736 //// ant1 = QString("%1 ").arg(stax,0,'f',4);
737 //// emit(newMessage(_staID + ": ARP X " + ant1.toAscii() + "m" ));
738 //// ant1 = QString("%1 ").arg(stay,0,'f',4);
739 //// emit(newMessage(_staID + ": ARP Y " + ant1.toAscii() + "m" ));
740 //// ant1 = QString("%1 ").arg(staz,0,'f',4);
741 //// emit(newMessage(_staID + ": ARP Z " + ant1.toAscii() + "m" ));
742 //// ant1 = QString("%1 ").arg(dL1[0],0,'f',4);
743 //// emit(newMessage(_staID + ": L1 APC DX " + ant1.toAscii() + "m" ));
744 //// ant1 = QString("%1 ").arg(dL1[1],0,'f',4);
745 //// emit(newMessage(_staID + ": L1 APC DY " + ant1.toAscii() + "m" ));
746 //// ant1 = QString("%1 ").arg(dL1[2],0,'f',4);
747 //// emit(newMessage(_staID + ": L1 APC DZ " + ant1.toAscii() + "m" ));
748 //// ant1 = QString("%1 ").arg(dL2[0],0,'f',4);
749 //// emit(newMessage(_staID + ": L2 APC DX " + ant1.toAscii() + "m" ));
750 //// ant1 = QString("%1 ").arg(dL2[1],0,'f',4);
751 //// emit(newMessage(_staID + ": L2 APC DY " + ant1.toAscii() + "m" ));
752 //// ant1 = QString("%1 ").arg(dL2[2],0,'f',4);
753 //// emit(newMessage(_staID + ": L2 APC DZ " + ant1.toAscii() + "m" ));
754 //// }
755 //// _rnx_set_position = true;
756 //// }
757 //// }
[1218]758
[1044]759 if ( dump ) {
760 long iSec = long(floor(obs->_o.GPSWeeks+0.5));
761 long newTime = obs->_o.GPSWeek * 7*24*3600 + iSec;
762 if (_samplingRate == 0 || iSec % _samplingRate == 0) {
763 _rnx->deepCopy(obs);
764 }
765 _rnx->dumpEpoch(newTime);
[1029]766 }
767 }
[408]768
[1044]769 // Emit new observation signal
770 // ---------------------------
[621]771 bool firstObs = (obs == _decoder->_obsList.first());
[624]772 obs->_status = t_obs::posted;
[621]773 emit newObs(_staID, firstObs, obs);
[249]774 }
775 _decoder->_obsList.clear();
[1030]776
[249]777 }
[1030]778
779 // Timeout, reconnect
780 // ------------------
[249]781 else {
[1299]782 emit(newMessage(_staID + ": Data Timeout, reconnecting", true));
[249]783 tryReconnect();
784 }
[35]785 }
[249]786 catch (const char* msg) {
[1299]787 emit(newMessage(_staID + msg, true));
[136]788 tryReconnect();
[35]789 }
790 }
791}
792
793// Exit
794////////////////////////////////////////////////////////////////////////////
795void bncGetThread::exit(int exitCode) {
796 if (exitCode!= 0) {
[88]797 emit error(_staID);
[35]798 }
799 QThread::exit(exitCode);
[148]800 terminate();
[35]801}
[82]802
[136]803// Try Re-Connect
804////////////////////////////////////////////////////////////////////////////
805void bncGetThread::tryReconnect() {
[408]806 if (_rnx) {
807 _rnx->setReconnectFlag(true);
808 }
[658]809 if ( !_decodeStart.isValid()) {
810 _decodeStop = QDateTime::currentDateTime();
811 }
[138]812 while (1) {
813 sleep(_nextSleep);
814 if ( initRun() == success ) {
[658]815 if ( !_decodeStop.isValid()) {
816 _decodeStart = QDateTime::currentDateTime();
817 }
[138]818 break;
819 }
820 else {
[658]821
822 // Begin outage threshold
823 // ----------------------
[668]824 if ( _decodeStop.isValid() && _decodeStop.secsTo(QDateTime::currentDateTime()) > _adviseFail * 60 ) {
[658]825 _decodeStop.setDate(QDate());
826 _decodeStop.setTime(QTime());
[686]827 if (_inspSegm>0) {
[699]828 _begDateOut = _decodeTime.toUTC().date().toString("yy-MM-dd");
829 _begTimeOut = _decodeTime.toUTC().time().toString("hh:mm:ss");
[1299]830 emit(newMessage((_staID + ": Failure threshold exceeded, outage since "
831 + _begDateOut + " " + _begTimeOut).toAscii(), true));
[696]832 callScript(("Begin_Outage " + _begDateOut + " " + _begTimeOut).toAscii());
[686]833 }
[658]834 }
[138]835 _nextSleep *= 2;
[442]836 if (_nextSleep > 256) {
837 _nextSleep = 256;
[152]838 }
[277]839 _nextSleep += rand() % 6;
[138]840 }
841 }
842 _nextSleep = 1;
[136]843}
[658]844
[668]845// Call advisory notice script
[658]846////////////////////////////////////////////////////////////////////////////
847void bncGetThread::callScript(const char* _comment) {
[672]848 QMutexLocker locker(&_mutex);
[668]849 if (!_adviseScript.isEmpty()) {
[672]850 msleep(1);
[658]851#ifdef WIN32
[668]852 QProcess::startDetached(_adviseScript, QStringList() << _staID << _comment) ;
[658]853#else
[668]854 QProcess::startDetached("nohup", QStringList() << _adviseScript << _staID << _comment) ;
[658]855#endif
856 }
857}
[1044]858
859//
860//////////////////////////////////////////////////////////////////////////////
861void bncGetThread::slotNewEphGPS(gpsephemeris gpseph) {
862 RTCM2Decoder* decoder = dynamic_cast<RTCM2Decoder*>(_decoder);
863
864 if ( decoder ) {
865 QMutexLocker locker(&_mutex);
866
[1218]867 string storedPRN;
868 vector<int> IODs;
869
870 if ( decoder->storeEph(gpseph, storedPRN, IODs) ) {
871#ifdef DEBUG_RTCM2_2021
872 QString msg = _staID + QString(": stored eph %1 IODs").arg(storedPRN.c_str());
873
874 for (unsigned ii = 0; ii < IODs.size(); ii++) {
875 msg += QString(" %1").arg(IODs[ii],4);
876 }
877
[1299]878 emit(newMessage(msg.toAscii(), false));
[1218]879#endif
880 }
[1044]881 }
882}
883
Note: See TracBrowser for help on using the repository browser.