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

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

* empty log message *

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