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 <QComboBox> |
---|
46 | #include <QDialog> |
---|
47 | #include <QFile> |
---|
48 | #include <QTextStream> |
---|
49 | #include <QMutex> |
---|
50 | #include <QPushButton> |
---|
51 | #include <QTableWidget> |
---|
52 | #include <QTime> |
---|
53 | |
---|
54 | #include "bncgetthread.h" |
---|
55 | #include "bnctabledlg.h" |
---|
56 | #include "bnccore.h" |
---|
57 | #include "bncutils.h" |
---|
58 | #include "bnctime.h" |
---|
59 | #include "bnczerodecoder.h" |
---|
60 | #include "bncnetqueryv0.h" |
---|
61 | #include "bncnetqueryv1.h" |
---|
62 | #include "bncnetqueryv2.h" |
---|
63 | #include "bncnetqueryrtp.h" |
---|
64 | #include "bncnetqueryudp.h" |
---|
65 | #include "bncnetqueryudp0.h" |
---|
66 | #include "bncnetquerys.h" |
---|
67 | #include "bncsettings.h" |
---|
68 | #include "latencychecker.h" |
---|
69 | #include "upload/bncrtnetdecoder.h" |
---|
70 | #include "RTCM/RTCM2Decoder.h" |
---|
71 | #include "RTCM3/RTCM3Decoder.h" |
---|
72 | #include "serial/qextserialport.h" |
---|
73 | |
---|
74 | using namespace std; |
---|
75 | |
---|
76 | // Constructor 1 |
---|
77 | //////////////////////////////////////////////////////////////////////////// |
---|
78 | bncGetThread::bncGetThread(bncRawFile* rawFile) { |
---|
79 | |
---|
80 | _rawFile = rawFile; |
---|
81 | _format = rawFile->format(); |
---|
82 | _staID = rawFile->staID(); |
---|
83 | _rawOutput = false; |
---|
84 | _ntripVersion = "N"; |
---|
85 | |
---|
86 | initialize(); |
---|
87 | } |
---|
88 | |
---|
89 | // Constructor 2 |
---|
90 | //////////////////////////////////////////////////////////////////////////// |
---|
91 | bncGetThread::bncGetThread(const QUrl& mountPoint, const QByteArray& format, |
---|
92 | const QByteArray& latitude, const QByteArray& longitude, |
---|
93 | const QByteArray& nmea, const QByteArray& ntripVersion) { |
---|
94 | _rawFile = 0; |
---|
95 | _mountPoint = mountPoint; |
---|
96 | _staID = mountPoint.path().mid(1).toLatin1(); |
---|
97 | _format = format; |
---|
98 | _latitude = latitude; |
---|
99 | _longitude = longitude; |
---|
100 | _nmea = nmea; |
---|
101 | _ntripVersion = ntripVersion; |
---|
102 | |
---|
103 | bncSettings settings; |
---|
104 | if (!settings.value("rawOutFile").toString().isEmpty()) { |
---|
105 | _rawOutput = true; |
---|
106 | } |
---|
107 | else { |
---|
108 | _rawOutput = false; |
---|
109 | } |
---|
110 | if (!settings.value("miscMount").toString().isEmpty()) { |
---|
111 | _latencycheck = true; |
---|
112 | } |
---|
113 | else { |
---|
114 | _latencycheck = false; |
---|
115 | } |
---|
116 | initialize(); |
---|
117 | initDecoder(); |
---|
118 | } |
---|
119 | |
---|
120 | // Initialization (common part of the constructor) |
---|
121 | //////////////////////////////////////////////////////////////////////////// |
---|
122 | void bncGetThread::initialize() { |
---|
123 | |
---|
124 | bncSettings settings; |
---|
125 | |
---|
126 | setTerminationEnabled(true); |
---|
127 | |
---|
128 | connect(this, SIGNAL(newMessage(QByteArray,bool)), |
---|
129 | BNC_CORE, SLOT(slotMessage(const QByteArray,bool))); |
---|
130 | |
---|
131 | _isToBeDeleted = false; |
---|
132 | _query = 0; |
---|
133 | _nextSleep = 0; |
---|
134 | _miscMount = settings.value("miscMount").toString(); |
---|
135 | _decoder = 0; |
---|
136 | |
---|
137 | // NMEA Port |
---|
138 | // ----------- |
---|
139 | QListIterator<QString> iSta(settings.value("PPP/staTable").toStringList()); |
---|
140 | int nmeaPort = 0; |
---|
141 | while (iSta.hasNext()) { |
---|
142 | QStringList hlp = iSta.next().split(","); |
---|
143 | if (hlp.size() < 10) { |
---|
144 | continue; |
---|
145 | } |
---|
146 | QByteArray mp = hlp[0].toLatin1(); |
---|
147 | if (_staID == mp) { |
---|
148 | nmeaPort = hlp[9].toInt(); |
---|
149 | } |
---|
150 | } |
---|
151 | if (nmeaPort != 0) { |
---|
152 | _nmeaServer = new QTcpServer; |
---|
153 | if (!_nmeaServer->listen(QHostAddress::Any, nmeaPort)) { |
---|
154 | emit newMessage("bncCaster: Cannot listen on port", true); |
---|
155 | } else { |
---|
156 | connect(_nmeaServer, SIGNAL(newConnection()), this, |
---|
157 | SLOT(slotNewNMEAConnection())); |
---|
158 | connect(BNC_CORE, SIGNAL(newNMEAstr(QByteArray, QByteArray)), this, |
---|
159 | SLOT(slotNewNMEAstr(QByteArray, QByteArray))); |
---|
160 | _nmeaSockets = new QList<QTcpSocket*>; |
---|
161 | _nmeaPortsMap[_staID] = nmeaPort; |
---|
162 | } |
---|
163 | } else { |
---|
164 | _nmeaServer = 0; |
---|
165 | _nmeaSockets = 0; |
---|
166 | } |
---|
167 | |
---|
168 | // Serial Port |
---|
169 | // ----------- |
---|
170 | _serialNMEA = NO_NMEA; |
---|
171 | _serialOutFile = 0; |
---|
172 | _serialPort = 0; |
---|
173 | |
---|
174 | if (!_staID.isEmpty() |
---|
175 | && settings.value("serialMountPoint").toString() == _staID) { |
---|
176 | _serialPort = new QextSerialPort( |
---|
177 | settings.value("serialPortName").toString()); |
---|
178 | _serialPort->setTimeout(0, 100); |
---|
179 | |
---|
180 | // Baud Rate |
---|
181 | // --------- |
---|
182 | QString hlp = settings.value("serialBaudRate").toString(); |
---|
183 | if (hlp == "110") { |
---|
184 | _serialPort->setBaudRate(BAUD110); |
---|
185 | } else if (hlp == "300") { |
---|
186 | _serialPort->setBaudRate(BAUD300); |
---|
187 | } else if (hlp == "600") { |
---|
188 | _serialPort->setBaudRate(BAUD600); |
---|
189 | } else if (hlp == "1200") { |
---|
190 | _serialPort->setBaudRate(BAUD1200); |
---|
191 | } else if (hlp == "2400") { |
---|
192 | _serialPort->setBaudRate(BAUD2400); |
---|
193 | } else if (hlp == "4800") { |
---|
194 | _serialPort->setBaudRate(BAUD4800); |
---|
195 | } else if (hlp == "9600") { |
---|
196 | _serialPort->setBaudRate(BAUD9600); |
---|
197 | } else if (hlp == "19200") { |
---|
198 | _serialPort->setBaudRate(BAUD19200); |
---|
199 | } else if (hlp == "38400") { |
---|
200 | _serialPort->setBaudRate(BAUD38400); |
---|
201 | } else if (hlp == "57600") { |
---|
202 | _serialPort->setBaudRate(BAUD57600); |
---|
203 | } else if (hlp == "115200") { |
---|
204 | _serialPort->setBaudRate(BAUD115200); |
---|
205 | } |
---|
206 | |
---|
207 | // Parity |
---|
208 | // ------ |
---|
209 | hlp = settings.value("serialParity").toString(); |
---|
210 | if (hlp == "NONE") { |
---|
211 | _serialPort->setParity(PAR_NONE); |
---|
212 | } else if (hlp == "ODD") { |
---|
213 | _serialPort->setParity(PAR_ODD); |
---|
214 | } else if (hlp == "EVEN") { |
---|
215 | _serialPort->setParity(PAR_EVEN); |
---|
216 | } else if (hlp == "SPACE") { |
---|
217 | _serialPort->setParity(PAR_SPACE); |
---|
218 | } |
---|
219 | |
---|
220 | // Data Bits |
---|
221 | // --------- |
---|
222 | hlp = settings.value("serialDataBits").toString(); |
---|
223 | if (hlp == "5") { |
---|
224 | _serialPort->setDataBits(DATA_5); |
---|
225 | } else if (hlp == "6") { |
---|
226 | _serialPort->setDataBits(DATA_6); |
---|
227 | } else if (hlp == "7") { |
---|
228 | _serialPort->setDataBits(DATA_7); |
---|
229 | } else if (hlp == "8") { |
---|
230 | _serialPort->setDataBits(DATA_8); |
---|
231 | } |
---|
232 | hlp = settings.value("serialStopBits").toString(); |
---|
233 | if (hlp == "1") { |
---|
234 | _serialPort->setStopBits(STOP_1); |
---|
235 | } else if (hlp == "2") { |
---|
236 | _serialPort->setStopBits(STOP_2); |
---|
237 | } |
---|
238 | |
---|
239 | // Flow Control |
---|
240 | // ------------ |
---|
241 | hlp = settings.value("serialFlowControl").toString(); |
---|
242 | if (hlp == "XONXOFF") { |
---|
243 | _serialPort->setFlowControl(FLOW_XONXOFF); |
---|
244 | } else if (hlp == "HARDWARE") { |
---|
245 | _serialPort->setFlowControl(FLOW_HARDWARE); |
---|
246 | } else { |
---|
247 | _serialPort->setFlowControl(FLOW_OFF); |
---|
248 | } |
---|
249 | |
---|
250 | // Open Serial Port |
---|
251 | // ---------------- |
---|
252 | _serialPort->open(QIODevice::ReadWrite | QIODevice::Unbuffered); |
---|
253 | if (!_serialPort->isOpen()) { |
---|
254 | delete _serialPort; |
---|
255 | _serialPort = 0; |
---|
256 | emit(newMessage((_staID + ": Cannot open serial port\n"), true)); |
---|
257 | } |
---|
258 | connect(_serialPort, SIGNAL(readyRead()), this, |
---|
259 | SLOT(slotSerialReadyRead())); |
---|
260 | |
---|
261 | // Automatic NMEA |
---|
262 | // -------------- |
---|
263 | QString nmeaMode = settings.value("serialAutoNMEA").toString(); |
---|
264 | if (nmeaMode == "Auto") { |
---|
265 | _serialNMEA = AUTO_NMEA; |
---|
266 | QString fName = settings.value("serialFileNMEA").toString(); |
---|
267 | if (!fName.isEmpty()) { |
---|
268 | _serialOutFile = new QFile(fName); |
---|
269 | if (Qt::CheckState(settings.value("rnxAppend").toInt()) |
---|
270 | == Qt::Checked) { |
---|
271 | _serialOutFile->open(QIODevice::WriteOnly | QIODevice::Append); |
---|
272 | } else { |
---|
273 | _serialOutFile->open(QIODevice::WriteOnly); |
---|
274 | } |
---|
275 | } |
---|
276 | } |
---|
277 | // Manual NMEA |
---|
278 | // ----------- |
---|
279 | if ((nmeaMode == "Manual GPGGA") || (nmeaMode == "Manual GNGGA")) { |
---|
280 | _serialNMEA = MANUAL_NMEA; |
---|
281 | bncSettings settings; |
---|
282 | _manualNMEASampl = settings.value("serialManualNMEASampling").toInt(); |
---|
283 | QString hlp = settings.value("serialHeightNMEA").toString(); |
---|
284 | if (hlp.isEmpty()) { |
---|
285 | hlp = "0.0"; |
---|
286 | } |
---|
287 | QByteArray _serialHeightNMEA = hlp.toLatin1(); |
---|
288 | _manualNMEAString = ggaString(_latitude, _longitude, _serialHeightNMEA, |
---|
289 | nmeaMode); |
---|
290 | } |
---|
291 | } |
---|
292 | |
---|
293 | if (!_staID.isEmpty() && _latencycheck) { |
---|
294 | _latencyChecker = new latencyChecker(_staID); |
---|
295 | obs = false; |
---|
296 | ssrOrb = false; |
---|
297 | ssrClk = false; |
---|
298 | ssrOrbClk = false; |
---|
299 | ssrCbi = false; |
---|
300 | ssrPbi = false; |
---|
301 | ssrVtec = false; |
---|
302 | ssrUra = false; |
---|
303 | ssrHr = false; |
---|
304 | _ssrEpoch = 0; |
---|
305 | } else { |
---|
306 | _latencyChecker = 0; |
---|
307 | } |
---|
308 | } |
---|
309 | |
---|
310 | // Instantiate the decoder |
---|
311 | ////////////////////////////////////////////////////////////////////////////// |
---|
312 | t_irc bncGetThread::initDecoder() { |
---|
313 | |
---|
314 | _decoder = 0; |
---|
315 | |
---|
316 | if (_format.indexOf("RTCM_2") != -1 || _format.indexOf("RTCM2") != -1 |
---|
317 | || _format.indexOf("RTCM 2") != -1) { |
---|
318 | emit(newMessage(_staID + ": Get data in RTCM 2.x format", true)); |
---|
319 | _decoder = new RTCM2Decoder(_staID.data()); |
---|
320 | } else if (_format.indexOf("RTCM_3") != -1 || _format.indexOf("RTCM3") != -1 |
---|
321 | || _format.indexOf("RTCM 3") != -1) { |
---|
322 | emit(newMessage(_staID + ": Get data in RTCM 3.x format", true)); |
---|
323 | RTCM3Decoder* newDecoder = new RTCM3Decoder(_staID, _rawFile); |
---|
324 | _decoder = newDecoder; |
---|
325 | connect((RTCM3Decoder*) newDecoder, SIGNAL(newMessage(QByteArray,bool)), |
---|
326 | this, SIGNAL(newMessage(QByteArray,bool))); |
---|
327 | } else if (_format.indexOf("ZERO") != -1) { |
---|
328 | emit(newMessage(_staID + ": Get data in original format", true)); |
---|
329 | _decoder = new bncZeroDecoder(_staID); |
---|
330 | } else if (_format.indexOf("RTNET") != -1) { |
---|
331 | emit(newMessage(_staID + ": Get data in RTNet format", true)); |
---|
332 | _decoder = new bncRtnetDecoder(); |
---|
333 | } else { |
---|
334 | emit(newMessage(_staID + ": Unknown data format " + _format, true)); |
---|
335 | _isToBeDeleted = true; |
---|
336 | return failure; |
---|
337 | } |
---|
338 | |
---|
339 | msleep(100); //sleep 0.1 sec |
---|
340 | |
---|
341 | _decoder->initRinex(_staID, _mountPoint, _latitude, _longitude, _nmea, |
---|
342 | _ntripVersion); |
---|
343 | |
---|
344 | if (_rawFile) { |
---|
345 | _decodersRaw[_staID] = _decoder; |
---|
346 | } |
---|
347 | |
---|
348 | return success; |
---|
349 | } |
---|
350 | |
---|
351 | // Current decoder in use |
---|
352 | //////////////////////////////////////////////////////////////////////////// |
---|
353 | GPSDecoder* bncGetThread::decoder() { |
---|
354 | if (!_rawFile) { |
---|
355 | return _decoder; |
---|
356 | } else { |
---|
357 | if (_decodersRaw.contains(_staID) || initDecoder() == success) { |
---|
358 | return _decodersRaw[_staID]; |
---|
359 | } |
---|
360 | } |
---|
361 | return 0; |
---|
362 | } |
---|
363 | |
---|
364 | // Destructor |
---|
365 | //////////////////////////////////////////////////////////////////////////// |
---|
366 | bncGetThread::~bncGetThread() { |
---|
367 | if (isRunning()) { |
---|
368 | wait(); |
---|
369 | } |
---|
370 | if (_query) { |
---|
371 | _query->stop(); |
---|
372 | _query->deleteLater(); |
---|
373 | } |
---|
374 | if (_rawFile) { |
---|
375 | QMapIterator<QString, GPSDecoder*> it(_decodersRaw); |
---|
376 | while (it.hasNext()) { |
---|
377 | it.next(); |
---|
378 | delete it.value(); |
---|
379 | } |
---|
380 | } else { |
---|
381 | delete _decoder; |
---|
382 | } |
---|
383 | delete _rawFile; |
---|
384 | delete _serialOutFile; |
---|
385 | delete _serialPort; |
---|
386 | delete _latencyChecker; |
---|
387 | emit getThreadFinished(_staID); |
---|
388 | } |
---|
389 | |
---|
390 | // |
---|
391 | //////////////////////////////////////////////////////////////////////////// |
---|
392 | void bncGetThread::terminate() { |
---|
393 | _isToBeDeleted = true; |
---|
394 | |
---|
395 | if (_nmeaPortsMap.contains(_staID)) { |
---|
396 | _nmeaPortsMap.remove(_staID); |
---|
397 | } |
---|
398 | if (_nmeaServer) { |
---|
399 | delete _nmeaServer; |
---|
400 | } |
---|
401 | if (_nmeaSockets) { |
---|
402 | delete _nmeaSockets; |
---|
403 | } |
---|
404 | |
---|
405 | #ifdef BNC_DEBUG |
---|
406 | if (BNC_CORE->mode() != t_bncCore::interactive) { |
---|
407 | while (!isFinished()) { |
---|
408 | wait(); |
---|
409 | } |
---|
410 | delete this; |
---|
411 | } else { |
---|
412 | if (!isRunning()) { |
---|
413 | delete this; |
---|
414 | } |
---|
415 | } |
---|
416 | #else |
---|
417 | if (!isRunning()) {delete this;} |
---|
418 | #endif |
---|
419 | |
---|
420 | } |
---|
421 | |
---|
422 | // Run |
---|
423 | //////////////////////////////////////////////////////////////////////////// |
---|
424 | void bncGetThread::run() { |
---|
425 | |
---|
426 | while (true) { |
---|
427 | try { |
---|
428 | if (_isToBeDeleted) { |
---|
429 | QThread::exit(0); |
---|
430 | this->deleteLater(); |
---|
431 | return; |
---|
432 | } |
---|
433 | |
---|
434 | if (tryReconnect() != success) { |
---|
435 | if (_latencyChecker) { |
---|
436 | _latencyChecker->checkReconnect(); |
---|
437 | } |
---|
438 | continue; |
---|
439 | } |
---|
440 | |
---|
441 | // Delete old observations |
---|
442 | // ----------------------- |
---|
443 | if (_rawFile) { |
---|
444 | QMapIterator<QString, GPSDecoder*> itDec(_decodersRaw); |
---|
445 | while (itDec.hasNext()) { |
---|
446 | itDec.next(); |
---|
447 | GPSDecoder* decoder = itDec.value(); |
---|
448 | decoder->_obsList.clear(); |
---|
449 | } |
---|
450 | } else { |
---|
451 | _decoder->_obsList.clear(); |
---|
452 | } |
---|
453 | |
---|
454 | // Read Data |
---|
455 | // --------- |
---|
456 | QByteArray data; |
---|
457 | if (_query) { |
---|
458 | _query->waitForReadyRead(data); |
---|
459 | } else if (_rawFile) { |
---|
460 | data = _rawFile->readChunk(); |
---|
461 | _format = _rawFile->format(); |
---|
462 | _staID = _rawFile->staID(); |
---|
463 | |
---|
464 | QCoreApplication::processEvents(); |
---|
465 | |
---|
466 | if (data.isEmpty() || BNC_CORE->sigintReceived) { |
---|
467 | cout << "no more data or Ctrl-C received" << endl; |
---|
468 | BNC_CORE->stopCombination(); |
---|
469 | BNC_CORE->stopPPP(); |
---|
470 | ::exit(0); |
---|
471 | } |
---|
472 | } |
---|
473 | |
---|
474 | qint64 nBytes = data.size(); |
---|
475 | |
---|
476 | // Timeout, reconnect |
---|
477 | // ------------------ |
---|
478 | if (nBytes == 0) { |
---|
479 | if (_latencyChecker) { |
---|
480 | _latencyChecker->checkReconnect(); |
---|
481 | } |
---|
482 | emit(newMessage(_staID + ": Data timeout, reconnecting", true)); |
---|
483 | msleep(10000); //sleep 10 sec, G. Weber |
---|
484 | continue; |
---|
485 | } else { |
---|
486 | emit newBytes(_staID, nBytes); |
---|
487 | emit newRawData(_staID, data); |
---|
488 | } |
---|
489 | |
---|
490 | // Output Data |
---|
491 | // ----------- |
---|
492 | if (_rawOutput) { |
---|
493 | BNC_CORE->writeRawData(data, _staID, _format); |
---|
494 | } |
---|
495 | |
---|
496 | if (_serialPort) { |
---|
497 | slotSerialReadyRead(); |
---|
498 | _serialPort->write(data); |
---|
499 | } |
---|
500 | |
---|
501 | // Decode Data |
---|
502 | // ----------- |
---|
503 | vector<string> errmsg; |
---|
504 | if (!decoder()) { |
---|
505 | _isToBeDeleted = true; |
---|
506 | continue; |
---|
507 | } |
---|
508 | |
---|
509 | t_irc irc = decoder()->Decode(data.data(), data.size(), errmsg); |
---|
510 | |
---|
511 | if (irc != success) { |
---|
512 | continue; |
---|
513 | } |
---|
514 | // Perform various scans and checks |
---|
515 | // -------------------------------- |
---|
516 | if (_latencyChecker) { |
---|
517 | _latencyChecker->checkOutage(irc); |
---|
518 | QListIterator<int> it(decoder()->_typeList); |
---|
519 | _ssrEpoch = static_cast<int>(decoder()->corrGPSEpochTime()); |
---|
520 | if (_ssrEpoch != -1) { |
---|
521 | if (ssrOrb) { |
---|
522 | _latencyChecker->checkCorrLatency(_ssrEpoch, 1057); |
---|
523 | ssrOrb = false; |
---|
524 | } |
---|
525 | if (ssrClk) { |
---|
526 | _latencyChecker->checkCorrLatency(_ssrEpoch, 1058); |
---|
527 | ssrClk = false; |
---|
528 | } |
---|
529 | if (ssrOrbClk) { |
---|
530 | _latencyChecker->checkCorrLatency(_ssrEpoch, 1060); |
---|
531 | ssrOrbClk = false; |
---|
532 | } |
---|
533 | if (ssrCbi) { |
---|
534 | _latencyChecker->checkCorrLatency(_ssrEpoch, 1059); |
---|
535 | ssrCbi = false; |
---|
536 | } |
---|
537 | if (ssrPbi) { |
---|
538 | _latencyChecker->checkCorrLatency(_ssrEpoch, 1265); |
---|
539 | ssrPbi = false; |
---|
540 | } |
---|
541 | if (ssrVtec) { |
---|
542 | _latencyChecker->checkCorrLatency(_ssrEpoch, 1264); |
---|
543 | ssrVtec = false; |
---|
544 | } |
---|
545 | if (ssrUra) { |
---|
546 | _latencyChecker->checkCorrLatency(_ssrEpoch, 1061); |
---|
547 | ssrUra = false; |
---|
548 | } |
---|
549 | if (ssrHr) { |
---|
550 | _latencyChecker->checkCorrLatency(_ssrEpoch, 1062); |
---|
551 | ssrHr = false; |
---|
552 | } |
---|
553 | } |
---|
554 | while (it.hasNext()) { |
---|
555 | int rtcmType = it.next(); |
---|
556 | if ((rtcmType >= 1001 && rtcmType <= 1004) || // legacy RTCM OBS |
---|
557 | (rtcmType >= 1009 && rtcmType <= 1012) || // legacy RTCM OBS |
---|
558 | (rtcmType >= 1071 && rtcmType <= 1127)) { // MSM RTCM OBS |
---|
559 | obs = true; |
---|
560 | } else if ((rtcmType >= 1057 && rtcmType <= 1068) || |
---|
561 | (rtcmType >= 1240 && rtcmType <= 1270)) { |
---|
562 | switch (rtcmType) { |
---|
563 | case 1057: case 1063: case 1240: case 1246: case 1252: case 1258: |
---|
564 | ssrOrb = true; |
---|
565 | break; |
---|
566 | case 1058: case 1064: case 1241: case 1247: case 1253: case 1259: |
---|
567 | ssrClk = true; |
---|
568 | break; |
---|
569 | case 1060: case 1066: case 1243: case 1249: case 1255: case 1261: |
---|
570 | ssrOrbClk = true; |
---|
571 | break; |
---|
572 | case 1059: case 1065: case 1242: case 1248: case 1254: case 1260: |
---|
573 | ssrCbi = true; |
---|
574 | break; |
---|
575 | case 1265: case 1266: case 1267: case 1268: case 1269: case 1270: |
---|
576 | ssrPbi = true; |
---|
577 | break; |
---|
578 | case 1264: |
---|
579 | ssrVtec = true; |
---|
580 | break; |
---|
581 | case 1061: case 1067: case 1244: case 1250: case 1256: case 1262: |
---|
582 | ssrUra = true; |
---|
583 | break; |
---|
584 | case 1062: case 1068: case 1245: case 1251: case 1257: case 1263: |
---|
585 | ssrHr = true; |
---|
586 | break; |
---|
587 | } |
---|
588 | } |
---|
589 | } |
---|
590 | if (obs) { |
---|
591 | _latencyChecker->checkObsLatency(decoder()->_obsList); |
---|
592 | } |
---|
593 | emit newLatency(_staID, _latencyChecker->currentLatency()); |
---|
594 | } |
---|
595 | miscScanRTCM(); |
---|
596 | |
---|
597 | // Loop over all observations (observations output) |
---|
598 | // ------------------------------------------------ |
---|
599 | QListIterator<t_satObs> it(decoder()->_obsList); |
---|
600 | |
---|
601 | QList<t_satObs> obsListHlp; |
---|
602 | |
---|
603 | while (it.hasNext()) { |
---|
604 | const t_satObs& obs = it.next(); |
---|
605 | |
---|
606 | // Check observation epoch |
---|
607 | // ----------------------- |
---|
608 | if (!_rawFile) { |
---|
609 | bool wrongObservationEpoch = checkForWrongObsEpoch(obs._time); |
---|
610 | if (wrongObservationEpoch) { |
---|
611 | QString prn(obs._prn.toString().c_str()); |
---|
612 | emit(newMessage( |
---|
613 | _staID + " (" + prn.toLatin1() + ")" |
---|
614 | + ": Wrong observation epoch(s)", false)); |
---|
615 | continue; |
---|
616 | } |
---|
617 | } |
---|
618 | |
---|
619 | // Check observations coming twice (e.g. KOUR0 Problem) |
---|
620 | // ---------------------------------------------------- |
---|
621 | if (!_rawFile) { |
---|
622 | QString prn(obs._prn.toString().c_str()); |
---|
623 | bncTime obsTime = obs._time; |
---|
624 | QMap<QString, bncTime>::const_iterator it = _prnLastEpo.find(prn); |
---|
625 | if (it != _prnLastEpo.end()) { |
---|
626 | bncTime oldTime = it.value(); |
---|
627 | if (obsTime < oldTime) { |
---|
628 | emit(newMessage(_staID + ": old observation " + prn.toLatin1(), false)); |
---|
629 | continue; |
---|
630 | } else if (obsTime == oldTime) { |
---|
631 | emit(newMessage(_staID + ": observation coming more than once " |
---|
632 | + prn.toLatin1(), false)); |
---|
633 | continue; |
---|
634 | } |
---|
635 | } |
---|
636 | _prnLastEpo[prn] = obsTime; |
---|
637 | } |
---|
638 | |
---|
639 | decoder()->dumpRinexEpoch(obs, _format); |
---|
640 | |
---|
641 | // Save observations |
---|
642 | // ----------------- |
---|
643 | obsListHlp.append(obs); |
---|
644 | } |
---|
645 | |
---|
646 | // Emit signal |
---|
647 | // ----------- |
---|
648 | if (!_isToBeDeleted && obsListHlp.size() > 0) { |
---|
649 | emit newObs(_staID, obsListHlp); |
---|
650 | } |
---|
651 | |
---|
652 | } catch (Exception& exc) { |
---|
653 | emit(newMessage(_staID + " " + exc.what(), true)); |
---|
654 | _isToBeDeleted = true; |
---|
655 | } catch (...) { |
---|
656 | emit(newMessage(_staID + " bncGetThread exception", true)); |
---|
657 | _isToBeDeleted = true; |
---|
658 | } |
---|
659 | } |
---|
660 | } |
---|
661 | |
---|
662 | // Try Re-Connect |
---|
663 | //////////////////////////////////////////////////////////////////////////// |
---|
664 | t_irc bncGetThread::tryReconnect() { |
---|
665 | |
---|
666 | // Easy Return |
---|
667 | // ----------- |
---|
668 | if (_query && _query->status() == bncNetQuery::running) { |
---|
669 | _nextSleep = 0; |
---|
670 | if (_rawFile) { |
---|
671 | QMapIterator<QString, GPSDecoder*> itDec(_decodersRaw); |
---|
672 | while (itDec.hasNext()) { |
---|
673 | itDec.next(); |
---|
674 | GPSDecoder* decoder = itDec.value(); |
---|
675 | decoder->setRinexReconnectFlag(false); |
---|
676 | } |
---|
677 | } else { |
---|
678 | _decoder->setRinexReconnectFlag(false); |
---|
679 | } |
---|
680 | return success; |
---|
681 | } |
---|
682 | |
---|
683 | // Start a new query |
---|
684 | // ----------------- |
---|
685 | if (!_rawFile) { |
---|
686 | |
---|
687 | sleep(_nextSleep); |
---|
688 | if (_nextSleep == 0) { |
---|
689 | _nextSleep = 1; |
---|
690 | } else { |
---|
691 | _nextSleep = 2 * _nextSleep; |
---|
692 | if (_nextSleep > 256) { |
---|
693 | _nextSleep = 256; |
---|
694 | } |
---|
695 | #ifdef MLS_SOFTWARE |
---|
696 | if (_nextSleep > 4) { |
---|
697 | _nextSleep = 4; |
---|
698 | } |
---|
699 | #endif |
---|
700 | } |
---|
701 | delete _query; |
---|
702 | if (_ntripVersion == "U") { |
---|
703 | _query = new bncNetQueryUdp(); |
---|
704 | } else if (_ntripVersion == "R") { |
---|
705 | _query = new bncNetQueryRtp(); |
---|
706 | } else if (_ntripVersion == "S") { |
---|
707 | _query = new bncNetQueryS(); |
---|
708 | } else if (_ntripVersion == "N") { |
---|
709 | _query = new bncNetQueryV0(); |
---|
710 | } else if (_ntripVersion == "UN") { |
---|
711 | _query = new bncNetQueryUdp0(); |
---|
712 | } else if (_ntripVersion == "2") { |
---|
713 | _query = new bncNetQueryV2(false); |
---|
714 | } else if (_ntripVersion == "2s") { |
---|
715 | _query = new bncNetQueryV2(true); |
---|
716 | } else { |
---|
717 | _query = new bncNetQueryV1(); |
---|
718 | } |
---|
719 | if (_nmea == "yes") { |
---|
720 | if (_serialNMEA == MANUAL_NMEA) { |
---|
721 | _query->startRequest(_mountPoint, _manualNMEAString); |
---|
722 | _lastManualNMEA = QDateTime::currentDateTime(); |
---|
723 | } else if (_serialNMEA == AUTO_NMEA) { |
---|
724 | if (_serialPort) { |
---|
725 | int nb = _serialPort->bytesAvailable(); |
---|
726 | if (nb > 0) { |
---|
727 | QByteArray data = _serialPort->read(nb); |
---|
728 | int i1 = data.indexOf("$GPGGA"); |
---|
729 | if (i1 == -1) { |
---|
730 | i1 = data.indexOf("$GNGGA"); |
---|
731 | } |
---|
732 | if (i1 != -1) { |
---|
733 | int i2 = data.indexOf("*", i1); |
---|
734 | if (i2 != -1 && data.size() > i2 + 1) { |
---|
735 | QByteArray gga = data.mid(i1, i2 - i1 + 3); |
---|
736 | _query->startRequest(_mountPoint, gga); |
---|
737 | } |
---|
738 | } |
---|
739 | } |
---|
740 | } |
---|
741 | } |
---|
742 | } else { |
---|
743 | _query->startRequest(_mountPoint, ""); |
---|
744 | } |
---|
745 | |
---|
746 | if (_query->status() != bncNetQuery::running) { |
---|
747 | return failure; |
---|
748 | } |
---|
749 | } |
---|
750 | |
---|
751 | if (_rawFile) { |
---|
752 | QMapIterator<QString, GPSDecoder*> itDec(_decodersRaw); |
---|
753 | while (itDec.hasNext()) { |
---|
754 | itDec.next(); |
---|
755 | GPSDecoder* decoder = itDec.value(); |
---|
756 | decoder->setRinexReconnectFlag(false); |
---|
757 | } |
---|
758 | } else { |
---|
759 | _decoder->setRinexReconnectFlag(false); |
---|
760 | } |
---|
761 | |
---|
762 | return success; |
---|
763 | } |
---|
764 | |
---|
765 | // RTCM scan output |
---|
766 | ////////////////////////////////////////////////////////////////////////////// |
---|
767 | void bncGetThread::miscScanRTCM() { |
---|
768 | |
---|
769 | if (!decoder()) { |
---|
770 | return; |
---|
771 | } |
---|
772 | |
---|
773 | bncSettings settings; |
---|
774 | if (Qt::CheckState(settings.value("miscScanRTCM").toInt()) == Qt::Checked) { |
---|
775 | |
---|
776 | if (_miscMount == _staID || _miscMount == "ALL") { |
---|
777 | // RTCM message types |
---|
778 | // ------------------ |
---|
779 | for (int ii = 0; ii < decoder()->_typeList.size(); ii++) { |
---|
780 | QString type = QString("%1 ").arg(decoder()->_typeList[ii]); |
---|
781 | emit(newMessage(_staID + ": Received message type " + type.toLatin1(), |
---|
782 | true)); |
---|
783 | } |
---|
784 | |
---|
785 | // Check Observation Types |
---|
786 | // ----------------------- |
---|
787 | for (int ii = 0; ii < decoder()->_obsList.size(); ii++) { |
---|
788 | t_satObs& obs = decoder()->_obsList[ii]; |
---|
789 | QVector<QString>& rnxTypes = _rnxTypes[obs._prn.system()]; |
---|
790 | bool allFound = true; |
---|
791 | for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) { |
---|
792 | if (obs._obs[iFrq]->_codeValid) { |
---|
793 | QString rnxStr('C'); |
---|
794 | rnxStr.append(obs._obs[iFrq]->_rnxType2ch.c_str()); |
---|
795 | if (_format.indexOf("RTCM_2") != -1 |
---|
796 | || _format.indexOf("RTCM2") != -1 |
---|
797 | || _format.indexOf("RTCM 2") != -1) { |
---|
798 | rnxStr = t_rnxObsFile::type3to2(obs._prn.system(), rnxStr); |
---|
799 | } |
---|
800 | if (rnxTypes.indexOf(rnxStr) == -1) { |
---|
801 | rnxTypes.push_back(rnxStr); |
---|
802 | allFound = false; |
---|
803 | } |
---|
804 | } |
---|
805 | if (obs._obs[iFrq]->_phaseValid) { |
---|
806 | QString rnxStr('L'); |
---|
807 | rnxStr.append(obs._obs[iFrq]->_rnxType2ch.c_str()); |
---|
808 | if (_format.indexOf("RTCM_2") != -1 |
---|
809 | || _format.indexOf("RTCM2") != -1 |
---|
810 | || _format.indexOf("RTCM 2") != -1) { |
---|
811 | rnxStr = t_rnxObsFile::type3to2(obs._prn.system(), rnxStr); |
---|
812 | } |
---|
813 | if (rnxTypes.indexOf(rnxStr) == -1) { |
---|
814 | rnxTypes.push_back(rnxStr); |
---|
815 | allFound = false; |
---|
816 | } |
---|
817 | } |
---|
818 | if (obs._obs[iFrq]->_dopplerValid) { |
---|
819 | QString rnxStr('D'); |
---|
820 | rnxStr.append(obs._obs[iFrq]->_rnxType2ch.c_str()); |
---|
821 | if (_format.indexOf("RTCM_2") != -1 |
---|
822 | || _format.indexOf("RTCM2") != -1 |
---|
823 | || _format.indexOf("RTCM 2") != -1) { |
---|
824 | rnxStr = t_rnxObsFile::type3to2(obs._prn.system(), rnxStr); |
---|
825 | } |
---|
826 | if (rnxTypes.indexOf(rnxStr) == -1) { |
---|
827 | rnxTypes.push_back(rnxStr); |
---|
828 | allFound = false; |
---|
829 | } |
---|
830 | } |
---|
831 | if (obs._obs[iFrq]->_snrValid) { |
---|
832 | QString rnxStr('S'); |
---|
833 | rnxStr.append(obs._obs[iFrq]->_rnxType2ch.c_str()); |
---|
834 | if (_format.indexOf("RTCM_2") != -1 |
---|
835 | || _format.indexOf("RTCM2") != -1 |
---|
836 | || _format.indexOf("RTCM 2") != -1) { |
---|
837 | rnxStr = t_rnxObsFile::type3to2(obs._prn.system(), rnxStr); |
---|
838 | } |
---|
839 | if (rnxTypes.indexOf(rnxStr) == -1) { |
---|
840 | rnxTypes.push_back(rnxStr); |
---|
841 | allFound = false; |
---|
842 | } |
---|
843 | } |
---|
844 | } |
---|
845 | if (!allFound) { |
---|
846 | QString msg; |
---|
847 | QTextStream str(&msg); |
---|
848 | QString s; |
---|
849 | str << obs._prn.system() << " " |
---|
850 | << s.sprintf("%2d", rnxTypes.size()) << " "; |
---|
851 | for (int iType = 0; iType < rnxTypes.size(); iType++) { |
---|
852 | str << " " << rnxTypes[iType]; |
---|
853 | } |
---|
854 | emit(newMessage(_staID + ": Observation Types: " + msg.toLatin1(), |
---|
855 | true)); |
---|
856 | } |
---|
857 | } |
---|
858 | |
---|
859 | // RTCMv3 antenna descriptor |
---|
860 | // ------------------------- |
---|
861 | for (int ii = 0; ii < decoder()->_antType.size(); ii++) { |
---|
862 | QString ant1 = QString(": Antenna Descriptor: %1 ").arg(decoder()->_antType[ii].descriptor); |
---|
863 | emit(newMessage(_staID + ant1.toLatin1(), true)); |
---|
864 | if (strlen(decoder()->_antType[ii].serialnumber)) { |
---|
865 | QString ant2 = QString(": Antenna Serial Number: %1 ").arg(decoder()->_antType[ii].serialnumber); |
---|
866 | emit(newMessage(_staID + ant2.toLatin1(), true)); |
---|
867 | } |
---|
868 | } |
---|
869 | |
---|
870 | // RTCM Antenna Coordinates |
---|
871 | // ------------------------ |
---|
872 | for (int ii = 0; ii < decoder()->_antList.size(); ii++) { |
---|
873 | QByteArray antT; |
---|
874 | if (decoder()->_antList[ii].type == GPSDecoder::t_antRefPoint::ARP) { |
---|
875 | antT = "ARP"; |
---|
876 | } else if (decoder()->_antList[ii].type == GPSDecoder::t_antRefPoint::APC) { |
---|
877 | antT = "APC"; |
---|
878 | } |
---|
879 | QByteArray ant1, ant2, ant3; |
---|
880 | ant1 = QString("%1 ").arg(decoder()->_antList[ii].xx, 0, 'f', 4).toLatin1(); |
---|
881 | ant2 = QString("%1 ").arg(decoder()->_antList[ii].yy, 0, 'f', 4).toLatin1(); |
---|
882 | ant3 = QString("%1 ").arg(decoder()->_antList[ii].zz, 0, 'f', 4).toLatin1(); |
---|
883 | emit(newMessage(_staID + ": " + antT + " (ITRF) X " + ant1 + "m", true)); |
---|
884 | emit(newMessage(_staID + ": " + antT + " (ITRF) Y " + ant2 + "m", true)); |
---|
885 | emit(newMessage(_staID + ": " + antT + " (ITRF) Z " + ant3 + "m", true)); |
---|
886 | double hh = 0.0; |
---|
887 | if (decoder()->_antList[ii].height_f) { |
---|
888 | hh = decoder()->_antList[ii].height; |
---|
889 | QByteArray ant4 = QString("%1 ").arg(hh, 0, 'f', 4).toLatin1(); |
---|
890 | emit(newMessage( |
---|
891 | _staID + ": Antenna height above marker " + ant4 + "m", true)); |
---|
892 | } |
---|
893 | emit(newAntCrd(_staID, decoder()->_antList[ii].xx, |
---|
894 | decoder()->_antList[ii].yy, decoder()->_antList[ii].zz, hh, antT)); |
---|
895 | } |
---|
896 | |
---|
897 | // RTCMv3 receiver descriptor |
---|
898 | // -------------------------- |
---|
899 | for (int ii = 0; ii < decoder()->_recType.size(); ii++) { |
---|
900 | QString rec1 = QString(": Receiver Descriptor: %1 ").arg(decoder()->_recType[ii].descriptor); |
---|
901 | QString rec2 = QString(": Receiver Firmware Version: %1 ").arg(decoder()->_recType[ii].firmware); |
---|
902 | QString rec3 = QString(": Receiver Serial Number: %1 ").arg(decoder()->_recType[ii].serialnumber); |
---|
903 | emit(newMessage(_staID + rec1.toLatin1(), true)); |
---|
904 | emit(newMessage(_staID + rec2.toLatin1(), true)); |
---|
905 | emit(newMessage(_staID + rec3.toLatin1(), true)); |
---|
906 | } |
---|
907 | |
---|
908 | // RTCM GLONASS slots |
---|
909 | // ------------------ |
---|
910 | if (decoder()->_gloFrq.size()) { |
---|
911 | bool allFound = true; |
---|
912 | QString slot = decoder()->_gloFrq; |
---|
913 | slot.replace(" ", " ").replace(" ", ":"); |
---|
914 | if (_gloSlots.indexOf(slot) == -1) { |
---|
915 | _gloSlots.append(slot); |
---|
916 | allFound = false; |
---|
917 | } |
---|
918 | if (!allFound) { |
---|
919 | _gloSlots.sort(); |
---|
920 | emit(newMessage( |
---|
921 | _staID + ": GLONASS Slot:Freq " + _gloSlots.join(" ").toLatin1(), |
---|
922 | true)); |
---|
923 | } |
---|
924 | } |
---|
925 | } |
---|
926 | } |
---|
927 | |
---|
928 | #ifdef MLS_SOFTWARE |
---|
929 | for (int ii=0; ii <decoder()->_antList.size(); ii++) { |
---|
930 | QByteArray antT; |
---|
931 | if (decoder()->_antList[ii].type == GPSDecoder::t_antInfo::ARP) { |
---|
932 | antT = "ARP"; |
---|
933 | } |
---|
934 | else if (decoder()->_antList[ii].type == GPSDecoder::t_antInfo::APC) { |
---|
935 | antT = "APC"; |
---|
936 | } |
---|
937 | double hh = 0.0; |
---|
938 | if (decoder()->_antList[ii].height_f) { |
---|
939 | hh = decoder()->_antList[ii].height; |
---|
940 | } |
---|
941 | emit(newAntCrd(_staID, decoder()->_antList[ii].xx, |
---|
942 | decoder()->_antList[ii].yy, decoder()->_antList[ii].zz, |
---|
943 | hh, antT)); |
---|
944 | } |
---|
945 | |
---|
946 | for (int ii = 0; ii <decoder()->_typeList.size(); ii++) { |
---|
947 | emit(newRTCMMessage(_staID, decoder()->_typeList[ii])); |
---|
948 | } |
---|
949 | #endif |
---|
950 | |
---|
951 | decoder()->_gloFrq.clear(); |
---|
952 | decoder()->_typeList.clear(); |
---|
953 | decoder()->_antType.clear(); |
---|
954 | decoder()->_recType.clear(); |
---|
955 | decoder()->_antList.clear(); |
---|
956 | } |
---|
957 | |
---|
958 | // Handle Data from Serial Port |
---|
959 | //////////////////////////////////////////////////////////////////////////// |
---|
960 | void bncGetThread::slotSerialReadyRead() { |
---|
961 | |
---|
962 | if (_serialPort) { |
---|
963 | |
---|
964 | if (_nmea == "yes" && _serialNMEA == MANUAL_NMEA) { |
---|
965 | if (_manualNMEASampl) { |
---|
966 | int dt = _lastManualNMEA.secsTo(QDateTime::currentDateTime()); |
---|
967 | if (dt && (fmod(double(dt), double(_manualNMEASampl)) == 0.0)) { |
---|
968 | _query->sendNMEA(_manualNMEAString); |
---|
969 | _lastManualNMEA = QDateTime::currentDateTime(); |
---|
970 | } |
---|
971 | } |
---|
972 | } |
---|
973 | |
---|
974 | int nb = _serialPort->bytesAvailable(); |
---|
975 | if (nb > 0) { |
---|
976 | QByteArray data = _serialPort->read(nb); |
---|
977 | |
---|
978 | if (_nmea == "yes" && _serialNMEA == AUTO_NMEA) { |
---|
979 | int i1 = data.indexOf("$GPGGA"); |
---|
980 | if (i1 == -1) { |
---|
981 | i1 = data.indexOf("$GNGGA"); |
---|
982 | } |
---|
983 | if (i1 != -1) { |
---|
984 | int i2 = data.indexOf("*", i1); |
---|
985 | if (i2 != -1 && data.size() > i2 + 1) { |
---|
986 | QByteArray gga = data.mid(i1, i2 - i1 + 3); |
---|
987 | _query->sendNMEA(gga); |
---|
988 | } |
---|
989 | } |
---|
990 | } |
---|
991 | |
---|
992 | if (_serialOutFile) { |
---|
993 | _serialOutFile->write(data); |
---|
994 | _serialOutFile->flush(); |
---|
995 | } |
---|
996 | } |
---|
997 | } |
---|
998 | } |
---|
999 | |
---|
1000 | void bncGetThread::slotNewNMEAConnection() { |
---|
1001 | _nmeaSockets->push_back(_nmeaServer->nextPendingConnection()); |
---|
1002 | emit(newMessage( |
---|
1003 | QString("New PPP client on port: # %1").arg(_nmeaSockets->size()).toLatin1(), |
---|
1004 | true)); |
---|
1005 | } |
---|
1006 | |
---|
1007 | // |
---|
1008 | //////////////////////////////////////////////////////////////////////////// |
---|
1009 | void bncGetThread::slotNewNMEAstr(QByteArray staID, QByteArray str) { |
---|
1010 | if (_nmeaPortsMap.contains(staID)) { |
---|
1011 | int nmeaPort = _nmeaPortsMap.value(staID); |
---|
1012 | QMutableListIterator<QTcpSocket*> is(*_nmeaSockets); |
---|
1013 | while (is.hasNext()) { |
---|
1014 | QTcpSocket* sock = is.next(); |
---|
1015 | if (sock->localPort() == nmeaPort) { |
---|
1016 | if (sock->state() == QAbstractSocket::ConnectedState) { |
---|
1017 | sock->write(str); |
---|
1018 | } else if (sock->state() != QAbstractSocket::ConnectingState) { |
---|
1019 | delete sock; |
---|
1020 | is.remove(); |
---|
1021 | } |
---|
1022 | } |
---|
1023 | } |
---|
1024 | } |
---|
1025 | } |
---|