source: ntrip/trunk/rtcm3torinex/rtcm3torinex.c@ 439

Last change on this file since 439 was 439, checked in by stoecker, 17 years ago

added more version information in help view

File size: 38.3 KB
Line 
1/*
2 Converter for RTCM3 data to RINEX.
3 $Id: rtcm3torinex.c,v 1.17 2007/01/23 17:16:39 stoecker Exp $
4 Copyright (C) 2005-2006 by Dirk Stoecker <stoecker@euronik.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#include "rtcm3torinex.h"
51
52/* CVS revision and version */
53static char revisionstr[] = "$Revision: 1.17 $";
54
55#ifndef COMPILEDATE
56#define COMPILEDATE " built " __DATE__
57#endif
58
59static uint32_t CRC24(long size, const unsigned char *buf)
60{
61 uint32_t crc = 0;
62 int i;
63
64 while(size--)
65 {
66 crc ^= (*buf++) << (16);
67 for(i = 0; i < 8; i++)
68 {
69 crc <<= 1;
70 if(crc & 0x1000000)
71 crc ^= 0x01864cfb;
72 }
73 }
74 return crc;
75}
76
77static int GetMessage(struct RTCM3ParserData *handle)
78{
79 unsigned char *m, *e;
80 int i;
81
82 m = handle->Message+handle->SkipBytes;
83 e = handle->Message+handle->MessageSize;
84 handle->NeedBytes = handle->SkipBytes = 0;
85 while(e-m >= 3)
86 {
87 if(m[0] == 0xD3)
88 {
89 handle->size = ((m[1]&3)<<8)|m[2];
90 if(e-m >= handle->size+6)
91 {
92 if((uint32_t)((m[3+handle->size]<<16)|(m[3+handle->size+1]<<8)
93 |(m[3+handle->size+2])) == CRC24(handle->size+3, m))
94 {
95 handle->SkipBytes = handle->size;
96 break;
97 }
98 else
99 ++m;
100 }
101 else
102 {
103 handle->NeedBytes = handle->size+6;
104 break;
105 }
106 }
107 else
108 ++m;
109 }
110 if(e-m < 3)
111 handle->NeedBytes = 3;
112
113 /* copy buffer to front */
114 i = m - handle->Message;
115 if(i && m < e)
116 memmove(handle->Message, m, (size_t)(handle->MessageSize-i));
117 handle->MessageSize -= i;
118
119 return !handle->NeedBytes;
120}
121
122#define LOADBITS(a) \
123{ \
124 while((a) > numbits) \
125 { \
126 if(!size--) break; \
127 bitfield = (bitfield<<8)|*(data++); \
128 numbits += 8; \
129 } \
130}
131
132/* extract bits from data stream
133 b = variable to store result, a = number of bits */
134#define GETBITS(b, a) \
135{ \
136 LOADBITS(a) \
137 b = (bitfield<<(64-numbits))>>(64-(a)); \
138 numbits -= (a); \
139}
140
141/* extract bits from data stream
142 b = variable to store result, a = number of bits */
143#define GETBITSSIGN(b, a) \
144{ \
145 LOADBITS(a) \
146 b = ((int64_t)(bitfield<<(64-numbits)))>>(64-(a)); \
147 numbits -= (a); \
148}
149
150#define SKIPBITS(b) { LOADBITS(b) numbits -= (b); }
151
152struct leapseconds { /* specify the day of leap second */
153 int day; /* this is the day, where 23:59:59 exists 2 times */
154 int month; /* not the next day! */
155 int year;
156 int taicount;
157};
158static const int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
159static const struct leapseconds leap[] = {
160/*{31, 12, 1971, 11},*/
161/*{31, 12, 1972, 12},*/
162/*{31, 12, 1973, 13},*/
163/*{31, 12, 1974, 14},*/
164/*{31, 12, 1975, 15},*/
165/*{31, 12, 1976, 16},*/
166/*{31, 12, 1977, 17},*/
167/*{31, 12, 1978, 18},*/
168/*{31, 12, 1979, 19},*/
169{30, 06, 1981,20},
170{30, 06, 1982,21},
171{30, 06, 1983,22},
172{30, 06, 1985,23},
173{31, 12, 1987,24},
174{31, 12, 1989,25},
175{31, 12, 1990,26},
176{30, 06, 1992,27},
177{30, 06, 1993,28},
178{30, 06, 1994,29},
179{31, 12, 1995,30},
180{30, 06, 1997,31},
181{31, 12, 1998,32},
182{31, 12, 2005,33},
183{0,0,0,0} /* end marker */
184};
185#define LEAPSECONDS 14 /* only needed for approx. time */
186#define GPSLEAPSTART 19 /* 19 leap seconds existed at 6.1.1980 */
187
188static int longyear(int year, int month)
189{
190 if(!(year % 4) && (!(year % 400) || (year % 100)))
191 {
192 if(!month || month == 2)
193 return 1;
194 }
195 return 0;
196}
197
198static int gnumleap(int year, int month, int day)
199{
200 int ls = 0;
201 const struct leapseconds *l;
202
203 for(l = leap; l->taicount && year >= l->year; ++l)
204 {
205 if(year > l->year || month > l->month || day > l->day)
206 ls = l->taicount - GPSLEAPSTART;
207 }
208 return ls;
209}
210
211static void updatetime(int *week, int *tow, int tk)
212{
213 int y,m,d,k,l;
214 unsigned int j = *week*(7*24*60*60) + *tow + 5*24*60*60+3*60*60;
215 int glo_daynumber = 0, glo_timeofday;
216 for(y = 1980; j >= (unsigned int)(k = (l = (365+longyear(y,0)))*24*60*60)
217 + gnumleap(y+1,1,1); ++y)
218 {
219 j -= k; glo_daynumber += l;
220 }
221 for(m = 1; j >= (unsigned int)(k = (l = months[m]+longyear(y, m))*24*60*60)
222 + gnumleap(y, m+1, 1); ++m)
223 {
224 j -= k; glo_daynumber += l;
225 }
226 for(d = 1; j >= 24UL*60UL*60UL + gnumleap(y, m, d+1); ++d)
227 j -= 24*60*60;
228 glo_daynumber -= 16*365+4-d;
229 glo_timeofday = j-gnumleap(y, m, d);
230
231 if(tk < 5*60*1000 && glo_timeofday > 23*60*60)
232 *tow += 24*60*60;
233 else if(glo_timeofday < 5*60 && tk > 23*60*60*1000)
234 *tow -= 24*60*60;
235 *tow += tk/1000-glo_timeofday;
236 if(*tow < 0) {*tow += 24*60*60*7; --*week; }
237 if(*tow >= 24*60*60*7) {*tow -= 24*60*60*7; ++*week; }
238}
239
240int RTCM3Parser(struct RTCM3ParserData *handle)
241{
242 int ret=0;
243
244 while(!ret && GetMessage(handle))
245 {
246 /* using 64 bit integer types, as it is much easier than handling
247 the long datatypes in 32 bit */
248 uint64_t numbits = 0, bitfield = 0;
249 int size = handle->size, type;
250 int syncf, old = 0;
251 unsigned char *data = handle->Message+3;
252
253 GETBITS(type,12)
254 switch(type)
255 {
256 case 1001: case 1002: case 1003: case 1004:
257 if(handle->GPSWeek)
258 {
259 int lastlockl1[64];
260 int lastlockl2[64];
261 struct gnssdata *gnss;
262 int i, num, wasamb=0;
263
264 for(i = 0; i < 64; ++i)
265 lastlockl1[i] = lastlockl2[i] = 0;
266
267 gnss = &handle->DataNew;
268
269 SKIPBITS(12) /* id */
270 GETBITS(i,30)
271 if(i/1000 < (int)handle->GPSTOW - 86400)
272 ++handle->GPSWeek;
273 handle->GPSTOW = i/1000;
274 if(gnss->week && (gnss->timeofweek != i || gnss->week
275 != handle->GPSWeek))
276 {
277 handle->Data = *gnss;
278 memset(gnss, 0, sizeof(*gnss));
279 old = 1;
280 }
281 gnss->timeofweek = i;
282 gnss->week = handle->GPSWeek;
283
284 GETBITS(syncf,1) /* sync */
285 GETBITS(i,5)
286 gnss->numsats = i;
287 SKIPBITS(4) /* smind, smint */
288
289 for(num = 0; num < gnss->numsats; ++num)
290 {
291 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
292
293 GETBITS(sv, 6);
294 gnss->satellites[num] = (sv < 40 ? sv : sv+80);
295 /* L1 */
296 GETBITS(code, 1);
297 if(code)
298 {
299 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
300 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
301 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
302 }
303 else
304 {
305 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
306 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
307 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
308 }
309 GETBITS(l1range, 24);
310 if((l1range&((1<<24)-1)) != 0x80000)
311 {
312 gnss->dataflags[num] |= c;
313 gnss->measdata[num][ce] = l1range*0.02;
314 }
315 GETBITSSIGN(i, 20);
316 if((i&((1<<20)-1)) != 0x80000)
317 {
318 gnss->dataflags[num] |= l;
319 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
320 }
321 GETBITS(i, 7);
322 lastlockl1[sv] = i;
323 if(handle->lastlockl1[sv] > i)
324 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
325 if(type == 1002 || type == 1004)
326 {
327 GETBITS(amb,8);
328 if(amb && (gnss->dataflags[num] & c))
329 {
330 gnss->measdata[num][ce] += amb*299792.458;
331 gnss->measdata[num][le] += amb*299792.458;
332 ++wasamb;
333 }
334 GETBITS(i, 8);
335 if(i)
336 {
337 gnss->dataflags[num] |= s;
338 gnss->measdata[num][se] = i*0.25;
339 i /= 4*4;
340 if(i > 9) i = 9;
341 else if(i < 1) i = 1;
342 gnss->snrL1[num] = i;
343 }
344 }
345 gnss->measdata[num][le] /= GPS_WAVELENGTH_L1;
346 if(type == 1003 || type == 1004)
347 {
348 /* L2 */
349 GETBITS(code,2);
350 if(code)
351 {
352 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
353 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
354 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
355 }
356 else
357 {
358 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
359 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
360 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
361 }
362 GETBITSSIGN(i,14);
363 if((i&((1<<14)-1)) != 0x2000)
364 {
365 gnss->dataflags[num] |= c;
366 gnss->measdata[num][ce] = l1range*0.02+i*0.02
367 +amb*299792.458;
368 }
369 GETBITSSIGN(i,20);
370 if((i&((1<<20)-1)) != 0x80000)
371 {
372 gnss->dataflags[num] |= l;
373 gnss->measdata[num][le] = l1range*0.02+i*0.0005
374 +amb*299792.458;
375 }
376 GETBITS(i,7);
377 lastlockl2[sv] = i;
378 if(handle->lastlockl2[sv] > i)
379 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
380 if(type == 1004)
381 {
382 GETBITS(i, 8);
383 if(i)
384 {
385 gnss->dataflags[num] |= s;
386 gnss->measdata[num][se] = i*0.25;
387 i /= 4*4;
388 if(i > 9) i = 9;
389 else if(i < 1) i = 1;
390 gnss->snrL2[num] = i;
391 }
392 }
393 gnss->measdata[num][le] /= GPS_WAVELENGTH_L2;
394 }
395 }
396 for(i = 0; i < 64; ++i)
397 {
398 handle->lastlockl1[i] = lastlockl1[i];
399 handle->lastlockl2[i] = lastlockl2[i];
400 }
401 if(!syncf && !old)
402 {
403 handle->Data = *gnss;
404 memset(gnss, 0, sizeof(*gnss));
405 }
406 if(!syncf || old)
407 {
408 if(wasamb) /* not RINEX compatible without */
409 ret = 1;
410 else
411 ret = 2;
412 }
413 }
414 break;
415 case 1009: case 1010: case 1011: case 1012:
416 {
417 int lastlockl1[64];
418 int lastlockl2[64];
419 struct gnssdata *gnss;
420 int i, num;
421 int wasamb=0;
422
423 for(i = 0; i < 64; ++i)
424 lastlockl1[i] = lastlockl2[i] = 0;
425
426 gnss = &handle->DataNew;
427
428 SKIPBITS(12) /* id */;
429 GETBITS(i,27) /* tk */
430
431 updatetime(&handle->GPSWeek, &handle->GPSTOW, i);
432 i = handle->GPSTOW*1000;
433 if(gnss->week && (gnss->timeofweek != i || gnss->week
434 != handle->GPSWeek))
435 {
436 handle->Data = *gnss;
437 memset(gnss, 0, sizeof(*gnss));
438 old = 1;
439 }
440
441 gnss->timeofweek = i;
442 gnss->week = handle->GPSWeek;
443
444 GETBITS(syncf,1) /* sync */
445 GETBITS(i,5)
446 gnss->numsats += i;
447
448 SKIPBITS(4) /* smind, smint */
449
450 for(num = gnss->numsats-i; num < gnss->numsats; ++num)
451 {
452 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
453 int freq;
454
455 GETBITS(sv, 6)
456 gnss->satellites[num] = sv-1 + PRN_GLONASS_START;
457 /* L1 */
458 GETBITS(code, 1)
459 GETBITS(freq, 5)
460 if(code)
461 {
462 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
463 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
464 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
465 }
466 else
467 {
468 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
469 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
470 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
471 }
472 GETBITS(l1range, 25)
473 if((l1range&((1<<25)-1)) != 0x80000)
474 {
475 gnss->dataflags[num] |= c;
476 gnss->measdata[num][ce] = l1range*0.02;
477 }
478 GETBITSSIGN(i, 20)
479 if((i&((1<<20)-1)) != 0x80000)
480 {
481 gnss->dataflags[num] |= l;
482 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
483 }
484 GETBITS(i, 7)
485 lastlockl1[sv] = i;
486 if(handle->lastlockl1[sv] > i)
487 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
488 if(type == 1010 || type == 1012)
489 {
490 GETBITS(amb,7)
491 if(amb && (gnss->dataflags[num] & c))
492 {
493 gnss->measdata[num][ce] += amb*599584.916;
494 gnss->measdata[num][le] += amb*599584.916;
495 ++wasamb;
496 }
497 GETBITS(i, 8)
498 if(i)
499 {
500 gnss->dataflags[num] |= s;
501 gnss->measdata[num][se] = i*0.25;
502 i /= 4*4;
503 if(i > 9) i = 9;
504 else if(i < 1) i = 1;
505 gnss->snrL1[num] = i;
506 }
507 }
508 gnss->measdata[num][le] /= GLO_WAVELENGTH_L1(freq-7);
509 if(type == 1011 || type == 1012)
510 {
511 /* L2 */
512 GETBITS(code,2)
513 if(code)
514 {
515 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
516 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
517 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
518 }
519 else
520 {
521 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
522 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
523 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
524 }
525 GETBITSSIGN(i,14)
526 if((i&((1<<14)-1)) != 0x2000)
527 {
528 gnss->dataflags[num] |= c;
529 gnss->measdata[num][ce] = l1range*0.02+i*0.02
530 +amb*599584.916;
531 }
532 GETBITSSIGN(i,20)
533 if((i&((1<<20)-1)) != 0x80000)
534 {
535 gnss->dataflags[num] |= l;
536 gnss->measdata[num][le] = l1range*0.02+i*0.0005
537 +amb*599584.915;
538 }
539 GETBITS(i,7)
540 lastlockl2[sv] = i;
541 if(handle->lastlockl2[sv] > i)
542 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
543 if(type == 1012)
544 {
545 GETBITS(i, 8)
546 if(i)
547 {
548 gnss->dataflags[num] |= s;
549 gnss->measdata[num][se] = i*0.25;
550 i /= 4*4;
551 if(i > 9) i = 9;
552 else if(i < 1) i = 1;
553 gnss->snrL2[num] = i;
554 }
555 }
556 gnss->measdata[num][le] /= GLO_WAVELENGTH_L2(freq-7);
557 }
558 if(!sv || sv > 24)
559 {
560 --num; --gnss->numsats;
561 }
562 }
563 for(i = 0; i < 64; ++i)
564 {
565 handle->lastlockl1[i] = lastlockl1[i];
566 handle->lastlockl2[i] = lastlockl2[i];
567 }
568 if(!syncf && !old)
569 {
570 handle->Data = *gnss;
571 memset(gnss, 0, sizeof(*gnss));
572 }
573 if(!syncf || old)
574 {
575 if(wasamb) /* not RINEX compatible without */
576 ret = 1;
577 else
578 ret = 2;
579 }
580 }
581 break;
582 }
583 }
584 return ret;
585}
586
587struct Header
588{
589 const char *version;
590 const char *pgm;
591 const char *marker;
592 const char *observer;
593 const char *receiver;
594 const char *antenna;
595 const char *position;
596 const char *antennaposition;
597 const char *wavelength;
598 const char *typesofobs; /* should not be modified outside */
599 const char *timeoffirstobs; /* should not be modified outside */
600};
601
602#define MAXHEADERLINES 50
603#define MAXHEADERBUFFERSIZE 4096
604struct HeaderData
605{
606 union
607 {
608 struct Header named;
609 const char *unnamed[MAXHEADERLINES];
610 } data;
611 int numheaders;
612};
613
614struct converttimeinfo {
615 int second; /* seconds of GPS time [0..59] */
616 int minute; /* minutes of GPS time [0..59] */
617 int hour; /* hour of GPS time [0..24] */
618 int day; /* day of GPS time [1..28..30(31)*/
619 int month; /* month of GPS time [1..12]*/
620 int year; /* year of GPS time [1980..] */
621};
622
623static void converttime(struct converttimeinfo *c, int week, int tow)
624{
625 int i, k, doy, j; /* temporary variables */
626 j = week*(7*24*60*60) + tow + 5*24*60*60;
627 for(i = 1980; j >= (k = (365+longyear(i,0))*24*60*60); ++i)
628 j -= k;
629 c->year = i;
630 doy = 1+ (j / (24*60*60));
631 j %= (24*60*60);
632 c->hour = j / (60*60);
633 j %= (60*60);
634 c->minute = j / 60;
635 c->second = j % 60;
636 j = 0;
637 for(i = 1; j + (k = months[i] + longyear(c->year,i)) < doy; ++i)
638 j += k;
639 c->month = i;
640 c->day = doy - j;
641}
642
643#ifndef NO_RTCM3_MAIN
644void RTCM3Error(const char *fmt, ...)
645{
646 va_list v;
647 va_start(v, fmt);
648 vfprintf(stderr, fmt, v);
649 va_end(v);
650}
651#endif
652
653void RTCM3Text(const char *fmt, ...)
654{
655 va_list v;
656 va_start(v, fmt);
657 vprintf(fmt, v);
658 va_end(v);
659}
660
661#define NUMSTARTSKIP 3
662void HandleHeader(struct RTCM3ParserData *Parser)
663{
664 struct HeaderData hdata;
665 char thebuffer[MAXHEADERBUFFERSIZE];
666 char *buffer = thebuffer;
667 size_t buffersize = sizeof(thebuffer);
668 int i;
669
670 hdata.data.named.version =
671 " 2.11 OBSERVATION DATA M (Mixed)"
672 " RINEX VERSION / TYPE";
673
674 {
675 const char *str;
676 time_t t;
677 struct tm * t2;
678
679#ifdef NO_RTCM3_MAIN
680 if(revisionstr[0] == '$')
681 {
682 char *a;
683 int i=0;
684 for(a = revisionstr+11; *a && *a != ' '; ++a)
685 revisionstr[i++] = *a;
686 revisionstr[i] = 0;
687 }
688#endif
689
690 str = getenv("USER");
691 if(!str) str = "";
692 t = time(&t);
693 t2 = gmtime(&t);
694 hdata.data.named.pgm = buffer;
695 i = 1+snprintf(buffer, buffersize,
696 "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d "
697 "PGM / RUN BY / DATE",
698 revisionstr, str, 1900+t2->tm_year, t2->tm_mon+1, t2->tm_mday, t2->tm_hour,
699 t2->tm_min);
700 buffer += i; buffersize -= i;
701
702 hdata.data.named.observer = buffer;
703 i = 1+snprintf(buffer, buffersize,
704 "%-20.20s "
705 "OBSERVER / AGENCY", str);
706 buffer += i; buffersize -= i;
707 }
708
709 hdata.data.named.marker =
710 "RTCM3TORINEX "
711 "MARKER NAME";
712
713 hdata.data.named.receiver =
714 " "
715 "REC # / TYPE / VERS";
716
717 hdata.data.named.antenna =
718 " "
719 "ANT # / TYPE";
720
721 hdata.data.named.position =
722 " .0000 .0000 .0000 "
723 "APPROX POSITION XYZ";
724
725 hdata.data.named.antennaposition =
726 " .0000 .0000 .0000 "
727 "ANTENNA: DELTA H/E/N";
728
729 hdata.data.named.wavelength =
730 " 1 1 "
731 "WAVELENGTH FACT L1/2";
732
733 {
734#define CHECKFLAGS(a, b) \
735 if(flags & GNSSDF_##a##DATA) \
736 { \
737 if(data[RINEXENTRY_##b##DATA]) \
738 { \
739 Parser->dataflag2[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
740 Parser->datapos2[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
741 } \
742 else \
743 { \
744 Parser->dataflag[Parser->numdatatypes] = GNSSDF_##a##DATA; \
745 Parser->datapos[Parser->numdatatypes] = GNSSENTRY_##a##DATA; \
746 data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypes; \
747 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#b); \
748 tbufferpos += 6; \
749 } \
750 }
751
752 int flags = Parser->startflags;
753 int data[RINEXENTRY_NUMBER];
754 char tbuffer[6*RINEXENTRY_NUMBER+1];
755 int tbufferpos = 0;
756 for(i = 0; i < RINEXENTRY_NUMBER; ++i)
757 data[i] = 0;
758 for(i = 0; i < Parser->Data.numsats; ++i)
759 flags |= Parser->Data.dataflags[i];
760
761 CHECKFLAGS(C1,C1)
762 CHECKFLAGS(C2,C2)
763 CHECKFLAGS(P1,P1)
764 CHECKFLAGS(P2,P2)
765 CHECKFLAGS(L1C,L1)
766 CHECKFLAGS(L1P,L1)
767 CHECKFLAGS(L2C,L2)
768 CHECKFLAGS(L2P,L2)
769 CHECKFLAGS(D1C,D1)
770 CHECKFLAGS(D1P,D1)
771 CHECKFLAGS(D2C,D2)
772 CHECKFLAGS(D2P,D2)
773 CHECKFLAGS(S1C,S1)
774 CHECKFLAGS(S1P,S1)
775 CHECKFLAGS(S2C,S2)
776 CHECKFLAGS(S2P,S2)
777
778 hdata.data.named.typesofobs = buffer;
779 i = 1+snprintf(buffer, buffersize,
780 "%6i%-54.54s# / TYPES OF OBSERV", Parser->numdatatypes, tbuffer);
781 if(Parser->numdatatypes>9)
782 {
783 i += snprintf(buffer+i-1, buffersize,
784 "\n %-54.54s# / TYPES OF OBSERV", tbuffer+9*6);
785 }
786 buffer += i; buffersize -= i;
787 }
788
789 {
790 struct converttimeinfo cti;
791 converttime(&cti, Parser->Data.week,
792 (int)floor(Parser->Data.timeofweek/1000.0));
793 hdata.data.named.timeoffirstobs = buffer;
794 i = 1+snprintf(buffer, buffersize,
795 " %4d %2d %2d %2d %2d %10.7f GPS "
796 "TIME OF FIRST OBS", cti.year, cti.month, cti.day, cti.hour,
797 cti.minute, cti.second + fmod(Parser->Data.timeofweek/1000.0,1.0));
798
799 buffer += i; buffersize -= i;
800 }
801
802 hdata.numheaders = 11;
803
804 if(Parser->headerfile)
805 {
806 FILE *fh;
807 if((fh = fopen(Parser->headerfile, "r")))
808 {
809 size_t siz;
810 char *lastblockstart;
811 if((siz = fread(buffer, 1, buffersize-1, fh)) > 0)
812 {
813 buffer[siz] = '\n';
814 if(siz == buffersize)
815 {
816 RTCM3Error("Header file is too large. Only %d bytes read.",
817 (int)siz);
818 }
819 /* scan the file line by line and enter the entries in the list */
820 /* warn for "# / TYPES OF OBSERV" and "TIME OF FIRST OBS" */
821 /* overwrites entries, except for comments */
822 lastblockstart = buffer;
823 for(i = 0; i < (int)siz; ++i)
824 {
825 if(buffer[i] == '\n')
826 { /* we found a line */
827 char *end;
828 while(buffer[i+1] == '\r')
829 ++i; /* skip \r in case there are any */
830 end = buffer+i;
831 while(*end == '\t' || *end == ' ' || *end == '\r' || *end == '\n')
832 *(end--) = 0;
833 if(end-lastblockstart < 60+5) /* short line */
834 RTCM3Error("Short Header line '%s' ignored.\n", lastblockstart);
835 else
836 {
837 int pos;
838 if(!strcmp("COMMENT", lastblockstart+60))
839 pos = hdata.numheaders;
840 else
841 {
842 for(pos = 0; pos < hdata.numheaders; ++pos)
843 {
844 if(!strcmp(hdata.data.unnamed[pos]+60, lastblockstart+60))
845 break;
846 }
847 if(!strcmp("# / TYPES OF OBSERV", lastblockstart+60)
848 || !strcmp("TIME OF FIRST OBS", lastblockstart+60))
849 {
850 RTCM3Error("Overwriting header '%s' is dangerous.\n",
851 lastblockstart+60);
852 }
853 }
854 if(pos >= MAXHEADERLINES)
855 {
856 RTCM3Error("Maximum number of header lines of %d reached.\n",
857 MAXHEADERLINES);
858 }
859 else if(!strcmp("END OF HEADER", lastblockstart+60))
860 {
861 RTCM3Error("End of header ignored.\n");
862 }
863 else
864 {
865 hdata.data.unnamed[pos] = lastblockstart;
866 if(pos == hdata.numheaders)
867 ++hdata.numheaders;
868 }
869 }
870 lastblockstart = buffer+i+1;
871 }
872 }
873 }
874 else
875 {
876 RTCM3Error("Could not read data from headerfile '%s'.\n",
877 Parser->headerfile);
878 }
879 fclose(fh);
880 }
881 else
882 {
883 RTCM3Error("Could not open header datafile '%s'.\n",
884 Parser->headerfile);
885 }
886 }
887
888#ifndef NO_RTCM3_MAIN
889 for(i = 0; i < hdata.numheaders; ++i)
890 RTCM3Text("%s\n", hdata.data.unnamed[i]);
891 RTCM3Text(" "
892 "END OF HEADER\n");
893#endif
894}
895
896void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
897{
898 Parser->Message[Parser->MessageSize++] = byte;
899 if(Parser->MessageSize >= Parser->NeedBytes)
900 {
901 int r;
902 while((r = RTCM3Parser(Parser)))
903 {
904 int i, j, o;
905 struct converttimeinfo cti;
906
907 if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
908 {
909 ++Parser->init;
910
911 if(Parser->init == NUMSTARTSKIP)
912 HandleHeader(Parser);
913 else
914 {
915 for(i = 0; i < Parser->Data.numsats; ++i)
916 Parser->startflags |= Parser->Data.dataflags[i];
917 continue;
918 }
919 }
920 if(r == 2 && !Parser->validwarning)
921 {
922 RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
923 " COMMENT\n");
924 Parser->validwarning = 1;
925 }
926
927 converttime(&cti, Parser->Data.week,
928 (int)floor(Parser->Data.timeofweek/1000.0));
929 RTCM3Text(" %02d %2d %2d %2d %2d %10.7f 0%3d",
930 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
931 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
932 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
933 {
934 if(Parser->Data.satellites[i] <= PRN_GPS_END)
935 RTCM3Text("G%02d", Parser->Data.satellites[i]);
936 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
937 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
938 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
939 else
940 RTCM3Text("%3d", Parser->Data.satellites[i]);
941 }
942 RTCM3Text("\n");
943 o = 12;
944 j = Parser->Data.numsats - 12;
945 while(j > 0)
946 {
947 RTCM3Text(" ");
948 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
949 {
950 if(Parser->Data.satellites[i] <= PRN_GPS_END)
951 RTCM3Text("G%02d", Parser->Data.satellites[i]);
952 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
953 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
954 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
955 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
956 && Parser->Data.satellites[i] <= PRN_WAAS_END)
957 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START);
958 else
959 RTCM3Text("%3d", Parser->Data.satellites[i]);
960 }
961 RTCM3Text("\n");
962 j -= 12;
963 o += 12;
964 }
965 for(i = 0; i < Parser->Data.numsats; ++i)
966 {
967 for(j = 0; j < Parser->numdatatypes; ++j)
968 {
969 int v = 0;
970 int df = Parser->dataflag[j];
971 int pos = Parser->datapos[j];
972 if((Parser->Data.dataflags[i] & df)
973 && !isnan(Parser->Data.measdata[i][pos])
974 && !isinf(Parser->Data.measdata[i][pos]))
975 {
976 v = 1;
977 }
978 else
979 {
980 df = Parser->dataflag2[j];
981 pos = Parser->datapos2[j];
982
983 if((Parser->Data.dataflags[i] & df)
984 && !isnan(Parser->Data.measdata[i][pos])
985 && !isinf(Parser->Data.measdata[i][pos]))
986 {
987 v = 1;
988 }
989 }
990
991 if(!v)
992 { /* no or illegal data */
993 RTCM3Text(" ");
994 }
995 else
996 {
997 char lli = ' ';
998 char snr = ' ';
999 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1000 {
1001 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1002 lli = '1';
1003 snr = '0'+Parser->Data.snrL1[i];
1004 }
1005 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1006 {
1007 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1008 lli = '1';
1009 snr = '0'+Parser->Data.snrL2[i];
1010 }
1011 RTCM3Text("%14.3f%c%c",
1012 Parser->Data.measdata[i][pos],lli,snr);
1013 }
1014 if(j%5 == 4 || j == Parser->numdatatypes-1)
1015 RTCM3Text("\n");
1016 }
1017 }
1018 }
1019 }
1020}
1021
1022#ifndef NO_RTCM3_MAIN
1023static char datestr[] = "$Date: 2007/01/23 17:16:39 $";
1024
1025/* The string, which is send as agent in HTTP request */
1026#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
1027
1028#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
1029
1030static const char encodingTable [64] = {
1031 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1032 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1033 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1034 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1035};
1036
1037/* does not buffer overrun, but breaks directly after an error */
1038/* returns the number of required bytes */
1039static int encode(char *buf, int size, const char *user, const char *pwd)
1040{
1041 unsigned char inbuf[3];
1042 char *out = buf;
1043 int i, sep = 0, fill = 0, bytes = 0;
1044
1045 while(*user || *pwd)
1046 {
1047 i = 0;
1048 while(i < 3 && *user) inbuf[i++] = *(user++);
1049 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1050 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1051 while(i < 3) {inbuf[i++] = 0; ++fill; }
1052 if(out-buf < size-1)
1053 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1054 if(out-buf < size-1)
1055 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1056 | ((inbuf [1] & 0xF0) >> 4)];
1057 if(out-buf < size-1)
1058 {
1059 if(fill == 2)
1060 *(out++) = '=';
1061 else
1062 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1063 | ((inbuf [2] & 0xC0) >> 6)];
1064 }
1065 if(out-buf < size-1)
1066 {
1067 if(fill >= 1)
1068 *(out++) = '=';
1069 else
1070 *(out++) = encodingTable[inbuf [2] & 0x3F];
1071 }
1072 bytes += 4;
1073 }
1074 if(out-buf < size)
1075 *out = 0;
1076 return bytes;
1077}
1078
1079static int stop = 0;
1080
1081struct Args
1082{
1083 const char *server;
1084 int port;
1085 const char *user;
1086 const char *password;
1087 const char *data;
1088 const char *headerfile;
1089};
1090
1091/* option parsing */
1092#ifdef NO_LONG_OPTS
1093#define LONG_OPT(a)
1094#else
1095#define LONG_OPT(a) a
1096static struct option opts[] = {
1097{ "data", required_argument, 0, 'd'},
1098{ "server", required_argument, 0, 's'},
1099{ "password", required_argument, 0, 'p'},
1100{ "port", required_argument, 0, 'r'},
1101{ "header", required_argument, 0, 'f'},
1102{ "user", required_argument, 0, 'u'},
1103{ "help", no_argument, 0, 'h'},
1104{0,0,0,0}};
1105#endif
1106#define ARGOPT "-d:hp:r:s:u:f:"
1107
1108static const char *geturl(const char *url, struct Args *args)
1109{
1110 static char buf[1000];
1111 static char *Buffer = buf;
1112 static char *Bufend = buf+sizeof(buf);
1113
1114 if(strncmp("ntrip:", url, 6))
1115 return "URL must start with 'ntrip:'.";
1116 url += 6; /* skip ntrip: */
1117
1118 if(*url != '@' && *url != '/')
1119 {
1120 /* scan for mountpoint */
1121 args->data = Buffer;
1122 while(*url && *url != '@' && *url != '/' && Buffer != Bufend)
1123 *(Buffer++) = *(url++);
1124 if(Buffer == args->data)
1125 return "Mountpoint required.";
1126 else if(Buffer >= Bufend-1)
1127 return "Parsing buffer too short.";
1128 *(Buffer++) = 0;
1129 }
1130
1131 if(*url == '/') /* username and password */
1132 {
1133 ++url;
1134 args->user = Buffer;
1135 while(*url && *url != '@' && *url != ':' && Buffer != Bufend)
1136 *(Buffer++) = *(url++);
1137 if(Buffer == args->user)
1138 return "Username cannot be empty.";
1139 else if(Buffer >= Bufend-1)
1140 return "Parsing buffer too short.";
1141 *(Buffer++) = 0;
1142
1143 if(*url == ':') ++url;
1144
1145 args->password = Buffer;
1146 while(*url && *url != '@' && Buffer != Bufend)
1147 *(Buffer++) = *(url++);
1148 if(Buffer == args->password)
1149 return "Password cannot be empty.";
1150 else if(Buffer >= Bufend-1)
1151 return "Parsing buffer too short.";
1152 *(Buffer++) = 0;
1153 }
1154
1155 if(*url == '@') /* server */
1156 {
1157 ++url;
1158 args->server = Buffer;
1159 while(*url && *url != ':' && Buffer != Bufend)
1160 *(Buffer++) = *(url++);
1161 if(Buffer == args->server)
1162 return "Servername cannot be empty.";
1163 else if(Buffer >= Bufend-1)
1164 return "Parsing buffer too short.";
1165 *(Buffer++) = 0;
1166
1167 if(*url == ':')
1168 {
1169 char *s2 = 0;
1170 args->port = strtol(++url, &s2, 10);
1171 if(*s2 || args->port <= 0 || args->port > 0xFFFF)
1172 return "Illegal port number.";
1173 url = s2;
1174 }
1175 }
1176
1177 return *url ? "Garbage at end of server string." : 0;
1178}
1179
1180static int getargs(int argc, char **argv, struct Args *args)
1181{
1182 int res = 1;
1183 int getoptr;
1184 int help = 0;
1185 char *t;
1186
1187 args->server = "www.euref-ip.net";
1188 args->port = 2101;
1189 args->user = "";
1190 args->password = "";
1191 args->data = 0;
1192 args->headerfile = 0;
1193 help = 0;
1194
1195 do
1196 {
1197#ifdef NO_LONG_OPTS
1198 switch((getoptr = getopt(argc, argv, ARGOPT)))
1199#else
1200 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
1201#endif
1202 {
1203 case 's': args->server = optarg; break;
1204 case 'u': args->user = optarg; break;
1205 case 'p': args->password = optarg; break;
1206 case 'd': args->data = optarg; break;
1207 case 'f': args->headerfile = optarg; break;
1208 case 'h': help=1; break;
1209 case 'r':
1210 args->port = strtoul(optarg, &t, 10);
1211 if((t && *t) || args->port < 1 || args->port > 65535)
1212 res = 0;
1213 break;
1214 case 1:
1215 {
1216 const char *err;
1217 if((err = geturl(optarg, args)))
1218 {
1219 RTCM3Error("%s\n\n", err);
1220 res = 0;
1221 }
1222 }
1223 break;
1224 case -1: break;
1225 }
1226 } while(getoptr != -1 || !res);
1227
1228 datestr[0] = datestr[7];
1229 datestr[1] = datestr[8];
1230 datestr[2] = datestr[9];
1231 datestr[3] = datestr[10];
1232 datestr[5] = datestr[12];
1233 datestr[6] = datestr[13];
1234 datestr[8] = datestr[15];
1235 datestr[9] = datestr[16];
1236 datestr[4] = datestr[7] = '-';
1237 datestr[10] = 0;
1238
1239 if(!res || help)
1240 {
1241 RTCM3Error("Version %s (%s) GPL" COMPILEDATE
1242 "\nUsage: %s -s server -u user ...\n"
1243 " -d " LONG_OPT("--data ") "the requested data set\n"
1244 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
1245 " -s " LONG_OPT("--server ") "the server name or address\n"
1246 " -p " LONG_OPT("--password ") "the login password\n"
1247 " -r " LONG_OPT("--port ") "the server port number (default 2101)\n"
1248 " -u " LONG_OPT("--user ") "the user name\n"
1249 "or using an URL:\n%s ntrip:mountpoint[/username[:password]][@server[:port]]\n"
1250 , revisionstr, datestr, argv[0], argv[0]);
1251 exit(1);
1252 }
1253 return res;
1254}
1255
1256/* let the output complete a block if necessary */
1257static void signalhandler(int sig)
1258{
1259 if(!stop)
1260 {
1261 RTCM3Error("Stop signal number %d received. "
1262 "Trying to terminate gentle.\n", sig);
1263 stop = 1;
1264 alarm(1);
1265 }
1266}
1267
1268/* for some reason we had to abort hard (maybe waiting for data */
1269#ifdef __GNUC__
1270static __attribute__ ((noreturn)) void signalhandler_alarm(
1271int sig __attribute__((__unused__)))
1272#else /* __GNUC__ */
1273static void signalhandler_alarm(int sig)
1274#endif /* __GNUC__ */
1275{
1276 RTCM3Error("Programm forcefully terminated.\n");
1277 exit(1);
1278}
1279
1280int main(int argc, char **argv)
1281{
1282 struct Args args;
1283 struct RTCM3ParserData Parser;
1284
1285 setbuf(stdout, 0);
1286 setbuf(stdin, 0);
1287 setbuf(stderr, 0);
1288
1289 {
1290 char *a;
1291 int i=0;
1292 for(a = revisionstr+11; *a && *a != ' '; ++a)
1293 revisionstr[i++] = *a;
1294 revisionstr[i] = 0;
1295 }
1296
1297 signal(SIGINT, signalhandler);
1298 signal(SIGALRM,signalhandler_alarm);
1299 signal(SIGQUIT,signalhandler);
1300 signal(SIGTERM,signalhandler);
1301 signal(SIGPIPE,signalhandler);
1302 memset(&Parser, 0, sizeof(Parser));
1303 {
1304 time_t tim;
1305 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
1306 Parser.GPSWeek = tim/(7*24*60*60);
1307 Parser.GPSTOW = tim%(7*24*60*60);
1308 }
1309
1310 if(getargs(argc, argv, &args))
1311 {
1312 int i, sockfd, numbytes;
1313 char buf[MAXDATASIZE];
1314 struct hostent *he;
1315 struct sockaddr_in their_addr; /* connector's address information */
1316
1317 Parser.headerfile = args.headerfile;
1318
1319 if(!(he=gethostbyname(args.server)))
1320 {
1321 RTCM3Error("Function gethostbyname: %s\n", strerror(errno));
1322 exit(1);
1323 }
1324 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
1325 {
1326 RTCM3Error("Function socket: %s\n", strerror(errno));
1327 exit(1);
1328 }
1329 their_addr.sin_family = AF_INET; /* host byte order */
1330 their_addr.sin_port = htons(args.port); /* short, network byte order */
1331 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
1332 memset(&(their_addr.sin_zero), '\0', 8);
1333 if(connect(sockfd, (struct sockaddr *)&their_addr,
1334 sizeof(struct sockaddr)) == -1)
1335 {
1336 RTCM3Error("Function connect: %s\n", strerror(errno));
1337 exit(1);
1338 }
1339
1340 if(!args.data)
1341 {
1342 i = snprintf(buf, MAXDATASIZE,
1343 "GET / HTTP/1.0\r\n"
1344 "User-Agent: %s/%s\r\n"
1345#ifdef UNUSED
1346 "Accept: */*\r\n"
1347 "Connection: close\r\n"
1348#endif
1349 "\r\n"
1350 , AGENTSTRING, revisionstr);
1351 }
1352 else
1353 {
1354 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
1355 "GET /%s HTTP/1.0\r\n"
1356 "User-Agent: %s/%s\r\n"
1357#ifdef UNUSED
1358 "Accept: */*\r\n"
1359 "Connection: close\r\n"
1360#endif
1361 "Authorization: Basic "
1362 , args.data, AGENTSTRING, revisionstr);
1363 if(i > MAXDATASIZE-40 && i < 0) /* second check for old glibc */
1364 {
1365 RTCM3Error("Requested data too long\n");
1366 exit(1);
1367 }
1368 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
1369 if(i > MAXDATASIZE-4)
1370 {
1371 RTCM3Error("Username and/or password too long\n");
1372 exit(1);
1373 }
1374 buf[i++] = '\r';
1375 buf[i++] = '\n';
1376 buf[i++] = '\r';
1377 buf[i++] = '\n';
1378 }
1379 if(send(sockfd, buf, (size_t)i, 0) != i)
1380 {
1381 RTCM3Error("Function send: %s\n", strerror(errno));
1382 exit(1);
1383 }
1384 if(args.data)
1385 {
1386 int k = 0;
1387 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
1388 {
1389 if(!k)
1390 {
1391 if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
1392 {
1393 RTCM3Error("Could not get the requested data: ");
1394 for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
1395 {
1396 RTCM3Error("%c", isprint(buf[k]) ? buf[k] : '.');
1397 }
1398 RTCM3Error("\n");
1399 exit(1);
1400 }
1401 ++k;
1402 }
1403 else
1404 {
1405 int z;
1406 for(z = 0; z < numbytes && !stop; ++z)
1407 HandleByte(&Parser, (unsigned int) buf[z]);
1408 }
1409 }
1410 }
1411 else
1412 {
1413 while((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
1414 {
1415 fwrite(buf, (size_t)numbytes, 1, stdout);
1416 }
1417 }
1418
1419 close(sockfd);
1420 }
1421 return 0;
1422}
1423#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.