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

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

some BNC related fixes

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