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

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

* empty log message *

File size: 34.3 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
57#include "RTCM/RTCM2Decoder.h"
58#include "RTCM3/RTCM3Decoder.h"
59#include "RTIGS/RTIGSDecoder.h"
60#include "GPSS/gpssDecoder.h"
61#include "serial/qextserialport.h"
62
63using namespace std;
64
65// Constructor 1
66////////////////////////////////////////////////////////////////////////////
67bncGetThread::bncGetThread(const QByteArray& rawInpFileName,
68 const QByteArray& format) {
69
70 _format = format;
71
72 int iSep = rawInpFileName.lastIndexOf(QDir::separator());
73 _staID = rawInpFileName.mid(iSep+1,4);
74
75 initialize();
76
77 _inspSegm = 0;
78
79 _rawInpFile = new QFile(rawInpFileName);
80 _rawInpFile->open(QIODevice::ReadOnly);
81
82 if (!_rnx) {
83 cerr << "no RINEX path specified" << endl;
84 ::exit(0);
85 }
86}
87
88// Constructor 2
89////////////////////////////////////////////////////////////////////////////
90bncGetThread::bncGetThread(const QUrl& mountPoint,
91 const QByteArray& format,
92 const QByteArray& latitude,
93 const QByteArray& longitude,
94 const QByteArray& nmea, int iMount) {
95
96 setTerminationEnabled(true);
97
98 _mountPoint = mountPoint;
99 _staID = mountPoint.path().mid(1).toAscii();
100 _format = format;
101 _latitude = latitude;
102 _longitude = longitude;
103 _nmea = nmea;
104 _iMount = iMount; // index in mountpoints array
105
106 initialize();
107}
108
109// Initialization
110////////////////////////////////////////////////////////////////////////////
111void bncGetThread::initialize() {
112
113
114 bncApp* app = (bncApp*) qApp;
115 app->connect(this, SIGNAL(newMessage(QByteArray,bool)),
116 app, SLOT(slotMessage(const QByteArray,bool)));
117
118 _decoder = 0;
119 _socket = 0;
120 _timeOut = 20*1000; // 20 seconds
121 _nextSleep = 1; // 1 second
122 _rawInpFile = 0;
123 _rawOutFile = 0;
124 _staID_orig = _staID;
125
126 // Check name conflict
127 // -------------------
128 QSettings settings;
129 QListIterator<QString> it(settings.value("mountPoints").toStringList());
130 int num = 0;
131 int ind = -1;
132 while (it.hasNext()) {
133 ++ind;
134 QStringList hlp = it.next().split(" ");
135 if (hlp.size() <= 1) continue;
136 QUrl url(hlp[0]);
137 if (_mountPoint.path() == url.path()) {
138 if (_iMount > ind || _iMount < 0) {
139 ++num;
140 }
141 }
142 }
143
144 if (num > 0) {
145 _staID = _staID.left(_staID.length()-1) + QString("%1").arg(num).toAscii();
146 }
147
148 // Notice threshold
149 // ----------------
150 _inspSegm = 50;
151 if ( settings.value("obsRate").toString().isEmpty() ) { _inspSegm = 0; }
152 if ( settings.value("obsRate").toString().indexOf("5 Hz") != -1 ) { _inspSegm = 2; }
153 if ( settings.value("obsRate").toString().indexOf("1 Hz") != -1 ) { _inspSegm = 10; }
154 if ( settings.value("obsRate").toString().indexOf("0.5 Hz") != -1 ) { _inspSegm = 20; }
155 if ( settings.value("obsRate").toString().indexOf("0.2 Hz") != -1 ) { _inspSegm = 40; }
156 if ( settings.value("obsRate").toString().indexOf("0.1 Hz") != -1 ) { _inspSegm = 50; }
157 _adviseFail = settings.value("adviseFail").toInt();
158 _adviseReco = settings.value("adviseReco").toInt();
159 _makePause = false;
160 if ( Qt::CheckState(settings.value("makePause").toInt()) == Qt::Checked) {_makePause = true; }
161 _adviseScript = settings.value("adviseScript").toString();
162 expandEnvVar(_adviseScript);
163
164 // Latency interval/average
165 // ------------------------
166 _perfIntr = 86400;
167 if ( settings.value("perfIntr").toString().isEmpty() ) { _perfIntr = 0; }
168 if ( settings.value("perfIntr").toString().indexOf("1 min") != -1 ) { _perfIntr = 60; }
169 if ( settings.value("perfIntr").toString().indexOf("5 min") != -1 ) { _perfIntr = 300; }
170 if ( settings.value("perfIntr").toString().indexOf("15 min") != -1 ) { _perfIntr = 900; }
171 if ( settings.value("perfIntr").toString().indexOf("1 hour") != -1 ) { _perfIntr = 3600; }
172 if ( settings.value("perfIntr").toString().indexOf("6 hours") != -1 ) { _perfIntr = 21600; }
173 if ( settings.value("perfIntr").toString().indexOf("1 day") != -1 ) { _perfIntr = 86400; }
174
175 // RTCM message types
176 // ------------------
177 _checkMountPoint = settings.value("miscMount").toString();
178
179 // RINEX writer
180 // ------------
181 _samplingRate = settings.value("rnxSampl").toInt();
182 if ( settings.value("rnxPath").toString().isEmpty() ) {
183 _rnx = 0;
184 }
185 else {
186 _rnx = new bncRinex(_staID, _mountPoint,
187 _format, _latitude, _longitude, _nmea);
188 }
189 _rnx_set_position = false;
190
191 connect(((bncApp*)qApp), SIGNAL(newEphGPS(gpsephemeris)),
192 this, SLOT(slotNewEphGPS(gpsephemeris)));
193
194 if (settings.value("serialMountPoint").toString() == _staID) {
195 _serialPort = new QextSerialPort(
196 settings.value("serialPortName").toString() );
197 _serialPort->setBaudRate(BAUD9600);
198 _serialPort->setParity(PAR_NONE);
199 _serialPort->setDataBits(DATA_8);
200 _serialPort->setStopBits(STOP_1);
201 _serialPort->open(QIODevice::ReadWrite|QIODevice::Unbuffered);
202 qDebug() << "serial port opened: " << _serialPort->isOpen() << endl;
203 }
204 else {
205 _serialPort = 0;
206 }
207
208 // Raw Output
209 // ----------
210 // QByteArray rawOutFileName = "./" + _staID + ".raw";
211 // _rawOutFile = new QFile(rawOutFileName);
212 // _rawOutFile->open(QIODevice::WriteOnly);
213
214 msleep(100); //sleep 0.1 sec
215}
216
217// Destructor
218////////////////////////////////////////////////////////////////////////////
219bncGetThread::~bncGetThread() {
220 if (_socket) {
221 _socket->close();
222#if QT_VERSION == 0x040203
223 delete _socket;
224#else
225 _socket->deleteLater();
226#endif
227 }
228 delete _decoder;
229 delete _rnx;
230 delete _rawInpFile;
231 delete _rawOutFile;
232}
233
234#define AGENTVERSION "1.7"
235// Connect to Caster, send the Request (static)
236////////////////////////////////////////////////////////////////////////////
237QTcpSocket* bncGetThread::request(const QUrl& mountPoint,
238 QByteArray& latitude, QByteArray& longitude,
239 QByteArray& nmea, int timeOut,
240 QString& msg) {
241
242 // Connect the Socket
243 // ------------------
244 QSettings settings;
245 QString proxyHost = settings.value("proxyHost").toString();
246 int proxyPort = settings.value("proxyPort").toInt();
247
248 QTcpSocket* socket = new QTcpSocket();
249 if ( proxyHost.isEmpty() ) {
250 socket->connectToHost(mountPoint.host(), mountPoint.port());
251 }
252 else {
253 socket->connectToHost(proxyHost, proxyPort);
254 }
255 if (!socket->waitForConnected(timeOut)) {
256 msg += "Connect timeout\n";
257 delete socket;
258 return 0;
259 }
260
261 // Send Request
262 // ------------
263 QString uName = QUrl::fromPercentEncoding(mountPoint.userName().toAscii());
264 QString passW = QUrl::fromPercentEncoding(mountPoint.password().toAscii());
265 QByteArray userAndPwd;
266
267 if(!uName.isEmpty() || !passW.isEmpty())
268 {
269 userAndPwd = "Authorization: Basic " + (uName.toAscii() + ":" +
270 passW.toAscii()).toBase64() + "\r\n";
271 }
272
273 QUrl hlp;
274 hlp.setScheme("http");
275 hlp.setHost(mountPoint.host());
276 hlp.setPort(mountPoint.port());
277 hlp.setPath(mountPoint.path());
278
279 QByteArray reqStr;
280 if ( proxyHost.isEmpty() ) {
281 if (hlp.path().indexOf("/") != 0) hlp.setPath("/");
282 reqStr = "GET " + hlp.path().toAscii() + " HTTP/1.0\r\n"
283 + "User-Agent: NTRIP BNC/" AGENTVERSION "\r\n"
284 + userAndPwd + "\r\n";
285 } else {
286 reqStr = "GET " + hlp.toEncoded() + " HTTP/1.0\r\n"
287 + "User-Agent: NTRIP BNC/" AGENTVERSION "\r\n"
288 + "Host: " + hlp.host().toAscii() + "\r\n"
289 + userAndPwd + "\r\n";
290 }
291
292 // NMEA string to handle VRS stream
293 // --------------------------------
294 double lat, lon;
295
296 lat = strtod(latitude,NULL);
297 lon = strtod(longitude,NULL);
298
299 if ((nmea == "yes") && (hlp.path().length() > 2) && (hlp.path().indexOf(".skl") < 0)) {
300 const char* flagN="N";
301 const char* flagE="E";
302 if (lon >180.) {lon=(lon-360.)*(-1.); flagE="W";}
303 if ((lon < 0.) && (lon >= -180.)) {lon=lon*(-1.); flagE="W";}
304 if (lon < -180.) {lon=(lon+360.); flagE="E";}
305 if (lat < 0.) {lat=lat*(-1.); flagN="S";}
306 QTime ttime(QDateTime::currentDateTime().toUTC().time());
307 int lat_deg = (int)lat;
308 double lat_min=(lat-lat_deg)*60.;
309 int lon_deg = (int)lon;
310 double lon_min=(lon-lon_deg)*60.;
311 int hh = 0 , mm = 0;
312 double ss = 0.0;
313 hh=ttime.hour();
314 mm=ttime.minute();
315 ss=(double)ttime.second()+0.001*ttime.msec();
316 QString gga;
317 gga += "GPGGA,";
318 gga += QString("%1%2%3,").arg((int)hh, 2, 10, QLatin1Char('0')).arg((int)mm, 2, 10, QLatin1Char('0')).arg((int)ss, 2, 10, QLatin1Char('0'));
319 gga += QString("%1%2,").arg((int)lat_deg,2, 10, QLatin1Char('0')).arg(lat_min, 7, 'f', 4, QLatin1Char('0'));
320 gga += flagN;
321 gga += QString(",%1%2,").arg((int)lon_deg,3, 10, QLatin1Char('0')).arg(lon_min, 7, 'f', 4, QLatin1Char('0'));
322 gga += flagE + QString(",1,05,1.00,+00100,M,10.000,M,,");
323 int xori;
324 char XOR = 0;
325 char *Buff =gga.toAscii().data();
326 int iLen = strlen(Buff);
327 for (xori = 0; xori < iLen; xori++) {
328 XOR ^= (char)Buff[xori];
329 }
330 gga += QString("*%1").arg(XOR, 2, 16, QLatin1Char('0'));
331 reqStr += "$";
332 reqStr += gga;
333 reqStr += "\r\n";
334 }
335
336 msg += reqStr;
337
338 socket->write(reqStr, reqStr.length());
339
340 if (!socket->waitForBytesWritten(timeOut)) {
341 msg += "Write timeout\n";
342 delete socket;
343 return 0;
344 }
345
346 return socket;
347}
348
349// Init Run
350////////////////////////////////////////////////////////////////////////////
351t_irc bncGetThread::initRun() {
352
353 if (!_rawInpFile) {
354
355 // Initialize Socket
356 // -----------------
357 QString msg;
358 _socket = this->request(_mountPoint, _latitude, _longitude,
359 _nmea, _timeOut, msg);
360 if (!_socket) {
361 return failure;
362 }
363
364 // Read Caster Response
365 // --------------------
366 _socket->waitForReadyRead(_timeOut);
367 if (_socket->canReadLine()) {
368 QString line = _socket->readLine();
369
370 // Skip messages from proxy server
371 // -------------------------------
372 if (line.indexOf("ICY 200 OK") == -1 &&
373 line.indexOf("200 OK") != -1 ) {
374 bool proxyRespond = true;
375 while (true) {
376 if (_socket->canReadLine()) {
377 line = _socket->readLine();
378 if (!proxyRespond) {
379 break;
380 }
381 if (line.trimmed().isEmpty()) {
382 proxyRespond = false;
383 }
384 }
385 else {
386 _socket->waitForReadyRead(_timeOut);
387 if (_socket->bytesAvailable() <= 0) {
388 break;
389 }
390 }
391 }
392 }
393
394 if (line.indexOf("Unauthorized") != -1) {
395 QStringList table;
396 bncTableDlg::getFullTable(_mountPoint.host(), _mountPoint.port(), table);
397 QString net;
398 QStringListIterator it(table);
399 while (it.hasNext()) {
400 QString line = it.next();
401 if (line.indexOf("STR") == 0) {
402 QStringList tags = line.split(";");
403 if (tags.at(1) == _staID_orig) {
404 net = tags.at(7);
405 break;
406 }
407 }
408 }
409
410 QString reg;
411 it.toFront();
412 while (it.hasNext()) {
413 QString line = it.next();
414 if (line.indexOf("NET") == 0) {
415 QStringList tags = line.split(";");
416 if (tags.at(1) == net) {
417 reg = tags.at(7);
418 break;
419 }
420 }
421 }
422 emit(newMessage((_staID + ": Caster Response: " + line +
423 " Adjust User-ID and Password Register, see"
424 "\n " + reg).toAscii(), true));
425 return fatal;
426 }
427 if (line.indexOf("ICY 200 OK") != 0) {
428 emit(newMessage((_staID + ": Wrong Caster Response:\n" + line).toAscii(), true));
429 return failure;
430 }
431 }
432 else {
433 emit(newMessage(_staID + ": Response Timeout", true));
434 return failure;
435 }
436 }
437
438 // Instantiate the filter
439 // ----------------------
440 if (!_decoder) {
441 if (_format.indexOf("RTCM_2") != -1) {
442 emit(newMessage("Get Data: " + _staID + " in RTCM 2.x format", true));
443 _decoder = new RTCM2Decoder(_staID.data());
444 }
445 else if (_format.indexOf("RTCM_3") != -1) {
446 emit(newMessage("Get Data: " + _staID + " in RTCM 3.x format", true));
447 _decoder = new RTCM3Decoder(_staID);
448 connect((RTCM3Decoder*) _decoder, SIGNAL(newMessage(QByteArray,bool)),
449 this, SIGNAL(newMessage(QByteArray,bool)));
450 }
451 else if (_format.indexOf("RTIGS") != -1) {
452 emit(newMessage("Get Data: " + _staID + " in RTIGS format", true));
453 _decoder = new RTIGSDecoder();
454 }
455 else if (_format.indexOf("GPSS") != -1 || _format.indexOf("BNC") != -1) {
456 emit(newMessage("Get Data: " + _staID + " in GPSS format", true));
457 _decoder = new gpssDecoder();
458 }
459 else if (_format.indexOf("ZERO") != -1) {
460 emit(newMessage("Get Data: " + _staID + " in original format", true));
461 _decoder = new bncZeroDecoder(_staID);
462 }
463 else {
464 emit(newMessage(_staID + ": Unknown data format " + _format, true));
465 if (_rawInpFile) {
466 cerr << "Uknown data format" << endl;
467 ::exit(0);
468 }
469 else {
470 return fatal;
471 }
472 }
473 }
474 return success;
475}
476
477// Run
478////////////////////////////////////////////////////////////////////////////
479void bncGetThread::run() {
480
481 const double maxDt = 600.0; // Check observation epoch
482 bool wrongEpoch = false;
483 bool decode = true;
484 int numSucc = 0;
485 int secSucc = 0;
486 int secFail = 0;
487 int initPause = 30; // Initial pause for corrupted streams
488 int currPause = 0;
489 bool begCorrupt = false;
490 bool endCorrupt = false;
491 bool followSec = false;
492 int oldSecGPS= 0;
493 int newSecGPS = 0;
494 int numGaps = 0;
495 int diffSecGPS = 0;
496 int numLat = 0;
497 double sumLat = 0.;
498 double sumLatQ = 0.;
499 double meanDiff = 0.;
500 double minLat = maxDt;
501 double maxLat = -maxDt;
502 double curLat = 0.;
503
504 _decodeTime = QDateTime::currentDateTime();
505 _decodeSucc = QDateTime::currentDateTime();
506 t_irc irc = initRun();
507
508 if (irc == fatal) {
509 QThread::exit(1);
510 return;
511 }
512 else if (irc != success) {
513 emit(newMessage(_staID + ": initRun failed, reconnecting", true));
514 tryReconnect();
515 }
516
517 if (initPause < _inspSegm) {
518 initPause = _inspSegm;
519 }
520 if(!_makePause) {initPause = 0;}
521 currPause = initPause;
522
523 // Read Incoming Data
524 // ------------------
525 while (true) {
526 try {
527 if (_socket && _socket->state() != QAbstractSocket::ConnectedState) {
528 emit(newMessage(_staID + ": Socket not connected, reconnecting", true));
529 tryReconnect();
530 }
531
532 QListIterator<p_obs> it(_decoder->_obsList);
533 while (it.hasNext()) {
534 delete it.next();
535 }
536 _decoder->_obsList.clear();
537
538 qint64 nBytes = 0;
539
540 if (_socket) {
541 _socket->waitForReadyRead(_timeOut);
542 nBytes = _socket->bytesAvailable();
543 }
544 else if (_rawInpFile) {
545 const qint64 maxBytes = 1024;
546 nBytes = maxBytes;
547 }
548
549 if (nBytes > 0) {
550 emit newBytes(_staID, nBytes);
551
552 char* data = new char[nBytes];
553
554 if (_socket) {
555 _socket->read(data, nBytes);
556 }
557 else if (_rawInpFile) {
558 nBytes = _rawInpFile->read(data, nBytes);
559 if (nBytes <= 0) {
560 cout << "no more data" << endl;
561 ::exit(0);
562 }
563 }
564
565 if (_rawOutFile) {
566 _rawOutFile->write(data, nBytes);
567 _rawOutFile->flush();
568 }
569
570 if (_serialPort) {
571 int irc = _serialPort->write(data, nBytes);
572 //// _serialPort->flush();
573 qDebug() << nBytes << " " << irc << endl;
574 }
575
576 if (_inspSegm<1) {
577 vector<string> errmsg;
578 _decoder->Decode(data, nBytes, errmsg);
579#ifdef DEBUG_RTCM2_2021
580 for (unsigned ii = 0; ii < errmsg.size(); ii++) {
581 emit newMessage(_staID + ": " + errmsg[ii].c_str(), false);
582 }
583#endif
584 }
585 else {
586
587 // Decode data
588 // -----------
589 if (!_decodePause.isValid() ||
590 _decodePause.secsTo(QDateTime::currentDateTime()) >= currPause ) {
591
592 if (decode) {
593 vector<string> errmsg;
594 if ( _decoder->Decode(data, nBytes, errmsg) == success ) {
595 numSucc += 1;
596 }
597 if ( _decodeTime.secsTo(QDateTime::currentDateTime()) > _inspSegm ) {
598 decode = false;
599 }
600#ifdef DEBUG_RTCM2_2021
601 for (unsigned ii = 0; ii < errmsg.size(); ii++) {
602 emit newMessage(_staID + ": " + errmsg[ii].c_str(), false);
603 }
604#endif
605 }
606
607 // Check - once per inspect segment
608 // --------------------------------
609 if (!decode) {
610 _decodeTime = QDateTime::currentDateTime();
611 if (numSucc>0) {
612 secSucc += _inspSegm;
613 _decodeSucc = QDateTime::currentDateTime();
614 if (secSucc > _adviseReco * 60) {
615 secSucc = _adviseReco * 60 + 1;
616 }
617 numSucc = 0;
618 currPause = initPause;
619 _decodePause.setDate(QDate());
620 _decodePause.setTime(QTime());
621 }
622 else {
623 secFail += _inspSegm;
624 secSucc = 0;
625 if (secFail > _adviseFail * 60) {
626 secFail = _adviseFail * 60 + 1;
627 }
628 if (!_decodePause.isValid() || !_makePause) {
629 _decodePause = QDateTime::currentDateTime();
630 }
631 else {
632 _decodePause.setDate(QDate());
633 _decodePause.setTime(QTime());
634 secFail = secFail + currPause - _inspSegm;
635 currPause = currPause * 2;
636 if (currPause > 960) {
637 currPause = 960;
638 }
639 }
640 }
641
642 // End corrupt threshold
643 // ---------------------
644 if ( begCorrupt && !endCorrupt && secSucc > _adviseReco * 60 ) {
645 _endDateCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
646 _endTimeCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
647 emit(newMessage((_staID + ": Recovery threshold exceeded, corruption ended "
648 + _endDateCor + " " + _endTimeCor).toAscii(), true));
649 callScript(("End_Corrupted " + _endDateCor + " " + _endTimeCor + " Begin was " + _begDateCor + " " + _begTimeCor).toAscii());
650 endCorrupt = true;
651 begCorrupt = false;
652 secFail = 0;
653 }
654 else {
655
656 // Begin corrupt threshold
657 // -----------------------
658 if ( !begCorrupt && secFail > _adviseFail * 60 ) {
659 _begDateCor = _decodeSucc.toUTC().date().toString("yy-MM-dd");
660 _begTimeCor = _decodeSucc.toUTC().time().toString("hh:mm:ss");
661 emit(newMessage((_staID + ": Failure threshold exceeded, corrupted since "
662 + _begDateCor + " " + _begTimeCor).toAscii(), true));
663 callScript(("Begin_Corrupted " + _begDateCor + " " + _begTimeCor).toAscii());
664 begCorrupt = true;
665 endCorrupt = false;
666 secSucc = 0;
667 numSucc = 0;
668 }
669 }
670 decode = true;
671 }
672 }
673 }
674
675 // End outage threshold
676 // --------------------
677 if ( _decodeStart.isValid() && _decodeStart.secsTo(QDateTime::currentDateTime()) > _adviseReco * 60 ) {
678 _decodeStart.setDate(QDate());
679 _decodeStart.setTime(QTime());
680 if (_inspSegm>0) {
681 _endDateOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
682 _endTimeOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
683 emit(newMessage((_staID + ": Recovery threshold exceeded, outage ended "
684 + _endDateOut + " " + _endTimeOut).toAscii(), true));
685 callScript(("End_Outage " + _endDateOut + " " + _endTimeOut + " Begin was " + _begDateOut + " " + _begTimeOut).toAscii());
686 }
687 }
688
689 delete [] data;
690
691
692 // RTCM scan output
693 // ----------------
694 if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
695 QSettings settings;
696 if ( Qt::CheckState(settings.value("scanRTCM").toInt()) == Qt::Checked) {
697
698 // RTCMv3 message types
699 // --------------------
700 if (0<_decoder->_typeList.size()) {
701 QString type;
702 for (int ii=0;ii<_decoder->_typeList.size();ii++) {
703 type = QString("%1 ").arg(_decoder->_typeList[ii]);
704 emit(newMessage(_staID + ": Received message type " + type.toAscii(), true));
705 }
706 }
707
708 // RTCMv3 antenna descriptor
709 // -------------------------
710 if (0<_decoder->_antType.size()) {
711 QString ant1;
712 for (int ii=0;ii<_decoder->_antType.size();ii++) {
713 ant1 = QString("%1 ").arg(_decoder->_antType[ii]);
714 emit(newMessage(_staID + ": Antenna descriptor " + ant1.toAscii(), true));
715 }
716 }
717
718 // Antenna XYZ
719 // ------------------
720 if (0<_decoder->_antList.size()) {
721 for (int ii=0;ii<_decoder->_antList.size();++ii) {
722 QByteArray ant1,ant2,ant3, antT;
723 ant1 = QString("%1 ").arg(_decoder->_antList[ii].xx,0,'f',4).toAscii();
724 ant2 = QString("%1 ").arg(_decoder->_antList[ii].yy,0,'f',4).toAscii();
725 ant3 = QString("%1 ").arg(_decoder->_antList[ii].zz,0,'f',4).toAscii();
726 switch (_decoder->_antList[ii].type) {
727 case GPSDecoder::t_antInfo::ARP: antT = "ARP"; break;
728 case GPSDecoder::t_antInfo::APC: antT = "APC"; break;
729 }
730 emit(newMessage(_staID + ": " + antT + " (ITRF) X " + ant1 + "m", true));
731 emit(newMessage(_staID + ": " + antT + " (ITRF) Y " + ant2 + "m", true));
732 emit(newMessage(_staID + ": " + antT + " (ITRF) Z " + ant3 + "m", true));
733 if (_decoder->_antList[ii].height_f) {
734 QByteArray ant4 = QString("%1 ").arg(_decoder->_antList[ii].height,0,'f',4).toAscii();
735 emit(newMessage(_staID + ": Antenna height above marker " + ant4 + "m", true));
736 }
737 emit(newAntCrd(_staID,
738 _decoder->_antList[ii].xx, _decoder->_antList[ii].yy, _decoder->_antList[ii].zz,
739 antT));
740 }
741 }
742 }
743 if ( _checkMountPoint == "ANTCRD_ONLY" && _decoder->_antList.size() ) {
744 for (int ii=0;ii<_decoder->_antList.size();++ii) {
745 QByteArray antT;
746 switch (_decoder->_antList[ii].type) {
747 case GPSDecoder::t_antInfo::ARP: antT = "ARP"; break;
748 case GPSDecoder::t_antInfo::APC: antT = "APC"; break;
749 }
750 emit(newAntCrd(_staID,
751 _decoder->_antList[ii].xx, _decoder->_antList[ii].yy, _decoder->_antList[ii].zz,
752 antT));
753 }
754 }
755 }
756
757 _decoder->_typeList.clear();
758 _decoder->_antType.clear();
759 _decoder->_antList.clear();
760
761 // Loop over all observations (observations output)
762 // ------------------------------------------------
763 QListIterator<p_obs> it(_decoder->_obsList);
764 while (it.hasNext()) {
765 p_obs obs = it.next();
766
767 // Check observation epoch
768 // -----------------------
769 if (!_rawInpFile && !dynamic_cast<gpssDecoder*>(_decoder)) {
770 int week;
771 double sec;
772 currentGPSWeeks(week, sec);
773 const double secPerWeek = 7.0 * 24.0 * 3600.0;
774
775 if (week < obs->_o.GPSWeek) {
776 week += 1;
777 sec -= secPerWeek;
778 }
779 if (week > obs->_o.GPSWeek) {
780 week -= 1;
781 sec += secPerWeek;
782 }
783 double dt = fabs(sec - obs->_o.GPSWeeks);
784 if (week != obs->_o.GPSWeek || dt > maxDt) {
785 if (!wrongEpoch) {
786 emit( newMessage(_staID + ": Wrong observation epoch(s)", true) );
787 wrongEpoch = true;
788 }
789 delete obs;
790 continue;
791 }
792 else {
793 wrongEpoch = false;
794
795 // Latency and completeness
796 // ------------------------
797 if (_perfIntr>0) {
798 if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
799 newSecGPS = static_cast<int>(obs->_o.GPSWeeks);
800 if (newSecGPS != oldSecGPS) {
801 if (newSecGPS % _perfIntr < oldSecGPS % _perfIntr) {
802 if (numLat>0) {
803 if (meanDiff>0.) {
804 emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs, %7 gaps")
805 .arg(_staID.data())
806 .arg(int(sumLat/numLat*100)/100.)
807 .arg(int(minLat*100)/100.)
808 .arg(int(maxLat*100)/100.)
809 .arg(int((sqrt((sumLatQ - sumLat * sumLat / numLat)/numLat))*100)/100.)
810 .arg(numLat)
811 .arg(numGaps)
812 .toAscii(), true) );
813 } else {
814 emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs")
815 .arg(_staID.data())
816 .arg(int(sumLat/numLat*100)/100.)
817 .arg(int(minLat*100)/100.)
818 .arg(int(maxLat*100)/100.)
819 .arg(int((sqrt((sumLatQ - sumLat * sumLat / numLat)/numLat))*100)/100.)
820 .arg(numLat)
821 .toAscii(), true) );
822 }
823 }
824 meanDiff = diffSecGPS/numLat;
825 diffSecGPS = 0;
826 numGaps = 0;
827 sumLat = 0.;
828 sumLatQ = 0.;
829 numLat = 0;
830 minLat = maxDt;
831 maxLat = -maxDt;
832 }
833 if (followSec) {
834 diffSecGPS += newSecGPS - oldSecGPS;
835 if (meanDiff>0.) {
836 if (newSecGPS - oldSecGPS > 1.5 * meanDiff) {
837 numGaps += 1;
838 }
839 }
840 }
841 curLat = sec - obs->_o.GPSWeeks;
842 sumLat += curLat;
843 sumLatQ += curLat * curLat;
844 if (curLat < minLat) minLat = curLat;
845 if (curLat >= maxLat) maxLat = curLat;
846 numLat += 1;
847 oldSecGPS = newSecGPS;
848 followSec = true;
849 }
850 }
851 }
852 }
853 }
854
855 // RINEX Output
856 // ------------
857 if (_rnx) {
858 bool dump = true;
859
860 //// // RTCMv2 XYZ
861 //// // ----------
862 //// RTCM2Decoder* decoder2 = dynamic_cast<RTCM2Decoder*>(_decoder);
863 //// if ( decoder2 && !_rnx_set_position ) {
864 //// double stax, stay, staz;
865 //// double dL1[3], dL2[3];
866 //// if ( decoder2->getStaCrd(stax, stay, staz,
867 //// dL1[0], dL1[1], dL1[2],
868 //// dL2[0], dL2[1], dL2[2]) == success ) {
869 ////
870 //// if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
871 //// QString ant1;
872 //// ant1 = QString("%1 ").arg(stax,0,'f',4);
873 //// emit(newMessage(_staID + ": ARP X " + ant1.toAscii() + "m" ));
874 //// ant1 = QString("%1 ").arg(stay,0,'f',4);
875 //// emit(newMessage(_staID + ": ARP Y " + ant1.toAscii() + "m" ));
876 //// ant1 = QString("%1 ").arg(staz,0,'f',4);
877 //// emit(newMessage(_staID + ": ARP Z " + ant1.toAscii() + "m" ));
878 //// ant1 = QString("%1 ").arg(dL1[0],0,'f',4);
879 //// emit(newMessage(_staID + ": L1 APC DX " + ant1.toAscii() + "m" ));
880 //// ant1 = QString("%1 ").arg(dL1[1],0,'f',4);
881 //// emit(newMessage(_staID + ": L1 APC DY " + ant1.toAscii() + "m" ));
882 //// ant1 = QString("%1 ").arg(dL1[2],0,'f',4);
883 //// emit(newMessage(_staID + ": L1 APC DZ " + ant1.toAscii() + "m" ));
884 //// ant1 = QString("%1 ").arg(dL2[0],0,'f',4);
885 //// emit(newMessage(_staID + ": L2 APC DX " + ant1.toAscii() + "m" ));
886 //// ant1 = QString("%1 ").arg(dL2[1],0,'f',4);
887 //// emit(newMessage(_staID + ": L2 APC DY " + ant1.toAscii() + "m" ));
888 //// ant1 = QString("%1 ").arg(dL2[2],0,'f',4);
889 //// emit(newMessage(_staID + ": L2 APC DZ " + ant1.toAscii() + "m" ));
890 //// }
891 //// _rnx_set_position = true;
892 //// }
893 //// }
894
895 if ( dump ) {
896 long iSec = long(floor(obs->_o.GPSWeeks+0.5));
897 long newTime = obs->_o.GPSWeek * 7*24*3600 + iSec;
898 if (_samplingRate == 0 || iSec % _samplingRate == 0) {
899 _rnx->deepCopy(obs);
900 }
901 _rnx->dumpEpoch(newTime);
902 }
903 }
904
905 // Emit new observation signal
906 // ---------------------------
907 bool firstObs = (obs == _decoder->_obsList.first());
908 obs->_status = t_obs::posted;
909 emit newObs(_staID, firstObs, obs);
910 }
911 _decoder->_obsList.clear();
912
913 }
914
915 // Timeout, reconnect
916 // ------------------
917 else {
918 emit(newMessage(_staID + ": Data Timeout, reconnecting", true));
919 tryReconnect();
920 }
921 }
922 catch (const char* msg) {
923 emit(newMessage(_staID + msg, true));
924 tryReconnect();
925 }
926 }
927}
928
929// Exit
930////////////////////////////////////////////////////////////////////////////
931void bncGetThread::exit(int exitCode) {
932 if (exitCode!= 0) {
933 emit error(_staID);
934 }
935 QThread::exit(exitCode);
936 terminate();
937}
938
939// Try Re-Connect
940////////////////////////////////////////////////////////////////////////////
941void bncGetThread::tryReconnect() {
942 if (_rnx) {
943 _rnx->setReconnectFlag(true);
944 }
945 if ( !_decodeStart.isValid()) {
946 _decodeStop = QDateTime::currentDateTime();
947 }
948 while (1) {
949 delete _socket; _socket = 0;
950 sleep(_nextSleep);
951 if ( initRun() == success ) {
952 if ( !_decodeStop.isValid()) {
953 _decodeStart = QDateTime::currentDateTime();
954 }
955 break;
956 }
957 else {
958
959 // Begin outage threshold
960 // ----------------------
961 if ( _decodeStop.isValid() && _decodeStop.secsTo(QDateTime::currentDateTime()) > _adviseFail * 60 ) {
962 _decodeStop.setDate(QDate());
963 _decodeStop.setTime(QTime());
964 if (_inspSegm>0) {
965 _begDateOut = _decodeTime.toUTC().date().toString("yy-MM-dd");
966 _begTimeOut = _decodeTime.toUTC().time().toString("hh:mm:ss");
967 emit(newMessage((_staID + ": Failure threshold exceeded, outage since "
968 + _begDateOut + " " + _begTimeOut).toAscii(), true));
969 callScript(("Begin_Outage " + _begDateOut + " " + _begTimeOut).toAscii());
970 }
971 }
972 _nextSleep *= 2;
973 if (_nextSleep > 256) {
974 _nextSleep = 256;
975 }
976 _nextSleep += rand() % 6;
977 }
978 }
979 _nextSleep = 1;
980}
981
982// Call advisory notice script
983////////////////////////////////////////////////////////////////////////////
984void bncGetThread::callScript(const char* _comment) {
985 QMutexLocker locker(&_mutex);
986 if (!_adviseScript.isEmpty()) {
987 msleep(1);
988#ifdef WIN32
989 QProcess::startDetached(_adviseScript, QStringList() << _staID << _comment) ;
990#else
991 QProcess::startDetached("nohup", QStringList() << _adviseScript << _staID << _comment) ;
992#endif
993 }
994}
995
996//
997//////////////////////////////////////////////////////////////////////////////
998void bncGetThread::slotNewEphGPS(gpsephemeris gpseph) {
999 RTCM2Decoder* decoder = dynamic_cast<RTCM2Decoder*>(_decoder);
1000
1001 if ( decoder ) {
1002 QMutexLocker locker(&_mutex);
1003
1004 string storedPRN;
1005 vector<int> IODs;
1006
1007 if ( decoder->storeEph(gpseph, storedPRN, IODs) ) {
1008#ifdef DEBUG_RTCM2_2021
1009 QString msg = _staID + QString(": stored eph %1 IODs").arg(storedPRN.c_str());
1010
1011 for (unsigned ii = 0; ii < IODs.size(); ii++) {
1012 msg += QString(" %1").arg(IODs[ii],4);
1013 }
1014
1015 emit(newMessage(msg.toAscii(), false));
1016#endif
1017 }
1018 }
1019}
1020
Note: See TracBrowser for help on using the repository browser.