Index: /trunk/BNC/CHANGELOG.md
===================================================================
--- /trunk/BNC/CHANGELOG.md	(revision 11135)
+++ /trunk/BNC/CHANGELOG.md	(revision 11136)
@@ -21,4 +21,6 @@
 - ADDED: ANTEX file name, number of entries and latest satellite entry are logged; satellites without a valid ANTEX entry are reported (and not combined)
 - 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
+- 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
+- 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
 - ADDED: Regression test suite ('tests'): example configurations and short raw captures replayed through BNC and compared with reference outputs
 - ADDED: macOS packaging script
Index: /trunk/BNC/src/bnccore.cpp
===================================================================
--- /trunk/BNC/src/bnccore.cpp	(revision 11135)
+++ /trunk/BNC/src/bnccore.cpp	(revision 11136)
@@ -76,13 +76,6 @@
   // Eph file(s)
   // -----------
-  _rinexVers        = 0;
-  _ephFileGPS       = 0;
-  _ephStreamGPS     = 0;
-  _ephFileGlonass   = 0;
-  _ephStreamGlonass = 0;
-  _ephFileGalileo   = 0;
-  _ephStreamGalileo = 0;
-  _ephFileSBAS      = 0;
-  _ephStreamSBAS    = 0;
+  _rinexVers         = 0;
+  _ephFilePerStation = false;
 
   _portEph    = 0;
@@ -129,15 +122,9 @@
   delete _logStream; _logStream = 0;
   delete _logFile;   _logFile   = 0;
-  delete _ephStreamGPS;
-  delete _ephFileGPS;
+  qDeleteAll(_ephFiles);
   delete _serverEph;
   delete _socketsEph;
   delete _serverCorr;
   delete _socketsCorr;
-  if (_rinexVers == 2) {
-    delete _ephStreamGlonass;
-    delete _ephFileGlonass;
-  }
-
   delete _dateAndTimeGPS;
   if (_rawFile) {
@@ -230,6 +217,14 @@
   }
 #endif
-  printEphHeader(eph->receptStaID());
-  printEph(*eph, bool(ircPut == success));
+  t_ephFile* ephFile = printEphHeader(eph->receptStaID());
+  bool printFile = (ircPut == success);
+  if (ephFile && ephFile->_ephUser) {
+    // file per stream: new ephemerides of this stream, independent of other streams;
+    // the check state of the emitted ephemeris stays that of the common check
+    t_eph::e_checkState checkState = eph->checkState();
+    printFile = (ephFile->_ephUser->putNewEph(eph, true) == success);
+    eph->setCheckState(checkState);
+  }
+  printEph(ephFile, *eph, printFile);
   return success;
 }
@@ -275,12 +270,71 @@
 }
 
-// Print Header of the output File(s)
-////////////////////////////////////////////////////////////////////////////
-void t_bncCore::printEphHeader(QString receptStaID) {
+// Close RINEX Navigation File(s)
+////////////////////////////////////////////////////////////////////////////
+void t_bncCore::t_ephFile::close() {
+  delete _streamN; _streamN = 0;
+  delete _fileN;   _fileN   = 0;
+  delete _streamG; _streamG = 0;
+  delete _fileG;   _fileG   = 0;
+}
+
+// Destructor
+////////////////////////////////////////////////////////////////////////////
+t_bncCore::t_ephFile::~t_ephFile() {
+  close();
+  delete _ephUser;
+}
+
+// Station part of a RINEX navigation file name: "BRDC" (+ "00WRD" in RINEX 3/4)
+// for the single file, otherwise derived from the stream like the observation files
+////////////////////////////////////////////////////////////////////////////
+QString t_bncCore::ephFileNameBase(const QString& staID, const QString& country) const {
+  QString ID = staID.isEmpty() ? QString("BRDC") : staID.left(4).toUpper();
+  if (_rinexVers <= 2) {
+    return ID;
+  }
+  if (staID.size() >= 9 &&
+      isdigit((unsigned char) staID[4].toLatin1()) &&
+      isdigit((unsigned char) staID[5].toLatin1())) {
+    return staID.left(9).toUpper();   // e.g. BCEP00BKG0 -> BCEP00BKG
+  }
+  return ID + "00" + ((!staID.isEmpty() && country.size() >= 3) ? country.left(3).toUpper()
+                                                                : QString("WRD")); // WORLD
+}
+
+// Print Header of the output File(s), returns the file of the stream
+////////////////////////////////////////////////////////////////////////////
+t_bncCore::t_ephFile* t_bncCore::printEphHeader(QString receptStaID) {
 
   bncSettings settings;
+
+  // Initialization
+  // --------------
+  if (_rinexVers == 0) {
+
+    _rinexVers = settings.value("ephVersion").toInt();
+
+    _ephFilePerStation = Qt::CheckState(settings.value("ephFilePerStation").toInt()) == Qt::Checked;
+
+    _ephPath = settings.value("ephPath").toString();
+
+    if ( !_ephPath.isEmpty() ) {
+      if ( _ephPath[_ephPath.length()-1] != QDir::separator() ) {
+        _ephPath += QDir::separator();
+      }
+      expandEnvVar(_ephPath);
+    }
+  }
+
+  if (_ephPath.isEmpty()) {
+    return 0;
+  }
+
+  QString key = _ephFilePerStation ? receptStaID : QString();
+
+  // Source comments and station part of the file name
+  // --------------------------------------------------
   QStringList comments;
-  bool separateFiles = false;// Qt::CheckState(settings.value("ephFilePerStation").toInt());
-
+  QMap<QString, QString> nameBase;  // staID -> station part of its file name
   QListIterator<QString> it(settings.value("mountPoints").toStringList());
   while (it.hasNext()) {
@@ -290,24 +344,32 @@
     QUrl url(hlp[0]);
     QString decoder = hlp[1];
-    if (!separateFiles) {
+    QString staID   = url.path().mid(1);
+    if (key.isEmpty() || staID == key) {
       comments.append("Source: " + decoder +
                       " " + QUrl::toAce(url.host()) +
                       "/" + url.path().mid(1).toLatin1());
     }
-  }
-
-  // Initialization
-  // --------------
-  if (_rinexVers == 0) {
-
-    _rinexVers = settings.value("ephVersion").toInt();
-
-    _ephPath = settings.value("ephPath").toString();
-
-    if ( !_ephPath.isEmpty() ) {
-      if ( _ephPath[_ephPath.length()-1] != QDir::separator() ) {
-        _ephPath += QDir::separator();
-      }
-      expandEnvVar(_ephPath);
+    nameBase[staID] = ephFileNameBase(staID, hlp[2]);
+  }
+
+  QString base = (!key.isEmpty() && nameBase.contains(key)) ? nameBase[key]
+                                                           : ephFileNameBase(key, QString());
+  QString distStr;
+  if (!key.isEmpty()) {
+    QMapIterator<QString, QString> im(nameBase);
+    while (im.hasNext()) {
+      im.next();
+      if (im.key() != key && im.value() == base) { // name conflict with another stream
+        distStr = "_" + key;
+        break;
+      }
+    }
+  }
+
+  t_ephFile*& ephFile = _ephFiles[key];
+  if (!ephFile) {
+    ephFile = new t_ephFile;
+    if (_ephFilePerStation) {
+      ephFile->_ephUser = new bncEphUser(false);
     }
   }
@@ -315,180 +377,153 @@
   // (Re-)Open output File(s)
   // ------------------------
-  if (!_ephPath.isEmpty()) {
-
-    QDateTime datTim = currentDateAndTimeGPS();
-
-    QString ephFileNameGPS = _ephPath; // + "BRDC";
-
-    (separateFiles) ?  ephFileNameGPS += receptStaID.left(4) :
-                       ephFileNameGPS += "BRDC";
-
-    QString hlpStr = bncRinex::nextEpochStr(datTim,
-                         settings.value("ephIntr").toString(), _rinexVers);
-
-    if (_rinexVers > 2) {
-      QString country = "WRD"; // WORLD
-      QString monNum = "0";
-      QString recNum = "0";
-      if (separateFiles && receptStaID.size() >= 9) {
-        monNum = receptStaID.mid(4,1);
-        recNum = receptStaID.mid(5,1);
-        country = receptStaID.mid(6,3);
-      }
-      ephFileNameGPS += QString("%1").arg(monNum, 1, 10) +
-                        QString("%1").arg(recNum, 1, 10) +
-                        country +
-                        "_S_" +     // stream
-                        QString("%1").arg(datTim.date().year()) +
-                        QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) +
-                        hlpStr +   // HM_period
-                        "_MN.rnx"; // mixed BRDC
-    }
-    else { // RNX v2.11
-      ephFileNameGPS += QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) +
-                        hlpStr + datTim.toString(".yyN");
-    }
-
-    if (_ephFileNameGPS == ephFileNameGPS) {
-      return;
-    }
-    else {
-      _ephFileNameGPS = ephFileNameGPS;
-    }
-
-    delete _ephStreamGPS;
-    delete _ephFileGPS;
-
-    QFlags<QIODevice::OpenModeFlag> appendFlagGPS;
-    QFlags<QIODevice::OpenModeFlag> appendFlagGlonass;
+  QDateTime datTim = currentDateAndTimeGPS();
+
+  QString hlpStr = bncRinex::nextEpochStr(datTim,
+                       settings.value("ephIntr").toString(), _rinexVers);
+
+  QString ephFileNameGPS = _ephPath + base;
+
+  if (_rinexVers > 2) {
+    ephFileNameGPS += "_S_" +     // stream
+                      QString("%1").arg(datTim.date().year()) +
+                      QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) +
+                      hlpStr +   // HM_period
+                      "_MN" +    // mixed BRDC
+                      distStr + ".rnx";
+  }
+  else { // RNX v2.11
+    ephFileNameGPS += QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) +
+                      hlpStr + distStr + datTim.toString(".yyN");
+  }
+
+  if (ephFile->_name == ephFileNameGPS) {
+    return ephFile;
+  }
+  ephFile->_name = ephFileNameGPS;
+  ephFile->close();
+
+  QFlags<QIODevice::OpenModeFlag> appendFlagGPS;
+  QFlags<QIODevice::OpenModeFlag> appendFlagGlonass;
+
+  if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked &&
+       QFile::exists(ephFileNameGPS) ) {
+    appendFlagGPS = QIODevice::Append;
+  }
+
+  ephFile->_fileN = new QFile(ephFileNameGPS);
+  ephFile->_fileN->open(QIODevice::WriteOnly | appendFlagGPS);
+  ephFile->_streamN = new QTextStream();
+  ephFile->_streamN->setDevice(ephFile->_fileN);
+  QTextStream* streamGPS = ephFile->_streamN;
+
+  if (_rinexVers == 2) {
+    QString ephFileNameGlonass = _ephPath + base +
+        QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) +
+        hlpStr + distStr + datTim.toString(".yyG");
 
     if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked &&
-         QFile::exists(ephFileNameGPS) ) {
-      appendFlagGPS = QIODevice::Append;
-    }
-
-    _ephFileGPS = new QFile(ephFileNameGPS);
-    _ephFileGPS->open(QIODevice::WriteOnly | appendFlagGPS);
-    _ephStreamGPS = new QTextStream();
-    _ephStreamGPS->setDevice(_ephFileGPS);
-
-    if      (_rinexVers > 2) {
-      _ephFileGlonass   = _ephFileGPS;
-      _ephStreamGlonass = _ephStreamGPS;
-      _ephFileGalileo   = _ephFileGPS;
-      _ephStreamGalileo = _ephStreamGPS;
-      _ephFileSBAS      = _ephFileGPS;
-      _ephStreamSBAS    = _ephStreamGPS;
-    }
-    else {
-      QString ephFileNameGlonass = _ephPath + "BRDC" +
-          QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) +
-          hlpStr + datTim.toString(".yyG");
-
-      delete _ephStreamGlonass;
-      delete _ephFileGlonass;
-
-      if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked &&
-           QFile::exists(ephFileNameGlonass) ) {
-        appendFlagGlonass = QIODevice::Append;
-      }
-
-      _ephFileGlonass = new QFile(ephFileNameGlonass);
-      _ephFileGlonass->open(QIODevice::WriteOnly | appendFlagGlonass);
-      _ephStreamGlonass = new QTextStream();
-      _ephStreamGlonass->setDevice(_ephFileGlonass);
-    }
-
-    // Header - RINEX Version 3
-    // ------------------------
-    if (_rinexVers > 2) {
-      if ( ! (appendFlagGPS & QIODevice::Append)) {
-        double rinexVersion = defaultRnxNavVersion4;
-        if (_rinexVers < 4.0) {
-          rinexVersion = defaultRnxNavVersion3;
-        }
-        QString line = QString().asprintf("%9.2f%11sN: GNSS NAV DATA    M: Mixed%12sRINEX VERSION / TYPE\n",
-            rinexVersion, "", "");
-        *_ephStreamGPS << line;
-        line.clear();
-
-        QString hlp = currentDateAndTimeGPS().toString("yyyyMMdd hhmmss UTC").leftJustified(20, ' ', true);
-        *_ephStreamGPS << _pgmName.toLatin1().data()
-                       << _userName.toLatin1().data()
-                       << hlp.toLatin1().data()
-                       << "PGM / RUN BY / DATE\n";
-
-        QStringListIterator it(comments);
-        while (it.hasNext()) {
-          *_ephStreamGPS << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
-        }
-
-        if (_rinexVers == 4) {
-          int leapSecs = gnumleap(datTim.date().year(), datTim.date().month(), datTim.date().day());
-          *_ephStreamGPS << QString("%1").arg(leapSecs, 6, 10, QLatin1Char(' ')).left(60).leftJustified(60)
-                  << "LEAP SECONDS\n";
-        }
-
-        line = QString().asprintf("%60sEND OF HEADER\n", "");
-        *_ephStreamGPS << line;
-
-        _ephStreamGPS->flush();
-      }
-    }
-
-    // Headers - RINEX Version 2
-    // -------------------------
-    else {
-      if (! (appendFlagGPS & QIODevice::Append)) {
-        QString line = QString().asprintf("%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n",
-                     defaultRnxNavVersion2, "", "");
-        *_ephStreamGPS << line;
-        line.clear();
-
-        QString hlp = currentDateAndTimeGPS().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true);
-        *_ephStreamGPS << _pgmName.toLatin1().data()
-                       << _userName.toLatin1().data()
-                       << hlp.toLatin1().data()
-                       << "PGM / RUN BY / DATE\n";
-
-        QStringListIterator it(comments);
-        while (it.hasNext()) {
-          *_ephStreamGPS << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
-        }
-
-        line = QString().asprintf("%60sEND OF HEADER\n", "");
-        *_ephStreamGPS << line;
-
-        _ephStreamGPS->flush();
-      }
-      if (! (appendFlagGlonass & QIODevice::Append)) {
-        QString line = QString().asprintf("%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n",
-                     defaultRnxNavVersion2, "", "");
-        *_ephStreamGlonass << line;
-        line.clear();
-
-        QString hlp = currentDateAndTimeGPS().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true);
-        *_ephStreamGlonass << _pgmName.toLatin1().data()
-                           << _userName.toLatin1().data()
-                           << hlp.toLatin1().data()
-                           << "PGM / RUN BY / DATE\n";
-
-        QStringListIterator it(comments);
-        while (it.hasNext()) {
-          *_ephStreamGlonass << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
-        }
-
-        line = QString().asprintf("%60sEND OF HEADER\n", "");
-        *_ephStreamGlonass << line;
-
-        _ephStreamGlonass->flush();
-      }
-    }
-  }
+         QFile::exists(ephFileNameGlonass) ) {
+      appendFlagGlonass = QIODevice::Append;
+    }
+
+    ephFile->_fileG = new QFile(ephFileNameGlonass);
+    ephFile->_fileG->open(QIODevice::WriteOnly | appendFlagGlonass);
+    ephFile->_streamG = new QTextStream();
+    ephFile->_streamG->setDevice(ephFile->_fileG);
+  }
+  QTextStream* streamGlonass = ephFile->_streamG;
+
+  // Header - RINEX Version 3
+  // ------------------------
+  if (_rinexVers > 2) {
+    if ( ! (appendFlagGPS & QIODevice::Append)) {
+      double rinexVersion = defaultRnxNavVersion4;
+      if (_rinexVers < 4.0) {
+        rinexVersion = defaultRnxNavVersion3;
+      }
+      QString line = QString().asprintf("%9.2f%11sN: GNSS NAV DATA    M: Mixed%12sRINEX VERSION / TYPE\n",
+          rinexVersion, "", "");
+      *streamGPS << line;
+      line.clear();
+
+      QString hlp = currentDateAndTimeGPS().toString("yyyyMMdd hhmmss UTC").leftJustified(20, ' ', true);
+      *streamGPS << _pgmName.toLatin1().data()
+                 << _userName.toLatin1().data()
+                 << hlp.toLatin1().data()
+                 << "PGM / RUN BY / DATE\n";
+
+      QStringListIterator it(comments);
+      while (it.hasNext()) {
+        *streamGPS << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
+      }
+
+      if (_rinexVers == 4) {
+        int leapSecs = gnumleap(datTim.date().year(), datTim.date().month(), datTim.date().day());
+        *streamGPS << QString("%1").arg(leapSecs, 6, 10, QLatin1Char(' ')).left(60).leftJustified(60)
+                   << "LEAP SECONDS\n";
+      }
+
+      line = QString().asprintf("%60sEND OF HEADER\n", "");
+      *streamGPS << line;
+
+      streamGPS->flush();
+    }
+  }
+
+  // Headers - RINEX Version 2
+  // -------------------------
+  else {
+    if (! (appendFlagGPS & QIODevice::Append)) {
+      QString line = QString().asprintf("%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n",
+                   defaultRnxNavVersion2, "", "");
+      *streamGPS << line;
+      line.clear();
+
+      QString hlp = currentDateAndTimeGPS().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true);
+      *streamGPS << _pgmName.toLatin1().data()
+                 << _userName.toLatin1().data()
+                 << hlp.toLatin1().data()
+                 << "PGM / RUN BY / DATE\n";
+
+      QStringListIterator it(comments);
+      while (it.hasNext()) {
+        *streamGPS << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
+      }
+
+      line = QString().asprintf("%60sEND OF HEADER\n", "");
+      *streamGPS << line;
+
+      streamGPS->flush();
+    }
+    if (! (appendFlagGlonass & QIODevice::Append)) {
+      QString line = QString().asprintf("%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n",
+                   defaultRnxNavVersion2, "", "");
+      *streamGlonass << line;
+      line.clear();
+
+      QString hlp = currentDateAndTimeGPS().date().toString("dd-MMM-yyyy").leftJustified(20, ' ', true);
+      *streamGlonass << _pgmName.toLatin1().data()
+                     << _userName.toLatin1().data()
+                     << hlp.toLatin1().data()
+                     << "PGM / RUN BY / DATE\n";
+
+      QStringListIterator it(comments);
+      while (it.hasNext()) {
+        *streamGlonass << it.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
+      }
+
+      line = QString().asprintf("%60sEND OF HEADER\n", "");
+      *streamGlonass << line;
+
+      streamGlonass->flush();
+    }
+  }
+
+  return ephFile;
 }
 
 // Print One Ephemeris
 ////////////////////////////////////////////////////////////////////////////
-void t_bncCore::printEph(const t_eph& eph, bool printFile) {
+void t_bncCore::printEph(t_ephFile* ephFile, const t_eph& eph, bool printFile) {
 
   QString strV2 = eph.toString(defaultRnxNavVersion2);
@@ -496,12 +531,15 @@
   QString strV4 = eph.toString(defaultRnxNavVersion4);
 
+  QTextStream* streamN = ephFile ? ephFile->_streamN : 0;
+  QTextStream* streamG = ephFile ? ephFile->_streamG : 0;
+
   if      (_rinexVers == 2 && eph.system() == t_eph::GLONASS) {
-    printOutputEph(printFile, _ephStreamGlonass, strV2, strV3, strV4);
+    printOutputEph(printFile, streamG, strV2, strV3, strV4);
   }
   else if (_rinexVers == 2 && eph.system() == t_eph::GPS) {
-    printOutputEph(printFile, _ephStreamGPS, strV2, strV3, strV4);
+    printOutputEph(printFile, streamN, strV2, strV3, strV4);
   }
   else if (_rinexVers >= 3) {
-    printOutputEph(printFile, _ephStreamGPS, strV2, strV3, strV4);
+    printOutputEph(printFile, streamN, strV2, strV3, strV4);
   }
 }
Index: /trunk/BNC/src/bnccore.h
===================================================================
--- /trunk/BNC/src/bnccore.h	(revision 11135)
+++ /trunk/BNC/src/bnccore.h	(revision 11136)
@@ -132,7 +132,22 @@
 
  private:
+  // RINEX navigation file(s): one file, or one per stream (ephFilePerStation)
+  class t_ephFile {
+   public:
+    t_ephFile() : _fileN(0), _streamN(0), _fileG(0), _streamG(0), _ephUser(0) {}
+    ~t_ephFile();
+    void close();
+    QString      _name;     // current file name (RINEX 2: GPS file)
+    QFile*       _fileN;    // mixed (RINEX 3/4) or GPS (RINEX 2)
+    QTextStream* _streamN;
+    QFile*       _fileG;    // GLONASS (RINEX 2 only)
+    QTextStream* _streamG;
+    bncEphUser*  _ephUser;  // file per stream: ephemerides of this stream only
+  };
+
   t_irc checkPrintEph(t_eph* eph);
-  void  printEphHeader(QString receptStaID);
-  void  printEph(const t_eph& eph, bool printFile);
+  t_ephFile* printEphHeader(QString receptStaID);
+  QString ephFileNameBase(const QString& staID, const QString& country) const;
+  void  printEph(t_ephFile* ephFile, const t_eph& eph, bool printFile);
   void  printOutputEph(bool printFile, QTextStream* stream,
                        const QString& strV2, const QString& strV3,
@@ -147,14 +162,7 @@
   QMutex                 _mutexMessage;
   QString                _ephPath;
-  QString                _ephFileNameGPS;
   int                    _rinexVers;
-  QFile*                 _ephFileGPS;
-  QTextStream*           _ephStreamGPS;
-  QFile*                 _ephFileGlonass;
-  QTextStream*           _ephStreamGlonass;
-  QFile*                 _ephFileGalileo;
-  QTextStream*           _ephStreamGalileo;
-  QFile*                 _ephFileSBAS;
-  QTextStream*           _ephStreamSBAS;
+  bool                   _ephFilePerStation;
+  QMap<QString, t_ephFile*> _ephFiles;  // key: staID, "" for the single file
   QString                _userName;
   QString                _pgmName;
Index: /trunk/BNC/src/bnchelp.html
===================================================================
--- /trunk/BNC/src/bnchelp.html	(revision 11135)
+++ /trunk/BNC/src/bnchelp.html	(revision 11136)
@@ -129,4 +129,5 @@
     &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.5.3 <a href="#ephport">Port</a><br>
     &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.5.4 <a href="#ephvers">Version</a><br>
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.5.5 <a href="#ephperstream">File per Stream</a><br>
     &nbsp; &nbsp; &nbsp; 2.6 <a href="#reqc"><b>RINEX Editing & QC</b></a><br>
     &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.6.1 <a href="#reqcact">Action</a><br>
@@ -189,24 +190,25 @@
       Stream</a><br>
     &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.7 <a href=#pppionofile>Ionosphere File</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.8 <a href=#ppprnxobs>RINEX Observation
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.8 <a href=#pppephstream>Ephemeris Stream</a><br>
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.9 <a href=#ppprnxobs>RINEX Observation
       File</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.9 <a href=#ppprnxnav>RINEX Navigation
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.10 <a href=#ppprnxnav>RINEX Navigation
       File</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.10 <a href=#pppantexfile>ANTEX File</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.11 <a href=#pppmarkcoor>Coordinates
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.11 <a href=#pppantexfile>ANTEX File</a><br>
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.12 <a href=#pppmarkcoor>Coordinates
       File</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.12 <a href=#pppblqfile>BLQ File</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.13 <a href=#ppplogfile>Logfile Directory and
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.13 <a href=#pppblqfile>BLQ File</a><br>
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.14 <a href=#ppplogfile>Logfile Directory and
       Log mode</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.14 <a href=#pppnmeafile>NMEA Directory</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.15 <a href=#pppsnxtrofile>SNX TRO
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.15 <a href=#pppnmeafile>NMEA Directory</a><br>
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.16 <a href=#pppsnxtrofile>SNX TRO
       Directory</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.15.1 <a
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.16.1 <a
       href=#pppsnxtrointr>Interval</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.15.2 <a
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.16.2 <a
       href=#pppsnxtrosampl>Sampling</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.15.3 <a href=#pppsnxAc>Analysis
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.16.3 <a href=#pppsnxAc>Analysis
       Center</a><br>
-    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.15.4 <a href=#pppsnxSol>Solution
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.1.16.4 <a href=#pppsnxSol>Solution
       ID</a><br>
     &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.13.2 <a href=#pppOptions><b>PPP (2): Processing Options</b></a><br>
@@ -3495,4 +3497,24 @@
     Note that the here choosen Version concerns the Broadcast Ephemeris output through IP port as well.
   </p>
+  <p>
+  <h4 id="ephperstream">2.5.5 File per Stream - optional</h4>
+  </p>
+  <p>
+    By default, the Broadcast Ephemeris of all streams are saved in one RINEX Navigation file (BRDC). Each ephemeris is
+    saved only once, from the stream which first provided it, so the file does not show which stream an ephemeris
+    came from.
+  </p>
+  <p>
+    Tick 'File per stream' to save one RINEX Navigation file per stream instead. The files are named after the
+    stream like the RINEX Observation files, e.g. 'BCEP00BKG_S_20262730000_01D_MN.rnx' for stream 'BCEP00BKG0' (RINEX
+    Version 3 or 4) or 'BCEP2730.26N' (RINEX Version 2). If two streams would get the same file name, the complete
+    stream name is appended. Each file contains all ephemerides received from its stream, independent of the
+    other streams, and its header contains the source of this stream only. This allows to check the Broadcast
+    Ephemeris of a stream, e.g. of an ephemeris stream like 'BCEP00BKG0' compared to those contained in
+    observation streams.
+  </p>
+  <p>
+    The output through IP port is not affected by this option.
+  </p>
 
   <p>
@@ -6393,5 +6415,18 @@
   </p>
   <p>
-  <h4 id="ppprnxobs">2.13.1.8 RINEX Observation File - mandatory if 'Data source' is set to 'RINEX Files'</h4>
+  <h4 id="pppephstream">2.13.1.8 Ephemeris Stream - optional if 'Data source' is set to 'Real-Time Streams'</h4>
+  </p>
+  <p>
+    By default, real-time PPP uses the Broadcast Ephemeris of all streams you are pulling, including those contained
+    in the observation streams. Specify one or more 'mountpoints' (separated by comma) from the list of selected
+    'Streams' to use the Broadcast Ephemeris of these streams only, e.g. 'BCEP00BKG0'. Ephemerides of all other
+    streams, the observation streams included, are then not used in PPP.
+  </p>
+  <p>
+    Note that the ephemerides of the selected stream must match the IODs of the corrections stream. If you do not
+    specify an 'Ephemeris stream' via this option, BNC will use the Broadcast Ephemeris of all streams.
+  </p>
+  <p>
+  <h4 id="ppprnxobs">2.13.1.9 RINEX Observation File - mandatory if 'Data source' is set to 'RINEX Files'</h4>
   </p>
   <p>
@@ -6399,5 +6434,5 @@
   </p>
   <p>
-  <h4 id="ppprnxnav">2.13.1.9 RINEX Navigation File - mandatory if 'Data source' is set to 'RINEX Files'</h4>
+  <h4 id="ppprnxnav">2.13.1.10 RINEX Navigation File - mandatory if 'Data source' is set to 'RINEX Files'</h4>
   </p>
   <p>
@@ -6405,5 +6440,5 @@
   </p>
   <p>
-  <h4 id="pppantexfile">2.13.1.10 ANTEX File - optional</h4>
+  <h4 id="pppantexfile">2.13.1.11 ANTEX File - optional</h4>
   </p>
   <p>
@@ -6465,5 +6500,5 @@
   </p>
   <p>
-  <h4 id="pppmarkcoor">2.13.1.11 Coordinates File - optional </h4>
+  <h4 id="pppmarkcoor">2.13.1.12 Coordinates File - optional </h4>
   </p>
   <p>
@@ -6611,5 +6646,5 @@
 
   <p>
-  <h4 id="pppblqfile">2.13.1.12 BLQ File - optional </h4>
+  <h4 id="pppblqfile">2.13.1.13 BLQ File - optional </h4>
   </p>
   <p>
@@ -6623,5 +6658,5 @@
 
   <p>
-  <h4 id="ppplogfile">2.13.1.13 Logfile Directory and Log mode - optional</h4>
+  <h4 id="ppplogfile">2.13.1.14 Logfile Directory and Log mode - optional</h4>
   </p>
   <p>
@@ -7059,5 +7094,5 @@
 
   <p>
-  <h4 id="pppnmeafile">2.13.1.14 NMEA Directory - optional</h4>
+  <h4 id="pppnmeafile">2.13.1.15 NMEA Directory - optional</h4>
   </p>
   <p>
@@ -7106,5 +7141,5 @@
 
   <p>
-  <h4 id="pppsnxtrofile">2.13.1.15 SNX TRO Directory - optional</h4>
+  <h4 id="pppsnxtrofile">2.13.1.16 SNX TRO Directory - optional</h4>
   </p>
   <p>
@@ -7263,5 +7298,5 @@
 
   <p>
-  <h4 id="pppsnxtrointr">2.13.1.15.1 Interval - mandatory if 'SINEX TRO Directory' is set</h4>
+  <h4 id="pppsnxtrointr">2.13.1.16.1 Interval - mandatory if 'SINEX TRO Directory' is set</h4>
   </p>
   <p>
@@ -7272,5 +7307,5 @@
   </p>
   <p>
-  <h4 id="pppsnxtrosampl">2.13.1.15.2 Sampling - mandatory if 'SINEX TRO Directory' is set</h4>
+  <h4 id="pppsnxtrosampl">2.13.1.16.2 Sampling - mandatory if 'SINEX TRO Directory' is set</h4>
   </p>
   <p>
@@ -7282,5 +7317,5 @@
 
   <p>
-  <h4 id="pppsnxAc">2.13.1.15.3 Analysis Center - Mandatory if 'SINEX TRO Directory' is set</h4>
+  <h4 id="pppsnxAc">2.13.1.16.3 Analysis Center - Mandatory if 'SINEX TRO Directory' is set</h4>
   </p>
   <p>
@@ -7290,5 +7325,5 @@
 
   <p>
-  <h4 id="pppsnxSol">2.13.1.15.4 Solution ID - Mandatory if 'SINEX TRO Directory' is set</h4>
+  <h4 id="pppsnxSol">2.13.1.16.4 Solution ID - Mandatory if 'SINEX TRO Directory' is set</h4>
   </p>
   <p>
@@ -10962,4 +10997,5 @@
    ephOutPort     {Output port [integer number]}
    ephVersion     {Specifies the RINEX version of the file contents [integer number: 2|3|4]}
+   ephFilePerStation {One RINEX navigation file per stream [integer number: 0=no,2=yes]}
 
 RINEX Editing and QC Panel keys:
@@ -11058,4 +11094,5 @@
    PPP/ionoMount     {VTEC mountpoint, [char string]}
    PPP/ionoFile      {VTEC file, full path [char string]}
+   PPP/ephMount      {Broadcast Ephemeris mountpoint(s), comma separated [char string]}
    PPP/nmeaPath      {Directory for NMEA output files [character string]}
    PPP/snxtroPath    {Directory for SINEX troposphere output files [character string]}
Index: /trunk/BNC/src/bncmain.cpp
===================================================================
--- /trunk/BNC/src/bncmain.cpp	(revision 11135)
+++ /trunk/BNC/src/bncmain.cpp	(revision 11136)
@@ -161,4 +161,5 @@
         "   ephOutPort     {Output port [integer number]}\n"
         "   ephVersion     {Specifies the RINEX version of the file contents [integer number: 2|3|4]}\n"
+        "   ephFilePerStation {One RINEX navigation file per stream [integer number: 0=no,2=yes]}\n"
         "\n"
         "RINEX Editing and QC Panel keys:\n"
@@ -263,4 +264,5 @@
         "   PPP/ionoMount     {VTEC mountpoint, [char string]}\n"
         "   PPP/ionoFile      {VTEC file, full path [char string]}\n"
+        "   PPP/ephMount      {Broadcast Ephemeris mountpoint(s), comma separated [char string]}\n"
         "   PPP/nmeaPath      {Directory for NMEA output files [character string]}\n"
         "   PPP/snxtroPath    {Directory for SINEX troposphere output files [character string]}\n"
Index: /trunk/BNC/src/bncsettings.cpp
===================================================================
--- /trunk/BNC/src/bncsettings.cpp	(revision 11135)
+++ /trunk/BNC/src/bncsettings.cpp	(revision 11136)
@@ -96,4 +96,5 @@
         setValue_p("ephOutPort", "");
         setValue_p("ephVersion", "3");
+        setValue_p("ephFilePerStation", "0");
         // Reqc
         setValue_p("reqcAction", "");
Index: /trunk/BNC/src/bncwindow.cpp
===================================================================
--- /trunk/BNC/src/bncwindow.cpp	(revision 11135)
+++ /trunk/BNC/src/bncwindow.cpp	(revision 11136)
@@ -278,6 +278,6 @@
     _ephVersComboBox->setCurrentIndex(jk);
   }
-  //_ephFilePerStation = new QCheckBox();
-  //_ephFilePerStation->setCheckState(Qt::CheckState(settings.value("ephFilePerStation").toInt()));
+  _ephFilePerStation = new QCheckBox();
+  _ephFilePerStation->setCheckState(Qt::CheckState(settings.value("ephFilePerStation").toInt()));
 
   connect(_ephOutPortLineEdit, SIGNAL(textChanged(const QString&)),
@@ -902,8 +902,7 @@
   eLayout->addWidget(new QLabel("Version"), 4, 0);
   eLayout->addWidget(_ephVersComboBox, 4, 1);
-  eLayout->setRowStretch(5, 999);
-  //eLayout->addWidget(new QLabel("File per Station"),              5, 0);
-  //eLayout->addWidget(_ephFilePerStation,                          5, 1);
-  //eLayout->setRowStretch(6, 999);
+  eLayout->addWidget(new QLabel("File per stream"), 5, 0);
+  eLayout->addWidget(_ephFilePerStation, 5, 1);
+  eLayout->setRowStretch(6, 999);
 
   egroup->setLayout(eLayout);
@@ -1066,4 +1065,5 @@
   _pppWidgets._snxtroCampId->setMaximumWidth(7 * ww);
   _pppWidgets._ionoMount->setMaximumWidth(15 * ww);
+  _pppWidgets._ephMount->setMaximumWidth(15 * ww);
 
 
@@ -1100,4 +1100,7 @@
   pppLayout1->addWidget(new QLabel("   SNX TRO sampling"), ir, 6);
   pppLayout1->addWidget(_pppWidgets._snxtroSampl, ir, 7, Qt::AlignRight);
+  ++ir;
+  pppLayout1->addWidget(new QLabel("Ephemeris stream"), ir, 0);
+  pppLayout1->addWidget(_pppWidgets._ephMount, ir, 1);
   ++ir;
   pppLayout1->addWidget(new QLabel("RINEX Obs file"), ir, 0);
@@ -1580,5 +1583,5 @@
   _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>"));
   _ephVersComboBox->setWhatsThis(tr("<p>Select the format for RINEX Navigation files. <i>[key: ephVersion]</i></p>"));
-  //_ephFilePerStation->setWhatsThis(tr("<p>By default, all received Broadcast Ephemeris data will be stored within one File. Thick 'File per Stations' to get separate files per station/mountpoint. <i>[key: ephFilePerStation]</i></p>"));
+  _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>"));
 
   // WhatsThis, RINEX Editing & QC
@@ -1662,4 +1665,5 @@
   _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>"));
   _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>"));
+  _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>"));
   _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>"));
   _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,5 +1885,5 @@
   delete _rnxV2Priority;
   delete _ephPathLineEdit;
-  //delete _ephFilePerStation;
+  delete _ephFilePerStation;
   delete _ephIntrComboBox;
   delete _ephOutPortLineEdit;
@@ -2416,5 +2420,5 @@
   settings.setValue("ephOutPort", _ephOutPortLineEdit->text());
   settings.setValue("ephVersion", _ephVersComboBox->currentText());
-  //settings.setValue("ephFilePerStation", _ephFilePerStation->checkState());
+  settings.setValue("ephFilePerStation", _ephFilePerStation->checkState());
   // Broadcast Corrections
   settings.setValue("corrPath", _corrPathLineEdit->text());
@@ -2951,6 +2955,5 @@
     enableWidget(enable, _ephIntrComboBox);
     enableWidget(enable, _ephVersComboBox);
-    //enableWidget(enable, _ephVersComboBox);
-    //enableWidget(enable, _ephFilePerStation);
+    enableWidget(!_ephPathLineEdit->text().isEmpty(), _ephFilePerStation);
   }
 
Index: /trunk/BNC/src/bncwindow.h
===================================================================
--- /trunk/BNC/src/bncwindow.h	(revision 11135)
+++ /trunk/BNC/src/bncwindow.h	(revision 11136)
@@ -179,5 +179,5 @@
     QLineEdit* _rnxV2Priority;
     QComboBox* _ephVersComboBox;
-    //QCheckBox* _ephFilePerStation;
+    QCheckBox* _ephFilePerStation;
     QCheckBox* _rnxFileCheckBox;
     QLineEdit* _rnxScrpLineEdit;
Index: /trunk/BNC/src/pppMain.cpp
===================================================================
--- /trunk/BNC/src/pppMain.cpp	(revision 11135)
+++ /trunk/BNC/src/pppMain.cpp	(revision 11136)
@@ -217,4 +217,5 @@
       opt->_biasMount.assign(settings.value("PPP/biasMount").toString().toStdString());
       opt->_ionoMount.assign(settings.value("PPP/ionoMount").toString().toStdString());
+      opt->_ephMount.assign(settings.value("PPP/ephMount").toString().toStdString());
     }
     else {
Index: /trunk/BNC/src/pppOptions.h
===================================================================
--- /trunk/BNC/src/pppOptions.h	(revision 11135)
+++ /trunk/BNC/src/pppOptions.h	(revision 11136)
@@ -66,4 +66,5 @@
   std::string                   _biasMount;
   std::string                   _ionoMount;
+  std::string                   _ephMount;
   bool                          _isAPC;
   std::string                   _rinexObs;
Index: /trunk/BNC/src/pppRun.cpp
===================================================================
--- /trunk/BNC/src/pppRun.cpp	(revision 11135)
+++ /trunk/BNC/src/pppRun.cpp	(revision 11136)
@@ -82,4 +82,11 @@
 
   if (_opt->_realTime) {
+    _ephMounts = QString::fromStdString(_opt->_ephMount).split(QRegularExpression("[,\\s]+"),
+                                                                Qt::SkipEmptyParts);
+    if (!_ephMounts.isEmpty()) {
+      emit newMessage(QByteArray(_opt->_roverName.c_str()) + ": PPP uses the ephemerides of "
+                      + _ephMounts.join(", ").toLatin1() + " only", true);
+    }
+
     Qt::ConnectionType conType = Qt::AutoConnection;
     if (BNC_CORE->mode() == t_bncCore::batchPostProcessing) {
@@ -248,7 +255,16 @@
 }
 
+// Ephemeris from a stream selected for PPP (PPP/ephMount)?
+////////////////////////////////////////////////////////////////////////////
+bool t_pppRun::useEph(const t_eph& eph) const {
+  return _ephMounts.isEmpty() || _ephMounts.contains(eph.receptStaID());
+}
+
 //
 ////////////////////////////////////////////////////////////////////////////
 void t_pppRun::slotNewGPSEph(t_ephGPS eph) {
+  if (!useEph(eph)) {
+    return;
+  }
   QMutexLocker locker(&_mutex);
   _pppClient->putEphemeris(&eph);
@@ -258,4 +274,7 @@
 ////////////////////////////////////////////////////////////////////////////
 void t_pppRun::slotNewGlonassEph(t_ephGlo eph) {
+  if (!useEph(eph)) {
+    return;
+  }
   QMutexLocker locker(&_mutex);
   _pppClient->putEphemeris(&eph);
@@ -265,4 +284,7 @@
 ////////////////////////////////////////////////////////////////////////////
 void t_pppRun::slotNewGalileoEph(t_ephGal eph) {
+  if (!useEph(eph)) {
+    return;
+  }
   QMutexLocker locker(&_mutex);
   _pppClient->putEphemeris(&eph);
@@ -272,4 +294,7 @@
 ////////////////////////////////////////////////////////////////////////////
 void t_pppRun::slotNewBDSEph(t_ephBDS eph) {
+  if (!useEph(eph)) {
+    return;
+  }
   QMutexLocker locker(&_mutex);
   _pppClient->putEphemeris(&eph);
Index: /trunk/BNC/src/pppRun.h
===================================================================
--- /trunk/BNC/src/pppRun.h	(revision 11135)
+++ /trunk/BNC/src/pppRun.h	(revision 11136)
@@ -65,6 +65,9 @@
   };
 
+  bool useEph(const t_eph& eph) const;
+
   QMutex                 _mutex;
   const t_pppOptions*    _opt;
+  QStringList            _ephMounts;  // empty: ephemerides of all streams
   t_pppClient*           _pppClient;
   std::deque<t_epoData*> _epoData;
Index: /trunk/BNC/src/pppWidgets.cpp
===================================================================
--- /trunk/BNC/src/pppWidgets.cpp	(revision 11135)
+++ /trunk/BNC/src/pppWidgets.cpp	(revision 11136)
@@ -67,4 +67,5 @@
   _biasMount    = new QLineEdit();     _biasMount   ->setObjectName("PPP/biasMount");    _widgets << _biasMount;
   _ionoMount    = new QLineEdit();     _ionoMount   ->setObjectName("PPP/ionoMount");    _widgets << _ionoMount;
+  _ephMount     = new QLineEdit();     _ephMount    ->setObjectName("PPP/ephMount");     _widgets << _ephMount;
   _corrFile     = new qtFileChooser(); _corrFile    ->setObjectName("PPP/corrFile");     _widgets << _corrFile;
   _biasFile     = new qtFileChooser(); _biasFile    ->setObjectName("PPP/biasFile");     _widgets << _biasFile;
@@ -395,4 +396,5 @@
     _biasMount    ->setEnabled(false);
     _ionoMount    ->setEnabled(false);
+    _ephMount     ->setEnabled(false);
     _audioResponse->setEnabled(false);
   }
Index: /trunk/BNC/src/pppWidgets.h
===================================================================
--- /trunk/BNC/src/pppWidgets.h	(revision 11135)
+++ /trunk/BNC/src/pppWidgets.h	(revision 11136)
@@ -51,4 +51,5 @@
   QLineEdit*     _biasMount;
   QLineEdit*     _ionoMount;
+  QLineEdit*     _ephMount;
   qtFileChooser* _corrFile;
   qtFileChooser* _biasFile;
Index: /trunk/BNC/tests/README.md
===================================================================
--- /trunk/BNC/tests/README.md	(revision 11135)
+++ /trunk/BNC/tests/README.md	(revision 11136)
@@ -52,4 +52,7 @@
   `replay_rinex_eph` (02), `replay_feed_engine` (07, IP port disabled) and
   `replay_save_sp3` (14, with SSRA00CNE1 instead of SSRA00BKG1).
+* `replay_rinex_eph_perstream`: 02 with 'File per stream' on `data/eph_perstream_260930_4min.raw`
+  (ephemeris messages of BCEP00BKG0, SSRA00EUH0, FFMJ00DEU0, WTZR00DEU0 cut from the
+  merged capture): one RINEX 4 navigation file per stream.
 * `replay_save_sp3_has`: 14 with Galileo HAS (SSRA00EUH0) only; its epochs are
   off the SP3/CLK sampling grid and are written at the preceding grid epoch.
