Index: /trunk/BNC/src/ssrRefSig.cpp
===================================================================
--- /trunk/BNC/src/ssrRefSig.cpp	(revision 11090)
+++ /trunk/BNC/src/ssrRefSig.cpp	(revision 11090)
@@ -0,0 +1,193 @@
+// Part of BNC, a utility for retrieving decoding and
+// converting GNSS data streams from NTRIP broadcasters.
+//
+// Copyright (C) 2007
+// German Federal Agency for Cartography and Geodesy (BKG)
+// http://bkg.bund.de
+// Czech Technical University Prague, Department of Geodesy
+// http://www.fsv.cvut.cz
+//
+// Email: euref-ip@bkg.bund.de
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation, version 2.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/* -------------------------------------------------------------------------
+ * BKG NTRIP Client
+ * -------------------------------------------------------------------------
+ *
+ * Class:      t_ssrRefSig
+ *
+ * Purpose:    Reference signals of the satellite clocks per GNSS
+ *
+ * -----------------------------------------------------------------------*/
+
+#include "ssrRefSig.h"
+#include "bncsettings.h"
+
+using namespace std;
+
+QMutex                          t_ssrRefSig::_mutex;
+bool                            t_ssrRefSig::_initialized = false;
+QMap<char, t_ssrRefSig::t_pair> t_ssrRefSig::_pairs;
+
+static const char* DEFAULT_REF_SIGNALS = "G:1W&2W R:1P&2P E:1C&5Q C:2I&6I J:1C&2L S:1C&5Q";
+
+// Frequency of a band of a system (e.g. 'C', '1' -> C1)
+////////////////////////////////////////////////////////////////////////////
+static t_frequency::type bandToFreq(char sys, char band) {
+  for (int ii = t_frequency::dummy + 1; ii < t_frequency::max; ii++) {
+    string str = t_frequency::toString(t_frequency::type(ii));
+    if (str.size() >= 2 && str[0] == sys && str[1] == band) {
+      return t_frequency::type(ii);
+    }
+  }
+  return t_frequency::dummy;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+string t_ssrRefSig::t_pair::sig1() const {
+  string str = t_frequency::toString(frq1);
+  return str.size() >= 2 ? string(1, str[1]) + att1 : string();
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+string t_ssrRefSig::t_pair::sig2() const {
+  string str = t_frequency::toString(frq2);
+  return str.size() >= 2 ? string(1, str[1]) + att2 : string();
+}
+
+// Parse 'G:1W&2W C:1P&5P ...'
+////////////////////////////////////////////////////////////////////////////
+bool t_ssrRefSig::parse(const QString& str, QMap<char, t_pair>& pairs, QStringList* errors) {
+  bool ok = true;
+  QStringList items = str.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts);
+  for (const QString& item : items) {
+    QRegularExpressionMatch mm =
+      QRegularExpression("^([A-Z]):([0-9])([A-Z])&([0-9])([A-Z])$").match(item.trimmed());
+    t_pair pair;
+    char sys = 0;
+    if (mm.hasMatch()) {
+      sys       = mm.captured(1)[0].toLatin1();
+      pair.frq1 = bandToFreq(sys, mm.captured(2)[0].toLatin1());
+      pair.att1 = mm.captured(3)[0].toLatin1();
+      pair.frq2 = bandToFreq(sys, mm.captured(4)[0].toLatin1());
+      pair.att2 = mm.captured(5)[0].toLatin1();
+    }
+    if (sys == 0 || pair.frq1 == t_frequency::dummy || pair.frq2 == t_frequency::dummy ||
+        pair.frq1 == pair.frq2) {
+      ok = false;
+      if (errors) {
+        *errors << QString("reference signals '%1' invalid (unknown system or band, or format other than e.g. 'C:1P&5P'), ignored").arg(item);
+      }
+      continue;
+    }
+    pairs[sys] = pair;
+  }
+  return ok;
+}
+
+// (Re-)read the option
+////////////////////////////////////////////////////////////////////////////
+QStringList t_ssrRefSig::init() {
+  QMutexLocker locker(&_mutex);
+  QStringList errors;
+  _pairs.clear();
+  parse(DEFAULT_REF_SIGNALS, _pairs, 0);
+  bncSettings settings;
+  parse(settings.value("ssrRefSignals").toString(), _pairs, &errors);
+  _initialized = true;
+  return errors;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+bool t_ssrRefSig::get(char sys, t_pair& pair) {
+  if (!_initialized) {
+    init();
+  }
+  QMutexLocker locker(&_mutex);
+  if (!_pairs.contains(sys)) {
+    return false;
+  }
+  pair = _pairs[sys];
+  return true;
+}
+
+// True if the system uses the default reference signals
+////////////////////////////////////////////////////////////////////////////
+bool t_ssrRefSig::isDefault(char sys) {
+  QMap<char, t_pair> defaults;
+  parse(DEFAULT_REF_SIGNALS, defaults, 0);
+  t_pair pair;
+  bool   has = get(sys, pair);
+  if (!defaults.contains(sys)) {
+    return !has;
+  }
+  const t_pair& def = defaults[sys];
+  return has && pair.frq1 == def.frq1 && pair.att1 == def.att1 &&
+                pair.frq2 == def.frq2 && pair.att2 == def.att2;
+}
+
+// True if all systems use the default reference signals
+////////////////////////////////////////////////////////////////////////////
+bool t_ssrRefSig::allDefault() {
+  QMap<char, t_pair> defaults;
+  parse(DEFAULT_REF_SIGNALS, defaults, 0);
+  if (!_initialized) {
+    init();
+  }
+  QMutexLocker locker(&_mutex);
+  if (defaults.keys() != _pairs.keys()) {
+    return false;
+  }
+  for (char sys : defaults.keys()) {
+    const t_pair& p1 = defaults[sys];
+    const t_pair& p2 = _pairs[sys];
+    if (p1.frq1 != p2.frq1 || p1.att1 != p2.att1 || p1.frq2 != p2.frq2 || p1.att2 != p2.att2) {
+      return false;
+    }
+  }
+  return true;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+QString t_ssrRefSig::defaultString() {
+  return DEFAULT_REF_SIGNALS;
+}
+
+// Current reference signals, e.g. for the logfile
+////////////////////////////////////////////////////////////////////////////
+QString t_ssrRefSig::currentString() {
+  if (!_initialized) {
+    init();
+  }
+  QMutexLocker locker(&_mutex);
+  QStringList items;
+  QString     systems = "GRECJSI";
+  for (char sys : _pairs.keys()) {
+    if (!systems.contains(sys)) {
+      systems += sys;
+    }
+  }
+  for (QChar sys : systems) {
+    char cs = sys.toLatin1();
+    if (_pairs.contains(cs)) {
+      items << QString("%1:%2&%3").arg(sys).arg(_pairs[cs].sig1().c_str()).arg(_pairs[cs].sig2().c_str());
+    }
+  }
+  return items.join(" ");
+}
Index: /trunk/BNC/src/ssrRefSig.h
===================================================================
--- /trunk/BNC/src/ssrRefSig.h	(revision 11090)
+++ /trunk/BNC/src/ssrRefSig.h	(revision 11090)
@@ -0,0 +1,44 @@
+#ifndef SSRREFSIG_H
+#define SSRREFSIG_H
+
+#include <QtCore>
+#include "bncconst.h"
+
+// Reference signals of the satellite clocks per GNSS (IGS conventions):
+// the clocks refer to the ionosphere-free combination of the code signals
+// of these two signals. Used by the combination (referring the AC clocks,
+// code biases from a Bias SINEX file) and the SSR QC (B_IF, stream
+// comparison). Default 'G:1W&2W R:1P&2P E:1C&5Q C:2I&6I J:1C&2L S:1C&5Q',
+// systems can be overwritten with the option ssrRefSignals.
+////////////////////////////////////////////////////////////////////////////
+class t_ssrRefSig {
+ public:
+  class t_pair {
+   public:
+    t_pair() : frq1(t_frequency::dummy), frq2(t_frequency::dummy), att1('_'), att2('_') {}
+    t_frequency::type frq1;
+    t_frequency::type frq2;
+    char              att1;
+    char              att2;
+    std::string sig1() const;  // e.g. "1W"
+    std::string sig2() const;
+  };
+
+  // (Re-)read the option ssrRefSignals; returns the messages about invalid
+  // entries (these systems keep their default)
+  static QStringList init();
+
+  static bool    get(char sys, t_pair& pair);
+  static bool    isDefault(char sys);
+  static bool    allDefault();
+  static QString defaultString();
+  static QString currentString();
+
+ private:
+  static bool parse(const QString& str, QMap<char, t_pair>& pairs, QStringList* errors);
+  static QMutex              _mutex;
+  static bool                _initialized;
+  static QMap<char, t_pair>  _pairs;
+};
+
+#endif
