Index: trunk/BNC/src/RTCM3/RTCM3Decoder.cpp
===================================================================
--- trunk/BNC/src/RTCM3/RTCM3Decoder.cpp	(revision 6799)
+++ 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 6799)
+++ 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 6799)
+++ 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 6799)
+++ 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 */
