Changeset 11136 in ntrip for trunk/BNC/src/bnccore.cpp


Ignore:
Timestamp:
Oct 28, 2026, 4:23:04 PM (5 days ago)
Author:
stuerze
Message:

Added:
EPH RINEX files can be written now per station like observation files and in PPP mode the Broadcast stream can be specified

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/BNC/src/bnccore.cpp

    r11075 r11136  
    7676  // Eph file(s)
    7777  // -----------
    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;
    8780
    8881  _portEph    = 0;
    … …  
    129122  delete _logStream; _logStream = 0;
    130123  delete _logFile;   _logFile   = 0;
    131   delete _ephStreamGPS;
    132   delete _ephFileGPS;
     124  qDeleteAll(_ephFiles);
    133125  delete _serverEph;
    134126  delete _socketsEph;
    135127  delete _serverCorr;
    136128  delete _socketsCorr;
    137   if (_rinexVers == 2) {
    138     delete _ephStreamGlonass;
    139     delete _ephFileGlonass;
    140   }
    141 
    142129  delete _dateAndTimeGPS;
    143130  if (_rawFile) {
    … …  
    230217  }
    231218#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);
    234229  return success;
    235230}
    … …  
    275270}
    276271
    277 // Print Header of the output File(s)
    278 ////////////////////////////////////////////////////////////////////////////
    279 void t_bncCore::printEphHeader(QString receptStaID) {
     272// Close RINEX Navigation File(s)
     273////////////////////////////////////////////////////////////////////////////
     274void 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////////////////////////////////////////////////////////////////////////////
     283t_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////////////////////////////////////////////////////////////////////////////
     291QString 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////////////////////////////////////////////////////////////////////////////
     307t_bncCore::t_ephFile* t_bncCore::printEphHeader(QString receptStaID) {
    280308
    281309  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  // --------------------------------------------------
    282337  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
    285339  QListIterator<QString> it(settings.value("mountPoints").toStringList());
    286340  while (it.hasNext()) {
    … …  
    290344    QUrl url(hlp[0]);
    291345    QString decoder = hlp[1];
    292     if (!separateFiles) {
     346    QString staID   = url.path().mid(1);
     347    if (key.isEmpty() || staID == key) {
    293348      comments.append("Source: " + decoder +
    294349                      " " + QUrl::toAce(url.host()) +
    295350                      "/" + url.path().mid(1).toLatin1());
    296351    }
    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);
    312374    }
    313375  }
    … …  
    315377  // (Re-)Open output File(s)
    316378  // ------------------------
    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");
    364423
    365424    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;
    488523}
    489524
    490525// Print One Ephemeris
    491526////////////////////////////////////////////////////////////////////////////
    492 void t_bncCore::printEph(const t_eph& eph, bool printFile) {
     527void t_bncCore::printEph(t_ephFile* ephFile, const t_eph& eph, bool printFile) {
    493528
    494529  QString strV2 = eph.toString(defaultRnxNavVersion2);
    … …  
    496531  QString strV4 = eph.toString(defaultRnxNavVersion4);
    497532
     533  QTextStream* streamN = ephFile ? ephFile->_streamN : 0;
     534  QTextStream* streamG = ephFile ? ephFile->_streamG : 0;
     535
    498536  if      (_rinexVers == 2 && eph.system() == t_eph::GLONASS) {
    499     printOutputEph(printFile, _ephStreamGlonass, strV2, strV3, strV4);
     537    printOutputEph(printFile, streamG, strV2, strV3, strV4);
    500538  }
    501539  else if (_rinexVers == 2 && eph.system() == t_eph::GPS) {
    502     printOutputEph(printFile, _ephStreamGPS, strV2, strV3, strV4);
     540    printOutputEph(printFile, streamN, strV2, strV3, strV4);
    503541  }
    504542  else if (_rinexVers >= 3) {
    505     printOutputEph(printFile, _ephStreamGPS, strV2, strV3, strV4);
     543    printOutputEph(printFile, streamN, strV2, strV3, strV4);
    506544  }
    507545}
Note: See TracChangeset for help on using the changeset viewer.