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

Last change on this file since 1210 was 1210, checked in by weber, 15 years ago

* empty log message *

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