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

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

* empty log message *

File size: 16.5 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 "bncnetqueryv1.h"
57#include "bncnetqueryv2.h"
58#include "bncnetqueryrtp.h"
59#include "bncsettings.h"
60#include "latencychecker.h"
61
62#include "RTCM/RTCM2Decoder.h"
63#include "RTCM3/RTCM3Decoder.h"
64#include "RTIGS/RTIGSDecoder.h"
65#include "GPSS/gpssDecoder.h"
66#include "serial/qextserialport.h"
67
68using namespace std;
69
70// Constructor 1
71////////////////////////////////////////////////////////////////////////////
72bncGetThread::bncGetThread(const QByteArray& rawInpFileName,
73 const QByteArray& format) {
74
75 _rawInpFile = new QFile(rawInpFileName);
76 _rawInpFile->open(QIODevice::ReadOnly);
77 _format = format;
78 _staID = rawInpFileName.mid(
79 rawInpFileName.lastIndexOf(QDir::separator())+1,4);
80
81 initialize();
82}
83
84// Constructor 2
85////////////////////////////////////////////////////////////////////////////
86bncGetThread::bncGetThread(const QUrl& mountPoint,
87 const QByteArray& format,
88 const QByteArray& latitude,
89 const QByteArray& longitude,
90 const QByteArray& nmea,
91 const QByteArray& ntripVersion, int iMount) {
92 _rawInpFile = 0;
93 _mountPoint = mountPoint;
94 _staID = mountPoint.path().mid(1).toAscii();
95 _format = format;
96 _latitude = latitude;
97 _longitude = longitude;
98 _nmea = nmea;
99 _ntripVersion = ntripVersion;
100 _iMount = iMount; // index in mountpoints array
101
102 initialize();
103}
104
105// Initialization (common part of the constructor)
106////////////////////////////////////////////////////////////////////////////
107void bncGetThread::initialize() {
108
109 setTerminationEnabled(true);
110
111 bncApp* app = (bncApp*) qApp;
112
113 connect(this, SIGNAL(newMessage(QByteArray,bool)),
114 app, SLOT(slotMessage(const QByteArray,bool)));
115
116 _isToBeDeleted = false;
117 _decoder = 0;
118 _query = 0;
119 _nextSleep = 0;
120 _rawOutFile = 0;
121 _staID_orig = _staID;
122
123 bncSettings settings;
124
125 _miscMount = settings.value("miscMount").toString();
126
127 if ( settings.value("serialMountPoint").toString() == _staID &&
128 settings.value("serialAutoNMEA").toString() != "Auto" ) {
129 _height = settings.value("serialHeightNMEA").toString().toAscii();
130 } else {
131 _height = "100";
132 }
133
134 // Check name conflict
135 // -------------------
136 QListIterator<QString> it(settings.value("mountPoints").toStringList());
137 int num = 0;
138 int ind = -1;
139 while (it.hasNext()) {
140 ++ind;
141 QStringList hlp = it.next().split(" ");
142 if (hlp.size() <= 1) continue;
143 QUrl url(hlp[0]);
144 if (_mountPoint.path() == url.path()) {
145 if (_iMount > ind || _iMount < 0) {
146 ++num;
147 }
148 }
149 }
150
151 if (num > 0) {
152 _staID = _staID.left(_staID.length()-1) + QString("%1").arg(num).toAscii();
153 }
154
155 // RINEX writer
156 // ------------
157 _samplingRate = settings.value("rnxSampl").toInt();
158 if ( settings.value("rnxPath").toString().isEmpty() ) {
159 _rnx = 0;
160 if (_rawInpFile) {
161 cerr << "no RINEX path specified" << endl;
162 ::exit(1);
163 }
164 }
165 else {
166 _rnx = new bncRinex(_staID, _mountPoint, _format, _latitude,
167 _longitude, _nmea);
168 }
169
170 // Serial Port
171 // -----------
172 if (settings.value("serialMountPoint").toString() == _staID) {
173 _serialPort = new QextSerialPort(
174 settings.value("serialPortName").toString() );
175 QString hlp = settings.value("serialBaudRate").toString();
176 if (hlp == "110") {
177 _serialPort->setBaudRate(BAUD110);
178 }
179 else if (hlp == "300") {
180 _serialPort->setBaudRate(BAUD300);
181 }
182 else if (hlp == "600") {
183 _serialPort->setBaudRate(BAUD600);
184 }
185 else if (hlp == "1200") {
186 _serialPort->setBaudRate(BAUD1200);
187 }
188 else if (hlp == "2400") {
189 _serialPort->setBaudRate(BAUD2400);
190 }
191 else if (hlp == "4800") {
192 _serialPort->setBaudRate(BAUD4800);
193 }
194 else if (hlp == "9600") {
195 _serialPort->setBaudRate(BAUD9600);
196 }
197 else if (hlp == "19200") {
198 _serialPort->setBaudRate(BAUD19200);
199 }
200 else if (hlp == "38400") {
201 _serialPort->setBaudRate(BAUD38400);
202 }
203 else if (hlp == "57600") {
204 _serialPort->setBaudRate(BAUD57600);
205 }
206 else if (hlp == "115200") {
207 _serialPort->setBaudRate(BAUD115200);
208 }
209 hlp = settings.value("serialParity").toString();
210 if (hlp == "NONE") {
211 _serialPort->setParity(PAR_NONE);
212 }
213 else if (hlp == "ODD") {
214 _serialPort->setParity(PAR_ODD);
215 }
216 else if (hlp == "EVEN") {
217 _serialPort->setParity(PAR_EVEN);
218 }
219 else if (hlp == "SPACE") {
220 _serialPort->setParity(PAR_SPACE);
221 }
222 hlp = settings.value("serialDataBits").toString();
223 if (hlp == "5") {
224 _serialPort->setDataBits(DATA_5);
225 }
226 else if (hlp == "6") {
227 _serialPort->setDataBits(DATA_6);
228 }
229 else if (hlp == "7") {
230 _serialPort->setDataBits(DATA_7);
231 }
232 else if (hlp == "8") {
233 _serialPort->setDataBits(DATA_8);
234 }
235 hlp = settings.value("serialStopBits").toString();
236 if (hlp == "1") {
237 _serialPort->setStopBits(STOP_1);
238 }
239 else if (hlp == "2") {
240 _serialPort->setStopBits(STOP_2);
241 }
242 _serialPort->open(QIODevice::ReadWrite|QIODevice::Unbuffered);
243 if (!_serialPort->isOpen()) {
244 delete _serialPort;
245 _serialPort = 0;
246 emit(newMessage((_staID + ": Cannot open serial port\n"), true));
247 }
248
249 connect(_serialPort, SIGNAL(readyRead()),
250 this, SLOT(slotSerialReadyRead()));
251
252 // Serial File Output
253 // ------------------
254 QString serialFileNMEA = settings.value("serialFileNMEA").toString();
255 if (!serialFileNMEA.isEmpty()) {
256 _serialOutFile = new QFile(serialFileNMEA);
257 _serialOutFile->open(QIODevice::WriteOnly);
258 }
259 else {
260 _serialOutFile = 0;
261 }
262 }
263 else {
264 _serialPort = 0;
265 }
266
267 // Raw Output
268 // ----------
269 // QByteArray rawOutFileName = "./" + _staID + ".raw";
270 // _rawOutFile = new QFile(rawOutFileName);
271 // _rawOutFile->open(QIODevice::WriteOnly);
272
273
274 // Instantiate the decoder
275 // -----------------------
276 if (_format.indexOf("RTCM_2") != -1) {
277 emit(newMessage(_staID + ": Get data in RTCM 2.x format", true));
278 _decoder = new RTCM2Decoder(_staID.data());
279 }
280 else if (_format.indexOf("RTCM_3") != -1) {
281 emit(newMessage(_staID + ": Get data in RTCM 3.x format", true));
282 _decoder = new RTCM3Decoder(_staID);
283 connect((RTCM3Decoder*) _decoder, SIGNAL(newMessage(QByteArray,bool)),
284 this, SIGNAL(newMessage(QByteArray,bool)));
285 }
286 else if (_format.indexOf("RTIGS") != -1) {
287 emit(newMessage(_staID + ": Get data in RTIGS format", true));
288 _decoder = new RTIGSDecoder();
289 }
290 else if (_format.indexOf("GPSS") != -1 || _format.indexOf("BNC") != -1) {
291 emit(newMessage(_staID + ": Get Data in GPSS format", true));
292 _decoder = new gpssDecoder();
293 }
294 else if (_format.indexOf("ZERO") != -1) {
295 emit(newMessage(_staID + ": Get data in original format", true));
296 _decoder = new bncZeroDecoder(_staID);
297 }
298 else {
299 emit(newMessage(_staID + ": Unknown data format " + _format, true));
300 _isToBeDeleted = true;
301 delete this;
302 }
303
304 _latencyChecker = new latencyChecker(_staID);
305
306 msleep(100); //sleep 0.1 sec
307}
308
309// Destructor
310////////////////////////////////////////////////////////////////////////////
311bncGetThread::~bncGetThread() {
312 if (_query) {
313 _query->stop();
314 delete _query;
315 }
316 delete _decoder;
317 delete _rnx;
318 delete _rawInpFile;
319 delete _rawOutFile;
320 delete _serialPort;
321 delete _latencyChecker;
322 emit getThreadFinished(_staID);
323}
324
325//
326////////////////////////////////////////////////////////////////////////////
327void bncGetThread::terminate() {
328 _isToBeDeleted = true;
329 if (!isRunning()) {
330 delete this;
331 }
332}
333
334// Run
335////////////////////////////////////////////////////////////////////////////
336void bncGetThread::run() {
337
338 while (true) {
339 try {
340 if (_isToBeDeleted) {
341 QThread::exit(0);
342 this->deleteLater();
343 return;
344 }
345
346 if (tryReconnect() != success) {
347 _latencyChecker->checkReconnect();
348 continue;
349 }
350
351 // Delete old observations
352 // -----------------------
353 QListIterator<p_obs> itOld(_decoder->_obsList);
354 while (itOld.hasNext()) {
355 delete itOld.next();
356 }
357 _decoder->_obsList.clear();
358
359 // Read Data
360 // ---------
361 QByteArray data;
362 if (_query) {
363 _query->waitForReadyRead(data);
364 }
365 else if (_rawInpFile) {
366 const qint64 maxBytes = 1024;
367 data = _rawInpFile->read(maxBytes);
368 if (data.isEmpty()) {
369 cout << "no more data" << endl;
370 ::exit(0);
371 }
372 }
373 qint64 nBytes = data.size();
374
375 // Timeout, reconnect
376 // ------------------
377 if (nBytes == 0) {
378 _latencyChecker->checkReconnect();
379 emit(newMessage(_staID + ": Data timeout, reconnecting", true));
380 continue;
381 }
382 else {
383 emit newBytes(_staID, nBytes);
384 }
385
386 // Output Data
387 // -----------
388 if (_rawOutFile) {
389 _rawOutFile->write(data);
390 _rawOutFile->flush();
391 }
392 if (_serialPort) {
393 _serialPort->write(data);
394 }
395
396 // Decode Data
397 // -----------
398 vector<string> errmsg;
399 t_irc irc = _decoder->Decode(data.data(), data.size(), errmsg);
400
401 // Perform various scans and checks
402 // --------------------------------
403 _latencyChecker->checkOutage(irc == success);
404 _latencyChecker->checkObsLatency(_decoder->_obsList);
405 _latencyChecker->checkCorrLatency(_decoder->corrGPSEpochTime());
406
407 scanRTCM();
408
409 // Loop over all observations (observations output)
410 // ------------------------------------------------
411 QListIterator<p_obs> it(_decoder->_obsList);
412 while (it.hasNext()) {
413 p_obs obs = it.next();
414
415 // Check observation epoch
416 // -----------------------
417 if (!_rawInpFile && !dynamic_cast<gpssDecoder*>(_decoder)) {
418 int week;
419 double sec;
420 currentGPSWeeks(week, sec);
421 const double secPerWeek = 7.0 * 24.0 * 3600.0;
422
423 if (week < obs->_o.GPSWeek) {
424 week += 1;
425 sec -= secPerWeek;
426 }
427 if (week > obs->_o.GPSWeek) {
428 week -= 1;
429 sec += secPerWeek;
430 }
431 double dt = fabs(sec - obs->_o.GPSWeeks);
432 const double maxDt = 600.0;
433 if (week != obs->_o.GPSWeek || dt > maxDt) {
434 emit( newMessage(_staID + ": Wrong observation epoch(s)", true) );
435 delete obs;
436 continue;
437 }
438 }
439
440 // RINEX Output
441 // ------------
442 if (_rnx) {
443 long iSec = long(floor(obs->_o.GPSWeeks+0.5));
444 long newTime = obs->_o.GPSWeek * 7*24*3600 + iSec;
445 if (_samplingRate == 0 || iSec % _samplingRate == 0) {
446 _rnx->deepCopy(obs);
447 }
448 _rnx->dumpEpoch(newTime);
449 }
450
451 // Emit new observation signal
452 // ---------------------------
453 bool firstObs = (obs == _decoder->_obsList.first());
454 obs->_status = t_obs::posted;
455 emit newObs(_staID, firstObs, obs);
456 }
457 _decoder->_obsList.clear();
458 }
459 catch (...) {
460 emit(newMessage(_staID + "bncGetThread exception", true));
461 _isToBeDeleted = true;
462 }
463 }
464}
465
466// Try Re-Connect
467////////////////////////////////////////////////////////////////////////////
468t_irc bncGetThread::tryReconnect() {
469
470 // Easy Return
471 // -----------
472 if (_query && _query->status() == bncNetQuery::running) {
473 _nextSleep = 0;
474 return success;
475 }
476
477 // Start a new query
478 // -----------------
479 if (!_rawInpFile) {
480
481 sleep(_nextSleep);
482 if (_nextSleep == 0) {
483 _nextSleep = 1;
484 }
485 else {
486 _nextSleep = 2 * _nextSleep;
487 if (_nextSleep > 256) {
488 _nextSleep = 256;
489 }
490 }
491
492 delete _query;
493 if (_ntripVersion == "R") {
494 _query = new bncNetQueryRtp();
495 }
496 else if (_ntripVersion == "2") {
497 _query = new bncNetQueryV2();
498 }
499 else {
500 _query = new bncNetQueryV1();
501 }
502 if (_nmea == "yes") {
503 QByteArray gga = ggaString(_latitude, _longitude, _height);
504 _query->startRequest(_mountPoint, gga);
505 }
506 else {
507 _query->startRequest(_mountPoint, "");
508 }
509 if (_query->status() != bncNetQuery::running) {
510 return failure;
511 }
512 }
513
514 if (_rnx) {
515 _rnx->setReconnectFlag(true);
516 }
517
518 return success;
519}
520
521// RTCM scan output
522//////////////////////////////////////////////////////////////////////////////
523void bncGetThread::scanRTCM() {
524
525 bncSettings settings;
526 if ( Qt::CheckState(settings.value("scanRTCM").toInt()) == Qt::Checked ) {
527
528 if ( _miscMount == _staID || _miscMount == "ALL" ) {
529
530 // RTCM message types
531 // ------------------
532 for (int ii = 0; ii <_decoder->_typeList.size(); ii++) {
533 QString type = QString("%1 ").arg(_decoder->_typeList[ii]);
534 emit(newMessage(_staID + ": Received message type " + type.toAscii(), true));
535 }
536
537 // RTCMv3 antenna descriptor
538 // -------------------------
539 for (int ii=0;ii<_decoder->_antType.size();ii++) {
540 QString ant1 = QString("%1 ").arg(_decoder->_antType[ii]);
541 emit(newMessage(_staID + ": Antenna descriptor " + ant1.toAscii(), true));
542 }
543
544 // RTCM Antenna Coordinates
545 // ------------------------
546 for (int ii=0; ii <_decoder->_antList.size(); ii++) {
547 QByteArray antT;
548 if (_decoder->_antList[ii].type == GPSDecoder::t_antInfo::ARP) {
549 antT = "ARP";
550 }
551 else if (_decoder->_antList[ii].type == GPSDecoder::t_antInfo::APC) {
552 antT = "APC";
553 }
554 QByteArray ant1, ant2, ant3;
555 ant1 = QString("%1 ").arg(_decoder->_antList[ii].xx,0,'f',4).toAscii();
556 ant2 = QString("%1 ").arg(_decoder->_antList[ii].yy,0,'f',4).toAscii();
557 ant3 = QString("%1 ").arg(_decoder->_antList[ii].zz,0,'f',4).toAscii();
558 emit(newMessage(_staID + ": " + antT + " (ITRF) X " + ant1 + "m", true));
559 emit(newMessage(_staID + ": " + antT + " (ITRF) Y " + ant2 + "m", true));
560 emit(newMessage(_staID + ": " + antT + " (ITRF) Z " + ant3 + "m", true));
561 if (_decoder->_antList[ii].height_f) {
562 QByteArray ant4 = QString("%1 ").arg(_decoder->_antList[ii].height,0,'f',4).toAscii();
563 emit(newMessage(_staID + ": Antenna height above marker " + ant4 + "m", true));
564 }
565 emit(newAntCrd(_staID, _decoder->_antList[ii].xx,
566 _decoder->_antList[ii].yy, _decoder->_antList[ii].zz,
567 antT));
568 }
569 }
570 }
571
572 _decoder->_typeList.clear();
573 _decoder->_antType.clear();
574 _decoder->_antList.clear();
575}
576
577// Handle Data from Serial Port
578////////////////////////////////////////////////////////////////////////////
579void bncGetThread::slotSerialReadyRead() {
580
581}
Note: See TracBrowser for help on using the repository browser.