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

Last change on this file since 1348 was 1270, checked in by stoecker, 16 years ago

fixed problem with joined RTCM blocks

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