source: ntrip/trunk/rtcm3torinex/lib/rtcm3torinex.c @ 3270

Last change on this file since 3270 was 3270, checked in by mervart, 9 years ago

LM: modification due to 24-hour problem

  • Property svn:keywords set to Id Revision Date
File size: 109.1 KB
Line 
1/*
2  Converter for RTCM3 data to RINEX.
3  $Id: rtcm3torinex.c 3270 2011-04-08 09:29:56Z mervart $
4  Copyright (C) 2005-2008 by Dirk Stöcker <stoecker@alberding.eu>
5
6  This software is a complete NTRIP-RTCM3 to RINEX converter as well as
7  a module of the BNC tool for multiformat conversion. Contact Dirk
8  Stöcker for suggestions and bug reports related to the RTCM3 to RINEX
9  conversion problems and the author of BNC for all the other problems.
10
11  This program is free software; you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation; either version 2 of the License, or
14  (at your option) any later version.
15
16  This program is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  GNU General Public License for more details.
20
21  You should have received a copy of the GNU General Public License
22  along with this program; if not, write to the Free Software
23  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  or read http://www.gnu.org/licenses/gpl.txt
25*/
26
27#include <ctype.h>
28#include <errno.h>
29#include <math.h>
30#include <signal.h>
31#include <stdarg.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/types.h>
36#include <time.h>
37#include <unistd.h>
38
39#ifndef NO_RTCM3_MAIN
40#include <getopt.h>
41#include <netdb.h>
42#include <netinet/in.h>
43#include <sys/socket.h>
44#endif
45
46#ifndef sparc
47#include <stdint.h>
48#endif
49
50#ifndef isinf
51#define isinf(x) 0
52#endif
53
54#include "rtcm3torinex.h"
55
56/* CVS revision and version */
57static char revisionstr[] = "$Revision: 3270 $";
58
59#ifndef COMPILEDATE
60#define COMPILEDATE " built " __DATE__
61#endif
62
63static uint32_t CRC24(long size, const unsigned char *buf)
64{
65  uint32_t crc = 0;
66  int i;
67
68  while(size--)
69  {
70    crc ^= (*buf++) << (16);
71    for(i = 0; i < 8; i++)
72    {
73      crc <<= 1;
74      if(crc & 0x1000000)
75        crc ^= 0x01864cfb;
76    }
77  }
78  return crc;
79}
80
81static int GetMessage(struct RTCM3ParserData *handle)
82{
83  unsigned char *m, *e;
84  int i;
85
86  m = handle->Message+handle->SkipBytes;
87  e = handle->Message+handle->MessageSize;
88  handle->NeedBytes = handle->SkipBytes = 0;
89  while(e-m >= 3)
90  {
91    if(m[0] == 0xD3)
92    {
93      handle->size = ((m[1]&3)<<8)|m[2];
94      if(e-m >= handle->size+6)
95      {
96        if((uint32_t)((m[3+handle->size]<<16)|(m[3+handle->size+1]<<8)
97        |(m[3+handle->size+2])) == CRC24(handle->size+3, m))
98        {
99          handle->SkipBytes = handle->size;
100          break;
101        }
102        else
103          ++m;
104      }
105      else
106      {
107        handle->NeedBytes = handle->size+6;
108        break;
109      }
110    }
111    else
112      ++m;
113  }
114  if(e-m < 3)
115    handle->NeedBytes = 3;
116
117  /* copy buffer to front */
118  i = m - handle->Message;
119  if(i && m < e)
120    memmove(handle->Message, m, (size_t)(handle->MessageSize-i));
121  handle->MessageSize -= i;
122
123  return !handle->NeedBytes;
124}
125
126#define LOADBITS(a) \
127{ \
128  while((a) > numbits) \
129  { \
130    if(!size--) break; \
131    bitfield = (bitfield<<8)|*(data++); \
132    numbits += 8; \
133  } \
134}
135
136/* extract bits from data stream
137   b = variable to store result, a = number of bits */
138#define GETBITS64(b, a) \
139{ \
140  if(((a) > 56) && ((a)-56) > numbits) \
141  { \
142    uint64_t x; \
143    GETBITS(x, 56) \
144    LOADBITS((a)-56) \
145    b = ((x<<((a)-56)) | (bitfield<<(sizeof(bitfield)*8-numbits)) \
146    >>(sizeof(bitfield)*8-((a)-56))); \
147    numbits -= ((a)-56); \
148  } \
149  else \
150  { \
151    GETBITS(b, a) \
152  } \
153}
154
155/* extract bits from data stream
156   b = variable to store result, a = number of bits */
157#define GETBITS(b, a) \
158{ \
159  LOADBITS(a) \
160  b = (bitfield<<(64-numbits))>>(64-(a)); \
161  numbits -= (a); \
162}
163
164/* extract bits from data stream
165   b = variable to store result, a = number of bits */
166#define GETBITSFACTOR(b, a, c) \
167{ \
168  LOADBITS(a) \
169  b = ((bitfield<<(sizeof(bitfield)*8-numbits))>>(sizeof(bitfield)*8-(a)))*(c); \
170  numbits -= (a); \
171}
172
173/* extract floating value from data stream
174   b = variable to store result, a = number of bits */
175#define GETFLOAT(b, a, c) \
176{ \
177  LOADBITS(a) \
178  b = ((double)((bitfield<<(64-numbits))>>(64-(a))))*(c); \
179  numbits -= (a); \
180}
181
182/* extract signed floating value from data stream
183   b = variable to store result, a = number of bits */
184#define GETFLOATSIGN(b, a, c) \
185{ \
186  LOADBITS(a) \
187  b = ((double)(((int64_t)(bitfield<<(64-numbits)))>>(64-(a))))*(c); \
188  numbits -= (a); \
189}
190
191/* extract bits from data stream
192   b = variable to store result, a = number of bits */
193#define GETBITSSIGN(b, a) \
194{ \
195  LOADBITS(a) \
196  b = ((int64_t)(bitfield<<(64-numbits)))>>(64-(a)); \
197  numbits -= (a); \
198}
199
200#define GETFLOATSIGNM(b, a, c) \
201{ int l; \
202  LOADBITS(a) \
203  l = (bitfield<<(64-numbits))>>(64-1); \
204  b = ((double)(((bitfield<<(64-(numbits-1))))>>(64-(a-1))))*(c); \
205  numbits -= (a); \
206  if(l) b *= -1.0; \
207}
208
209#define SKIPBITS(b) { LOADBITS(b) numbits -= (b); }
210
211/* extract byte-aligned byte from data stream,
212   b = variable to store size, s = variable to store string pointer */
213#define GETSTRING(b, s) \
214{ \
215  b = *(data++); \
216  s = (char *) data; \
217  data += b; \
218  size -= b+1; \
219}
220
221struct leapseconds { /* specify the day of leap second */
222  int day;        /* this is the day, where 23:59:59 exists 2 times */
223  int month;      /* not the next day! */
224  int year;
225  int taicount;
226};
227static const int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
228static const struct leapseconds leap[] = {
229/*{31, 12, 1971, 11},*/
230/*{31, 12, 1972, 12},*/
231/*{31, 12, 1973, 13},*/
232/*{31, 12, 1974, 14},*/
233/*{31, 12, 1975, 15},*/
234/*{31, 12, 1976, 16},*/
235/*{31, 12, 1977, 17},*/
236/*{31, 12, 1978, 18},*/
237/*{31, 12, 1979, 19},*/
238{30, 06, 1981,20},
239{30, 06, 1982,21},
240{30, 06, 1983,22},
241{30, 06, 1985,23},
242{31, 12, 1987,24},
243{31, 12, 1989,25},
244{31, 12, 1990,26},
245{30, 06, 1992,27},
246{30, 06, 1993,28},
247{30, 06, 1994,29},
248{31, 12, 1995,30},
249{30, 06, 1997,31},
250{31, 12, 1998,32},
251{31, 12, 2005,33},
252{31, 12, 2008,34},
253{0,0,0,0} /* end marker */
254};
255#define LEAPSECONDS     15 /* only needed for approx. time */
256#define GPSLEAPSTART    19 /* 19 leap seconds existed at 6.1.1980 */
257
258static int longyear(int year, int month)
259{
260  if(!(year % 4) && (!(year % 400) || (year % 100)))
261  {
262    if(!month || month == 2)
263      return 1;
264  }
265  return 0;
266}
267
268int gnumleap(int year, int month, int day)
269{
270  int ls = 0;
271  const struct leapseconds *l;
272
273  for(l = leap; l->taicount && year >= l->year; ++l)
274  {
275    if(year > l->year || month > l->month || (month == l->month && day > l->day))
276       ls = l->taicount - GPSLEAPSTART;
277  }
278  return ls;
279}
280
281/* Convert Moscow time into UTC (fixnumleap == 1) or GPS (fixnumleap == 0) */
282void updatetime(int *week, int *secOfWeek, int mSecOfWeek, int fixnumleap)
283{
284  int y,m,d,k,l, nul;
285  unsigned int j = *week*(7*24*60*60) + *secOfWeek + 5*24*60*60+3*60*60;
286  int glo_daynumber = 0, glo_timeofday;
287  for(y = 1980; j >= (unsigned int)(k = (l = (365+longyear(y,0)))*24*60*60)
288  + gnumleap(y+1,1,1); ++y)
289  {
290    j -= k; glo_daynumber += l;
291  }
292  for(m = 1; j >= (unsigned int)(k = (l = months[m]+longyear(y, m))*24*60*60)
293  + gnumleap(y, m+1, 1); ++m)
294  {
295    j -= k; glo_daynumber += l;
296  }
297  for(d = 1; j >= 24UL*60UL*60UL + gnumleap(y, m, d+1); ++d)
298    j -= 24*60*60;
299  glo_daynumber -= 16*365+4-d;
300  nul = gnumleap(y, m, d);
301  glo_timeofday = j-nul;
302
303  // original version
304  // if(mSecOfWeek < 5*60*1000 && glo_timeofday > 23*60*60)
305  //   *secOfWeek += 24*60*60;
306  // else if(glo_timeofday < 5*60 && mSecOfWeek > 23*60*60*1000)
307  //   *secOfWeek -= 24*60*60;
308
309  // new version
310  if(mSecOfWeek < 4*60*60*1000 && glo_timeofday > 20*60*60)
311    *secOfWeek += 24*60*60;
312  else if(glo_timeofday < 4*60*60 && mSecOfWeek > 20*60*60*1000)
313    *secOfWeek -= 24*60*60;
314
315  *secOfWeek += mSecOfWeek/1000-glo_timeofday;
316  if(fixnumleap)
317    *secOfWeek -= nul;
318  if(*secOfWeek < 0) {*secOfWeek += 24*60*60*7; --*week; }
319  if(*secOfWeek >= 24*60*60*7) {*secOfWeek -= 24*60*60*7; ++*week; }
320}
321
322int RTCM3Parser(struct RTCM3ParserData *handle)
323{
324  int ret=0;
325
326#ifdef NO_RTCM3_MAIN
327  if(GetMessage(handle)) /* don't repeat */
328#else
329  while(!ret && GetMessage(handle))
330#endif /* NO_RTCM3_MAIN */
331  {
332    /* using 64 bit integer types, as it is much easier than handling
333    the long datatypes in 32 bit */
334    uint64_t numbits = 0, bitfield = 0;
335    int size = handle->size, type;
336    int syncf, old = 0;
337    unsigned char *data = handle->Message+3;
338
339    GETBITS(type,12)
340#ifdef NO_RTCM3_MAIN
341    handle->blocktype = type;
342#endif /* NO_RTCM3_MAIN */
343    switch(type)
344    {
345#ifdef NO_RTCM3_MAIN
346    default:
347      ret = type;
348      break;
349    case 1005: case 1006:
350      {
351        SKIPBITS(22)
352        GETBITSSIGN(handle->antX, 38)
353        SKIPBITS(2)
354        GETBITSSIGN(handle->antY, 38)
355        SKIPBITS(2)
356        GETBITSSIGN(handle->antZ, 38)
357        if(type == 1006)
358          GETBITS(handle->antH, 16)
359        ret = type;
360      }
361      break;
362    case 1007: case 1008: case 1033:
363      {
364        char *antenna;
365        int antnum;
366
367        SKIPBITS(12)
368        GETSTRING(antnum,antenna)
369        memcpy(handle->antenna, antenna, antnum);
370        handle->antenna[antnum] = 0;
371        ret = type;
372      }
373      break;
374    case 1013:
375      {
376        SKIPBITS(12);
377        GETBITS(handle->modjulday, 16);
378        GETBITS(handle->secofday, 17);
379        SKIPBITS(5);
380        GETBITS(handle->leapsec, 8);
381        ret = 1013;
382      }
383      break;
384#endif /* NO_RTCM3_MAIN */
385    case 1019:
386      {
387        struct gpsephemeris *ge;
388        int sv, i;
389
390        ge = &handle->ephemerisGPS;
391        memset(ge, 0, sizeof(*ge));
392
393        GETBITS(sv, 6)
394        ge->satellite = (sv < 40 ? sv : sv+80);
395        GETBITS(ge->GPSweek, 10)
396        ge->GPSweek += 1024;
397        GETBITS(ge->URAindex, 4)
398        GETBITS(sv, 2)
399        if(sv & 1)
400          ge->flags |= GPSEPHF_L2PCODE;
401        if(sv & 2)
402          ge->flags |= GPSEPHF_L2CACODE;
403        GETFLOATSIGN(ge->IDOT, 14, R2R_PI/(double)(1<<30)/(double)(1<<13))
404        GETBITS(ge->IODE, 8)
405        GETBITS(ge->TOC, 16)
406        ge->TOC <<= 4;
407        GETFLOATSIGN(ge->clock_driftrate, 8, 1.0/(double)(1<<30)/(double)(1<<25))
408        GETFLOATSIGN(ge->clock_drift, 16, 1.0/(double)(1<<30)/(double)(1<<13))
409        GETFLOATSIGN(ge->clock_bias, 22, 1.0/(double)(1<<30)/(double)(1<<1))
410        GETBITS(ge->IODC, 10)
411        GETFLOATSIGN(ge->Crs, 16, 1.0/(double)(1<<5))
412        GETFLOATSIGN(ge->Delta_n, 16, R2R_PI/(double)(1<<30)/(double)(1<<13))
413        GETFLOATSIGN(ge->M0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
414        GETFLOATSIGN(ge->Cuc, 16, 1.0/(double)(1<<29))
415        GETFLOAT(ge->e, 32, 1.0/(double)(1<<30)/(double)(1<<3))
416        GETFLOATSIGN(ge->Cus, 16, 1.0/(double)(1<<29))
417        GETFLOAT(ge->sqrt_A, 32, 1.0/(double)(1<<19))
418        GETBITS(ge->TOE, 16)
419        ge->TOE <<= 4;
420
421        GETFLOATSIGN(ge->Cic, 16, 1.0/(double)(1<<29))
422        GETFLOATSIGN(ge->OMEGA0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
423        GETFLOATSIGN(ge->Cis, 16, 1.0/(double)(1<<29))
424        GETFLOATSIGN(ge->i0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
425        GETFLOATSIGN(ge->Crc, 16, 1.0/(double)(1<<5))
426        GETFLOATSIGN(ge->omega, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
427        GETFLOATSIGN(ge->OMEGADOT, 24, R2R_PI/(double)(1<<30)/(double)(1<<13))
428        GETFLOATSIGN(ge->TGD, 8, 1.0/(double)(1<<30)/(double)(1<<1))
429        GETBITS(ge->SVhealth, 6)
430        GETBITS(sv, 1)
431        if(sv)
432          ge->flags |= GPSEPHF_L2PCODEDATA;
433
434        i = ((int)ge->GPSweek - (int)handle->GPSWeek)*7*24*60*60
435        + ((int)ge->TOE - (int)handle->GPSTOW) - 2*60*60;
436        if(i > 5*60*60 && i < 8*60*60)
437        {
438          handle->GPSTOW = ge->TOE;
439          handle->GPSWeek = ge->GPSweek;
440        }
441        ge->TOW = 0.9999E9;
442        ret = 1019;
443      }
444      break;
445    case 1045:
446      {
447        struct galileoephemeris *ge;
448        int sv;
449
450        ge = &handle->ephemerisGALILEO;
451        memset(ge, 0, sizeof(*ge));
452
453        GETBITS(sv, 6)
454        ge->satellite = sv;
455        GETBITS(ge->Week, 12)
456        GETBITS(ge->IODnav, 10)
457        GETBITS(ge->SISA, 8)
458        GETFLOATSIGN(ge->IDOT, 14, R2R_PI/(double)(1<<30)/(double)(1<<13))
459        GETBITSFACTOR(ge->TOC, 14, 60)
460        GETFLOATSIGN(ge->clock_driftrate, 6, 1.0/(double)(1<<30)/(double)(1<<29))
461        GETFLOATSIGN(ge->clock_drift, 21, 1.0/(double)(1<<30)/(double)(1<<16))
462        GETFLOATSIGN(ge->clock_bias, 31, 1.0/(double)(1<<30)/(double)(1<<4))
463        GETFLOATSIGN(ge->Crs, 16, 1.0/(double)(1<<5))
464        GETFLOATSIGN(ge->Delta_n, 16, R2R_PI/(double)(1<<30)/(double)(1<<13))
465        GETFLOATSIGN(ge->M0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
466        GETFLOATSIGN(ge->Cuc, 16, 1.0/(double)(1<<29))
467        GETFLOAT(ge->e, 32, 1.0/(double)(1<<30)/(double)(1<<3))
468        GETFLOATSIGN(ge->Cus, 16, 1.0/(double)(1<<29))
469        GETFLOAT(ge->sqrt_A, 32, 1.0/(double)(1<<19))
470        GETBITSFACTOR(ge->TOE, 14, 60)
471        GETFLOATSIGN(ge->Cic, 16, 1.0/(double)(1<<29))
472        GETFLOATSIGN(ge->OMEGA0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
473        GETFLOATSIGN(ge->Cis, 16, 1.0/(double)(1<<29))
474        GETFLOATSIGN(ge->i0, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
475        GETFLOATSIGN(ge->Crc, 16, 1.0/(double)(1<<5))
476        GETFLOATSIGN(ge->omega, 32, R2R_PI/(double)(1<<30)/(double)(1<<1))
477        GETFLOATSIGN(ge->OMEGADOT, 24, R2R_PI/(double)(1<<30)/(double)(1<<13))
478        GETFLOATSIGN(ge->BGD_1_5A, 10, 1.0/(double)(1<<30)/(double)(1<<2))
479        GETFLOATSIGN(ge->BGD_1_5B, 10, 1.0/(double)(1<<30)/(double)(1<<2))
480        GETBITS(ge->E5aHS, 2)
481        GETBITS(sv, 1)
482        if(sv)
483          ge->flags |= GALEPHF_E5ADINVALID;
484        ret = 1045;
485      }
486      break;
487    case 1020:
488      {
489        struct glonassephemeris *ge;
490        int i;
491
492        ge = &handle->ephemerisGLONASS;
493        memset(ge, 0, sizeof(*ge));
494
495        ge->flags |= GLOEPHF_PAVAILABLE;
496        GETBITS(ge->almanac_number, 6)
497        GETBITS(i, 5)
498        ge->frequency_number = i-7;
499        if(ge->almanac_number >= 1 && ge->almanac_number <= PRN_GLONASS_NUM)
500          handle->GLOFreq[ge->almanac_number-1] = 100+ge->frequency_number;
501        GETBITS(i, 1)
502        if(i)
503          ge->flags |= GLOEPHF_ALMANACHEALTHY;
504        GETBITS(i, 1)
505        if(i)
506          ge->flags |= GLOEPHF_ALMANACHEALTHOK;
507        GETBITS(i, 2)
508        if(i & 1)
509          ge->flags |= GLOEPHF_P10TRUE;
510        if(i & 2)
511          ge->flags |= GLOEPHF_P11TRUE;
512        GETBITS(i, 5)
513        ge->tk = i*60*60;
514        GETBITS(i, 6)
515        ge->tk += i*60;
516        GETBITS(i, 1)
517        ge->tk += i*30;
518        GETBITS(i, 1)
519        if(i)
520          ge->flags |= GLOEPHF_UNHEALTHY;
521        GETBITS(i, 1)
522        if(i)
523          ge->flags |= GLOEPHF_P2TRUE;
524        GETBITS(i, 7)
525        ge->tb = i*15*60;
526        GETFLOATSIGNM(ge->x_velocity, 24, 1.0/(double)(1<<20))
527        GETFLOATSIGNM(ge->x_pos, 27, 1.0/(double)(1<<11))
528        GETFLOATSIGNM(ge->x_acceleration, 5, 1.0/(double)(1<<30))
529        GETFLOATSIGNM(ge->y_velocity, 24, 1.0/(double)(1<<20))
530        GETFLOATSIGNM(ge->y_pos, 27, 1.0/(double)(1<<11))
531        GETFLOATSIGNM(ge->y_acceleration, 5, 1.0/(double)(1<<30))
532        GETFLOATSIGNM(ge->z_velocity, 24, 1.0/(double)(1<<20))
533        GETFLOATSIGNM(ge->z_pos, 27, 1.0/(double)(1<<11))
534        GETFLOATSIGNM(ge->z_acceleration, 5, 1.0/(double)(1<<30))
535        GETBITS(i, 1)
536        if(i)
537          ge->flags |= GLOEPHF_P3TRUE;
538        GETFLOATSIGNM(ge->gamma, 11, 1.0/(double)(1<<30)/(double)(1<<10))
539        SKIPBITS(3) /* GLONASS-M P, GLONASS-M ln (third string) */
540        GETFLOATSIGNM(ge->tau, 22, 1.0/(double)(1<<30)) /* GLONASS tau n(tb) */
541        SKIPBITS(5) /* GLONASS-M delta tau n(tb) */
542        GETBITS(ge->E, 5)
543        /* GETBITS(b, 1) / * GLONASS-M P4 */
544        /* GETBITS(b, 4) / * GLONASS-M Ft */
545        /* GETBITS(b, 11) / * GLONASS-M Nt */
546        /* GETBITS(b, 2) / * GLONASS-M M */
547        /* GETBITS(b, 1) / * GLONASS-M The Availability of Additional Data */
548        /* GETBITS(b, 11) / * GLONASS-M Na */
549        /* GETFLOATSIGNM(b, 32, 1.0/(double)(1<<30)/(double)(1<<1)) / * GLONASS tau c */
550        /* GETBITS(b, 5) / * GLONASS-M N4 */
551        /* GETFLOATSIGNM(b, 22, 1.0/(double)(1<<30)/(double)(1<<1)) / * GLONASS-M tau GPS */
552        /* GETBITS(b, 1) / * GLONASS-M ln (fifth string) */
553        ge->GPSWeek = handle->GPSWeek;
554        ge->GPSTOW = handle->GPSTOW;
555        ret = 1020;
556      }
557      break;
558    case 1001: case 1002: case 1003: case 1004:
559      if(handle->GPSWeek)
560      {
561        int lastlockl1[64];
562        int lastlockl2[64];
563        struct gnssdata *gnss;
564        int i, numsats, wasamb=0;
565
566        for(i = 0; i < 64; ++i)
567          lastlockl1[i] = lastlockl2[i] = 0;
568
569        gnss = &handle->DataNew;
570
571        SKIPBITS(12) /* id */
572        GETBITS(i,30)
573        if(i/1000 < (int)handle->GPSTOW - 86400)
574          ++handle->GPSWeek;
575        handle->GPSTOW = i/1000;
576        if(gnss->week && (gnss->timeofweek != i || gnss->week
577        != handle->GPSWeek))
578        {
579          handle->Data = *gnss;
580          memset(gnss, 0, sizeof(*gnss));
581          old = 1;
582        }
583        gnss->timeofweek = i;
584        gnss->week = handle->GPSWeek;
585
586        GETBITS(syncf,1) /* sync */
587        GETBITS(numsats,5)
588        SKIPBITS(4) /* smind, smint */
589
590        while(numsats-- && gnss->numsats < GNSS_MAXSATS)
591        {
592          int sv, code, l1range, c,l,s,ce,le,se,amb=0;
593          int fullsat, num;
594
595          GETBITS(sv, 6)
596          fullsat = sv < 40 ? sv : sv+80;
597          for(num = 0; num < gnss->numsats
598          && fullsat != gnss->satellites[num]; ++num)
599            ;
600
601          if(num == gnss->numsats)
602            gnss->satellites[gnss->numsats++] = fullsat;
603
604          /* L1 */
605          GETBITS(code, 1);
606          if(code)
607          {
608            c = GNSSDF_P1DATA;  ce = GNSSENTRY_P1DATA;
609            l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
610            s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
611          }
612          else
613          {
614            c = GNSSDF_C1DATA;  ce = GNSSENTRY_C1DATA;
615            l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
616            s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
617          }
618          GETBITS(l1range, 24);
619          GETBITSSIGN(i, 20);
620          if((i&((1<<20)-1)) != 0x80000)
621          {
622            gnss->dataflags[num] |= (c|l);
623            gnss->measdata[num][ce] = l1range*0.02;
624            gnss->measdata[num][le] = l1range*0.02+i*0.0005;
625          }
626          GETBITS(i, 7);
627          lastlockl1[sv] = i;
628          if(handle->lastlockGPSl1[sv] > i || i == 0)
629            gnss->dataflags2[num] |= GNSSDF2_LOCKLOSSL1;
630          if(type == 1002 || type == 1004)
631          {
632            GETBITS(amb,8);
633            if(amb && (gnss->dataflags[num] & c))
634            {
635              gnss->measdata[num][ce] += amb*299792.458;
636              gnss->measdata[num][le] += amb*299792.458;
637              ++wasamb;
638            }
639            GETBITS(i, 8);
640            if(i)
641            {
642              gnss->dataflags[num] |= s;
643              gnss->measdata[num][se] = i*0.25;
644              i /= 4*4;
645              if(i > 9) i = 9;
646              else if(i < 1) i = 1;
647              gnss->snrL1[num] = i;
648            }
649          }
650          gnss->measdata[num][le] /= GPS_WAVELENGTH_L1;
651          if(type == 1003 || type == 1004)
652          {
653            /* L2 */
654            GETBITS(code,2);
655            if(code)
656            {
657              c = GNSSDF_P2DATA;  ce = GNSSENTRY_P2DATA;
658              l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
659              s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
660              if(code >= 2)
661                gnss->dataflags2[num] |= GNSSDF2_XCORRL2;
662            }
663            else
664            {
665              c = GNSSDF_C2DATA;  ce = GNSSENTRY_C2DATA;
666              l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
667              s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
668            }
669            GETBITSSIGN(i,14);
670            if((i&((1<<14)-1)) != 0x2000)
671            {
672              gnss->dataflags[num] |= c;
673              gnss->measdata[num][ce] = l1range*0.02+i*0.02
674              +amb*299792.458;
675            }
676            GETBITSSIGN(i,20);
677            if((i&((1<<20)-1)) != 0x80000)
678            {
679              gnss->dataflags[num] |= l;
680              gnss->measdata[num][le] = l1range*0.02+i*0.0005
681              +amb*299792.458;
682            }
683            GETBITS(i,7);
684            lastlockl2[sv] = i;
685            if(handle->lastlockGPSl2[sv] > i || i == 0)
686              gnss->dataflags2[num] |= GNSSDF2_LOCKLOSSL2;
687            if(type == 1004)
688            {
689              GETBITS(i, 8);
690              if(i)
691              {
692                gnss->dataflags[num] |= s;
693                gnss->measdata[num][se] = i*0.25;
694                i /= 4*4;
695                if(i > 9) i = 9;
696                else if(i < 1) i = 1;
697                gnss->snrL2[num] = i;
698              }
699            }
700            gnss->measdata[num][le] /= GPS_WAVELENGTH_L2;
701          }
702        }
703        for(i = 0; i < 64; ++i)
704        {
705          handle->lastlockGPSl1[i] = lastlockl1[i];
706          handle->lastlockGPSl2[i] = lastlockl2[i];
707        }
708        if(!syncf && !old)
709        {
710          handle->Data = *gnss;
711          memset(gnss, 0, sizeof(*gnss));
712        }
713        if(!syncf || old)
714        {
715          if(wasamb) /* not RINEX compatible without */
716            ret = 1;
717          else
718            ret = 2;
719        }
720#ifdef NO_RTCM3_MAIN
721        else
722          ret = type;
723#endif /* NO_RTCM3_MAIN */
724      }
725      break;
726    case 1009: case 1010: case 1011: case 1012:
727      {
728        int lastlockl1[64];
729        int lastlockl2[64];
730        struct gnssdata *gnss;
731        int i, numsats;
732        int wasamb=0;
733
734        for(i = 0; i < 64; ++i)
735          lastlockl1[i] = lastlockl2[i] = 0;
736
737        gnss = &handle->DataNew;
738
739        SKIPBITS(12) /* id */;
740        GETBITS(i,27) /* tk */
741
742        updatetime(&handle->GPSWeek, &handle->GPSTOW, i, 0); /* Moscow -> GPS */
743        i = handle->GPSTOW*1000;
744        if(gnss->week && (gnss->timeofweek != i || gnss->week
745        != handle->GPSWeek))
746        {
747          handle->Data = *gnss;
748          memset(gnss, 0, sizeof(*gnss));
749          old = 1;
750        }
751
752        gnss->timeofweek = i;
753        gnss->week = handle->GPSWeek;
754
755        GETBITS(syncf,1) /* sync */
756        GETBITS(numsats,5)
757
758        SKIPBITS(4) /* smind, smint */
759
760        while(numsats-- && gnss->numsats < GNSS_MAXSATS)
761        {
762          int sv, code, l1range, c,l,s,ce,le,se,amb=0;
763          int freq;
764          int fullsat, num;
765
766          GETBITS(sv, 6)
767          fullsat = sv-1 + PRN_GLONASS_START;
768          for(num = 0; num < gnss->numsats
769          && fullsat != gnss->satellites[num]; ++num)
770            ;
771
772          if(num == gnss->numsats)
773            gnss->satellites[gnss->numsats++] = fullsat;
774
775          /* L1 */
776          GETBITS(code, 1)
777          GETBITS(freq, 5)
778
779          if(sv >= 1 && sv <= PRN_GLONASS_NUM)
780            handle->GLOFreq[sv-1] = 100+freq-7;
781
782          if(code)
783          {
784            c = GNSSDF_P1DATA;  ce = GNSSENTRY_P1DATA;
785            l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
786            s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
787          }
788          else
789          {
790            c = GNSSDF_C1DATA;  ce = GNSSENTRY_C1DATA;
791            l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
792            s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
793          }
794          GETBITS(l1range, 25)
795          GETBITSSIGN(i, 20)
796          if((i&((1<<20)-1)) != 0x80000)
797          {
798            /* Handle this like GPS. Actually for GLONASS L1 range is always
799               valid. To be on the save side, we handle it as invalid like we
800               do for GPS and also remove range in case of 0x80000. */
801            gnss->dataflags[num] |= (c|l);
802            gnss->measdata[num][ce] = l1range*0.02;
803            gnss->measdata[num][le] = l1range*0.02+i*0.0005;
804          }
805          GETBITS(i, 7)
806          lastlockl1[sv] = i;
807          if(handle->lastlockGLOl1[sv] > i || i == 0)
808            gnss->dataflags2[num] |= GNSSDF2_LOCKLOSSL1;
809          if(type == 1010 || type == 1012)
810          {
811            GETBITS(amb,7)
812            if(amb && (gnss->dataflags[num] & c))
813            {
814              gnss->measdata[num][ce] += amb*599584.916;
815              gnss->measdata[num][le] += amb*599584.916;
816              ++wasamb;
817            }
818            GETBITS(i, 8)
819            if(i)
820            {
821              gnss->dataflags[num] |= s;
822              gnss->measdata[num][se] = i*0.25;
823              i /= 4*4;
824              if(i > 9) i = 9;
825              else if(i < 1) i = 1;
826              gnss->snrL1[num] = i;
827            }
828          }
829          gnss->measdata[num][le] /= GLO_WAVELENGTH_L1(freq-7);
830          if(type == 1011 || type == 1012)
831          {
832            /* L2 */
833            GETBITS(code,2)
834            if(code)
835            {
836              c = GNSSDF_P2DATA;  ce = GNSSENTRY_P2DATA;
837              l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
838              s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
839            }
840            else
841            {
842              c = GNSSDF_C2DATA;  ce = GNSSENTRY_C2DATA;
843              l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
844              s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
845            }
846            GETBITSSIGN(i,14)
847            if((i&((1<<14)-1)) != 0x2000)
848            {
849              gnss->dataflags[num] |= c;
850              gnss->measdata[num][ce] = l1range*0.02+i*0.02
851              +amb*599584.916;
852            }
853            GETBITSSIGN(i,20)
854            if((i&((1<<20)-1)) != 0x80000)
855            {
856              gnss->dataflags[num] |= l;
857              gnss->measdata[num][le] = l1range*0.02+i*0.0005
858              +amb*599584.916;
859            }
860            GETBITS(i,7)
861            lastlockl2[sv] = i;
862            if(handle->lastlockGLOl2[sv] > i || i == 0)
863              gnss->dataflags2[num] |= GNSSDF2_LOCKLOSSL2;
864            if(type == 1012)
865            {
866              GETBITS(i, 8)
867              if(i)
868              {
869                gnss->dataflags[num] |= s;
870                gnss->measdata[num][se] = i*0.25;
871                i /= 4*4;
872                if(i > 9) i = 9;
873                else if(i < 1) i = 1;
874                gnss->snrL2[num] = i;
875              }
876            }
877            gnss->measdata[num][le] /= GLO_WAVELENGTH_L2(freq-7);
878          }
879          if(!sv || sv > 24) /* illegal, remove it again */
880            --gnss->numsats;
881        }
882        for(i = 0; i < 64; ++i)
883        {
884          handle->lastlockGLOl1[i] = lastlockl1[i];
885          handle->lastlockGLOl2[i] = lastlockl2[i];
886        }
887        if(!syncf && !old)
888        {
889          handle->Data = *gnss;
890          memset(gnss, 0, sizeof(*gnss));
891        }
892        if(!syncf || old)
893        {
894          if(wasamb) /* not RINEX compatible without */
895            ret = 1;
896          else
897            ret = 2;
898        }
899#ifdef NO_RTCM3_MAIN
900        else
901          ret = type;
902#endif /* NO_RTCM3_MAIN */
903      }
904      break;
905    case 1071: case 1081: case 1091:
906    case 1072: case 1082: case 1092:
907    case 1073: case 1083: case 1093:
908    case 1074: case 1084: case 1094:
909    case 1075: case 1085: case 1095:
910    case 1076: case 1086: case 1096:
911    case 1077: case 1087: case 1097:
912      if(handle->GPSWeek)
913      {
914        struct CodeData {
915          int typeR;
916          int typeP;
917          int typeD;
918          int typeS;
919          int lock;
920          double wl;
921          const char *code; /* currently unused */
922        };
923        struct CodeData gps[RTCM3_MSM_NUMSIG] =
924        {
925          {0,0,0,0,0,0,0},
926          {GNSSENTRY_C1DATA,GNSSENTRY_L1CDATA,GNSSENTRY_D1CDATA,
927          GNSSENTRY_S1CDATA,GNSSDF2_LOCKLOSSL1,GPS_WAVELENGTH_L1,"1C"},
928          {GNSSENTRY_P1DATA,GNSSENTRY_L1PDATA,GNSSENTRY_D1PDATA,
929          GNSSENTRY_S1PDATA,GNSSDF2_LOCKLOSSL1,GPS_WAVELENGTH_L1,"1P"},
930          {GNSSENTRY_P1DATA,GNSSENTRY_L1PDATA,GNSSENTRY_D1PDATA,
931          GNSSENTRY_S1PDATA,GNSSDF2_LOCKLOSSL1,GPS_WAVELENGTH_L1,"1W"},
932          {GNSSENTRY_P1DATA,GNSSENTRY_L1PDATA,GNSSENTRY_D1PDATA,
933          GNSSENTRY_S1PDATA,GNSSDF2_LOCKLOSSL1,GPS_WAVELENGTH_L1,"1Y"},
934          {0,0,0,0,0,0,0},
935          {0,0,0,0,0,0,0},
936          {GNSSENTRY_C2DATA,GNSSENTRY_L2CDATA,GNSSENTRY_D2CDATA,
937          GNSSENTRY_S2CDATA,GNSSDF2_LOCKLOSSL2,GPS_WAVELENGTH_L2,"2C"},
938          {GNSSENTRY_P2DATA,GNSSENTRY_L2PDATA,GNSSENTRY_D2PDATA,
939          GNSSENTRY_S2PDATA,GNSSDF2_LOCKLOSSL2,GPS_WAVELENGTH_L2,"2P"},
940          {GNSSENTRY_P2DATA,GNSSENTRY_L2PDATA,GNSSENTRY_D2PDATA,
941          GNSSENTRY_S2PDATA,GNSSDF2_LOCKLOSSL2,GPS_WAVELENGTH_L2,"2W"},
942          {GNSSENTRY_P2DATA,GNSSENTRY_L2PDATA,GNSSENTRY_D2PDATA,
943          GNSSENTRY_S2PDATA,GNSSDF2_LOCKLOSSL2,GPS_WAVELENGTH_L2,"2Y"},
944          {0,0,0,0,0,0,0},
945          {0,0,0,0,0,0,0},
946          {0,0,0,0,0,0,0},
947          {GNSSENTRY_C2DATA,GNSSENTRY_L2CDATA,GNSSENTRY_D2CDATA,
948          GNSSENTRY_S2CDATA,GNSSDF2_LOCKLOSSL2,GPS_WAVELENGTH_L2,"2S"},
949          {GNSSENTRY_C2DATA,GNSSENTRY_L2CDATA,GNSSENTRY_D2CDATA,
950          GNSSENTRY_S2CDATA,GNSSDF2_LOCKLOSSL2,GPS_WAVELENGTH_L2,"2L"},
951          {GNSSENTRY_C2DATA,GNSSENTRY_L2CDATA,GNSSENTRY_D2CDATA,
952          GNSSENTRY_S2CDATA,GNSSDF2_LOCKLOSSL2,GPS_WAVELENGTH_L2,"2X"},
953          {0,0,0,0,0,0,0},
954          {0,0,0,0,0,0,0},
955          {0,0,0,0,0,0,0},
956          {0,0,0,0,0,0,0},
957          {GNSSENTRY_C5DATA,GNSSENTRY_L5DATA,GNSSENTRY_D5DATA,
958          GNSSENTRY_S5DATA,GNSSDF2_LOCKLOSSL5,GPS_WAVELENGTH_L5,"5I"},
959          {GNSSENTRY_C5DATA,GNSSENTRY_L5DATA,GNSSENTRY_D5DATA,
960          GNSSENTRY_S5DATA,GNSSDF2_LOCKLOSSL5,GPS_WAVELENGTH_L5,"5Q"},
961          {GNSSENTRY_C5DATA,GNSSENTRY_L5DATA,GNSSENTRY_D5DATA,
962          GNSSENTRY_S5DATA,GNSSDF2_LOCKLOSSL5,GPS_WAVELENGTH_L5,"5X"}
963        };
964        /* NOTE: Uses 0.0, 1.0 for wavelength as sat index dependence is done later! */
965        struct CodeData glo[RTCM3_MSM_NUMSIG] =
966        {
967          {0,0,0,0,0,0,0},
968          {GNSSENTRY_C1DATA,GNSSENTRY_L1CDATA,GNSSENTRY_D1CDATA,
969          GNSSENTRY_S1CDATA,GNSSDF2_LOCKLOSSL1,0.0,"1C"},
970          {GNSSENTRY_P1DATA,GNSSENTRY_L1PDATA,GNSSENTRY_D1PDATA,
971          GNSSENTRY_S1PDATA,GNSSDF2_LOCKLOSSL1,0.0,"1P"},
972          {0,0,0,0,0,0,0},
973          {0,0,0,0,0,0,0},
974          {0,0,0,0,0,0,0},
975          {0,0,0,0,0,0,0},
976          {GNSSENTRY_C2DATA,GNSSENTRY_L2CDATA,GNSSENTRY_D2CDATA,
977          GNSSENTRY_S2CDATA,GNSSDF2_LOCKLOSSL2,1.0,"2C"},
978          {GNSSENTRY_P2DATA,GNSSENTRY_L2PDATA,GNSSENTRY_D2PDATA,
979          GNSSENTRY_S2PDATA,GNSSDF2_LOCKLOSSL2,1.0,"2P"},
980          {0,0,0,0,0,0,0},
981          {0,0,0,0,0,0,0},
982          {0,0,0,0,0,0,0},
983          {0,0,0,0,0,0,0},
984          {0,0,0,0,0,0,0},
985          {0,0,0,0,0,0,0},
986          {0,0,0,0,0,0,0},
987          {0,0,0,0,0,0,0},
988          {0,0,0,0,0,0,0},
989          {0,0,0,0,0,0,0},
990          {0,0,0,0,0,0,0},
991          {0,0,0,0,0,0,0},
992          {0,0,0,0,0,0,0},
993          {0,0,0,0,0,0,0},
994          {0,0,0,0,0,0,0}
995        };
996        struct CodeData gal[RTCM3_MSM_NUMSIG] =
997        {
998          {0,0,0,0,0,0,0},
999          {GNSSENTRY_C1DATA,GNSSENTRY_L1CDATA,GNSSENTRY_D1CDATA,
1000          GNSSENTRY_S1CDATA,GNSSDF2_LOCKLOSSL1,GAL_WAVELENGTH_E1,"1C"},
1001          {GNSSENTRY_C1DATA,GNSSENTRY_L1CDATA,GNSSENTRY_D1CDATA,
1002          GNSSENTRY_S1CDATA,GNSSDF2_LOCKLOSSL1,GAL_WAVELENGTH_E1,"1A"},
1003          {GNSSENTRY_C1DATA,GNSSENTRY_L1CDATA,GNSSENTRY_D1CDATA,
1004          GNSSENTRY_S1CDATA,GNSSDF2_LOCKLOSSL1,GAL_WAVELENGTH_E1,"1B"},
1005          {GNSSENTRY_C1DATA,GNSSENTRY_L1CDATA,GNSSENTRY_D1CDATA,
1006          GNSSENTRY_S1CDATA,GNSSDF2_LOCKLOSSL1,GAL_WAVELENGTH_E1,"1X"},
1007          {GNSSENTRY_C1DATA,GNSSENTRY_L1CDATA,GNSSENTRY_D1CDATA,
1008          GNSSENTRY_S1CDATA,GNSSDF2_LOCKLOSSL1,GAL_WAVELENGTH_E1,"1Z"},
1009          {0,0,0,0,0,0,0},
1010          {GNSSENTRY_C6DATA,GNSSENTRY_L6DATA,GNSSENTRY_D6DATA,
1011          GNSSENTRY_S6DATA,GNSSDF2_LOCKLOSSE6,GAL_WAVELENGTH_E6,"6I"},
1012          {GNSSENTRY_C6DATA,GNSSENTRY_L6DATA,GNSSENTRY_D6DATA,
1013          GNSSENTRY_S6DATA,GNSSDF2_LOCKLOSSE6,GAL_WAVELENGTH_E6,"6Q"},
1014          {GNSSENTRY_C6DATA,GNSSENTRY_L6DATA,GNSSENTRY_D6DATA,
1015          GNSSENTRY_S6DATA,GNSSDF2_LOCKLOSSE6,GAL_WAVELENGTH_E6,"6I"},
1016          {GNSSENTRY_C6DATA,GNSSENTRY_L6DATA,GNSSENTRY_D6DATA,
1017          GNSSENTRY_S6DATA,GNSSDF2_LOCKLOSSE6,GAL_WAVELENGTH_E6,"6Q"},
1018          {GNSSENTRY_C6DATA,GNSSENTRY_L6DATA,GNSSENTRY_D6DATA,
1019          GNSSENTRY_S6DATA,GNSSDF2_LOCKLOSSE6,GAL_WAVELENGTH_E6,"6X"},
1020          {0,0,0,0,0,0,0},
1021          {GNSSENTRY_C5BDATA,GNSSENTRY_L5BDATA,GNSSENTRY_D5BDATA,
1022          GNSSENTRY_S5BDATA,GNSSDF2_LOCKLOSSE5B,GAL_WAVELENGTH_E5B,"7I"},
1023          {GNSSENTRY_C5BDATA,GNSSENTRY_L5BDATA,GNSSENTRY_D5BDATA,
1024          GNSSENTRY_S5BDATA,GNSSDF2_LOCKLOSSE5B,GAL_WAVELENGTH_E5B,"7Q"},
1025          {GNSSENTRY_C5BDATA,GNSSENTRY_L5BDATA,GNSSENTRY_D5BDATA,
1026          GNSSENTRY_S5BDATA,GNSSDF2_LOCKLOSSE5B,GAL_WAVELENGTH_E5B,"7X"},
1027          {0,0,0,0,0,0,0},
1028          {GNSSENTRY_C5ABDATA,GNSSENTRY_L5ABDATA,GNSSENTRY_D5ABDATA,
1029          GNSSENTRY_S5ABDATA,GNSSDF2_LOCKLOSSE5AB,GAL_WAVELENGTH_E5AB,"8I"},
1030          {GNSSENTRY_C5ABDATA,GNSSENTRY_L5ABDATA,GNSSENTRY_D5ABDATA,
1031          GNSSENTRY_S5ABDATA,GNSSDF2_LOCKLOSSE5AB,GAL_WAVELENGTH_E5AB,"8Q"},
1032          {GNSSENTRY_C5ABDATA,GNSSENTRY_L5ABDATA,GNSSENTRY_D5ABDATA,
1033          GNSSENTRY_S5ABDATA,GNSSDF2_LOCKLOSSE5AB,GAL_WAVELENGTH_E5AB,"8X"},
1034          {0,0,0,0,0,0,0},
1035          {GNSSENTRY_C5DATA,GNSSENTRY_L5DATA,GNSSENTRY_D5DATA,
1036          GNSSENTRY_S5DATA,GNSSDF2_LOCKLOSSL5,GAL_WAVELENGTH_E5A,"5I"},
1037          {GNSSENTRY_C5DATA,GNSSENTRY_L5DATA,GNSSENTRY_D5DATA,
1038          GNSSENTRY_S5DATA,GNSSDF2_LOCKLOSSL5,GAL_WAVELENGTH_E5A,"5Q"},
1039          {GNSSENTRY_C5DATA,GNSSENTRY_L5DATA,GNSSENTRY_D5DATA,
1040          GNSSENTRY_S5DATA,GNSSDF2_LOCKLOSSL5,GAL_WAVELENGTH_E5A,"5X"},
1041        };
1042
1043        int sys = RTCM3_MSM_GPS, i=0, count, j, old = 0, wasnoamb = 0;
1044        int syncf, sigmask, numsat = 0, numsig = 0, numcells;
1045        uint64_t satmask, cellmask, ui;
1046        double rrmod[RTCM3_MSM_NUMSAT];
1047        int rrint[RTCM3_MSM_NUMSAT], rdop[RTCM3_MSM_NUMSAT];
1048        int ll[RTCM3_MSM_NUMCELLS];
1049        double cnr[RTCM3_MSM_NUMCELLS];
1050        double cp[RTCM3_MSM_NUMCELLS], psr[RTCM3_MSM_NUMCELLS],
1051        dop[RTCM3_MSM_NUMCELLS];
1052        struct gnssdata *gnss = &handle->DataNew;
1053
1054        SKIPBITS(12)
1055        if(type >= 1091)
1056          sys = RTCM3_MSM_GALILEO;
1057        else if(type >= 1081)
1058          sys = RTCM3_MSM_GLONASS;
1059
1060        switch(sys)
1061        {
1062        case RTCM3_MSM_GALILEO: /* use DF004 instead of DF248 */
1063        case RTCM3_MSM_GPS:
1064          GETBITS(i,30)
1065          if(i/1000 < (int)handle->GPSTOW - 86400)
1066            ++handle->GPSWeek;
1067          handle->GPSTOW = i/1000;
1068          break;
1069        case RTCM3_MSM_GLONASS:
1070          SKIPBITS(3)
1071          GETBITS(i,27) /* tk */
1072
1073          updatetime(&handle->GPSWeek, &handle->GPSTOW, i, 0); /* Moscow -> GPS */
1074          i = handle->GPSTOW*1000;
1075          break;
1076        }
1077
1078        if(gnss->week && (gnss->timeofweek != i || gnss->week
1079        != handle->GPSWeek))
1080        {
1081          handle->Data = *gnss;
1082          memset(gnss, 0, sizeof(*gnss));
1083          old = 1;
1084        }
1085        gnss->timeofweek = i;
1086        gnss->week = handle->GPSWeek;
1087
1088        GETBITS(syncf, 1)
1089        SKIPBITS(3+7+1)
1090        GETBITS64(satmask, RTCM3_MSM_NUMSAT)
1091
1092        /* http://gurmeetsingh.wordpress.com/2008/08/05/fast-bit-counting-routines/ */
1093        for(ui = satmask; ui; ui &= (ui - 1) /* remove rightmost bit */)
1094          ++numsat;
1095        GETBITS(sigmask, RTCM3_MSM_NUMSIG)
1096        for(i = sigmask; i; i &= (i - 1) /* remove rightmost bit */)
1097          ++numsig;
1098        i = numsat*numsig;
1099        GETBITS64(cellmask, (unsigned)i)
1100
1101        switch(type % 10)
1102        {
1103        case 1: case 2: case 3:
1104          ++wasnoamb;
1105          for(j = numsat; j--;)
1106            GETFLOAT(rrmod[j], 10, 1/1024.0)
1107          break;
1108        case 4: case 6:
1109          for(j = numsat; j--;)
1110            GETBITS(rrint[j], 8)
1111          for(j = numsat; j--;)
1112            GETFLOAT(rrmod[j], 10, 1/1024.0)
1113          break;
1114        case 5: case 7:
1115          for(j = numsat; j--;)
1116            GETBITS(rrint[j], 8)
1117          for(j = numsat; j--;)
1118            GETFLOAT(rrmod[j], 10, 1/1024.0)
1119          for(j = numsat; j--;)
1120            GETBITSSIGN(rdop[j], 14)
1121          break;
1122        }
1123
1124        numcells = numsat*numsig;
1125        if(numcells <= RTCM3_MSM_NUMCELLS)
1126        {
1127          switch(type % 10)
1128          {
1129          case 1:
1130            for(count = numcells; count--;)
1131              if(cellmask & (UINT64(1)<<count))
1132                GETFLOATSIGN(psr[count], 15, 0.02)
1133            break;
1134          case 2:
1135            for(count = numcells; count--;)
1136              if(cellmask & (UINT64(1)<<count))
1137                GETFLOATSIGN(cp[count], 20, 1/256.0)
1138            for(count = numcells; count--;)
1139              if(cellmask & (UINT64(1)<<count))
1140                GETBITS(ll[count], 4)
1141            break;
1142          case 3:
1143            for(count = numcells; count--;)
1144              if(cellmask & (UINT64(1)<<count))
1145                GETFLOATSIGN(psr[count], 15, 0.02)
1146            for(count = numcells; count--;)
1147              if(cellmask & (UINT64(1)<<count))
1148                GETFLOATSIGN(cp[count], 20, 1/256.0)
1149            for(count = numcells; count--;)
1150              if(cellmask & (UINT64(1)<<count))
1151                GETBITS(ll[count], 4)
1152            break;
1153          case 4:
1154            for(count = numcells; count--;)
1155              if(cellmask & (UINT64(1)<<count))
1156                GETFLOATSIGN(psr[count], 15, 0.02)
1157            for(count = numcells; count--;)
1158              if(cellmask & (UINT64(1)<<count))
1159                GETFLOATSIGN(cp[count], 20, 1/256.0)
1160            for(count = numcells; count--;)
1161              if(cellmask & (UINT64(1)<<count))
1162                GETBITS(ll[count], 4)
1163            for(count = numcells; count--;)
1164              if(cellmask & (UINT64(1)<<count))
1165                GETBITS(cnr[count], 6)
1166            break;
1167          case 5:
1168            for(count = numcells; count--;)
1169              if(cellmask & (UINT64(1)<<count))
1170                GETFLOATSIGN(psr[count], 15, 0.02)
1171            for(count = numcells; count--;)
1172              if(cellmask & (UINT64(1)<<count))
1173                GETFLOATSIGN(cp[count], 20, 1/256.0)
1174            for(count = numcells; count--;)
1175              if(cellmask & (UINT64(1)<<count))
1176                GETBITS(ll[count], 4)
1177            for(count = numcells; count--;)
1178              if(cellmask & (UINT64(1)<<count))
1179                GETFLOAT(cnr[count], 6, 1.0)
1180            for(count = numcells; count--;)
1181              if(cellmask & (UINT64(1)<<count))
1182                GETFLOATSIGN(dop[count], 15, 0.0001)
1183            break;
1184          case 6:
1185            for(count = numcells; count--;)
1186              if(cellmask & (UINT64(1)<<count))
1187                GETFLOATSIGN(psr[count], 20, 0.001)
1188            for(count = numcells; count--;)
1189              if(cellmask & (UINT64(1)<<count))
1190                GETFLOATSIGN(cp[count], 22, 1/1024.0)
1191            for(count = numcells; count--;)
1192              if(cellmask & (UINT64(1)<<count))
1193                GETBITS(ll[count], 10)
1194            for(count = numcells; count--;)
1195              if(cellmask & (UINT64(1)<<count))
1196                GETFLOAT(cnr[count], 10, 0.1)
1197          case 7:
1198            for(count = numcells; count--;)
1199              if(cellmask & (UINT64(1)<<count))
1200                GETFLOATSIGN(psr[count], 20, 0.001)
1201            for(count = numcells; count--;)
1202              if(cellmask & (UINT64(1)<<count))
1203                GETFLOATSIGN(cp[count], 22, 1/1024.0)
1204            for(count = numcells; count--;)
1205              if(cellmask & (UINT64(1)<<count))
1206                GETBITS(ll[count], 10)
1207            for(count = numcells; count--;)
1208              if(cellmask & (UINT64(1)<<count))
1209                GETFLOAT(cnr[count], 10, 0.1)
1210            for(count = numcells; count--;)
1211              if(cellmask & (UINT64(1)<<count))
1212                GETFLOATSIGN(dop[count], 15, 0.0001)
1213            break;
1214          }
1215          i = RTCM3_MSM_NUMSAT;
1216          j = -1;
1217          for(count = numcells; count--;)
1218          {
1219            while(j >= 0 && !(sigmask&(1<<--j)))
1220              ;
1221            if(j < 0)
1222            {
1223              while(!(satmask&(UINT64(1)<<(--i)))) /* next satellite */
1224                ;
1225              j = RTCM3_MSM_NUMSIG;
1226              while(!(sigmask&(1<<--j)))
1227                ;
1228              --numsat;
1229            }
1230            if(cellmask & (UINT64(1)<<count))
1231            {
1232              struct CodeData cd = {0,0,0,0,0,0,0};
1233              double wl = 0.0;
1234              switch(sys)
1235              {
1236              case RTCM3_MSM_GPS: cd = gps[RTCM3_MSM_NUMSIG-j-1];
1237                wl = cd.wl;
1238                break;
1239              case RTCM3_MSM_GLONASS: cd = glo[RTCM3_MSM_NUMSIG-j-1];
1240                {
1241                  int k = handle->GLOFreq[RTCM3_MSM_NUMSAT-i-1];
1242                  if(k)
1243                  {
1244                    if(cd.wl == 0.0)
1245                      wl = GLO_WAVELENGTH_L1(k-100);
1246                    else if(cd.wl == 1.0)
1247                      wl = GLO_WAVELENGTH_L2(k-100);
1248                  }
1249                }
1250                break;
1251              case RTCM3_MSM_GALILEO: cd = gal[RTCM3_MSM_NUMSIG-j-1];
1252                wl = cd.wl;
1253                break;
1254              }
1255              if(cd.lock && wl) /* lock cannot have a valid zero value */
1256              {
1257                int fullsat = RTCM3_MSM_NUMSAT-i-1, num;
1258
1259                if(sys == RTCM3_MSM_GALILEO && fullsat >= 50 && fullsat <= 51)
1260                  fullsat += PRN_GIOVE_START-50;
1261                else
1262                  fullsat += sys;
1263
1264                for(num = 0; num < gnss->numsats
1265                && fullsat != gnss->satellites[num]; ++num)
1266                  ;
1267
1268                if(num == gnss->numsats)
1269                  gnss->satellites[gnss->numsats++] = fullsat;
1270
1271                switch(type % 10)
1272                {
1273                case 1:
1274                  if(psr[count] > -327.68)
1275                  {
1276                    gnss->measdata[num][cd.typeR] = psr[count]
1277                    +(rrmod[numsat])*LIGHTSPEED/1000.0;
1278                    gnss->dataflags[num] |= (1<<cd.typeR);
1279                  }
1280                  break;
1281                case 2:
1282                  if(wl && cp[count] > -2048.0)
1283                  {
1284                    gnss->measdata[num][cd.typeP] = cp[count]
1285                    +(rrmod[numsat])*LIGHTSPEED/1000.0/wl;
1286                    if(handle->lastlockmsm[j][i] != ll[count])
1287                    {
1288                      gnss->dataflags2[num] |= cd.lock;
1289                      handle->lastlockmsm[j][i] = ll[count];
1290                    }
1291                    gnss->dataflags[num] |= (1<<cd.typeP);
1292                  }
1293                  break;
1294                case 3:
1295                  if(psr[count] > -327.68)
1296                  {
1297                    gnss->measdata[num][cd.typeR] = psr[count]
1298                    +(rrmod[numsat])*LIGHTSPEED/1000.0;
1299                    gnss->dataflags[num] |= (1<<cd.typeR);
1300                  }
1301
1302                  if(wl && cp[count] > -2048.0)
1303                  {
1304                    gnss->measdata[num][cd.typeP] = cp[count]
1305                    +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0/wl;
1306                    if(handle->lastlockmsm[j][i] != ll[count])
1307                    {
1308                      gnss->dataflags2[num] |= cd.lock;
1309                      handle->lastlockmsm[j][i] = ll[count];
1310                    }
1311                    gnss->dataflags[num] |= (1<<cd.typeP);
1312                  }
1313                  break;
1314                case 4:
1315                  if(psr[count] > -327.68)
1316                  {
1317                    gnss->measdata[num][cd.typeR] = psr[count]
1318                    +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0;
1319                    gnss->dataflags[num] |= (1<<cd.typeR);
1320                  }
1321
1322                  if(wl && cp[count] > -2048.0)
1323                  {
1324                    gnss->measdata[num][cd.typeP] = cp[count]
1325                    +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0/wl;
1326                    if(handle->lastlockmsm[j][i] != ll[count])
1327                    {
1328                      gnss->dataflags2[num] |= cd.lock;
1329                      handle->lastlockmsm[j][i] = ll[count];
1330                    }
1331                    gnss->dataflags[num] |= (1<<cd.typeP);
1332                  }
1333
1334                  gnss->measdata[num][cd.typeS] = cnr[count];
1335                    gnss->dataflags[num] |= (1<<cd.typeS);
1336                  break;
1337                case 5:
1338                  if(psr[count] > -327.68)
1339                  {
1340                    gnss->measdata[num][cd.typeR] = psr[count]
1341                    +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0;
1342                    gnss->dataflags[num] |= (1<<cd.typeR);
1343                  }
1344
1345                  if(wl && cp[count] > -2048.0)
1346                  {
1347                    gnss->measdata[num][cd.typeP] = cp[count]
1348                    +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0/wl;
1349                    if(handle->lastlockmsm[j][i] != ll[count])
1350                    {
1351                      gnss->dataflags2[num] |= cd.lock;
1352                      handle->lastlockmsm[j][i] = ll[count];
1353                    }
1354                    gnss->dataflags[num] |= (1<<cd.typeP);
1355                  }
1356
1357                  gnss->measdata[num][cd.typeS] = cnr[count];
1358                    gnss->dataflags[num] |= (1<<cd.typeS);
1359
1360                  if(dop[count] > -1.6384)
1361                  {
1362                    gnss->measdata[num][cd.typeD] = -(dop[count]
1363                    +rdop[numsat])/wl;
1364                    gnss->dataflags[num] |= (1<<cd.typeD);
1365                  }
1366                  break;
1367                case 6:
1368                  if(psr[count] > -524.288)
1369                  {
1370                    gnss->measdata[num][cd.typeR] = psr[count]
1371                    +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0;
1372                    gnss->dataflags[num] |= (1<<cd.typeR);
1373                  }
1374
1375                  if(wl && cp[count] > -2048.0)
1376                  {
1377                    gnss->measdata[num][cd.typeP] = cp[count]
1378                    +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0/wl;
1379                    if(handle->lastlockmsm[j][i] != ll[count])
1380                    {
1381                      gnss->dataflags2[num] |= cd.lock;
1382                      handle->lastlockmsm[j][i] = ll[count];
1383                    }
1384                    gnss->dataflags[num] |= (1<<cd.typeP);
1385                  }
1386
1387                  gnss->measdata[num][cd.typeS] = cnr[count];
1388                    gnss->dataflags[num] |= (1<<cd.typeS);
1389                  break;
1390                case 7:
1391                  if(psr[count] > -524.288)
1392                  {
1393                    gnss->measdata[num][cd.typeR] = psr[count]
1394                    +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0;
1395                    gnss->dataflags[num] |= (1<<cd.typeR);
1396                  }
1397
1398                  if(wl && cp[count] > -2048.0)
1399                  {
1400                    gnss->measdata[num][cd.typeP] = cp[count]
1401                    +(rrmod[numsat]+rrint[numsat])*LIGHTSPEED/1000.0/wl;
1402                    if(handle->lastlockmsm[j][i] != ll[count])
1403                    {
1404                      gnss->dataflags2[num] |= cd.lock;
1405                      handle->lastlockmsm[j][i] = ll[count];
1406                    }
1407                    gnss->dataflags[num] |= (1<<cd.typeP);
1408                  }
1409
1410                  gnss->measdata[num][cd.typeS] = cnr[count];
1411                    gnss->dataflags[num] |= (1<<cd.typeS);
1412
1413                  if(dop[count] > -1.6384)
1414                  {
1415                    gnss->measdata[num][cd.typeD] = -(dop[count]
1416                    +rdop[numsat])/wl;
1417                    gnss->dataflags[num] |= (1<<cd.typeD);
1418                  }
1419                  break;
1420                }
1421              }
1422            }
1423          }
1424        }
1425        if(!syncf && !old)
1426        {
1427          handle->Data = *gnss;
1428          memset(gnss, 0, sizeof(*gnss));
1429        }
1430        if(!syncf || old)
1431        {
1432          if(!wasnoamb) /* not RINEX compatible without */
1433            ret = 1;
1434          else
1435            ret = 2;
1436        }
1437#ifdef NO_RTCM3_MAIN
1438        else
1439          ret = type;
1440#endif /* NO_RTCM3_MAIN */
1441      }
1442      break;
1443    }
1444  }
1445  return ret;
1446}
1447
1448struct Header
1449{
1450  const char *version;
1451  const char *pgm;
1452  const char *marker;
1453  const char *markertype;
1454  const char *observer;
1455  const char *receiver;
1456  const char *antenna;
1457  const char *position;
1458  const char *antennaposition;
1459  const char *wavelength;
1460  const char *typesofobs; /* should not be modified outside */
1461  const char *typesofobsG; /* should not be modified outside */
1462  const char *typesofobsR; /* should not be modified outside */
1463  const char *typesofobsS; /* should not be modified outside */
1464  const char *typesofobsE; /* should not be modified outside */
1465  const char *timeoffirstobs; /* should not be modified outside */
1466};
1467
1468#define MAXHEADERLINES 50
1469#define MAXHEADERBUFFERSIZE 4096
1470struct HeaderData
1471{
1472  union
1473  {
1474    struct Header named;
1475    const char *unnamed[MAXHEADERLINES];
1476  } data;
1477  int  numheaders;
1478};
1479
1480void converttime(struct converttimeinfo *c, int week, int tow)
1481{
1482  int i, k, doy, j; /* temporary variables */
1483  j = week*(7*24*60*60) + tow + 5*24*60*60;
1484  for(i = 1980; j >= (k = (365+longyear(i,0))*24*60*60); ++i)
1485    j -= k;
1486  c->year = i;
1487  doy = 1+ (j / (24*60*60));
1488  j %= (24*60*60);
1489  c->hour = j / (60*60);
1490  j %= (60*60);
1491  c->minute = j / 60;
1492  c->second = j % 60;
1493  j = 0;
1494  for(i = 1; j + (k = months[i] + longyear(c->year,i)) < doy; ++i)
1495    j += k;
1496  c->month = i;
1497  c->day = doy - j;
1498}
1499
1500#ifndef NO_RTCM3_MAIN
1501void RTCM3Error(const char *fmt, ...)
1502{
1503  va_list v;
1504  va_start(v, fmt);
1505  vfprintf(stderr, fmt, v);
1506  va_end(v);
1507}
1508#endif
1509
1510void RTCM3Text(const char *fmt, ...)
1511{
1512  va_list v;
1513  va_start(v, fmt);
1514  vprintf(fmt, v);
1515  va_end(v);
1516}
1517
1518static void fixrevision(void)
1519{
1520  if(revisionstr[0] == '$')
1521  {
1522    char *a;
1523    int i=sizeof(RTCM3TORINEX_VERSION); /* set version to 1.<revision> */
1524    strcpy(revisionstr, RTCM3TORINEX_VERSION ".");
1525    for(a = revisionstr+11; *a && *a != ' '; ++a)
1526      revisionstr[i++] = *a;
1527    revisionstr[i] = 0;
1528  }
1529}
1530
1531static int HandleRunBy(char *buffer, int buffersize, const char **u,
1532int rinex3)
1533{
1534  const char *user;
1535  time_t t;
1536  struct tm * t2;
1537
1538#ifdef NO_RTCM3_MAIN
1539  fixrevision();
1540#endif
1541
1542  user= getenv("USER");
1543  if(!user) user = "";
1544  t = time(&t);
1545  t2 = gmtime(&t);
1546  if(u) *u = user;
1547  return 1+snprintf(buffer, buffersize,
1548  rinex3 ?
1549  "RTCM3TORINEX %-7.7s%-20.20s%04d%02d%02d %02d%02d%02d UTC "
1550  "PGM / RUN BY / DATE" :
1551  "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d    "
1552  "PGM / RUN BY / DATE", revisionstr, user, 1900+t2->tm_year,
1553  t2->tm_mon+1, t2->tm_mday, t2->tm_hour, t2->tm_min, t2->tm_sec);
1554}
1555
1556#ifdef NO_RTCM3_MAIN
1557#define NUMSTARTSKIP 1
1558#else
1559#define NUMSTARTSKIP 3
1560#endif
1561
1562void HandleHeader(struct RTCM3ParserData *Parser)
1563{
1564#ifdef NO_RTCM3_MAIN
1565  int i;
1566  if(Parser->allflags == 0)
1567    Parser->allflags = ~0;
1568  if(Parser->rinex3)
1569  {
1570#define CHECKFLAGSNEW(a, b, c) \
1571    if(Parser->allflags & GNSSDF_##b##DATA) \
1572    { \
1573      Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
1574      Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
1575      ++Parser->numdatatypes##a; \
1576    }
1577
1578    CHECKFLAGSNEW(GPS, C1,  C1C)
1579    CHECKFLAGSNEW(GPS, L1C, L1C)
1580    CHECKFLAGSNEW(GPS, D1C, D1C)
1581    CHECKFLAGSNEW(GPS, S1C, S1C)
1582    CHECKFLAGSNEW(GPS, P1,  C1P)
1583    CHECKFLAGSNEW(GPS, L1P, L1P)
1584    CHECKFLAGSNEW(GPS, D1P, D1P)
1585    CHECKFLAGSNEW(GPS, S1P, S1P)
1586    CHECKFLAGSNEW(GPS, P2,  C2P)
1587    CHECKFLAGSNEW(GPS, L2P, L2P)
1588    CHECKFLAGSNEW(GPS, D2P, D2P)
1589    CHECKFLAGSNEW(GPS, S2P, S2P)
1590    CHECKFLAGSNEW(GPS, C2,  C2X)
1591    CHECKFLAGSNEW(GPS, L2C, L2X)
1592    CHECKFLAGSNEW(GPS, D2C, D2X)
1593    CHECKFLAGSNEW(GPS, S2C, S2X)
1594    CHECKFLAGSNEW(GLO, C1,  C1C)
1595    CHECKFLAGSNEW(GLO, L1C, L1C)
1596    CHECKFLAGSNEW(GLO, D1C, D1C)
1597    CHECKFLAGSNEW(GLO, S1C, S1C)
1598    CHECKFLAGSNEW(GLO, P1,  C1P)
1599    CHECKFLAGSNEW(GLO, L1P, L1P)
1600    CHECKFLAGSNEW(GLO, D1P, D1P)
1601    CHECKFLAGSNEW(GLO, S1P, S1P)
1602    CHECKFLAGSNEW(GLO, P2,  C2P)
1603    CHECKFLAGSNEW(GLO, L2P, L2P)
1604    CHECKFLAGSNEW(GLO, D2P, D2P)
1605    CHECKFLAGSNEW(GLO, S2P, S2P)
1606    CHECKFLAGSNEW(GLO, C2,  C2C)
1607    CHECKFLAGSNEW(GLO, L2C, L2C)
1608    CHECKFLAGSNEW(GLO, D2C, D2C)
1609    CHECKFLAGSNEW(GLO, S2C, S2C)
1610  }
1611  else
1612  {
1613#define CHECKFLAGS(a, b) \
1614    if(Parser->allflags & GNSSDF_##a##DATA) \
1615    { \
1616      if(data[RINEXENTRY_##b##DATA]) \
1617      { \
1618        Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
1619        Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
1620      } \
1621      else \
1622      { \
1623        Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
1624        Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
1625        data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
1626      } \
1627    }
1628
1629    int data[RINEXENTRY_NUMBER];
1630    for(i = 0; i < RINEXENTRY_NUMBER; ++i) data[i] = 0;
1631
1632    CHECKFLAGS(C1,C1)
1633    CHECKFLAGS(C2,C2)
1634    CHECKFLAGS(P1,P1)
1635    CHECKFLAGS(P2,P2)
1636    CHECKFLAGS(L1C,L1)
1637    CHECKFLAGS(L1P,L1)
1638    CHECKFLAGS(L2C,L2)
1639    CHECKFLAGS(L2P,L2)
1640    CHECKFLAGS(D1C,D1)
1641    CHECKFLAGS(D1P,D1)
1642    CHECKFLAGS(D2C,D2)
1643    CHECKFLAGS(D2P,D2)
1644    CHECKFLAGS(S1C,S1)
1645    CHECKFLAGS(S1P,S1)
1646    CHECKFLAGS(S2C,S2)
1647    CHECKFLAGS(S2P,S2)
1648    CHECKFLAGS(C5,C5)
1649    CHECKFLAGS(L5,L5)
1650    CHECKFLAGS(D5,D5)
1651    CHECKFLAGS(S5,S5)
1652    CHECKFLAGS(C5AB,C5AB)
1653    CHECKFLAGS(L5AB,L5AB)
1654    CHECKFLAGS(D5AB,D5AB)
1655    CHECKFLAGS(S5AB,S5AB)
1656    CHECKFLAGS(C5B,C5B)
1657    CHECKFLAGS(L5B,L5B)
1658    CHECKFLAGS(D5B,D5B)
1659    CHECKFLAGS(S5B,S5B)
1660    CHECKFLAGS(C6,C6)
1661    CHECKFLAGS(L6,L6)
1662    CHECKFLAGS(D6,D6)
1663    CHECKFLAGS(S6,S6)
1664  }
1665#else /* NO_RTCM3_MAIN */
1666  struct HeaderData hdata;
1667  char thebuffer[MAXHEADERBUFFERSIZE];
1668  char *buffer = thebuffer;
1669  size_t buffersize = sizeof(thebuffer);
1670  int i;
1671
1672  memset(&hdata, 0, sizeof(hdata));
1673
1674  hdata.data.named.version = buffer;
1675  i = 1+snprintf(buffer, buffersize,
1676  "%9.2f           OBSERVATION DATA    M (Mixed)"
1677  "           RINEX VERSION / TYPE", Parser->rinex3 ? 3.0 : 2.11);
1678  buffer += i; buffersize -= i;
1679
1680  {
1681    const char *str;
1682    hdata.data.named.pgm = buffer;
1683    i = HandleRunBy(buffer, buffersize, &str, Parser->rinex3);
1684    buffer += i; buffersize -= i;
1685    hdata.data.named.observer = buffer;
1686    i = 1+snprintf(buffer, buffersize,
1687    "%-20.20s                                        "
1688    "OBSERVER / AGENCY", str);
1689    buffer += i; buffersize -= i;
1690  }
1691
1692  hdata.data.named.marker =
1693  "RTCM3TORINEX                                                "
1694  "MARKER NAME";
1695
1696  hdata.data.named.markertype =  !Parser->rinex3 ? 0 :
1697  "GEODETIC                                                    "
1698  "MARKER TYPE";
1699
1700  hdata.data.named.receiver =
1701  "                                                            "
1702  "REC # / TYPE / VERS";
1703
1704  hdata.data.named.antenna =
1705  "                                                            "
1706  "ANT # / TYPE";
1707
1708  hdata.data.named.position =
1709  "         .0000         .0000         .0000                  "
1710  "APPROX POSITION XYZ";
1711
1712  hdata.data.named.antennaposition =
1713  "         .0000         .0000         .0000                  "
1714  "ANTENNA: DELTA H/E/N";
1715
1716  hdata.data.named.wavelength = Parser->rinex3 ? 0 :
1717  "     1     1                                                "
1718  "WAVELENGTH FACT L1/2";
1719
1720  if(Parser->rinex3)
1721  {
1722#define CHECKFLAGSNEW(a, b, c) \
1723    if(flags & GNSSDF_##b##DATA) \
1724    { \
1725      Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
1726      Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
1727      ++Parser->numdatatypes##a; \
1728      snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " %-3s", #c); \
1729      tbufferpos += 4; \
1730    }
1731
1732    int flags = Parser->startflags;
1733    char tbuffer[6*RINEXENTRY_NUMBER+1];
1734    int tbufferpos = 0;
1735    for(i = 0; i < Parser->Data.numsats; ++i)
1736      flags |= Parser->Data.dataflags[i];
1737
1738    CHECKFLAGSNEW(GPS, C1,  C1C)
1739    CHECKFLAGSNEW(GPS, L1C, L1C)
1740    CHECKFLAGSNEW(GPS, D1C, D1C)
1741    CHECKFLAGSNEW(GPS, S1C, S1C)
1742    CHECKFLAGSNEW(GPS, P1,  C1W)
1743    CHECKFLAGSNEW(GPS, L1P, L1W)
1744    CHECKFLAGSNEW(GPS, D1P, D1W)
1745    CHECKFLAGSNEW(GPS, S1P, S1W)
1746
1747    hdata.data.named.typesofobsS = buffer;
1748    i = 1+snprintf(buffer, buffersize,
1749    "S  %3d%-52.52s  SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
1750    buffer += i; buffersize -= i;
1751
1752    CHECKFLAGSNEW(GPS, P2,  C2P)
1753    CHECKFLAGSNEW(GPS, L2P, L2P)
1754    CHECKFLAGSNEW(GPS, D2P, D2P)
1755    CHECKFLAGSNEW(GPS, S2P, S2P)
1756    CHECKFLAGSNEW(GPS, C2,  C2X)
1757    CHECKFLAGSNEW(GPS, L2C, L2X)
1758    CHECKFLAGSNEW(GPS, D2C, D2X)
1759    CHECKFLAGSNEW(GPS, S2C, S2X)
1760    CHECKFLAGSNEW(GPS, C5,  C5)
1761    CHECKFLAGSNEW(GPS, L5,  L5)
1762    CHECKFLAGSNEW(GPS, D5,  D5)
1763    CHECKFLAGSNEW(GPS, S5,  S5)
1764
1765    hdata.data.named.typesofobsG = buffer;
1766    i = 1+snprintf(buffer, buffersize,
1767    "G  %3d%-52.52s  SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
1768    if(Parser->numdatatypesGPS>13)
1769    {
1770      i += snprintf(buffer+i-1, buffersize,
1771      "\n      %-52.52s  SYS / # / OBS TYPES", tbuffer+13*4);
1772    }
1773    buffer += i; buffersize -= i;
1774
1775    tbufferpos = 0;
1776
1777    CHECKFLAGSNEW(GLO, C1,  C1C)
1778    CHECKFLAGSNEW(GLO, L1C, L1C)
1779    CHECKFLAGSNEW(GLO, D1C, D1C)
1780    CHECKFLAGSNEW(GLO, S1C, S1C)
1781    CHECKFLAGSNEW(GLO, P1,  C1P)
1782    CHECKFLAGSNEW(GLO, L1P, L1P)
1783    CHECKFLAGSNEW(GLO, D1P, D1P)
1784    CHECKFLAGSNEW(GLO, S1P, S1P)
1785    CHECKFLAGSNEW(GLO, P2,  C2P)
1786    CHECKFLAGSNEW(GLO, L2P, L2P)
1787    CHECKFLAGSNEW(GLO, D2P, D2P)
1788    CHECKFLAGSNEW(GLO, S2P, S2P)
1789    CHECKFLAGSNEW(GLO, C2,  C2C)
1790    CHECKFLAGSNEW(GLO, L2C, L2C)
1791    CHECKFLAGSNEW(GLO, D2C, D2C)
1792    CHECKFLAGSNEW(GLO, S2C, S2C)
1793
1794    hdata.data.named.typesofobsR = buffer;
1795    i = 1+snprintf(buffer, buffersize,
1796    "R  %3d%-52.52s  SYS / # / OBS TYPES", Parser->numdatatypesGLO, tbuffer);
1797    if(Parser->numdatatypesGLO>13)
1798    {
1799      i += snprintf(buffer+i-1, buffersize,
1800      "\n      %-52.52s  SYS / # / OBS TYPES", tbuffer+13*4);
1801    }
1802    buffer += i; buffersize -= i;
1803
1804    tbufferpos = 0;
1805
1806    CHECKFLAGSNEW(GAL, C1,   C1)
1807    CHECKFLAGSNEW(GAL, L1C,  L1)
1808    CHECKFLAGSNEW(GAL, D1C,  D1)
1809    CHECKFLAGSNEW(GAL, S1C,  S1)
1810    CHECKFLAGSNEW(GAL, C6,   C6)
1811    CHECKFLAGSNEW(GAL, L6,   L6)
1812    CHECKFLAGSNEW(GAL, D6,   D6)
1813    CHECKFLAGSNEW(GAL, S6,   S6)
1814    CHECKFLAGSNEW(GAL, C5,   C5)
1815    CHECKFLAGSNEW(GAL, L5,   L5)
1816    CHECKFLAGSNEW(GAL, D5,   D5)
1817    CHECKFLAGSNEW(GAL, S5,   S5)
1818    CHECKFLAGSNEW(GAL, C5B,  C7)
1819    CHECKFLAGSNEW(GAL, L5B,  L7)
1820    CHECKFLAGSNEW(GAL, D5B,  D7)
1821    CHECKFLAGSNEW(GAL, S5B,  S7)
1822    CHECKFLAGSNEW(GAL, C5AB, C8)
1823    CHECKFLAGSNEW(GAL, L5AB, L8)
1824    CHECKFLAGSNEW(GAL, D5AB, D8)
1825    CHECKFLAGSNEW(GAL, S5AB, S8)
1826
1827    hdata.data.named.typesofobsE = buffer;
1828    i = 1+snprintf(buffer, buffersize,
1829    "E  %3d%-52.52s  SYS / # / OBS TYPES", Parser->numdatatypesGAL, tbuffer);
1830    if(Parser->numdatatypesGAL>13)
1831    {
1832      i += snprintf(buffer+i-1, buffersize,
1833      "\n      %-52.52s  SYS / # / OBS TYPES", tbuffer+13*4);
1834    }
1835    buffer += i; buffersize -= i;
1836  }
1837  else
1838  {
1839#define CHECKFLAGS(a, b) \
1840    if(flags & GNSSDF_##a##DATA) \
1841    { \
1842      if(data[RINEXENTRY_##b##DATA]) \
1843      { \
1844        Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
1845        Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
1846      } \
1847      else \
1848      { \
1849        Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
1850        Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
1851        data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
1852        snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, "    "#b); \
1853        tbufferpos += 6; \
1854      } \
1855    }
1856
1857    int flags = Parser->startflags;
1858    int data[RINEXENTRY_NUMBER];
1859    char tbuffer[6*RINEXENTRY_NUMBER+1];
1860    int tbufferpos = 0;
1861    for(i = 0; i < RINEXENTRY_NUMBER; ++i)
1862      data[i] = 0;
1863    for(i = 0; i < Parser->Data.numsats; ++i)
1864      flags |= Parser->Data.dataflags[i];
1865
1866    CHECKFLAGS(C1,C1)
1867    CHECKFLAGS(C2,C2)
1868    CHECKFLAGS(P1,P1)
1869    CHECKFLAGS(P2,P2)
1870    CHECKFLAGS(L1C,L1)
1871    CHECKFLAGS(L1P,L1)
1872    CHECKFLAGS(L2C,L2)
1873    CHECKFLAGS(L2P,L2)
1874    CHECKFLAGS(D1C,D1)
1875    CHECKFLAGS(D1P,D1)
1876    CHECKFLAGS(D2C,D2)
1877    CHECKFLAGS(D2P,D2)
1878    CHECKFLAGS(S1C,S1)
1879    CHECKFLAGS(S1P,S1)
1880    CHECKFLAGS(S2C,S2)
1881    CHECKFLAGS(S2P,S2)
1882    CHECKFLAGS(C5,C5)
1883    CHECKFLAGS(L5,L5)
1884    CHECKFLAGS(D5,D5)
1885    CHECKFLAGS(S5,S5)
1886    CHECKFLAGS(C5AB,C5AB)
1887    CHECKFLAGS(L5AB,L5AB)
1888    CHECKFLAGS(D5AB,D5AB)
1889    CHECKFLAGS(S5AB,S5AB)
1890    CHECKFLAGS(C5B,C5B)
1891    CHECKFLAGS(L5B,L5B)
1892    CHECKFLAGS(D5B,D5B)
1893    CHECKFLAGS(S5B,S5B)
1894    CHECKFLAGS(C6,C6)
1895    CHECKFLAGS(L6,L6)
1896    CHECKFLAGS(D6,D6)
1897    CHECKFLAGS(S6,S6)
1898
1899    hdata.data.named.typesofobs = buffer;
1900    i = 1+snprintf(buffer, buffersize,
1901    "%6d%-54.54s# / TYPES OF OBSERV", Parser->numdatatypesGPS, tbuffer);
1902    if(Parser->numdatatypesGPS>9)
1903    {
1904      i += snprintf(buffer+i-1, buffersize,
1905      "\n      %-54.54s# / TYPES OF OBSERV", tbuffer+9*6);
1906    }
1907    buffer += i; buffersize -= i;
1908  }
1909
1910  {
1911    struct converttimeinfo cti;
1912    converttime(&cti, Parser->Data.week,
1913    (int)floor(Parser->Data.timeofweek/1000.0));
1914    hdata.data.named.timeoffirstobs = buffer;
1915    i = 1+snprintf(buffer, buffersize,
1916    "  %4d    %2d    %2d    %2d    %2d   %10.7f     GPS         "
1917    "TIME OF FIRST OBS", cti.year, cti.month, cti.day, cti.hour,
1918    cti.minute, cti.second + fmod(Parser->Data.timeofweek/1000.0,1.0));
1919
1920    buffer += i; buffersize -= i;
1921  }
1922
1923  hdata.numheaders = 15;
1924
1925  if(Parser->headerfile)
1926  {
1927    FILE *fh;
1928    if((fh = fopen(Parser->headerfile, "r")))
1929    {
1930      size_t siz;
1931      char *lastblockstart;
1932      if((siz = fread(buffer, 1, buffersize-1, fh)) > 0)
1933      {
1934        buffer[siz] = '\n';
1935        if(siz == buffersize)
1936        {
1937          RTCM3Error("Header file is too large. Only %d bytes read.",
1938          (int)siz);
1939        }
1940        /* scan the file line by line and enter the entries in the list */
1941        /* warn for "# / TYPES OF OBSERV" and "TIME OF FIRST OBS" */
1942        /* overwrites entries, except for comments */
1943        lastblockstart = buffer;
1944        for(i = 0; i < (int)siz; ++i)
1945        {
1946          if(buffer[i] == '\n')
1947          { /* we found a line */
1948            char *end;
1949            while(buffer[i+1] == '\r')
1950              ++i; /* skip \r in case there are any */
1951            end = buffer+i;
1952            while(*end == '\t' || *end == ' ' || *end == '\r' || *end == '\n')
1953              *(end--) = 0;
1954            if(end-lastblockstart < 60+5) /* short line */
1955              RTCM3Error("Short Header line '%s' ignored.\n", lastblockstart);
1956            else
1957            {
1958              int pos;
1959              if(!strcmp("COMMENT", lastblockstart+60))
1960                pos = hdata.numheaders;
1961              else
1962              {
1963                for(pos = 0; pos < hdata.numheaders; ++pos)
1964                {
1965                  if(!strcmp(hdata.data.unnamed[pos]+60, lastblockstart+60))
1966                    break;
1967                }
1968                if(!strcmp("# / TYPES OF OBSERV", lastblockstart+60)
1969                || !strcmp("TIME OF FIRST OBS", lastblockstart+60))
1970                {
1971                  RTCM3Error("Overwriting header '%s' is dangerous.\n",
1972                  lastblockstart+60);
1973                }
1974              }
1975              if(pos >= MAXHEADERLINES)
1976              {
1977                RTCM3Error("Maximum number of header lines of %d reached.\n",
1978                MAXHEADERLINES);
1979              }
1980              else if(!strcmp("END OF HEADER", lastblockstart+60))
1981              {
1982                RTCM3Error("End of header ignored.\n");
1983              }
1984              else
1985              {
1986                hdata.data.unnamed[pos] = lastblockstart;
1987                if(pos == hdata.numheaders)
1988                  ++hdata.numheaders;
1989              }
1990            }
1991            lastblockstart = buffer+i+1;
1992          }
1993        }
1994      }
1995      else
1996      {
1997        RTCM3Error("Could not read data from headerfile '%s'.\n",
1998        Parser->headerfile);
1999      }
2000      fclose(fh);
2001    }
2002    else
2003    {
2004      RTCM3Error("Could not open header datafile '%s'.\n",
2005      Parser->headerfile);
2006    }
2007  }
2008
2009  for(i = 0; i < hdata.numheaders; ++i)
2010  {
2011    if(hdata.data.unnamed[i] && hdata.data.unnamed[i][0])
2012      RTCM3Text("%s\n", hdata.data.unnamed[i]);
2013  }
2014  RTCM3Text("                                                            "
2015  "END OF HEADER\n");
2016#endif
2017}
2018
2019static void ConvLine(FILE *file, const char *fmt, ...)
2020{
2021  char buffer[100], *b;
2022  va_list v;
2023  va_start(v, fmt);
2024  vsnprintf(buffer, sizeof(buffer), fmt, v);
2025  for(b = buffer; *b; ++b)
2026  {
2027    if(*b == 'e') *b = 'D';
2028  }
2029  fprintf(file, "%s", buffer);
2030  va_end(v);
2031}
2032
2033void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
2034{
2035  Parser->Message[Parser->MessageSize++] = byte;
2036  if(Parser->MessageSize >= Parser->NeedBytes)
2037  {
2038    int r;
2039    while((r = RTCM3Parser(Parser)))
2040    {
2041      if(r == 1020 || r == 1019)
2042      {
2043        FILE *file = 0;
2044
2045        if(Parser->rinex3 && !(file = Parser->gpsfile))
2046        {
2047          const char *n = Parser->gpsephemeris ? Parser->gpsephemeris : Parser->glonassephemeris;
2048          if(n)
2049          {
2050            if(!(Parser->gpsfile = fopen(n, "w")))
2051            {
2052              RTCM3Error("Could not open ephemeris output file.\n");
2053            }
2054            else
2055            {
2056              char buffer[100];
2057              fprintf(Parser->gpsfile,
2058              "%9.2f%11sN: GNSS NAV DATA    M: Mixed%12sRINEX VERSION / TYPE\n", 3.0, "", "");
2059              HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
2060              fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
2061            }
2062            Parser->gpsephemeris = 0;
2063            Parser->glonassephemeris = 0;
2064            file = Parser->gpsfile;
2065          }
2066        }
2067        else
2068        {
2069          if(r == 1020)
2070          {
2071            if(Parser->glonassephemeris)
2072            {
2073              if(!(Parser->glonassfile = fopen(Parser->glonassephemeris, "w")))
2074              {
2075                RTCM3Error("Could not open GLONASS ephemeris output file.\n");
2076              }
2077              else
2078              {
2079                char buffer[100];
2080                fprintf(Parser->glonassfile,
2081                "%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n", 2.1, "", "");
2082                HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
2083                fprintf(Parser->glonassfile, "%s\n%60sEND OF HEADER\n", buffer, "");
2084              }
2085              Parser->glonassephemeris = 0;
2086            }
2087            file = Parser->glonassfile;
2088          }
2089          else if(r == 1019)
2090          {
2091            if(Parser->gpsephemeris)
2092            {
2093              if(!(Parser->gpsfile = fopen(Parser->gpsephemeris, "w")))
2094              {
2095                RTCM3Error("Could not open GPS ephemeris output file.\n");
2096              }
2097              else
2098              {
2099                char buffer[100];
2100                fprintf(Parser->gpsfile,
2101                "%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 2.1, "", "");
2102                HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
2103                fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
2104              }
2105              Parser->gpsephemeris = 0;
2106            }
2107            file = Parser->gpsfile;
2108          }
2109        }
2110        if(file)
2111        {
2112          if(r == 1020)
2113          {
2114            struct glonassephemeris *e = &Parser->ephemerisGLONASS;
2115            int w = e->GPSWeek, tow = e->GPSTOW, i;
2116            struct converttimeinfo cti;
2117
2118            updatetime(&w, &tow, e->tb*1000, 1);  /* Moscow - > UTC */
2119            converttime(&cti, w, tow);
2120
2121            i = e->tk-3*60*60; if(i < 0) i += 86400;
2122
2123            if(Parser->rinex3)
2124              ConvLine(file, "R%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
2125              e->almanac_number, cti.year, cti.month, cti.day, cti.hour, cti.minute,
2126              cti.second, -e->tau, e->gamma, (double) i);
2127            else
2128              ConvLine(file, "%02d %02d %02d %02d %02d %02d%5.1f%19.12e%19.12e%19.12e\n",
2129              e->almanac_number, cti.year%100, cti.month, cti.day, cti.hour, cti.minute,
2130              (double) cti.second, -e->tau, e->gamma, (double) i);
2131            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->x_pos,
2132            e->x_velocity, e->x_acceleration, (e->flags & GLOEPHF_UNHEALTHY) ? 1.0 : 0.0);
2133            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->y_pos,
2134            e->y_velocity, e->y_acceleration, (double) e->frequency_number);
2135            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->z_pos,
2136            e->z_velocity, e->z_acceleration, (double) e->E);
2137          }
2138          else /* if(r == 1019) */
2139          {
2140            struct gpsephemeris *e = &Parser->ephemerisGPS;
2141            double d;                 /* temporary variable */
2142            unsigned long int i;       /* temporary variable */
2143            struct converttimeinfo cti;
2144            converttime(&cti, e->GPSweek, e->TOC);
2145
2146            if(Parser->rinex3)
2147              ConvLine(file, "G%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
2148              e->satellite, cti.year, cti.month, cti.day, cti.hour,
2149              cti.minute, cti.second, e->clock_bias, e->clock_drift,
2150              e->clock_driftrate);
2151            else
2152              ConvLine(file, "%02d %02d %02d %02d %02d %02d%05.1f%19.12e%19.12e%19.12e\n",
2153              e->satellite, cti.year%100, cti.month, cti.day, cti.hour,
2154              cti.minute, (double) cti.second, e->clock_bias, e->clock_drift,
2155              e->clock_driftrate);
2156            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", (double)e->IODE,
2157            e->Crs, e->Delta_n, e->M0);
2158            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->Cuc,
2159            e->e, e->Cus, e->sqrt_A);
2160            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n",
2161            (double) e->TOE, e->Cic, e->OMEGA0, e->Cis);
2162            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->i0,
2163            e->Crc, e->omega, e->OMEGADOT);
2164            d = 0;
2165            i = e->flags;
2166            if(i & GPSEPHF_L2CACODE)
2167              d += 2.0;
2168            if(i & GPSEPHF_L2PCODE)
2169              d += 1.0;
2170            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->IDOT, d,
2171            (double) e->GPSweek, i & GPSEPHF_L2PCODEDATA ? 1.0 : 0.0);
2172            if(e->URAindex <= 6) /* URA index */
2173              d = ceil(10.0*pow(2.0, 1.0+((double)e->URAindex)/2.0))/10.0;
2174            else
2175              d = ceil(10.0*pow(2.0, ((double)e->URAindex)/2.0))/10.0;
2176            /* 15 indicates not to use satellite. We can't handle this special
2177               case, so we create a high "non"-accuracy value. */
2178            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", d,
2179            ((double) e->SVhealth), e->TGD, ((double) e->IODC));
2180
2181            ConvLine(file, "   %19.12e%19.12e\n", ((double)e->TOW), 0.0);
2182            /* TOW */
2183          }
2184        }
2185      }
2186      else if (r == 1 || r == 2)
2187      {
2188        int i, j, o;
2189        struct converttimeinfo cti;
2190
2191        if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
2192        {
2193          ++Parser->init;
2194
2195          if(Parser->init == NUMSTARTSKIP)
2196            HandleHeader(Parser);
2197          else
2198          {
2199            for(i = 0; i < Parser->Data.numsats; ++i)
2200              Parser->startflags |= Parser->Data.dataflags[i];
2201            continue;
2202          }
2203        }
2204        if(r == 2 && !Parser->validwarning)
2205        {
2206          RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
2207          "           COMMENT\n");
2208          Parser->validwarning = 1;
2209        }
2210
2211        converttime(&cti, Parser->Data.week,
2212        (int)floor(Parser->Data.timeofweek/1000.0));
2213        if(Parser->rinex3)
2214        {
2215          RTCM3Text("> %04d %02d %02d %02d %02d%11.7f  0%3d\n",
2216          cti.year, cti.month, cti.day, cti.hour, cti.minute, cti.second
2217          + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
2218          for(i = 0; i < Parser->Data.numsats; ++i)
2219          {
2220            int glo = 0, gal = 0;
2221            if(Parser->Data.satellites[i] <= PRN_GPS_END)
2222              RTCM3Text("G%02d", Parser->Data.satellites[i]);
2223            else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
2224            && Parser->Data.satellites[i] <= PRN_GLONASS_END)
2225            {
2226              RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
2227              glo = 1;
2228            }
2229            else if(Parser->Data.satellites[i] >= PRN_GALILEO_START
2230            && Parser->Data.satellites[i] <= PRN_GALILEO_END)
2231            {
2232              RTCM3Text("E%02d", Parser->Data.satellites[i] - (PRN_GALILEO_START-1));
2233              gal = 1;
2234            }
2235            else if(Parser->Data.satellites[i] >= PRN_GIOVE_START
2236            && Parser->Data.satellites[i] <= PRN_GIOVE_END)
2237            {
2238              RTCM3Text("E%02d", Parser->Data.satellites[i] - (PRN_GIOVE_START-PRN_GIOVE_OFFSET));
2239              gal = 1;
2240            }
2241            else if(Parser->Data.satellites[i] >= PRN_WAAS_START
2242            && Parser->Data.satellites[i] <= PRN_WAAS_END)
2243              RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
2244            else
2245              RTCM3Text("%3d", Parser->Data.satellites[i]);
2246
2247            if(glo)
2248            {
2249              for(j = 0; j < Parser->numdatatypesGLO; ++j)
2250              {
2251                int df = Parser->dataflagGLO[j];
2252                int pos = Parser->dataposGLO[j];
2253                if((Parser->Data.dataflags[i] & df)
2254                && !isnan(Parser->Data.measdata[i][pos])
2255                && !isinf(Parser->Data.measdata[i][pos]))
2256                {
2257                  char lli = ' ';
2258                  char snr = ' ';
2259                  if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
2260                  {
2261                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSL1)
2262                      lli = '1';
2263                    snr = '0'+Parser->Data.snrL1[i];
2264                  }
2265                  if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
2266                  {
2267                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSL2)
2268                      lli = '1';
2269                    snr = '0'+Parser->Data.snrL2[i];
2270                  }
2271                  RTCM3Text("%14.3f%c%c",
2272                  Parser->Data.measdata[i][pos],lli,snr);
2273                }
2274                else
2275                { /* no or illegal data */
2276                  RTCM3Text("                ");
2277                }
2278              }
2279            }
2280            else if(gal)
2281            {
2282              for(j = 0; j < Parser->numdatatypesGAL; ++j)
2283              {
2284                int df = Parser->dataflagGAL[j];
2285                int pos = Parser->dataposGAL[j];
2286                if((Parser->Data.dataflags[i] & df)
2287                && !isnan(Parser->Data.measdata[i][pos])
2288                && !isinf(Parser->Data.measdata[i][pos]))
2289                {
2290                  char lli = ' ';
2291                  char snr = ' ';
2292                  if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
2293                  {
2294                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSL1)
2295                      lli = '1';
2296                    snr = '0'+Parser->Data.snrL1[i];
2297                  }
2298                  if(df & GNSSDF_L6DATA)
2299                  {
2300                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSE6)
2301                      lli = '1';
2302                    snr = ' ';
2303                  }
2304                  if(df & GNSSDF_L5DATA)
2305                  {
2306                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSL5)
2307                      lli = '1';
2308                    snr = ' ';
2309                  }
2310                  if(df & GNSSDF_L5BDATA)
2311                  {
2312                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSE5B)
2313                      lli = '1';
2314                    snr = ' ';
2315                  }
2316                  if(df & GNSSDF_L5ABDATA)
2317                  {
2318                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSE5AB)
2319                      lli = '1';
2320                    snr = ' ';
2321                  }
2322                  RTCM3Text("%14.3f%c%c",
2323                  Parser->Data.measdata[i][pos],lli,snr);
2324                }
2325                else
2326                { /* no or illegal data */
2327                  RTCM3Text("                ");
2328                }
2329              }
2330            }
2331            else
2332            {
2333              for(j = 0; j < Parser->numdatatypesGPS; ++j)
2334              {
2335                int df = Parser->dataflagGPS[j];
2336                int pos = Parser->dataposGPS[j];
2337                if((Parser->Data.dataflags[i] & df)
2338                && !isnan(Parser->Data.measdata[i][pos])
2339                && !isinf(Parser->Data.measdata[i][pos]))
2340                {
2341                  char lli = ' ';
2342                  char snr = ' ';
2343                  if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
2344                  {
2345                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSL1)
2346                      lli = '1';
2347                    snr = '0'+Parser->Data.snrL1[i];
2348                  }
2349                  if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
2350                  {
2351                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSL2)
2352                      lli = '1';
2353                    snr = '0'+Parser->Data.snrL2[i];
2354                  }
2355                  if(df & GNSSDF_L5DATA)
2356                  {
2357                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSL5)
2358                      lli = '1';
2359                    snr = ' ';
2360                  }
2361                  RTCM3Text("%14.3f%c%c",
2362                  Parser->Data.measdata[i][pos],lli,snr);
2363                }
2364                else
2365                { /* no or illegal data */
2366                  RTCM3Text("                ");
2367                }
2368              }
2369            }
2370            RTCM3Text("\n");
2371          }
2372        }
2373        else
2374        {
2375          RTCM3Text(" %02d %2d %2d %2d %2d %10.7f  0%3d",
2376          cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
2377          + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
2378          for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
2379          {
2380            if(Parser->Data.satellites[i] <= PRN_GPS_END)
2381              RTCM3Text("G%02d", Parser->Data.satellites[i]);
2382            else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
2383            && Parser->Data.satellites[i] <= PRN_GLONASS_END)
2384              RTCM3Text("R%02d", Parser->Data.satellites[i]
2385              - (PRN_GLONASS_START-1));
2386            else if(Parser->Data.satellites[i] >= PRN_WAAS_START
2387            && Parser->Data.satellites[i] <= PRN_WAAS_END)
2388              RTCM3Text("S%02d", Parser->Data.satellites[i]
2389              - PRN_WAAS_START+20);
2390            else if(Parser->Data.satellites[i] >= PRN_GALILEO_START
2391            && Parser->Data.satellites[i] <= PRN_GALILEO_END)
2392              RTCM3Text("E%02d", Parser->Data.satellites[i]
2393              - (PRN_GALILEO_START-1));
2394            else if(Parser->Data.satellites[i] >= PRN_GIOVE_START
2395            && Parser->Data.satellites[i] <= PRN_GIOVE_END)
2396              RTCM3Text("E%02d", Parser->Data.satellites[i]
2397              - (PRN_GIOVE_START-PRN_GIOVE_OFFSET));
2398            else
2399              RTCM3Text("%3d", Parser->Data.satellites[i]);
2400          }
2401          RTCM3Text("\n");
2402          o = 12;
2403          j = Parser->Data.numsats - 12;
2404          while(j > 0)
2405          {
2406            RTCM3Text("                                ");
2407            for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
2408            {
2409              if(Parser->Data.satellites[i] <= PRN_GPS_END)
2410                RTCM3Text("G%02d", Parser->Data.satellites[i]);
2411              else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
2412              && Parser->Data.satellites[i] <= PRN_GLONASS_END)
2413                RTCM3Text("R%02d", Parser->Data.satellites[i]
2414                - (PRN_GLONASS_START-1));
2415              else if(Parser->Data.satellites[i] >= PRN_WAAS_START
2416              && Parser->Data.satellites[i] <= PRN_WAAS_END)
2417                RTCM3Text("S%02d", Parser->Data.satellites[i]
2418                - PRN_WAAS_START+20);
2419              else if(Parser->Data.satellites[i] >= PRN_GALILEO_START
2420              && Parser->Data.satellites[i] <= PRN_GALILEO_END)
2421                RTCM3Text("E%02d", Parser->Data.satellites[i]
2422                - (PRN_GALILEO_START-1));
2423              else if(Parser->Data.satellites[i] >= PRN_GIOVE_START
2424              && Parser->Data.satellites[i] <= PRN_GIOVE_END)
2425                RTCM3Text("E%02d", Parser->Data.satellites[i]
2426                - (PRN_GIOVE_START-PRN_GIOVE_OFFSET));
2427              else
2428                RTCM3Text("%3d", Parser->Data.satellites[i]);
2429            }
2430            RTCM3Text("\n");
2431            j -= 12;
2432            o += 12;
2433          }
2434          for(i = 0; i < Parser->Data.numsats; ++i)
2435          {
2436            for(j = 0; j < Parser->numdatatypesGPS; ++j)
2437            {
2438              int v = 0;
2439              int df = Parser->dataflag[j];
2440              int pos = Parser->datapos[j];
2441              if((Parser->Data.dataflags[i] & df)
2442              && !isnan(Parser->Data.measdata[i][pos])
2443              && !isinf(Parser->Data.measdata[i][pos]))
2444              {
2445                v = 1;
2446              }
2447              else
2448              {
2449                df = Parser->dataflagGPS[j];
2450                pos = Parser->dataposGPS[j];
2451
2452                if((Parser->Data.dataflags[i] & df)
2453                && !isnan(Parser->Data.measdata[i][pos])
2454                && !isinf(Parser->Data.measdata[i][pos]))
2455                {
2456                  v = 1;
2457                }
2458              }
2459
2460              if(!v)
2461              { /* no or illegal data */
2462                RTCM3Text("                ");
2463              }
2464              else
2465              {
2466                char lli = ' ';
2467                char snr = ' ';
2468                if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
2469                {
2470                  if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSL1)
2471                    lli = '1';
2472                  snr = '0'+Parser->Data.snrL1[i];
2473                }
2474                if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
2475                {
2476                  if(Parser->Data.dataflags2[i]
2477                  & (GNSSDF2_LOCKLOSSL2|GNSSDF2_XCORRL2))
2478                  {
2479                    lli = '0';
2480                    if(Parser->Data.dataflags2[i] & GNSSDF2_LOCKLOSSL2)
2481                      lli += 1;
2482                    if(Parser->Data.dataflags2[i] & GNSSDF2_XCORRL2)
2483                      lli += 4;
2484                  }
2485                  snr = '0'+Parser->Data.snrL2[i];
2486                }
2487                if((df & GNSSDF_P2DATA) && (Parser->Data.dataflags2[i]
2488                & GNSSDF2_XCORRL2))
2489                  lli = '4';
2490                RTCM3Text("%14.3f%c%c",
2491                Parser->Data.measdata[i][pos],lli,snr);
2492              }
2493              if(j%5 == 4 || j == Parser->numdatatypesGPS-1)
2494                RTCM3Text("\n");
2495            }
2496          }
2497        }
2498      }
2499    }
2500  }
2501}
2502
2503#ifndef NO_RTCM3_MAIN
2504static char datestr[]     = "$Date: 2011-04-08 09:29:56 +0000 (Fri, 08 Apr 2011) $";
2505
2506/* The string, which is send as agent in HTTP request */
2507#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
2508
2509#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
2510
2511static const char encodingTable [64] = {
2512  'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
2513  'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
2514  'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
2515  'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
2516};
2517
2518/* does not buffer overrun, but breaks directly after an error */
2519/* returns the number of required bytes */
2520static int encode(char *buf, int size, const char *user, const char *pwd)
2521{
2522  unsigned char inbuf[3];
2523  char *out = buf;
2524  int i, sep = 0, fill = 0, bytes = 0;
2525
2526  while(*user || *pwd)
2527  {
2528    i = 0;
2529    while(i < 3 && *user) inbuf[i++] = *(user++);
2530    if(i < 3 && !sep)    {inbuf[i++] = ':'; ++sep; }
2531    while(i < 3 && *pwd)  inbuf[i++] = *(pwd++);
2532    while(i < 3)         {inbuf[i++] = 0; ++fill; }
2533    if(out-buf < size-1)
2534      *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
2535    if(out-buf < size-1)
2536      *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
2537               | ((inbuf [1] & 0xF0) >> 4)];
2538    if(out-buf < size-1)
2539    {
2540      if(fill == 2)
2541        *(out++) = '=';
2542      else
2543        *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
2544                 | ((inbuf [2] & 0xC0) >> 6)];
2545    }
2546    if(out-buf < size-1)
2547    {
2548      if(fill >= 1)
2549        *(out++) = '=';
2550      else
2551        *(out++) = encodingTable[inbuf [2] & 0x3F];
2552    }
2553    bytes += 4;
2554  }
2555  if(out-buf < size)
2556    *out = 0;
2557  return bytes;
2558}
2559
2560static int stop = 0;
2561
2562struct Args
2563{
2564  const char *server;
2565  const char *port;
2566  int         mode;
2567  int         timeout;
2568  int         rinex3;
2569  const char *user;
2570  const char *password;
2571  const char *proxyhost;
2572  const char *proxyport;
2573  const char *nmea;
2574  const char *data;
2575  const char *headerfile;
2576  const char *gpsephemeris;
2577  const char *glonassephemeris;
2578};
2579
2580/* option parsing */
2581#ifdef NO_LONG_OPTS
2582#define LONG_OPT(a)
2583#else
2584#define LONG_OPT(a) a
2585static struct option opts[] = {
2586{ "data",             required_argument, 0, 'd'},
2587{ "server",           required_argument, 0, 's'},
2588{ "password",         required_argument, 0, 'p'},
2589{ "port",             required_argument, 0, 'r'},
2590{ "timeout",          required_argument, 0, 't'},
2591{ "header",           required_argument, 0, 'f'},
2592{ "user",             required_argument, 0, 'u'},
2593{ "gpsephemeris",     required_argument, 0, 'E'},
2594{ "glonassephemeris", required_argument, 0, 'G'},
2595{ "rinex3",           no_argument,       0, '3'},
2596{ "proxyport",        required_argument, 0, 'R'},
2597{ "proxyhost",        required_argument, 0, 'S'},
2598{ "nmea",             required_argument, 0, 'n'},
2599{ "mode",             required_argument, 0, 'M'},
2600{ "help",             no_argument,       0, 'h'},
2601{0,0,0,0}};
2602#endif
2603#define ARGOPT "-d:s:p:r:t:f:u:E:G:M:S:R:n:h3"
2604
2605enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };
2606
2607static const char *geturl(const char *url, struct Args *args)
2608{
2609  static char buf[1000];
2610  static char *Buffer = buf;
2611  static char *Bufend = buf+sizeof(buf);
2612
2613  if(strncmp("ntrip:", url, 6))
2614    return "URL must start with 'ntrip:'.";
2615  url += 6; /* skip ntrip: */
2616
2617  if(*url != '@' && *url != '/')
2618  {
2619    /* scan for mountpoint */
2620    args->data = Buffer;
2621    while(*url && *url != '@' &&  *url != ';' &&*url != '/' && Buffer != Bufend)
2622      *(Buffer++) = *(url++);
2623    if(Buffer == args->data)
2624      return "Mountpoint required.";
2625    else if(Buffer >= Bufend-1)
2626      return "Parsing buffer too short.";
2627    *(Buffer++) = 0;
2628  }
2629
2630  if(*url == '/') /* username and password */
2631  {
2632    ++url;
2633    args->user = Buffer;
2634    while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
2635      *(Buffer++) = *(url++);
2636    if(Buffer == args->user)
2637      return "Username cannot be empty.";
2638    else if(Buffer >= Bufend-1)
2639      return "Parsing buffer too short.";
2640    *(Buffer++) = 0;
2641
2642    if(*url == ':') ++url;
2643
2644    args->password = Buffer;
2645    while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
2646      *(Buffer++) = *(url++);
2647    if(Buffer == args->password)
2648      return "Password cannot be empty.";
2649    else if(Buffer >= Bufend-1)
2650      return "Parsing buffer too short.";
2651    *(Buffer++) = 0;
2652  }
2653
2654  if(*url == '@') /* server */
2655  {
2656    ++url;
2657    if(*url != '@' && *url != ':')
2658    {
2659      args->server = Buffer;
2660      while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
2661        *(Buffer++) = *(url++);
2662      if(Buffer == args->server)
2663        return "Servername cannot be empty.";
2664      else if(Buffer >= Bufend-1)
2665        return "Parsing buffer too short.";
2666      *(Buffer++) = 0;
2667    }
2668
2669    if(*url == ':')
2670    {
2671      ++url;
2672      args->port = Buffer;
2673      while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
2674        *(Buffer++) = *(url++);
2675      if(Buffer == args->port)
2676        return "Port cannot be empty.";
2677      else if(Buffer >= Bufend-1)
2678        return "Parsing buffer too short.";
2679      *(Buffer++) = 0;
2680    }
2681
2682    if(*url == '@') /* proxy */
2683    {
2684      ++url;
2685      args->proxyhost = Buffer;
2686      while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
2687        *(Buffer++) = *(url++);
2688      if(Buffer == args->proxyhost)
2689        return "Proxy servername cannot be empty.";
2690      else if(Buffer >= Bufend-1)
2691        return "Parsing buffer too short.";
2692      *(Buffer++) = 0;
2693
2694      if(*url == ':')
2695      {
2696        ++url;
2697        args->proxyport = Buffer;
2698        while(*url && *url != ';' && Buffer != Bufend)
2699          *(Buffer++) = *(url++);
2700        if(Buffer == args->proxyport)
2701          return "Proxy port cannot be empty.";
2702        else if(Buffer >= Bufend-1)
2703          return "Parsing buffer too short.";
2704        *(Buffer++) = 0;
2705      }
2706    }
2707  }
2708  if(*url == ';') /* NMEA */
2709  {
2710    args->nmea = ++url;
2711    while(*url)
2712      ++url;
2713  }
2714
2715  return *url ? "Garbage at end of server string." : 0;
2716}
2717
2718static int getargs(int argc, char **argv, struct Args *args)
2719{
2720  int res = 1;
2721  int getoptr;
2722  int help = 0;
2723  char *t;
2724
2725  args->server = "www.euref-ip.net";
2726  args->port = "2101";
2727  args->timeout = 60;
2728  args->user = "";
2729  args->password = "";
2730  args->data = 0;
2731  args->headerfile = 0;
2732  args->gpsephemeris = 0;
2733  args->glonassephemeris = 0;
2734  args->rinex3 = 0;
2735  args->nmea = 0;
2736  args->proxyhost = 0;
2737  args->proxyport = "2101";
2738  args->mode = AUTO;
2739  help = 0;
2740
2741  do
2742  {
2743
2744#ifdef NO_LONG_OPTS
2745    switch((getoptr = getopt(argc, argv, ARGOPT)))
2746#else
2747    switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
2748#endif
2749    {
2750    case 's': args->server = optarg; break;
2751    case 'u': args->user = optarg; break;
2752    case 'p': args->password = optarg; break;
2753    case 'd': args->data = optarg; break;
2754    case 'f': args->headerfile = optarg; break;
2755    case 'E': args->gpsephemeris = optarg; break;
2756    case 'G': args->glonassephemeris = optarg; break;
2757    case 'r': args->port = optarg; break;
2758    case '3': args->rinex3 = 1; break;
2759    case 'S': args->proxyhost = optarg; break;
2760    case 'n': args->nmea = optarg; break;
2761    case 'R': args->proxyport = optarg; break;
2762    case 'h': help=1; break;
2763    case 'M':
2764      args->mode = 0;
2765      if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
2766        args->mode = NTRIP1;
2767      else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
2768        args->mode = HTTP;
2769      else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
2770        args->mode = RTSP;
2771      else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
2772        args->mode = AUTO;
2773      else args->mode = atoi(optarg);
2774      if((args->mode == 0) || (args->mode >= END))
2775      {
2776        fprintf(stderr, "Mode %s unknown\n", optarg);
2777        res = 0;
2778      }
2779      break;
2780    case 't':
2781      args->timeout = strtoul(optarg, &t, 10);
2782      if((t && *t) || args->timeout < 0)
2783        res = 0;
2784      break;
2785
2786    case 1:
2787      {
2788        const char *err;
2789        if((err = geturl(optarg, args)))
2790        {
2791          RTCM3Error("%s\n\n", err);
2792          res = 0;
2793        }
2794      }
2795      break;
2796    case -1: break;
2797    }
2798  } while(getoptr != -1 || !res);
2799
2800  datestr[0] = datestr[7];
2801  datestr[1] = datestr[8];
2802  datestr[2] = datestr[9];
2803  datestr[3] = datestr[10];
2804  datestr[5] = datestr[12];
2805  datestr[6] = datestr[13];
2806  datestr[8] = datestr[15];
2807  datestr[9] = datestr[16];
2808  datestr[4] = datestr[7] = '-';
2809  datestr[10] = 0;
2810
2811  if(args->gpsephemeris && args->glonassephemeris && args->rinex3)
2812  {
2813    RTCM3Error("RINEX3 produces a combined ephemeris file, but 2 files were specified.\n"
2814    "Please specify only one navigation file.\n");
2815    res = 0;
2816  }
2817  else if(!res || help)
2818  {
2819    RTCM3Error("Version %s (%s) GPL" COMPILEDATE
2820    "\nUsage: %s -s server -u user ...\n"
2821    " -d " LONG_OPT("--data             ") "the requested data set\n"
2822    " -f " LONG_OPT("--headerfile       ") "file for RINEX header information\n"
2823    " -s " LONG_OPT("--server           ") "the server name or address\n"
2824    " -p " LONG_OPT("--password         ") "the login password\n"
2825    " -r " LONG_OPT("--port             ") "the server port number (default 2101)\n"
2826    " -t " LONG_OPT("--timeout          ") "timeout in seconds (default 60)\n"
2827    " -u " LONG_OPT("--user             ") "the user name\n"
2828    " -E " LONG_OPT("--gpsephemeris     ") "output file for GPS ephemeris data\n"
2829    " -G " LONG_OPT("--glonassephemeris ") "output file for GLONASS ephemeris data\n"
2830    " -3 " LONG_OPT("--rinex3           ") "output RINEX type 3 data\n"
2831    " -S " LONG_OPT("--proxyhost        ") "proxy name or address\n"
2832    " -R " LONG_OPT("--proxyport        ") "proxy port, optional (default 2101)\n"
2833    " -n " LONG_OPT("--nmea             ") "NMEA string for sending to server\n"
2834    " -M " LONG_OPT("--mode             ") "mode for data request\n"
2835    "     Valid modes are:\n"
2836    "     1, h, http     NTRIP Version 2.0 Caster in TCP/IP mode\n"
2837    "     2, r, rtsp     NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
2838    "     3, n, ntrip1   NTRIP Version 1.0 Caster\n"
2839    "     4, a, auto     automatic detection (default)\n"
2840    "or using an URL:\n%s ntrip:data[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
2841    , revisionstr, datestr, argv[0], argv[0]);
2842    exit(1);
2843  }
2844  return res;
2845}
2846
2847/* let the output complete a block if necessary */
2848static void signalhandler(int sig)
2849{
2850  if(!stop)
2851  {
2852    RTCM3Error("Stop signal number %d received. "
2853    "Trying to terminate gentle.\n", sig);
2854    stop = 1;
2855    alarm(1);
2856  }
2857}
2858
2859#ifndef WINDOWSVERSION
2860static void WaitMicro(int mic)
2861{
2862  struct timeval tv;
2863  tv.tv_sec = mic/1000000;
2864  tv.tv_usec = mic%1000000;
2865#ifdef DEBUG
2866  fprintf(stderr, "Waiting %d micro seconds\n", mic);
2867#endif
2868  select(0, 0, 0, 0, &tv);
2869}
2870#else /* WINDOWSVERSION */
2871void WaitMicro(int mic)
2872{
2873   Sleep(mic/1000);
2874}
2875#endif /* WINDOWSVERSION */
2876
2877#define ALARMTIME   (2*60)
2878
2879/* for some reason we had to abort hard (maybe waiting for data */
2880#ifdef __GNUC__
2881static __attribute__ ((noreturn)) void signalhandler_alarm(
2882int sig __attribute__((__unused__)))
2883#else /* __GNUC__ */
2884static void signalhandler_alarm(int sig)
2885#endif /* __GNUC__ */
2886{
2887  RTCM3Error("Programm forcefully terminated.\n");
2888  exit(1);
2889}
2890
2891int main(int argc, char **argv)
2892{
2893  struct Args args;
2894  struct RTCM3ParserData Parser;
2895
2896  setbuf(stdout, 0);
2897  setbuf(stdin, 0);
2898  setbuf(stderr, 0);
2899
2900  fixrevision();
2901
2902  signal(SIGINT, signalhandler);
2903  signal(SIGALRM,signalhandler_alarm);
2904  signal(SIGQUIT,signalhandler);
2905  signal(SIGTERM,signalhandler);
2906  signal(SIGPIPE,signalhandler);
2907  memset(&Parser, 0, sizeof(Parser));
2908  {
2909    time_t tim;
2910    tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
2911    Parser.GPSWeek = tim/(7*24*60*60);
2912    Parser.GPSTOW = tim%(7*24*60*60);
2913  }
2914
2915  if(getargs(argc, argv, &args))
2916  {
2917    int sockfd, numbytes;
2918    char buf[MAXDATASIZE];
2919    struct sockaddr_in their_addr; /* connector's address information */
2920    struct hostent *he;
2921    struct servent *se;
2922    const char *server, *port, *proxyserver = 0;
2923    char proxyport[6];
2924    char *b;
2925    long i;
2926    struct timeval tv;
2927
2928    alarm(ALARMTIME);
2929
2930    Parser.headerfile = args.headerfile;
2931    Parser.glonassephemeris = args.glonassephemeris;
2932    Parser.gpsephemeris = args.gpsephemeris;
2933    Parser.rinex3 = args.rinex3;
2934
2935    if(args.proxyhost)
2936    {
2937      int p;
2938      if((i = strtol(args.port, &b, 10)) && (!b || !*b))
2939        p = i;
2940      else if(!(se = getservbyname(args.port, 0)))
2941      {
2942        RTCM3Error("Can't resolve port %s.", args.port);
2943        exit(1);
2944      }
2945      else
2946      {
2947        p = ntohs(se->s_port);
2948      }
2949      snprintf(proxyport, sizeof(proxyport), "%d", p);
2950      port = args.proxyport;
2951      proxyserver = args.server;
2952      server = args.proxyhost;
2953    }
2954    else
2955    {
2956      server = args.server;
2957      port = args.port;
2958    }
2959
2960    memset(&their_addr, 0, sizeof(struct sockaddr_in));
2961    if((i = strtol(port, &b, 10)) && (!b || !*b))
2962      their_addr.sin_port = htons(i);
2963    else if(!(se = getservbyname(port, 0)))
2964    {
2965      RTCM3Error("Can't resolve port %s.", port);
2966      exit(1);
2967    }
2968    else
2969    {
2970      their_addr.sin_port = se->s_port;
2971    }
2972    if(!(he=gethostbyname(server)))
2973    {
2974      RTCM3Error("Server name lookup failed for '%s'.\n", server);
2975      exit(1);
2976    }
2977    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
2978    {
2979      perror("socket");
2980      exit(1);
2981    }
2982
2983    tv.tv_sec  = args.timeout;
2984    tv.tv_usec = 0;
2985    if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval) ) == -1)
2986    {
2987      RTCM3Error("Function setsockopt: %s\n", strerror(errno));
2988      exit(1);
2989    }
2990
2991    their_addr.sin_family = AF_INET;
2992    their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2993
2994    if(args.data && args.mode == RTSP)
2995    {
2996      struct sockaddr_in local;
2997      int sockudp, localport;
2998      int cseq = 1;
2999      socklen_t len;
3000
3001      if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
3002      {
3003        perror("socket");
3004        exit(1);
3005      }
3006      /* fill structure with local address information for UDP */
3007      memset(&local, 0, sizeof(local));
3008      local.sin_family = AF_INET;
3009      local.sin_port = htons(0);
3010      local.sin_addr.s_addr = htonl(INADDR_ANY);
3011      len = sizeof(local);
3012      /* bind() in order to get a random RTP client_port */
3013      if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
3014      {
3015        perror("bind");
3016        exit(1);
3017      }
3018      if((getsockname(sockudp, (struct sockaddr*)&local, &len)) != -1)
3019      {
3020        localport = ntohs(local.sin_port);
3021      }
3022      else
3023      {
3024        perror("local access failed");
3025        exit(1);
3026      }
3027      if(connect(sockfd, (struct sockaddr *)&their_addr,
3028      sizeof(struct sockaddr)) == -1)
3029      {
3030        perror("connect");
3031        exit(1);
3032      }
3033      i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
3034      "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"
3035      "CSeq: %d\r\n"
3036      "Ntrip-Version: Ntrip/2.0\r\n"
3037      "Ntrip-Component: Ntripclient\r\n"
3038      "User-Agent: %s/%s\r\n"
3039      "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
3040      "Authorization: Basic ",
3041      args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
3042      args.data, cseq++, AGENTSTRING, revisionstr, localport);
3043      if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
3044      {
3045        RTCM3Error("Requested data too long\n");
3046        exit(1);
3047      }
3048      i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
3049      if(i > MAXDATASIZE-4)
3050      {
3051        RTCM3Error("Username and/or password too long\n");
3052        exit(1);
3053      }
3054      buf[i++] = '\r';
3055      buf[i++] = '\n';
3056      buf[i++] = '\r';
3057      buf[i++] = '\n';
3058      if(args.nmea)
3059      {
3060        int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
3061        if(j >= 0 && j < MAXDATASIZE-i)
3062          i += j;
3063        else
3064        {
3065          RTCM3Error("NMEA string too long\n");
3066          exit(1);
3067        }
3068      }
3069      if(send(sockfd, buf, (size_t)i, 0) != i)
3070      {
3071        perror("send");
3072        exit(1);
3073      }
3074      if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
3075      {
3076        if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
3077        {
3078          int serverport = 0, session = 0;
3079          const char *portcheck = "server_port=";
3080          const char *sessioncheck = "session: ";
3081          int l = strlen(portcheck)-1;
3082          int j=0;
3083          for(i = 0; j != l && i < numbytes-l; ++i)
3084          {
3085            for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
3086              ;
3087          }
3088          if(i == numbytes-l)
3089          {
3090            RTCM3Error("No server port number found\n");
3091            exit(1);
3092          }
3093          else
3094          {
3095            i+=l;
3096            while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
3097              serverport = serverport * 10 + buf[i++]-'0';
3098            if(buf[i] != '\r' && buf[i] != ';')
3099            {
3100              RTCM3Error("Could not extract server port\n");
3101              exit(1);
3102            }
3103          }
3104          l = strlen(sessioncheck)-1;
3105          j=0;
3106          for(i = 0; j != l && i < numbytes-l; ++i)
3107          {
3108            for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
3109              ;
3110          }
3111          if(i == numbytes-l)
3112          {
3113            RTCM3Error("No session number found\n");
3114            exit(1);
3115          }
3116          else
3117          {
3118            i+=l;
3119            while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
3120              session = session * 10 + buf[i++]-'0';
3121            if(buf[i] != '\r')
3122            {
3123              RTCM3Error("Could not extract session number\n");
3124              exit(1);
3125            }
3126          }
3127
3128          i = snprintf(buf, MAXDATASIZE,
3129          "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"
3130          "CSeq: %d\r\n"
3131          "Session: %d\r\n"
3132          "\r\n",
3133          args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
3134          args.data, cseq++, session);
3135
3136          if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
3137          {
3138            RTCM3Error("Requested data too long\n");
3139            exit(1);
3140          }
3141          if(send(sockfd, buf, (size_t)i, 0) != i)
3142          {
3143            perror("send");
3144            exit(1);
3145          }
3146          if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
3147          {
3148            if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
3149            {
3150              struct sockaddr_in addrRTP;
3151              /* fill structure with caster address information for UDP */
3152              memset(&addrRTP, 0, sizeof(addrRTP));
3153              addrRTP.sin_family = AF_INET;
3154              addrRTP.sin_port   = htons(serverport);
3155              their_addr.sin_addr = *((struct in_addr *)he->h_addr);
3156              len = sizeof(addrRTP);
3157              int ts = 0;
3158              int sn = 0;
3159              int ssrc = 0;
3160              int init = 0;
3161              int u, v, w;
3162              while(!stop && (i = recvfrom(sockudp, buf, 1526, 0,
3163              (struct sockaddr*) &addrRTP, &len)) > 0)
3164              {
3165                alarm(ALARMTIME);
3166                if(i >= 12+1 && (unsigned char)buf[0] == (2 << 6) && buf[1] == 0x60)
3167                {
3168                  u= ((unsigned char)buf[2]<<8)+(unsigned char)buf[3];
3169                  v = ((unsigned char)buf[4]<<24)+((unsigned char)buf[5]<<16)
3170                  +((unsigned char)buf[6]<<8)+(unsigned char)buf[7];
3171                  w = ((unsigned char)buf[8]<<24)+((unsigned char)buf[9]<<16)
3172                  +((unsigned char)buf[10]<<8)+(unsigned char)buf[11];
3173
3174                  if(init)
3175                  {
3176                    int z;
3177                    if(u < -30000 && sn > 30000) sn -= 0xFFFF;
3178                    if(ssrc != w || ts > v)
3179                    {
3180                      RTCM3Error("Illegal UDP data received.\n");
3181                      exit(1);
3182                    }
3183                    if(u > sn) /* don't show out-of-order packets */
3184                    for(z = 12; z < i && !stop; ++z)
3185                      HandleByte(&Parser, (unsigned int) buf[z]);
3186                  }
3187                  sn = u; ts = v; ssrc = w; init = 1;
3188                }
3189                else
3190                {
3191                  RTCM3Error("Illegal UDP header.\n");
3192                  exit(1);
3193                }
3194              }
3195            }
3196            i = snprintf(buf, MAXDATASIZE,
3197            "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"
3198            "CSeq: %d\r\n"
3199            "Session: %d\r\n"
3200            "\r\n",
3201            args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
3202            args.data, cseq++, session);
3203
3204            if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
3205            {
3206              RTCM3Error("Requested data too long\n");
3207              exit(1);
3208            }
3209            if(send(sockfd, buf, (size_t)i, 0) != i)
3210            {
3211              perror("send");
3212              exit(1);
3213            }
3214          }
3215          else
3216          {
3217            RTCM3Error("Could not start data stream.\n");
3218            exit(1);
3219          }
3220        }
3221        else
3222        {
3223          RTCM3Error("Could not setup initial control connection.\n");
3224          exit(1);
3225        }
3226      }
3227      else
3228      {
3229        perror("recv");
3230        exit(1);
3231      }
3232    }
3233    else
3234    {
3235      if(connect(sockfd, (struct sockaddr *)&their_addr,
3236      sizeof(struct sockaddr)) == -1)
3237      {
3238        perror("connect");
3239        exit(1);
3240      }
3241      if(!args.data)
3242      {
3243        i = snprintf(buf, MAXDATASIZE,
3244        "GET %s%s%s%s/ HTTP/1.0\r\n"
3245        "Host: %s\r\n%s"
3246        "User-Agent: %s/%s\r\n"
3247        "Connection: close\r\n"
3248        "\r\n"
3249        , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
3250        proxyserver ? ":" : "", proxyserver ? proxyport : "",
3251        args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
3252        AGENTSTRING, revisionstr);
3253      }
3254      else
3255      {
3256        i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
3257        "GET %s%s%s%s/%s HTTP/1.0\r\n"
3258        "Host: %s\r\n%s"
3259        "User-Agent: %s/%s\r\n"
3260        "Connection: close\r\n"
3261        "Authorization: Basic "
3262        , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
3263        proxyserver ? ":" : "", proxyserver ? proxyport : "",
3264        args.data, args.server,
3265        args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
3266        AGENTSTRING, revisionstr);
3267        if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
3268        {
3269          RTCM3Error("Requested data too long\n");
3270          exit(1);
3271        }
3272        i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
3273        if(i > MAXDATASIZE-4)
3274        {
3275          RTCM3Error("Username and/or password too long\n");
3276          exit(1);
3277        }
3278        buf[i++] = '\r';
3279        buf[i++] = '\n';
3280        buf[i++] = '\r';
3281        buf[i++] = '\n';
3282        if(args.nmea)
3283        {
3284          int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
3285          if(j >= 0 && j < MAXDATASIZE-i)
3286            i += j;
3287          else
3288          {
3289            RTCM3Error("NMEA string too long\n");
3290            exit(1);
3291          }
3292        }
3293      }
3294      if(send(sockfd, buf, (size_t)i, 0) != i)
3295      {
3296        perror("send");
3297        exit(1);
3298      }
3299      if(args.data)
3300      {
3301        int k = 0;
3302        int chunkymode = 0;
3303        int starttime = time(0);
3304        int lastout = starttime;
3305        int totalbytes = 0;
3306        int chunksize = 0;
3307
3308        while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
3309        {
3310          if(numbytes > 0)
3311            alarm(ALARMTIME);
3312          else
3313          {
3314            WaitMicro(100);
3315            continue;
3316          }
3317          if(!k)
3318          {
3319            if(numbytes > 17 && (!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17)
3320            || !strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)))
3321            {
3322              const char *datacheck = "Content-Type: gnss/data\r\n";
3323              const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
3324              int l = strlen(datacheck)-1;
3325              int j=0;
3326              for(i = 0; j != l && i < numbytes-l; ++i)
3327              {
3328                for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
3329                  ;
3330              }
3331              if(i == numbytes-l)
3332              {
3333                RTCM3Error("No 'Content-Type: gnss/data' found\n");
3334                exit(1);
3335              }
3336              l = strlen(chunkycheck)-1;
3337              j=0;
3338              for(i = 0; j != l && i < numbytes-l; ++i)
3339              {
3340                for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
3341                  ;
3342              }
3343              if(i < numbytes-l)
3344                chunkymode = 1;
3345            }
3346            else if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
3347            {
3348              RTCM3Error("Could not get the requested data: ");
3349              for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
3350              {
3351                RTCM3Error("%c", isprint(buf[k]) ? buf[k] : '.');
3352              }
3353              RTCM3Error("\n");
3354              exit(1);
3355            }
3356            else if(args.mode != NTRIP1)
3357            {
3358              if(args.mode != AUTO)
3359              {
3360                RTCM3Error("NTRIP version 2 HTTP connection failed%s.\n",
3361                args.mode == AUTO ? ", falling back to NTRIP1" : "");
3362              }
3363              if(args.mode == HTTP)
3364                exit(1);
3365            }
3366            ++k;
3367          }
3368          else
3369          {
3370            if(chunkymode)
3371            {
3372              int stop = 0;
3373              int pos = 0;
3374              while(!stop && pos < numbytes)
3375              {
3376                switch(chunkymode)
3377                {
3378                case 1: /* reading number starts */
3379                  chunksize = 0;
3380                  ++chunkymode; /* no break */
3381                case 2: /* during reading number */
3382                  i = buf[pos++];
3383                  if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
3384                  else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
3385                  else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
3386                  else if(i == '\r') ++chunkymode;
3387                  else if(i == ';') chunkymode = 5;
3388                  else stop = 1;
3389                  break;
3390                case 3: /* scanning for return */
3391                  if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
3392                  else stop = 1;
3393                  break;
3394                case 4: /* output data */
3395                  i = numbytes-pos;
3396                  if(i > chunksize) i = chunksize;
3397                  {
3398                    int z;
3399                    for(z = 0; z < i && !stop; ++z)
3400                      HandleByte(&Parser, (unsigned int) buf[pos+z]);
3401                  }
3402                  totalbytes += i;
3403                  chunksize -= i;
3404                  pos += i;
3405                  if(!chunksize)
3406                    chunkymode = 1;
3407                  break;
3408                case 5:
3409                  if(i == '\r') chunkymode = 3;
3410                  break;
3411                }
3412              }
3413              if(stop)
3414              {
3415                RTCM3Error("Error in chunky transfer encoding\n");
3416                break;
3417              }
3418            }
3419            else
3420            {
3421              totalbytes += numbytes;
3422              {
3423                int z;
3424                for(z = 0; z < numbytes && !stop; ++z)
3425                  HandleByte(&Parser, (unsigned int) buf[z]);
3426              }
3427            }
3428            if(totalbytes < 0) /* overflow */
3429            {
3430              totalbytes = 0;
3431              starttime = time(0);
3432              lastout = starttime;
3433            }
3434          }
3435        }
3436      }
3437      else
3438      {
3439        while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
3440        {
3441          alarm(ALARMTIME);
3442          fwrite(buf, (size_t)numbytes, 1, stdout);
3443        }
3444      }
3445      close(sockfd);
3446    }
3447  }
3448  return 0;
3449}
3450#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.