Index: trunk/BNC/bncgetthread.cpp
===================================================================
--- trunk/BNC/bncgetthread.cpp	(revision 1556)
+++ trunk/BNC/bncgetthread.cpp	(revision 1557)
@@ -277,4 +277,6 @@
   }
 
+  _latencyChecker = new bncGetThread::latencyChecker(_staID);
+
   msleep(100); //sleep 0.1 sec
 }
@@ -292,4 +294,5 @@
   delete _rawOutFile;
   delete _serialPort;
+  delete _latencyChecker;
   emit getThreadFinished(_staID);
 }
@@ -369,5 +372,5 @@
       // --------------------------------
       scanRTCM();            
-      checkLatency();
+      _latencyChecker->check(_decoder);
 
       // Loop over all observations (observations output)
@@ -529,210 +532,300 @@
 }
 
-//
+// Constructor
 //////////////////////////////////////////////////////////////////////////////
-void bncGetThread::checkLatency() {
-////  // Notice threshold
-////  // ----------------
-////  _inspSegm = 50;
-////  if ( settings.value("obsRate").toString().isEmpty() ) { _inspSegm = 0; }
-////  if ( settings.value("obsRate").toString().indexOf("5 Hz") != -1 ) { _inspSegm = 2; }
-////  if ( settings.value("obsRate").toString().indexOf("1 Hz") != -1 ) { _inspSegm = 10; }
-////  if ( settings.value("obsRate").toString().indexOf("0.5 Hz") != -1 ) { _inspSegm = 20; }
-////  if ( settings.value("obsRate").toString().indexOf("0.2 Hz") != -1 ) { _inspSegm = 40; }
-////  if ( settings.value("obsRate").toString().indexOf("0.1 Hz") != -1 ) { _inspSegm = 50; }
-////  _adviseFail = settings.value("adviseFail").toInt();
-////  _adviseReco = settings.value("adviseReco").toInt();
-////  _makePause = false;
-////  if ( Qt::CheckState(settings.value("makePause").toInt()) == Qt::Checked) {_makePause = true; }
-////  _adviseScript = settings.value("adviseScript").toString();
-////  expandEnvVar(_adviseScript);
-////
-////  // Latency interval/average
-////  // ------------------------
-////  _perfIntr = 86400;
-////  if ( settings.value("perfIntr").toString().isEmpty() ) { _perfIntr = 0; }
-////  if ( settings.value("perfIntr").toString().indexOf("2 sec") != -1 ) { _perfIntr = 2; }
-////  if ( settings.value("perfIntr").toString().indexOf("10 sec") != -1 ) { _perfIntr = 10; }
-////  if ( settings.value("perfIntr").toString().indexOf("1 min") != -1 ) { _perfIntr = 60; }
-////  if ( settings.value("perfIntr").toString().indexOf("5 min") != -1 ) { _perfIntr = 300; }
-////  if ( settings.value("perfIntr").toString().indexOf("15 min") != -1 ) { _perfIntr = 900; }
-////  if ( settings.value("perfIntr").toString().indexOf("1 hour") != -1 ) { _perfIntr = 3600; }
-////  if ( settings.value("perfIntr").toString().indexOf("6 hours") != -1 ) { _perfIntr = 21600; }
-////  if ( settings.value("perfIntr").toString().indexOf("1 day") != -1 ) { _perfIntr = 86400; }
-////
-////  // RTCM message types
-////  // ------------------
-////  _checkMountPoint = settings.value("miscMount").toString();
-////
-////
-////  const double maxDt = 600.0;  // Check observation epoch
-////  bool wrongEpoch = false;
-////  bool decode = true;
-////  int numSucc = 0;
-////  int secSucc = 0;
-////  int secFail = 0;
-////  int initPause = 30;  // Initial pause for corrupted streams
-////  int currPause = 0;
-////  bool begCorrupt = false;
-////  bool endCorrupt = false;
-////  bool followSec = false;
-////  int oldSecGPS= 0;
-////  int newSecGPS = 0;
-////  int numGaps = 0;
-////  int diffSecGPS = 0;
-////  int numLat = 0;
-////  double sumLat = 0.;
-////  double sumLatQ = 0.;
-////  double meanDiff = 0.;
-////  double minLat = maxDt;
-////  double maxLat = -maxDt;
-////  double curLat = 0.;
-////
-////
-////  _decodeTime = QDateTime::currentDateTime();
-////  _decodeSucc = QDateTime::currentDateTime();
-////
-////          // Check - once per inspect segment
-////          // --------------------------------
-////          if (!decode) {
-////            _decodeTime = QDateTime::currentDateTime();
-////            if (numSucc>0) {
-////              secSucc += _inspSegm;
-////              _decodeSucc = QDateTime::currentDateTime();
-////              if (secSucc > _adviseReco * 60) {
-////                secSucc = _adviseReco * 60 + 1;
-////              }
-////              numSucc = 0;
-////              currPause = initPause;
-////              _decodePause.setDate(QDate());
-////              _decodePause.setTime(QTime());
-////            }
-////            else {
-////              secFail += _inspSegm;
-////              secSucc = 0;
-////              if (secFail > _adviseFail * 60) { 
-////                secFail = _adviseFail * 60 + 1;
-////              }
-////              if (!_decodePause.isValid() || !_makePause) {
-////                _decodePause = QDateTime::currentDateTime();
-////              }
-////              else {
-////                _decodePause.setDate(QDate());
-////                _decodePause.setTime(QTime());
-////                secFail = secFail + currPause - _inspSegm;
-////                currPause = currPause * 2;
-////                if (currPause > 960) {
-////                currPause = 960;
-////                }
-////              }
-////            }
-////      
-////            // End corrupt threshold
-////            // ---------------------
-////            if ( begCorrupt && !endCorrupt && secSucc > _adviseReco * 60 ) {
-////              _endDateCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
-////              _endTimeCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
-////              emit(newMessage((_staID + ": Recovery threshold exceeded, corruption ended " 
-////                              + _endDateCor + " " + _endTimeCor).toAscii(), true));
-////              callScript(("End_Corrupted " + _endDateCor + " " + _endTimeCor + " Begin was " + _begDateCor + " " + _begTimeCor).toAscii());
-////              endCorrupt = true;
-////              begCorrupt = false;
-////              secFail = 0;
-////            } 
-////            else {
-////      
-////              // Begin corrupt threshold
-////              // -----------------------
-////              if ( !begCorrupt && secFail > _adviseFail * 60 ) {
-////                _begDateCor = _decodeSucc.toUTC().date().toString("yy-MM-dd");
-////                _begTimeCor = _decodeSucc.toUTC().time().toString("hh:mm:ss");
-////                emit(newMessage((_staID + ": Failure threshold exceeded, corrupted since " 
-////                                + _begDateCor + " " + _begTimeCor).toAscii(), true));
-////                callScript(("Begin_Corrupted " + _begDateCor + " " + _begTimeCor).toAscii());
-////                begCorrupt = true;
-////                endCorrupt = false;
-////                secSucc = 0;
-////                numSucc = 0;
-////              }
-////            }
-////            decode = true;
-////          }
-////        }
-////      }
-////      
-////      // End outage threshold
-////      // --------------------
-////      if ( _decodeStart.isValid() && _decodeStart.secsTo(QDateTime::currentDateTime()) > _adviseReco * 60 ) {
-////        _decodeStart.setDate(QDate());
-////        _decodeStart.setTime(QTime());
-////        if (_inspSegm>0) {
-////          _endDateOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
-////          _endTimeOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
-////          emit(newMessage((_staID + ": Recovery threshold exceeded, outage ended " 
-////                          + _endDateOut + " " + _endTimeOut).toAscii(), true));
-////          callScript(("End_Outage " + _endDateOut + " " + _endTimeOut + " Begin was " + _begDateOut + " " + _begTimeOut).toAscii());
-////        }
-////      }
-////      
-////          else {
-////            wrongEpoch = false;
-////          
-////            // Latency and completeness
-////            // ------------------------
-////            if (_perfIntr>0) {
-////              if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
-////                newSecGPS = static_cast<int>(obs->_o.GPSWeeks);
-////                if (newSecGPS != oldSecGPS) {
-////                  if (newSecGPS % _perfIntr < oldSecGPS % _perfIntr) {
-////                    if (numLat>0) {
-////                      if (meanDiff>0.) {
-////                        emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs, %7 gaps")
-////                          .arg(_staID.data())
-////                          .arg(int(sumLat/numLat*100)/100.)
-////                          .arg(int(minLat*100)/100.)
-////                          .arg(int(maxLat*100)/100.)
-////                          .arg(int((sqrt((sumLatQ - sumLat * sumLat / numLat)/numLat))*100)/100.)
-////                          .arg(numLat)
-////                          .arg(numGaps)
-////                          .toAscii(), true) );
-////                      } else {
-////                        emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs")
-////                          .arg(_staID.data())
-////                          .arg(int(sumLat/numLat*100)/100.)
-////                          .arg(int(minLat*100)/100.)
-////                          .arg(int(maxLat*100)/100.)
-////                          .arg(int((sqrt((sumLatQ - sumLat * sumLat / numLat)/numLat))*100)/100.)
-////                          .arg(numLat)
-////                          .toAscii(), true) );
-////                      }
-////                    }
-////                    meanDiff = diffSecGPS/numLat;
-////                    diffSecGPS = 0;
-////                    numGaps = 0;
-////                    sumLat = 0.;
-////                    sumLatQ = 0.;
-////                    numLat = 0;
-////                    minLat = maxDt;
-////                    maxLat = -maxDt;
-////                  }
-////                  if (followSec) {
-////                    diffSecGPS += newSecGPS - oldSecGPS;
-////                    if (meanDiff>0.) {
-////                      if (newSecGPS - oldSecGPS > 1.5 * meanDiff) {
-////                        numGaps += 1;
-////                      }
-////                    }
-////                  }
-////                  curLat = sec - obs->_o.GPSWeeks;
-////                  sumLat += curLat;
-////                  sumLatQ += curLat * curLat;
-////                  if (curLat < minLat) minLat = curLat;
-////                  if (curLat >= maxLat) maxLat = curLat;
-////                  numLat += 1;
-////                  oldSecGPS = newSecGPS;
-////                  followSec = true;
-////                }
-////              }
-////            }
-////
-}
+bncGetThread::latencyChecker::latencyChecker(QByteArray staID) {
+
+  _staID = staID;
+
+  bncApp* app = (bncApp*) qApp;
+  connect(this, SIGNAL(newMessage(QByteArray,bool)), 
+          app, SLOT(slotMessage(const QByteArray,bool)));
+
+  bncSettings settings;
+
+  // Notice threshold
+  // ----------------
+  QString obsRate = settings.value("obsRate").toString();
+  _inspSegm = 0;
+  if      ( obsRate.isEmpty() ) { 
+    _inspSegm = 0; 
+  }
+  else if ( obsRate.indexOf("5 Hz")   != -1 ) { 
+    _inspSegm = 20; 
+  }
+  else if ( obsRate.indexOf("1 Hz")   != -1 ) { 
+    _inspSegm = 10; 
+  }
+  else if ( obsRate.indexOf("0.5 Hz") != -1 ) { 
+    _inspSegm = 20; 
+  }
+  else if ( obsRate.indexOf("0.2 Hz") != -1 ) { 
+    _inspSegm = 40; 
+  }
+  else if ( obsRate.indexOf("0.1 Hz") != -1 ) { 
+    _inspSegm = 50; 
+  }
+  _adviseFail = settings.value("adviseFail").toInt();
+  _adviseReco = settings.value("adviseReco").toInt();
+  if ( Qt::CheckState(settings.value("makePause").toInt()) == Qt::Checked) {
+    _makePause = true; 
+  }
+  else {
+    _makePause = false;
+  }
+  _adviseScript = settings.value("adviseScript").toString();
+  expandEnvVar(_adviseScript);
+
+  // Latency interval/average
+  // ------------------------
+  _perfIntr = 0;
+  QString perfIntr = settings.value("perfIntr").toString();
+  if      ( perfIntr.isEmpty() ) { 
+    _perfIntr = 0; 
+  }
+  else if ( perfIntr.indexOf("2 sec")   != -1 ) { 
+    _perfIntr = 2; 
+  }
+  else if ( perfIntr.indexOf("10 sec")  != -1 ) { 
+    _perfIntr = 10; 
+  }
+  else if ( perfIntr.indexOf("1 min")   != -1 ) { 
+    _perfIntr = 60; 
+  }
+  else if ( perfIntr.indexOf("5 min")   != -1 ) { 
+    _perfIntr = 300; 
+  }
+  else if ( perfIntr.indexOf("15 min")  != -1 ) { 
+    _perfIntr = 900; 
+  }
+  else if ( perfIntr.indexOf("1 hour")  != -1 ) { 
+    _perfIntr = 3600; 
+  }
+  else if ( perfIntr.indexOf("6 hours") != -1 ) { 
+    _perfIntr = 21600; 
+  }
+  else if ( perfIntr.indexOf("1 day")   != -1 ) { 
+    _perfIntr = 86400; 
+  }
+
+  // RTCM message types
+  // ------------------
+  _checkMountPoint = settings.value("miscMount").toString();
+
+  // Initialize private members
+  // --------------------------
+  _maxDt      = 600.0;  // Check observation epoch
+  _wrongEpoch = false;
+  _decode     = true;
+  _numSucc    = 0;
+  _secSucc    = 0;
+  _secFail    = 0;
+  _initPause  = 30;  // Initial pause for corrupted streams
+  _currPause  = 0;
+  _begCorrupt = false;
+  _endCorrupt = false;
+  _followSec  = false;
+  _oldSecGPS  = 0;
+  _newSecGPS  = 0;
+  _numGaps    = 0;
+  _diffSecGPS = 0;
+  _numLat     = 0;
+  _sumLat     = 0.0;
+  _sumLatQ    = 0.0;
+  _meanDiff   = 0.0;
+  _minLat     =  _maxDt;
+  _maxLat     = -_maxDt;
+  _curLat     = 0.0;
+
+  _decodeTime = QDateTime::currentDateTime();
+  _decodeSucc = QDateTime::currentDateTime();
+}
+
+// Destructor
+//////////////////////////////////////////////////////////////////////////////
+bncGetThread::latencyChecker::~latencyChecker() {
+
+}
+
+// Perform latency checks
+//////////////////////////////////////////////////////////////////////////////
+void bncGetThread::latencyChecker::check(GPSDecoder* decoder) {
+
+  // Check - once per inspect segment
+  // --------------------------------
+  if (decoder->_obsList.size() > 0) {
+
+    _decodeTime = QDateTime::currentDateTime();
+
+    if (_numSucc > 0) {
+      _secSucc += _inspSegm;
+      _decodeSucc = QDateTime::currentDateTime();
+      if (_secSucc > _adviseReco * 60) {
+        _secSucc = _adviseReco * 60 + 1;
+      }
+      _numSucc = 0;
+      _currPause = _initPause;
+      _decodePause.setDate(QDate());
+      _decodePause.setTime(QTime());
+    }
+    else {
+      _secFail += _inspSegm;
+      _secSucc = 0;
+      if (_secFail > _adviseFail * 60) { 
+        _secFail = _adviseFail * 60 + 1;
+      }
+      if (!_decodePause.isValid() || !_makePause) {
+        _decodePause = QDateTime::currentDateTime();
+      }
+      else {
+        _decodePause.setDate(QDate());
+        _decodePause.setTime(QTime());
+        _secFail = _secFail + _currPause - _inspSegm;
+        _currPause = _currPause * 2;
+        if (_currPause > 960) {
+          _currPause = 960;
+        }
+      }
+    }
+  
+    // End corrupt threshold
+    // ---------------------
+    if ( _begCorrupt && !_endCorrupt && _secSucc > _adviseReco * 60 ) {
+      _endDateCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
+      _endTimeCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
+      emit(newMessage((_staID + ": Recovery threshold exceeded, corruption ended " 
+                      + _endDateCor + " " + _endTimeCor).toAscii(), true));
+      callScript(("End_Corrupted " + _endDateCor + " " + _endTimeCor + " Begin was " + _begDateCor + " " + _begTimeCor).toAscii());
+      _endCorrupt = true;
+      _begCorrupt = false;
+      _secFail = 0;
+    } 
+    else {
+  
+      // Begin corrupt threshold
+      // -----------------------
+      if ( !_begCorrupt && _secFail > _adviseFail * 60 ) {
+        _begDateCor = _decodeSucc.toUTC().date().toString("yy-MM-dd");
+        _begTimeCor = _decodeSucc.toUTC().time().toString("hh:mm:ss");
+        emit(newMessage((_staID + ": Failure threshold exceeded, corrupted since " 
+                        + _begDateCor + " " + _begTimeCor).toAscii(), true));
+        callScript(("Begin_Corrupted " + _begDateCor + " " + _begTimeCor).toAscii());
+        _begCorrupt = true;
+        _endCorrupt = false;
+        _secSucc = 0;
+        _numSucc = 0;
+      }
+    }
+  }
+      
+  // End outage threshold
+  // --------------------
+  if ( _decodeStart.isValid() && _decodeStart.secsTo(QDateTime::currentDateTime()) > _adviseReco * 60 ) {
+    _decodeStart.setDate(QDate());
+    _decodeStart.setTime(QTime());
+    if (_inspSegm > 0) {
+      _endDateOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
+      _endTimeOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
+      emit(newMessage((_staID + ": Recovery threshold exceeded, outage ended " 
+                      + _endDateOut + " " + _endTimeOut).toAscii(), true));
+      callScript(("End_Outage " + _endDateOut + " " + _endTimeOut + " Begin was " + _begDateOut + " " + _begTimeOut).toAscii());
+    }
+  }
+      
+  // Latency and completeness
+  // ------------------------
+  if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
+    if (_perfIntr > 0 ) {
+
+      QListIterator<p_obs> it(decoder->_obsList);
+      while (it.hasNext()) {
+        p_obs obs = it.next();
+      
+        _newSecGPS = static_cast<int>(obs->_o.GPSWeeks);
+        if (_newSecGPS != _oldSecGPS) {
+          if (_newSecGPS % _perfIntr < _oldSecGPS % _perfIntr) {
+            if (_numLat > 0) {
+              if (_meanDiff > 0.0) {
+                emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs, %7 gaps")
+                  .arg(_staID.data())
+                  .arg(int(_sumLat/_numLat*100)/100.)
+                  .arg(int(_minLat*100)/100.)
+                  .arg(int(_maxLat*100)/100.)
+                  .arg(int((sqrt((_sumLatQ - _sumLat * _sumLat / _numLat)/_numLat))*100)/100.)
+                  .arg(_numLat)
+                  .arg(_numGaps)
+                  .toAscii(), true) );
+              } else {
+                emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs")
+                  .arg(_staID.data())
+                  .arg(int(_sumLat/_numLat*100)/100.)
+                  .arg(int(_minLat*100)/100.)
+                  .arg(int(_maxLat*100)/100.)
+                  .arg(int((sqrt((_sumLatQ - _sumLat * _sumLat / _numLat)/_numLat))*100)/100.)
+                  .arg(_numLat)
+                  .toAscii(), true) );
+              }
+            }
+            _meanDiff  = _diffSecGPS / _numLat;
+            _diffSecGPS = 0;
+            _numGaps    = 0;
+            _sumLat     = 0.0;
+            _sumLatQ    = 0.0;
+            _numLat     = 0;
+            _minLat     = _maxDt;
+            _maxLat     = -_maxDt;
+          }
+          if (_followSec) {
+            _diffSecGPS += _newSecGPS - _oldSecGPS;
+            if (_meanDiff>0.) {
+              if (_newSecGPS - _oldSecGPS > 1.5 * _meanDiff) {
+                _numGaps += 1;
+              }
+            }
+          }
+
+          // Compute the observations latency
+          // --------------------------------
+          int week;
+          double sec;
+          currentGPSWeeks(week, sec);
+          const double secPerWeek = 7.0 * 24.0 * 3600.0;
+          if (week < obs->_o.GPSWeek) {
+            week += 1;
+            sec  -= secPerWeek;
+          }
+          if (week > obs->_o.GPSWeek) {
+            week -= 1;
+            sec  += secPerWeek;
+          }
+
+          _curLat   = sec - obs->_o.GPSWeeks;
+          _sumLat  += _curLat;
+          _sumLatQ += _curLat * _curLat;
+          if (_curLat < _minLat) {
+            _minLat = _curLat;
+	  }
+          if (_curLat >= _maxLat) {
+            _maxLat = _curLat;
+	  }
+          _numLat += 1;
+          _oldSecGPS = _newSecGPS;
+          _followSec = true;
+        }
+      }
+    }
+  }
+}
+
+// Call advisory notice script    
+////////////////////////////////////////////////////////////////////////////
+void bncGetThread::latencyChecker::callScript(const char* comment) {
+  if (!_adviseScript.isEmpty()) {
+    msleep(1);
+#ifdef WIN32
+    QProcess::startDetached(_adviseScript, QStringList() << _staID << comment) ;
+#else
+    QProcess::startDetached("nohup", QStringList() << _adviseScript << _staID << comment) ;
+#endif
+  }
+}
Index: trunk/BNC/bncgetthread.h
===================================================================
--- trunk/BNC/bncgetthread.h	(revision 1556)
+++ trunk/BNC/bncgetthread.h	(revision 1557)
@@ -74,7 +74,63 @@
 
  private:
+
+   class latencyChecker : public QObject {
+   Q_OBJECT
+   public:
+     latencyChecker(QByteArray staID);
+     ~latencyChecker();
+     void check(GPSDecoder* decoder);
+   signals:
+     void newMessage(QByteArray msg, bool showOnScreen);
+   private:
+     void callScript(const char* comment);
+     int        _inspSegm;
+     int        _adviseFail;
+     int        _adviseReco;
+     int        _perfIntr;
+     int        _numSucc;
+     int        _secSucc;
+     int        _secFail;
+     int        _initPause;
+     int        _currPause;
+     int        _oldSecGPS;
+     int        _newSecGPS;
+     int        _numGaps;
+     int        _diffSecGPS;
+     int        _numLat;
+     bool       _makePause;
+     bool       _wrongEpoch;
+     bool       _decode;
+     bool       _begCorrupt;
+     bool       _endCorrupt;
+     bool       _followSec;
+     double     _maxDt;
+     double     _sumLat;
+     double     _sumLatQ;
+     double     _meanDiff;
+     double     _minLat;
+     double     _maxLat;
+     double     _curLat;
+     QByteArray _staID;
+     QString    _adviseScript;
+     QString    _checkMountPoint;
+     QString    _begDateCor;
+     QString    _begTimeCor;
+     QString    _begDateOut;
+     QString    _begTimeOut;
+     QString    _endDateCor;
+     QString    _endTimeCor;
+     QString    _endDateOut;
+     QString    _endTimeOut;
+     QDateTime  _decodeTime;
+     QDateTime  _decodeSucc;
+     QDateTime  _decodeFailure;
+     QDateTime  _decodeStart;
+     QDateTime  _decodeStop;
+     QDateTime  _decodePause;
+   };
+
    void  initialize();
    t_irc tryReconnect();
-   void  checkLatency();
    void  scanRTCM();
 
@@ -97,4 +153,5 @@
    QextSerialPort* _serialPort;
    bool            _isToBeDeleted;
+   latencyChecker* _latencyChecker;
 };
 
