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

Last change on this file since 406 was 406, checked in by mervart, 17 years ago

* empty log message *

File size: 12.3 KB
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters,
3// written by Leos Mervart.
4//
5// Copyright (C) 2006
6// German Federal Agency for Cartography and Geodesy (BKG)
7// http://www.bkg.bund.de
8// Czech Technical University Prague, Department of Advanced Geodesy
9// http://www.fsv.cvut.cz
10//
11// Email: euref-ip@bkg.bund.de
12//
13// This program is free software; you can redistribute it and/or
14// modify it under the terms of the GNU General Public License
15// as published by the Free Software Foundation, version 2.
16//
17// This program is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU General Public License for more details.
21//
22// You should have received a copy of the GNU General Public License
23// along with this program; if not, write to the Free Software
24// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26/* -------------------------------------------------------------------------
27 * BKG NTRIP Client
28 * -------------------------------------------------------------------------
29 *
30 * Class: bncGetThread
31 *
32 * Purpose: Thread that retrieves data from NTRIP caster
33 *
34 * Author: L. Mervart
35 *
36 * Created: 24-Dec-2005
37 *
38 * Changes:
39 *
40 * -----------------------------------------------------------------------*/
41
42#include <stdlib.h>
43
44#include <QFile>
45#include <QTextStream>
46#include <QtNetwork>
47#include <QTime>
48
49#include "bncgetthread.h"
50#include "bnctabledlg.h"
51#include "bncapp.h"
52#include "bncutils.h"
53
54#include "RTCM/RTCM2Decoder.h"
55#include "RTCM3/RTCM3Decoder.h"
56#include "RTIGS/RTIGSDecoder.h"
57
58using namespace std;
59
60// Constructor
61////////////////////////////////////////////////////////////////////////////
62bncGetThread::bncGetThread(const QUrl& mountPoint,
63 const QByteArray& format,
64 const QByteArray& latitude,
65 const QByteArray& longitude,
66 const QByteArray& nmea, int iMount) {
67 _decoder = 0;
68 _zeroDecoder= false;
69 _mountPoint = mountPoint;
70 _staID = mountPoint.path().mid(1).toAscii();
71 _staID_orig = _staID;
72 _format = format;
73 _latitude = latitude;
74 _longitude = longitude;
75 _nmea = nmea;
76 _socket = 0;
77 _timeOut = 20*1000; // 20 seconds
78 _nextSleep = 1; // 1 second
79 _iMount = iMount; // index in mountpoints array
80
81 // Check name conflict
82 // -------------------
83 QSettings settings;
84 QListIterator<QString> it(settings.value("mountPoints").toStringList());
85 int num = 0;
86 int ind = -1;
87 while (it.hasNext()) {
88 ++ind;
89 QStringList hlp = it.next().split(" ");
90 if (hlp.size() <= 1) continue;
91 QUrl url(hlp[0]);
92 if (_mountPoint.path() == url.path()) {
93 if (_iMount > ind) {
94 ++num;
95 }
96 }
97 }
98
99 if (num > 0) {
100 _staID = _staID.left(_staID.length()-1) + QString("%1").arg(num).toAscii();
101 }
102 msleep(100); //sleep 0.1 sec
103}
104
105// Destructor
106////////////////////////////////////////////////////////////////////////////
107bncGetThread::~bncGetThread() {
108 delete _socket;
109 delete _decoder;
110}
111
112// Connect to Caster, send the Request (static)
113////////////////////////////////////////////////////////////////////////////
114QTcpSocket* bncGetThread::request(const QUrl& mountPoint,
115 QByteArray& latitude, QByteArray& longitude,
116 QByteArray& nmea, int timeOut,
117 QString& msg) {
118
119 // Connect the Socket
120 // ------------------
121 QSettings settings;
122 QString proxyHost = settings.value("proxyHost").toString();
123 int proxyPort = settings.value("proxyPort").toInt();
124
125 QTcpSocket* socket = new QTcpSocket();
126 if ( proxyHost.isEmpty() ) {
127 socket->connectToHost(mountPoint.host(), mountPoint.port());
128 }
129 else {
130 socket->connectToHost(proxyHost, proxyPort);
131 }
132 if (!socket->waitForConnected(timeOut)) {
133 msg += "Connect timeout\n";
134 delete socket;
135 return 0;
136 }
137
138 // Send Request
139 // ------------
140 QByteArray userAndPwd = mountPoint.userName().toAscii() + ":" +
141 mountPoint.password().toAscii();
142
143 QUrl hlp;
144 hlp.setScheme("http");
145 hlp.setHost(mountPoint.host());
146 hlp.setPort(mountPoint.port());
147 hlp.setPath(mountPoint.path());
148
149 QByteArray reqStr;
150 if ( proxyHost.isEmpty() ) {
151 if (hlp.path().indexOf("/") != 0) hlp.setPath("/");
152 reqStr = "GET " + hlp.path().toAscii() +
153 " HTTP/1.0\r\n"
154 "User-Agent: NTRIP BNC 1.2b\r\n"
155 "Authorization: Basic " +
156 userAndPwd.toBase64() + "\r\n\r\n";
157 } else {
158 reqStr = "GET " + hlp.toEncoded() +
159 " HTTP/1.0\r\n"
160 "User-Agent: NTRIP BNC 1.2b\r\n"
161 "Authorization: Basic " +
162 userAndPwd.toBase64() + "\r\n\r\n";
163 }
164
165//////////////////////////////////////////////////////////////////
166// Additional NMEA String in request to handle VRS data streams //
167// will be ignored from standard casters //
168//////////////////////////////////////////////////////////////////
169
170 double lat, lon;
171
172 lat = strtod(latitude,NULL);
173 lon = strtod(longitude,NULL);
174
175 if ((nmea == "VRS") && (hlp.path().length() > 2) && (hlp.path().indexOf(".skl") < 0)) {
176 const char* flagN="N";
177 const char* flagE="E";
178 if (lon >180.) {lon=(lon-360.)*(-1.); flagE="W";}
179 if ((lon < 0.) && (lon >= -180.)) {lon=lon*(-1.); flagE="W";}
180 if (lon < -180.) {lon=(lon+360.); flagE="E";}
181 if (lat < 0.) {lat=lat*(-1.); flagN="S";}
182 QTime ttime(QTime::currentTime());
183 int lat_deg = (int)lat;
184 double lat_min=(lat-lat_deg)*60.;
185 int lon_deg = (int)lon;
186 double lon_min=(lon-lon_deg)*60.;
187 int hh = 0 , mm = 0;
188 double ss = 0.0;
189 hh=ttime.hour();
190 mm=ttime.minute();
191 ss=(double)ttime.second()+0.001*ttime.msec();
192 QString gga;
193 gga += "GPGGA,";
194 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'));
195 gga += QString("%1%2,").arg((int)lat_deg,2, 10, QLatin1Char('0')).arg(lat_min, 7, 'f', 4, QLatin1Char('0'));
196 gga += flagN;
197 gga += QString(",%1%2,").arg((int)lon_deg,3, 10, QLatin1Char('0')).arg(lon_min, 7, 'f', 4, QLatin1Char('0'));
198 gga += flagE + QString(",1,05,1.00,+00100,M,10.000,M,,");
199 int xori;
200 char XOR = 0;
201 char *Buff =gga.toAscii().data();
202 int iLen = strlen(Buff);
203 for (xori = 0; xori < iLen; xori++) {
204 XOR ^= (char)Buff[xori];
205 }
206 gga += QString("*%1").arg(XOR, 2, 16, QLatin1Char('0'));
207 reqStr += "$";
208 reqStr += gga;
209 reqStr += "\r\n";
210 }
211////////////////////////////////////////////////////////////////
212
213 msg += reqStr;
214
215 socket->write(reqStr, reqStr.length());
216
217 if (!socket->waitForBytesWritten(timeOut)) {
218 msg += "Write timeout\n";
219 delete socket;
220 return 0;
221 }
222
223 return socket;
224}
225
226// Init Run
227////////////////////////////////////////////////////////////////////////////
228t_irc bncGetThread::initRun() {
229
230 // Send the Request
231 // ----------------
232 QString msg;
233
234 _socket = bncGetThread::request(_mountPoint, _latitude, _longitude, _nmea, _timeOut, msg);
235
236 //// emit(newMessage(msg.toAscii()));
237
238 if (!_socket) {
239 return failure;
240 }
241
242 // Read Caster Response
243 // --------------------
244 _socket->waitForReadyRead(_timeOut);
245 if (_socket->canReadLine()) {
246 QString line = _socket->readLine();
247 if (line.indexOf("Unauthorized") != -1) {
248 QStringList table;
249 bncTableDlg::getFullTable(_mountPoint.host(), _mountPoint.port(), table);
250 QString net;
251 QStringListIterator it(table);
252 while (it.hasNext()) {
253 QString line = it.next();
254 if (line.indexOf("STR") == 0) {
255 QStringList tags = line.split(";");
256 if (tags.at(1) == _staID_orig) {
257 net = tags.at(7);
258 break;
259 }
260 }
261 }
262
263 QString reg;
264 it.toFront();
265 while (it.hasNext()) {
266 QString line = it.next();
267 if (line.indexOf("NET") == 0) {
268 QStringList tags = line.split(";");
269 if (tags.at(1) == net) {
270 reg = tags.at(7);
271 break;
272 }
273 }
274 }
275 emit(newMessage((_staID + ": Caster Response: " + line +
276 " Adjust User-ID and Password Register, see"
277 "\n " + reg).toAscii()));
278 return fatal;
279 }
280 if (line.indexOf("ICY 200 OK") != 0) {
281 emit(newMessage((_staID + ": Wrong Caster Response:\n" + line).toAscii()));
282 return failure;
283 }
284 }
285 else {
286 emit(newMessage(_staID + ": Response Timeout"));
287 return failure;
288 }
289
290 // Instantiate the filter
291 // ----------------------
292 if (!_decoder && !_zeroDecoder) {
293 if (_format.indexOf("RTCM_2") != -1) {
294 emit(newMessage("Get Data: " + _staID + " in RTCM 2.x format"));
295 _decoder = new RTCM2Decoder();
296 }
297 else if (_format.indexOf("RTCM_3") != -1) {
298 emit(newMessage("Get Data: " + _staID + " in RTCM 3.0 format"));
299 _decoder = new RTCM3Decoder();
300 }
301 else if (_format.indexOf("RTIGS") != -1) {
302 emit(newMessage("Get Data: " + _staID + " in RTIGS format"));
303 _decoder = new RTIGSDecoder();
304 }
305 else if (_format.indexOf("SP3") != -1) {
306 emit(newMessage("Get Data in SP3 format"));
307 _zeroDecoder = true;
308 }
309 else {
310 emit(newMessage(_staID + ": Unknown data format " + _format));
311 return fatal;
312 }
313 }
314 return success;
315}
316
317// Run
318////////////////////////////////////////////////////////////////////////////
319void bncGetThread::run() {
320
321 t_irc irc = initRun();
322
323 if (irc == fatal) {
324 QThread::exit(1);
325 return;
326 }
327 else if (irc != success) {
328 emit(newMessage(_staID + ": initRun failed, reconnecting"));
329 tryReconnect();
330 }
331
332 // Read Incoming Data
333 // ------------------
334 while (true) {
335 try {
336 if (_socket->state() != QAbstractSocket::ConnectedState) {
337 emit(newMessage(_staID + ": Socket not connected, reconnecting"));
338 tryReconnect();
339 }
340
341
342 _socket->waitForReadyRead(_timeOut);
343 qint64 nBytes = _socket->bytesAvailable();
344 if (nBytes > 0) {
345 char* data = new char[nBytes];
346 _socket->read(data, nBytes);
347
348 if (_zeroDecoder) {
349 cout.write(data, nBytes);
350 continue;
351 }
352
353 _decoder->Decode(data, nBytes);
354 delete [] data;
355 for (list<Observation*>::iterator it = _decoder->_obsList.begin();
356 it != _decoder->_obsList.end(); it++) {
357
358 // Check observation epoch
359 // -----------------------
360 int week;
361 double sec;
362 currentGPSWeeks(week, sec);
363
364 const double secPerWeek = 7.0 * 24.0 * 3600.0;
365 const double maxDt = 600.0;
366
367 if (week < (*it)->GPSWeek) {
368 week += 1;
369 sec -= secPerWeek;
370 }
371 if (week > (*it)->GPSWeek) {
372 week -= 1;
373 sec += secPerWeek;
374 }
375 double dt = fabs(sec - (*it)->GPSWeeks);
376 if (week != (*it)->GPSWeek || dt > maxDt) {
377 emit( newMessage("Wrong observation epoch") );
378 delete (*it);
379 continue;
380 }
381
382 emit newObs(_staID, *it);
383 bool firstObs = (it == _decoder->_obsList.begin());
384 _global_caster->newObs(_staID, _mountPoint, firstObs, *it, _format, _latitude, _longitude, _nmea);
385 }
386 _decoder->_obsList.clear();
387 }
388 else {
389 emit(newMessage(_staID + ": Data Timeout, reconnecting"));
390 tryReconnect();
391 }
392 }
393 catch (const char* msg) {
394 emit(newMessage(_staID + msg));
395 tryReconnect();
396 }
397 }
398}
399
400// Exit
401////////////////////////////////////////////////////////////////////////////
402void bncGetThread::exit(int exitCode) {
403 if (exitCode!= 0) {
404 emit error(_staID);
405 }
406 QThread::exit(exitCode);
407 terminate();
408}
409
410// Try Re-Connect
411////////////////////////////////////////////////////////////////////////////
412void bncGetThread::tryReconnect() {
413 _global_caster->reconnecting(_staID);
414 while (1) {
415 delete _socket; _socket = 0;
416 sleep(_nextSleep);
417 if ( initRun() == success ) {
418 break;
419 }
420 else {
421 _nextSleep *= 2;
422 if (_nextSleep > 128) {
423 _nextSleep = 128;
424 }
425 _nextSleep += rand() % 6;
426 }
427 }
428 _nextSleep = 1;
429}
Note: See TracBrowser for help on using the repository browser.