source: ntrip/trunk/BNC/RTCM3/rtcm3torinex.c@ 1032

Last change on this file since 1032 was 1032, checked in by weber, 16 years ago

* empty log message *

File size: 76.9 KB
Line 
1/*
2 Converter for RTCM3 data to RINEX.
3 $Id: rtcm3torinex.c,v 1.13 2008/08/09 23:58:09 weber Exp $
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#include "rtcm3torinex.h"
51
52/* CVS revision and version */
53static char revisionstr[] = "$Revision: 1.13 $";
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 floating value from data stream
142 b = variable to store result, a = number of bits */
143#define GETFLOAT(b, a, c) \
144{ \
145 LOADBITS(a) \
146 b = ((double)((bitfield<<(64-numbits))>>(64-(a))))*(c); \
147 numbits -= (a); \
148}
149
150/* extract signed floating value from data stream
151 b = variable to store result, a = number of bits */
152#define GETFLOATSIGN(b, a, c) \
153{ \
154 LOADBITS(a) \
155 b = ((double)(((int64_t)(bitfield<<(64-numbits)))>>(64-(a))))*(c); \
156 numbits -= (a); \
157}
158
159/* extract bits from data stream
160 b = variable to store result, a = number of bits */
161#define GETBITSSIGN(b, a) \
162{ \
163 LOADBITS(a) \
164 b = ((int64_t)(bitfield<<(64-numbits)))>>(64-(a)); \
165 numbits -= (a); \
166}
167
168#define GETFLOATSIGNM(b, a, c) \
169{ int l; \
170 LOADBITS(a) \
171 l = (bitfield<<(64-numbits))>>(64-1); \
172 b = ((double)(((bitfield<<(64-(numbits-1))))>>(64-(a-1))))*(c); \
173 numbits -= (a); \
174 if(l) b *= -1.0; \
175}
176
177#define SKIPBITS(b) { LOADBITS(b) numbits -= (b); }
178
179struct leapseconds { /* specify the day of leap second */
180 int day; /* this is the day, where 23:59:59 exists 2 times */
181 int month; /* not the next day! */
182 int year;
183 int taicount;
184};
185static const int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
186static const struct leapseconds leap[] = {
187/*{31, 12, 1971, 11},*/
188/*{31, 12, 1972, 12},*/
189/*{31, 12, 1973, 13},*/
190/*{31, 12, 1974, 14},*/
191/*{31, 12, 1975, 15},*/
192/*{31, 12, 1976, 16},*/
193/*{31, 12, 1977, 17},*/
194/*{31, 12, 1978, 18},*/
195/*{31, 12, 1979, 19},*/
196{30, 06, 1981,20},
197{30, 06, 1982,21},
198{30, 06, 1983,22},
199{30, 06, 1985,23},
200{31, 12, 1987,24},
201{31, 12, 1989,25},
202{31, 12, 1990,26},
203{30, 06, 1992,27},
204{30, 06, 1993,28},
205{30, 06, 1994,29},
206{31, 12, 1995,30},
207{30, 06, 1997,31},
208{31, 12, 1998,32},
209{31, 12, 2005,33},
210{31, 12, 2008,34},
211{0,0,0,0} /* end marker */
212};
213#define LEAPSECONDS 14 /* only needed for approx. time */
214#define GPSLEAPSTART 19 /* 19 leap seconds existed at 6.1.1980 */
215
216static int longyear(int year, int month)
217{
218 if(!(year % 4) && (!(year % 400) || (year % 100)))
219 {
220 if(!month || month == 2)
221 return 1;
222 }
223 return 0;
224}
225
226static int gnumleap(int year, int month, int day)
227{
228 int ls = 0;
229 const struct leapseconds *l;
230
231 for(l = leap; l->taicount && year >= l->year; ++l)
232 {
233 if(year > l->year || month > l->month || day > l->day)
234 ls = l->taicount - GPSLEAPSTART;
235 }
236 return ls;
237}
238
239void updatetime(int *week, int *tow, int tk, int fixnumleap)
240{
241 int y,m,d,k,l, nul;
242 unsigned int j = *week*(7*24*60*60) + *tow + 5*24*60*60+3*60*60;
243 int glo_daynumber = 0, glo_timeofday;
244 for(y = 1980; j >= (unsigned int)(k = (l = (365+longyear(y,0)))*24*60*60)
245 + gnumleap(y+1,1,1); ++y)
246 {
247 j -= k; glo_daynumber += l;
248 }
249 for(m = 1; j >= (unsigned int)(k = (l = months[m]+longyear(y, m))*24*60*60)
250 + gnumleap(y, m+1, 1); ++m)
251 {
252 j -= k; glo_daynumber += l;
253 }
254 for(d = 1; j >= 24UL*60UL*60UL + gnumleap(y, m, d+1); ++d)
255 j -= 24*60*60;
256 glo_daynumber -= 16*365+4-d;
257 nul = gnumleap(y, m, d);
258 glo_timeofday = j-nul;
259
260 if(tk < 5*60*1000 && glo_timeofday > 23*60*60)
261 *tow += 24*60*60;
262 else if(glo_timeofday < 5*60 && tk > 23*60*60*1000)
263 *tow -= 24*60*60;
264 *tow += tk/1000-glo_timeofday;
265 if(fixnumleap)
266 *tow -= nul;
267 if(*tow < 0) {*tow += 24*60*60*7; --*week; }
268 if(*tow >= 24*60*60*7) {*tow -= 24*60*60*7; ++*week; }
269}
270
271int RTCM3Parser(struct RTCM3ParserData *handle)
272{
273 int ret=0;
274
275 while(!ret && GetMessage(handle))
276 {
277 /* using 64 bit integer types, as it is much easier than handling
278 the long datatypes in 32 bit */
279 uint64_t numbits = 0, bitfield = 0;
280 int size = handle->size, type;
281 int syncf, old = 0;
282 unsigned char *data = handle->Message+3;
283
284 GETBITS(type,12)
285 handle->typeList[handle->typeSize] = type; /* RTCM message types */
286 if(handle->typeSize < 100) {handle->typeSize += 1;} /* RTCM message types */
287 switch(type)
288 {
289 case 1019:
290 {
291 struct gpsephemeris *ge;
292 int sv;
293
294 ge = &handle->ephemerisGPS;
295 memset(ge, 0, sizeof(*ge));
296
297 GETBITS(sv, 6)
298 ge->satellite = (sv < 40 ? sv : sv+80);
299 GETBITS(ge->GPSweek, 10)
300 ge->GPSweek += 1024;
301 GETBITS(ge->URAindex, 4)
302 GETBITS(sv, 2)
303 if(sv & 1)
304 ge->flags |= GPSEPHF_L2PCODE;
305 if(sv & 2)
306 ge->flags |= GPSEPHF_L2CACODE;
307 GETFLOATSIGN(ge->IDOT, 14, PI/(double)(1<<30)/(double)(1<<13))
308 GETBITS(ge->IODE, 8)
309 GETBITS(ge->TOC, 16)
310 ge->TOC <<= 4;
311 GETFLOATSIGN(ge->clock_driftrate, 8, 1.0/(double)(1<<30)/(double)(1<<25))
312 GETFLOATSIGN(ge->clock_drift, 16, 1.0/(double)(1<<30)/(double)(1<<13))
313 GETFLOATSIGN(ge->clock_bias, 22, 1.0/(double)(1<<30)/(double)(1<<1))
314 GETBITS(ge->IODC, 10)
315 GETFLOATSIGN(ge->Crs, 16, 1.0/(double)(1<<5))
316 GETFLOATSIGN(ge->Delta_n, 16, PI/(double)(1<<30)/(double)(1<<13))
317 GETFLOATSIGN(ge->M0, 32, PI/(double)(1<<30)/(double)(1<<1))
318 GETFLOATSIGN(ge->Cuc, 16, 1.0/(double)(1<<29))
319 GETFLOAT(ge->e, 32, 1.0/(double)(1<<30)/(double)(1<<3))
320 GETFLOATSIGN(ge->Cus, 16, 1.0/(double)(1<<29))
321 GETFLOAT(ge->sqrt_A, 32, 1.0/(double)(1<<19))
322 GETBITS(ge->TOE, 16)
323 ge->TOE <<= 4;
324
325 GETFLOATSIGN(ge->Cic, 16, 1.0/(double)(1<<29))
326 GETFLOATSIGN(ge->OMEGA0, 32, PI/(double)(1<<30)/(double)(1<<1))
327 GETFLOATSIGN(ge->Cis, 16, 1.0/(double)(1<<29))
328 GETFLOATSIGN(ge->i0, 32, PI/(double)(1<<30)/(double)(1<<1))
329 GETFLOATSIGN(ge->Crc, 16, 1.0/(double)(1<<5))
330 GETFLOATSIGN(ge->omega, 32, PI/(double)(1<<30)/(double)(1<<1))
331 GETFLOATSIGN(ge->OMEGADOT, 24, PI/(double)(1<<30)/(double)(1<<13))
332 GETFLOATSIGN(ge->TGD, 8, 1.0/(double)(1<<30)/(double)(1<<1))
333 GETBITS(ge->SVhealth, 6)
334 GETBITS(sv, 1)
335 if(sv)
336 ge->flags |= GPSEPHF_L2PCODEDATA;
337
338 ret = 1019;
339 }
340 break;
341 case 1020:
342 {
343 struct glonassephemeris *ge;
344 int i;
345
346 ge = &handle->ephemerisGLONASS;
347 memset(ge, 0, sizeof(*ge));
348
349 ge->flags |= GLOEPHF_PAVAILABLE;
350 GETBITS(ge->almanac_number, 6)
351 GETBITS(i, 5)
352 ge->frequency_number = i-7;
353 GETBITS(i, 1)
354 if(i)
355 ge->flags |= GLOEPHF_ALMANACHEALTHY;
356 GETBITS(i, 1)
357 if(i)
358 ge->flags |= GLOEPHF_ALMANACHEALTHOK;
359 GETBITS(i, 2)
360 if(i & 1)
361 ge->flags |= GLOEPHF_P10TRUE;
362 if(i & 2)
363 ge->flags |= GLOEPHF_P11TRUE;
364 GETBITS(i, 5)
365 ge->tk = i*60*60;
366 GETBITS(i, 6)
367 ge->tk += i*60;
368 GETBITS(i, 1)
369 ge->tk += i*30;
370 GETBITS(i, 1)
371 if(i)
372 ge->flags |= GLOEPHF_UNHEALTHY;
373 GETBITS(i, 1)
374 if(i)
375 ge->flags |= GLOEPHF_P2TRUE;
376 GETBITS(i, 7)
377 ge->tb = i*15*60;
378 GETFLOATSIGNM(ge->x_velocity, 24, 1.0/(double)(1<<20))
379 GETFLOATSIGNM(ge->x_pos, 27, 1.0/(double)(1<<11))
380 GETFLOATSIGNM(ge->x_acceleration, 5, 1.0/(double)(1<<30))
381 GETFLOATSIGNM(ge->y_velocity, 24, 1.0/(double)(1<<20))
382 GETFLOATSIGNM(ge->y_pos, 27, 1.0/(double)(1<<11))
383 GETFLOATSIGNM(ge->y_acceleration, 5, 1.0/(double)(1<<30))
384 GETFLOATSIGNM(ge->z_velocity, 24, 1.0/(double)(1<<20))
385 GETFLOATSIGNM(ge->z_pos, 27, 1.0/(double)(1<<11))
386 GETFLOATSIGNM(ge->z_acceleration, 5, 1.0/(double)(1<<30))
387 GETBITS(i, 1)
388 if(i)
389 ge->flags |= GLOEPHF_P3TRUE;
390 GETFLOATSIGNM(ge->gamma, 11, 1.0/(double)(1<<30)/(double)(1<<10))
391 SKIPBITS(3) /* GLONASS-M P, GLONASS-M ln (third string) */
392 GETFLOATSIGNM(ge->tau, 22, 1.0/(double)(1<<30)) /* GLONASS tau n(tb) */
393 SKIPBITS(5) /* GLONASS-M delta tau n(tb) */
394 GETBITS(ge->E, 5)
395 /* GETBITS(b, 1) / * GLONASS-M P4 */
396 /* GETBITS(b, 4) / * GLONASS-M Ft */
397 /* GETBITS(b, 11) / * GLONASS-M Nt */
398 /* GETBITS(b, 2) / * GLONASS-M M */
399 /* GETBITS(b, 1) / * GLONASS-M The Availability of Additional Data */
400 /* GETBITS(b, 11) / * GLONASS-M Na */
401 /* GETFLOATSIGNM(b, 32, 1.0/(double)(1<<30)/(double)(1<<1)) / * GLONASS tau c */
402 /* GETBITS(b, 5) / * GLONASS-M N4 */
403 /* GETFLOATSIGNM(b, 22, 1.0/(double)(1<<30)/(double)(1<<1)) / * GLONASS-M tau GPS */
404 /* GETBITS(b, 1) / * GLONASS-M ln (fifth string) */
405 ge->GPSWeek = handle->GPSWeek;
406 ge->GPSTOW = handle->GPSTOW;
407 ret = 1020;
408 }
409 break;
410 case 1001: case 1002: case 1003: case 1004:
411 if(handle->GPSWeek)
412 {
413 int lastlockl1[64];
414 int lastlockl2[64];
415 struct gnssdata *gnss;
416 int i, num, wasamb=0;
417
418 for(i = 0; i < 64; ++i)
419 lastlockl1[i] = lastlockl2[i] = 0;
420
421 gnss = &handle->DataNew;
422
423 SKIPBITS(12) /* id */
424 GETBITS(i,30)
425 if(i/1000 < (int)handle->GPSTOW - 86400)
426 ++handle->GPSWeek;
427 handle->GPSTOW = i/1000;
428 if(gnss->week && (gnss->timeofweek != i || gnss->week
429 != handle->GPSWeek))
430 {
431 handle->Data = *gnss;
432 memset(gnss, 0, sizeof(*gnss));
433 old = 1;
434 }
435 gnss->timeofweek = i;
436 gnss->week = handle->GPSWeek;
437
438 GETBITS(syncf,1) /* sync */
439 GETBITS(i,5)
440 gnss->numsats = i;
441 SKIPBITS(4) /* smind, smint */
442
443 for(num = 0; num < gnss->numsats; ++num)
444 {
445 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
446
447 GETBITS(sv, 6);
448 gnss->satellites[num] = (sv < 40 ? sv : sv+80);
449 /* L1 */
450 GETBITS(code, 1);
451 if(code)
452 {
453 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
454 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
455 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
456 }
457 else
458 {
459 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
460 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
461 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
462 }
463 GETBITS(l1range, 24);
464 GETBITSSIGN(i, 20);
465 if((i&((1<<20)-1)) != 0x80000)
466 {
467 gnss->dataflags[num] |= (c|l);
468 gnss->measdata[num][ce] = l1range*0.02;
469 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
470 }
471 GETBITS(i, 7);
472 lastlockl1[sv] = i;
473 if(handle->lastlockl1[sv] > i)
474 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
475 if(type == 1002 || type == 1004)
476 {
477 GETBITS(amb,8);
478 if(amb && (gnss->dataflags[num] & c))
479 {
480 gnss->measdata[num][ce] += amb*299792.458;
481 gnss->measdata[num][le] += amb*299792.458;
482 ++wasamb;
483 }
484 GETBITS(i, 8);
485 if(i)
486 {
487 gnss->dataflags[num] |= s;
488 gnss->measdata[num][se] = i*0.25;
489 i /= 4*4;
490 if(i > 9) i = 9;
491 else if(i < 1) i = 1;
492 gnss->snrL1[num] = i;
493 }
494 }
495 gnss->measdata[num][le] /= GPS_WAVELENGTH_L1;
496 if(type == 1003 || type == 1004)
497 {
498 /* L2 */
499 GETBITS(code,2);
500 if(code)
501 {
502 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
503 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
504 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
505 }
506 else
507 {
508 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
509 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
510 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
511 }
512 GETBITSSIGN(i,14);
513 if((i&((1<<14)-1)) != 0x2000)
514 {
515 gnss->dataflags[num] |= c;
516 gnss->measdata[num][ce] = l1range*0.02+i*0.02
517 +amb*299792.458;
518 }
519 GETBITSSIGN(i,20);
520 if((i&((1<<20)-1)) != 0x80000)
521 {
522 gnss->dataflags[num] |= l;
523 gnss->measdata[num][le] = l1range*0.02+i*0.0005
524 +amb*299792.458;
525 }
526 GETBITS(i,7);
527 lastlockl2[sv] = i;
528 if(handle->lastlockl2[sv] > i)
529 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
530 if(type == 1004)
531 {
532 GETBITS(i, 8);
533 if(i)
534 {
535 gnss->dataflags[num] |= s;
536 gnss->measdata[num][se] = i*0.25;
537 i /= 4*4;
538 if(i > 9) i = 9;
539 else if(i < 1) i = 1;
540 gnss->snrL2[num] = i;
541 }
542 }
543 gnss->measdata[num][le] /= GPS_WAVELENGTH_L2;
544 }
545 }
546 for(i = 0; i < 64; ++i)
547 {
548 handle->lastlockl1[i] = lastlockl1[i];
549 handle->lastlockl2[i] = lastlockl2[i];
550 }
551 if(!syncf && !old)
552 {
553 handle->Data = *gnss;
554 memset(gnss, 0, sizeof(*gnss));
555 }
556 if(!syncf || old)
557 {
558 if(wasamb) /* not RINEX compatible without */
559 ret = 1;
560 else
561 ret = 2;
562 }
563 }
564 break;
565 case 1009: case 1010: case 1011: case 1012:
566 {
567 int lastlockl1[64];
568 int lastlockl2[64];
569 struct gnssdata *gnss;
570 int i, num;
571 int wasamb=0;
572
573 for(i = 0; i < 64; ++i)
574 lastlockl1[i] = lastlockl2[i] = 0;
575
576 gnss = &handle->DataNew;
577
578 SKIPBITS(12) /* id */;
579 GETBITS(i,27) /* tk */
580
581 updatetime(&handle->GPSWeek, &handle->GPSTOW, i, 0);
582 i = handle->GPSTOW*1000;
583 if(gnss->week && (gnss->timeofweek != i || gnss->week
584 != handle->GPSWeek))
585 {
586 handle->Data = *gnss;
587 memset(gnss, 0, sizeof(*gnss));
588 old = 1;
589 }
590
591 gnss->timeofweek = i;
592 gnss->week = handle->GPSWeek;
593
594 GETBITS(syncf,1) /* sync */
595 GETBITS(i,5)
596 gnss->numsats += i;
597
598 SKIPBITS(4) /* smind, smint */
599
600 for(num = gnss->numsats-i; num < gnss->numsats; ++num)
601 {
602 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
603 int freq;
604
605 GETBITS(sv, 6)
606 gnss->satellites[num] = sv-1 + PRN_GLONASS_START;
607 /* L1 */
608 GETBITS(code, 1)
609 GETBITS(freq, 5)
610 if(code)
611 {
612 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
613 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
614 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
615 }
616 else
617 {
618 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
619 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
620 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
621 }
622 GETBITS(l1range, 25)
623 GETBITSSIGN(i, 20)
624 if((i&((1<<20)-1)) != 0x80000)
625 {
626 /* Handle this like GPS. Actually for GLONASS L1 range is always
627 valid. To be on the save side, we handle it as invalid like we
628 do for GPS and also remove range in case of 0x80000. */
629 gnss->dataflags[num] |= (c|l);
630 gnss->measdata[num][ce] = l1range*0.02;
631 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
632 }
633 GETBITS(i, 7)
634 lastlockl1[sv] = i;
635 if(handle->lastlockl1[sv] > i)
636 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
637 if(type == 1010 || type == 1012)
638 {
639 GETBITS(amb,7)
640 if(amb && (gnss->dataflags[num] & c))
641 {
642 gnss->measdata[num][ce] += amb*599584.916;
643 gnss->measdata[num][le] += amb*599584.916;
644 ++wasamb;
645 }
646 GETBITS(i, 8)
647 if(i)
648 {
649 gnss->dataflags[num] |= s;
650 gnss->measdata[num][se] = i*0.25;
651 i /= 4*4;
652 if(i > 9) i = 9;
653 else if(i < 1) i = 1;
654 gnss->snrL1[num] = i;
655 }
656 }
657 gnss->measdata[num][le] /= GLO_WAVELENGTH_L1(freq-7);
658 if(type == 1011 || type == 1012)
659 {
660 /* L2 */
661 GETBITS(code,2)
662 if(code)
663 {
664 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
665 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
666 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
667 }
668 else
669 {
670 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
671 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
672 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
673 }
674 GETBITSSIGN(i,14)
675 if((i&((1<<14)-1)) != 0x2000)
676 {
677 gnss->dataflags[num] |= c;
678 gnss->measdata[num][ce] = l1range*0.02+i*0.02
679 +amb*599584.916;
680 }
681 GETBITSSIGN(i,20)
682 if((i&((1<<20)-1)) != 0x80000)
683 {
684 gnss->dataflags[num] |= l;
685 gnss->measdata[num][le] = l1range*0.02+i*0.0005
686 +amb*599584.916;
687 }
688 GETBITS(i,7)
689 lastlockl2[sv] = i;
690 if(handle->lastlockl2[sv] > i)
691 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
692 if(type == 1012)
693 {
694 GETBITS(i, 8)
695 if(i)
696 {
697 gnss->dataflags[num] |= s;
698 gnss->measdata[num][se] = i*0.25;
699 i /= 4*4;
700 if(i > 9) i = 9;
701 else if(i < 1) i = 1;
702 gnss->snrL2[num] = i;
703 }
704 }
705 gnss->measdata[num][le] /= GLO_WAVELENGTH_L2(freq-7);
706 }
707 if(!sv || sv > 24)
708 {
709 --num; --gnss->numsats;
710 }
711 }
712 for(i = 0; i < 64; ++i)
713 {
714 handle->lastlockl1[i] = lastlockl1[i];
715 handle->lastlockl2[i] = lastlockl2[i];
716 }
717 if(!syncf && !old)
718 {
719 handle->Data = *gnss;
720 memset(gnss, 0, sizeof(*gnss));
721 }
722 if(!syncf || old)
723 {
724 if(wasamb) /* not RINEX compatible without */
725 ret = 1;
726 else
727 ret = 2;
728 }
729 }
730 break;
731 }
732 }
733 return ret;
734}
735
736struct Header
737{
738 const char *version;
739 const char *pgm;
740 const char *marker;
741 const char *markertype;
742 const char *observer;
743 const char *receiver;
744 const char *antenna;
745 const char *position;
746 const char *antennaposition;
747 const char *wavelength;
748 const char *typesofobs; /* should not be modified outside */
749 const char *typesofobsG; /* should not be modified outside */
750 const char *typesofobsR; /* should not be modified outside */
751 const char *typesofobsS; /* should not be modified outside */
752 const char *timeoffirstobs; /* should not be modified outside */
753};
754
755#define MAXHEADERLINES 50
756#define MAXHEADERBUFFERSIZE 4096
757struct HeaderData
758{
759 union
760 {
761 struct Header named;
762 const char *unnamed[MAXHEADERLINES];
763 } data;
764 int numheaders;
765};
766
767struct converttimeinfo {
768 int second; /* seconds of GPS time [0..59] */
769 int minute; /* minutes of GPS time [0..59] */
770 int hour; /* hour of GPS time [0..24] */
771 int day; /* day of GPS time [1..28..30(31)*/
772 int month; /* month of GPS time [1..12]*/
773 int year; /* year of GPS time [1980..] */
774};
775
776void converttime(struct converttimeinfo *c, int week, int tow)
777{
778 int i, k, doy, j; /* temporary variables */
779 j = week*(7*24*60*60) + tow + 5*24*60*60;
780 for(i = 1980; j >= (k = (365+longyear(i,0))*24*60*60); ++i)
781 j -= k;
782 c->year = i;
783 doy = 1+ (j / (24*60*60));
784 j %= (24*60*60);
785 c->hour = j / (60*60);
786 j %= (60*60);
787 c->minute = j / 60;
788 c->second = j % 60;
789 j = 0;
790 for(i = 1; j + (k = months[i] + longyear(c->year,i)) < doy; ++i)
791 j += k;
792 c->month = i;
793 c->day = doy - j;
794}
795
796#ifndef NO_RTCM3_MAIN
797void RTCM3Error(const char *fmt, ...)
798{
799 va_list v;
800 va_start(v, fmt);
801 vfprintf(stderr, fmt, v);
802 va_end(v);
803}
804#endif
805
806void RTCM3Text(const char *fmt, ...)
807{
808 va_list v;
809 va_start(v, fmt);
810 vprintf(fmt, v);
811 va_end(v);
812}
813
814static int HandleRunBy(char *buffer, int buffersize, const char **u,
815int rinex3)
816{
817 const char *user;
818 time_t t;
819 struct tm * t2;
820
821#ifdef NO_RTCM3_MAIN
822 if(revisionstr[0] == '$')
823 {
824 char *a;
825 int i=0;
826 for(a = revisionstr+11; *a && *a != ' '; ++a)
827 revisionstr[i++] = *a;
828 revisionstr[i] = 0;
829 }
830#endif
831
832 user= getenv("USER");
833 if(!user) user = "";
834 t = time(&t);
835 t2 = gmtime(&t);
836 if(u) *u = user;
837 return 1+snprintf(buffer, buffersize,
838 rinex3 ?
839 "RTCM3TORINEX %-7.7s%-20.20s%04d%02d%02d %02d%02d%02d UTC "
840 "PGM / RUN BY / DATE" :
841 "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d "
842 "PGM / RUN BY / DATE", revisionstr, user, 1900+t2->tm_year,
843 t2->tm_mon+1, t2->tm_mday, t2->tm_hour, t2->tm_min, t2->tm_sec);
844}
845
846// Inserted parts for BNC Perlt
847#ifdef NO_RTCM3_MAIN
848#define NUMSTARTSKIP 1
849#else
850#define NUMSTARTSKIP 3
851#endif
852
853void HandleHeader(struct RTCM3ParserData *Parser)
854{
855#ifdef NO_RTCM3_MAIN
856// Part of Handle Header for data request for BNC (independently on actually delivered data), original is commented out by ifndef NO_RTCM3_MAIN. Perlt
857 int i;
858 if(Parser->rinex3)
859 {
860#define CHECKFLAGSNEW(a, b, c) \
861 { \
862 Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
863 Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
864 ++Parser->numdatatypes##a; \
865 }
866
867 CHECKFLAGSNEW(GPS, C1, C1C)
868 CHECKFLAGSNEW(GPS, L1C, L1C)
869 CHECKFLAGSNEW(GPS, D1C, D1C)
870 CHECKFLAGSNEW(GPS, S1C, S1C)
871 CHECKFLAGSNEW(GPS, P1, C1P)
872 CHECKFLAGSNEW(GPS, L1P, L1P)
873 CHECKFLAGSNEW(GPS, D1P, D1P)
874 CHECKFLAGSNEW(GPS, S1P, S1P)
875 CHECKFLAGSNEW(GPS, P2, C2P)
876 CHECKFLAGSNEW(GPS, L2P, L2P)
877 CHECKFLAGSNEW(GPS, D2P, D2P)
878 CHECKFLAGSNEW(GPS, S2P, S2P)
879 CHECKFLAGSNEW(GPS, C2, C2X)
880 CHECKFLAGSNEW(GPS, L2C, L2X)
881 CHECKFLAGSNEW(GPS, D2C, D2X)
882 CHECKFLAGSNEW(GPS, S2C, S2X)
883 CHECKFLAGSNEW(GLO, C1, C1C)
884 CHECKFLAGSNEW(GLO, L1C, L1C)
885 CHECKFLAGSNEW(GLO, D1C, D1C)
886 CHECKFLAGSNEW(GLO, S1C, S1C)
887 CHECKFLAGSNEW(GLO, P1, C1P)
888 CHECKFLAGSNEW(GLO, L1P, L1P)
889 CHECKFLAGSNEW(GLO, D1P, D1P)
890 CHECKFLAGSNEW(GLO, S1P, S1P)
891 CHECKFLAGSNEW(GLO, P2, C2P)
892 CHECKFLAGSNEW(GLO, L2P, L2P)
893 CHECKFLAGSNEW(GLO, D2P, D2P)
894 CHECKFLAGSNEW(GLO, S2P, S2P)
895 CHECKFLAGSNEW(GLO, C2, C2C)
896 CHECKFLAGSNEW(GLO, L2C, L2C)
897 CHECKFLAGSNEW(GLO, D2C, D2C)
898 CHECKFLAGSNEW(GLO, S2C, S2C)
899
900 }
901 else
902 {
903#define CHECKFLAGS(a, b) \
904 { \
905 if(data[RINEXENTRY_##b##DATA]) \
906 { \
907 Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
908 Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
909 } \
910 else \
911 { \
912 Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
913 Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
914 data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
915 } \
916 }
917
918 int data[RINEXENTRY_NUMBER];
919 for(i = 0; i < RINEXENTRY_NUMBER; ++i) data[i] = 0;
920
921 CHECKFLAGS(C1,C1)
922 CHECKFLAGS(C2,C2)
923 CHECKFLAGS(P1,P1)
924 CHECKFLAGS(P2,P2)
925 CHECKFLAGS(L1C,L1)
926 CHECKFLAGS(L1P,L1)
927 CHECKFLAGS(L2C,L2)
928 CHECKFLAGS(L2P,L2)
929 CHECKFLAGS(D1C,D1)
930 CHECKFLAGS(D1P,D1)
931 CHECKFLAGS(D2C,D2)
932 CHECKFLAGS(D2P,D2)
933 CHECKFLAGS(S1C,S1)
934 CHECKFLAGS(S1P,S1)
935 CHECKFLAGS(S2C,S2)
936 CHECKFLAGS(S2P,S2)
937 }
938// End Part of Handle Header for BNC Perlt
939#endif
940
941#ifndef NO_RTCM3_MAIN
942 struct HeaderData hdata;
943 char thebuffer[MAXHEADERBUFFERSIZE];
944 char *buffer = thebuffer;
945 size_t buffersize = sizeof(thebuffer);
946 int i;
947
948 memset(&hdata, 0, sizeof(hdata));
949
950 hdata.data.named.version = buffer;
951 i = 1+snprintf(buffer, buffersize,
952 "%9.2f OBSERVATION DATA M (Mixed)"
953 " RINEX VERSION / TYPE", Parser->rinex3 ? 3.0 : 2.11);
954 buffer += i; buffersize -= i;
955
956 {
957 const char *str;
958 hdata.data.named.pgm = buffer;
959 i = HandleRunBy(buffer, buffersize, &str, Parser->rinex3);
960 buffer += i; buffersize -= i;
961 hdata.data.named.observer = buffer;
962 i = 1+snprintf(buffer, buffersize,
963 "%-20.20s "
964 "OBSERVER / AGENCY", str);
965 buffer += i; buffersize -= i;
966 }
967
968 hdata.data.named.marker =
969 "RTCM3TORINEX "
970 "MARKER NAME";
971
972 hdata.data.named.markertype = !Parser->rinex3 ? 0 :
973 "GEODETIC "
974 "MARKER TYPE";
975
976 hdata.data.named.receiver =
977 " "
978 "REC # / TYPE / VERS";
979
980 hdata.data.named.antenna =
981 " "
982 "ANT # / TYPE";
983
984 hdata.data.named.position =
985 " .0000 .0000 .0000 "
986 "APPROX POSITION XYZ";
987
988 hdata.data.named.antennaposition =
989 " .0000 .0000 .0000 "
990 "ANTENNA: DELTA H/E/N";
991
992 hdata.data.named.wavelength = Parser->rinex3 ? 0 :
993 " 1 1 "
994 "WAVELENGTH FACT L1/2";
995
996 if(Parser->rinex3)
997 {
998#define CHECKFLAGSNEW(a, b, c) \
999 if(flags & GNSSDF_##b##DATA) \
1000 { \
1001 Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
1002 Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
1003 ++Parser->numdatatypes##a; \
1004 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#c); \
1005 tbufferpos += 4; \
1006 }
1007
1008 int flags = Parser->startflags;
1009 char tbuffer[6*RINEXENTRY_NUMBER+1];
1010 int tbufferpos = 0;
1011 for(i = 0; i < Parser->Data.numsats; ++i)
1012 flags |= Parser->Data.dataflags[i];
1013
1014 CHECKFLAGSNEW(GPS, C1, C1C)
1015 CHECKFLAGSNEW(GPS, L1C, L1C)
1016 CHECKFLAGSNEW(GPS, D1C, D1C)
1017 CHECKFLAGSNEW(GPS, S1C, S1C)
1018 CHECKFLAGSNEW(GPS, P1, C1P)
1019 CHECKFLAGSNEW(GPS, L1P, L1P)
1020 CHECKFLAGSNEW(GPS, D1P, D1P)
1021 CHECKFLAGSNEW(GPS, S1P, S1P)
1022
1023 hdata.data.named.typesofobsS = buffer;
1024 i = 1+snprintf(buffer, buffersize,
1025 "S %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
1026 buffer += i; buffersize -= i;
1027
1028 CHECKFLAGSNEW(GPS, P2, C2P)
1029 CHECKFLAGSNEW(GPS, L2P, L2P)
1030 CHECKFLAGSNEW(GPS, D2P, D2P)
1031 CHECKFLAGSNEW(GPS, S2P, S2P)
1032 CHECKFLAGSNEW(GPS, C2, C2X)
1033 CHECKFLAGSNEW(GPS, L2C, L2X)
1034 CHECKFLAGSNEW(GPS, D2C, D2X)
1035 CHECKFLAGSNEW(GPS, S2C, S2X)
1036
1037 hdata.data.named.typesofobsG = buffer;
1038 i = 1+snprintf(buffer, buffersize,
1039 "G %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
1040 if(Parser->numdatatypesGPS>13)
1041 {
1042 i += snprintf(buffer+i-1, buffersize,
1043 "\n %-52.52s SYS / # / OBS TYPES", tbuffer+13*4);
1044 }
1045 buffer += i; buffersize -= i;
1046
1047 tbufferpos = 0;
1048
1049 CHECKFLAGSNEW(GLO, C1, C1C)
1050 CHECKFLAGSNEW(GLO, L1C, L1C)
1051 CHECKFLAGSNEW(GLO, D1C, D1C)
1052 CHECKFLAGSNEW(GLO, S1C, S1C)
1053 CHECKFLAGSNEW(GLO, P1, C1P)
1054 CHECKFLAGSNEW(GLO, L1P, L1P)
1055 CHECKFLAGSNEW(GLO, D1P, D1P)
1056 CHECKFLAGSNEW(GLO, S1P, S1P)
1057 CHECKFLAGSNEW(GLO, P2, C2P)
1058 CHECKFLAGSNEW(GLO, L2P, L2P)
1059 CHECKFLAGSNEW(GLO, D2P, D2P)
1060 CHECKFLAGSNEW(GLO, S2P, S2P)
1061 CHECKFLAGSNEW(GLO, C2, C2C)
1062 CHECKFLAGSNEW(GLO, L2C, L2C)
1063 CHECKFLAGSNEW(GLO, D2C, D2C)
1064 CHECKFLAGSNEW(GLO, S2C, S2C)
1065
1066 hdata.data.named.typesofobsR = buffer;
1067 i = 1+snprintf(buffer, buffersize,
1068 "R %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGLO, tbuffer);
1069 if(Parser->numdatatypesGLO>13)
1070 {
1071 i += snprintf(buffer+i-1, buffersize,
1072 "\n %-52.52s SYS / # / OBS TYPES", tbuffer+13*4);
1073 }
1074 buffer += i; buffersize -= i;
1075 }
1076 else
1077 {
1078#define CHECKFLAGS(a, b) \
1079 if(flags & GNSSDF_##a##DATA) \
1080 { \
1081 if(data[RINEXENTRY_##b##DATA]) \
1082 { \
1083 Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
1084 Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
1085 } \
1086 else \
1087 { \
1088 Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
1089 Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
1090 data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
1091 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#b); \
1092 tbufferpos += 6; \
1093 } \
1094 }
1095
1096 int flags = Parser->startflags;
1097 int data[RINEXENTRY_NUMBER];
1098 char tbuffer[6*RINEXENTRY_NUMBER+1];
1099 int tbufferpos = 0;
1100 for(i = 0; i < RINEXENTRY_NUMBER; ++i)
1101 data[i] = 0;
1102 for(i = 0; i < Parser->Data.numsats; ++i)
1103 flags |= Parser->Data.dataflags[i];
1104
1105 CHECKFLAGS(C1,C1)
1106 CHECKFLAGS(C2,C2)
1107 CHECKFLAGS(P1,P1)
1108 CHECKFLAGS(P2,P2)
1109 CHECKFLAGS(L1C,L1)
1110 CHECKFLAGS(L1P,L1)
1111 CHECKFLAGS(L2C,L2)
1112 CHECKFLAGS(L2P,L2)
1113 CHECKFLAGS(D1C,D1)
1114 CHECKFLAGS(D1P,D1)
1115 CHECKFLAGS(D2C,D2)
1116 CHECKFLAGS(D2P,D2)
1117 CHECKFLAGS(S1C,S1)
1118 CHECKFLAGS(S1P,S1)
1119 CHECKFLAGS(S2C,S2)
1120 CHECKFLAGS(S2P,S2)
1121
1122 hdata.data.named.typesofobs = buffer;
1123 i = 1+snprintf(buffer, buffersize,
1124 "%6d%-54.54s# / TYPES OF OBSERV", Parser->numdatatypesGPS, tbuffer);
1125 if(Parser->numdatatypesGPS>9)
1126 {
1127 i += snprintf(buffer+i-1, buffersize,
1128 "\n %-54.54s# / TYPES OF OBSERV", tbuffer+9*6);
1129 }
1130 buffer += i; buffersize -= i;
1131 }
1132
1133 {
1134 struct converttimeinfo cti;
1135 converttime(&cti, Parser->Data.week,
1136 (int)floor(Parser->Data.timeofweek/1000.0));
1137 hdata.data.named.timeoffirstobs = buffer;
1138 i = 1+snprintf(buffer, buffersize,
1139 " %4d %2d %2d %2d %2d %10.7f GPS "
1140 "TIME OF FIRST OBS", cti.year, cti.month, cti.day, cti.hour,
1141 cti.minute, cti.second + fmod(Parser->Data.timeofweek/1000.0,1.0));
1142
1143 buffer += i; buffersize -= i;
1144 }
1145
1146 hdata.numheaders = 15;
1147
1148 if(Parser->headerfile)
1149 {
1150 FILE *fh;
1151 if((fh = fopen(Parser->headerfile, "r")))
1152 {
1153 size_t siz;
1154 char *lastblockstart;
1155 if((siz = fread(buffer, 1, buffersize-1, fh)) > 0)
1156 {
1157 buffer[siz] = '\n';
1158 if(siz == buffersize)
1159 {
1160 RTCM3Error("Header file is too large. Only %d bytes read.",
1161 (int)siz);
1162 }
1163 /* scan the file line by line and enter the entries in the list */
1164 /* warn for "# / TYPES OF OBSERV" and "TIME OF FIRST OBS" */
1165 /* overwrites entries, except for comments */
1166 lastblockstart = buffer;
1167 for(i = 0; i < (int)siz; ++i)
1168 {
1169 if(buffer[i] == '\n')
1170 { /* we found a line */
1171 char *end;
1172 while(buffer[i+1] == '\r')
1173 ++i; /* skip \r in case there are any */
1174 end = buffer+i;
1175 while(*end == '\t' || *end == ' ' || *end == '\r' || *end == '\n')
1176 *(end--) = 0;
1177 if(end-lastblockstart < 60+5) /* short line */
1178 RTCM3Error("Short Header line '%s' ignored.\n", lastblockstart);
1179 else
1180 {
1181 int pos;
1182 if(!strcmp("COMMENT", lastblockstart+60))
1183 pos = hdata.numheaders;
1184 else
1185 {
1186 for(pos = 0; pos < hdata.numheaders; ++pos)
1187 {
1188 if(!strcmp(hdata.data.unnamed[pos]+60, lastblockstart+60))
1189 break;
1190 }
1191 if(!strcmp("# / TYPES OF OBSERV", lastblockstart+60)
1192 || !strcmp("TIME OF FIRST OBS", lastblockstart+60))
1193 {
1194 RTCM3Error("Overwriting header '%s' is dangerous.\n",
1195 lastblockstart+60);
1196 }
1197 }
1198 if(pos >= MAXHEADERLINES)
1199 {
1200 RTCM3Error("Maximum number of header lines of %d reached.\n",
1201 MAXHEADERLINES);
1202 }
1203 else if(!strcmp("END OF HEADER", lastblockstart+60))
1204 {
1205 RTCM3Error("End of header ignored.\n");
1206 }
1207 else
1208 {
1209 hdata.data.unnamed[pos] = lastblockstart;
1210 if(pos == hdata.numheaders)
1211 ++hdata.numheaders;
1212 }
1213 }
1214 lastblockstart = buffer+i+1;
1215 }
1216 }
1217 }
1218 else
1219 {
1220 RTCM3Error("Could not read data from headerfile '%s'.\n",
1221 Parser->headerfile);
1222 }
1223 fclose(fh);
1224 }
1225 else
1226 {
1227 RTCM3Error("Could not open header datafile '%s'.\n",
1228 Parser->headerfile);
1229 }
1230 }
1231
1232 for(i = 0; i < hdata.numheaders; ++i)
1233 {
1234 if(hdata.data.unnamed[i] && hdata.data.unnamed[i][0])
1235 RTCM3Text("%s\n", hdata.data.unnamed[i]);
1236 }
1237 RTCM3Text(" "
1238 "END OF HEADER\n");
1239#endif
1240}
1241
1242static void ConvLine(FILE *file, const char *fmt, ...)
1243{
1244 char buffer[100], *b;
1245 va_list v;
1246 va_start(v, fmt);
1247 vsnprintf(buffer, sizeof(buffer), fmt, v);
1248 for(b = buffer; *b; ++b)
1249 {
1250 if(*b == 'e') *b = 'D';
1251 }
1252 fprintf(file, "%s", buffer);
1253 va_end(v);
1254}
1255
1256void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
1257{
1258 Parser->Message[Parser->MessageSize++] = byte;
1259 if(Parser->MessageSize >= Parser->NeedBytes)
1260 {
1261 int r;
1262 while((r = RTCM3Parser(Parser)))
1263 {
1264 if(r == 1020 || r == 1019)
1265 {
1266 FILE *file = 0;
1267
1268 if(Parser->rinex3 && !(file = Parser->gpsfile))
1269 {
1270 const char *n = Parser->gpsephemeris ? Parser->gpsephemeris : Parser->glonassephemeris;
1271 if(n)
1272 {
1273 if(!(Parser->gpsfile = fopen(n, "w")))
1274 {
1275 RTCM3Error("Could not open ephemeris output file.\n");
1276 }
1277 else
1278 {
1279 char buffer[100];
1280 fprintf(Parser->gpsfile,
1281 "%9.2f%11sN: GNSS NAV DATA M: Mixed%12sRINEX VERSION / TYPE\n", 3.0, "", "");
1282 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1283 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1284 }
1285 Parser->gpsephemeris = 0;
1286 Parser->glonassephemeris = 0;
1287 file = Parser->gpsfile;
1288 }
1289 }
1290 else
1291 {
1292 if(r == 1020)
1293 {
1294 if(Parser->glonassephemeris)
1295 {
1296 if(!(Parser->glonassfile = fopen(Parser->glonassephemeris, "w")))
1297 {
1298 RTCM3Error("Could not open GLONASS ephemeris output file.\n");
1299 }
1300 else
1301 {
1302 char buffer[100];
1303 fprintf(Parser->glonassfile,
1304 "%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n", 2.1, "", "");
1305 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1306 fprintf(Parser->glonassfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1307 }
1308 Parser->glonassephemeris = 0;
1309 }
1310 file = Parser->glonassfile;
1311 }
1312 else if(r == 1019)
1313 {
1314 if(Parser->gpsephemeris)
1315 {
1316 if(!(Parser->gpsfile = fopen(Parser->gpsephemeris, "w")))
1317 {
1318 RTCM3Error("Could not open GPS ephemeris output file.\n");
1319 }
1320 else
1321 {
1322 char buffer[100];
1323 fprintf(Parser->gpsfile,
1324 "%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 2.1, "", "");
1325 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1326 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1327 }
1328 Parser->gpsephemeris = 0;
1329 }
1330 file = Parser->gpsfile;
1331 }
1332 }
1333 if(file)
1334 {
1335 if(r == 1020)
1336 {
1337 struct glonassephemeris *e = &Parser->ephemerisGLONASS;
1338 int w = e->GPSWeek, tow = e->GPSTOW, i;
1339 struct converttimeinfo cti;
1340
1341 updatetime(&w, &tow, e->tb*1000, 1);
1342 converttime(&cti, w, tow);
1343
1344 i = e->tk-3*60*60; if(i < 0) i += 86400;
1345
1346 if(Parser->rinex3)
1347 ConvLine(file, "R%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1348 e->almanac_number, cti.year, cti.month, cti.day, cti.hour, cti.minute,
1349 cti.second, -e->tau, e->gamma, (double) i);
1350 else
1351 ConvLine(file, "%02d %02d %02d %02d %02d %02d%5.1f%19.12e%19.12e%19.12e\n",
1352 e->almanac_number, cti.year%100, cti.month, cti.day, cti.hour, cti.minute,
1353 (double) cti.second, -e->tau, e->gamma, (double) i);
1354 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->x_pos,
1355 e->x_velocity, e->x_acceleration, (e->flags & GLOEPHF_UNHEALTHY) ? 1.0 : 0.0);
1356 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->y_pos,
1357 e->y_velocity, e->y_acceleration, (double) e->frequency_number);
1358 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->z_pos,
1359 e->z_velocity, e->z_acceleration, (double) e->E);
1360 }
1361 else /* if(r == 1019) */
1362 {
1363 struct gpsephemeris *e = &Parser->ephemerisGPS;
1364 double d; /* temporary variable */
1365 unsigned long int i; /* temporary variable */
1366 struct converttimeinfo cti;
1367 converttime(&cti, e->GPSweek, e->TOC);
1368
1369 if(Parser->rinex3)
1370 ConvLine(file, "G%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1371 e->satellite, cti.year, cti.month, cti.day, cti.hour,
1372 cti.minute, cti.second, e->clock_bias, e->clock_drift,
1373 e->clock_driftrate);
1374 else
1375 ConvLine(file, "%02d %02d %02d %02d %02d %02d%05.1f%19.12e%19.12e%19.12e\n",
1376 e->satellite, cti.year%100, cti.month, cti.day, cti.hour,
1377 cti.minute, (double) cti.second, e->clock_bias, e->clock_drift,
1378 e->clock_driftrate);
1379 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", (double)e->IODE,
1380 e->Crs, e->Delta_n, e->M0);
1381 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->Cuc,
1382 e->e, e->Cus, e->sqrt_A);
1383 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n",
1384 (double) e->TOE, e->Cic, e->OMEGA0, e->Cis);
1385 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->i0,
1386 e->Crc, e->omega, e->OMEGADOT);
1387 d = 0;
1388 i = e->flags;
1389 if(i & GPSEPHF_L2CACODE)
1390 d += 2.0;
1391 if(i & GPSEPHF_L2PCODE)
1392 d += 1.0;
1393 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->IDOT, d,
1394 (double) e->GPSweek, i & GPSEPHF_L2PCODEDATA ? 1.0 : 0.0);
1395 if(e->URAindex <= 6) /* URA index */
1396 d = ceil(10.0*pow(2.0, 1.0+((double)e->URAindex)/2.0))/10.0;
1397 else
1398 d = ceil(10.0*pow(2.0, ((double)e->URAindex)/2.0))/10.0;
1399 /* 15 indicates not to use satellite. We can't handle this special
1400 case, so we create a high "non"-accuracy value. */
1401 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", d,
1402 ((double) e->SVhealth), e->TGD, ((double) e->IODC));
1403
1404 ConvLine(file, " %19.12e%19.12e\n", ((double)e->TOW), 0.0);
1405 /* TOW */
1406 }
1407 }
1408 }
1409 else
1410 {
1411 int i, j, o;
1412 struct converttimeinfo cti;
1413
1414 if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
1415 {
1416 ++Parser->init;
1417
1418 if(Parser->init == NUMSTARTSKIP)
1419 HandleHeader(Parser);
1420 else
1421 {
1422 for(i = 0; i < Parser->Data.numsats; ++i)
1423 Parser->startflags |= Parser->Data.dataflags[i];
1424 continue;
1425 }
1426 }
1427 if(r == 2 && !Parser->validwarning)
1428 {
1429 RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
1430 " COMMENT\n");
1431 Parser->validwarning = 1;
1432 }
1433
1434 converttime(&cti, Parser->Data.week,
1435 (int)floor(Parser->Data.timeofweek/1000.0));
1436 if(Parser->rinex3)
1437 {
1438 RTCM3Text("> %04d %02d %02d %02d %02d%11.7f 0%3d\n",
1439 cti.year, cti.month, cti.day, cti.hour, cti.minute, cti.second
1440 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1441 for(i = 0; i < Parser->Data.numsats; ++i)
1442 {
1443 int glo = 0;
1444 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1445 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1446 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1447 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1448 {
1449 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1450 glo = 1;
1451 }
1452 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1453 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1454 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1455 else
1456 RTCM3Text("%3d", Parser->Data.satellites[i]);
1457
1458 if(glo)
1459 {
1460 for(j = 0; j < Parser->numdatatypesGLO; ++j)
1461 {
1462 int df = Parser->dataflagGLO[j];
1463 int pos = Parser->dataposGLO[j];
1464 if((Parser->Data.dataflags[i] & df)
1465 && !isnan(Parser->Data.measdata[i][pos])
1466 && !isinf(Parser->Data.measdata[i][pos]))
1467 {
1468 char lli = ' ';
1469 char snr = ' ';
1470 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1471 {
1472 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1473 lli = '1';
1474 snr = '0'+Parser->Data.snrL1[i];
1475 }
1476 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1477 {
1478 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1479 lli = '1';
1480 snr = '0'+Parser->Data.snrL2[i];
1481 }
1482 RTCM3Text("%14.3f%c%c",
1483 Parser->Data.measdata[i][pos],lli,snr);
1484 }
1485 else
1486 { /* no or illegal data */
1487 RTCM3Text(" ");
1488 }
1489 }
1490 }
1491 else
1492 {
1493 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1494 {
1495 int df = Parser->dataflagGPS[j];
1496 int pos = Parser->dataposGPS[j];
1497 if((Parser->Data.dataflags[i] & df)
1498 && !isnan(Parser->Data.measdata[i][pos])
1499 && !isinf(Parser->Data.measdata[i][pos]))
1500 {
1501 char lli = ' ';
1502 char snr = ' ';
1503 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1504 {
1505 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1506 lli = '1';
1507 snr = '0'+Parser->Data.snrL1[i];
1508 }
1509 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1510 {
1511 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1512 lli = '1';
1513 snr = '0'+Parser->Data.snrL2[i];
1514 }
1515 RTCM3Text("%14.3f%c%c",
1516 Parser->Data.measdata[i][pos],lli,snr);
1517 }
1518 else
1519 { /* no or illegal data */
1520 RTCM3Text(" ");
1521 }
1522 }
1523 }
1524 RTCM3Text("\n");
1525 }
1526 }
1527 else
1528 {
1529 RTCM3Text(" %02d %2d %2d %2d %2d %10.7f 0%3d",
1530 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
1531 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1532 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
1533 {
1534 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1535 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1536 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1537 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1538 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1539 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1540 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1541 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1542 else
1543 RTCM3Text("%3d", Parser->Data.satellites[i]);
1544 }
1545 RTCM3Text("\n");
1546 o = 12;
1547 j = Parser->Data.numsats - 12;
1548 while(j > 0)
1549 {
1550 RTCM3Text(" ");
1551 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
1552 {
1553 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1554 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1555 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1556 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1557 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1558 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1559 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1560 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1561 else
1562 RTCM3Text("%3d", Parser->Data.satellites[i]);
1563 }
1564 RTCM3Text("\n");
1565 j -= 12;
1566 o += 12;
1567 }
1568 for(i = 0; i < Parser->Data.numsats; ++i)
1569 {
1570 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1571 {
1572 int v = 0;
1573 int df = Parser->dataflag[j];
1574 int pos = Parser->datapos[j];
1575 if((Parser->Data.dataflags[i] & df)
1576 && !isnan(Parser->Data.measdata[i][pos])
1577 && !isinf(Parser->Data.measdata[i][pos]))
1578 {
1579 v = 1;
1580 }
1581 else
1582 {
1583 df = Parser->dataflagGPS[j];
1584 pos = Parser->dataposGPS[j];
1585
1586 if((Parser->Data.dataflags[i] & df)
1587 && !isnan(Parser->Data.measdata[i][pos])
1588 && !isinf(Parser->Data.measdata[i][pos]))
1589 {
1590 v = 1;
1591 }
1592 }
1593
1594 if(!v)
1595 { /* no or illegal data */
1596 RTCM3Text(" ");
1597 }
1598 else
1599 {
1600 char lli = ' ';
1601 char snr = ' ';
1602 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1603 {
1604 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1605 lli = '1';
1606 snr = '0'+Parser->Data.snrL1[i];
1607 }
1608 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1609 {
1610 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1611 lli = '1';
1612 snr = '0'+Parser->Data.snrL2[i];
1613 }
1614 RTCM3Text("%14.3f%c%c",
1615 Parser->Data.measdata[i][pos],lli,snr);
1616 }
1617 if(j%5 == 4 || j == Parser->numdatatypesGPS-1)
1618 RTCM3Text("\n");
1619 }
1620 }
1621 }
1622 }
1623 }
1624 }
1625}
1626
1627#ifndef NO_RTCM3_MAIN
1628static char datestr[] = "$Date: 2008/08/09 23:58:09 $";
1629
1630/* The string, which is send as agent in HTTP request */
1631#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
1632
1633#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
1634
1635static const char encodingTable [64] = {
1636 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1637 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1638 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1639 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1640};
1641
1642/* does not buffer overrun, but breaks directly after an error */
1643/* returns the number of required bytes */
1644static int encode(char *buf, int size, const char *user, const char *pwd)
1645{
1646 unsigned char inbuf[3];
1647 char *out = buf;
1648 int i, sep = 0, fill = 0, bytes = 0;
1649
1650 while(*user || *pwd)
1651 {
1652 i = 0;
1653 while(i < 3 && *user) inbuf[i++] = *(user++);
1654 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1655 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1656 while(i < 3) {inbuf[i++] = 0; ++fill; }
1657 if(out-buf < size-1)
1658 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1659 if(out-buf < size-1)
1660 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1661 | ((inbuf [1] & 0xF0) >> 4)];
1662 if(out-buf < size-1)
1663 {
1664 if(fill == 2)
1665 *(out++) = '=';
1666 else
1667 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1668 | ((inbuf [2] & 0xC0) >> 6)];
1669 }
1670 if(out-buf < size-1)
1671 {
1672 if(fill >= 1)
1673 *(out++) = '=';
1674 else
1675 *(out++) = encodingTable[inbuf [2] & 0x3F];
1676 }
1677 bytes += 4;
1678 }
1679 if(out-buf < size)
1680 *out = 0;
1681 return bytes;
1682}
1683
1684static int stop = 0;
1685
1686struct Args
1687{
1688 const char *server;
1689 const char *port;
1690 int mode;
1691 int timeout;
1692 int rinex3;
1693 const char *user;
1694 const char *password;
1695 const char *proxyhost;
1696 const char *proxyport;
1697 const char *nmea;
1698 const char *data;
1699 const char *headerfile;
1700 const char *gpsephemeris;
1701 const char *glonassephemeris;
1702};
1703
1704/* option parsing */
1705#ifdef NO_LONG_OPTS
1706#define LONG_OPT(a)
1707#else
1708#define LONG_OPT(a) a
1709static struct option opts[] = {
1710{ "data", required_argument, 0, 'd'},
1711{ "server", required_argument, 0, 's'},
1712{ "password", required_argument, 0, 'p'},
1713{ "port", required_argument, 0, 'r'},
1714{ "timeout", required_argument, 0, 't'},
1715{ "header", required_argument, 0, 'f'},
1716{ "user", required_argument, 0, 'u'},
1717{ "gpsephemeris", required_argument, 0, 'E'},
1718{ "glonassephemeris", required_argument, 0, 'G'},
1719{ "rinex3", no_argument, 0, '3'},
1720{ "proxyport", required_argument, 0, 'R'},
1721{ "proxyhost", required_argument, 0, 'S'},
1722{ "nmea", required_argument, 0, 'n'},
1723{ "mode", required_argument, 0, 'M'},
1724{ "help", no_argument, 0, 'h'},
1725{0,0,0,0}};
1726#endif
1727#define ARGOPT "-d:s:p:r:t:f:u:E:G:M:S:R:n:h3"
1728
1729enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };
1730
1731static const char *geturl(const char *url, struct Args *args)
1732{
1733 static char buf[1000];
1734 static char *Buffer = buf;
1735 static char *Bufend = buf+sizeof(buf);
1736
1737 if(strncmp("ntrip:", url, 6))
1738 return "URL must start with 'ntrip:'.";
1739 url += 6; /* skip ntrip: */
1740
1741 if(*url != '@' && *url != '/')
1742 {
1743 /* scan for mountpoint */
1744 args->data = Buffer;
1745 while(*url && *url != '@' && *url != ';' &&*url != '/' && Buffer != Bufend)
1746 *(Buffer++) = *(url++);
1747 if(Buffer == args->data)
1748 return "Mountpoint required.";
1749 else if(Buffer >= Bufend-1)
1750 return "Parsing buffer too short.";
1751 *(Buffer++) = 0;
1752 }
1753
1754 if(*url == '/') /* username and password */
1755 {
1756 ++url;
1757 args->user = Buffer;
1758 while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
1759 *(Buffer++) = *(url++);
1760 if(Buffer == args->user)
1761 return "Username cannot be empty.";
1762 else if(Buffer >= Bufend-1)
1763 return "Parsing buffer too short.";
1764 *(Buffer++) = 0;
1765
1766 if(*url == ':') ++url;
1767
1768 args->password = Buffer;
1769 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1770 *(Buffer++) = *(url++);
1771 if(Buffer == args->password)
1772 return "Password cannot be empty.";
1773 else if(Buffer >= Bufend-1)
1774 return "Parsing buffer too short.";
1775 *(Buffer++) = 0;
1776 }
1777
1778 if(*url == '@') /* server */
1779 {
1780 ++url;
1781 if(*url != '@' && *url != ':')
1782 {
1783 args->server = Buffer;
1784 while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
1785 *(Buffer++) = *(url++);
1786 if(Buffer == args->server)
1787 return "Servername cannot be empty.";
1788 else if(Buffer >= Bufend-1)
1789 return "Parsing buffer too short.";
1790 *(Buffer++) = 0;
1791 }
1792
1793 if(*url == ':')
1794 {
1795 ++url;
1796 args->port = Buffer;
1797 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1798 *(Buffer++) = *(url++);
1799 if(Buffer == args->port)
1800 return "Port cannot be empty.";
1801 else if(Buffer >= Bufend-1)
1802 return "Parsing buffer too short.";
1803 *(Buffer++) = 0;
1804 }
1805
1806 if(*url == '@') /* proxy */
1807 {
1808 ++url;
1809 args->proxyhost = Buffer;
1810 while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
1811 *(Buffer++) = *(url++);
1812 if(Buffer == args->proxyhost)
1813 return "Proxy servername cannot be empty.";
1814 else if(Buffer >= Bufend-1)
1815 return "Parsing buffer too short.";
1816 *(Buffer++) = 0;
1817
1818 if(*url == ':')
1819 {
1820 ++url;
1821 args->proxyport = Buffer;
1822 while(*url && *url != ';' && Buffer != Bufend)
1823 *(Buffer++) = *(url++);
1824 if(Buffer == args->proxyport)
1825 return "Proxy port cannot be empty.";
1826 else if(Buffer >= Bufend-1)
1827 return "Parsing buffer too short.";
1828 *(Buffer++) = 0;
1829 }
1830 }
1831 }
1832 if(*url == ';') /* NMEA */
1833 {
1834 args->nmea = ++url;
1835 while(*url)
1836 ++url;
1837 }
1838
1839 return *url ? "Garbage at end of server string." : 0;
1840}
1841
1842static int getargs(int argc, char **argv, struct Args *args)
1843{
1844 int res = 1;
1845 int getoptr;
1846 int help = 0;
1847 char *t;
1848
1849 args->server = "www.euref-ip.net";
1850 args->port = "2101";
1851 args->timeout = 60;
1852 args->user = "";
1853 args->password = "";
1854 args->data = 0;
1855 args->headerfile = 0;
1856 args->gpsephemeris = 0;
1857 args->glonassephemeris = 0;
1858 args->rinex3 = 0;
1859 args->nmea = 0;
1860 args->proxyhost = 0;
1861 args->proxyport = "2101";
1862 args->mode = AUTO;
1863 help = 0;
1864
1865 do
1866 {
1867
1868#ifdef NO_LONG_OPTS
1869 switch((getoptr = getopt(argc, argv, ARGOPT)))
1870#else
1871 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
1872#endif
1873 {
1874 case 's': args->server = optarg; break;
1875 case 'u': args->user = optarg; break;
1876 case 'p': args->password = optarg; break;
1877 case 'd': args->data = optarg; break;
1878 case 'f': args->headerfile = optarg; break;
1879 case 'E': args->gpsephemeris = optarg; break;
1880 case 'G': args->glonassephemeris = optarg; break;
1881 case 'r': args->port = optarg; break;
1882 case '3': args->rinex3 = 1; break;
1883 case 'S': args->proxyhost = optarg; break;
1884 case 'n': args->nmea = optarg; break;
1885 case 'R': args->proxyport = optarg; break;
1886 case 'h': help=1; break;
1887 case 'M':
1888 args->mode = 0;
1889 if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
1890 args->mode = NTRIP1;
1891 else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
1892 args->mode = HTTP;
1893 else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
1894 args->mode = RTSP;
1895 else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
1896 args->mode = AUTO;
1897 else args->mode = atoi(optarg);
1898 if((args->mode == 0) || (args->mode >= END))
1899 {
1900 fprintf(stderr, "Mode %s unknown\n", optarg);
1901 res = 0;
1902 }
1903 break;
1904 case 't':
1905 args->timeout = strtoul(optarg, &t, 10);
1906 if((t && *t) || args->timeout < 0)
1907 res = 0;
1908 break;
1909
1910 case 1:
1911 {
1912 const char *err;
1913 if((err = geturl(optarg, args)))
1914 {
1915 RTCM3Error("%s\n\n", err);
1916 res = 0;
1917 }
1918 }
1919 break;
1920 case -1: break;
1921 }
1922 } while(getoptr != -1 || !res);
1923
1924 datestr[0] = datestr[7];
1925 datestr[1] = datestr[8];
1926 datestr[2] = datestr[9];
1927 datestr[3] = datestr[10];
1928 datestr[5] = datestr[12];
1929 datestr[6] = datestr[13];
1930 datestr[8] = datestr[15];
1931 datestr[9] = datestr[16];
1932 datestr[4] = datestr[7] = '-';
1933 datestr[10] = 0;
1934
1935 if(args->gpsephemeris && args->glonassephemeris && args->rinex3)
1936 {
1937 RTCM3Error("RINEX3 produces a combined ephemeris file, but 2 files were specified.\n"
1938 "Please specify only one navigation file.\n");
1939 res = 0;
1940 }
1941 else if(!res || help)
1942 {
1943 RTCM3Error("Version %s (%s) GPL" COMPILEDATE
1944 "\nUsage: %s -s server -u user ...\n"
1945 " -d " LONG_OPT("--data ") "the requested data set\n"
1946 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
1947 " -s " LONG_OPT("--server ") "the server name or address\n"
1948 " -p " LONG_OPT("--password ") "the login password\n"
1949 " -r " LONG_OPT("--port ") "the server port number (default 2101)\n"
1950 " -t " LONG_OPT("--timeout ") "timeout in seconds (default 60)\n"
1951 " -u " LONG_OPT("--user ") "the user name\n"
1952 " -E " LONG_OPT("--gpsephemeris ") "output file for GPS ephemeris data\n"
1953 " -G " LONG_OPT("--glonassephemeris ") "output file for GLONASS ephemeris data\n"
1954 " -3 " LONG_OPT("--rinex3 ") "output RINEX type 3 data\n"
1955 " -S " LONG_OPT("--proxyhost ") "proxy name or address\n"
1956 " -R " LONG_OPT("--proxyport ") "proxy port, optional (default 2101)\n"
1957 " -n " LONG_OPT("--nmea ") "NMEA string for sending to server\n"
1958 " -M " LONG_OPT("--mode ") "mode for data request\n"
1959 " Valid modes are:\n"
1960 " 1, h, http NTRIP Version 2.0 Caster in TCP/IP mode\n"
1961 " 2, r, rtsp NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
1962 " 3, n, ntrip1 NTRIP Version 1.0 Caster\n"
1963 " 4, a, auto automatic detection (default)\n"
1964 "or using an URL:\n%s ntrip:data[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
1965 , revisionstr, datestr, argv[0], argv[0]);
1966 exit(1);
1967 }
1968 return res;
1969}
1970
1971/* let the output complete a block if necessary */
1972static void signalhandler(int sig)
1973{
1974 if(!stop)
1975 {
1976 RTCM3Error("Stop signal number %d received. "
1977 "Trying to terminate gentle.\n", sig);
1978 stop = 1;
1979 alarm(1);
1980 }
1981}
1982
1983#define ALARMTIME (2*60)
1984
1985/* for some reason we had to abort hard (maybe waiting for data */
1986#ifdef __GNUC__
1987static __attribute__ ((noreturn)) void signalhandler_alarm(
1988int sig __attribute__((__unused__)))
1989#else /* __GNUC__ */
1990static void signalhandler_alarm(int sig)
1991#endif /* __GNUC__ */
1992{
1993 RTCM3Error("Programm forcefully terminated.\n");
1994 exit(1);
1995}
1996
1997int main(int argc, char **argv)
1998{
1999 struct Args args;
2000 struct RTCM3ParserData Parser;
2001
2002 setbuf(stdout, 0);
2003 setbuf(stdin, 0);
2004 setbuf(stderr, 0);
2005
2006 {
2007 char *a;
2008 int i=0;
2009 for(a = revisionstr+11; *a && *a != ' '; ++a)
2010 revisionstr[i++] = *a;
2011 revisionstr[i] = 0;
2012 }
2013
2014 signal(SIGINT, signalhandler);
2015 signal(SIGALRM,signalhandler_alarm);
2016 signal(SIGQUIT,signalhandler);
2017 signal(SIGTERM,signalhandler);
2018 signal(SIGPIPE,signalhandler);
2019 memset(&Parser, 0, sizeof(Parser));
2020 {
2021 time_t tim;
2022 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
2023 Parser.GPSWeek = tim/(7*24*60*60);
2024 Parser.GPSTOW = tim%(7*24*60*60);
2025 }
2026
2027 if(getargs(argc, argv, &args))
2028 {
2029 int sockfd, numbytes;
2030 char buf[MAXDATASIZE];
2031 struct sockaddr_in their_addr; /* connector's address information */
2032 struct hostent *he;
2033 struct servent *se;
2034 const char *server, *port, *proxyserver = 0;
2035 char proxyport[6];
2036 char *b;
2037 long i;
2038 struct timeval tv;
2039
2040 alarm(ALARMTIME);
2041
2042 Parser.headerfile = args.headerfile;
2043 Parser.glonassephemeris = args.glonassephemeris;
2044 Parser.gpsephemeris = args.gpsephemeris;
2045 Parser.rinex3 = args.rinex3;
2046
2047 if(args.proxyhost)
2048 {
2049 int p;
2050 if((i = strtol(args.port, &b, 10)) && (!b || !*b))
2051 p = i;
2052 else if(!(se = getservbyname(args.port, 0)))
2053 {
2054 RTCM3Error("Can't resolve port %s.", args.port);
2055 exit(1);
2056 }
2057 else
2058 {
2059 p = ntohs(se->s_port);
2060 }
2061 snprintf(proxyport, sizeof(proxyport), "%d", p);
2062 port = args.proxyport;
2063 proxyserver = args.server;
2064 server = args.proxyhost;
2065 }
2066 else
2067 {
2068 server = args.server;
2069 port = args.port;
2070 }
2071
2072 memset(&their_addr, 0, sizeof(struct sockaddr_in));
2073 if((i = strtol(port, &b, 10)) && (!b || !*b))
2074 their_addr.sin_port = htons(i);
2075 else if(!(se = getservbyname(port, 0)))
2076 {
2077 RTCM3Error("Can't resolve port %s.", port);
2078 exit(1);
2079 }
2080 else
2081 {
2082 their_addr.sin_port = se->s_port;
2083 }
2084 if(!(he=gethostbyname(server)))
2085 {
2086 RTCM3Error("Server name lookup failed for '%s'.\n", server);
2087 exit(1);
2088 }
2089 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
2090 {
2091 perror("socket");
2092 exit(1);
2093 }
2094
2095 tv.tv_sec = args.timeout;
2096 tv.tv_usec = 0;
2097 if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval) ) == -1)
2098 {
2099 RTCM3Error("Function setsockopt: %s\n", strerror(errno));
2100 exit(1);
2101 }
2102
2103 their_addr.sin_family = AF_INET;
2104 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2105
2106 if(args.data && args.mode == RTSP)
2107 {
2108 struct sockaddr_in local;
2109 int sockudp, localport;
2110 int cseq = 1;
2111 socklen_t len;
2112
2113 if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
2114 {
2115 perror("socket");
2116 exit(1);
2117 }
2118 /* fill structure with local address information for UDP */
2119 memset(&local, 0, sizeof(local));
2120 local.sin_family = AF_INET;
2121 local.sin_port = htons(0);
2122 local.sin_addr.s_addr = htonl(INADDR_ANY);
2123 len = sizeof(local);
2124 /* bind() in order to get a random RTP client_port */
2125 if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
2126 {
2127 perror("bind");
2128 exit(1);
2129 }
2130 if((getsockname(sockudp, (struct sockaddr*)&local, &len)) != -1)
2131 {
2132 localport = ntohs(local.sin_port);
2133 }
2134 else
2135 {
2136 perror("local access failed");
2137 exit(1);
2138 }
2139 if(connect(sockfd, (struct sockaddr *)&their_addr,
2140 sizeof(struct sockaddr)) == -1)
2141 {
2142 perror("connect");
2143 exit(1);
2144 }
2145 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2146 "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"
2147 "CSeq: %d\r\n"
2148 "Ntrip-Version: Ntrip/2.0\r\n"
2149 "Ntrip-Component: Ntripclient\r\n"
2150 "User-Agent: %s/%s\r\n"
2151 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
2152 "Authorization: Basic ",
2153 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2154 args.data, cseq++, AGENTSTRING, revisionstr, localport);
2155 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
2156 {
2157 RTCM3Error("Requested data too long\n");
2158 exit(1);
2159 }
2160 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
2161 if(i > MAXDATASIZE-4)
2162 {
2163 RTCM3Error("Username and/or password too long\n");
2164 exit(1);
2165 }
2166 buf[i++] = '\r';
2167 buf[i++] = '\n';
2168 buf[i++] = '\r';
2169 buf[i++] = '\n';
2170 if(args.nmea)
2171 {
2172 int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
2173 if(j >= 0 && j < MAXDATASIZE-i)
2174 i += j;
2175 else
2176 {
2177 RTCM3Error("NMEA string too long\n");
2178 exit(1);
2179 }
2180 }
2181 if(send(sockfd, buf, (size_t)i, 0) != i)
2182 {
2183 perror("send");
2184 exit(1);
2185 }
2186 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2187 {
2188 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2189 {
2190 int serverport = 0, session = 0;
2191 const char *portcheck = "server_port=";
2192 const char *sessioncheck = "session: ";
2193 int l = strlen(portcheck)-1;
2194 int j=0;
2195 for(i = 0; j != l && i < numbytes-l; ++i)
2196 {
2197 for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
2198 ;
2199 }
2200 if(i == numbytes-l)
2201 {
2202 RTCM3Error("No server port number found\n");
2203 exit(1);
2204 }
2205 else
2206 {
2207 i+=l;
2208 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2209 serverport = serverport * 10 + buf[i++]-'0';
2210 if(buf[i] != '\r' && buf[i] != ';')
2211 {
2212 RTCM3Error("Could not extract server port\n");
2213 exit(1);
2214 }
2215 }
2216 l = strlen(sessioncheck)-1;
2217 j=0;
2218 for(i = 0; j != l && i < numbytes-l; ++i)
2219 {
2220 for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
2221 ;
2222 }
2223 if(i == numbytes-l)
2224 {
2225 RTCM3Error("No session number found\n");
2226 exit(1);
2227 }
2228 else
2229 {
2230 i+=l;
2231 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2232 session = session * 10 + buf[i++]-'0';
2233 if(buf[i] != '\r')
2234 {
2235 RTCM3Error("Could not extract session number\n");
2236 exit(1);
2237 }
2238 }
2239
2240 i = snprintf(buf, MAXDATASIZE,
2241 "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"
2242 "CSeq: %d\r\n"
2243 "Session: %d\r\n"
2244 "\r\n",
2245 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2246 args.data, cseq++, session);
2247
2248 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2249 {
2250 RTCM3Error("Requested data too long\n");
2251 exit(1);
2252 }
2253 if(send(sockfd, buf, (size_t)i, 0) != i)
2254 {
2255 perror("send");
2256 exit(1);
2257 }
2258 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2259 {
2260 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2261 {
2262 struct sockaddr_in addrRTP;
2263 /* fill structure with caster address information for UDP */
2264 memset(&addrRTP, 0, sizeof(addrRTP));
2265 addrRTP.sin_family = AF_INET;
2266 addrRTP.sin_port = htons(serverport);
2267 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2268 len = sizeof(addrRTP);
2269 int ts = 0;
2270 int sn = 0;
2271 int ssrc = 0;
2272 int init = 0;
2273 int u, v, w;
2274 while(!stop && (i = recvfrom(sockudp, buf, 1526, 0,
2275 (struct sockaddr*) &addrRTP, &len)) > 0)
2276 {
2277 alarm(ALARMTIME);
2278 if(i >= 12+1 && (unsigned char)buf[0] == (2 << 6) && buf[1] == 0x60)
2279 {
2280 u= ((unsigned char)buf[2]<<8)+(unsigned char)buf[3];
2281 v = ((unsigned char)buf[4]<<24)+((unsigned char)buf[5]<<16)
2282 +((unsigned char)buf[6]<<8)+(unsigned char)buf[7];
2283 w = ((unsigned char)buf[8]<<24)+((unsigned char)buf[9]<<16)
2284 +((unsigned char)buf[10]<<8)+(unsigned char)buf[11];
2285
2286 if(init)
2287 {
2288 if(u < -30000 && sn > 30000) sn -= 0xFFFF;
2289 if(ssrc != w || ts > v)
2290 {
2291 RTCM3Error("Illegal UDP data received.\n");
2292 exit(1);
2293 }
2294 if(u > sn) /* don't show out-of-order packets */
2295 fwrite(buf+12, (size_t)i-12, 1, stdout);
2296 }
2297 sn = u; ts = v; ssrc = w; init = 1;
2298 }
2299 else
2300 {
2301 RTCM3Error("Illegal UDP header.\n");
2302 exit(1);
2303 }
2304 }
2305 }
2306 i = snprintf(buf, MAXDATASIZE,
2307 "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"
2308 "CSeq: %d\r\n"
2309 "Session: %d\r\n"
2310 "\r\n",
2311 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2312 args.data, cseq++, session);
2313
2314 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2315 {
2316 RTCM3Error("Requested data too long\n");
2317 exit(1);
2318 }
2319 if(send(sockfd, buf, (size_t)i, 0) != i)
2320 {
2321 perror("send");
2322 exit(1);
2323 }
2324 }
2325 else
2326 {
2327 RTCM3Error("Could not start data stream.\n");
2328 exit(1);
2329 }
2330 }
2331 else
2332 {
2333 RTCM3Error("Could not setup initial control connection.\n");
2334 exit(1);
2335 }
2336 }
2337 else
2338 {
2339 perror("recv");
2340 exit(1);
2341 }
2342 }
2343 else
2344 {
2345 if(connect(sockfd, (struct sockaddr *)&their_addr,
2346 sizeof(struct sockaddr)) == -1)
2347 {
2348 perror("connect");
2349 exit(1);
2350 }
2351 if(!args.data)
2352 {
2353 i = snprintf(buf, MAXDATASIZE,
2354 "GET %s%s%s%s/ HTTP/1.0\r\n"
2355 "Host: %s\r\n%s"
2356 "User-Agent: %s/%s\r\n"
2357 "Connection: close\r\n"
2358 "\r\n"
2359 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
2360 proxyserver ? ":" : "", proxyserver ? proxyport : "",
2361 args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
2362 AGENTSTRING, revisionstr);
2363 }
2364 else
2365 {
2366 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2367 "GET %s%s%s%s/%s HTTP/1.0\r\n"
2368 "Host: %s\r\n%s"
2369 "User-Agent: %s/%s\r\n"
2370 "Connection: close\r\n"
2371 "Authorization: Basic "
2372 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
2373 proxyserver ? ":" : "", proxyserver ? proxyport : "",
2374 args.data, args.server,
2375 args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
2376 AGENTSTRING, revisionstr);
2377 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
2378 {
2379 RTCM3Error("Requested data too long\n");
2380 exit(1);
2381 }
2382 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
2383 if(i > MAXDATASIZE-4)
2384 {
2385 RTCM3Error("Username and/or password too long\n");
2386 exit(1);
2387 }
2388 buf[i++] = '\r';
2389 buf[i++] = '\n';
2390 buf[i++] = '\r';
2391 buf[i++] = '\n';
2392 if(args.nmea)
2393 {
2394 int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
2395 if(j >= 0 && j < MAXDATASIZE-i)
2396 i += j;
2397 else
2398 {
2399 RTCM3Error("NMEA string too long\n");
2400 exit(1);
2401 }
2402 }
2403 }
2404 if(send(sockfd, buf, (size_t)i, 0) != i)
2405 {
2406 perror("send");
2407 exit(1);
2408 }
2409 if(args.data)
2410 {
2411 int k = 0;
2412 int chunkymode = 0;
2413 int starttime = time(0);
2414 int lastout = starttime;
2415 int totalbytes = 0;
2416 int chunksize = 0;
2417
2418 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2419 {
2420 alarm(ALARMTIME);
2421 if(!k)
2422 {
2423 if(numbytes > 17 && (!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17)
2424 || !strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)))
2425 {
2426 const char *datacheck = "Content-Type: gnss/data\r\n";
2427 const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
2428 int l = strlen(datacheck)-1;
2429 int j=0;
2430 for(i = 0; j != l && i < numbytes-l; ++i)
2431 {
2432 for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
2433 ;
2434 }
2435 if(i == numbytes-l)
2436 {
2437 RTCM3Error("No 'Content-Type: gnss/data' found\n");
2438 exit(1);
2439 }
2440 l = strlen(chunkycheck)-1;
2441 j=0;
2442 for(i = 0; j != l && i < numbytes-l; ++i)
2443 {
2444 for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
2445 ;
2446 }
2447 if(i < numbytes-l)
2448 chunkymode = 1;
2449 }
2450 else if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
2451 {
2452 RTCM3Error("Could not get the requested data: ");
2453 for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
2454 {
2455 RTCM3Error("%c", isprint(buf[k]) ? buf[k] : '.');
2456 }
2457 RTCM3Error("\n");
2458 exit(1);
2459 }
2460 else if(args.mode != NTRIP1)
2461 {
2462 if(args.mode != AUTO)
2463 {
2464 RTCM3Error("NTRIP version 2 HTTP connection failed%s.\n",
2465 args.mode == AUTO ? ", falling back to NTRIP1" : "");
2466 }
2467 if(args.mode == HTTP)
2468 exit(1);
2469 }
2470 ++k;
2471 }
2472 else
2473 {
2474 if(chunkymode)
2475 {
2476 int stop = 0;
2477 int pos = 0;
2478 while(!stop && pos < numbytes)
2479 {
2480 switch(chunkymode)
2481 {
2482 case 1: /* reading number starts */
2483 chunksize = 0;
2484 ++chunkymode; /* no break */
2485 case 2: /* during reading number */
2486 i = buf[pos++];
2487 if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
2488 else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
2489 else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
2490 else if(i == '\r') ++chunkymode;
2491 else if(i == ';') chunkymode = 5;
2492 else stop = 1;
2493 break;
2494 case 3: /* scanning for return */
2495 if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
2496 else stop = 1;
2497 break;
2498 case 4: /* output data */
2499 i = numbytes-pos;
2500 if(i > chunksize) i = chunksize;
2501 {
2502 int z;
2503 for(z = 0; z < i && !stop; ++z)
2504 HandleByte(&Parser, (unsigned int) buf[pos+z]);
2505 }
2506 totalbytes += i;
2507 chunksize -= i;
2508 pos += i;
2509 if(!chunksize)
2510 chunkymode = 1;
2511 break;
2512 case 5:
2513 if(i == '\r') chunkymode = 3;
2514 break;
2515 }
2516 }
2517 if(stop)
2518 {
2519 RTCM3Error("Error in chunky transfer encoding\n");
2520 break;
2521 }
2522 }
2523 else
2524 {
2525 totalbytes += numbytes;
2526 {
2527 int z;
2528 for(z = 0; z < numbytes && !stop; ++z)
2529 HandleByte(&Parser, (unsigned int) buf[z]);
2530 }
2531 }
2532 if(totalbytes < 0) /* overflow */
2533 {
2534 totalbytes = 0;
2535 starttime = time(0);
2536 lastout = starttime;
2537 }
2538 }
2539 }
2540 }
2541 else
2542 {
2543 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
2544 {
2545 alarm(ALARMTIME);
2546 fwrite(buf, (size_t)numbytes, 1, stdout);
2547 }
2548 }
2549 close(sockfd);
2550 }
2551 }
2552 return 0;
2553}
2554#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.