source: ntrip/trunk/BNC/bncapp.cpp@ 642

Last change on this file since 642 was 642, checked in by mervart, 16 years ago

* empty log message *

File size: 18.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: bncApp
30 *
31 * Purpose: This class implements the main application
32 *
33 * Author: L. Mervart
34 *
35 * Created: 29-Aug-2006
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include <QSettings>
43#include <QMessageBox>
44#include <cmath>
45#include <unistd.h>
46
47#include "bncapp.h"
48#include "bncutils.h"
49
50using namespace std;
51
52struct converttimeinfo {
53 int second; /* seconds of GPS time [0..59] */
54 int minute; /* minutes of GPS time [0..59] */
55 int hour; /* hour of GPS time [0..24] */
56 int day; /* day of GPS time [1..28..30(31)*/
57 int month; /* month of GPS time [1..12]*/
58 int year; /* year of GPS time [1980..] */
59};
60
61extern "C" {
62 void converttime(struct converttimeinfo *c, int week, int tow);
63 void updatetime(int *week, int *tow, int tk, int fixnumleap);
64}
65
66// Constructor
67////////////////////////////////////////////////////////////////////////////
68bncApp::bncApp(int argc, char* argv[], bool GUIenabled) :
69 QApplication(argc, argv, GUIenabled) {
70
71 _bncVersion = "BNC 1.5";
72
73 _logFileFlag = 0;
74 _logFile = 0;
75 _logStream = 0;
76 _caster = 0;
77
78 // Lists of Ephemeris
79 // ------------------
80 for (int ii = PRN_GPS_START; ii <= PRN_GPS_END; ii++) {
81 _gpsEph[ii-PRN_GPS_START] = 0;
82 }
83 for (int ii = PRN_GLONASS_START; ii <= PRN_GLONASS_END; ii++) {
84 _glonassEph[ii-PRN_GLONASS_START] = 0;
85 }
86
87 // Eph file(s)
88 // -----------
89 _rinexVers = 0;
90 _ephFileGPS = 0;
91 _ephStreamGPS = 0;
92 _ephFileGlonass = 0;
93 _ephStreamGlonass = 0;
94
95 _port = 0;
96 _server = 0;
97 _sockets = 0;
98
99 _pgmName = _bncVersion.leftJustified(20, ' ', true);
100#ifdef WIN32
101 _userName = QString("${USERNAME}");
102#else
103 _userName = QString("${USER}");
104#endif
105 expandEnvVar(_userName);
106 _userName = _userName.leftJustified(20, ' ', true);
107}
108
109// Destructor
110////////////////////////////////////////////////////////////////////////////
111bncApp::~bncApp() {
112 delete _logStream;
113 delete _logFile;
114 delete _ephStreamGPS;
115 delete _ephFileGPS;
116 delete _server;
117 delete _sockets;
118 if (_rinexVers == 2) {
119 delete _ephStreamGlonass;
120 delete _ephFileGlonass;
121 }
122 for (int ii = PRN_GPS_START; ii <= PRN_GPS_END; ii++) {
123 delete _gpsEph[ii-PRN_GPS_START];
124 }
125 for (int ii = PRN_GLONASS_START; ii <= PRN_GLONASS_END; ii++) {
126 delete _glonassEph[ii-PRN_GLONASS_START];
127 }
128}
129
130// Write a Program Message
131////////////////////////////////////////////////////////////////////////////
132void bncApp::slotMessage(const QByteArray msg) {
133
134 QMutexLocker locker(&_mutex);
135
136 // First time resolve the log file name
137 // ------------------------------------
138 if (_logFileFlag == 0) {
139 _logFileFlag = 1;
140 QSettings settings;
141 QString logFileName = settings.value("logFile").toString();
142 if ( !logFileName.isEmpty() ) {
143 expandEnvVar(logFileName);
144 _logFile = new QFile(logFileName);
145 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked) {
146 _logFile->open(QIODevice::WriteOnly | QIODevice::Append);
147 }
148 else {
149 _logFile->open(QIODevice::WriteOnly);
150 }
151 _logStream = new QTextStream();
152 _logStream->setDevice(_logFile);
153 }
154 }
155
156 if (_logStream) {
157 *_logStream << QDateTime::currentDateTime().toUTC().toString("yy-MM-dd hh:mm:ss ").toAscii().data();
158 *_logStream << msg.data() << endl;
159 _logStream->flush();
160 }
161}
162
163// New GPS Ephemeris
164////////////////////////////////////////////////////////////////////////////
165void bncApp::slotNewGPSEph(gpsephemeris* gpseph) {
166
167 QMutexLocker locker(&_mutex);
168
169 printEphHeader();
170
171 if (!_ephStreamGPS) {
172 delete gpseph;
173 return;
174 }
175
176 gpsephemeris** ee = &_gpsEph[gpseph->satellite-1];
177 if ( *ee == 0 ||
178 gpseph->GPSweek > (*ee)->GPSweek ||
179 (gpseph->GPSweek == (*ee)->GPSweek && gpseph->TOC > (*ee)->TOC) ) {
180 delete *ee;
181 *ee = gpseph;
182 printGPSEph(gpseph, true);
183 }
184 else {
185 printGPSEph(gpseph, false);
186 delete gpseph;
187 }
188}
189
190// New Glonass Ephemeris
191////////////////////////////////////////////////////////////////////////////
192void bncApp::slotNewGlonassEph(glonassephemeris* glonasseph) {
193
194 QMutexLocker locker(&_mutex);
195
196 printEphHeader();
197
198 if (!_ephStreamGlonass) {
199 delete glonasseph;
200 return;
201 }
202
203 glonassephemeris** ee = &_glonassEph[glonasseph->almanac_number-1];
204
205 int wwOld, towOld, wwNew, towNew;
206 if (*ee != 0) {
207 wwOld = (*ee)->GPSWeek;
208 towOld = (*ee)->GPSTOW;
209 updatetime(&wwOld, &towOld, (*ee)->tb*1000, 1);
210
211 wwNew = glonasseph->GPSWeek;
212 towNew = glonasseph->GPSTOW;
213 updatetime(&wwNew, &towNew, glonasseph->tb*1000, 1);
214 }
215
216 if ( *ee == 0 ||
217 wwNew > wwOld ||
218 (wwNew == wwOld && towNew > towOld) ) {
219 delete *ee;
220 *ee = glonasseph;
221 printGlonassEph(glonasseph, true);
222 }
223 else {
224 printGlonassEph(glonasseph, false);
225 delete glonasseph;
226 }
227}
228
229// Print Header of the output File(s)
230////////////////////////////////////////////////////////////////////////////
231void bncApp::printEphHeader() {
232
233 QSettings settings;
234
235 // Initialization
236 // --------------
237 if (_rinexVers == 0) {
238
239 if ( Qt::CheckState(settings.value("ephV3").toInt()) == Qt::Checked) {
240 _rinexVers = 3;
241 }
242 else {
243 _rinexVers = 2;
244 }
245
246 _ephPath = settings.value("ephPath").toString();
247
248 if ( !_ephPath.isEmpty() ) {
249 if ( _ephPath[_ephPath.length()-1] != QDir::separator() ) {
250 _ephPath += QDir::separator();
251 }
252 expandEnvVar(_ephPath);
253 }
254 }
255
256 // (Re-)Open output File(s)
257 // ------------------------
258 if (!_ephPath.isEmpty()) {
259
260 QDateTime datTim = QDateTime::currentDateTime().toUTC();
261
262 QString ephFileNameGPS = _ephPath + "BRDC" +
263 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0'));
264
265 QString hlpStr;
266 QString intStr = settings.value("ephIntr").toString();
267 if (intStr == "1 day") {
268 hlpStr = "0";
269 }
270 else if (intStr == "1 hour") {
271 char ch = 'A' + datTim.time().hour();
272 hlpStr = ch;
273 }
274 else if (intStr == "15 min") {
275 char ch = 'A' + datTim.time().hour();
276 hlpStr = ch;
277 if (datTim.time().minute() < 15) {
278 hlpStr += "00";
279 }
280 else if (datTim.time().minute() < 30) {
281 hlpStr += "15";
282 }
283 else if (datTim.time().minute() < 45) {
284 hlpStr += "30";
285 }
286 else {
287 hlpStr += "45";
288 }
289 }
290 else {
291 char ch = 'A' + datTim.time().hour();
292 hlpStr = ch;
293 if (datTim.time().minute() < 5) {
294 hlpStr += "00";
295 }
296 else if (datTim.time().minute() < 10) {
297 hlpStr += "05";
298 }
299 else if (datTim.time().minute() < 15) {
300 hlpStr += "10";
301 }
302 else if (datTim.time().minute() < 20) {
303 hlpStr += "15";
304 }
305 else if (datTim.time().minute() < 25) {
306 hlpStr += "20";
307 }
308 else if (datTim.time().minute() < 30) {
309 hlpStr += "25";
310 }
311 else if (datTim.time().minute() < 35) {
312 hlpStr += "30";
313 }
314 else if (datTim.time().minute() < 40) {
315 hlpStr += "35";
316 }
317 else if (datTim.time().minute() < 45) {
318 hlpStr += "40";
319 }
320 else if (datTim.time().minute() < 50) {
321 hlpStr += "45";
322 }
323 else if (datTim.time().minute() < 55) {
324 hlpStr += "50";
325 }
326 else {
327 hlpStr += "55";
328 }
329 }
330
331 if (_rinexVers == 3) {
332 ephFileNameGPS += hlpStr + datTim.toString(".yyP");
333 }
334 else {
335 ephFileNameGPS += hlpStr + datTim.toString(".yyN");
336 }
337
338 if (_ephFileNameGPS == ephFileNameGPS) {
339 return;
340 }
341 else {
342 _ephFileNameGPS = ephFileNameGPS;
343 }
344
345 for (int ii = PRN_GPS_START; ii <= PRN_GPS_END; ii++) {
346 delete _gpsEph[ii-PRN_GPS_START];
347 _gpsEph[ii-PRN_GPS_START] = 0;
348 }
349 for (int ii = PRN_GLONASS_START; ii <= PRN_GLONASS_END; ii++) {
350 delete _glonassEph[ii-PRN_GLONASS_START];
351 _glonassEph[ii-PRN_GLONASS_START] = 0;
352 }
353
354 delete _ephStreamGPS;
355 delete _ephFileGPS;
356
357 QFlags<QIODevice::OpenModeFlag> appendFlagGPS;
358 QFlags<QIODevice::OpenModeFlag> appendFlagGlonass;
359
360 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked &&
361 QFile::exists(ephFileNameGPS) ) {
362 appendFlagGPS = QIODevice::Append;
363 }
364
365 _ephFileGPS = new QFile(ephFileNameGPS);
366 _ephFileGPS->open(QIODevice::WriteOnly | appendFlagGPS);
367 _ephStreamGPS = new QTextStream();
368 _ephStreamGPS->setDevice(_ephFileGPS);
369
370 if (_rinexVers == 3) {
371 _ephFileGlonass = _ephFileGPS;
372 _ephStreamGlonass = _ephStreamGPS;
373 }
374 else if (_rinexVers == 2) {
375 QString ephFileNameGlonass = _ephPath + "BRDC" +
376 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) +
377 hlpStr + datTim.toString(".yyG");
378
379 delete _ephStreamGlonass;
380 delete _ephFileGlonass;
381
382 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked &&
383 QFile::exists(ephFileNameGlonass) ) {
384 appendFlagGlonass = QIODevice::Append;
385 }
386
387 _ephFileGlonass = new QFile(ephFileNameGlonass);
388 _ephFileGlonass->open(QIODevice::WriteOnly | appendFlagGlonass);
389 _ephStreamGlonass = new QTextStream();
390 _ephStreamGlonass->setDevice(_ephFileGlonass);
391 }
392
393 // Header - RINEX Version 3
394 // ------------------------
395 if (_rinexVers == 3) {
396 if ( ! (appendFlagGPS & QIODevice::Append)) {
397 QString line;
398 line.sprintf(
399 "%9.2f%11sN: GNSS NAV DATA M: Mixed%12sRINEX VERSION / TYPE\n",
400 3.0, "", "");
401 *_ephStreamGPS << line;
402
403 QString hlp = QDateTime::currentDateTime().toUTC().toString("yyyyMMdd hhmmss UTC").leftJustified(20, ' ', true);
404 *_ephStreamGPS << _pgmName.toAscii().data()
405 << _userName.toAscii().data()
406 << hlp.toAscii().data()
407 << "PGM / RUN BY / DATE" << endl;
408
409 line.sprintf("%60sEND OF HEADER\n", "");
410 *_ephStreamGPS << line;
411
412 _ephStreamGPS->flush();
413 }
414 }
415
416 // Headers - RINEX Version 2
417 // -------------------------
418 else if (_rinexVers == 2) {
419 if (! (appendFlagGPS & QIODevice::Append)) {
420 QString line;
421 line.sprintf(
422 "%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 2.11, "", "");
423 *_ephStreamGPS << line;
424
425 QString hlp = QDateTime::currentDateTime().toUTC().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true);
426 *_ephStreamGPS << _pgmName.toAscii().data()
427 << _userName.toAscii().data()
428 << hlp.toAscii().data()
429 << "PGM / RUN BY / DATE" << endl;
430
431 line.sprintf("%60sEND OF HEADER\n", "");
432 *_ephStreamGPS << line;
433
434 _ephStreamGPS->flush();
435 }
436 if (! (appendFlagGlonass & QIODevice::Append)) {
437 QString line;
438 line.sprintf(
439 "%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n",2.11,"","");
440 *_ephStreamGlonass << line;
441
442 QString hlp = QDateTime::currentDateTime().toUTC().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true);
443 *_ephStreamGlonass << _pgmName.toAscii().data()
444 << _userName.toAscii().data()
445 << hlp.toAscii().data()
446 << "PGM / RUN BY / DATE" << endl;
447
448 line.sprintf("%60sEND OF HEADER\n", "");
449 *_ephStreamGlonass << line;
450
451 _ephStreamGlonass->flush();
452 }
453 }
454 }
455}
456
457// Print One GPS Ephemeris
458////////////////////////////////////////////////////////////////////////////
459void bncApp::printGPSEph(gpsephemeris* ep, bool printFile) {
460
461 QString line;
462 QByteArray allLines;
463
464 struct converttimeinfo cti;
465 converttime(&cti, ep->GPSweek, ep->TOC);
466 if (_rinexVers == 3) {
467 line.sprintf("G%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
468 ep->satellite, cti.year, cti.month, cti.day, cti.hour,
469 cti.minute, cti.second, ep->clock_bias, ep->clock_drift,
470 ep->clock_driftrate);
471 }
472 else if (_rinexVers == 2) {
473 line.sprintf("%02d %02d %02d %02d %02d %02d%5.1f%19.12e%19.12e%19.12e\n",
474 ep->satellite, cti.year%100, cti.month, cti.day, cti.hour,
475 cti.minute, (double) cti.second, ep->clock_bias,
476 ep->clock_drift, ep->clock_driftrate);
477 }
478 allLines += line;
479
480 line.sprintf(" %19.12e%19.12e%19.12e%19.12e\n", (double)ep->IODE,
481 ep->Crs, ep->Delta_n, ep->M0);
482 allLines += line;
483
484 line.sprintf(" %19.12e%19.12e%19.12e%19.12e\n", ep->Cuc,
485 ep->e, ep->Cus, ep->sqrt_A);
486 allLines += line;
487
488 line.sprintf(" %19.12e%19.12e%19.12e%19.12e\n",
489 (double) ep->TOE, ep->Cic, ep->OMEGA0, ep->Cis);
490 allLines += line;
491
492 line.sprintf(" %19.12e%19.12e%19.12e%19.12e\n", ep->i0,
493 ep->Crc, ep->omega, ep->OMEGADOT);
494 allLines += line;
495
496 double dd = 0;
497 unsigned long ii = ep->flags;
498 if(ii & GPSEPHF_L2CACODE)
499 dd += 2.0;
500 if(ii & GPSEPHF_L2PCODE)
501 dd += 1.0;
502 line.sprintf(" %19.12e%19.12e%19.12e%19.12e\n", ep->IDOT, dd,
503 (double) ep->GPSweek, ii & GPSEPHF_L2PCODEDATA ? 1.0 : 0.0);
504 allLines += line;
505
506 if(ep->URAindex <= 6) /* URA index */
507 dd = ceil(10.0*pow(2.0, 1.0+((double)ep->URAindex)/2.0))/10.0;
508 else
509 dd = ceil(10.0*pow(2.0, ((double)ep->URAindex)/2.0))/10.0;
510 line.sprintf(" %19.12e%19.12e%19.12e%19.12e\n", dd,
511 ((double) ep->SVhealth), ep->TGD, ((double) ep->IODC));
512 allLines += line;
513
514 line.sprintf(" %19.12e%19.12e\n", ((double)ep->TOW), 0.0);
515 allLines += line;
516
517 // Output into file
518 // ----------------
519 if (printFile && _ephStreamGPS) {
520 *_ephStreamGPS << allLines;
521 _ephStreamGPS->flush();
522 }
523
524 // Output into the socket
525 // ----------------------
526 if (_sockets) {
527 QMutableListIterator<QTcpSocket*> is(*_sockets);
528 while (is.hasNext()) {
529 QTcpSocket* sock = is.next();
530 if (sock->state() == QAbstractSocket::ConnectedState) {
531 int fd = sock->socketDescriptor();
532 if (::write(fd, allLines.data(), allLines.size()) != allLines.size()) {
533 delete sock;
534 is.remove();
535 }
536 }
537 else if (sock->state() != QAbstractSocket::ConnectingState) {
538 delete sock;
539 is.remove();
540 }
541 }
542 }
543}
544
545// Print One Glonass Ephemeris
546////////////////////////////////////////////////////////////////////////////
547void bncApp::printGlonassEph(glonassephemeris* ep, bool printFile) {
548
549 QString line;
550 QByteArray allLines;
551
552 int ww = ep->GPSWeek;
553 int tow = ep->GPSTOW;
554 struct converttimeinfo cti;
555
556 updatetime(&ww, &tow, ep->tb*1000, 1);
557 converttime(&cti, ww, tow);
558
559 int ii = ep->tk-3*60*60;
560 if (ii < 0) {
561 ii += 86400;
562 }
563
564 if (_rinexVers == 3) {
565 line.sprintf("R%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
566 ep->almanac_number, cti.year, cti.month, cti.day, cti.hour,
567 cti.minute, cti.second, -ep->tau, ep->gamma, (double) ii);
568 }
569 else if (_rinexVers == 2) {
570 line.sprintf("%02d %02d %02d %02d %02d %02d%5.1f%19.12e%19.12e%19.12e\n",
571 ep->almanac_number, cti.year%100, cti.month, cti.day,
572 cti.hour, cti.minute, (double) cti.second, -ep->tau,
573 ep->gamma, (double) ii);
574 }
575 allLines += line;
576
577 line.sprintf(" %19.12e%19.12e%19.12e%19.12e\n", ep->x_pos,
578 ep->x_velocity, ep->x_acceleration,
579 (ep->flags & GLOEPHF_UNHEALTHY) ? 1.0 : 0.0);
580 allLines += line;
581
582 line.sprintf(" %19.12e%19.12e%19.12e%19.12e\n", ep->y_pos,
583 ep->y_velocity, ep->y_acceleration,
584 (double) ep->frequency_number);
585 allLines += line;
586
587 line.sprintf(" %19.12e%19.12e%19.12e%19.12e\n", ep->z_pos,
588 ep->z_velocity, ep->z_acceleration, (double) ep->E);
589 allLines += line;
590
591 // Output into file
592 // ----------------
593 if (printFile && _ephStreamGlonass) {
594 *_ephStreamGlonass << allLines;
595 _ephStreamGlonass->flush();
596 }
597
598 // Output into the socket
599 // ----------------------
600 if (_sockets) {
601 QMutableListIterator<QTcpSocket*> is(*_sockets);
602 while (is.hasNext()) {
603 QTcpSocket* sock = is.next();
604 if (sock->state() == QAbstractSocket::ConnectedState) {
605 int fd = sock->socketDescriptor();
606 if (::write(fd, allLines.data(), allLines.size()) != allLines.size()) {
607 delete sock;
608 is.remove();
609 }
610 }
611 else if (sock->state() != QAbstractSocket::ConnectingState) {
612 delete sock;
613 is.remove();
614 }
615 }
616 }
617}
618
619// Set Port Number
620////////////////////////////////////////////////////////////////////////////
621void bncApp::setPort(int port) {
622 _port = port;
623 if (_port != 0) {
624 _server = new QTcpServer;
625 _server->listen(QHostAddress::Any, _port);
626 connect(_server, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));
627 _sockets = new QList<QTcpSocket*>;
628 }
629}
630
631// New Connection
632////////////////////////////////////////////////////////////////////////////
633void bncApp::slotNewConnection() {
634 _sockets->push_back( _server->nextPendingConnection() );
635}
636
637//
638////////////////////////////////////////////////////////////////////////////
639void bncApp::slotQuit() {
640 cout << "bncApp::slotQuit" << endl;
641 delete _caster;
642 quit();
643}
644
645
Note: See TracBrowser for help on using the repository browser.