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

Last change on this file since 1747 was 1305, checked in by mervart, 16 years ago

* empty log message *

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