Index: trunk/BNC/src/Doxyfile
===================================================================
--- trunk/BNC/src/Doxyfile	(revision 6812)
+++ trunk/BNC/src/Doxyfile	(revision 6812)
@@ -0,0 +1,6 @@
+EXTRACT_PRIVATE = YES
+RECURSIVE = YES
+GENERATE_LATEX = NO
+
+# silence majority of warnings
+WARN_IF_UNDOCUMENTED = NO
Index: trunk/BNC/src/GPSDecoder.h
===================================================================
--- trunk/BNC/src/GPSDecoder.h	(revision 6809)
+++ trunk/BNC/src/GPSDecoder.h	(revision 6812)
@@ -76,4 +76,5 @@
   };
 
+  /** List of observations */
   QList<t_satObs>  _obsList;
   QList<int>       _typeList;  // RTCM message types
Index: trunk/BNC/src/RTCM3/RTCM3Decoder.cpp
===================================================================
--- trunk/BNC/src/RTCM3/RTCM3Decoder.cpp	(revision 6809)
+++ trunk/BNC/src/RTCM3/RTCM3Decoder.cpp	(revision 6812)
@@ -45,6 +45,8 @@
 #include <string.h>
 
+#include "bits.h"
+#include "gnss.h"
 #include "RTCM3Decoder.h"
-#include "../RTCM/rtcm_utils.h"
+#include "rtcm_utils.h"
 #include "bncconst.h"
 #include "bnccore.h"
@@ -54,8 +56,4 @@
 using namespace std;
 
-#ifndef isinf
-#  define isinf(x) 0
-#endif
-
 // Error Handling
 ////////////////////////////////////////////////////////////////////////////
@@ -70,7 +68,4 @@
   _staID   = staID;
   _rawFile = rawFile;
-
-  bncSettings settings;
-  _checkMountPoint = settings.value("miscMount").toString();
 
   connect(this, SIGNAL(newGPSEph(t_ephGPS)),     BNC_CORE, SLOT(slotNewGPSEph(t_ephGPS)));
@@ -80,12 +75,5 @@
   connect(this, SIGNAL(newBDSEph(t_ephBDS)),     BNC_CORE, SLOT(slotNewBDSEph(t_ephBDS)));
 
-  // Mode can be either observations or corrections
-  // ----------------------------------------------
-  _mode = unknown;
-
-  // Antenna position (used for decoding of message 1003)
-  // ----------------------------------------------------
-  _antXYZ[0] = _antXYZ[1] = _antXYZ[2] = 0;
-
+  _MessageSize = _SkipBytes = _BlockSize = _NeedBytes = 0;
 }
 
@@ -94,5 +82,6 @@
 RTCM3Decoder::~RTCM3Decoder() {
   QMapIterator<QByteArray, RTCM3coDecoder*> it(_coDecoders);
-  while (it.hasNext()) {
+  while(it.hasNext())
+  {
     it.next();
     delete it.value();
@@ -102,335 +91,1521 @@
 // 
 ////////////////////////////////////////////////////////////////////////////
-t_irc RTCM3Decoder::Decode(char* buffer, int bufLen, vector<string>& errmsg) {
-
-  errmsg.clear();
-
+bool RTCM3Decoder::DecodeRTCM3GPS(unsigned char* data, int size)
+{
   bool decoded = false;
-
-  // If read from file, mode is always uknown
-  // ----------------------------------------
-  if (_rawFile) {
-    _mode  = unknown;
-    _staID = _rawFile->staID();
-  }
-
-  // Try to decode Clock and Orbit Corrections
-  // -----------------------------------------
-  if (_mode == unknown || _mode == corrections) {
-
-    // Find the corresponding coDecoder
-    // --------------------------------
-    if (!_coDecoders.contains(_staID.toAscii())) {
-      _coDecoders[_staID.toAscii()] = new RTCM3coDecoder(_staID); 
+  bncTime CurrentObsTime;
+  int i, numsats, syncf, type;
+  uint64_t numbits = 0, bitfield = 0;
+
+  data += 3; /* header */
+  size -= 6; /* header + crc */
+
+  GETBITS(type, 12)
+  SKIPBITS(12) /* id */
+  GETBITS(i,30)
+
+  CurrentObsTime.set(i);
+  if(_CurrentTime.valid() && CurrentObsTime != _CurrentTime)
+  {
+    decoded = true;
+    _obsList = _CurrentObsList;
+    _CurrentObsList.clear();
+  }
+  _CurrentTime = CurrentObsTime;
+
+  GETBITS(syncf,1) /* sync */
+  GETBITS(numsats,5)
+  SKIPBITS(4) /* smind, smint */
+
+  while(numsats--)
+  {
+    int sv, code, l1range, amb=0;
+    t_satObs CurrentObs;
+    CurrentObs._time = CurrentObsTime;
+
+    GETBITS(sv, 6)
+    if(sv < 40)
+      CurrentObs._prn.set('G', sv);
+    else
+      CurrentObs._prn.set('S', sv-20);
+
+    t_frqObs *frqObs = new t_frqObs;
+    /* L1 */
+    GETBITS(code, 1);
+    frqObs->_rnxType2ch = code ? "1W" : "1C";
+    GETBITS(l1range, 24);
+    GETBITSSIGN(i, 20);
+    if((i&((1<<20)-1)) != 0x80000)
+    {
+      frqObs->_code = l1range*0.02;
+      frqObs->_phase = (l1range*0.02+i*0.0005)/GPS_WAVELENGTH_L1;
+      frqObs->_codeValid = frqObs->_phaseValid = true;
     }
-    RTCM3coDecoder* coDecoder = _coDecoders[_staID.toAscii()];
-
-    if ( coDecoder->Decode(buffer, bufLen, errmsg) == success ) {
-      decoded = true;
-      if  (!_rawFile && _mode == unknown) {
-        _mode = corrections;
+    GETBITS(i, 7);
+    frqObs->_slipCounter = i;
+    if(type == 1002 || type == 1004)
+    {
+      GETBITS(amb,8);
+      if(amb)
+      {
+        frqObs->_code += amb*299792.458;
+        frqObs->_phase += (amb*299792.458)/GPS_WAVELENGTH_L1;
+      }
+      GETBITS(i, 8);
+      if(i)
+      {
+        frqObs->_snr = i*0.25;
+        frqObs->_snrValid = true;
       }
     }
-  }
-
-  // Find the corresponding parser, initialize a new parser if necessary
-  // -------------------------------------------------------------------
-  bool newParser = !_parsers.contains(_staID.toAscii());
-  RTCM3ParserData& parser = _parsers[_staID.toAscii()];
-  if (newParser) {  
-    memset(&parser, 0, sizeof(parser));
-    parser.rinex3 = 0;
-    double secGPS;
-    currentGPSWeeks(parser.GPSWeek, secGPS);
-    parser.GPSTOW = int(secGPS);
-  }
-
-  // Remaining part decodes the Observations
-  // ---------------------------------------
-  if (_mode == unknown || _mode == observations || 
-      _checkMountPoint == _staID || _checkMountPoint == "ALL") {
-
-    for (int iByte = 0; iByte < bufLen; iByte++) {
-
-      parser.Message[parser.MessageSize++] = buffer[iByte];
-
-      if (parser.MessageSize >= parser.NeedBytes) {
-
-        while (int rr = RTCM3Parser(&parser)) {
-
-          // RTCMv3 message types
-          // --------------------
-          _typeList.push_back(parser.blocktype);
-
-          // RTCMv3 antenna descriptor
-          // -------------------------
-          if (rr == 1007 || rr == 1008 || rr == 1033) {
-            _antType.push_back(parser.antenna);
+    CurrentObs._obs.push_back(frqObs);
+    if(type == 1003 || type == 1004)
+    {
+      frqObs = new t_frqObs;
+      /* L2 */
+      GETBITS(code,2);
+      switch(code)
+      {
+      case 3: frqObs->_rnxType2ch = "2W"; /* or "2Y"? */ break;
+      case 2: frqObs->_rnxType2ch = "2W"; break;
+      case 1: frqObs->_rnxType2ch = "2P"; break;
+      case 0: frqObs->_rnxType2ch = "2X"; /* or "2S" or "2L"? */ break;
+      }
+      GETBITSSIGN(i,14);
+      if((i&((1<<14)-1)) != 0x2000)
+      {
+        frqObs->_code = l1range*0.02+i*0.02+amb*299792.458;
+        frqObs->_codeValid = true;
+      }
+      GETBITSSIGN(i,20);
+      if((i&((1<<20)-1)) != 0x80000)
+      {
+        frqObs->_phase = (l1range*0.02+i*0.0005+amb*299792.458)/GPS_WAVELENGTH_L2;
+        frqObs->_phaseValid = true;
+      }
+      GETBITS(i,7);
+      frqObs->_slipCounter = i;
+      if(type == 1004)
+      {
+        GETBITS(i, 8);
+        if(i)
+        {
+          frqObs->_snr = i*0.25;
+          frqObs->_snrValid = true;
+        }
+      }
+      CurrentObs._obs.push_back(frqObs);
+    }
+    _CurrentObsList.push_back(CurrentObs);
+  }
+  if(!syncf)
+  {
+    decoded = true;
+    _obsList = _CurrentObsList;
+    _CurrentTime.reset();
+    _CurrentObsList.clear();
+  }
+  return decoded;
+}
+
+#define RTCM3_MSM_NUMSIG      32
+#define RTCM3_MSM_NUMSAT      64
+#define RTCM3_MSM_NUMCELLS    96 /* arbitrary limit */
+
+/**
+ * Frequency numbers of GLONASS with an offset of 100 to detect unset values.
+ * Gets filled by ephemeris and data blocks and shared between different streams.
+ */
+static int GLOFreq[RTCM3_MSM_NUMSAT];
+
+/*
+ * Storage structure to store frequency and RINEX ID assignment for MSM
+ * message */
+struct CodeData {
+  double wl;
+  const char *code; /* currently unused */
+};
+
+/** MSM signal types for GPS and SBAS */
+static struct CodeData gps[RTCM3_MSM_NUMSIG] =
+{
+  {0.0,0},
+  {GPS_WAVELENGTH_L1,"1C"},
+  {GPS_WAVELENGTH_L1,"1P"},
+  {GPS_WAVELENGTH_L1,"1W"},
+  {0.0,0}/*{GPS_WAVELENGTH_L1,"1Y"}*/,
+  {0.0,0},
+  {0.0,0},
+  {GPS_WAVELENGTH_L2,"2C"},
+  {GPS_WAVELENGTH_L2,"2P"},
+  {GPS_WAVELENGTH_L2,"2W"},
+  {0.0,0}/*{GPS_WAVELENGTH_L2,"2Y"}*/,
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {GPS_WAVELENGTH_L2,"2S"},
+  {GPS_WAVELENGTH_L2,"2L"},
+  {GPS_WAVELENGTH_L2,"2X"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {GPS_WAVELENGTH_L5,"5I"},
+  {GPS_WAVELENGTH_L5,"5Q"},
+  {GPS_WAVELENGTH_L5,"5X"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {GPS_WAVELENGTH_L1,"1S"},
+  {GPS_WAVELENGTH_L1,"1L"},
+  {GPS_WAVELENGTH_L1,"1X"}
+};
+
+/**
+ * MSM signal types for GLONASS
+ * 
+ * NOTE: Uses 0.0, 1.0 for wavelength as sat index dependence is done later!
+ */
+static struct CodeData glo[RTCM3_MSM_NUMSIG] =
+{
+  {0.0,0},
+  {0.0,"1C"},
+  {0.0,"1P"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {1.0,"2C"},
+  {1.0,"2P"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0}
+};
+
+/** MSM signal types for Galileo */
+static struct CodeData gal[RTCM3_MSM_NUMSIG] =
+{
+  {0.0,0},
+  {GAL_WAVELENGTH_E1,"1C"},
+  {GAL_WAVELENGTH_E1,"1A"},
+  {GAL_WAVELENGTH_E1,"1B"},
+  {GAL_WAVELENGTH_E1,"1X"},
+  {GAL_WAVELENGTH_E1,"1Z"},
+  {0.0,0},
+  {GAL_WAVELENGTH_E6,"6C"},
+  {GAL_WAVELENGTH_E6,"6A"},
+  {GAL_WAVELENGTH_E6,"6B"},
+  {GAL_WAVELENGTH_E6,"6X"},
+  {GAL_WAVELENGTH_E6,"6Z"},
+  {0.0,0},
+  {GAL_WAVELENGTH_E5B,"7I"},
+  {GAL_WAVELENGTH_E5B,"7Q"},
+  {GAL_WAVELENGTH_E5B,"7X"},
+  {0.0,0},
+  {GAL_WAVELENGTH_E5AB,"8I"},
+  {GAL_WAVELENGTH_E5AB,"8Q"},
+  {GAL_WAVELENGTH_E5AB,"8X"},
+  {0.0,0},
+  {GAL_WAVELENGTH_E5A,"5I"},
+  {GAL_WAVELENGTH_E5A,"5Q"},
+  {GAL_WAVELENGTH_E5A,"5X"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+};
+
+/** MSM signal types for QZSS */
+static struct CodeData qzss[RTCM3_MSM_NUMSIG] =
+{
+  {0.0,0},
+  {GPS_WAVELENGTH_L1,"1C"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {GPS_WAVELENGTH_L1,"1Z"},
+  {0.0,0},
+  {0.0,0},
+  {QZSS_WAVELENGTH_LEX,"6S"},
+  {QZSS_WAVELENGTH_LEX,"6L"},
+  {QZSS_WAVELENGTH_LEX,"6X"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {GPS_WAVELENGTH_L2,"2S"},
+  {GPS_WAVELENGTH_L2,"2L"},
+  {GPS_WAVELENGTH_L2,"2X"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {GPS_WAVELENGTH_L5,"5I"},
+  {GPS_WAVELENGTH_L5,"5Q"},
+  {GPS_WAVELENGTH_L5,"5X"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {GPS_WAVELENGTH_L1,"1D"},
+  {GPS_WAVELENGTH_L1,"1P"},
+  {GPS_WAVELENGTH_L1,"1X"}
+};
+
+/** MSM signal types for Beidou/BDS */
+static struct CodeData bds[RTCM3_MSM_NUMSIG] =
+{
+  {0.0,0},
+  {BDS_WAVELENGTH_B1,"1I"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {BDS_WAVELENGTH_B3,"6I"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {BDS_WAVELENGTH_B2,"7I"},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+  {0.0,0},
+};
+
+#define UINT64(c) c ## ULL
+
+// 
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeRTCM3MSM(unsigned char* data, int size)
+{
+  bool decoded = false;
+  int type, syncf, i;
+  uint64_t numbits = 0, bitfield = 0;
+
+  data += 3; /* header */
+  size -= 6; /* header + crc */
+
+  GETBITS(type, 12)
+  SKIPBITS(12) /* id */
+  char sys;
+  if(type >= 1121)
+    sys = 'C';
+  else if(type >= 1111)
+    sys = 'J';
+  else if(type >= 1101)
+    sys = 'S';
+  else if(type >= 1091)
+    sys = 'E';
+  else if(type >= 1081)
+    sys = 'R';
+  else
+    sys = 'G';
+
+  bncTime CurrentObsTime;
+  if(sys == 'C') /* BDS */
+  {
+    GETBITS(i,30)
+    CurrentObsTime.setBDS(i);
+  }
+  else if(sys == 'R') /* GLONASS */
+  {
+    SKIPBITS(3)
+    GETBITS(i,27) /* tk */
+    CurrentObsTime.setTk(i);
+  }
+  else /* GPS style date */
+  {
+    GETBITS(i,30)
+    CurrentObsTime.set(i);
+  }
+  if(_CurrentTime.valid() && CurrentObsTime != _CurrentTime)
+  {
+    decoded = true;
+    _obsList = _CurrentObsList;
+    _CurrentObsList.clear();
+  }
+  _CurrentTime = CurrentObsTime;
+
+  GETBITS(syncf, 1)
+  /**
+   * Ignore unknown types except for sync flag
+   * 
+   * We actually support types 1-3 in following code, but as they are missing
+   * the full cycles and can't be used later we skip interpretation here already.
+   */
+  if(type <= 1130 && (type % 10) >= 4 && (type % 10) <= 7)
+  {
+    int sigmask, numsat = 0, numsig = 0;
+    uint64_t satmask, cellmask, ui;
+    double rrmod[RTCM3_MSM_NUMSAT];
+    int rrint[RTCM3_MSM_NUMSAT], rdop[RTCM3_MSM_NUMSAT],
+    extsat[RTCM3_MSM_NUMSAT];
+    int ll[RTCM3_MSM_NUMCELLS]/*, hc[RTCM3_MSM_NUMCELLS]*/;
+    double cnr[RTCM3_MSM_NUMCELLS];
+    double cp[RTCM3_MSM_NUMCELLS], psr[RTCM3_MSM_NUMCELLS],
+    dop[RTCM3_MSM_NUMCELLS];
+
+    SKIPBITS(3+7+2+2+1+3)
+    GETBITS64(satmask, RTCM3_MSM_NUMSAT)
+
+    /* http://gurmeetsingh.wordpress.com/2008/08/05/fast-bit-counting-routines/ */
+    for(ui = satmask; ui; ui &= (ui - 1) /* remove rightmost bit */)
+      ++numsat;
+    GETBITS(sigmask, RTCM3_MSM_NUMSIG)
+    for(i = sigmask; i; i &= (i - 1) /* remove rightmost bit */)
+      ++numsig;
+    for(i = 0; i < RTCM3_MSM_NUMSAT; ++i)
+      extsat[i] = 15;
+
+    i = numsat*numsig;
+    GETBITS64(cellmask, (unsigned)i)
+
+    switch(type % 10)
+    {
+    case 1: case 2: case 3:
+      /* partial data, already skipped above, but implemented for future expansion ! */
+      for(int j = numsat; j--;)
+        GETFLOAT(rrmod[j], 10, 1.0/1024.0)
+      break;
+    case 4: case 6:
+      for(int j = numsat; j--;)
+        GETBITS(rrint[j], 8)
+      for(int j = numsat; j--;)
+        GETFLOAT(rrmod[j], 10, 1.0/1024.0)
+      break;
+    case 5: case 7:
+      for(int j = numsat; j--;)
+        GETBITS(rrint[j], 8)
+      for(int j = numsat; j--;)
+        GETBITS(extsat[j], 4)
+      for(int j = numsat; j--;)
+        GETFLOAT(rrmod[j], 10, 1.0/1024.0)
+      for(int j = numsat; j--;)
+        GETBITSSIGN(rdop[j], 14)
+      break;
+    }
+
+    int numcells = numsat*numsig;
+    /** Drop anything which exceeds our cell limit. Increase limit definition
+     * when that happens. */
+    if(numcells <= RTCM3_MSM_NUMCELLS)
+    {
+      switch(type % 10)
+      {
+      case 1:
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(psr[count], 15, 1.0/(1<<24))
+        break;
+      case 2:
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(cp[count], 22, 1.0/(1<<29))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETBITS(ll[count], 4)
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            SKIPBITS(1)/*GETBITS(hc[count], 1)*/
+        break;
+      case 3:
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(psr[count], 15, 1.0/(1<<24))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(cp[count], 22, 1.0/(1<<29))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETBITS(ll[count], 4)
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            SKIPBITS(1)/*GETBITS(hc[count], 1)*/
+        break;
+      case 4:
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(psr[count], 15, 1.0/(1<<24))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(cp[count], 22, 1.0/(1<<29))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETBITS(ll[count], 4)
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            SKIPBITS(1)/*GETBITS(hc[count], 1)*/
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETBITS(cnr[count], 6)
+        break;
+      case 5:
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(psr[count], 15, 1.0/(1<<24))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(cp[count], 22, 1.0/(1<<29))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETBITS(ll[count], 4)
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            SKIPBITS(1)/*GETBITS(hc[count], 1)*/
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOAT(cnr[count], 6, 1.0)
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(dop[count], 15, 0.0001)
+        break;
+      case 6:
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(psr[count], 20, 1.0/(1<<29))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(cp[count], 24, 1.0/(1U<<31))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETBITS(ll[count], 10)
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            SKIPBITS(1)/*GETBITS(hc[count], 1)*/
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOAT(cnr[count], 10, 1.0/(1<<4))
+        break;
+      case 7:
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(psr[count], 20, 1.0/(1<<29))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(cp[count], 24, 1.0/(1U<<31))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETBITS(ll[count], 10)
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            SKIPBITS(1)/*GETBITS(hc[count], 1)*/
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOAT(cnr[count], 10, 1.0/(1<<4))
+        for(int count = numcells; count--;)
+          if(cellmask & (UINT64(1)<<count))
+            GETFLOATSIGN(dop[count], 15, 0.0001)
+        break;
+      }
+      i = RTCM3_MSM_NUMSAT;
+      int j = -1;
+      t_satObs CurrentObs;
+      for(int count = numcells; count--;)
+      {
+        while(j >= 0 && !(sigmask&(1<<--j)))
+          ;
+        if(j < 0)
+        {
+          while(!(satmask&(UINT64(1)<<(--i)))) /* next satellite */
+            ;
+          if(CurrentObs._obs.size() > 0)
+            _CurrentObsList.push_back(CurrentObs);
+          CurrentObs.clear();
+          CurrentObs._time = CurrentObsTime;
+          if(sys == 'S')
+            CurrentObs._prn.set(sys, 20-1+RTCM3_MSM_NUMSAT-i);
+          else
+            CurrentObs._prn.set(sys, RTCM3_MSM_NUMSAT-i);
+          j = RTCM3_MSM_NUMSIG;
+          while(!(sigmask&(1<<--j)))
+            ;
+          --numsat;
+        }
+        if(cellmask & (UINT64(1)<<count))
+        {
+          struct CodeData cd = {0.0,0};
+          switch(sys)
+          {
+          case 'J':
+            cd = qzss[RTCM3_MSM_NUMSIG-j-1];
+            break;
+          case 'C':
+            cd = bds[RTCM3_MSM_NUMSIG-j-1];
+            break;
+          case 'G': case 'S':
+            cd = gps[RTCM3_MSM_NUMSIG-j-1];
+            break;
+          case 'R':
+            cd = glo[RTCM3_MSM_NUMSIG-j-1];
+            {
+              int k = GLOFreq[RTCM3_MSM_NUMSAT-i-1];
+              if(extsat[numsat] < 14)
+              {
+                k = GLOFreq[RTCM3_MSM_NUMSAT-i-1] = 100+extsat[numsat]-7;
+              }
+              if(k)
+                cd.wl = (cd.wl == 0.0 ? GLO_WAVELENGTH_L1(k-100) : GLO_WAVELENGTH_L2(k-100));
+              else
+                cd.code = 0;
+            }
+            break;
+          case 'E':
+            cd = gal[RTCM3_MSM_NUMSIG-j-1];
+            break;
           }
-
-          // RTCMv3 antenna XYZ
-          // ------------------
-          else if (rr == 1005) {
-            _antList.push_back(t_antInfo());
-            _antList.back().type     = t_antInfo::ARP;
-            _antList.back().xx       = parser.antX * 1e-4;
-            _antList.back().yy       = parser.antY * 1e-4;
-            _antList.back().zz       = parser.antZ * 1e-4;
-            _antList.back().message  = rr;
-
-            // Remember station position for 1003 message decoding
-            _antXYZ[0] = parser.antX * 1e-4;
-            _antXYZ[1] = parser.antY * 1e-4;
-            _antXYZ[2] = parser.antZ * 1e-4;
-          }
-
-          // RTCMv3 antenna XYZ-H
-          // --------------------
-          else if(rr == 1006) {
-            _antList.push_back(t_antInfo());
-            _antList.back().type     = t_antInfo::ARP;
-            _antList.back().xx       = parser.antX * 1e-4;
-            _antList.back().yy       = parser.antY * 1e-4;
-            _antList.back().zz       = parser.antZ * 1e-4;
-            _antList.back().height   = parser.antH * 1e-4;
-            _antList.back().height_f = true;
-            _antList.back().message  = rr;
-
-            // Remember station position for 1003 message decoding
-            _antXYZ[0] = parser.antX * 1e-4;
-            _antXYZ[1] = parser.antY * 1e-4;
-            _antXYZ[2] = parser.antZ * 1e-4;
-          }
-
-          // GNSS Observations
-          // -----------------
-          else if (rr == 1 || rr == 2) {
-            decoded = true;
-    
-            if (!parser.init) {
-              HandleHeader(&parser);
-              parser.init = 1;
+          if(cd.code)
+          {
+            t_frqObs *frqObs = new t_frqObs;
+            frqObs->_rnxType2ch = cd.code;
+
+            switch(type % 10)
+            {
+            case 1:
+              if(psr[count] > -1.0/(1<<10))
+              {
+                frqObs->_code = psr[count]*LIGHTSPEED/1000.0
+                +(rrmod[numsat])*LIGHTSPEED/1000.0;
+                frqObs->_codeValid = true;
+              }
+              break;
+            case 2:
+              if(cp[count] > -1.0/(1<<8))
+              {
+                frqObs->_phase = cp[count]*LIGHTSPEED/1000.0/cd.wl
+                +(rrmod[numsat])*LIGHTSPEED/1000.0/cd.wl;
+                frqObs->_phaseValid = true;
+                frqObs->_slipCounter = ll[count];
+              }
+              break;
+            case 3:
+              if(psr[count] > -1.0/(1<<10))
+              {
+                frqObs->_code = psr[count]*LIGHTSPEED/1000.0
+                +(rrmod[numsat])*LIGHTSPEED/1000.0;
+                frqObs->_codeValid = true;
+              }
+
+              if(cp[count] > -1.0/(1<<8))
+              {
+                frqObs->_phase = cp[count]*LIGHTSPEED/1000.0/cd.wl
+                +rrmod[numsat]*LIGHTSPEED/1000.0/cd.wl;
+                frqObs->_phaseValid = true;
+                frqObs->_slipCounter = ll[count];
+              }
+              break;
+            case 4:
+              if(psr[count] > -1.0/(1<<10))
+              {
+                frqObs->_code = psr[count]*LIGHTSPEED/1000.0
+                +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0;
+                frqObs->_codeValid = true;
+              }
+
+              if(cp[count] > -1.0/(1<<8))
+              {
+                frqObs->_phase = cp[count]*LIGHTSPEED/1000.0/cd.wl
+                +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0/cd.wl;
+                frqObs->_phaseValid = true;
+                frqObs->_slipCounter = ll[count];
+              }
+
+              frqObs->_snr = cnr[count];
+              frqObs->_snrValid = true;
+              break;
+            case 5:
+              if(psr[count] > -1.0/(1<<10))
+              {
+                frqObs->_code = psr[count]*LIGHTSPEED/1000.0
+                +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0;
+                frqObs->_codeValid = true;
+              }
+
+              if(cp[count] > -1.0/(1<<8))
+              {
+                frqObs->_phase = cp[count]*LIGHTSPEED/1000.0/cd.wl
+                +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0/cd.wl;
+                frqObs->_phaseValid = true;
+                frqObs->_slipCounter = ll[count];
+              }
+
+              frqObs->_snr = cnr[count];
+              frqObs->_snrValid = true;
+
+              if(dop[count] > -1.6384)
+              {
+                frqObs->_doppler = -(dop[count]+rdop[numsat])/cd.wl;
+                frqObs->_dopplerValid = true;
+              }
+              break;
+            case 6:
+              if(psr[count] > -1.0/(1<<10))
+              {
+                frqObs->_code = psr[count]*LIGHTSPEED/1000.0
+                +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0;
+                frqObs->_codeValid = true;
+              }
+
+              if(cp[count] > -1.0/(1<<8))
+              {
+                frqObs->_phase = cp[count]*LIGHTSPEED/1000.0/cd.wl
+                +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0/cd.wl;
+                frqObs->_phaseValid = true;
+                frqObs->_slipCounter = ll[count];
+              }
+
+              frqObs->_snr = cnr[count];
+              frqObs->_snrValid = true;
+              break;
+            case 7:
+              if(psr[count] > -1.0/(1<<10))
+              {
+                frqObs->_code = psr[count]*LIGHTSPEED/1000.0
+                +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0;
+                frqObs->_codeValid = true;
+              }
+
+              if(cp[count] > -1.0/(1<<8))
+              {
+                frqObs->_phase = cp[count]*LIGHTSPEED/1000.0/cd.wl
+                +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0/cd.wl;
+                frqObs->_phaseValid = true;
+                frqObs->_slipCounter = ll[count];
+              }
+
+              frqObs->_snr = cnr[count];
+              frqObs->_snrValid = true;
+
+              if(dop[count] > -1.6384)
+              {
+                frqObs->_doppler = -(dop[count]+rdop[numsat])/cd.wl;
+                frqObs->_dopplerValid = true;
+              }
+              break;
             }
-            
-            if (rr == 2) {
-              emit(newMessage( (_staID + 
-               ": No valid RINEX! All values are modulo 299792.458!").toAscii(),
-               true));
-            }
-
-            gnssdata& gnssData = parser.Data;
-            
-            for (int iSat = 0; iSat < gnssData.numsats; iSat++) {
-
-              t_satObs obs;
-              int   satID = gnssData.satellites[iSat];
-
-              // GPS
-              // ---
-              if      (satID >= PRN_GPS_START     && satID <= PRN_GPS_END) {
-                obs._prn.set('G', satID);
-              }
-
-              // Glonass
-              // -------
-              else if (satID >= PRN_GLONASS_START && satID <= PRN_GLONASS_END) {
-                obs._prn.set('R', satID - PRN_GLONASS_START + 1);
-              }
-
-              // Galileo
-              // -------
-              else if (satID >= PRN_GALILEO_START && satID <= PRN_GALILEO_END) {
-                obs._prn.set('E', satID - PRN_GALILEO_START + 1);
-              }
-
-              // SBAS
-              // ----
-              else if (satID >= PRN_SBAS_START && satID <= PRN_SBAS_END) {
-                obs._prn.set('S', satID - PRN_SBAS_START + 20);
-              }
-
-              // Giove A and B
-              // -------------
-              else if (satID >= PRN_GIOVE_START && satID <= PRN_GIOVE_END) {
-                obs._prn.set('E', satID - PRN_GIOVE_START + PRN_GIOVE_OFFSET);
-              }
-
-              // QZSS
-              // -------------
-              else if (satID >= PRN_QZSS_START && satID <= PRN_QZSS_END) {
-                obs._prn.set('J', satID - PRN_QZSS_START + 1);
-              }
-
-              // BDS
-              // -------------
-              else if (satID >= PRN_BDS_START && satID <= PRN_BDS_END) {
-                obs._prn.set('C', satID - PRN_BDS_START + 1);
-              }
-
-              // Unknown System
-              // --------------
-              else {
-                continue;
-              }
-
-              obs._time.set(gnssData.week, gnssData.timeofweek / 1000.0);
-
-              QString prn(obs._prn.toString().c_str());
-
-              int obs_slip_cnt_L1 = 0;
-              int obs_slip_cnt_L2 = 0;
-              int obs_slip_cnt_L5 = 0;
-
-              // Handle loss-of-lock flags
-              // -------------------------
-              const int maxSlipCnt = 100;
-              if (!_slip_cnt_L1.contains(prn)) {
-                _slip_cnt_L1[prn] = 0;
-                _slip_cnt_L2[prn] = 0;
-                _slip_cnt_L5[prn] = 0;
-              }
-              if (GNSSDF2_LOCKLOSSL1 & gnssData.dataflags2[iSat]) {
-                if (_slip_cnt_L1[prn] < maxSlipCnt) {
-                  ++_slip_cnt_L1[prn];
-                }
-                else {
-                  _slip_cnt_L1[prn] = 1;
-                }
-                obs_slip_cnt_L1 = _slip_cnt_L1[prn];
-              }
-              if (GNSSDF2_LOCKLOSSL2 & gnssData.dataflags2[iSat]) {
-                if (_slip_cnt_L2[prn] < maxSlipCnt) {
-                  ++_slip_cnt_L2[prn];
-                }
-                else {
-                  _slip_cnt_L2[prn] = 1;
-                }
-                obs_slip_cnt_L2 = _slip_cnt_L2[prn];
-              }
-              if (GNSSDF2_LOCKLOSSL5 & gnssData.dataflags2[iSat]) {
-                if (_slip_cnt_L5[prn] < maxSlipCnt) {
-                  ++_slip_cnt_L5[prn];
-                }
-                else {
-                  _slip_cnt_L5[prn] = 1;
-                }
-                obs_slip_cnt_L5 = _slip_cnt_L5[prn];
-              }
-
-              // Loop over all data types
-              // ------------------------
-              for (int iEntry = 0; iEntry < GNSSENTRY_NUMBER; ++iEntry) {
-                if (gnssData.codetype[iSat][iEntry] == 0) {
-                  continue;
-                }
-                string rnxType(gnssData.codetype[iSat][iEntry]);
-
-                t_frqObs* frqObs = 0;
-                for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) {
-                  if (obs._obs[iFrq]->_rnxType2ch == rnxType) {
-                    frqObs = obs._obs[iFrq];
-                    break;
-                  }
-                }
-                if (frqObs == 0) {
-                  frqObs = new t_frqObs;
-                  frqObs->_rnxType2ch = rnxType;
-                  obs._obs.push_back(frqObs);
-                }
-
-                switch(iEntry & 3) {
-                case GNSSENTRY_CODE:
-                  frqObs->_codeValid = true;
-                  frqObs->_code      = gnssData.measdata[iSat][iEntry];
-                  break;
-                case GNSSENTRY_PHASE:
-                  frqObs->_phaseValid = true;
-                  frqObs->_phase      = gnssData.measdata[iSat][iEntry];
-                  if      (rnxType[0] == '1') {
-                    frqObs->_slipCounter = obs_slip_cnt_L1;
-                  }
-                  else if (rnxType[0] == '2') {
-                    frqObs->_slipCounter = obs_slip_cnt_L2;
-                  }
-                  else if (rnxType[0] == '5') {
-                    frqObs->_slipCounter = obs_slip_cnt_L5;
-                  }
-                  break;
-                case GNSSENTRY_DOPPLER: 
-                  frqObs->_dopplerValid = true;
-                  frqObs->_doppler      = gnssData.measdata[iSat][iEntry];
-                  break;
-                case GNSSENTRY_SNR:
-                  frqObs->_snrValid = true;
-                  frqObs->_snr      = gnssData.measdata[iSat][iEntry];
-                  break;
-                }
-              }
-              _obsList.push_back(obs);
-            }
-          }
-    
-          // GPS Ephemeris
-          // -------------
-          else if (rr == 1019) {
-            decoded = true;
-            t_ephGPS eph; eph.set(&parser.ephemerisGPS);
-            emit newGPSEph(eph);
-          }
-    
-          // GLONASS Ephemeris
-          // -----------------
-          else if (rr == 1020 && parser.ephemerisGLONASS.almanac_number >= 1 &&
-                                 parser.ephemerisGLONASS.almanac_number <= PRN_GLONASS_NUM) {
-            decoded = true;
-            t_ephGlo eph; eph.set(&parser.ephemerisGLONASS);
-            emit newGlonassEph(eph);
-          }
-
-          // Galileo Ephemeris
-          // -----------------
-          else if (rr == 1045 || rr == 1046) {
-            decoded = true;
-            t_ephGal eph; eph.set(&parser.ephemerisGALILEO);
-            emit newGalileoEph(eph);
-          }
-
-          // QZSS Ephemeris
-          // --------------
-          else if (rr == 1044) {
-            decoded = true;
-            t_ephGPS eph; eph.set(&parser.ephemerisGPS);
-            emit newGPSEph(eph);
-          }
-
-          // SBAS Ephemeris
-          // --------------
-          else if (rr == 1043) {
-            decoded = true;
-            t_ephSBAS eph; eph.set(&parser.ephemerisSBAS);
-            emit newSBASEph(eph);
-          }
-
-          // BDS Ephemeris
-          // -----------------
-          else if (rr == RTCM3ID_BDS) {
-            decoded = true;
-            t_ephBDS eph; eph.set(&parser.ephemerisBDS);
-            emit newBDSEph(eph);
+            CurrentObs._obs.push_back(frqObs);
           }
         }
       }
+      if(CurrentObs._obs.size() > 0)
+        _CurrentObsList.push_back(CurrentObs);
     }
-    if (!_rawFile && _mode == unknown && decoded) {
-      _mode = observations;
+  }
+  else if((type % 10) < 3)
+  {
+    emit(newMessage(QString("%1: Block %2 contain partial data! Ignored!")
+    .arg(_staID).arg(type).toAscii(), true));
+  }
+  if(!syncf)
+  {
+    decoded = true;
+    _obsList = _CurrentObsList;
+    _CurrentTime.reset();
+    _CurrentObsList.clear();
+  }
+  return decoded;
+}
+
+// 
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeRTCM3GLONASS(unsigned char* data, int size)
+{
+  bool decoded = false;
+  bncTime CurrentObsTime;
+  int i, numsats, syncf, type;
+  uint64_t numbits = 0, bitfield = 0;
+
+  data += 3; /* header */
+  size -= 6; /* header + crc */
+
+  GETBITS(type, 12)
+  SKIPBITS(12) /* id */
+  GETBITS(i,27) /* tk */
+
+  CurrentObsTime.setTk(i);
+  if(_CurrentTime.valid() && CurrentObsTime != _CurrentTime)
+  {
+    decoded = true;
+    _obsList = _CurrentObsList;
+    _CurrentObsList.clear();
+  }
+  _CurrentTime = CurrentObsTime;
+
+  GETBITS(syncf,1) /* sync */
+  GETBITS(numsats,5)
+  SKIPBITS(4) /* smind, smint */
+
+  while(numsats--)
+  {
+    int sv, code, l1range, amb=0, freq;
+    t_satObs CurrentObs;
+    CurrentObs._time = CurrentObsTime;
+
+    GETBITS(sv, 6)
+    CurrentObs._prn.set('R', sv);
+    GETBITS(code, 1)
+    GETBITS(freq, 5)
+    GLOFreq[sv-1] = 100+freq-7; /* store frequency for other users (MSM) */
+
+    t_frqObs *frqObs = new t_frqObs;
+    /* L1 */
+    frqObs->_rnxType2ch = code ? "1P" : "1C";
+    GETBITS(l1range, 25);
+    GETBITSSIGN(i, 20);
+    if((i&((1<<20)-1)) != 0x80000)
+    {
+      frqObs->_code = l1range*0.02;
+      frqObs->_phase = (l1range*0.02+i*0.0005)/GLO_WAVELENGTH_L1(freq-7);
+      frqObs->_codeValid = frqObs->_phaseValid = true;
     }
-  }
-
-  if (decoded) {
-    return success;
-  }
-  else {
-    return failure;
-  }
+    GETBITS(i, 7);
+    frqObs->_slipCounter = i;
+    if(type == 1010 || type == 1012)
+    {
+      GETBITS(amb,7);
+      if(amb)
+      {
+        frqObs->_code += amb*599584.916;
+        frqObs->_phase += (amb*599584.916)/GLO_WAVELENGTH_L1(freq-7);
+      }
+      GETBITS(i, 8);
+      if(i)
+      {
+        frqObs->_snr = i*0.25;
+        frqObs->_snrValid = true;
+      }
+    }
+    CurrentObs._obs.push_back(frqObs);
+    if(type == 1011 || type == 1012)
+    {
+      frqObs = new t_frqObs;
+      /* L2 */
+      GETBITS(code,2);
+      switch(code)
+      {
+      case 3: frqObs->_rnxType2ch = "2P"; break;
+      case 2: frqObs->_rnxType2ch = "2P"; break;
+      case 1: frqObs->_rnxType2ch = "2P"; break;
+      case 0: frqObs->_rnxType2ch = "2C"; break;
+      }
+      GETBITSSIGN(i,14);
+      if((i&((1<<14)-1)) != 0x2000)
+      {
+        frqObs->_code = l1range*0.02+i*0.02+amb*599584.916;
+        frqObs->_codeValid = true;
+      }
+      GETBITSSIGN(i,20);
+      if((i&((1<<20)-1)) != 0x80000)
+      {
+        frqObs->_phase = (l1range*0.02+i*0.0005+amb*599584.916)/GLO_WAVELENGTH_L2(freq-7);
+        frqObs->_phaseValid = true;
+      }
+      GETBITS(i,7);
+      frqObs->_slipCounter = i;
+      if(type == 1012)
+      {
+        GETBITS(i, 8);
+        if(i)
+        {
+          frqObs->_snr = i*0.25;
+          frqObs->_snrValid = true;
+        }
+      }
+      CurrentObs._obs.push_back(frqObs);
+    }
+    _CurrentObsList.push_back(CurrentObs);
+  }
+  if(!syncf)
+  {
+    decoded = true;
+    _obsList = _CurrentObsList;
+    _CurrentTime.reset();
+    _CurrentObsList.clear();
+  }
+  return decoded;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeGPSEphemeris(unsigned char* data, int size)
+{
+  bool decoded = false;
+
+  if(size == 67)
+  {
+    t_ephGPS eph;
+    int i, week;
+    uint64_t numbits = 0, bitfield = 0;
+
+    data += 3; /* header */
+    size -= 6; /* header + crc */
+    SKIPBITS(12)
+
+    eph._receptDateTime = currentDateAndTimeGPS();
+
+    GETBITS(i, 6)
+    eph._prn.set('G', i);
+    GETBITS(week, 10)
+    week += 1024;
+    GETBITS(i, 4)
+    eph._ura = accuracyFromIndex(i, eph.type());
+    GETBITS(eph._L2Codes, 2)
+    GETFLOATSIGN(eph._IDOT, 14, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETBITS(eph._IODE, 8)
+    GETBITS(i, 16)
+    i <<= 4;
+    eph._TOC.set(i*1000);
+    GETFLOATSIGN(eph._clock_driftrate, 8, 1.0/(double)(1<<30)/(double)(1<<25))
+    GETFLOATSIGN(eph._clock_drift, 16, 1.0/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._clock_bias, 22, 1.0/(double)(1<<30)/(double)(1<<1))
+    GETBITS(eph._IODC, 10)
+    GETFLOATSIGN(eph._Crs, 16, 1.0/(double)(1<<5))
+    GETFLOATSIGN(eph._Delta_n, 16, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._M0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Cuc, 16, 1.0/(double)(1<<29))
+    GETFLOAT(eph._e, 32, 1.0/(double)(1<<30)/(double)(1<<3))
+    GETFLOATSIGN(eph._Cus, 16, 1.0/(double)(1<<29))
+    GETFLOAT(eph._sqrt_A, 32, 1.0/(double)(1<<19))
+    GETBITS(i, 16)
+    i <<= 4;
+    eph._TOEsec = i;
+    bncTime t;
+    t.set(i*1000);
+    eph._TOEweek = t.gpsw();
+    /* week from HOW, differs from TOC, TOE week, we use adapted value instead */
+    if(eph._TOEweek > week + 1 || eph._TOEweek < week-1) /* invalid week */
+      return false;
+    GETFLOATSIGN(eph._Cic, 16, 1.0/(double)(1<<29))
+    GETFLOATSIGN(eph._OMEGA0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Cis, 16, 1.0/(double)(1<<29))
+    GETFLOATSIGN(eph._i0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Crc, 16, 1.0/(double)(1<<5))
+    GETFLOATSIGN(eph._omega, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._OMEGADOT, 24, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._TGD, 8, 1.0/(double)(1<<30)/(double)(1<<1))
+    GETBITS(eph._health, 6)
+    GETBITS(eph._L2PFlag, 1)
+    GETBITS(eph._fitInterval, 1)
+    eph._TOT = 0.9999e9;
+
+    emit newGPSEph(eph);
+    decoded = true;
+  }
+  return decoded;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeGLONASSEphemeris(unsigned char* data, int size)
+{
+  bool decoded = false;
+
+  if(size == 51)
+  {
+    t_ephGlo eph;
+    int sv, i, tk;
+    uint64_t numbits = 0, bitfield = 0;
+
+    data += 3; /* header */
+    size -= 6; /* header + crc */
+    SKIPBITS(12)
+
+    eph._receptDateTime = currentDateAndTimeGPS();
+
+    GETBITS(sv, 6)
+    eph._prn.set('R', sv);
+
+    GETBITS(i, 5)
+    eph._frequency_number = i-7;
+    GLOFreq[sv-1] = 100+i-7; /* store frequency for other users (MSM) */
+
+    SKIPBITS(4) /* almanac healthy, almanac health ok, P1 */
+    GETBITS(i, 5)
+    tk = i*60*60;
+    GETBITS(i, 6)
+    tk += i*60;
+    GETBITS(i, 1)
+    tk += i*30;
+    eph._tki = tk < 3*60*60 ? tk-3*60*60+86400 : tk-3*60*60;
+    GETBITS(eph._health, 1)
+    SKIPBITS(1) /* P2 */
+    GETBITS(i, 7)
+    eph._TOC.setTk(i*15*60*1000); /* tb */
+
+    GETFLOATSIGNM(eph._x_velocity, 24, 1.0/(double)(1<<20))
+    GETFLOATSIGNM(eph._x_pos, 27, 1.0/(double)(1<<11))
+    GETFLOATSIGNM(eph._x_acceleration, 5, 1.0/(double)(1<<30))
+    GETFLOATSIGNM(eph._y_velocity, 24, 1.0/(double)(1<<20))
+    GETFLOATSIGNM(eph._y_pos, 27, 1.0/(double)(1<<11))
+    GETFLOATSIGNM(eph._y_acceleration, 5, 1.0/(double)(1<<30))
+    GETFLOATSIGNM(eph._z_velocity, 24, 1.0/(double)(1<<20))
+    GETFLOATSIGNM(eph._z_pos, 27, 1.0/(double)(1<<11))
+    GETFLOATSIGNM(eph._z_acceleration, 5, 1.0/(double)(1<<30))
+    SKIPBITS(1) /* P3 */
+    GETFLOATSIGNM(eph._gamma, 11, 1.0/(double)(1<<30)/(double)(1<<10))
+    SKIPBITS(3) /* GLONASS-M P, GLONASS-M ln (third string) */
+    GETFLOATSIGNM(eph._tau, 22, 1.0/(double)(1<<30)) /* GLONASS tau n(tb) */
+    SKIPBITS(5) /* GLONASS-M delta tau n(tb) */
+    GETBITS(eph._E, 5)
+    /* GETBITS(i, 1) / * GLONASS-M P4 */
+    /* GETBITS(i, 4) / * GLONASS-M Ft */
+    /* GETBITS(i, 11) / * GLONASS-M Nt */
+    /* GETBITS(i, 2) / * GLONASS-M M */
+    /* GETBITS(i, 1) / * GLONASS-M The Availability of Additional Data */
+    /* GETBITS(i, 11) / * GLONASS-M Na */
+    /* GETFLOATSIGNM(i, 32, 1.0/(double)(1<<30)/(double)(1<<1)) / * GLONASS tau c */
+    /* GETBITS(i, 5) / * GLONASS-M N4 */
+    /* GETFLOATSIGNM(i, 22, 1.0/(double)(1<<30)) / * GLONASS-M tau GPS */
+    /* GETBITS(i, 1) / * GLONASS-M ln (fifth string) */
+
+    unsigned year, month, day;
+    eph._TOC.civil_date(year, month, day);
+    eph._gps_utc = gnumleap(year, month, day);
+    eph._tt = eph._TOC;
+
+    eph._xv(1) = eph._x_pos * 1.e3; 
+    eph._xv(2) = eph._y_pos * 1.e3; 
+    eph._xv(3) = eph._z_pos * 1.e3; 
+    eph._xv(4) = eph._x_velocity * 1.e3; 
+    eph._xv(5) = eph._y_velocity * 1.e3; 
+    eph._xv(6) = eph._z_velocity * 1.e3; 
+
+    emit newGlonassEph(eph);
+    decoded = true;
+  }
+  return decoded;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeQZSSEphemeris(unsigned char* data, int size)
+{
+  bool decoded = false;
+
+  if(size == 67)
+  {
+    t_ephGPS eph;
+    int i, week;
+    uint64_t numbits = 0, bitfield = 0;
+
+    data += 3; /* header */
+    size -= 6; /* header + crc */
+    SKIPBITS(12)
+
+    eph._receptDateTime = currentDateAndTimeGPS();
+
+    GETBITS(i, 4)
+    eph._prn.set('J', i);
+
+    GETBITS(i, 16)
+    i <<= 4;
+    eph._TOC.set(i*1000);
+
+    GETFLOATSIGN(eph._clock_driftrate, 8, 1.0/(double)(1<<30)/(double)(1<<25))
+    GETFLOATSIGN(eph._clock_drift, 16, 1.0/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._clock_bias, 22, 1.0/(double)(1<<30)/(double)(1<<1))
+    GETBITS(eph._IODE, 8)
+    GETFLOATSIGN(eph._Crs, 16, 1.0/(double)(1<<5))
+    GETFLOATSIGN(eph._Delta_n, 16, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._M0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Cuc, 16, 1.0/(double)(1<<29))
+    GETFLOAT(eph._e, 32, 1.0/(double)(1<<30)/(double)(1<<3))
+    GETFLOATSIGN(eph._Cus, 16, 1.0/(double)(1<<29))
+    GETFLOAT(eph._sqrt_A, 32, 1.0/(double)(1<<19))
+    GETBITS(i, 16)
+    i <<= 4;
+    eph._TOEsec = i;
+    bncTime t;
+    t.set(i);
+
+    GETFLOATSIGN(eph._Cic, 16, 1.0/(double)(1<<29))
+    GETFLOATSIGN(eph._OMEGA0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Cis, 16, 1.0/(double)(1<<29))
+    GETFLOATSIGN(eph._i0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Crc, 16, 1.0/(double)(1<<5))
+    GETFLOATSIGN(eph._omega, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._OMEGADOT, 24, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._IDOT, 14, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETBITS(eph._L2Codes, 2)
+    GETBITS(week, 10)
+    week += 1024;
+    eph._TOEweek = t.gpsw();
+    /* week from HOW, differs from TOC, TOE week, we use adapted value instead */
+    if(eph._TOEweek > week + 1 || eph._TOEweek < week-1) /* invalid week */
+      return false;
+
+    GETBITS(i, 4)
+    if(i <= 6)
+      eph._ura = ceil(10.0*pow(2.0, 1.0+i/2.0))/10.0;
+    else
+      eph._ura = ceil(10.0*pow(2.0, i/2.0))/10.0;
+    GETBITS(eph._health, 6)
+    GETFLOATSIGN(eph._TGD, 8, 1.0/(double)(1<<30)/(double)(1<<1))
+    GETBITS(eph._IODC, 10)
+    GETBITS(eph._fitInterval, 1)
+    eph._TOT = 0.9999e9;
+    eph._L2PFlag = 0; /* does not exist for QZSS */
+
+    emit newGPSEph(eph);
+    decoded = true;
+  }
+  return decoded;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeSBASEphemeris(unsigned char* data, int size)
+{
+  bool decoded = false;
+
+  if(size == 35)
+  {
+    t_ephSBAS eph;
+    int i;
+    uint64_t numbits = 0, bitfield = 0;
+
+    data += 3; /* header */
+    size -= 6; /* header + crc */
+    SKIPBITS(12)
+
+    eph._receptDateTime = currentDateAndTimeGPS();
+
+    GETBITS(i, 6)
+    eph._prn.set('S', 20+i);
+    GETBITS(eph._IODN, 8)
+    GETBITS(i, 13)
+    i <<= 4;
+    eph._TOC.setTOD(i*1000);
+    GETBITS(i, 4)
+    eph._ura = accuracyFromIndex(i, eph.type());
+    GETFLOATSIGN(eph._x_pos, 30, 0.08)
+    GETFLOATSIGN(eph._y_pos, 30, 0.08)
+    GETFLOATSIGN(eph._z_pos, 25, 0.4)
+    GETFLOATSIGN(eph._x_velocity, 17, 0.000625)
+    GETFLOATSIGN(eph._y_velocity, 17, 0.000625)
+    GETFLOATSIGN(eph._z_velocity, 18, 0.004)
+    GETFLOATSIGN(eph._x_acceleration, 10, 0.0000125)
+    GETFLOATSIGN(eph._y_acceleration, 10, 0.0000125)
+    GETFLOATSIGN(eph._z_acceleration, 10, 0.0000625)
+    GETFLOATSIGN(eph._agf0, 12, 1.0/(1<<30)/(1<<1))
+    GETFLOATSIGN(eph._agf1, 8, 1.0/(1<<30)/(1<<10))
+
+    eph._TOW = 0.9999E9;
+    eph._health = 0;
+
+    emit newSBASEph(eph);
+    decoded = true;
+  }
+  return decoded;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeGalileoEphemeris(unsigned char* data, int size)
+{
+  bool decoded = false;
+  uint64_t numbits = 0, bitfield = 0;
+  int i;
+
+  data += 3; /* header */
+  size -= 6; /* header + crc */
+  GETBITS(i, 12)
+
+  if((i == 1046 && size == 61) || (i == 1045 && size == 60))
+  {
+    t_ephGal eph;
+
+    eph._receptDateTime = currentDateAndTimeGPS();
+
+    eph._inav = (i == 1046);
+    eph._fnav = (i == 1045);
+    GETBITS(i, 6)
+    eph._prn.set('E', i, eph._inav ? 1 : 0);
+
+    GETBITS(eph._TOEweek, 12)
+    GETBITS(eph._IODnav, 10)
+    GETBITS(i, 8)
+    eph._SISA = accuracyFromIndex(i, eph.type());
+    GETFLOATSIGN(eph._IDOT, 14, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETBITSFACTOR(i, 14, 60)
+    eph._TOC.set(eph._TOEweek, i);
+    GETFLOATSIGN(eph._clock_driftrate, 6, 1.0/(double)(1<<30)/(double)(1<<29))
+    GETFLOATSIGN(eph._clock_drift, 21, 1.0/(double)(1<<30)/(double)(1<<16))
+    GETFLOATSIGN(eph._clock_bias, 31, 1.0/(double)(1<<30)/(double)(1<<4))
+    GETFLOATSIGN(eph._Crs, 16, 1.0/(double)(1<<5))
+    GETFLOATSIGN(eph._Delta_n, 16, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._M0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Cuc, 16, 1.0/(double)(1<<29))
+    GETFLOAT(eph._e, 32, 1.0/(double)(1<<30)/(double)(1<<3))
+    GETFLOATSIGN(eph._Cus, 16, 1.0/(double)(1<<29))
+    GETFLOAT(eph._sqrt_A, 32, 1.0/(double)(1<<19))
+    GETBITSFACTOR(eph._TOEsec, 14, 60)
+    /* FIXME: overwrite value, copied from old code */
+    eph._TOEsec = eph._TOC.gpssec();
+    GETFLOATSIGN(eph._Cic, 16, 1.0/(double)(1<<29))
+    GETFLOATSIGN(eph._OMEGA0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Cis, 16, 1.0/(double)(1<<29))
+    GETFLOATSIGN(eph._i0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Crc, 16, 1.0/(double)(1<<5))
+    GETFLOATSIGN(eph._omega, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._OMEGADOT, 24, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._BGD_1_5A, 10, 1.0/(double)(1<<30)/(double)(1<<2))
+    if(eph._inav)
+    {
+      /* set usused F/NAV values */
+      eph._E5aHS = 0.0;
+      eph._e5aDataInValid = false;
+
+      GETFLOATSIGN(eph._BGD_1_5B, 10, 1.0/(double)(1<<30)/(double)(1<<2))
+      GETBITS(eph._E5bHS, 2)
+      GETBITS(eph._e5bDataInValid, 1)
+      GETBITS(eph._E1_bHS, 2)
+      GETBITS(eph._e1DataInValid, 1)
+    }
+    else
+    {
+      /* set usused I/NAV values */
+      eph._BGD_1_5B = 0.0;
+      eph._E5bHS = 0.0;
+      eph._E1_bHS = 0.0;
+      eph._e1DataInValid = false;
+      eph._e5bDataInValid = false;
+
+      GETBITS(eph._E5aHS, 2)
+      GETBITS(eph._e5aDataInValid, 1)
+    }
+    eph._TOT = 0.9999e9;
+
+    emit newGalileoEph(eph);
+    decoded = true;
+  }
+  return decoded;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeBDSEphemeris(unsigned char* data, int size)
+{
+  bool decoded = false;
+
+  if(size == 70)
+  {
+    t_ephBDS eph;
+    int i;
+    uint64_t numbits = 0, bitfield = 0;
+
+    data += 3; /* header */
+    size -= 6; /* header + crc */
+    SKIPBITS(12)
+
+    eph._receptDateTime = currentDateAndTimeGPS();
+
+    GETBITS(i, 6)
+    eph._prn.set('C', i);
+
+    SKIPBITS(13) /* week */
+    GETBITS(i, 4)
+    eph._URA = accuracyFromIndex(i, eph.type());
+    GETFLOATSIGN(eph._IDOT, 14, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETBITS(eph._AODE, 5)
+    GETBITS(i, 17)
+    i <<= 3;
+    eph._TOC.setBDS(i*1000);
+    GETFLOATSIGN(eph._clock_driftrate, 11, 1.0/(double)(1<<30)/(double)(1<<30)/(double)(1<<6))
+    GETFLOATSIGN(eph._clock_drift, 22, 1.0/(double)(1<<30)/(double)(1<<20))
+    GETFLOATSIGN(eph._clock_bias, 24, 1.0/(double)(1<<30)/(double)(1<<3))
+    GETBITS(eph._AODC, 5)
+    GETFLOATSIGN(eph._Crs, 18, 1.0/(double)(1<<6))
+    GETFLOATSIGN(eph._Delta_n, 16, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._M0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Cuc, 18, 1.0/(double)(1<<30)/(double)(1<<1))
+    GETFLOAT(eph._e, 32, 1.0/(double)(1<<30)/(double)(1<<3))
+    GETFLOATSIGN(eph._Cus, 18, 1.0/(double)(1<<30)/(double)(1<<1))
+    GETFLOAT(eph._sqrt_A, 32, 1.0/(double)(1<<19))
+    GETBITS(i, 17)
+    i <<= 3;
+    eph._TOEsec = i;
+    eph._TOE.setBDS(i*1000);
+    GETFLOATSIGN(eph._Cic, 18, 1.0/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._OMEGA0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Cis, 18, 1.0/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._i0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._Crc, 18, 1.0/(double)(1<<6))
+    GETFLOATSIGN(eph._omega, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
+    GETFLOATSIGN(eph._OMEGADOT, 24, R2R_PI/(double)(1<<30)/(double)(1<<13))
+    GETFLOATSIGN(eph._TGD1, 10, 0.0000000001)
+    GETFLOATSIGN(eph._TGD2, 10, 0.0000000001)
+    GETBITS(eph._SatH1, 1)
+
+    eph._TOW = 0.9999E9;
+    emit newBDSEph(eph);
+    decoded = true;
+  }
+  return decoded;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeAntenna(unsigned char* data, int size)
+{
+  char *antenna;
+  int antnum;
+  uint64_t numbits = 0, bitfield = 0;
+
+  data += 3; /* header */
+  size -= 6; /* header + crc */
+
+  SKIPBITS(12)
+  GETSTRING(antnum,antenna)
+  _antType.push_back(antenna);
+
+  return true;
+}
+
+//
+////////////////////////////////////////////////////////////////////////////
+bool RTCM3Decoder::DecodeAntennaPosition(unsigned char* data, int size)
+{
+  int type;
+  uint64_t numbits = 0, bitfield = 0;
+  double x, y, z;
+
+  data += 3; /* header */
+  size -= 6; /* header + crc */
+
+  GETBITS(type, 12)
+  _antList.push_back(t_antInfo());
+  _antList.back().type = t_antInfo::ARP;
+  SKIPBITS(22)
+  GETBITSSIGN(x, 38)
+  _antList.back().xx = x * 1e-4;
+  SKIPBITS(2)
+  GETBITSSIGN(y, 38)
+  _antList.back().yy = y * 1e-4;
+  SKIPBITS(2)
+  GETBITSSIGN(z, 38)
+  _antList.back().zz = z * 1e-4;
+  if(type == 1006)
+  {
+    double h;
+    GETBITS(h, 16)
+    _antList.back().height = h * 1e-4;
+    _antList.back().height_f = true;
+  }
+  _antList.back().message  = type;
+
+  return true;
+}
+
+// 
+////////////////////////////////////////////////////////////////////////////
+t_irc RTCM3Decoder::Decode(char* buffer, int bufLen, vector<string>& errmsg)
+{
+  bool decoded = false;
+
+  errmsg.clear();
+
+  while(bufLen && _MessageSize < sizeof(_Message))
+  {
+    int l = sizeof(_Message) - _MessageSize;
+    if(l > bufLen)
+      l = bufLen;
+    memcpy(_Message+_MessageSize, buffer, l);
+    _MessageSize += l;
+    bufLen -= l;
+    buffer += l;
+    int id;
+    while((id = GetMessage()))
+    {
+      /* reset station ID for file loading as it can change */
+      if(_rawFile)
+        _staID = _rawFile->staID();
+      /* store the id into the list of loaded blocks */
+      _typeList.push_back(id);
+
+      /* Clock and orbit data handled in another function, already pass the
+       * extracted data block. That does no harm, as it anyway skip everything
+       * else. */
+      if((id >= 1057 && id <= 1068) || (id >= 1240 && id <= 1263))
+      {
+        if (!_coDecoders.contains(_staID.toAscii()))
+          _coDecoders[_staID.toAscii()] = new RTCM3coDecoder(_staID); 
+        RTCM3coDecoder* coDecoder = _coDecoders[_staID.toAscii()];
+        if(coDecoder->Decode(reinterpret_cast<char *>(_Message), _BlockSize,
+        errmsg) == success)
+        {
+          decoded = true;
+        }
+      }
+      else if(id >= 1070 && id <= 1229) /* MSM */
+      {
+        if(DecodeRTCM3MSM(_Message, _BlockSize))
+          decoded = true;
+      }
+      else
+      {
+        switch(id)
+        {
+        case 1001: case 1003:
+          emit(newMessage(QString("%1: Block %2 contain partial data! Ignored!")
+          .arg(_staID).arg(id).toAscii(), true));
+          break; /* no use decoding partial data ATM, remove break when data can be used */
+        case 1002: case 1004:
+          if(DecodeRTCM3GPS(_Message, _BlockSize))
+            decoded = true;
+          break;
+        case 1009: case 1011:
+          emit(newMessage(QString("%1: Block %2 contain partial data! Ignored!")
+          .arg(_staID).arg(id).toAscii(), true));
+          break; /* no use decoding partial data ATM, remove break when data can be used */
+        case 1010: case 1012:
+          if(DecodeRTCM3GLONASS(_Message, _BlockSize))
+            decoded = true;
+          break;
+        case 1019:
+          if(DecodeGPSEphemeris(_Message, _BlockSize))
+            decoded = true;
+          break;
+        case 1020:
+          if(DecodeGLONASSEphemeris(_Message, _BlockSize))
+            decoded = true;
+          break;
+        case 1043:
+          if(DecodeSBASEphemeris(_Message, _BlockSize))
+            decoded = true;
+          break;
+        case 1044:
+          if(DecodeQZSSEphemeris(_Message, _BlockSize))
+            decoded = true;
+          break;
+        case 1045: case 1046:
+          if(DecodeGalileoEphemeris(_Message, _BlockSize))
+            decoded = true;
+          break;
+        case RTCM3ID_BDS:
+          if(DecodeBDSEphemeris(_Message, _BlockSize))
+            decoded = true;
+          break;
+        case 1007: case 1008: case 1033:
+          DecodeAntenna(_Message, _BlockSize);
+          break;
+        case 1005: case 1006:
+          DecodeAntennaPosition(_Message, _BlockSize);
+          break;
+        }
+      }
+    }
+  }
+  return decoded ? success : failure;
+};
+
+// 
+////////////////////////////////////////////////////////////////////////////
+uint32_t RTCM3Decoder::CRC24(long size, const unsigned char *buf)
+{
+  uint32_t crc = 0;
+  int i;
+
+  while(size--)
+  {
+    crc ^= (*buf++) << (16);
+    for(i = 0; i < 8; i++)
+    {
+      crc <<= 1;
+      if(crc & 0x1000000)
+        crc ^= 0x01864cfb;
+    }
+  }
+  return crc;
+}
+
+// 
+////////////////////////////////////////////////////////////////////////////
+int RTCM3Decoder::GetMessage(void)
+{
+  unsigned char *m, *e;
+  int i;
+
+  m = _Message+_SkipBytes;
+  e = _Message+_MessageSize;
+  _NeedBytes = _SkipBytes = 0;
+  while(e-m >= 3)
+  {
+    if(m[0] == 0xD3)
+    {
+      _BlockSize = ((m[1]&3)<<8)|m[2];
+      if(e-m >= static_cast<int>(_BlockSize+6))
+      {
+        if(static_cast<uint32_t>((m[3+_BlockSize]<<16)|(m[3+_BlockSize+1]<<8)
+        |(m[3+_BlockSize+2])) == CRC24(_BlockSize+3, m))
+        {
+          _BlockSize +=6;
+          _SkipBytes = _BlockSize;
+          break;
+        }
+        else
+          ++m;
+      }
+      else
+      {
+        _NeedBytes = _BlockSize;
+        break;
+      }
+    }
+    else
+      ++m;
+  }
+  if(e-m < 3)
+    _NeedBytes = 3;
+
+  /* copy buffer to front */
+  i = m - _Message;
+  if(i && m < e)
+    memmove(_Message, m, static_cast<size_t>(_MessageSize-i));
+  _MessageSize -= i;
+
+  return !_NeedBytes ? ((_Message[3]<<4)|(_Message[4]>>4)) : 0;
 }
 
@@ -438,9 +1613,4 @@
 //////////////////////////////////////////////////////////////////////////////
 int RTCM3Decoder::corrGPSEpochTime() const {
-  if (_mode == corrections && _coDecoders.size() > 0) {
-    return _coDecoders.begin().value()->corrGPSEpochTime();
-  }
-  else {
-    return -1;
-  }
+  return _coDecoders.size() > 0 ? _coDecoders.begin().value()->corrGPSEpochTime() : -1;
 }
Index: trunk/BNC/src/RTCM3/RTCM3Decoder.h
===================================================================
--- trunk/BNC/src/RTCM3/RTCM3Decoder.h	(revision 6809)
+++ trunk/BNC/src/RTCM3/RTCM3Decoder.h	(revision 6812)
@@ -29,12 +29,9 @@
 #include <map>
 
+#include <stdint.h>
 #include "GPSDecoder.h"
 #include "RTCM3coDecoder.h"
 #include "bncrawfile.h"
 #include "ephemeris.h"
-
-extern "C" {
-#include "rtcm3torinex.h"
-}
 
 class RTCM3Decoder : public QObject, public GPSDecoder {
@@ -45,4 +42,11 @@
   virtual t_irc Decode(char* buffer, int bufLen, std::vector<std::string>& errmsg);
   virtual int corrGPSEpochTime() const;
+  /**
+   * CRC24Q checksum calculation function (only full bytes supported).
+   * @param size Size of the passed data
+   * @param buf Data buffer containing the data to checksum
+   * @return the CRC24Q checksum of the data
+   */
+  static uint32_t CRC24(long size, const unsigned char *buf);
 
  signals:
@@ -55,18 +59,134 @@
 
  private:
-  enum t_mode{unknown = 0, observations, corrections};
+  /**
+   * Extract a RTCM3 message. Data is passed in the follow fields:<br>
+   * {@link _Message}: contains the message bytes<br>
+   * {@link _MessageSize}: contains to current amount of bytes in the buffer<br>
+   * {@link _SkipBytes}: amount of bytes to skip at the beginning of the buffer
+   * 
+   * The functions sets following variables:<br>
+   * {@link _NeedBytes}: Minimum number of bytes needed on next call<br>
+   * {@link _SkipBytes}: internal, Bytes to skip before next call (usually the amount of
+   *   found bytes)<br>
+   * {@link _MessageSize}: Updated size after processed bytes have been removed from buffer
+   * @return message number when message found, 0 otherwise
+   */
+  int GetMessage(void);
+  /**
+   * Extract data from old 1001-1004 RTCM3 messages.
+   * @param buffer the buffer containing an 1001-1004 RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block is finished and transfered into
+   * {@link GPSDecoder::_obsList} variable
+   * @see DecodeRTCM3GLONASS()
+   * @see DecodeRTCM3MSM()
+   */
+  bool DecodeRTCM3GPS(unsigned char* buffer, int bufLen);
+  /**
+   * Extract data from old 1009-1012 RTCM3 messages.
+   * @param buffer the buffer containing an 1009-1012 RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block is finished and transfered into
+   * {@link GPSDecoder::_obsList} variable
+   * @see DecodeRTCM3GPS()
+   * @see DecodeRTCM3MSM()
+   */
+  bool DecodeRTCM3GLONASS(unsigned char* buffer, int bufLen);
+  /**
+   * Extract data from MSM 1070-1229 RTCM3 messages.
+   * @param buffer the buffer containing an 1070-1229 RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block is finished and transfered into
+   * {@link GPSDecoder::_obsList} variable
+   * @see DecodeRTCM3GPS()
+   * @see DecodeRTCM3GLONASS()
+   */
+  bool DecodeRTCM3MSM(unsigned char* buffer, int bufLen);
+  /**
+   * Extract ephemeris data from 1019 RTCM3 messages.
+   * @param buffer the buffer containing an 1019 RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block was decodable
+   */
+  bool DecodeGPSEphemeris(unsigned char* buffer, int bufLen);
+  /**
+   * Extract ephemeris data from 1020 RTCM3 messages.
+   * @param buffer the buffer containing an 1020 RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block was decodable
+   */
+  bool DecodeGLONASSEphemeris(unsigned char* buffer, int bufLen);
+  /**
+   * Extract ephemeris data from 1043 RTCM3 messages.
+   * @param buffer the buffer containing an 1043 RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block was decodable
+   */
+  bool DecodeSBASEphemeris(unsigned char* buffer, int bufLen);
+  /**
+   * Extract ephemeris data from 1044 RTCM3 messages.
+   * @param buffer the buffer containing an 1044 RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block was decodable
+   */
+  bool DecodeQZSSEphemeris(unsigned char* buffer, int bufLen);
+  /**
+   * Extract ephemeris data from 1045 and 1046 RTCM3 messages.
+   * @param buffer the buffer containing an 1045 and 1046 RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block was decodable
+   */
+  bool DecodeGalileoEphemeris(unsigned char* buffer, int bufLen);
+  /**
+   * Extract ephemeris data from BDS RTCM3 messages.
+   * @param buffer the buffer containing an BDS RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block was decodable
+   */
+  bool DecodeBDSEphemeris(unsigned char* buffer, int bufLen);
+  /**
+   * Extract antenna type from 1007, 1008 or 1033 RTCM3 messages.
+   * @param buffer the buffer containing an antenna RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block was decodable
+   */
+  bool DecodeAntenna(unsigned char* buffer, int bufLen);
+  /**
+   * Extract antenna type from 1005 or 1006 RTCM3 messages.
+   * @param buffer the buffer containing an antenna RTCM block
+   * @param bufLen the length of the buffer (the message length including header+crc)
+   * @return <code>true</code> when data block was decodable
+   */
+  bool DecodeAntennaPosition(unsigned char* buffer, int bufLen);
 
+  /** Current station description, dynamic in case of raw input file handling */
   QString                _staID;
-  QString                _checkMountPoint;
-  QMap<QByteArray, RTCM3ParserData> _parsers;
-  QMap<QByteArray, RTCM3coDecoder*> _coDecoders; 
-  t_mode                 _mode;
-
-  double                 _antXYZ[3];
+  /** Raw input file for post processing, required to extract station ID */
   bncRawFile*            _rawFile;
 
-  QMap<QString, int>  _slip_cnt_L1;
-  QMap<QString, int>  _slip_cnt_L2;
-  QMap<QString, int>  _slip_cnt_L5;
+  /** List of decoders for Clock and Orbit data */
+  QMap<QByteArray, RTCM3coDecoder*> _coDecoders; 
+
+  /** Message buffer for input parsing */
+  unsigned char _Message[2048];
+  /** Current size of the message buffer */
+  size_t _MessageSize;
+  /** Minimum bytes required to have success during next {@link GetMessage()} call */
+  size_t _NeedBytes;
+  /** Bytes to skip in next {@link GetMessage()} call, intrnal to that function */
+  size_t _SkipBytes;
+  /** Size of the current RTCM3 block beginning at buffer start after a successful
+   *  {@link GetMessage()} call
+   */
+  size_t _BlockSize;
+
+  /**
+   * Current observation epoch. Used to link together blocks in one epoch.
+   */
+  bncTime _CurrentTime;
+  /** Current observation data block list, Filled by {@link DecodeRTCM3GPS()},
+   * {@link DecodeRTCM3GLONASS()} and {@link DecodeRTCM3MSM()} functions.
+   */
+  QList<t_satObs> _CurrentObsList;
 };
 
Index: trunk/BNC/src/RTCM3/RTCM3coDecoder.cpp
===================================================================
--- trunk/BNC/src/RTCM3/RTCM3coDecoder.cpp	(revision 6809)
+++ trunk/BNC/src/RTCM3/RTCM3coDecoder.cpp	(revision 6812)
@@ -47,5 +47,4 @@
 #include "bnccore.h"
 #include "bncsettings.h"
-#include "rtcm3torinex.h"
 #include "bnctime.h"
 
Index: trunk/BNC/src/RTCM3/bits.h
===================================================================
--- trunk/BNC/src/RTCM3/bits.h	(revision 6812)
+++ trunk/BNC/src/RTCM3/bits.h	(revision 6812)
@@ -0,0 +1,123 @@
+// Part of BNC, a utility for retrieving decoding and
+// converting GNSS data streams from NTRIP broadcasters.
+//
+// Copyright (C) 2015
+// German Federal Agency for Cartography and Geodesy (BKG)
+// http://www.bkg.bund.de
+// Alberding GmbH
+// http://www.alberding.eu
+//
+// 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.
+
+#ifndef BITS_H
+#define BITS_H
+
+#define LOADBITS(a) \
+{ \
+  while((a) > numbits) \
+  { \
+    if(!size--) return false; \
+    bitfield = (bitfield<<8)|*(data++); \
+    numbits += 8; \
+  } \
+}
+
+/* extract bits from data stream
+   b = variable to store result, a = number of bits */
+#define GETBITS64(b, a) \
+{ \
+  if(((a) > 56) && ((a)-56) > numbits) \
+  { \
+    uint64_t x; \
+    GETBITS(x, 56) \
+    LOADBITS((a)-56) \
+    b = ((x<<((a)-56)) | (bitfield<<(sizeof(bitfield)*8-numbits)) \
+    >>(sizeof(bitfield)*8-((a)-56))); \
+    numbits -= ((a)-56); \
+  } \
+  else \
+  { \
+    GETBITS(b, a) \
+  } \
+}
+
+/* extract bits from data stream
+   b = variable to store result, a = number of bits */
+#define GETBITS(b, a) \
+{ \
+  LOADBITS(a) \
+  b = (bitfield<<(64-numbits))>>(64-(a)); \
+  numbits -= (a); \
+}
+
+/* extract bits from data stream
+   b = variable to store result, a = number of bits */
+#define GETBITSFACTOR(b, a, c) \
+{ \
+  LOADBITS(a) \
+  b = ((bitfield<<(sizeof(bitfield)*8-numbits))>>(sizeof(bitfield)*8-(a)))*(c); \
+  numbits -= (a); \
+}
+
+/* extract floating value from data stream
+   b = variable to store result, a = number of bits */
+#define GETFLOAT(b, a, c) \
+{ \
+  LOADBITS(a) \
+  b = ((double)((bitfield<<(64-numbits))>>(64-(a))))*(c); \
+  numbits -= (a); \
+}
+
+/* extract signed floating value from data stream
+   b = variable to store result, a = number of bits */
+#define GETFLOATSIGN(b, a, c) \
+{ \
+  LOADBITS(a) \
+  b = ((double)(((int64_t)(bitfield<<(64-numbits)))>>(64-(a))))*(c); \
+  numbits -= (a); \
+}
+
+/* extract bits from data stream
+   b = variable to store result, a = number of bits */
+#define GETBITSSIGN(b, a) \
+{ \
+  LOADBITS(a) \
+  b = ((int64_t)(bitfield<<(64-numbits)))>>(64-(a)); \
+  numbits -= (a); \
+}
+
+#define GETFLOATSIGNM(b, a, c) \
+{ int l; \
+  LOADBITS(a) \
+  l = (bitfield<<(64-numbits))>>(64-1); \
+  b = ((double)(((bitfield<<(64-(numbits-1))))>>(64-(a-1))))*(c); \
+  numbits -= (a); \
+  if(l) b *= -1.0; \
+}
+
+#define SKIPBITS(b) { LOADBITS(b) numbits -= (b); }
+
+/* extract byte-aligned byte from data stream,
+   b = variable to store size, s = variable to store string pointer */
+#define GETSTRING(b, s) \
+{ \
+  b = *(data++); \
+  s = (char *) data; \
+  data += b; \
+  size -= b+1; \
+}
+
+#endif /* BITS_H */
Index: trunk/BNC/src/RTCM3/ephEncoder.cpp
===================================================================
--- trunk/BNC/src/RTCM3/ephEncoder.cpp	(revision 6809)
+++ trunk/BNC/src/RTCM3/ephEncoder.cpp	(revision 6812)
@@ -1,8 +1,4 @@
 
 #include "ephEncoder.h"
-
-extern "C" {
-#  include "rtcm3torinex.h"
-}
 
 using namespace std;
@@ -47,10 +43,5 @@
   eph._ura = indexFromAccuracy(eph._ura, eph.type());
   GPSADDBITS(12, 1019)
-  if (eph._prn.system() == 'J') {
-    GPSADDBITS(6,eph._prn.number() + PRN_QZSS_START - 1)
-  }
-  else {
-    GPSADDBITS(6,eph._prn.number())
-  }
+  GPSADDBITS(6,eph._prn.number())
   GPSADDBITS(10, eph._TOC.gpsw())
   GPSADDBITS(4, eph._ura)
@@ -210,6 +201,5 @@
   eph._SISA = indexFromAccuracy(eph._SISA, eph.type());
 
-  bool inav = ( (eph._flags & GALEPHF_INAV) == GALEPHF_INAV );
-  GALILEOADDBITS(12, inav ? 1046 : 1045)
+  GALILEOADDBITS(12, eph._inav ? 1046 : 1045)
   GALILEOADDBITS(6, eph._prn.number())
   GALILEOADDBITS(12, eph._TOC.gpsw())
@@ -246,20 +236,20 @@
   GALILEOADDBITSFLOAT(10, eph._BGD_1_5A, 1.0/static_cast<double>(1<<30)
   /static_cast<double>(1<<2))
-  if(inav)
+  if(eph._inav)
   {
     GALILEOADDBITSFLOAT(10, eph._BGD_1_5B, 1.0/static_cast<double>(1<<30)
     /static_cast<double>(1<<2))
     GALILEOADDBITS(2, static_cast<int>(eph._E5bHS))
-    GALILEOADDBITS(1, eph._flags & GALEPHF_E5BDINVALID)
+    GALILEOADDBITS(1, eph._e5bDataInValid ? 1 : 0)
   }
   else
   {
     GALILEOADDBITS(2, static_cast<int>(eph._E5aHS))
-    GALILEOADDBITS(1, eph._flags & GALEPHF_E5ADINVALID)
+    GALILEOADDBITS(1,  eph._e5aDataInValid ? 1 : 0)
   }
   ////  eph._TOEsec = 0.9999E9;
   GALILEOADDBITS(20, eph._TOEsec)
 
-  GALILEOADDBITS((inav ? 1 : 3), 0)
+  GALILEOADDBITS((eph._inav ? 1 : 3), 0)
 
   startbuffer[0]=0xD3;
@@ -345,9 +335,9 @@
   BDSADDBITS(12, RTCM3ID_BDS)
   BDSADDBITS(6, eph._prn.number())
-  BDSADDBITS(13, eph._TOC_bdt.gpsw() - 1356.0)
+  BDSADDBITS(13, eph._TOC.bdsw() - 1356.0)
   BDSADDBITS(4, eph._URA);
   BDSADDBITSFLOAT(14, eph._IDOT, M_PI/static_cast<double>(1<<30)/static_cast<double>(1<<13))
   BDSADDBITS(5, eph._AODE)
-  BDSADDBITS(17, static_cast<int>(eph._TOC_bdt.gpssec())>>3)
+  BDSADDBITS(17, static_cast<int>(eph._TOC.bdssec())>>3)
   BDSADDBITSFLOAT(11, eph._clock_driftrate, 1.0/static_cast<double>(1<<30)
       /static_cast<double>(1<<30)/static_cast<double>(1<<6))
@@ -362,5 +352,5 @@
   BDSADDBITSFLOAT(18, eph._Cus, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<1))
   BDSADDBITSFLOAT(32, eph._sqrt_A, 1.0/static_cast<double>(1<<19))
-  BDSADDBITS(17, static_cast<int>(eph._TOE_bdt.gpssec())>>3)
+  BDSADDBITS(17, static_cast<int>(eph._TOE.bdssec())>>3)
   BDSADDBITSFLOAT(18, eph._Cic, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<1))
   BDSADDBITSFLOAT(32, eph._OMEGA0, M_PI/static_cast<double>(1<<30)/static_cast<double>(1<<1))
Index: trunk/BNC/src/RTCM3/gnss.h
===================================================================
--- trunk/BNC/src/RTCM3/gnss.h	(revision 6812)
+++ trunk/BNC/src/RTCM3/gnss.h	(revision 6812)
@@ -0,0 +1,76 @@
+// Part of BNC, a utility for retrieving decoding and
+// converting GNSS data streams from NTRIP broadcasters.
+//
+// Copyright (C) 2015
+// German Federal Agency for Cartography and Geodesy (BKG)
+// http://www.bkg.bund.de
+// Alberding GmbH
+// http://www.alberding.eu
+//
+// 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.
+
+#ifndef GNSS_H
+#define GNSS_H
+
+#define LIGHTSPEED         2.99792458e8    /* m/sec */
+#define GPS_FREQU_L1       1575420000.0  /* Hz */
+#define GPS_FREQU_L2       1227600000.0  /* Hz */
+#define GPS_FREQU_L5       1176450000.0  /* Hz */
+#define GPS_WAVELENGTH_L1  (LIGHTSPEED / GPS_FREQU_L1) /* m */
+#define GPS_WAVELENGTH_L2  (LIGHTSPEED / GPS_FREQU_L2) /* m */
+#define GPS_WAVELENGTH_L5  (LIGHTSPEED / GPS_FREQU_L5) /* m */
+
+#define GLO_FREQU_L1_BASE  1602000000.0  /* Hz */
+#define GLO_FREQU_L2_BASE  1246000000.0  /* Hz */
+#define GLO_FREQU_L1_STEP      562500.0  /* Hz */
+#define GLO_FREQU_L2_STEP      437500.0  /* Hz */
+#define GLO_FREQU_L1(a)      (GLO_FREQU_L1_BASE+(a)*GLO_FREQU_L1_STEP)
+#define GLO_FREQU_L2(a)      (GLO_FREQU_L2_BASE+(a)*GLO_FREQU_L2_STEP)
+#define GLO_WAVELENGTH_L1(a) (LIGHTSPEED / GLO_FREQU_L1(a)) /* m */
+#define GLO_WAVELENGTH_L2(a) (LIGHTSPEED / GLO_FREQU_L2(a)) /* m */
+
+#define GAL_FREQU_E1       1575420000.0  /* Hz */
+#define GAL_FREQU_E5A      1176450000.0  /* Hz */
+#define GAL_FREQU_E5AB     1191795000.0  /* Hz */
+#define GAL_FREQU_E5B      1207140000.0  /* Hz */
+#define GAL_FREQU_E6       1278750000.0  /* Hz */
+#define GAL_WAVELENGTH_E1     (LIGHTSPEED / GAL_FREQU_E1) /* m */
+#define GAL_WAVELENGTH_E5A    (LIGHTSPEED / GAL_FREQU_E5A) /* m */
+#define GAL_WAVELENGTH_E5AB   (LIGHTSPEED / GAL_FREQU_E5AB) /* m */
+#define GAL_WAVELENGTH_E5B    (LIGHTSPEED / GAL_FREQU_E5B) /* m */
+#define GAL_WAVELENGTH_E6     (LIGHTSPEED / GAL_FREQU_E6) /* m */
+
+#define QZSS_FREQU_L1       1575420000.0  /* Hz */
+#define QZSS_FREQU_L2       1227600000.0  /* Hz */
+#define QZSS_FREQU_L5       1176450000.0  /* Hz */
+#define QZSS_FREQU_LEX      1278750000.0 /* Hz */
+#define QZSS_WAVELENGTH_L1  (LIGHTSPEED / QZSS_FREQU_L1) /* m */
+#define QZSS_WAVELENGTH_L2  (LIGHTSPEED / QZSS_FREQU_L2) /* m */
+#define QZSS_WAVELENGTH_L5  (LIGHTSPEED / QZSS_FREQU_L5) /* m */
+#define QZSS_WAVELENGTH_LEX (LIGHTSPEED / QZSS_FREQU_LEX) /* m */
+
+#define BDS_FREQU_B1       1561098000.0  /* Hz */
+#define BDS_FREQU_B2       1207140000.0  /* Hz */
+#define BDS_FREQU_B3       1268520000.0  /* Hz */
+#define BDS_WAVELENGTH_B1  (LIGHTSPEED / BDS_FREQU_B1) /* m */
+#define BDS_WAVELENGTH_B2  (LIGHTSPEED / BDS_FREQU_B2) /* m */
+#define BDS_WAVELENGTH_B3  (LIGHTSPEED / BDS_FREQU_B3) /* m */
+
+#define R2R_PI          3.1415926535898
+
+#define RTCM3ID_BDS 63
+
+#endif /* GNSS_H */
Index: trunk/BNC/src/bncgetthread.cpp
===================================================================
--- trunk/BNC/src/bncgetthread.cpp	(revision 6809)
+++ trunk/BNC/src/bncgetthread.cpp	(revision 6812)
@@ -502,5 +502,5 @@
           }
         }
-      
+
         // Check observations coming twice (e.g. KOUR0 Problem)
         // ----------------------------------------------------
Index: trunk/BNC/src/bnctime.cpp
===================================================================
--- trunk/BNC/src/bnctime.cpp	(revision 6809)
+++ trunk/BNC/src/bnctime.cpp	(revision 6812)
@@ -53,4 +53,68 @@
 // 
 //////////////////////////////////////////////////////////////////////////////
+bncTime &bncTime::set(int msec) {
+  int week;
+  double sec;
+
+  currentGPSWeeks(week, sec);
+  if(msec/1000.0 < sec - 86400.0)
+    ++week;
+  return set(week, msec/1000.0);
+}
+
+// 
+//////////////////////////////////////////////////////////////////////////////
+bncTime &bncTime::setTOD(int msec) {
+  int week;
+  double sec;
+
+  currentGPSWeeks(week, sec);
+  int intsec = sec;
+  int day = intsec/(24*60*60);
+  int tod = (intsec%(24*60*60))*1000;
+  if(msec > 19*60*60*1000 && tod < 5*60*60*1000)
+    --day;
+  else if(msec < 5*60*60 && tod > 19*60*60*1000)
+    ++day;
+  msec += day*24*60*60*1000;
+  if(msec < 0.0) {
+    msec += 7*24*60*60*1000;
+    --week;
+  }
+
+  return set(week, msec/1000.0);
+}
+
+// 
+//////////////////////////////////////////////////////////////////////////////
+bncTime &bncTime::setTk(int msec) {
+  int week;
+  double sec;
+  int intsec;
+
+  currentGPSWeeks(week, sec);
+  intsec = sec;
+  updatetime(&week, &intsec, msec, 0); /* Moscow -> GPS */
+  sec = intsec+(msec%1000)/1000.0;
+  return set(week, sec);
+}
+
+// 
+//////////////////////////////////////////////////////////////////////////////
+bncTime &bncTime::setBDS(int msec) {
+  int week;
+  double sec;
+
+  msec += 14000;
+  if(msec >= 7*24*60*60*1000)
+    msec -= 7*24*60*60*1000;
+  currentGPSWeeks(week, sec);
+  if(msec/1000.0 < sec - 86400.0)
+    ++week;
+  return set(week, msec/1000.0);
+}
+
+// 
+//////////////////////////////////////////////////////////////////////////////
 bncTime& bncTime::setmjd(double daysec, int mjd) {
   _sec = daysec;
@@ -105,8 +169,32 @@
 }
 
+//
+//////////////////////////////////////////////////////////////////////////////
+unsigned int bncTime::bdsw() const {
+  double   gsec;
+  long     gpsw;
+  jdgp(_mjd, gsec, gpsw);
+  if(gsec <= 14.0)
+    gpsw -= 1;
+  return (int)gpsw-1356;
+}
+
+// 
+//////////////////////////////////////////////////////////////////////////////
+double bncTime::bdssec() const {
+  double   gsec;
+  long     gpsw;
+  jdgp(_mjd, gsec, gpsw);
+  if(gsec <= 14.0)
+    gsec += 7.0*24.0*60.0*60.0-14.0;
+  else
+    gsec -= 14.0;
+  return gsec + _sec;
+}
+
 // 
 //////////////////////////////////////////////////////////////////////////////
 bool bncTime::operator!=(const bncTime &time1) const {
-  if ( ((*this) - time1) != 0.0 ) {
+  if ( fabs((*this) - time1) > 0.000000000001 ) {
     return true;
   }
@@ -119,5 +207,5 @@
 //////////////////////////////////////////////////////////////////////////////
 bool bncTime::operator==(const bncTime &time1) const {
-  if ( ((*this) - time1) == 0.0 ) {
+  if ( fabs((*this) - time1) < 0.000000000001 ) {
     return true;
   }
@@ -294,5 +382,5 @@
 // 
 //////////////////////////////////////////////////////////////////////////////
-bncTime::operator string() const {
+bncTime::operator std::string() const {
   return datestr() + '_' + timestr();
 }
@@ -303,4 +391,11 @@
                       int hour, int min, double sec) {
   return set(year, month, day, hour*3600 + min*60 + sec);
+}
+
+// 
+//////////////////////////////////////////////////////////////////////////////
+bncTime& bncTime::setBDS(int year, int month, int day, 
+                      int hour, int min, double sec) {
+  return set(year, month, day, hour*3600 + min*60 + sec+14.0);
 }
 
Index: trunk/BNC/src/bnctime.h
===================================================================
--- trunk/BNC/src/bnctime.h	(revision 6809)
+++ trunk/BNC/src/bnctime.h	(revision 6812)
@@ -11,4 +11,10 @@
   bncTime(const std::string& isoString);
 
+  /**
+   * Set GPS time.
+   * @param gpsw GPS week
+   * @param gpssec GPS time of week in seconds
+   * @return reference to current instance
+   */
   bncTime& set(int gpsw, double gpssec);
   bncTime& set(int year, int month, int day, int hour, int min, double sec);
@@ -16,10 +22,60 @@
   bncTime& setmjd(double daysec, int mjd);
   bncTime& setmjd(double mjddec);
+  /**
+   * Set GPS time relative to current time.
+   * @param msec milliseconds of GPS week
+   * @return reference to current instance
+   */
+  bncTime &set(int msec);
+  /**
+   * Set GPS time relative to current time.
+   * @param msec milliseconds of current GPS day
+   * @return reference to current instance
+   */
+  bncTime &setTOD(int msec);
+  /**
+   * Set GLONASS time relative to current time.
+   * @param msec milliseconds of GLONASS day
+   * @return reference to current instance
+   */
+  bncTime &setTk(int msec);
+  /**
+   * Set BDS time relative to current time.
+   * @param msec milliseconds of BDS week
+   * @return reference to current instance
+   */
+  bncTime &setBDS(int msec);
+
+  /**
+   * Set BDS time.
+   * @param year 4 digit year
+   * @param month month in year (1..12)
+   * @param day day of month (1..31)
+   * @param hour hour of day (0..23)
+   * @param min minute of hopur (0..59)
+   * @param sec second of minutte (0..59,60)
+   * @return reference to current instance
+   */
+  bncTime &setBDS (int year, int month, int day, int hour, int min, double sec);
 
   void         reset() {_mjd = 0; _sec = 0;}
   unsigned int mjd()    const;
   double       daysec() const;
+  /** Get GPS week.
+   * @return GPS week number
+   */
   unsigned int gpsw()   const;
+  /** Get Seconds in GPS week.
+   * @return time of GPS week in seconds
+   */
   double       gpssec() const;
+  /** Get BDS/Beidou week.
+   * @return BDS week number
+   */
+  unsigned int bdsw()   const;
+  /** Get Seconds in BDS/Beidou week.
+   * @return time of BDS week in seconds
+   */
+  double       bdssec() const;
   double       mjddec() const {return (_mjd + _sec / 86400.0);}
   void         civil_date (unsigned int& year, unsigned int& month,
Index: trunk/BNC/src/bncutils.cpp
===================================================================
--- trunk/BNC/src/bncutils.cpp	(revision 6809)
+++ trunk/BNC/src/bncutils.cpp	(revision 6812)
@@ -53,4 +53,108 @@
 
 using namespace std;
+
+struct leapseconds { /* specify the day of leap second */
+  int day;        /* this is the day, where 23:59:59 exists 2 times */
+  int month;      /* not the next day! */
+  int year;
+  int taicount;
+};
+static const int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
+static const struct leapseconds leap[] = {
+/*{31, 12, 1971, 10},*/
+/*{30, 06, 1972, 11},*/
+/*{31, 12, 1972, 12},*/
+/*{31, 12, 1973, 13},*/
+/*{31, 12, 1974, 14},*/
+/*{31, 12, 1975, 15},*/
+/*{31, 12, 1976, 16},*/
+/*{31, 12, 1977, 17},*/
+/*{31, 12, 1978, 18},*/
+/*{31, 12, 1979, 19},*/
+{30, 06, 1981,20},
+{30, 06, 1982,21},
+{30, 06, 1983,22},
+{30, 06, 1985,23},
+{31, 12, 1987,24},
+{31, 12, 1989,25},
+{31, 12, 1990,26},
+{30, 06, 1992,27},
+{30, 06, 1993,28},
+{30, 06, 1994,29},
+{31, 12, 1995,30},
+{30, 06, 1997,31},
+{31, 12, 1998,32},
+{31, 12, 2005,33},
+{31, 12, 2008,34},
+{30, 06, 2012,35},
+{30, 06, 2015,36},
+{0,0,0,0} /* end marker */
+};
+
+#define GPSLEAPSTART    19 /* 19 leap seconds existed at 6.1.1980 */
+
+static int longyear(int year, int month)
+{
+  if(!(year % 4) && (!(year % 400) || (year % 100)))
+  {
+    if(!month || month == 2)
+      return 1;
+  }
+  return 0;
+}
+
+int gnumleap(int year, int month, int day)
+{
+  int ls = 0;
+  const struct leapseconds *l;
+
+  for(l = leap; l->taicount && year >= l->year; ++l)
+  {
+    if(year > l->year || month > l->month || (month == l->month && day > l->day))
+       ls = l->taicount - GPSLEAPSTART;
+  }
+  return ls;
+}
+
+/* Convert Moscow time into UTC (fixnumleap == 1) or GPS (fixnumleap == 0) */
+void updatetime(int *week, int *secOfWeek, int mSecOfWeek, bool fixnumleap)
+{
+  int y,m,d,k,l, nul;
+  unsigned int j = *week*(7*24*60*60) + *secOfWeek + 5*24*60*60+3*60*60;
+  int glo_daynumber = 0, glo_timeofday;
+  for(y = 1980; j >= (unsigned int)(k = (l = (365+longyear(y,0)))*24*60*60)
+  + gnumleap(y+1,1,1); ++y)
+  {
+    j -= k; glo_daynumber += l;
+  }
+  for(m = 1; j >= (unsigned int)(k = (l = months[m]+longyear(y, m))*24*60*60)
+  + gnumleap(y, m+1, 1); ++m)
+  {
+    j -= k; glo_daynumber += l;
+  }
+  for(d = 1; j >= 24UL*60UL*60UL + gnumleap(y, m, d+1); ++d)
+    j -= 24*60*60;
+  glo_daynumber -= 16*365+4-d;
+  nul = gnumleap(y, m, d);
+  glo_timeofday = j-nul;
+
+  // original version
+  // if(mSecOfWeek < 5*60*1000 && glo_timeofday > 23*60*60)
+  //   *secOfWeek += 24*60*60;
+  // else if(glo_timeofday < 5*60 && mSecOfWeek > 23*60*60*1000)
+  //   *secOfWeek -= 24*60*60;
+
+  // new version 
+  if(mSecOfWeek < 4*60*60*1000 && glo_timeofday > 20*60*60)
+    *secOfWeek += 24*60*60;
+  else if(glo_timeofday < 4*60*60 && mSecOfWeek > 20*60*60*1000)
+    *secOfWeek -= 24*60*60;
+
+  *secOfWeek += mSecOfWeek/1000-glo_timeofday;
+  if(fixnumleap)
+    *secOfWeek -= nul;
+  if(*secOfWeek < 0) {*secOfWeek += 24*60*60*7; --*week; }
+  if(*secOfWeek >= 24*60*60*7) {*secOfWeek -= 24*60*60*7; ++*week; }
+}
 
 // 
Index: trunk/BNC/src/bncutils.h
===================================================================
--- trunk/BNC/src/bncutils.h	(revision 6809)
+++ trunk/BNC/src/bncutils.h	(revision 6812)
@@ -36,4 +36,24 @@
 
 void         expandEnvVar(QString& str);
+
+/**
+ * Return GPS leap seconds for a given UTC time
+ * @param year 4 digit year
+ * @param month month in year (1-12)
+ * @param day day in month (1-31)
+ * @return number of leap seconds since 6.1.1980
+ */
+int          gnumleap(int year, int month, int day);
+
+/**
+ * Convert Moscow time into GPS or UTC. Note that parts of a second are not preserved
+ * and must be handled separately.
+ * @param week GPS week number (must be prefilled, contains fixed value afterwards)
+ * @param secOfWeek seconds in GPS week (must be prefilled, contains fixed value afterwards) 
+ * @param mSecOfWeek milli seconds in GLONASS time
+ * @param fixnumleap when <code>true</code> then result is UTC time, otherwise it is GPS
+ * @return does not return a value, but updates first two arguments
+ */
+void         updatetime(int *week, int *secOfWeek, int mSecOfWeek, bool fixnumleap);
 
 QDateTime    dateAndTimeFromGPSweek(int GPSWeek, double GPSWeeks);
Index: trunk/BNC/src/ephemeris.cpp
===================================================================
--- trunk/BNC/src/ephemeris.cpp	(revision 6809)
+++ trunk/BNC/src/ephemeris.cpp	(revision 6812)
@@ -259,61 +259,4 @@
     }
   }
-}
-
-// Set GPS Satellite Position
-////////////////////////////////////////////////////////////////////////////
-void t_ephGPS::set(const gpsephemeris* ee) {
-
-  _receptDateTime = currentDateAndTimeGPS();
-
-  if      (PRN_GPS_START <= ee->satellite && ee->satellite <= PRN_GPS_END) {
-    _prn.set('G', ee->satellite);
-  }
-  else if (PRN_QZSS_START <= ee->satellite && ee->satellite <= PRN_QZSS_END) {
-    _prn.set('J', ee->satellite - PRN_QZSS_START + 1);
-  }
-  else {
-    _checkState = bad;
-    return;
-  }
-
-  _TOC.set(ee->GPSweek, ee->TOC);
-  _clock_bias      = ee->clock_bias;
-  _clock_drift     = ee->clock_drift;
-  _clock_driftrate = ee->clock_driftrate;
-
-  _IODE     = ee->IODE;
-  _Crs      = ee->Crs;
-  _Delta_n  = ee->Delta_n;
-  _M0       = ee->M0;
-
-  _Cuc      = ee->Cuc;
-  _e        = ee->e;
-  _Cus      = ee->Cus;
-  _sqrt_A   = ee->sqrt_A;
-
-  _TOEsec   = ee->TOE;
-  _Cic      = ee->Cic;
-  _OMEGA0   = ee->OMEGA0;
-  _Cis      = ee->Cis;
-
-  _i0       = ee->i0;
-  _Crc      = ee->Crc;
-  _omega    = ee->omega;
-  _OMEGADOT = ee->OMEGADOT;
-
-  _IDOT     = ee->IDOT;
-  _L2Codes  = 0.0;
-  _TOEweek  = ee->GPSweek;
-  _L2PFlag  = 0.0;
-
-  _ura = accuracyFromIndex(ee->URAindex, type());
-
-  _health   = ee->SVhealth;
-  _TGD      = ee->TGD;
-  _IODC     = ee->IODC;
-
-  _TOT         = 0.9999e9;
-  _fitInterval = 0.0;
 }
 
@@ -570,99 +513,4 @@
 }
 
-// Set Glonass Ephemeris
-////////////////////////////////////////////////////////////////////////////
-void t_ephGlo::set(const glonassephemeris* ee) {
-
-  _receptDateTime = currentDateAndTimeGPS();
-
-  _prn.set('R', ee->almanac_number);
-
-  int ww  = ee->GPSWeek;
-  int tow = ee->GPSTOW; 
-  updatetime(&ww, &tow, ee->tb*1000, 0);  // Moscow -> GPS
-
-  // Check the day once more 
-  // -----------------------
-  bool timeChanged = false;
-  {
-    const double secPerDay  = 24 * 3600.0;
-    const double secPerWeek = 7 * secPerDay;
-    int ww_old  = ww;
-    int tow_old = tow;
-    int    currentWeek;
-    double currentSec;
-    currentGPSWeeks(currentWeek, currentSec);
-    bncTime currentTime(currentWeek, currentSec);
-    bncTime hTime(ww, (double) tow);
-
-    if      (hTime - currentTime >  secPerDay/2.0) {
-      timeChanged = true;
-      tow -= int(secPerDay);
-      if (tow < 0) {
-        tow += int(secPerWeek);
-        ww  -= 1;
-      }
-    }
-    else if (hTime - currentTime < -secPerDay/2.0) {
-      timeChanged = true;
-      tow += int(secPerDay);
-      if (tow > secPerWeek) {
-        tow -= int(secPerWeek);
-        ww  += 1;
-      }
-    }
-
-    if (false && timeChanged && BNC_CORE->mode() == t_bncCore::batchPostProcessing) {
-      bncTime newHTime(ww, (double) tow);
-      cout << "GLONASS " << ee->almanac_number <<  " Time Changed at " 
-           << currentTime.datestr()         << " " << currentTime.timestr() 
-           << endl
-           << "old: " << hTime.datestr()    << " " << hTime.timestr()       
-           << endl
-           << "new: " << newHTime.datestr() << " " << newHTime.timestr()    
-           << endl
-           << "eph: " << ee->GPSWeek << " " << ee->GPSTOW << " " << ee->tb 
-           << endl
-           << "ww, tow (old): " << ww_old << " " << tow_old 
-           << endl
-           << "ww, tow (new): " << ww     << " " << tow 
-           << endl << endl;
-    }
-  }
-
-  bncTime hlpTime(ww, (double) tow);
-  unsigned year, month, day;
-  hlpTime.civil_date(year, month, day);
-  _gps_utc = gnumleap(year, month, day);
-
-  _TOC.set(ww, tow);
-  _E                 = ee->E;
-  _tau               = ee->tau;
-  _gamma             = ee->gamma;
-  _x_pos             = ee->x_pos;
-  _x_velocity        = ee->x_velocity;     
-  _x_acceleration    = ee->x_acceleration;
-  _y_pos             = ee->y_pos;         
-  _y_velocity        = ee->y_velocity;    
-  _y_acceleration    = ee->y_acceleration;
-  _z_pos             = ee->z_pos;         
-  _z_velocity        = ee->z_velocity;    
-  _z_acceleration    = ee->z_acceleration;
-  _health            = 0;
-  _frequency_number  = ee->frequency_number;
-  _tki               = ee->tk-3*60*60; if (_tki < 0) _tki += 86400;
-
-  // Initialize status vector
-  // ------------------------
-  _tt = _TOC;
-
-  _xv(1) = _x_pos * 1.e3; 
-  _xv(2) = _y_pos * 1.e3; 
-  _xv(3) = _z_pos * 1.e3; 
-  _xv(4) = _x_velocity * 1.e3; 
-  _xv(5) = _y_velocity * 1.e3; 
-  _xv(6) = _z_velocity * 1.e3; 
-}
-
 // Compute Glonass Satellite Position (virtual)
 ////////////////////////////////////////////////////////////////////////////
@@ -805,5 +653,4 @@
     return;
   }
-  _flags = 0;
 
   // RINEX Format
@@ -893,7 +740,9 @@
       } else {
         if        (int(datasource) & (1<<8)) {
-          _flags |= GALEPHF_FNAV;
+          _fnav = true;
+          _inav = false;
         } else if (int(datasource) & (1<<9)) {
-          _flags |= GALEPHF_INAV;
+          _fnav = false;
+          _inav = true;
         }
       }
@@ -909,27 +758,18 @@
       } else {
         // Bit 0
-        if (int(SVhealth) & (1<<0)) {
-          _flags |= GALEPHF_E1DINVALID;
-        }
+        _e1DataInValid = (int(SVhealth) & (1<<0));
         // Bit 1-2
         _E1_bHS = double((int(SVhealth) >> 1) & 0x3);
         // Bit 3
-        if (int(SVhealth) & (1<<3)) {
-          _flags |= GALEPHF_E5ADINVALID;
-        }
+        _e5aDataInValid = (int(SVhealth) & (1<<3));
         // Bit 4-5
         _E5aHS = double((int(SVhealth) >> 4) & 0x3);
         // Bit 6
-        if (int(SVhealth) & (1<<6)) {
-          _flags |= GALEPHF_E5BDINVALID;
-        }
+        _e5bDataInValid = (int(SVhealth) & (1<<6));
         // Bit 7-8
         _E5bHS = double((int(SVhealth) >> 7) & 0x3);
 
         if (prnStr.at(0) == 'E') {
-          _prn.set('E', prnStr.mid(1,2).toInt(), _flags);
-        }
-        else {
-          _prn.set('E', prnStr.mid(1,2).toInt(), _flags);
+          _prn.set('E', prnStr.mid(1,2).toInt(), _inav ? 1 : 0);
         }
       }
@@ -943,53 +783,4 @@
     }
   }
-}
-
-// Set Galileo Satellite Position
-////////////////////////////////////////////////////////////////////////////
-void t_ephGal::set(const galileoephemeris* ee) {
-
-  _receptDateTime = currentDateAndTimeGPS();
-
-  _flags    = ee->flags;
-  _prn.set('E', ee->satellite, _flags);
-
-  _TOC.set(ee->Week, ee->TOC);
-  _clock_bias      = ee->clock_bias;
-  _clock_drift     = ee->clock_drift;
-  _clock_driftrate = ee->clock_driftrate;
-
-  _IODnav   = ee->IODnav;
-  _Crs      = ee->Crs;
-  _Delta_n  = ee->Delta_n;
-  _M0       = ee->M0;
-
-  _Cuc      = ee->Cuc;
-  _e        = ee->e;
-  _Cus      = ee->Cus;
-  _sqrt_A   = ee->sqrt_A;
-
-  _TOEsec   = _TOC.gpssec();
-  //  _TOEsec   = ee->TOE;  // TODO:
-
-  _Cic      = ee->Cic;
-  _OMEGA0   = ee->OMEGA0;
-  _Cis      = ee->Cis;
-
-  _i0       = ee->i0;
-  _Crc      = ee->Crc;
-  _omega    = ee->omega;
-  _OMEGADOT = ee->OMEGADOT;
-
-  _IDOT     = ee->IDOT;
-  _TOEweek  = ee->Week;
-
-  _SISA = accuracyFromIndex(ee->SISA, type());
-  _E5aHS    = ee->E5aHS;
-  _E5bHS    = ee->E5bHS;
-  _E1_bHS   = ee->E1_HS;
-  _BGD_1_5A = ee->BGD_1_5A;
-  _BGD_1_5B = ee->BGD_1_5B;
-
-  _TOT      = 0.9999e9;
 }
 
@@ -1124,5 +915,5 @@
   double BGD_1_5A   = _BGD_1_5A;
   double BGD_1_5B   = _BGD_1_5B;
-  if      ((_flags & GALEPHF_FNAV) == GALEPHF_FNAV) {
+  if (_fnav) {
     dataSource |= (1<<1);
     dataSource |= (1<<8);
@@ -1130,5 +921,5 @@
     // SVhealth
     //   Bit 3  : E5a DVS
-    if ((_flags & GALEPHF_E5ADINVALID) == GALEPHF_E5ADINVALID) {
+    if (_e5aDataInValid) {
       SVhealth |= (1<<3);
     }
@@ -1145,5 +936,5 @@
     }
   }
-  else if ((_flags & GALEPHF_INAV) == GALEPHF_INAV) {
+  else if(_inav) {
     // Bit 2 and 0 are set because from MT1046 the data source cannot be determined
     // and RNXv3.03 says both can be set if the navigation messages were merged
@@ -1153,5 +944,5 @@
     // SVhealth
     //   Bit 0  : E1-B DVS
-    if ((_flags & GALEPHF_E1DINVALID) == GALEPHF_E1DINVALID) {
+    if (_e1DataInValid) {
       SVhealth |= (1<<0);
     }
@@ -1168,5 +959,5 @@
     }
     //   Bit 3  : E5a DVS
-    if ((_flags & GALEPHF_E5ADINVALID) == GALEPHF_E5ADINVALID) {
+    if (_e5aDataInValid) {
       SVhealth |= (1<<3);
     }
@@ -1183,5 +974,5 @@
     }
     //   Bit 6  : E5b DVS
-    if ((_flags & GALEPHF_E5BDINVALID) == GALEPHF_E5BDINVALID) {
+    if (_e5bDataInValid) {
       SVhealth |= (1<<6);
     }
@@ -1322,34 +1113,4 @@
 }
 
-// Set SBAS Satellite Position
-////////////////////////////////////////////////////////////////////////////
-void t_ephSBAS::set(const sbasephemeris* ee) {
-
-  _prn.set('S', ee->satellite - PRN_SBAS_START + 20);
-  _TOC.set(ee->GPSweek_TOE, double(ee->TOE));
-
-  _IODN           = ee->IODN;
-  _TOW            = ee->TOW;            
-
-  _agf0           = ee->agf0;           
-  _agf1           = ee->agf1;           
-                                
-  _x_pos          = ee->x_pos;          
-  _x_velocity     = ee->x_velocity;     
-  _x_acceleration = ee->x_acceleration; 
-                                
-  _y_pos          = ee->y_pos;          
-  _y_velocity     = ee->y_velocity;     
-  _y_acceleration = ee->y_acceleration; 
-                                
-  _z_pos          = ee->z_pos;          
-  _z_velocity     = ee->z_velocity;     
-  _z_acceleration = ee->z_acceleration; 
-
-  _ura            = accuracyFromIndex(ee->URA, type());
-
-  _health = 0;
-}
-
 // Compute SBAS Satellite Position (virtual)
 ////////////////////////////////////////////////////////////////////////////
@@ -1426,5 +1187,4 @@
   // ------------
   int fieldLen = 19;
-  double TOEw;
 
   int pos[4];
@@ -1461,5 +1221,5 @@
       }
 
-      _TOC_bdt.set(year, month, day, hour, min, sec);
+      _TOC.setBDS(year, month, day, hour, min, sec);
 
       if ( readDbl(line, pos[1], fieldLen, _clock_bias     ) ||
@@ -1494,5 +1254,5 @@
 
     else if ( iLine == 3 ) {
-      if ( readDbl(line, pos[0], fieldLen, _TOEs   )  ||
+      if ( readDbl(line, pos[0], fieldLen, _TOEsec )  ||
            readDbl(line, pos[1], fieldLen, _Cic   )  ||
            readDbl(line, pos[2], fieldLen, _OMEGA0)  ||
@@ -1515,5 +1275,5 @@
     else if ( iLine == 5 ) {
       if ( readDbl(line, pos[0], fieldLen, _IDOT    ) ||
-           readDbl(line, pos[2], fieldLen, TOEw)    ) {
+           readDbl(line, pos[2], fieldLen, _TOEweek)) {
         _checkState = bad;
         return;
@@ -1535,79 +1295,19 @@
     else if ( iLine == 7 ) {
       double aodc;
-      if ( readDbl(line, pos[0], fieldLen, _TOTs) ||
+      if ( readDbl(line, pos[0], fieldLen, _TOT) ||
            readDbl(line, pos[1], fieldLen, aodc) ) {
         _checkState = bad;
         return;
       }
-      if (_TOTs == 0.9999e9) {  // 0.9999e9 means not known (RINEX standard)
-        _TOTs = _TOEs;
+      if (_TOT == 0.9999e9) {  // 0.9999e9 means not known (RINEX standard)
+        _TOT = _TOEsec;
       }
       _AODC = int(aodc);
     }
   }
-
-  TOEw += 1356;  // BDT -> GPS week number
-  _TOE_bdt.set(int(TOEw), _TOEs);
-
-  // GPS->BDT
-  // --------
-  _TOC = _TOC_bdt + 14.0;
-  _TOE = _TOE_bdt + 14.0;
 
   // remark: actually should be computed from second_tot
   //         but it seems to be unreliable in RINEX files
-  _TOT = _TOC;
-}
-
-// Set BDS Satellite Position
-////////////////////////////////////////////////////////////////////////////
-void t_ephBDS::set(const bdsephemeris* ee) {
-
-  // RTCM usage: set RINEX File entries to zero
-  // ------------------------------------------
-  _TOTs = 0.0;
-  _TOEs = 0.0;
-
-  _receptDateTime = currentDateAndTimeGPS();
-
-  _prn.set('C', ee->satellite - PRN_BDS_START + 1);
-
-  _TOE_bdt.set(1356 + ee->BDSweek, ee->TOE);
-  _TOE   = _TOE_bdt + 14.0;
-
-  _TOC_bdt.set(1356 + ee->BDSweek, ee->TOC);
-  _TOC   = _TOC_bdt + 14.0;
-
-  _AODE  = ee->AODE;
-  _AODC  = ee->AODC;
-
-  _clock_bias      = ee->clock_bias;
-  _clock_drift     = ee->clock_drift;
-  _clock_driftrate = ee->clock_driftrate;
-
-  _Crs      = ee->Crs;
-  _Delta_n  = ee->Delta_n;
-  _M0       = ee->M0;
-
-  _Cuc      = ee->Cuc;
-  _e        = ee->e;
-  _Cus      = ee->Cus;
-  _sqrt_A   = ee->sqrt_A;
-
-  _Cic      = ee->Cic;
-  _OMEGA0   = ee->OMEGA0;
-  _Cis      = ee->Cis;
-
-  _i0       = ee->i0;
-  _Crc      = ee->Crc;
-  _omega    = ee->omega;
-  _OMEGADOT = ee->OMEGADOT;
-
-  _IDOT     = ee->IDOT;
-
-  _URA      = accuracyFromIndex(ee->URAI, type());
-  _SatH1    = (ee->flags & BDSEPHF_SATH1) ? 1: 0;
-  _TGD1     = ee->TGD_B1_B3;
-  _TGD2     = ee->TGD_B2_B3;
+  _TOT = _TOC.bdssec();
 }
 
@@ -1746,5 +1446,5 @@
 QString t_ephBDS::toString(double version) const {
 
-  QString rnxStr = rinexDateStr(_TOC_bdt, _prn, version);
+  QString rnxStr = rinexDateStr(_TOC-14.0, _prn, version);
 
   QTextStream out(&rnxStr);
@@ -1769,7 +1469,7 @@
     .arg(_sqrt_A, 19, 'e', 12);
 
-  double toes = _TOEs;
+  double toes = _TOEsec;
   if (!toes) { // RTCM stream input
-    toes = _TOE_bdt.gpssec();
+    toes = _TOE.bdssec();
   }
   out << QString(fmt)
@@ -1788,5 +1488,5 @@
     .arg(_IDOT,                             19, 'e', 12)
     .arg(0.0,                               19, 'e', 12)
-    .arg(double(_TOE_bdt.gpsw() - 1356.0),  19, 'e', 12)
+    .arg(double(_TOE.bdsw()),               19, 'e', 12)
     .arg(0.0,                               19, 'e', 12);
 
@@ -1797,7 +1497,7 @@
     .arg(_TGD2,          19, 'e', 12);
 
-  double tots = _TOTs;
+  double tots = _TOT;
   if (!tots) { // RTCM stream input
-    tots = _TOE_bdt.gpssec();
+    tots = _TOE.bdssec();
   }
   out << QString(fmt)
@@ -1808,3 +1508,2 @@
   return rnxStr;
 }
-
Index: trunk/BNC/src/ephemeris.h
===================================================================
--- trunk/BNC/src/ephemeris.h	(revision 6809)
+++ trunk/BNC/src/ephemeris.h	(revision 6812)
@@ -9,8 +9,5 @@
 #include "bncconst.h"
 #include "t_prn.h"
-
-extern "C" {
-#  include "rtcm3torinex.h"
-}
+#include "gnss.h"
 
 class t_orbCorr;
@@ -55,4 +52,5 @@
 class t_ephGPS : public t_eph {
  friend class t_ephEncoder;
+ friend class RTCM3Decoder;
  public:
   t_ephGPS() { }
@@ -63,5 +61,4 @@
   virtual QString toString(double version) const;
   virtual int  IOD() const { return static_cast<int>(_IODC); }
-  void set(const gpsephemeris* ee);
   double TGD() const {return _TGD;} // Timing Group Delay (P1-P2 DCB)
 
@@ -109,4 +106,5 @@
 class t_ephGlo : public t_eph {
  friend class t_ephEncoder;
+ friend class RTCM3Decoder;
  public:
   t_ephGlo() { _xv.ReSize(6); }
@@ -118,5 +116,4 @@
   virtual int  IOD() const;
   virtual int slotNum() const {return int(_frequency_number);}
-  void set(const glonassephemeris* ee);
 
  private:
@@ -150,6 +147,7 @@
 class t_ephGal : public t_eph {
  friend class t_ephEncoder;
- public:
-  t_ephGal() : _flags(0) { };
+ friend class RTCM3Decoder;
+ public:
+  t_ephGal() { };
   t_ephGal(float rnxVersion, const QStringList& lines);
   virtual ~t_ephGal() {}
@@ -158,5 +156,4 @@
   virtual e_type type() const {return t_eph::Galileo;}
   virtual int  IOD() const { return static_cast<int>(_IODnav); }
-  void set(const galileoephemeris* ee);
 
  private:
@@ -167,5 +164,5 @@
   double  _clock_driftrate;  //  [s/s^2]
 
-  double  _IODnav;             
+  double  _IODnav;
   double  _Crs;              //  [m]    
   double  _Delta_n;          //  [rad/s]
@@ -199,14 +196,19 @@
 
   double  _TOT;              // [s]
-
-  int     _flags;            // GALEPHF_E5ADINVALID   E5aDVS set invalid
-                             // GALEPHF_E5BDINVALID   E5bDVS set invalid
-                             // GALEPHF_INAV          INAV data
-                             // GALEPHF_FNAV          FNAV data
-                             // GALEPHF_E1DINVALID    E1DVS set invalid
+  /** Data comes from I/NAV when <code>true</code> */
+  bool    _inav;
+  /** Data comes from F/NAV when <code>true</code> */
+  bool    _fnav;
+  /** EE Data is not valid */
+  bool    _e1DataInValid;
+  /** E5A Data is not valid */
+  bool    _e5aDataInValid;
+  /** E5B Data is not valid */
+  bool    _e5bDataInValid;
 };
 
 class t_ephSBAS : public t_eph {
  friend class t_ephEncoder;
+ friend class RTCM3Decoder;
  public:
   t_ephSBAS() {}
@@ -214,5 +216,4 @@
   virtual ~t_ephSBAS() {}
 
-  void            set(const sbasephemeris* ee);
   virtual e_type  type() const {return t_eph::SBAS;}
   virtual int     IOD() const {return _IODN;}
@@ -245,4 +246,5 @@
 class t_ephBDS : public t_eph {
  friend class t_ephEncoder;
+ friend class RTCM3Decoder;
  public:
  t_ephBDS() {}
@@ -250,5 +252,4 @@
   virtual ~t_ephBDS() {}
 
-  void set(const bdsephemeris* ee);
   virtual e_type  type() const {return t_eph::BDS;}
   virtual int     IOD() const {return _AODC;}
@@ -258,10 +259,9 @@
   virtual t_irc position(int GPSweek, double GPSweeks, double* xc, double* vv) const;
 
-  bncTime _TOT;
+  double  _TOT;
   bncTime _TOE;
-  bncTime _TOC_bdt;
-  bncTime _TOE_bdt;
   int     _AODE;
   int     _AODC;
+  int     _URAI;             //  [0..15] index from RTCM stream
   mutable double  _URA;      //  user range accuracy
   double  _clock_bias;       //  [s]    
@@ -286,6 +286,7 @@
   double  _TGD2;             //  [s]    
   int     _SatH1;            // 
-  double  _TOTs;             //  [s] of BDT week; RINEX file entry
-  double  _TOEs;             //  [s] of BDT week; RINEX file entry
+  double  _TOW;              //  [s] of BDT week; RINEX file entry
+  double  _TOEsec;           //  [s] of BDT week; RINEX file entry
+  double  _TOEweek;
 };
 
Index: trunk/BNC/src/satObs.h
===================================================================
--- trunk/BNC/src/satObs.h	(revision 6809)
+++ trunk/BNC/src/satObs.h	(revision 6812)
@@ -52,5 +52,25 @@
     }
   }
-  ~t_satObs() {for (unsigned ii = 0; ii < _obs.size(); ii++) delete _obs[ii];}
+  /**
+   * Destructor of satellite measurement storage class
+   */
+  ~t_satObs()
+  {
+    clear();
+  }
+
+  /**
+   * Cleanup function resets all elements to initial state.
+   */
+  inline void clear(void)
+  {
+    for (unsigned ii = 0; ii < _obs.size(); ii++)
+      delete _obs[ii];
+    _obs.clear();
+    _obs.resize(0);
+    _time.reset();
+    _prn.clear();
+    _staID.clear();
+  }
 
   std::string            _staID;
Index: trunk/BNC/src/src.pri
===================================================================
--- trunk/BNC/src/src.pri	(revision 6809)
+++ trunk/BNC/src/src.pri	(revision 6812)
@@ -27,5 +27,5 @@
 # Include Path
 # ------------
-INCLUDEPATH += . ../newmat ./RTCM3 ./RTCM3/clock_and_orbit ./RTCM3/rtcm3torinex \
+INCLUDEPATH += . ../newmat ./RTCM3 ./RTCM3/clock_and_orbit ./RTCM \
                ../qwt ../qwtpolar
 
@@ -57,7 +57,8 @@
           RTCM/RTCM2.h RTCM/RTCM2Decoder.h                            \
           RTCM/RTCM2_2021.h RTCM/rtcm_utils.h                         \
-          RTCM3/RTCM3Decoder.h RTCM3/rtcm3torinex/rtcm3torinex.h      \
+          RTCM3/RTCM3Decoder.h RTCM3/bits.h RTCM3/gnss.h              \
           RTCM3/RTCM3coDecoder.h RTCM3/ephEncoder.h                   \
           RTCM3/clock_and_orbit/clock_orbit_rtcm.h                    \
+          RTCM3/gnss.h RTCM3/bits.h                                   \
           rinex/rnxobsfile.h                                          \
           rinex/rnxnavfile.h       rinex/corrfile.h                   \
@@ -89,8 +90,9 @@
           upload/bncephuploadcaster.cpp qtfilechooser.cpp             \
           GPSDecoder.cpp pppWidgets.cpp pppModel.cpp                  \
-          pppMain.cpp pppRun.cpp pppOptions.cpp pppCrdFile.cpp pppThread.cpp \
+          pppMain.cpp pppRun.cpp pppOptions.cpp pppCrdFile.cpp        \
+          pppThread.cpp                                               \
           RTCM/RTCM2.cpp RTCM/RTCM2Decoder.cpp                        \
           RTCM/RTCM2_2021.cpp RTCM/rtcm_utils.cpp                     \
-          RTCM3/RTCM3Decoder.cpp RTCM3/rtcm3torinex/rtcm3torinex.c    \
+          RTCM3/RTCM3Decoder.cpp                                      \
           RTCM3/RTCM3coDecoder.cpp RTCM3/ephEncoder.cpp               \
           RTCM3/clock_and_orbit/clock_orbit_rtcm.c                    \
Index: trunk/BNC/src/t_prn.h
===================================================================
--- trunk/BNC/src/t_prn.h	(revision 6809)
+++ trunk/BNC/src/t_prn.h	(revision 6812)
@@ -66,4 +66,13 @@
   }
 
+  /**
+   * Cleanup function resets all elements to initial state.
+   */
+  inline void clear(void)
+  {
+    _system = 'G';
+    _number = 0;
+  }
+
   operator unsigned() const;
 
Index: trunk/BNC/src/upload/bncrtnetuploadcaster.cpp
===================================================================
--- trunk/BNC/src/upload/bncrtnetuploadcaster.cpp	(revision 6809)
+++ trunk/BNC/src/upload/bncrtnetuploadcaster.cpp	(revision 6812)
@@ -21,8 +21,5 @@
 #include "bncclockrinex.h"
 #include "bncsp3.h"
-
-extern "C" {
-#  include "rtcm3torinex.h"
-}
+#include "gnss.h"
 
 using namespace std;
