Changeset 11136 in ntrip
- Timestamp:
- Oct 28, 2026, 4:23:04 PM (4 hours ago)
- Location:
- trunk/BNC
- Files:
-
- 15 edited
-
CHANGELOG.md (modified) (1 diff)
-
src/bnccore.cpp (modified) (7 diffs)
-
src/bnccore.h (modified) (2 diffs)
-
src/bnchelp.html (modified) (17 diffs)
-
src/bncmain.cpp (modified) (2 diffs)
-
src/bncsettings.cpp (modified) (1 diff)
-
src/bncwindow.cpp (modified) (9 diffs)
-
src/bncwindow.h (modified) (1 diff)
-
src/pppMain.cpp (modified) (1 diff)
-
src/pppOptions.h (modified) (1 diff)
-
src/pppRun.cpp (modified) (5 diffs)
-
src/pppRun.h (modified) (1 diff)
-
src/pppWidgets.cpp (modified) (2 diffs)
-
src/pppWidgets.h (modified) (1 diff)
-
tests/README.md (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/BNC/CHANGELOG.md
r11134 r11136 21 21 - ADDED: ANTEX file name, number of entries and latest satellite entry are logged; satellites without a valid ANTEX entry are reported (and not combined) 22 22 - ADDED: Combination and PPP: a changed ANTEX file is read again while BNC is running and used from the GPS week given in it (SINEX code of the entries, e.g. IGS20_2437) on; the attitude model states are taken over 23 - ADDED: Option 'File per stream' (key ephFilePerStation) in the RINEX Ephemeris panel: one RINEX navigation file per stream, named after the stream like the observation files, each with all ephemerides of its stream; by default still one file with each ephemeris once 24 - ADDED: PPP option 'Ephemeris stream' (key PPP/ephMount): real-time PPP uses the Broadcast Ephemeris of the given stream(s) only, e.g. BCEP00BKG0, not those of the observation streams; empty: all streams as before 23 25 - ADDED: Regression test suite ('tests'): example configurations and short raw captures replayed through BNC and compared with reference outputs 24 26 - ADDED: macOS packaging script -
trunk/BNC/src/bnccore.cpp
r11075 r11136 76 76 // Eph file(s) 77 77 // ----------- 78 _rinexVers = 0; 79 _ephFileGPS = 0; 80 _ephStreamGPS = 0; 81 _ephFileGlonass = 0; 82 _ephStreamGlonass = 0; 83 _ephFileGalileo = 0; 84 _ephStreamGalileo = 0; 85 _ephFileSBAS = 0; 86 _ephStreamSBAS = 0; 78 _rinexVers = 0; 79 _ephFilePerStation = false; 87 80 88 81 _portEph = 0; … … 129 122 delete _logStream; _logStream = 0; 130 123 delete _logFile; _logFile = 0; 131 delete _ephStreamGPS; 132 delete _ephFileGPS; 124 qDeleteAll(_ephFiles); 133 125 delete _serverEph; 134 126 delete _socketsEph; 135 127 delete _serverCorr; 136 128 delete _socketsCorr; 137 if (_rinexVers == 2) {138 delete _ephStreamGlonass;139 delete _ephFileGlonass;140 }141 142 129 delete _dateAndTimeGPS; 143 130 if (_rawFile) { … … 230 217 } 231 218 #endif 232 printEphHeader(eph->receptStaID()); 233 printEph(*eph, bool(ircPut == success)); 219 t_ephFile* ephFile = printEphHeader(eph->receptStaID()); 220 bool printFile = (ircPut == success); 221 if (ephFile && ephFile->_ephUser) { 222 // file per stream: new ephemerides of this stream, independent of other streams; 223 // the check state of the emitted ephemeris stays that of the common check 224 t_eph::e_checkState checkState = eph->checkState(); 225 printFile = (ephFile->_ephUser->putNewEph(eph, true) == success); 226 eph->setCheckState(checkState); 227 } 228 printEph(ephFile, *eph, printFile); 234 229 return success; 235 230 } … … 275 270 } 276 271 277 // Print Header of the output File(s) 278 //////////////////////////////////////////////////////////////////////////// 279 void t_bncCore::printEphHeader(QString receptStaID) { 272 // Close RINEX Navigation File(s) 273 //////////////////////////////////////////////////////////////////////////// 274 void t_bncCore::t_ephFile::close() { 275 delete _streamN; _streamN = 0; 276 delete _fileN; _fileN = 0; 277 delete _streamG; _streamG = 0; 278 delete _fileG; _fileG = 0; 279 } 280 281 // Destructor 282 //////////////////////////////////////////////////////////////////////////// 283 t_bncCore::t_ephFile::~t_ephFile() { 284 close(); 285 delete _ephUser; 286 } 287 288 // Station part of a RINEX navigation file name: "BRDC" (+ "00WRD" in RINEX 3/4) 289 // for the single file, otherwise derived from the stream like the observation files 290 //////////////////////////////////////////////////////////////////////////// 291 QString t_bncCore::ephFileNameBase(const QString& staID, const QString& country) const { 292 QString ID = staID.isEmpty() ? QString("BRDC") : staID.left(4).toUpper(); 293 if (_rinexVers <= 2) { 294 return ID; 295 } 296 if (staID.size() >= 9 && 297 isdigit((unsigned char) staID[4].toLatin1()) && 298 isdigit((unsigned char) staID[5].toLatin1())) { 299 return staID.left(9).toUpper(); // e.g. BCEP00BKG0 -> BCEP00BKG 300 } 301 return ID + "00" + ((!staID.isEmpty() && country.size() >= 3) ? country.left(3).toUpper() 302 : QString("WRD")); // WORLD 303 } 304 305 // Print Header of the output File(s), returns the file of the stream 306 //////////////////////////////////////////////////////////////////////////// 307 t_bncCore::t_ephFile* t_bncCore::printEphHeader(QString receptStaID) { 280 308 281 309 bncSettings settings; 310 311 // Initialization 312 // -------------- 313 if (_rinexVers == 0) { 314 315 _rinexVers = settings.value("ephVersion").toInt(); 316 317 _ephFilePerStation = Qt::CheckState(settings.value("ephFilePerStation").toInt()) == Qt::Checked; 318 319 _ephPath = settings.value("ephPath").toString(); 320 321 if ( !_ephPath.isEmpty() ) { 322 if ( _ephPath[_ephPath.length()-1] != QDir::separator() ) { 323 _ephPath += QDir::separator(); 324 } 325 expandEnvVar(_ephPath); 326 } 327 } 328 329 if (_ephPath.isEmpty()) { 330 return 0; 331 } 332 333 QString key = _ephFilePerStation ? receptStaID : QString(); 334 335 // Source comments and station part of the file name 336 // -------------------------------------------------- 282 337 QStringList comments; 283 bool separateFiles = false;// Qt::CheckState(settings.value("ephFilePerStation").toInt()); 284 338 QMap<QString, QString> nameBase; // staID -> station part of its file name 285 339 QListIterator<QString> it(settings.value("mountPoints").toStringList()); 286 340 while (it.hasNext()) { … … 290 344 QUrl url(hlp[0]); 291 345 QString decoder = hlp[1]; 292 if (!separateFiles) { 346 QString staID = url.path().mid(1); 347 if (key.isEmpty() || staID == key) { 293 348 comments.append("Source: " + decoder + 294 349 " " + QUrl::toAce(url.host()) + 295 350 "/" + url.path().mid(1).toLatin1()); 296 351 } 297 } 298 299 // Initialization 300 // -------------- 301 if (_rinexVers == 0) { 302 303 _rinexVers = settings.value("ephVersion").toInt(); 304 305 _ephPath = settings.value("ephPath").toString(); 306 307 if ( !_ephPath.isEmpty() ) { 308 if ( _ephPath[_ephPath.length()-1] != QDir::separator() ) { 309 _ephPath += QDir::separator(); 310 } 311 expandEnvVar(_ephPath); 352 nameBase[staID] = ephFileNameBase(staID, hlp[2]); 353 } 354 355 QString base = (!key.isEmpty() && nameBase.contains(key)) ? nameBase[key] 356 : ephFileNameBase(key, QString()); 357 QString distStr; 358 if (!key.isEmpty()) { 359 QMapIterator<QString, QString> im(nameBase); 360 while (im.hasNext()) { 361 im.next(); 362 if (im.key() != key && im.value() == base) { // name conflict with another stream 363 distStr = "_" + key; 364 break; 365 } 366 } 367 } 368 369 t_ephFile*& ephFile = _ephFiles[key]; 370 if (!ephFile) { 371 ephFile = new t_ephFile; 372 if (_ephFilePerStation) { 373 ephFile->_ephUser = new bncEphUser(false); 312 374 } 313 375 } … … 315 377 // (Re-)Open output File(s) 316 378 // ------------------------ 317 if (!_ephPath.isEmpty()) { 318 319 QDateTime datTim = currentDateAndTimeGPS(); 320 321 QString ephFileNameGPS = _ephPath; // + "BRDC"; 322 323 (separateFiles) ? ephFileNameGPS += receptStaID.left(4) : 324 ephFileNameGPS += "BRDC"; 325 326 QString hlpStr = bncRinex::nextEpochStr(datTim, 327 settings.value("ephIntr").toString(), _rinexVers); 328 329 if (_rinexVers > 2) { 330 QString country = "WRD"; // WORLD 331 QString monNum = "0"; 332 QString recNum = "0"; 333 if (separateFiles && receptStaID.size() >= 9) { 334 monNum = receptStaID.mid(4,1); 335 recNum = receptStaID.mid(5,1); 336 country = receptStaID.mid(6,3); 337 } 338 ephFileNameGPS += QString("%1").arg(monNum, 1, 10) + 339 QString("%1").arg(recNum, 1, 10) + 340 country + 341 "_S_" + // stream 342 QString("%1").arg(datTim.date().year()) + 343 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) + 344 hlpStr + // HM_period 345 "_MN.rnx"; // mixed BRDC 346 } 347 else { // RNX v2.11 348 ephFileNameGPS += QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) + 349 hlpStr + datTim.toString(".yyN"); 350 } 351 352 if (_ephFileNameGPS == ephFileNameGPS) { 353 return; 354 } 355 else { 356 _ephFileNameGPS = ephFileNameGPS; 357 } 358 359 delete _ephStreamGPS; 360 delete _ephFileGPS; 361 362 QFlags<QIODevice::OpenModeFlag> appendFlagGPS; 363 QFlags<QIODevice::OpenModeFlag> appendFlagGlonass; 379 QDateTime datTim = currentDateAndTimeGPS(); 380 381 QString hlpStr = bncRinex::nextEpochStr(datTim, 382 settings.value("ephIntr").toString(), _rinexVers); 383 384 QString ephFileNameGPS = _ephPath + base; 385 386 if (_rinexVers > 2) { 387 ephFileNameGPS += "_S_" + // stream 388 QString("%1").arg(datTim.date().year()) + 389 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) + 390 hlpStr + // HM_period 391 "_MN" + // mixed BRDC 392 distStr + ".rnx"; 393 } 394 else { // RNX v2.11 395 ephFileNameGPS += QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) + 396 hlpStr + distStr + datTim.toString(".yyN"); 397 } 398 399 if (ephFile->_name == ephFileNameGPS) { 400 return ephFile; 401 } 402 ephFile->_name = ephFileNameGPS; 403 ephFile->close(); 404 405 QFlags<QIODevice::OpenModeFlag> appendFlagGPS; 406 QFlags<QIODevice::OpenModeFlag> appendFlagGlonass; 407 408 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked && 409 QFile::exists(ephFileNameGPS) ) { 410 appendFlagGPS = QIODevice::Append; 411 } 412 413 ephFile->_fileN = new QFile(ephFileNameGPS); 414 ephFile->_fileN->open(QIODevice::WriteOnly | appendFlagGPS); 415 ephFile->_streamN = new QTextStream(); 416 ephFile->_streamN->setDevice(ephFile->_fileN); 417 QTextStream* streamGPS = ephFile->_streamN; 418 419 if (_rinexVers == 2) { 420 QString ephFileNameGlonass = _ephPath + base + 421 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) + 422 hlpStr + distStr + datTim.toString(".yyG"); 364 423 365 424 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked && 366 QFile::exists(ephFileNameGPS) ) { 367 appendFlagGPS = QIODevice::Append; 368 } 369 370 _ephFileGPS = new QFile(ephFileNameGPS); 371 _ephFileGPS->open(QIODevice::WriteOnly | appendFlagGPS); 372 _ephStreamGPS = new QTextStream(); 373 _ephStreamGPS->setDevice(_ephFileGPS); 374 375 if (_rinexVers > 2) { 376 _ephFileGlonass = _ephFileGPS; 377 _ephStreamGlonass = _ephStreamGPS; 378 _ephFileGalileo = _ephFileGPS; 379 _ephStreamGalileo = _ephStreamGPS; 380 _ephFileSBAS = _ephFileGPS; 381 _ephStreamSBAS = _ephStreamGPS; 382 } 383 else { 384 QString ephFileNameGlonass = _ephPath + "BRDC" + 385 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) + 386 hlpStr + datTim.toString(".yyG"); 387 388 delete _ephStreamGlonass; 389 delete _ephFileGlonass; 390 391 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked && 392 QFile::exists(ephFileNameGlonass) ) { 393 appendFlagGlonass = QIODevice::Append; 394 } 395 396 _ephFileGlonass = new QFile(ephFileNameGlonass); 397 _ephFileGlonass->open(QIODevice::WriteOnly | appendFlagGlonass); 398 _ephStreamGlonass = new QTextStream(); 399 _ephStreamGlonass->setDevice(_ephFileGlonass); 400 } 401 402 // Header - RINEX Version 3 403 // ------------------------ 404 if (_rinexVers > 2) { 405 if ( ! (appendFlagGPS & QIODevice::Append)) { 406 double rinexVersion = defaultRnxNavVersion4; 407 if (_rinexVers < 4.0) { 408 rinexVersion = defaultRnxNavVersion3; 409 } 410 QString line = QString().asprintf("%9.2f%11sN: GNSS NAV DATA M: Mixed%12sRINEX VERSION / TYPE\n", 411 rinexVersion, "", ""); 412 *_ephStreamGPS << line; 413 line.clear(); 414 415 QString hlp = currentDateAndTimeGPS().toString("yyyyMMdd hhmmss UTC").leftJustified(20, ' ', true); 416 *_ephStreamGPS << _pgmName.toLatin1().data() 417 << _userName.toLatin1().data() 418 << hlp.toLatin1().data() 419 << "PGM / RUN BY / DATE\n"; 420 421 QStringListIterator it(comments); 422 while (it.hasNext()) { 423 *_ephStreamGPS << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n"; 424 } 425 426 if (_rinexVers == 4) { 427 int leapSecs = gnumleap(datTim.date().year(), datTim.date().month(), datTim.date().day()); 428 *_ephStreamGPS << QString("%1").arg(leapSecs, 6, 10, QLatin1Char(' ')).left(60).leftJustified(60) 429 << "LEAP SECONDS\n"; 430 } 431 432 line = QString().asprintf("%60sEND OF HEADER\n", ""); 433 *_ephStreamGPS << line; 434 435 _ephStreamGPS->flush(); 436 } 437 } 438 439 // Headers - RINEX Version 2 440 // ------------------------- 441 else { 442 if (! (appendFlagGPS & QIODevice::Append)) { 443 QString line = QString().asprintf("%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 444 defaultRnxNavVersion2, "", ""); 445 *_ephStreamGPS << line; 446 line.clear(); 447 448 QString hlp = currentDateAndTimeGPS().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true); 449 *_ephStreamGPS << _pgmName.toLatin1().data() 450 << _userName.toLatin1().data() 451 << hlp.toLatin1().data() 452 << "PGM / RUN BY / DATE\n"; 453 454 QStringListIterator it(comments); 455 while (it.hasNext()) { 456 *_ephStreamGPS << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n"; 457 } 458 459 line = QString().asprintf("%60sEND OF HEADER\n", ""); 460 *_ephStreamGPS << line; 461 462 _ephStreamGPS->flush(); 463 } 464 if (! (appendFlagGlonass & QIODevice::Append)) { 465 QString line = QString().asprintf("%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n", 466 defaultRnxNavVersion2, "", ""); 467 *_ephStreamGlonass << line; 468 line.clear(); 469 470 QString hlp = currentDateAndTimeGPS().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true); 471 *_ephStreamGlonass << _pgmName.toLatin1().data() 472 << _userName.toLatin1().data() 473 << hlp.toLatin1().data() 474 << "PGM / RUN BY / DATE\n"; 475 476 QStringListIterator it(comments); 477 while (it.hasNext()) { 478 *_ephStreamGlonass << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n"; 479 } 480 481 line = QString().asprintf("%60sEND OF HEADER\n", ""); 482 *_ephStreamGlonass << line; 483 484 _ephStreamGlonass->flush(); 485 } 486 } 487 } 425 QFile::exists(ephFileNameGlonass) ) { 426 appendFlagGlonass = QIODevice::Append; 427 } 428 429 ephFile->_fileG = new QFile(ephFileNameGlonass); 430 ephFile->_fileG->open(QIODevice::WriteOnly | appendFlagGlonass); 431 ephFile->_streamG = new QTextStream(); 432 ephFile->_streamG->setDevice(ephFile->_fileG); 433 } 434 QTextStream* streamGlonass = ephFile->_streamG; 435 436 // Header - RINEX Version 3 437 // ------------------------ 438 if (_rinexVers > 2) { 439 if ( ! (appendFlagGPS & QIODevice::Append)) { 440 double rinexVersion = defaultRnxNavVersion4; 441 if (_rinexVers < 4.0) { 442 rinexVersion = defaultRnxNavVersion3; 443 } 444 QString line = QString().asprintf("%9.2f%11sN: GNSS NAV DATA M: Mixed%12sRINEX VERSION / TYPE\n", 445 rinexVersion, "", ""); 446 *streamGPS << line; 447 line.clear(); 448 449 QString hlp = currentDateAndTimeGPS().toString("yyyyMMdd hhmmss UTC").leftJustified(20, ' ', true); 450 *streamGPS << _pgmName.toLatin1().data() 451 << _userName.toLatin1().data() 452 << hlp.toLatin1().data() 453 << "PGM / RUN BY / DATE\n"; 454 455 QStringListIterator it(comments); 456 while (it.hasNext()) { 457 *streamGPS << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n"; 458 } 459 460 if (_rinexVers == 4) { 461 int leapSecs = gnumleap(datTim.date().year(), datTim.date().month(), datTim.date().day()); 462 *streamGPS << QString("%1").arg(leapSecs, 6, 10, QLatin1Char(' ')).left(60).leftJustified(60) 463 << "LEAP SECONDS\n"; 464 } 465 466 line = QString().asprintf("%60sEND OF HEADER\n", ""); 467 *streamGPS << line; 468 469 streamGPS->flush(); 470 } 471 } 472 473 // Headers - RINEX Version 2 474 // ------------------------- 475 else { 476 if (! (appendFlagGPS & QIODevice::Append)) { 477 QString line = QString().asprintf("%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 478 defaultRnxNavVersion2, "", ""); 479 *streamGPS << line; 480 line.clear(); 481 482 QString hlp = currentDateAndTimeGPS().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true); 483 *streamGPS << _pgmName.toLatin1().data() 484 << _userName.toLatin1().data() 485 << hlp.toLatin1().data() 486 << "PGM / RUN BY / DATE\n"; 487 488 QStringListIterator it(comments); 489 while (it.hasNext()) { 490 *streamGPS << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n"; 491 } 492 493 line = QString().asprintf("%60sEND OF HEADER\n", ""); 494 *streamGPS << line; 495 496 streamGPS->flush(); 497 } 498 if (! (appendFlagGlonass & QIODevice::Append)) { 499 QString line = QString().asprintf("%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n", 500 defaultRnxNavVersion2, "", ""); 501 *streamGlonass << line; 502 line.clear(); 503 504 QString hlp = currentDateAndTimeGPS().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true); 505 *streamGlonass << _pgmName.toLatin1().data() 506 << _userName.toLatin1().data() 507 << hlp.toLatin1().data() 508 << "PGM / RUN BY / DATE\n"; 509 510 QStringListIterator it(comments); 511 while (it.hasNext()) { 512 *streamGlonass << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n"; 513 } 514 515 line = QString().asprintf("%60sEND OF HEADER\n", ""); 516 *streamGlonass << line; 517 518 streamGlonass->flush(); 519 } 520 } 521 522 return ephFile; 488 523 } 489 524 490 525 // Print One Ephemeris 491 526 //////////////////////////////////////////////////////////////////////////// 492 void t_bncCore::printEph(const t_eph& eph, bool printFile) { 527 void t_bncCore::printEph(t_ephFile* ephFile, const t_eph& eph, bool printFile) { 493 528 494 529 QString strV2 = eph.toString(defaultRnxNavVersion2); … … 496 531 QString strV4 = eph.toString(defaultRnxNavVersion4); 497 532 533 QTextStream* streamN = ephFile ? ephFile->_streamN : 0; 534 QTextStream* streamG = ephFile ? ephFile->_streamG : 0; 535 498 536 if (_rinexVers == 2 && eph.system() == t_eph::GLONASS) { 499 printOutputEph(printFile, _ephStreamGlonass, strV2, strV3, strV4);537 printOutputEph(printFile, streamG, strV2, strV3, strV4); 500 538 } 501 539 else if (_rinexVers == 2 && eph.system() == t_eph::GPS) { 502 printOutputEph(printFile, _ephStreamGPS, strV2, strV3, strV4);540 printOutputEph(printFile, streamN, strV2, strV3, strV4); 503 541 } 504 542 else if (_rinexVers >= 3) { 505 printOutputEph(printFile, _ephStreamGPS, strV2, strV3, strV4);543 printOutputEph(printFile, streamN, strV2, strV3, strV4); 506 544 } 507 545 } -
trunk/BNC/src/bnccore.h
r11066 r11136 132 132 133 133 private: 134 // RINEX navigation file(s): one file, or one per stream (ephFilePerStation) 135 class t_ephFile { 136 public: 137 t_ephFile() : _fileN(0), _streamN(0), _fileG(0), _streamG(0), _ephUser(0) {} 138 ~t_ephFile(); 139 void close(); 140 QString _name; // current file name (RINEX 2: GPS file) 141 QFile* _fileN; // mixed (RINEX 3/4) or GPS (RINEX 2) 142 QTextStream* _streamN; 143 QFile* _fileG; // GLONASS (RINEX 2 only) 144 QTextStream* _streamG; 145 bncEphUser* _ephUser; // file per stream: ephemerides of this stream only 146 }; 147 134 148 t_irc checkPrintEph(t_eph* eph); 135 void printEphHeader(QString receptStaID); 136 void printEph(const t_eph& eph, bool printFile); 149 t_ephFile* printEphHeader(QString receptStaID); 150 QString ephFileNameBase(const QString& staID, const QString& country) const; 151 void printEph(t_ephFile* ephFile, const t_eph& eph, bool printFile); 137 152 void printOutputEph(bool printFile, QTextStream* stream, 138 153 const QString& strV2, const QString& strV3, … … 147 162 QMutex _mutexMessage; 148 163 QString _ephPath; 149 QString _ephFileNameGPS;150 164 int _rinexVers; 151 QFile* _ephFileGPS; 152 QTextStream* _ephStreamGPS; 153 QFile* _ephFileGlonass; 154 QTextStream* _ephStreamGlonass; 155 QFile* _ephFileGalileo; 156 QTextStream* _ephStreamGalileo; 157 QFile* _ephFileSBAS; 158 QTextStream* _ephStreamSBAS; 165 bool _ephFilePerStation; 166 QMap<QString, t_ephFile*> _ephFiles; // key: staID, "" for the single file 159 167 QString _userName; 160 168 QString _pgmName; -
trunk/BNC/src/bnchelp.html
r11134 r11136 129 129 2.5.3 <a href="#ephport">Port</a><br> 130 130 2.5.4 <a href="#ephvers">Version</a><br> 131 2.5.5 <a href="#ephperstream">File per Stream</a><br> 131 132 2.6 <a href="#reqc"><b>RINEX Editing & QC</b></a><br> 132 133 2.6.1 <a href="#reqcact">Action</a><br> … … 189 190 Stream</a><br> 190 191 2.13.1.7 <a href=#pppionofile>Ionosphere File</a><br> 191 2.13.1.8 <a href=#ppprnxobs>RINEX Observation 192 2.13.1.8 <a href=#pppephstream>Ephemeris Stream</a><br> 193 2.13.1.9 <a href=#ppprnxobs>RINEX Observation 192 194 File</a><br> 193 2.13.1. 9<a href=#ppprnxnav>RINEX Navigation195 2.13.1.10 <a href=#ppprnxnav>RINEX Navigation 194 196 File</a><br> 195 2.13.1.1 0<a href=#pppantexfile>ANTEX File</a><br>196 2.13.1.1 1<a href=#pppmarkcoor>Coordinates197 2.13.1.11 <a href=#pppantexfile>ANTEX File</a><br> 198 2.13.1.12 <a href=#pppmarkcoor>Coordinates 197 199 File</a><br> 198 2.13.1.1 2<a href=#pppblqfile>BLQ File</a><br>199 2.13.1.1 3<a href=#ppplogfile>Logfile Directory and200 2.13.1.13 <a href=#pppblqfile>BLQ File</a><br> 201 2.13.1.14 <a href=#ppplogfile>Logfile Directory and 200 202 Log mode</a><br> 201 2.13.1.1 4<a href=#pppnmeafile>NMEA Directory</a><br>202 2.13.1.1 5<a href=#pppsnxtrofile>SNX TRO203 2.13.1.15 <a href=#pppnmeafile>NMEA Directory</a><br> 204 2.13.1.16 <a href=#pppsnxtrofile>SNX TRO 203 205 Directory</a><br> 204 2.13.1.1 5.1 <a206 2.13.1.16.1 <a 205 207 href=#pppsnxtrointr>Interval</a><br> 206 2.13.1.1 5.2 <a208 2.13.1.16.2 <a 207 209 href=#pppsnxtrosampl>Sampling</a><br> 208 2.13.1.1 5.3 <a href=#pppsnxAc>Analysis210 2.13.1.16.3 <a href=#pppsnxAc>Analysis 209 211 Center</a><br> 210 2.13.1.1 5.4 <a href=#pppsnxSol>Solution212 2.13.1.16.4 <a href=#pppsnxSol>Solution 211 213 ID</a><br> 212 214 2.13.2 <a href=#pppOptions><b>PPP (2): Processing Options</b></a><br> … … 3495 3497 Note that the here choosen Version concerns the Broadcast Ephemeris output through IP port as well. 3496 3498 </p> 3499 <p> 3500 <h4 id="ephperstream">2.5.5 File per Stream - optional</h4> 3501 </p> 3502 <p> 3503 By default, the Broadcast Ephemeris of all streams are saved in one RINEX Navigation file (BRDC). Each ephemeris is 3504 saved only once, from the stream which first provided it, so the file does not show which stream an ephemeris 3505 came from. 3506 </p> 3507 <p> 3508 Tick 'File per stream' to save one RINEX Navigation file per stream instead. The files are named after the 3509 stream like the RINEX Observation files, e.g. 'BCEP00BKG_S_20262730000_01D_MN.rnx' for stream 'BCEP00BKG0' (RINEX 3510 Version 3 or 4) or 'BCEP2730.26N' (RINEX Version 2). If two streams would get the same file name, the complete 3511 stream name is appended. Each file contains all ephemerides received from its stream, independent of the 3512 other streams, and its header contains the source of this stream only. This allows to check the Broadcast 3513 Ephemeris of a stream, e.g. of an ephemeris stream like 'BCEP00BKG0' compared to those contained in 3514 observation streams. 3515 </p> 3516 <p> 3517 The output through IP port is not affected by this option. 3518 </p> 3497 3519 3498 3520 <p> … … 6393 6415 </p> 6394 6416 <p> 6395 <h4 id="ppprnxobs">2.13.1.8 RINEX Observation File - mandatory if 'Data source' is set to 'RINEX Files'</h4> 6417 <h4 id="pppephstream">2.13.1.8 Ephemeris Stream - optional if 'Data source' is set to 'Real-Time Streams'</h4> 6418 </p> 6419 <p> 6420 By default, real-time PPP uses the Broadcast Ephemeris of all streams you are pulling, including those contained 6421 in the observation streams. Specify one or more 'mountpoints' (separated by comma) from the list of selected 6422 'Streams' to use the Broadcast Ephemeris of these streams only, e.g. 'BCEP00BKG0'. Ephemerides of all other 6423 streams, the observation streams included, are then not used in PPP. 6424 </p> 6425 <p> 6426 Note that the ephemerides of the selected stream must match the IODs of the corrections stream. If you do not 6427 specify an 'Ephemeris stream' via this option, BNC will use the Broadcast Ephemeris of all streams. 6428 </p> 6429 <p> 6430 <h4 id="ppprnxobs">2.13.1.9 RINEX Observation File - mandatory if 'Data source' is set to 'RINEX Files'</h4> 6396 6431 </p> 6397 6432 <p> … … 6399 6434 </p> 6400 6435 <p> 6401 <h4 id="ppprnxnav">2.13.1. 9RINEX Navigation File - mandatory if 'Data source' is set to 'RINEX Files'</h4>6436 <h4 id="ppprnxnav">2.13.1.10 RINEX Navigation File - mandatory if 'Data source' is set to 'RINEX Files'</h4> 6402 6437 </p> 6403 6438 <p> … … 6405 6440 </p> 6406 6441 <p> 6407 <h4 id="pppantexfile">2.13.1.1 0ANTEX File - optional</h4>6442 <h4 id="pppantexfile">2.13.1.11 ANTEX File - optional</h4> 6408 6443 </p> 6409 6444 <p> … … 6465 6500 </p> 6466 6501 <p> 6467 <h4 id="pppmarkcoor">2.13.1.1 1Coordinates File - optional </h4>6502 <h4 id="pppmarkcoor">2.13.1.12 Coordinates File - optional </h4> 6468 6503 </p> 6469 6504 <p> … … 6611 6646 6612 6647 <p> 6613 <h4 id="pppblqfile">2.13.1.1 2BLQ File - optional </h4>6648 <h4 id="pppblqfile">2.13.1.13 BLQ File - optional </h4> 6614 6649 </p> 6615 6650 <p> … … 6623 6658 6624 6659 <p> 6625 <h4 id="ppplogfile">2.13.1.1 3Logfile Directory and Log mode - optional</h4>6660 <h4 id="ppplogfile">2.13.1.14 Logfile Directory and Log mode - optional</h4> 6626 6661 </p> 6627 6662 <p> … … 7059 7094 7060 7095 <p> 7061 <h4 id="pppnmeafile">2.13.1.1 4NMEA Directory - optional</h4>7096 <h4 id="pppnmeafile">2.13.1.15 NMEA Directory - optional</h4> 7062 7097 </p> 7063 7098 <p> … … 7106 7141 7107 7142 <p> 7108 <h4 id="pppsnxtrofile">2.13.1.1 5SNX TRO Directory - optional</h4>7143 <h4 id="pppsnxtrofile">2.13.1.16 SNX TRO Directory - optional</h4> 7109 7144 </p> 7110 7145 <p> … … 7263 7298 7264 7299 <p> 7265 <h4 id="pppsnxtrointr">2.13.1.1 5.1 Interval - mandatory if 'SINEX TRO Directory' is set</h4>7300 <h4 id="pppsnxtrointr">2.13.1.16.1 Interval - mandatory if 'SINEX TRO Directory' is set</h4> 7266 7301 </p> 7267 7302 <p> … … 7272 7307 </p> 7273 7308 <p> 7274 <h4 id="pppsnxtrosampl">2.13.1.1 5.2 Sampling - mandatory if 'SINEX TRO Directory' is set</h4>7309 <h4 id="pppsnxtrosampl">2.13.1.16.2 Sampling - mandatory if 'SINEX TRO Directory' is set</h4> 7275 7310 </p> 7276 7311 <p> … … 7282 7317 7283 7318 <p> 7284 <h4 id="pppsnxAc">2.13.1.1 5.3 Analysis Center - Mandatory if 'SINEX TRO Directory' is set</h4>7319 <h4 id="pppsnxAc">2.13.1.16.3 Analysis Center - Mandatory if 'SINEX TRO Directory' is set</h4> 7285 7320 </p> 7286 7321 <p> … … 7290 7325 7291 7326 <p> 7292 <h4 id="pppsnxSol">2.13.1.1 5.4 Solution ID - Mandatory if 'SINEX TRO Directory' is set</h4>7327 <h4 id="pppsnxSol">2.13.1.16.4 Solution ID - Mandatory if 'SINEX TRO Directory' is set</h4> 7293 7328 </p> 7294 7329 <p> … … 10962 10997 ephOutPort {Output port [integer number]} 10963 10998 ephVersion {Specifies the RINEX version of the file contents [integer number: 2|3|4]} 10999 ephFilePerStation {One RINEX navigation file per stream [integer number: 0=no,2=yes]} 10964 11000 10965 11001 RINEX Editing and QC Panel keys: … … 11058 11094 PPP/ionoMount {VTEC mountpoint, [char string]} 11059 11095 PPP/ionoFile {VTEC file, full path [char string]} 11096 PPP/ephMount {Broadcast Ephemeris mountpoint(s), comma separated [char string]} 11060 11097 PPP/nmeaPath {Directory for NMEA output files [character string]} 11061 11098 PPP/snxtroPath {Directory for SINEX troposphere output files [character string]} -
trunk/BNC/src/bncmain.cpp
r11130 r11136 161 161 " ephOutPort {Output port [integer number]}\n" 162 162 " ephVersion {Specifies the RINEX version of the file contents [integer number: 2|3|4]}\n" 163 " ephFilePerStation {One RINEX navigation file per stream [integer number: 0=no,2=yes]}\n" 163 164 "\n" 164 165 "RINEX Editing and QC Panel keys:\n" … … 263 264 " PPP/ionoMount {VTEC mountpoint, [char string]}\n" 264 265 " PPP/ionoFile {VTEC file, full path [char string]}\n" 266 " PPP/ephMount {Broadcast Ephemeris mountpoint(s), comma separated [char string]}\n" 265 267 " PPP/nmeaPath {Directory for NMEA output files [character string]}\n" 266 268 " PPP/snxtroPath {Directory for SINEX troposphere output files [character string]}\n" -
trunk/BNC/src/bncsettings.cpp
r11129 r11136 96 96 setValue_p("ephOutPort", ""); 97 97 setValue_p("ephVersion", "3"); 98 setValue_p("ephFilePerStation", "0"); 98 99 // Reqc 99 100 setValue_p("reqcAction", ""); -
trunk/BNC/src/bncwindow.cpp
r11129 r11136 278 278 _ephVersComboBox->setCurrentIndex(jk); 279 279 } 280 //_ephFilePerStation = new QCheckBox();281 //_ephFilePerStation->setCheckState(Qt::CheckState(settings.value("ephFilePerStation").toInt()));280 _ephFilePerStation = new QCheckBox(); 281 _ephFilePerStation->setCheckState(Qt::CheckState(settings.value("ephFilePerStation").toInt())); 282 282 283 283 connect(_ephOutPortLineEdit, SIGNAL(textChanged(const QString&)), … … 902 902 eLayout->addWidget(new QLabel("Version"), 4, 0); 903 903 eLayout->addWidget(_ephVersComboBox, 4, 1); 904 eLayout->setRowStretch(5, 999); 905 //eLayout->addWidget(new QLabel("File per Station"), 5, 0); 906 //eLayout->addWidget(_ephFilePerStation, 5, 1); 907 //eLayout->setRowStretch(6, 999); 904 eLayout->addWidget(new QLabel("File per stream"), 5, 0); 905 eLayout->addWidget(_ephFilePerStation, 5, 1); 906 eLayout->setRowStretch(6, 999); 908 907 909 908 egroup->setLayout(eLayout); … … 1066 1065 _pppWidgets._snxtroCampId->setMaximumWidth(7 * ww); 1067 1066 _pppWidgets._ionoMount->setMaximumWidth(15 * ww); 1067 _pppWidgets._ephMount->setMaximumWidth(15 * ww); 1068 1068 1069 1069 … … 1100 1100 pppLayout1->addWidget(new QLabel(" SNX TRO sampling"), ir, 6); 1101 1101 pppLayout1->addWidget(_pppWidgets._snxtroSampl, ir, 7, Qt::AlignRight); 1102 ++ir; 1103 pppLayout1->addWidget(new QLabel("Ephemeris stream"), ir, 0); 1104 pppLayout1->addWidget(_pppWidgets._ephMount, ir, 1); 1102 1105 ++ir; 1103 1106 pppLayout1->addWidget(new QLabel("RINEX Obs file"), ir, 0); … … 1580 1583 _ephOutPortLineEdit->setWhatsThis(tr("<p>BNC can produce ephemeris data in RINEX Navigation ASCII format on your local host through an IP port.</p><p>Specify a port number here to activate this function. <i>[key: ephOutPort]</i></p>")); 1581 1584 _ephVersComboBox->setWhatsThis(tr("<p>Select the format for RINEX Navigation files. <i>[key: ephVersion]</i></p>")); 1582 //_ephFilePerStation->setWhatsThis(tr("<p>By default,all received Broadcast Ephemeris data will be stored within one File. Thick 'File perStations' to get separate files per station/mountpoint. <i>[key: ephFilePerStation]</i></p>"));1585 _ephFilePerStation->setWhatsThis(tr("<p>By default, the Broadcast Ephemeris of all streams are saved in one RINEX Navigation file, each ephemeris once, from the stream which first provided it.</p><p>Tick 'File per stream' to save one file per stream instead, named after the stream like the RINEX Observation files (e.g. BCEP00BKG_S_... for stream BCEP00BKG0). Each file then contains all ephemerides received from its stream. The output through the IP port is not affected. <i>[key: ephFilePerStation]</i></p>")); 1583 1586 1584 1587 // WhatsThis, RINEX Editing & QC … … 1662 1665 _pppWidgets._biasMount->setWhatsThis(tr("<p>Specify a 'mountpoint' from the 'Streams' canvas below which provides satellite biases in SSR format.</p><p>If you don't specify a corrections stream via this option, BNC will use satellite biases from the Corrections stream 'mountpoint', if available. <i>[key: PPP/biasMount]</i></p>")); 1663 1666 _pppWidgets._ionoMount->setWhatsThis(tr("<p>Specify a 'mountpoint' from the 'Streams' canvas below which provides VTEC informations in SSR format.</p><p>If you don't specify a corrections stream via this option, BNC will use VTEC informations from the Corrections stream 'mountpoint', if available. <i>[key: PPP/ionoMount]</i></p>")); 1667 _pppWidgets._ephMount->setWhatsThis(tr("<p>Specify a 'mountpoint' from the 'Streams' canvas below which provides the Broadcast Ephemeris for PPP, e.g. 'BCEP00BKG0'. Several mountpoints can be given, separated by comma.</p><p>Ephemerides of all other streams, also those contained in the observation streams, are then not used in PPP. If you don't specify an ephemeris stream via this option, BNC will use the Broadcast Ephemeris of all streams. <i>[key: PPP/ephMount]</i></p>")); 1664 1668 _pppWidgets._corrFile->setWhatsThis(tr("<p>Specify the Broadcast Ephemeris Corrections file as saved beforehand using BNC.</p><p>If you don't specify corrections by this option, BNC will fall back to Single Point Positioning (SPP, positioning from RINEX Obs and RINEX Nav files only) instead of doing PPP. <i>[key: PPP/corrFile]</i></p>")); 1665 1669 _pppWidgets._biasFile->setWhatsThis(tr("<p>Specify the satellite bias file as saved beforehand using BNC.</p><p>If you don't specify corrections by this option, BNC will use satellite biases from the Corrections file, if available. <i>[key: PPP/biasFile]</i></p>")); … … 1881 1885 delete _rnxV2Priority; 1882 1886 delete _ephPathLineEdit; 1883 //delete _ephFilePerStation;1887 delete _ephFilePerStation; 1884 1888 delete _ephIntrComboBox; 1885 1889 delete _ephOutPortLineEdit; … … 2416 2420 settings.setValue("ephOutPort", _ephOutPortLineEdit->text()); 2417 2421 settings.setValue("ephVersion", _ephVersComboBox->currentText()); 2418 //settings.setValue("ephFilePerStation", _ephFilePerStation->checkState());2422 settings.setValue("ephFilePerStation", _ephFilePerStation->checkState()); 2419 2423 // Broadcast Corrections 2420 2424 settings.setValue("corrPath", _corrPathLineEdit->text()); … … 2951 2955 enableWidget(enable, _ephIntrComboBox); 2952 2956 enableWidget(enable, _ephVersComboBox); 2953 //enableWidget(enable, _ephVersComboBox); 2954 //enableWidget(enable, _ephFilePerStation); 2957 enableWidget(!_ephPathLineEdit->text().isEmpty(), _ephFilePerStation); 2955 2958 } 2956 2959 -
trunk/BNC/src/bncwindow.h
r11129 r11136 179 179 QLineEdit* _rnxV2Priority; 180 180 QComboBox* _ephVersComboBox; 181 //QCheckBox* _ephFilePerStation;181 QCheckBox* _ephFilePerStation; 182 182 QCheckBox* _rnxFileCheckBox; 183 183 QLineEdit* _rnxScrpLineEdit; -
trunk/BNC/src/pppMain.cpp
r11079 r11136 217 217 opt->_biasMount.assign(settings.value("PPP/biasMount").toString().toStdString()); 218 218 opt->_ionoMount.assign(settings.value("PPP/ionoMount").toString().toStdString()); 219 opt->_ephMount.assign(settings.value("PPP/ephMount").toString().toStdString()); 219 220 } 220 221 else { -
trunk/BNC/src/pppOptions.h
r11019 r11136 66 66 std::string _biasMount; 67 67 std::string _ionoMount; 68 std::string _ephMount; 68 69 bool _isAPC; 69 70 std::string _rinexObs; -
trunk/BNC/src/pppRun.cpp
r11047 r11136 82 82 83 83 if (_opt->_realTime) { 84 _ephMounts = QString::fromStdString(_opt->_ephMount).split(QRegularExpression("[,\\s]+"), 85 Qt::SkipEmptyParts); 86 if (!_ephMounts.isEmpty()) { 87 emit newMessage(QByteArray(_opt->_roverName.c_str()) + ": PPP uses the ephemerides of " 88 + _ephMounts.join(", ").toLatin1() + " only", true); 89 } 90 84 91 Qt::ConnectionType conType = Qt::AutoConnection; 85 92 if (BNC_CORE->mode() == t_bncCore::batchPostProcessing) { … … 248 255 } 249 256 257 // Ephemeris from a stream selected for PPP (PPP/ephMount)? 258 //////////////////////////////////////////////////////////////////////////// 259 bool t_pppRun::useEph(const t_eph& eph) const { 260 return _ephMounts.isEmpty() || _ephMounts.contains(eph.receptStaID()); 261 } 262 250 263 // 251 264 //////////////////////////////////////////////////////////////////////////// 252 265 void t_pppRun::slotNewGPSEph(t_ephGPS eph) { 266 if (!useEph(eph)) { 267 return; 268 } 253 269 QMutexLocker locker(&_mutex); 254 270 _pppClient->putEphemeris(&eph); … … 258 274 //////////////////////////////////////////////////////////////////////////// 259 275 void t_pppRun::slotNewGlonassEph(t_ephGlo eph) { 276 if (!useEph(eph)) { 277 return; 278 } 260 279 QMutexLocker locker(&_mutex); 261 280 _pppClient->putEphemeris(&eph); … … 265 284 //////////////////////////////////////////////////////////////////////////// 266 285 void t_pppRun::slotNewGalileoEph(t_ephGal eph) { 286 if (!useEph(eph)) { 287 return; 288 } 267 289 QMutexLocker locker(&_mutex); 268 290 _pppClient->putEphemeris(&eph); … … 272 294 //////////////////////////////////////////////////////////////////////////// 273 295 void t_pppRun::slotNewBDSEph(t_ephBDS eph) { 296 if (!useEph(eph)) { 297 return; 298 } 274 299 QMutexLocker locker(&_mutex); 275 300 _pppClient->putEphemeris(&eph); -
trunk/BNC/src/pppRun.h
r11041 r11136 65 65 }; 66 66 67 bool useEph(const t_eph& eph) const; 68 67 69 QMutex _mutex; 68 70 const t_pppOptions* _opt; 71 QStringList _ephMounts; // empty: ephemerides of all streams 69 72 t_pppClient* _pppClient; 70 73 std::deque<t_epoData*> _epoData; -
trunk/BNC/src/pppWidgets.cpp
r11022 r11136 67 67 _biasMount = new QLineEdit(); _biasMount ->setObjectName("PPP/biasMount"); _widgets << _biasMount; 68 68 _ionoMount = new QLineEdit(); _ionoMount ->setObjectName("PPP/ionoMount"); _widgets << _ionoMount; 69 _ephMount = new QLineEdit(); _ephMount ->setObjectName("PPP/ephMount"); _widgets << _ephMount; 69 70 _corrFile = new qtFileChooser(); _corrFile ->setObjectName("PPP/corrFile"); _widgets << _corrFile; 70 71 _biasFile = new qtFileChooser(); _biasFile ->setObjectName("PPP/biasFile"); _widgets << _biasFile; … … 395 396 _biasMount ->setEnabled(false); 396 397 _ionoMount ->setEnabled(false); 398 _ephMount ->setEnabled(false); 397 399 _audioResponse->setEnabled(false); 398 400 } -
trunk/BNC/src/pppWidgets.h
r11022 r11136 51 51 QLineEdit* _biasMount; 52 52 QLineEdit* _ionoMount; 53 QLineEdit* _ephMount; 53 54 qtFileChooser* _corrFile; 54 55 qtFileChooser* _biasFile; -
trunk/BNC/tests/README.md
r11130 r11136 52 52 `replay_rinex_eph` (02), `replay_feed_engine` (07, IP port disabled) and 53 53 `replay_save_sp3` (14, with SSRA00CNE1 instead of SSRA00BKG1). 54 * `replay_rinex_eph_perstream`: 02 with 'File per stream' on `data/eph_perstream_260930_4min.raw` 55 (ephemeris messages of BCEP00BKG0, SSRA00EUH0, FFMJ00DEU0, WTZR00DEU0 cut from the 56 merged capture): one RINEX 4 navigation file per stream. 54 57 * `replay_save_sp3_has`: 14 with Galileo HAS (SSRA00EUH0) only; its epochs are 55 58 off the SP3/CLK sampling grid and are written at the preceding grid epoch.
Note:
See TracChangeset
for help on using the changeset viewer.
