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

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

* empty log message *

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