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

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

fixed L2C

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