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

Last change on this file since 1097 was 1097, checked in by stoecker, 16 years ago

Minor fix

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