source: ntrip/trunk/rtcm3torinex/lib/rtcm3torinex.c@ 2502

Last change on this file since 2502 was 2502, checked in by stoecker, 14 years ago

fix #4 - patch by johansen - allow external specification of data types

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