Index: /trunk/BNC/src/bncantex.cpp
===================================================================
--- /trunk/BNC/src/bncantex.cpp	(revision 11065)
+++ /trunk/BNC/src/bncantex.cpp	(revision 11066)
@@ -68,4 +68,12 @@
   }
   _maps.clear();
+  QMapIterator<QString, QVector<t_antMap*> > itSat(_satMaps);
+  while (itSat.hasNext()) {
+    itSat.next();
+    for (int ii = 0; ii < itSat.value().size(); ii++) {
+      delete itSat.value()[ii];
+    }
+  }
+  _satMaps.clear();
 }
 
@@ -141,4 +149,5 @@
 t_irc bncAntex::readFile(const QString& fileName) {
 
+  _fileName = fileName;
   QFile inFile(fileName);
   inFile.open(QIODevice::ReadOnly | QIODevice::Text);
@@ -176,8 +185,13 @@
           _satBlocks[newAntMap->antName].append(satBlock);
         }
-        if (_maps.contains(newAntMap->antName)) {
-          delete _maps[newAntMap->antName];
-        }
-        _maps[newAntMap->antName] = newAntMap;
+        if (newAntMap->isSat) {
+          _satMaps[newAntMap->antName].append(newAntMap);
+        }
+        else {
+          if (_maps.contains(newAntMap->antName)) {
+            delete _maps[newAntMap->antName];
+          }
+          _maps[newAntMap->antName] = newAntMap;
+        }
         newAntMap = 0;
       }
@@ -199,4 +213,5 @@
             line.indexOf("NavIC") == 0 ){
           newAntMap->antName = line.mid(20,3);
+          newAntMap->isSat   = true;
           if (line.indexOf("BLOCK I") == 0) {
             // Extract GPS block type: "BLOCK IIF   " → "IIF"
@@ -789,10 +804,11 @@
   }
 
-  QMap<QString, t_antMap*>::const_iterator it = _maps.find(prn.mid(0,3));
-  if (it != _maps.end()) {
-    t_antMap* map = it.value();
+  bncTime epoch;
+  epoch.setmjd(Mjd);
+  const t_antMap* map = satMap(prn, epoch);
+  if (map) {
     if (map->frqMap.find(frqType) != map->frqMap.end()) {
 
-      double* neu = map->frqMap[frqType]->neu;
+      const double* neu = map->frqMap[frqType]->neu;
 
       // Unit Vectors sz, sy, sx
@@ -879,12 +895,12 @@
 ////////////////////////////////////////////////////////////////////////////
 double bncAntex::satCorr(const QString& prn, t_frequency::type frqType,
-                         double elTx, double azTx, bool& found) const {
-
-  if (_maps.find(prn.mid(0,3)) == _maps.end()) {
+                         double elTx, double azTx, bool& found,
+                         const bncTime& epoch) const {
+
+  const t_antMap* map = satMap(prn, epoch);
+  if (!map) {
     found = false;
     return 0.0;
   };
-
-  t_antMap* map = _maps[prn.mid(0,3)];
 
   if (map->frqMap.find(frqType) == map->frqMap.end()) {
@@ -964,4 +980,66 @@
 }
 
+// Satellite antenna entry valid at the given epoch (the last entry of the
+// PRN if the epoch is not valid), 0 if there is none
+////////////////////////////////////////////////////////////////////////////
+const bncAntex::t_antMap* bncAntex::satMap(const QString& prn, const bncTime& epoch) const {
+  QMap<QString, QVector<t_antMap*> >::const_iterator it = _satMaps.find(prn.mid(0,3));
+  if (it == _satMaps.end() || it.value().isEmpty()) {
+    return 0;
+  }
+  const QVector<t_antMap*>& maps = it.value();
+  if (!epoch.valid()) {
+    return maps.last();
+  }
+  for (int ii = maps.size() - 1; ii >= 0; ii--) {
+    const t_antMap* map = maps[ii];
+    if ((!map->validFrom.valid() || !(epoch < map->validFrom)) &&
+        (!map->validTo.valid()   || epoch < map->validTo)) {
+      return map;
+    }
+  }
+  return 0;
+}
+
+// File name, number of satellite entries and the latest satellite entry,
+// which identifies the version of the file
+////////////////////////////////////////////////////////////////////////////
+QString bncAntex::info() const {
+  int     numSat = 0;
+  bncTime latest;
+  QString latestPrn;
+  QMapIterator<QString, QVector<t_antMap*> > it(_satMaps);
+  while (it.hasNext()) {
+    it.next();
+    for (int ii = 0; ii < it.value().size(); ii++) {
+      const t_antMap* map = it.value()[ii];
+      ++numSat;
+      if (map->validFrom.valid() && (!latest.valid() || latest < map->validFrom)) {
+        latest    = map->validFrom;
+        latestPrn = it.key();
+      }
+    }
+  }
+  QString str = QString("ANTEX file %1: %2 receiver and %3 satellite antenna entries")
+                .arg(_fileName).arg(_maps.size()).arg(numSat);
+  if (latest.valid()) {
+    str += QString(", latest satellite entry %1 valid from %2").arg(latestPrn)
+           .arg(QString::fromStdString(latest.datestr()));
+  }
+  return str;
+}
+
+// True if a missing satellite antenna entry has to be reported (at most once
+// per hour and PRN)
+////////////////////////////////////////////////////////////////////////////
+bool bncAntex::warnNoSatEntry(const QString& prn, const bncTime& epoch) const {
+  bncTime& warned = _noSatEntryWarned[prn.mid(0,3)];
+  if (!warned.valid() || !epoch.valid() || epoch - warned >= 3600.0) {
+    warned = epoch;
+    return true;
+  }
+  return false;
+}
+
 // Satellite block type valid at the given epoch
 ////////////////////////////////////////////////////////////////////////////
Index: /trunk/BNC/src/bncantex.h
===================================================================
--- /trunk/BNC/src/bncantex.h	(revision 11065)
+++ /trunk/BNC/src/bncantex.h	(revision 11066)
@@ -43,5 +43,6 @@
   QString snxCodeSinexString(const std::string& antName);
   double  satCorr(const QString& prn, t_frequency::type frqType,
-                  double eleSat, double azSat, bool& found) const;
+                  double eleSat, double azSat, bool& found,
+                  const bncTime& epoch = bncTime()) const;
   double  rcvCorr(const std::string& antName, t_frequency::type frqType,
                   double eleSat, double azSat, bool& found) const;
@@ -50,4 +51,7 @@
   // empty if unknown
   QString satBlockType(const QString& prn, const bncTime& epoch) const;
+  QString info() const;
+  bool    hasSatEntry(const QString& prn, const bncTime& epoch) const {return satMap(prn, epoch) != 0;}
+  bool    warnNoSatEntry(const QString& prn, const bncTime& epoch) const;
 
   // Attitude model selection for satCoMcorrection().
@@ -178,4 +182,5 @@
       dZen    = 0.0;
       snxCode = "";
+      isSat   = false;
     }
     ~t_antMap() {
@@ -192,4 +197,5 @@
     double                             dZen;
     QString                            snxCode;
+    bool                               isSat;
     QMap<t_frequency::type, t_frqMap*> frqMap;
     bncTime                            validFrom;
@@ -197,8 +203,14 @@
   };
 
-  QMap<QString, t_antMap*> _maps;
-
-  // Block type history per satellite PRN. _maps keeps only the last ANTEX
-  // entry per PRN, which is wrong for epochs before a PRN was reassigned.
+  const t_antMap* satMap(const QString& prn, const bncTime& epoch) const;
+
+  QString                  _fileName;
+  QMap<QString, t_antMap*> _maps;     // receiver antennas
+  // All entries per satellite PRN (a PRN is reassigned to new satellites),
+  // the entry valid at the epoch is selected via VALID FROM / VALID UNTIL
+  QMap<QString, QVector<t_antMap*> > _satMaps;
+  mutable QMap<QString, bncTime>     _noSatEntryWarned; // last warning per PRN
+
+  // Block type history per satellite PRN
   struct t_satBlock {
     bncTime validFrom;
Index: /trunk/BNC/src/bnccore.cpp
===================================================================
--- /trunk/BNC/src/bnccore.cpp	(revision 11065)
+++ /trunk/BNC/src/bnccore.cpp	(revision 11066)
@@ -45,4 +45,5 @@
 
 #include "bnccore.h"
+#include "ssrQc.h"
 #include "bncutils.h"
 #include "bncrinex.h"
@@ -106,4 +107,5 @@
 
   _pppMain = new BNC_PPP::t_pppMain();
+  _ssrQc   = 0;
   qRegisterMetaType< QVector<double> >      ("QVector<double>");
   qRegisterMetaType<bncTime>                ("bncTime");
@@ -144,4 +146,5 @@
 
   bncComb::destruct();
+  delete _ssrQc;
 
   delete _pppMain;
@@ -830,4 +833,31 @@
 }
 
+// SSR QC of the decoded correction streams (optional)
+////////////////////////////////////////////////////////////////////////////
+void t_bncCore::initSsrQc() {
+  delete _ssrQc; _ssrQc = 0;
+  bncSettings settings;
+  QString fileName = settings.value("ssrQcFile").toString();
+  if (fileName.isEmpty()) {
+    return;
+  }
+  expandEnvVar(fileName);
+  QStringList hlp = settings.value("ssrQcIntr").toString().split(' ', Qt::SkipEmptyParts);
+  double interval = 3600.0;
+  if (hlp.size() == 2) {
+    double fac = (hlp[1] == "min") ? 60.0 : (hlp[1] == "hour") ? 3600.0 : (hlp[1] == "day") ? 86400.0 : 0.0;
+    if (hlp[0].toDouble() * fac > 0.0) {
+      interval = hlp[0].toDouble() * fac;
+    }
+  }
+  _ssrQc = new t_ssrQc(fileName, interval);
+}
+
+// Writes the final SSR QC report
+////////////////////////////////////////////////////////////////////////////
+void t_bncCore::stopSsrQc() {
+  delete _ssrQc; _ssrQc = 0;
+}
+
 //
 ////////////////////////////////////////////////////////////////////////////
Index: /trunk/BNC/src/bnccore.h
===================================================================
--- /trunk/BNC/src/bnccore.h	(revision 11065)
+++ /trunk/BNC/src/bnccore.h	(revision 11066)
@@ -32,4 +32,5 @@
 
 class bncComb;
+class t_ssrQc;
 class bncTableItem;
 namespace BNC_PPP {
@@ -73,4 +74,6 @@
   void             initCombination();
   void             stopCombination();
+  void             initSsrQc();
+  void             stopSsrQc();
   const QString&   pgmName() {return _pgmName;}
   const QString&   userName() {return _userName;}
@@ -172,4 +175,5 @@
   mutable QMutex         _mutexDateAndTimeGPS;
   BNC_PPP::t_pppMain*    _pppMain;
+  t_ssrQc*               _ssrQc;
   bncEphUser             _ephUser;
 };
Index: /trunk/BNC/src/bncgetthread.cpp
===================================================================
--- /trunk/BNC/src/bncgetthread.cpp	(revision 11065)
+++ /trunk/BNC/src/bncgetthread.cpp	(revision 11066)
@@ -491,4 +491,5 @@
           BNC_CORE->stopPPP();
           BNC_CORE->stopCombination();
+          BNC_CORE->stopSsrQc();
           sleep(2);
           ::exit(5);
Index: /trunk/BNC/src/bnchelp.html
===================================================================
--- /trunk/BNC/src/bnchelp.html	(revision 11065)
+++ /trunk/BNC/src/bnchelp.html	(revision 11066)
@@ -147,4 +147,5 @@
     &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.8.2 <a href="#corrint">Interval</a><br>
     &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.8.3 <a href="#corrport">Port</a><br>
+    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.8.4 <a href="#ssrqc">QC Logfile, QC Interval</a><br>
     &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.8.4 <a href="#corrwait">Wait for Full Corr Epoch</a><br>
     &nbsp; &nbsp; &nbsp; 2.9 <a href="#syncout"><b>Feed Engine</b></a><br>
@@ -4997,4 +4998,26 @@
     falls back to using ANTEX-based satellite antenna corrections instead.
   </p>
+  <p>
+    <b>SSR epoch times:</b> In IGS-SSR, the SSR Epoch Time (IDF003) of all GNSS is given in GPS seconds of week. In
+    RTCM-SSR, the GLONASS epoch time (DF386) is given in GLONASS time (UTC+3h) as seconds of day, the BDS epoch time
+    (DF465) in BDT. Some encoders use other conventions for IGS-SSR. BNC recognises them by comparison with the GPS or
+    Galileo epoch of the same stream, converts the epochs and writes a warning to the logfile at most once per hour
+    per stream and system:
+  </p>
+  <ul>
+    <li>'IGS-SSR GLONASS epoch time in outdated convention (UTC seconds of day ...)': the convention of older BNC
+      versions; the SSR encoder should be updated.</li>
+    <li>'IGS-SSR GLONASS epoch time erroneously encoded (UTC seconds of week ...)': UTC instead of GPS time; the SSR
+      encoder should be corrected.</li>
+    <li>'IGS-SSR BDS epoch time in outdated convention (BDT ...)': BDT instead of GPS time; the SSR encoder should be
+      updated.</li>
+  </ul>
+  <p>
+    In addition, the orbit and clock epochs of all systems of a stream, converted to GPS time, are compared with the
+    latest GPS orbit and clock epoch of the same stream. A difference of more than 120 seconds points to another
+    erroneous encoding and is reported as 'X SSR epoch time ... differs by ... s from the GPS SSR epoch time of the
+    stream - erroneously encoded?'. Such epochs are not converted. Code and phase biases are not checked, as they may
+    be sent with the epoch of their last update.
+  </p>
 
   <p>
@@ -5032,4 +5055,67 @@
   <p><img src="IMG/Figure17.png" width=1000 /></p>
   <p>Figure 17: Example for pulling, saving and output of Broadcast Corrections using BNC</p>
+
+  <p>
+  <h4 id="ssrqc">2.8.4 QC Logfile, QC Interval - optional</h4>
+  </p>
+  <p>
+    BNC can check the quality of all Broadcast Correction streams it decodes, in real time or when reading a raw file
+    ('--file'). Specify the full path to a 'QC Logfile' to activate this function, and select the 'QC Interval' for
+    the reports (default: 1 hour). At the end of each interval and at the end of the program, a report is written per
+    stream and system. Broadcast ephemerides must be received as well, e.g. via stream 'BCEP00BKG0'.
+  </p>
+  <p>
+    A table lists per system and message type (ORBIT, CLOCK, CODE_BIAS, PHASE_BIAS):
+  </p>
+  <ul>
+    <li>the number of epochs,</li>
+    <li>the update interval as declared in the messages (SSR Update Interval), the median and the maximum of the
+      actual intervals,</li>
+    <li>the number of gaps, i.e. intervals longer than twice the larger of declared and median interval,</li>
+    <li>the number of epochs older than the previous one (out of order),</li>
+    <li>the latency, median and maximum, i.e. the time of the decoded output minus the epoch time. Note that BNC
+      passes on the corrections of an epoch when the next epoch arrives; the latency therefore includes one update
+      interval. When reading a raw file, the times of the file are used,</li>
+    <li>the number of satellites.</li>
+  </ul>
+  <p>
+    It is followed by the findings per system, only lines with findings are listed:
+  </p>
+  <ul>
+    <li>a declared update interval differing from the actual one (BNC uses it e.g. to detect outdated
+      corrections),</li>
+    <li>satellites with a healthy, current broadcast ephemeris without orbit corrections, clock corrections, code
+      biases or phase biases (the latter two only if the stream provides them for the system),</li>
+    <li>orbit and clock corrections referring to an IOD of no received broadcast ephemeris, to an unhealthy
+      broadcast ephemeris, or to a satellite without broadcast ephemeris (number of corrections in brackets),</li>
+    <li>the code bias signals provided, satellites without code biases of the reference signals (GPS C1W/C2W, GLONASS
+      C1P/C2P, Galileo C1C/C5Q, BDS C2I/C6I, QZSS C1C/C2L), and the standard deviation and maximum of the
+      ionosphere-free combination B_IF of the reference signal biases. A B_IF varying between the satellites is
+      legitimate if the clocks are estimated with other signals, but must then be consistent with the clocks
+      (see section 'Combination'),</li>
+    <li>clock jumps, i.e. clock changes between consecutive epochs (same IOD) beyond the clock rate of more than
+      0.5 m,</li>
+    <li>the largest radial and along-/cross-track orbit corrections. Their size mainly reflects the quality of the
+      broadcast ephemerides; a value differing from that of other streams for the same satellite points to a
+      problem of the stream.</li>
+  </ul>
+  <p>
+    Example:
+  </p>
+  <pre>
+Stream SSRA00GMV0
+  Sys Type        Epochs  Interval nom/med/max [s]  Gaps  Out-of-order  Latency med/max [s]  Sats
+  G   ORBIT           47         1 /   5.0 /    5.0     0             0      11.0 /   12.0     32
+  ...
+  G ORBIT: declared update interval 1 s, actual 5.0 s
+  G corrections referring to an IOD of no received broadcast ephemeris: G10(94) G22(94) G29(94)
+  G code bias signals: 1C 1P 1W 2L 2P 2S 2W 5Q
+  G ionosphere-free combination B_IF of the reference signal biases: std. dev. 0.586 m, max |B_IF| 2.058 m (32 satellites)
+  G largest orbit corrections: radial 1.06 m (G11), along/cross 2.05 m (G11)
+</pre>
+  <p>
+    Errors in the encoding of the SSR epoch times are reported by the decoder itself in the BNC logfile (see section
+    'Broadcast Corrections').
+  </p>
 
   <p>
@@ -6173,4 +6259,22 @@
     Default value for 'ANTEX file' is an empty option field, meaning that you do not want to correct observations for
     Antenna Phase Center offsets and variations.
+  </p>
+  <p>
+    A satellite PRN is reassigned to new satellites over time, therefore an ANTEX file contains several entries per
+    PRN with their validity ('VALID FROM' / 'VALID UNTIL'). BNC uses the entry valid at the epoch processed, so that
+    the same ANTEX file can be used for current and for older data. At startup, BNC logs the ANTEX file name, the
+    number of receiver and satellite antenna entries and the latest satellite entry, e.g.
+  </p>
+  <pre>
+ANTEX file Input/igs20.atx: 515 receiver and 405 satellite antenna entries, latest satellite entry R26 valid from 2026-09-26
+</pre>
+  <p>
+    The date of the latest satellite entry identifies the version of the file. Use the current IGS ANTEX file and update
+    it promptly when new satellites are announced, ideally at the same time as the providers of the corrections, as
+    their orbits and clocks refer to the antenna offsets of their own ANTEX file.
+    If there is no satellite antenna entry valid at the epoch for a satellite, e.g. a new satellite in an outdated
+    ANTEX file, its observations are not corrected for the satellite antenna offset and the message
+    'ANTEX: no satellite antenna entry valid at ... - ANTEX file outdated?' is written to the PPP logfile, at most once
+    per hour and satellite.
   </p>
   <p>
@@ -7916,4 +8020,10 @@
     Hence, the ionosphere-free linear combination of code biases for the IGS reference signals is determined
     from the supplied code biases and subtracted from the clocks before combination.
+    This requires the code biases of both reference signals of a system. If an AC provides none or only one of them
+    for a satellite, its clock cannot be referred to the reference signals. It is still combined, but, as long as
+    other ACs provide referred clocks for this satellite, it is excluded from the clock datum like the clocks of an AC
+    with inconsistent biases (see below): its satellite offset absorbs the difference, and the combined clock is
+    defined by the referred clocks only. The message '... provides no code biases for the ... reference signal(s)
+    ...' naming the missing signal(s) is written to the logfile at most once per hour per AC and system.
     The combined satellite clocks are consistent to IGS clocks, which means ionosphere-free clocks based on the defined
     reference signals
@@ -7931,7 +8041,9 @@
   </p>
   <p>
-    In the combination (method 'Filter') such errors are absorbed by the satellite-specific clock offsets estimated
-    for each AC, which consequently follow B_IF of that AC from satellite to satellite. BNC uses this to check the
-    consistency, separately for each AC and system:
+    In the combination (method 'Filter') such errors show up in the satellite-specific clock offsets estimated for
+    each AC, which consequently follow B_IF of that AC from satellite to satellite. As the offsets of all ACs of a
+    satellite are constrained to sum up to zero, they absorb only part of the error: with N ACs, the offset of the
+    inconsistent AC takes up about (N-1)/N of it, while about 1/N goes into the combined clock. BNC uses the offsets
+    to check the consistency, separately for each AC and system:
   </p>
   <ul>
@@ -7952,12 +8064,37 @@
   <pre>
 bncComb: BKG E code biases (C1C/C5Q) seem inconsistent with its clocks: satellite offsets follow the bias
-combination B_IF (27 satellites, B_IF spread 0.084 m, slope 0.60, correlation 0.88)
+combination B_IF (27 satellites, B_IF spread 0.084 m, slope 0.60, correlation 0.88), AC excluded from the clock datum
 </pre>
   <p>
-    The AC is still used in the combination, its offsets absorb most of the error. Nevertheless, the code biases
-    sent out by this AC should be corrected by its provider: either biases estimated together with the clocks
-    should be used, or the external biases have to be aligned to the clocks per satellite (b' = b - B_IF of the
-    reference signals, SSR sign convention). The check is not applied with the 'Single-Epoch' method.
-  </p>
+    Such an AC is therefore excluded from the clock datum of the respective system: its satellite offsets are no
+    longer part of the zero-sum conditions (their own sum is constrained to zero instead), and the satellite offsets
+    of all ACs of this system are re-initialized. The combined clocks are then defined by the consistent ACs only,
+    while the offsets of the excluded AC take up its error completely (a regression slope of about 1 at the
+    following checks). The AC is still used in the combination: it contributes its epoch-wise clock variations and
+    is counted for the minimum of 2 ACs per satellite. A satellite observed by excluded ACs only is combined with
+    the zero-sum condition of all its ACs as before, and if no consistent AC provides corrections for a system, the
+    exclusion is not applied. The checks continue: as soon as a check finds no inconsistency any more (or B_IF no
+    longer varies noticeably between the satellites, e.g. after the provider has aligned its biases), the AC is
+    used for the clock datum again, which is reported in both logfiles. A smaller weight factor of the AC would not
+    help instead: the weights act on the epoch-wise clock variations, while the satellite-specific constant part is
+    fixed by the zero-sum conditions, independent of the weights.
+  </p>
+  <p>
+    Nevertheless, the code biases sent out by this AC should be corrected by its provider: either biases estimated
+    together with the clocks should be used, or the external biases have to be aligned to the clocks per satellite
+    (b' = b - B_IF of the reference signals, SSR sign convention). The check is not applied with the 'Single-Epoch' method.
+  </p>
+  <p>
+    <b>Persistent outliers:</b>
+    A clock correction whose residual exceeds 'Maximal Residuum' is rejected as outlier. If an AC's clock for a single
+    satellite differs persistently from those of the other ACs, its satellite offset cannot absorb the difference, since
+    the offsets of all ACs of a satellite sum up to zero, and the correction is rejected again in every epoch. This
+    protects the combined clock, but it is worth to be reported to the AC. Therefore, once per hour and system, BNC
+    reports all AC satellites rejected in at least half of their epochs of the last hour (minimum 10 epochs), in the
+    combination logfile and in the BNC logfile, e.g.
+  </p>
+  <pre>
+bncComb: SHA G26 rejected as outlier in 99% of 720 epochs in the last hour (median residual 1.08 m)
+</pre>
   <p>
     This convention allows the ionosphere-free linear combination of the two OSBs of the reference signals to be set to
@@ -9267,4 +9404,22 @@
     If you do not specify an ANTEX file, the SP3 file will contain orbit information which is referred to Antenna Phase
     Center (APC) instead of CoM.
+  </p>
+  <p>
+    A satellite PRN is reassigned to new satellites over time, therefore an ANTEX file contains several entries per
+    PRN with their validity ('VALID FROM' / 'VALID UNTIL'). BNC uses the entry valid at the epoch processed, so that
+    the same ANTEX file can be used for current and for older data. At startup, BNC logs the ANTEX file name, the
+    number of receiver and satellite antenna entries and the latest satellite entry, e.g.
+  </p>
+  <pre>
+ANTEX file Input/igs20.atx: 515 receiver and 405 satellite antenna entries, latest satellite entry R26 valid from 2026-09-26
+</pre>
+  <p>
+    The date of the latest satellite entry identifies the version of the file. Use the current IGS ANTEX file and update
+    it promptly when new satellites are announced, ideally at the same time as the providers of the corrections, as
+    their orbits and clocks refer to the antenna offsets of their own ANTEX file.
+    If there is no satellite antenna entry valid at the epoch for a satellite, its orbit cannot be referred to CoM;
+    the satellite is then not part of the combined product, and the message
+    'bncComb: no satellite antenna entry valid at ... - ANTEX file outdated? Satellite not combined' is written to the
+    logfile, at most once per hour and satellite.
   </p>
   <p>
Index: /trunk/BNC/src/bncmain.cpp
===================================================================
--- /trunk/BNC/src/bncmain.cpp	(revision 11065)
+++ /trunk/BNC/src/bncmain.cpp	(revision 11066)
@@ -68,4 +68,5 @@
     BNC_CORE->stopPPP();
     BNC_CORE->stopCombination();
+    BNC_CORE->stopSsrQc();
 #ifndef WIN32
     sleep(2);
@@ -81,4 +82,5 @@
     BNC_CORE->stopPPP();
     BNC_CORE->stopCombination();
+    BNC_CORE->stopSsrQc();
 #ifndef WIN32
     sleep(2);
@@ -208,4 +210,6 @@
         "   corrIntr {File interval [character string: 1 min|2 min|5 min|10 min|15 min|30 min|1 hour|1 day]}\n"
         "   corrPort {Output port [integer number]}\n"
+        "   ssrQcFile {SSR QC logfile, full path [character string]}\n"
+        "   ssrQcIntr {SSR QC report interval [character string: 5 min|15 min|30 min|1 hour|1 day]}\n"
         "\n"
         "Feed Engine Panel keys:\n"
@@ -548,4 +552,5 @@
         BNC_CORE->setPortCorr(settings.value("corrPort").toInt());
         BNC_CORE->initCombination();
+        BNC_CORE->initSsrQc();
 
         BNC_CORE->connect(caster, SIGNAL(getThreadsFinished()), app->instance(), SLOT(quit()));
@@ -592,4 +597,5 @@
         BNC_CORE->stopPPP();
         BNC_CORE->stopCombination();
+        BNC_CORE->stopSsrQc();
 #ifndef WIN32
         sleep(2);
Index: /trunk/BNC/src/bncsettings.cpp
===================================================================
--- /trunk/BNC/src/bncsettings.cpp	(revision 11065)
+++ /trunk/BNC/src/bncsettings.cpp	(revision 11066)
@@ -138,4 +138,6 @@
         setValue_p("corrIntr", "1 day");
         setValue_p("corrPort", "");
+        setValue_p("ssrQcFile", "");
+        setValue_p("ssrQcIntr", "1 hour");
         // Feed Engine
         setValue_p("outPort", "");
Index: /trunk/BNC/src/bncwindow.cpp
===================================================================
--- /trunk/BNC/src/bncwindow.cpp	(revision 11065)
+++ /trunk/BNC/src/bncwindow.cpp	(revision 11066)
@@ -298,4 +298,17 @@
   }
   _corrPortLineEdit = new QLineEdit(settings.value("corrPort").toString());
+  _ssrQcFileLineEdit = new QLineEdit(settings.value("ssrQcFile").toString());
+  _ssrQcIntrComboBox = new QComboBox();
+  _ssrQcIntrComboBox->setEditable(false);
+  _ssrQcIntrComboBox->addItems(QString("5 min,15 min,30 min,1 hour,1 day").split(","));
+  bi = _ssrQcIntrComboBox->findText(settings.value("ssrQcIntr").toString());
+  if (bi != -1) {
+    _ssrQcIntrComboBox->setCurrentIndex(bi);
+  }
+  else {
+    _ssrQcIntrComboBox->setCurrentIndex(_ssrQcIntrComboBox->findText("1 hour"));
+  }
+  connect(_ssrQcFileLineEdit, SIGNAL(textChanged(const QString&)),
+          this, SLOT(slotBncTextChanged()));
 
   connect(_corrPathLineEdit, SIGNAL(textChanged(const QString&)),
@@ -894,4 +907,5 @@
   _corrIntrComboBox->setMaximumWidth(9 * ww);
   _corrPortLineEdit->setMaximumWidth(9 * ww);
+  _ssrQcIntrComboBox->setMaximumWidth(9 * ww);
 
   cLayout->addWidget(new QLabel("Saving Broadcast Ephemeris correction files and correction output through IP port.<br>"), 0, 0, 1, 70);
@@ -902,5 +916,9 @@
   cLayout->addWidget(new QLabel("Port"), 3, 0);
   cLayout->addWidget(_corrPortLineEdit, 3, 1);
-  cLayout->addWidget(new QLabel(""), 4, 1);
+  cLayout->addWidget(new QLabel("QC Logfile"), 4, 0);
+  cLayout->addWidget(_ssrQcFileLineEdit, 4, 1, 1, 30);
+  cLayout->addWidget(new QLabel("QC Interval"), 5, 0);
+  cLayout->addWidget(_ssrQcIntrComboBox, 5, 1);
+  cLayout->addWidget(new QLabel(""), 6, 1);
   cLayout->setRowStretch(7, 999);
   cgroup->setLayout(cLayout);
@@ -1570,4 +1588,6 @@
   _corrPathLineEdit->setWhatsThis(tr("<p>Specify a directory for saving Broadcast Ephemeris Correction files.</p><p>If the specified directory does not exist, BNC will not create the files. <i>[key: corrPath]</i></p>"));
   _corrIntrComboBox->setWhatsThis(tr("<p>Select the length of Broadcast Ephemeris Correction files. <i>[key: corrIntr]</i></p>"));
+  _ssrQcFileLineEdit->setWhatsThis(tr("<p>Specify the full path to a logfile for the quality control of all decoded Broadcast Correction streams: epochs, update intervals, gaps, latency, completeness, IODs, code biases of the reference signals, clock jumps and orbit correction size.</p><p>Default is an empty option field, meaning that no SSR QC is done. <i>[key: ssrQcFile]</i></p>"));
+  _ssrQcIntrComboBox->setWhatsThis(tr("<p>Select the interval of the SSR QC reports. <i>[key: ssrQcIntr]</i></p>"));
   _corrPortLineEdit->setWhatsThis(tr("<p>BNC can produce Broadcast Ephemeris Corrections on your local host through an IP port.</p><p>Specify a port number here to activate this function. <i>[key: corrPort]</i></p>"));
 
@@ -1843,4 +1863,6 @@
   delete _corrPathLineEdit;
   delete _corrIntrComboBox;
+  delete _ssrQcFileLineEdit;
+  delete _ssrQcIntrComboBox;
   delete _corrPortLineEdit;
   delete _outPortLineEdit;
@@ -2369,4 +2391,6 @@
   settings.setValue("corrPath", _corrPathLineEdit->text());
   settings.setValue("corrIntr", _corrIntrComboBox->currentText());
+  settings.setValue("ssrQcFile", _ssrQcFileLineEdit->text());
+  settings.setValue("ssrQcIntr", _ssrQcIntrComboBox->currentText());
   settings.setValue("corrPort", _corrPortLineEdit->text());
   // Feed Engine
@@ -2538,4 +2562,5 @@
   BNC_CORE->setPortCorr(_corrPortLineEdit->text().toInt());
   BNC_CORE->initCombination();
+  BNC_CORE->initSsrQc();
 
   connect(_caster, SIGNAL(getThreadsFinished()), this, SLOT(slotGetThreadsFinished()));
@@ -2607,4 +2632,5 @@
     BNC_CORE->stopPPP();
     BNC_CORE->stopCombination();
+    BNC_CORE->stopSsrQc();
     delete _caster;    _caster = 0; BNC_CORE->setCaster(0);
     delete _casterEph; _casterEph = 0;
@@ -2900,4 +2926,7 @@
     enable = !_corrPathLineEdit->text().isEmpty() || !_corrPortLineEdit->text().isEmpty();
     enableWidget(enable, _corrIntrComboBox);
+  }
+  if (sender() == 0 || sender() == _ssrQcFileLineEdit) {
+    enableWidget(!_ssrQcFileLineEdit->text().isEmpty(), _ssrQcIntrComboBox);
   }
 
Index: /trunk/BNC/src/bncwindow.h
===================================================================
--- /trunk/BNC/src/bncwindow.h	(revision 11065)
+++ /trunk/BNC/src/bncwindow.h	(revision 11066)
@@ -151,4 +151,5 @@
     QLineEdit* _ephPathLineEdit;
     QLineEdit* _corrPathLineEdit;
+    QLineEdit* _ssrQcFileLineEdit;
     QLineEdit* _miscMountLineEdit;
     QLineEdit* _miscPortLineEdit;
@@ -182,4 +183,5 @@
     QComboBox* _ephIntrComboBox;
     QComboBox* _corrIntrComboBox;
+    QComboBox* _ssrQcIntrComboBox;
     QComboBox* _rnxSamplComboBox;
     QComboBox* _rnxSkelExtComboBox;
