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

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

* empty log message *

File size: 29.9 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://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: 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
41#include <stdlib.h>
42#include <iomanip>
43#include <sstream>
44
45#include <QFile>
46#include <QTextStream>
47#include <QtNetwork>
48#include <QTime>
49
50#include "bncgetthread.h"
51#include "bnctabledlg.h"
52#include "bncapp.h"
53#include "bncutils.h"
54#include "bncrinex.h"
55#include "bnczerodecoder.h"
56#include "bncnetquery.h"
57
58#include "RTCM/RTCM2Decoder.h"
59#include "RTCM3/RTCM3Decoder.h"
60#include "RTIGS/RTIGSDecoder.h"
61#include "GPSS/gpssDecoder.h"
62#include "serial/qextserialport.h"
63
64using namespace std;
65
66// Constructor 1
67////////////////////////////////////////////////////////////////////////////
68bncGetThread::bncGetThread(const QByteArray& rawInpFileName,
69 const QByteArray& format) {
70
71 _format = format;
72
73 int iSep = rawInpFileName.lastIndexOf(QDir::separator());
74 _staID = rawInpFileName.mid(iSep+1,4);
75
76 initialize();
77
78 _inspSegm = 0;
79
80 _rawInpFile = new QFile(rawInpFileName);
81 _rawInpFile->open(QIODevice::ReadOnly);
82
83 if (!_rnx) {
84 cerr << "no RINEX path specified" << endl;
85 ::exit(0);
86 }
87}
88
89// Constructor 2
90////////////////////////////////////////////////////////////////////////////
91bncGetThread::bncGetThread(const QUrl& mountPoint,
92 const QByteArray& format,
93 const QByteArray& latitude,
94 const QByteArray& longitude,
95 const QByteArray& nmea,
96 const QByteArray& ntripVersion, int iMount) {
97
98 setTerminationEnabled(true);
99
100 _mountPoint = mountPoint;
101 _staID = mountPoint.path().mid(1).toAscii();
102 _format = format;
103 _latitude = latitude;
104 _longitude = longitude;
105 _nmea = nmea;
106 _ntripVersion = ntripVersion;
107 _iMount = iMount; // index in mountpoints array
108
109 initialize();
110}
111
112// Initialization
113////////////////////////////////////////////////////////////////////////////
114void bncGetThread::initialize() {
115
116
117 bncApp* app = (bncApp*) qApp;
118 app->connect(this, SIGNAL(newMessage(QByteArray,bool)),
119 app, SLOT(slotMessage(const QByteArray,bool)));
120
121 _decoder = 0;
122 _query = 0;
123 _timeOut = 20*1000; // 20 seconds
124 _nextSleep = 1; // 1 second
125 _rawInpFile = 0;
126 _rawOutFile = 0;
127 _staID_orig = _staID;
128
129 // Check name conflict
130 // -------------------
131 QSettings settings;
132 QListIterator<QString> it(settings.value("mountPoints").toStringList());
133 int num = 0;
134 int ind = -1;
135 while (it.hasNext()) {
136 ++ind;
137 QStringList hlp = it.next().split(" ");
138 if (hlp.size() <= 1) continue;
139 QUrl url(hlp[0]);
140 if (_mountPoint.path() == url.path()) {
141 if (_iMount > ind || _iMount < 0) {
142 ++num;
143 }
144 }
145 }
146
147 if (num > 0) {
148 _staID = _staID.left(_staID.length()-1) + QString("%1").arg(num).toAscii();
149 }
150
151 // Notice threshold
152 // ----------------
153 _inspSegm = 50;
154 if ( settings.value("obsRate").toString().isEmpty() ) { _inspSegm = 0; }
155 if ( settings.value("obsRate").toString().indexOf("5 Hz") != -1 ) { _inspSegm = 2; }
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; }
160 _adviseFail = settings.value("adviseFail").toInt();
161 _adviseReco = settings.value("adviseReco").toInt();
162 _makePause = false;
163 if ( Qt::CheckState(settings.value("makePause").toInt()) == Qt::Checked) {_makePause = true; }
164 _adviseScript = settings.value("adviseScript").toString();
165 expandEnvVar(_adviseScript);
166
167 // Latency interval/average
168 // ------------------------
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; }
177
178 // RTCM message types
179 // ------------------
180 _checkMountPoint = settings.value("miscMount").toString();
181
182 // RINEX writer
183 // ------------
184 _samplingRate = settings.value("rnxSampl").toInt();
185 if ( settings.value("rnxPath").toString().isEmpty() ) {
186 _rnx = 0;
187 }
188 else {
189 _rnx = new bncRinex(_staID, _mountPoint, _format, _latitude,
190 _longitude, _nmea, _ntripVersion);
191 }
192 _rnx_set_position = false;
193
194 connect(((bncApp*)qApp), SIGNAL(newEphGPS(gpsephemeris)),
195 this, SLOT(slotNewEphGPS(gpsephemeris)));
196
197 if (settings.value("serialMountPoint").toString() == _staID) {
198 _serialPort = new QextSerialPort(
199 settings.value("serialPortName").toString() );
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 }
267 _serialPort->open(QIODevice::ReadWrite|QIODevice::Unbuffered);
268 if (!_serialPort->isOpen()) {
269 delete _serialPort;
270 _serialPort = 0;
271 emit(newMessage((_staID + ": Cannot Open Serial Port\n"), true));
272 }
273 }
274 else {
275 _serialPort = 0;
276 }
277
278 // Raw Output
279 // ----------
280 // QByteArray rawOutFileName = "./" + _staID + ".raw";
281 // _rawOutFile = new QFile(rawOutFileName);
282 // _rawOutFile->open(QIODevice::WriteOnly);
283
284 msleep(100); //sleep 0.1 sec
285}
286
287// Destructor
288////////////////////////////////////////////////////////////////////////////
289bncGetThread::~bncGetThread() {
290 if (_query) {
291 _query->deleteLater();
292 }
293 delete _decoder;
294 delete _rnx;
295 delete _rawInpFile;
296 delete _rawOutFile;
297 delete _serialPort;
298}
299
300// Init Run
301////////////////////////////////////////////////////////////////////////////
302t_irc bncGetThread::initRun() {
303
304 if (!_rawInpFile) {
305 delete _query;
306 _query = new bncNetQuery();
307 _query->startRequest(_mountPoint);
308 }
309
310 // Instantiate the filter
311 // ----------------------
312 if (!_decoder) {
313 if (_format.indexOf("RTCM_2") != -1) {
314 emit(newMessage("Get Data: " + _staID + " in RTCM 2.x format", true));
315 _decoder = new RTCM2Decoder(_staID.data());
316 }
317 else if (_format.indexOf("RTCM_3") != -1) {
318 emit(newMessage("Get Data: " + _staID + " in RTCM 3.x format", true));
319 _decoder = new RTCM3Decoder(_staID);
320 connect((RTCM3Decoder*) _decoder, SIGNAL(newMessage(QByteArray,bool)),
321 this, SIGNAL(newMessage(QByteArray,bool)));
322 }
323 else if (_format.indexOf("RTIGS") != -1) {
324 emit(newMessage("Get Data: " + _staID + " in RTIGS format", true));
325 _decoder = new RTIGSDecoder();
326 }
327 else if (_format.indexOf("GPSS") != -1 || _format.indexOf("BNC") != -1) {
328 emit(newMessage("Get Data: " + _staID + " in GPSS format", true));
329 _decoder = new gpssDecoder();
330 }
331 else if (_format.indexOf("ZERO") != -1) {
332 emit(newMessage("Get Data: " + _staID + " in original format", true));
333 _decoder = new bncZeroDecoder(_staID);
334 }
335 else {
336 emit(newMessage(_staID + ": Unknown data format " + _format, true));
337 if (_rawInpFile) {
338 cerr << "Uknown data format" << endl;
339 ::exit(0);
340 }
341 else {
342 return fatal;
343 }
344 }
345 }
346 return success;
347}
348
349// Run
350////////////////////////////////////////////////////////////////////////////
351void bncGetThread::run() {
352
353 const double maxDt = 600.0; // Check observation epoch
354 bool wrongEpoch = false;
355 bool decode = true;
356 int numSucc = 0;
357 int secSucc = 0;
358 int secFail = 0;
359 int initPause = 30; // Initial pause for corrupted streams
360 int currPause = 0;
361 bool begCorrupt = false;
362 bool endCorrupt = false;
363 bool followSec = false;
364 int oldSecGPS= 0;
365 int newSecGPS = 0;
366 int numGaps = 0;
367 int diffSecGPS = 0;
368 int numLat = 0;
369 double sumLat = 0.;
370 double sumLatQ = 0.;
371 double meanDiff = 0.;
372 double minLat = maxDt;
373 double maxLat = -maxDt;
374 double curLat = 0.;
375
376 _decodeTime = QDateTime::currentDateTime();
377 _decodeSucc = QDateTime::currentDateTime();
378 t_irc irc = initRun();
379
380 if (irc == fatal) {
381 QThread::exit(1);
382 return;
383 }
384 else if (irc != success) {
385 emit(newMessage(_staID + ": initRun failed, reconnecting", true));
386 tryReconnect();
387 }
388
389 if (initPause < _inspSegm) {
390 initPause = _inspSegm;
391 }
392 if(!_makePause) {initPause = 0;}
393 currPause = initPause;
394
395 // Read Incoming Data
396 // ------------------
397 while (true) {
398 try {
399 if (_query && _query->status() != bncNetQuery::running) {
400 emit(newMessage(_staID + ": Internet query not running, reconnecting", true));
401 tryReconnect();
402 }
403
404 QListIterator<p_obs> it(_decoder->_obsList);
405 while (it.hasNext()) {
406 delete it.next();
407 }
408 _decoder->_obsList.clear();
409
410 qint64 nBytes = 0;
411
412 QByteArray data;
413
414 if (_query) {
415 _query->waitForReadyRead(data);
416 nBytes = data.size();
417 }
418 else if (_rawInpFile) {
419 const qint64 maxBytes = 1024;
420 nBytes = maxBytes;
421 }
422
423 if (nBytes > 0) {
424 emit newBytes(_staID, nBytes);
425
426 if (_rawInpFile) {
427 data = _rawInpFile->read(nBytes);
428 if (data.isEmpty()) {
429 cout << "no more data" << endl;
430 ::exit(0);
431 }
432 }
433
434 if (_rawOutFile) {
435 _rawOutFile->write(data);
436 _rawOutFile->flush();
437 }
438
439 if (_serialPort) {
440 _serialPort->write(data);
441 }
442
443 if (_inspSegm<1) {
444 vector<string> errmsg;
445 _decoder->Decode(data.data(), data.size(), errmsg);
446#ifdef DEBUG_RTCM2_2021
447 for (unsigned ii = 0; ii < errmsg.size(); ii++) {
448 emit newMessage(_staID + ": " + errmsg[ii].c_str(), false);
449 }
450#endif
451 }
452 else {
453
454 // Decode data
455 // -----------
456 if (!_decodePause.isValid() ||
457 _decodePause.secsTo(QDateTime::currentDateTime()) >= currPause ) {
458
459 if (decode) {
460 vector<string> errmsg;
461 if ( _decoder->Decode(data.data(), data.size(), errmsg) == success ) {
462 numSucc += 1;
463 }
464 if ( _decodeTime.secsTo(QDateTime::currentDateTime()) > _inspSegm ) {
465 decode = false;
466 }
467#ifdef DEBUG_RTCM2_2021
468 for (unsigned ii = 0; ii < errmsg.size(); ii++) {
469 emit newMessage(_staID + ": " + errmsg[ii].c_str(), false);
470 }
471#endif
472 }
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());
488 }
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 }
507 }
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");
514 emit(newMessage((_staID + ": Recovery threshold exceeded, corruption ended "
515 + _endDateCor + " " + _endTimeCor).toAscii(), true));
516 callScript(("End_Corrupted " + _endDateCor + " " + _endTimeCor + " Begin was " + _begDateCor + " " + _begTimeCor).toAscii());
517 endCorrupt = true;
518 begCorrupt = false;
519 secFail = 0;
520 }
521 else {
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");
528 emit(newMessage((_staID + ": Failure threshold exceeded, corrupted since "
529 + _begDateCor + " " + _begTimeCor).toAscii(), true));
530 callScript(("Begin_Corrupted " + _begDateCor + " " + _begTimeCor).toAscii());
531 begCorrupt = true;
532 endCorrupt = false;
533 secSucc = 0;
534 numSucc = 0;
535 }
536 }
537 decode = true;
538 }
539 }
540 }
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");
550 emit(newMessage((_staID + ": Recovery threshold exceeded, outage ended "
551 + _endDateOut + " " + _endTimeOut).toAscii(), true));
552 callScript(("End_Outage " + _endDateOut + " " + _endTimeOut + " Begin was " + _begDateOut + " " + _begTimeOut).toAscii());
553 }
554 }
555
556 // RTCM scan output
557 // ----------------
558 if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
559 QSettings settings;
560 if ( Qt::CheckState(settings.value("scanRTCM").toInt()) == Qt::Checked) {
561
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 }
570 }
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 }
580 }
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 }
606 }
607 if ( _checkMountPoint == "ANTCRD_ONLY" && _decoder->_antList.size() ) {
608 for (int ii=0;ii<_decoder->_antList.size();++ii) {
609 QByteArray antT;
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,
615 _decoder->_antList[ii].xx, _decoder->_antList[ii].yy, _decoder->_antList[ii].zz,
616 antT));
617 }
618 }
619 }
620
621 _decoder->_typeList.clear();
622 _decoder->_antType.clear();
623 _decoder->_antList.clear();
624
625 // Loop over all observations (observations output)
626 // ------------------------------------------------
627 QListIterator<p_obs> it(_decoder->_obsList);
628 while (it.hasNext()) {
629 p_obs obs = it.next();
630
631 // Check observation epoch
632 // -----------------------
633 if (!_rawInpFile && !dynamic_cast<gpssDecoder*>(_decoder)) {
634 int week;
635 double sec;
636 currentGPSWeeks(week, sec);
637 const double secPerWeek = 7.0 * 24.0 * 3600.0;
638
639 if (week < obs->_o.GPSWeek) {
640 week += 1;
641 sec -= secPerWeek;
642 }
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) {
650 emit( newMessage(_staID + ": Wrong observation epoch(s)", true) );
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) {
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 }
687 }
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;
696 }
697 if (followSec) {
698 diffSecGPS += newSecGPS - oldSecGPS;
699 if (meanDiff>0.) {
700 if (newSecGPS - oldSecGPS > 1.5 * meanDiff) {
701 numGaps += 1;
702 }
703 }
704 }
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;
713 }
714 }
715 }
716 }
717 }
718
719 // RINEX Output
720 // ------------
721 if (_rnx) {
722 bool dump = true;
723
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 //// }
758
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);
766 }
767 }
768
769 // Emit new observation signal
770 // ---------------------------
771 bool firstObs = (obs == _decoder->_obsList.first());
772 obs->_status = t_obs::posted;
773 emit newObs(_staID, firstObs, obs);
774 }
775 _decoder->_obsList.clear();
776
777 }
778
779 // Timeout, reconnect
780 // ------------------
781 else {
782 emit(newMessage(_staID + ": Data Timeout, reconnecting", true));
783 tryReconnect();
784 }
785 }
786 catch (const char* msg) {
787 emit(newMessage(_staID + msg, true));
788 tryReconnect();
789 }
790 }
791}
792
793// Exit
794////////////////////////////////////////////////////////////////////////////
795void bncGetThread::exit(int exitCode) {
796 if (exitCode!= 0) {
797 emit error(_staID);
798 }
799 QThread::exit(exitCode);
800 terminate();
801}
802
803// Try Re-Connect
804////////////////////////////////////////////////////////////////////////////
805void bncGetThread::tryReconnect() {
806 if (_rnx) {
807 _rnx->setReconnectFlag(true);
808 }
809 if ( !_decodeStart.isValid()) {
810 _decodeStop = QDateTime::currentDateTime();
811 }
812 while (1) {
813 sleep(_nextSleep);
814 if ( initRun() == success ) {
815 if ( !_decodeStop.isValid()) {
816 _decodeStart = QDateTime::currentDateTime();
817 }
818 break;
819 }
820 else {
821
822 // Begin outage threshold
823 // ----------------------
824 if ( _decodeStop.isValid() && _decodeStop.secsTo(QDateTime::currentDateTime()) > _adviseFail * 60 ) {
825 _decodeStop.setDate(QDate());
826 _decodeStop.setTime(QTime());
827 if (_inspSegm>0) {
828 _begDateOut = _decodeTime.toUTC().date().toString("yy-MM-dd");
829 _begTimeOut = _decodeTime.toUTC().time().toString("hh:mm:ss");
830 emit(newMessage((_staID + ": Failure threshold exceeded, outage since "
831 + _begDateOut + " " + _begTimeOut).toAscii(), true));
832 callScript(("Begin_Outage " + _begDateOut + " " + _begTimeOut).toAscii());
833 }
834 }
835 _nextSleep *= 2;
836 if (_nextSleep > 256) {
837 _nextSleep = 256;
838 }
839 _nextSleep += rand() % 6;
840 }
841 }
842 _nextSleep = 1;
843}
844
845// Call advisory notice script
846////////////////////////////////////////////////////////////////////////////
847void bncGetThread::callScript(const char* _comment) {
848 QMutexLocker locker(&_mutex);
849 if (!_adviseScript.isEmpty()) {
850 msleep(1);
851#ifdef WIN32
852 QProcess::startDetached(_adviseScript, QStringList() << _staID << _comment) ;
853#else
854 QProcess::startDetached("nohup", QStringList() << _adviseScript << _staID << _comment) ;
855#endif
856 }
857}
858
859//
860//////////////////////////////////////////////////////////////////////////////
861void bncGetThread::slotNewEphGPS(gpsephemeris gpseph) {
862 RTCM2Decoder* decoder = dynamic_cast<RTCM2Decoder*>(_decoder);
863
864 if ( decoder ) {
865 QMutexLocker locker(&_mutex);
866
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
878 emit(newMessage(msg.toAscii(), false));
879#endif
880 }
881 }
882}
883
Note: See TracBrowser for help on using the repository browser.