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

Last change on this file since 2368 was 2352, checked in by stoecker, 15 years ago

fixed overflow

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