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

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

fix #5 - support date reading from block 1013

  • Property svn:keywords set to Id Revision Date
File size: 79.3 KB
Line 
1/*
2 Converter for RTCM3 data to RINEX.
3 $Id: rtcm3torinex.c 2501 2010-06-28 13:54:17Z 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: 2501 $";
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->rinex3)
939 {
940#define CHECKFLAGSNEW(a, b, c) \
941 { \
942 Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
943 Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
944 ++Parser->numdatatypes##a; \
945 }
946
947 CHECKFLAGSNEW(GPS, C1, C1C)
948 CHECKFLAGSNEW(GPS, L1C, L1C)
949 CHECKFLAGSNEW(GPS, D1C, D1C)
950 CHECKFLAGSNEW(GPS, S1C, S1C)
951 CHECKFLAGSNEW(GPS, P1, C1P)
952 CHECKFLAGSNEW(GPS, L1P, L1P)
953 CHECKFLAGSNEW(GPS, D1P, D1P)
954 CHECKFLAGSNEW(GPS, S1P, S1P)
955 CHECKFLAGSNEW(GPS, P2, C2P)
956 CHECKFLAGSNEW(GPS, L2P, L2P)
957 CHECKFLAGSNEW(GPS, D2P, D2P)
958 CHECKFLAGSNEW(GPS, S2P, S2P)
959 CHECKFLAGSNEW(GPS, C2, C2X)
960 CHECKFLAGSNEW(GPS, L2C, L2X)
961 CHECKFLAGSNEW(GPS, D2C, D2X)
962 CHECKFLAGSNEW(GPS, S2C, S2X)
963 CHECKFLAGSNEW(GLO, C1, C1C)
964 CHECKFLAGSNEW(GLO, L1C, L1C)
965 CHECKFLAGSNEW(GLO, D1C, D1C)
966 CHECKFLAGSNEW(GLO, S1C, S1C)
967 CHECKFLAGSNEW(GLO, P1, C1P)
968 CHECKFLAGSNEW(GLO, L1P, L1P)
969 CHECKFLAGSNEW(GLO, D1P, D1P)
970 CHECKFLAGSNEW(GLO, S1P, S1P)
971 CHECKFLAGSNEW(GLO, P2, C2P)
972 CHECKFLAGSNEW(GLO, L2P, L2P)
973 CHECKFLAGSNEW(GLO, D2P, D2P)
974 CHECKFLAGSNEW(GLO, S2P, S2P)
975 CHECKFLAGSNEW(GLO, C2, C2C)
976 CHECKFLAGSNEW(GLO, L2C, L2C)
977 CHECKFLAGSNEW(GLO, D2C, D2C)
978 CHECKFLAGSNEW(GLO, S2C, S2C)
979 }
980 else
981 {
982#define CHECKFLAGS(a, b) \
983 { \
984 if(data[RINEXENTRY_##b##DATA]) \
985 { \
986 Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
987 Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
988 } \
989 else \
990 { \
991 Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
992 Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
993 data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
994 } \
995 }
996
997 int data[RINEXENTRY_NUMBER];
998 for(i = 0; i < RINEXENTRY_NUMBER; ++i) data[i] = 0;
999
1000 CHECKFLAGS(C1,C1)
1001 CHECKFLAGS(C2,C2)
1002 CHECKFLAGS(P1,P1)
1003 CHECKFLAGS(P2,P2)
1004 CHECKFLAGS(L1C,L1)
1005 CHECKFLAGS(L1P,L1)
1006 CHECKFLAGS(L2C,L2)
1007 CHECKFLAGS(L2P,L2)
1008 CHECKFLAGS(D1C,D1)
1009 CHECKFLAGS(D1P,D1)
1010 CHECKFLAGS(D2C,D2)
1011 CHECKFLAGS(D2P,D2)
1012 CHECKFLAGS(S1C,S1)
1013 CHECKFLAGS(S1P,S1)
1014 CHECKFLAGS(S2C,S2)
1015 CHECKFLAGS(S2P,S2)
1016 }
1017#else /* NO_RTCM3_MAIN */
1018 struct HeaderData hdata;
1019 char thebuffer[MAXHEADERBUFFERSIZE];
1020 char *buffer = thebuffer;
1021 size_t buffersize = sizeof(thebuffer);
1022 int i;
1023
1024 memset(&hdata, 0, sizeof(hdata));
1025
1026 hdata.data.named.version = buffer;
1027 i = 1+snprintf(buffer, buffersize,
1028 "%9.2f OBSERVATION DATA M (Mixed)"
1029 " RINEX VERSION / TYPE", Parser->rinex3 ? 3.0 : 2.11);
1030 buffer += i; buffersize -= i;
1031
1032 {
1033 const char *str;
1034 hdata.data.named.pgm = buffer;
1035 i = HandleRunBy(buffer, buffersize, &str, Parser->rinex3);
1036 buffer += i; buffersize -= i;
1037 hdata.data.named.observer = buffer;
1038 i = 1+snprintf(buffer, buffersize,
1039 "%-20.20s "
1040 "OBSERVER / AGENCY", str);
1041 buffer += i; buffersize -= i;
1042 }
1043
1044 hdata.data.named.marker =
1045 "RTCM3TORINEX "
1046 "MARKER NAME";
1047
1048 hdata.data.named.markertype = !Parser->rinex3 ? 0 :
1049 "GEODETIC "
1050 "MARKER TYPE";
1051
1052 hdata.data.named.receiver =
1053 " "
1054 "REC # / TYPE / VERS";
1055
1056 hdata.data.named.antenna =
1057 " "
1058 "ANT # / TYPE";
1059
1060 hdata.data.named.position =
1061 " .0000 .0000 .0000 "
1062 "APPROX POSITION XYZ";
1063
1064 hdata.data.named.antennaposition =
1065 " .0000 .0000 .0000 "
1066 "ANTENNA: DELTA H/E/N";
1067
1068 hdata.data.named.wavelength = Parser->rinex3 ? 0 :
1069 " 1 1 "
1070 "WAVELENGTH FACT L1/2";
1071
1072 if(Parser->rinex3)
1073 {
1074#define CHECKFLAGSNEW(a, b, c) \
1075 if(flags & GNSSDF_##b##DATA) \
1076 { \
1077 Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
1078 Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
1079 ++Parser->numdatatypes##a; \
1080 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#c); \
1081 tbufferpos += 4; \
1082 }
1083
1084 int flags = Parser->startflags;
1085 char tbuffer[6*RINEXENTRY_NUMBER+1];
1086 int tbufferpos = 0;
1087 for(i = 0; i < Parser->Data.numsats; ++i)
1088 flags |= Parser->Data.dataflags[i];
1089
1090 CHECKFLAGSNEW(GPS, C1, C1C)
1091 CHECKFLAGSNEW(GPS, L1C, L1C)
1092 CHECKFLAGSNEW(GPS, D1C, D1C)
1093 CHECKFLAGSNEW(GPS, S1C, S1C)
1094 CHECKFLAGSNEW(GPS, P1, C1P)
1095 CHECKFLAGSNEW(GPS, L1P, L1P)
1096 CHECKFLAGSNEW(GPS, D1P, D1P)
1097 CHECKFLAGSNEW(GPS, S1P, S1P)
1098
1099 hdata.data.named.typesofobsS = buffer;
1100 i = 1+snprintf(buffer, buffersize,
1101 "S %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
1102 buffer += i; buffersize -= i;
1103
1104 CHECKFLAGSNEW(GPS, P2, C2P)
1105 CHECKFLAGSNEW(GPS, L2P, L2P)
1106 CHECKFLAGSNEW(GPS, D2P, D2P)
1107 CHECKFLAGSNEW(GPS, S2P, S2P)
1108 CHECKFLAGSNEW(GPS, C2, C2X)
1109 CHECKFLAGSNEW(GPS, L2C, L2X)
1110 CHECKFLAGSNEW(GPS, D2C, D2X)
1111 CHECKFLAGSNEW(GPS, S2C, S2X)
1112
1113 hdata.data.named.typesofobsG = buffer;
1114 i = 1+snprintf(buffer, buffersize,
1115 "G %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
1116 if(Parser->numdatatypesGPS>13)
1117 {
1118 i += snprintf(buffer+i-1, buffersize,
1119 "\n %-52.52s SYS / # / OBS TYPES", tbuffer+13*4);
1120 }
1121 buffer += i; buffersize -= i;
1122
1123 tbufferpos = 0;
1124
1125 CHECKFLAGSNEW(GLO, C1, C1C)
1126 CHECKFLAGSNEW(GLO, L1C, L1C)
1127 CHECKFLAGSNEW(GLO, D1C, D1C)
1128 CHECKFLAGSNEW(GLO, S1C, S1C)
1129 CHECKFLAGSNEW(GLO, P1, C1P)
1130 CHECKFLAGSNEW(GLO, L1P, L1P)
1131 CHECKFLAGSNEW(GLO, D1P, D1P)
1132 CHECKFLAGSNEW(GLO, S1P, S1P)
1133 CHECKFLAGSNEW(GLO, P2, C2P)
1134 CHECKFLAGSNEW(GLO, L2P, L2P)
1135 CHECKFLAGSNEW(GLO, D2P, D2P)
1136 CHECKFLAGSNEW(GLO, S2P, S2P)
1137 CHECKFLAGSNEW(GLO, C2, C2C)
1138 CHECKFLAGSNEW(GLO, L2C, L2C)
1139 CHECKFLAGSNEW(GLO, D2C, D2C)
1140 CHECKFLAGSNEW(GLO, S2C, S2C)
1141
1142 hdata.data.named.typesofobsR = buffer;
1143 i = 1+snprintf(buffer, buffersize,
1144 "R %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGLO, tbuffer);
1145 if(Parser->numdatatypesGLO>13)
1146 {
1147 i += snprintf(buffer+i-1, buffersize,
1148 "\n %-52.52s SYS / # / OBS TYPES", tbuffer+13*4);
1149 }
1150 buffer += i; buffersize -= i;
1151 }
1152 else
1153 {
1154#define CHECKFLAGS(a, b) \
1155 if(flags & GNSSDF_##a##DATA) \
1156 { \
1157 if(data[RINEXENTRY_##b##DATA]) \
1158 { \
1159 Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
1160 Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
1161 } \
1162 else \
1163 { \
1164 Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
1165 Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
1166 data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
1167 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#b); \
1168 tbufferpos += 6; \
1169 } \
1170 }
1171
1172 int flags = Parser->startflags;
1173 int data[RINEXENTRY_NUMBER];
1174 char tbuffer[6*RINEXENTRY_NUMBER+1];
1175 int tbufferpos = 0;
1176 for(i = 0; i < RINEXENTRY_NUMBER; ++i)
1177 data[i] = 0;
1178 for(i = 0; i < Parser->Data.numsats; ++i)
1179 flags |= Parser->Data.dataflags[i];
1180
1181 CHECKFLAGS(C1,C1)
1182 CHECKFLAGS(C2,C2)
1183 CHECKFLAGS(P1,P1)
1184 CHECKFLAGS(P2,P2)
1185 CHECKFLAGS(L1C,L1)
1186 CHECKFLAGS(L1P,L1)
1187 CHECKFLAGS(L2C,L2)
1188 CHECKFLAGS(L2P,L2)
1189 CHECKFLAGS(D1C,D1)
1190 CHECKFLAGS(D1P,D1)
1191 CHECKFLAGS(D2C,D2)
1192 CHECKFLAGS(D2P,D2)
1193 CHECKFLAGS(S1C,S1)
1194 CHECKFLAGS(S1P,S1)
1195 CHECKFLAGS(S2C,S2)
1196 CHECKFLAGS(S2P,S2)
1197
1198 hdata.data.named.typesofobs = buffer;
1199 i = 1+snprintf(buffer, buffersize,
1200 "%6d%-54.54s# / TYPES OF OBSERV", Parser->numdatatypesGPS, tbuffer);
1201 if(Parser->numdatatypesGPS>9)
1202 {
1203 i += snprintf(buffer+i-1, buffersize,
1204 "\n %-54.54s# / TYPES OF OBSERV", tbuffer+9*6);
1205 }
1206 buffer += i; buffersize -= i;
1207 }
1208
1209 {
1210 struct converttimeinfo cti;
1211 converttime(&cti, Parser->Data.week,
1212 (int)floor(Parser->Data.timeofweek/1000.0));
1213 hdata.data.named.timeoffirstobs = buffer;
1214 i = 1+snprintf(buffer, buffersize,
1215 " %4d %2d %2d %2d %2d %10.7f GPS "
1216 "TIME OF FIRST OBS", cti.year, cti.month, cti.day, cti.hour,
1217 cti.minute, cti.second + fmod(Parser->Data.timeofweek/1000.0,1.0));
1218
1219 buffer += i; buffersize -= i;
1220 }
1221
1222 hdata.numheaders = 15;
1223
1224 if(Parser->headerfile)
1225 {
1226 FILE *fh;
1227 if((fh = fopen(Parser->headerfile, "r")))
1228 {
1229 size_t siz;
1230 char *lastblockstart;
1231 if((siz = fread(buffer, 1, buffersize-1, fh)) > 0)
1232 {
1233 buffer[siz] = '\n';
1234 if(siz == buffersize)
1235 {
1236 RTCM3Error("Header file is too large. Only %d bytes read.",
1237 (int)siz);
1238 }
1239 /* scan the file line by line and enter the entries in the list */
1240 /* warn for "# / TYPES OF OBSERV" and "TIME OF FIRST OBS" */
1241 /* overwrites entries, except for comments */
1242 lastblockstart = buffer;
1243 for(i = 0; i < (int)siz; ++i)
1244 {
1245 if(buffer[i] == '\n')
1246 { /* we found a line */
1247 char *end;
1248 while(buffer[i+1] == '\r')
1249 ++i; /* skip \r in case there are any */
1250 end = buffer+i;
1251 while(*end == '\t' || *end == ' ' || *end == '\r' || *end == '\n')
1252 *(end--) = 0;
1253 if(end-lastblockstart < 60+5) /* short line */
1254 RTCM3Error("Short Header line '%s' ignored.\n", lastblockstart);
1255 else
1256 {
1257 int pos;
1258 if(!strcmp("COMMENT", lastblockstart+60))
1259 pos = hdata.numheaders;
1260 else
1261 {
1262 for(pos = 0; pos < hdata.numheaders; ++pos)
1263 {
1264 if(!strcmp(hdata.data.unnamed[pos]+60, lastblockstart+60))
1265 break;
1266 }
1267 if(!strcmp("# / TYPES OF OBSERV", lastblockstart+60)
1268 || !strcmp("TIME OF FIRST OBS", lastblockstart+60))
1269 {
1270 RTCM3Error("Overwriting header '%s' is dangerous.\n",
1271 lastblockstart+60);
1272 }
1273 }
1274 if(pos >= MAXHEADERLINES)
1275 {
1276 RTCM3Error("Maximum number of header lines of %d reached.\n",
1277 MAXHEADERLINES);
1278 }
1279 else if(!strcmp("END OF HEADER", lastblockstart+60))
1280 {
1281 RTCM3Error("End of header ignored.\n");
1282 }
1283 else
1284 {
1285 hdata.data.unnamed[pos] = lastblockstart;
1286 if(pos == hdata.numheaders)
1287 ++hdata.numheaders;
1288 }
1289 }
1290 lastblockstart = buffer+i+1;
1291 }
1292 }
1293 }
1294 else
1295 {
1296 RTCM3Error("Could not read data from headerfile '%s'.\n",
1297 Parser->headerfile);
1298 }
1299 fclose(fh);
1300 }
1301 else
1302 {
1303 RTCM3Error("Could not open header datafile '%s'.\n",
1304 Parser->headerfile);
1305 }
1306 }
1307
1308 for(i = 0; i < hdata.numheaders; ++i)
1309 {
1310 if(hdata.data.unnamed[i] && hdata.data.unnamed[i][0])
1311 RTCM3Text("%s\n", hdata.data.unnamed[i]);
1312 }
1313 RTCM3Text(" "
1314 "END OF HEADER\n");
1315#endif
1316}
1317
1318static void ConvLine(FILE *file, const char *fmt, ...)
1319{
1320 char buffer[100], *b;
1321 va_list v;
1322 va_start(v, fmt);
1323 vsnprintf(buffer, sizeof(buffer), fmt, v);
1324 for(b = buffer; *b; ++b)
1325 {
1326 if(*b == 'e') *b = 'D';
1327 }
1328 fprintf(file, "%s", buffer);
1329 va_end(v);
1330}
1331
1332void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
1333{
1334 Parser->Message[Parser->MessageSize++] = byte;
1335 if(Parser->MessageSize >= Parser->NeedBytes)
1336 {
1337 int r;
1338 while((r = RTCM3Parser(Parser)))
1339 {
1340 if(r == 1020 || r == 1019)
1341 {
1342 FILE *file = 0;
1343
1344 if(Parser->rinex3 && !(file = Parser->gpsfile))
1345 {
1346 const char *n = Parser->gpsephemeris ? Parser->gpsephemeris : Parser->glonassephemeris;
1347 if(n)
1348 {
1349 if(!(Parser->gpsfile = fopen(n, "w")))
1350 {
1351 RTCM3Error("Could not open ephemeris output file.\n");
1352 }
1353 else
1354 {
1355 char buffer[100];
1356 fprintf(Parser->gpsfile,
1357 "%9.2f%11sN: GNSS NAV DATA M: Mixed%12sRINEX VERSION / TYPE\n", 3.0, "", "");
1358 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1359 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1360 }
1361 Parser->gpsephemeris = 0;
1362 Parser->glonassephemeris = 0;
1363 file = Parser->gpsfile;
1364 }
1365 }
1366 else
1367 {
1368 if(r == 1020)
1369 {
1370 if(Parser->glonassephemeris)
1371 {
1372 if(!(Parser->glonassfile = fopen(Parser->glonassephemeris, "w")))
1373 {
1374 RTCM3Error("Could not open GLONASS ephemeris output file.\n");
1375 }
1376 else
1377 {
1378 char buffer[100];
1379 fprintf(Parser->glonassfile,
1380 "%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n", 2.1, "", "");
1381 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1382 fprintf(Parser->glonassfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1383 }
1384 Parser->glonassephemeris = 0;
1385 }
1386 file = Parser->glonassfile;
1387 }
1388 else if(r == 1019)
1389 {
1390 if(Parser->gpsephemeris)
1391 {
1392 if(!(Parser->gpsfile = fopen(Parser->gpsephemeris, "w")))
1393 {
1394 RTCM3Error("Could not open GPS ephemeris output file.\n");
1395 }
1396 else
1397 {
1398 char buffer[100];
1399 fprintf(Parser->gpsfile,
1400 "%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 2.1, "", "");
1401 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1402 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1403 }
1404 Parser->gpsephemeris = 0;
1405 }
1406 file = Parser->gpsfile;
1407 }
1408 }
1409 if(file)
1410 {
1411 if(r == 1020)
1412 {
1413 struct glonassephemeris *e = &Parser->ephemerisGLONASS;
1414 int w = e->GPSWeek, tow = e->GPSTOW, i;
1415 struct converttimeinfo cti;
1416
1417 updatetime(&w, &tow, e->tb*1000, 1); /* Moscow - > UTC */
1418 converttime(&cti, w, tow);
1419
1420 i = e->tk-3*60*60; if(i < 0) i += 86400;
1421
1422 if(Parser->rinex3)
1423 ConvLine(file, "R%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1424 e->almanac_number, cti.year, cti.month, cti.day, cti.hour, cti.minute,
1425 cti.second, -e->tau, e->gamma, (double) i);
1426 else
1427 ConvLine(file, "%02d %02d %02d %02d %02d %02d%5.1f%19.12e%19.12e%19.12e\n",
1428 e->almanac_number, cti.year%100, cti.month, cti.day, cti.hour, cti.minute,
1429 (double) cti.second, -e->tau, e->gamma, (double) i);
1430 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->x_pos,
1431 e->x_velocity, e->x_acceleration, (e->flags & GLOEPHF_UNHEALTHY) ? 1.0 : 0.0);
1432 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->y_pos,
1433 e->y_velocity, e->y_acceleration, (double) e->frequency_number);
1434 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->z_pos,
1435 e->z_velocity, e->z_acceleration, (double) e->E);
1436 }
1437 else /* if(r == 1019) */
1438 {
1439 struct gpsephemeris *e = &Parser->ephemerisGPS;
1440 double d; /* temporary variable */
1441 unsigned long int i; /* temporary variable */
1442 struct converttimeinfo cti;
1443 converttime(&cti, e->GPSweek, e->TOC);
1444
1445 if(Parser->rinex3)
1446 ConvLine(file, "G%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1447 e->satellite, cti.year, cti.month, cti.day, cti.hour,
1448 cti.minute, cti.second, e->clock_bias, e->clock_drift,
1449 e->clock_driftrate);
1450 else
1451 ConvLine(file, "%02d %02d %02d %02d %02d %02d%05.1f%19.12e%19.12e%19.12e\n",
1452 e->satellite, cti.year%100, cti.month, cti.day, cti.hour,
1453 cti.minute, (double) cti.second, e->clock_bias, e->clock_drift,
1454 e->clock_driftrate);
1455 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", (double)e->IODE,
1456 e->Crs, e->Delta_n, e->M0);
1457 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->Cuc,
1458 e->e, e->Cus, e->sqrt_A);
1459 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n",
1460 (double) e->TOE, e->Cic, e->OMEGA0, e->Cis);
1461 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->i0,
1462 e->Crc, e->omega, e->OMEGADOT);
1463 d = 0;
1464 i = e->flags;
1465 if(i & GPSEPHF_L2CACODE)
1466 d += 2.0;
1467 if(i & GPSEPHF_L2PCODE)
1468 d += 1.0;
1469 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->IDOT, d,
1470 (double) e->GPSweek, i & GPSEPHF_L2PCODEDATA ? 1.0 : 0.0);
1471 if(e->URAindex <= 6) /* URA index */
1472 d = ceil(10.0*pow(2.0, 1.0+((double)e->URAindex)/2.0))/10.0;
1473 else
1474 d = ceil(10.0*pow(2.0, ((double)e->URAindex)/2.0))/10.0;
1475 /* 15 indicates not to use satellite. We can't handle this special
1476 case, so we create a high "non"-accuracy value. */
1477 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", d,
1478 ((double) e->SVhealth), e->TGD, ((double) e->IODC));
1479
1480 ConvLine(file, " %19.12e%19.12e\n", ((double)e->TOW), 0.0);
1481 /* TOW */
1482 }
1483 }
1484 }
1485 else
1486 {
1487 int i, j, o;
1488 struct converttimeinfo cti;
1489
1490 if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
1491 {
1492 ++Parser->init;
1493
1494 if(Parser->init == NUMSTARTSKIP)
1495 HandleHeader(Parser);
1496 else
1497 {
1498 for(i = 0; i < Parser->Data.numsats; ++i)
1499 Parser->startflags |= Parser->Data.dataflags[i];
1500 continue;
1501 }
1502 }
1503 if(r == 2 && !Parser->validwarning)
1504 {
1505 RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
1506 " COMMENT\n");
1507 Parser->validwarning = 1;
1508 }
1509
1510 converttime(&cti, Parser->Data.week,
1511 (int)floor(Parser->Data.timeofweek/1000.0));
1512 if(Parser->rinex3)
1513 {
1514 RTCM3Text("> %04d %02d %02d %02d %02d%11.7f 0%3d\n",
1515 cti.year, cti.month, cti.day, cti.hour, cti.minute, cti.second
1516 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1517 for(i = 0; i < Parser->Data.numsats; ++i)
1518 {
1519 int glo = 0;
1520 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1521 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1522 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1523 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1524 {
1525 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1526 glo = 1;
1527 }
1528 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1529 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1530 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1531 else
1532 RTCM3Text("%3d", Parser->Data.satellites[i]);
1533
1534 if(glo)
1535 {
1536 for(j = 0; j < Parser->numdatatypesGLO; ++j)
1537 {
1538 int df = Parser->dataflagGLO[j];
1539 int pos = Parser->dataposGLO[j];
1540 if((Parser->Data.dataflags[i] & df)
1541 && !isnan(Parser->Data.measdata[i][pos])
1542 && !isinf(Parser->Data.measdata[i][pos]))
1543 {
1544 char lli = ' ';
1545 char snr = ' ';
1546 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1547 {
1548 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1549 lli = '1';
1550 snr = '0'+Parser->Data.snrL1[i];
1551 }
1552 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1553 {
1554 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1555 lli = '1';
1556 snr = '0'+Parser->Data.snrL2[i];
1557 }
1558 RTCM3Text("%14.3f%c%c",
1559 Parser->Data.measdata[i][pos],lli,snr);
1560 }
1561 else
1562 { /* no or illegal data */
1563 RTCM3Text(" ");
1564 }
1565 }
1566 }
1567 else
1568 {
1569 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1570 {
1571 int df = Parser->dataflagGPS[j];
1572 int pos = Parser->dataposGPS[j];
1573 if((Parser->Data.dataflags[i] & df)
1574 && !isnan(Parser->Data.measdata[i][pos])
1575 && !isinf(Parser->Data.measdata[i][pos]))
1576 {
1577 char lli = ' ';
1578 char snr = ' ';
1579 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1580 {
1581 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1582 lli = '1';
1583 snr = '0'+Parser->Data.snrL1[i];
1584 }
1585 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1586 {
1587 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1588 lli = '1';
1589 snr = '0'+Parser->Data.snrL2[i];
1590 }
1591 RTCM3Text("%14.3f%c%c",
1592 Parser->Data.measdata[i][pos],lli,snr);
1593 }
1594 else
1595 { /* no or illegal data */
1596 RTCM3Text(" ");
1597 }
1598 }
1599 }
1600 RTCM3Text("\n");
1601 }
1602 }
1603 else
1604 {
1605 RTCM3Text(" %02d %2d %2d %2d %2d %10.7f 0%3d",
1606 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
1607 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1608 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
1609 {
1610 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1611 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1612 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1613 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1614 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1615 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1616 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1617 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1618 else
1619 RTCM3Text("%3d", Parser->Data.satellites[i]);
1620 }
1621 RTCM3Text("\n");
1622 o = 12;
1623 j = Parser->Data.numsats - 12;
1624 while(j > 0)
1625 {
1626 RTCM3Text(" ");
1627 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
1628 {
1629 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1630 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1631 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1632 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1633 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1634 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1635 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1636 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1637 else
1638 RTCM3Text("%3d", Parser->Data.satellites[i]);
1639 }
1640 RTCM3Text("\n");
1641 j -= 12;
1642 o += 12;
1643 }
1644 for(i = 0; i < Parser->Data.numsats; ++i)
1645 {
1646 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1647 {
1648 int v = 0;
1649 int df = Parser->dataflag[j];
1650 int pos = Parser->datapos[j];
1651 if((Parser->Data.dataflags[i] & df)
1652 && !isnan(Parser->Data.measdata[i][pos])
1653 && !isinf(Parser->Data.measdata[i][pos]))
1654 {
1655 v = 1;
1656 }
1657 else
1658 {
1659 df = Parser->dataflagGPS[j];
1660 pos = Parser->dataposGPS[j];
1661
1662 if((Parser->Data.dataflags[i] & df)
1663 && !isnan(Parser->Data.measdata[i][pos])
1664 && !isinf(Parser->Data.measdata[i][pos]))
1665 {
1666 v = 1;
1667 }
1668 }
1669
1670 if(!v)
1671 { /* no or illegal data */
1672 RTCM3Text(" ");
1673 }
1674 else
1675 {
1676 char lli = ' ';
1677 char snr = ' ';
1678 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1679 {
1680 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1681 lli = '1';
1682 snr = '0'+Parser->Data.snrL1[i];
1683 }
1684 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1685 {
1686 if(Parser->Data.dataflags[i] & (GNSSDF_LOCKLOSSL2|GNSSDF_XCORRL2))
1687 {
1688 lli = '0';
1689 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1690 lli += 1;
1691 if(Parser->Data.dataflags[i] & GNSSDF_XCORRL2)
1692 lli += 4;
1693 }
1694 snr = '0'+Parser->Data.snrL2[i];
1695 }
1696 if((df & GNSSDF_P2DATA) && (Parser->Data.dataflags[i] & GNSSDF_XCORRL2))
1697 lli = '4';
1698 RTCM3Text("%14.3f%c%c",
1699 Parser->Data.measdata[i][pos],lli,snr);
1700 }
1701 if(j%5 == 4 || j == Parser->numdatatypesGPS-1)
1702 RTCM3Text("\n");
1703 }
1704 }
1705 }
1706 }
1707 }
1708 }
1709}
1710
1711#ifndef NO_RTCM3_MAIN
1712static char datestr[] = "$Date: 2010-06-28 13:54:17 +0000 (Mon, 28 Jun 2010) $";
1713
1714/* The string, which is send as agent in HTTP request */
1715#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
1716
1717#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
1718
1719static const char encodingTable [64] = {
1720 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1721 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1722 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1723 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1724};
1725
1726/* does not buffer overrun, but breaks directly after an error */
1727/* returns the number of required bytes */
1728static int encode(char *buf, int size, const char *user, const char *pwd)
1729{
1730 unsigned char inbuf[3];
1731 char *out = buf;
1732 int i, sep = 0, fill = 0, bytes = 0;
1733
1734 while(*user || *pwd)
1735 {
1736 i = 0;
1737 while(i < 3 && *user) inbuf[i++] = *(user++);
1738 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1739 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1740 while(i < 3) {inbuf[i++] = 0; ++fill; }
1741 if(out-buf < size-1)
1742 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1743 if(out-buf < size-1)
1744 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1745 | ((inbuf [1] & 0xF0) >> 4)];
1746 if(out-buf < size-1)
1747 {
1748 if(fill == 2)
1749 *(out++) = '=';
1750 else
1751 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1752 | ((inbuf [2] & 0xC0) >> 6)];
1753 }
1754 if(out-buf < size-1)
1755 {
1756 if(fill >= 1)
1757 *(out++) = '=';
1758 else
1759 *(out++) = encodingTable[inbuf [2] & 0x3F];
1760 }
1761 bytes += 4;
1762 }
1763 if(out-buf < size)
1764 *out = 0;
1765 return bytes;
1766}
1767
1768static int stop = 0;
1769
1770struct Args
1771{
1772 const char *server;
1773 const char *port;
1774 int mode;
1775 int timeout;
1776 int rinex3;
1777 const char *user;
1778 const char *password;
1779 const char *proxyhost;
1780 const char *proxyport;
1781 const char *nmea;
1782 const char *data;
1783 const char *headerfile;
1784 const char *gpsephemeris;
1785 const char *glonassephemeris;
1786};
1787
1788/* option parsing */
1789#ifdef NO_LONG_OPTS
1790#define LONG_OPT(a)
1791#else
1792#define LONG_OPT(a) a
1793static struct option opts[] = {
1794{ "data", required_argument, 0, 'd'},
1795{ "server", required_argument, 0, 's'},
1796{ "password", required_argument, 0, 'p'},
1797{ "port", required_argument, 0, 'r'},
1798{ "timeout", required_argument, 0, 't'},
1799{ "header", required_argument, 0, 'f'},
1800{ "user", required_argument, 0, 'u'},
1801{ "gpsephemeris", required_argument, 0, 'E'},
1802{ "glonassephemeris", required_argument, 0, 'G'},
1803{ "rinex3", no_argument, 0, '3'},
1804{ "proxyport", required_argument, 0, 'R'},
1805{ "proxyhost", required_argument, 0, 'S'},
1806{ "nmea", required_argument, 0, 'n'},
1807{ "mode", required_argument, 0, 'M'},
1808{ "help", no_argument, 0, 'h'},
1809{0,0,0,0}};
1810#endif
1811#define ARGOPT "-d:s:p:r:t:f:u:E:G:M:S:R:n:h3"
1812
1813enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };
1814
1815static const char *geturl(const char *url, struct Args *args)
1816{
1817 static char buf[1000];
1818 static char *Buffer = buf;
1819 static char *Bufend = buf+sizeof(buf);
1820
1821 if(strncmp("ntrip:", url, 6))
1822 return "URL must start with 'ntrip:'.";
1823 url += 6; /* skip ntrip: */
1824
1825 if(*url != '@' && *url != '/')
1826 {
1827 /* scan for mountpoint */
1828 args->data = Buffer;
1829 while(*url && *url != '@' && *url != ';' &&*url != '/' && Buffer != Bufend)
1830 *(Buffer++) = *(url++);
1831 if(Buffer == args->data)
1832 return "Mountpoint required.";
1833 else if(Buffer >= Bufend-1)
1834 return "Parsing buffer too short.";
1835 *(Buffer++) = 0;
1836 }
1837
1838 if(*url == '/') /* username and password */
1839 {
1840 ++url;
1841 args->user = Buffer;
1842 while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
1843 *(Buffer++) = *(url++);
1844 if(Buffer == args->user)
1845 return "Username cannot be empty.";
1846 else if(Buffer >= Bufend-1)
1847 return "Parsing buffer too short.";
1848 *(Buffer++) = 0;
1849
1850 if(*url == ':') ++url;
1851
1852 args->password = Buffer;
1853 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1854 *(Buffer++) = *(url++);
1855 if(Buffer == args->password)
1856 return "Password cannot be empty.";
1857 else if(Buffer >= Bufend-1)
1858 return "Parsing buffer too short.";
1859 *(Buffer++) = 0;
1860 }
1861
1862 if(*url == '@') /* server */
1863 {
1864 ++url;
1865 if(*url != '@' && *url != ':')
1866 {
1867 args->server = Buffer;
1868 while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
1869 *(Buffer++) = *(url++);
1870 if(Buffer == args->server)
1871 return "Servername cannot be empty.";
1872 else if(Buffer >= Bufend-1)
1873 return "Parsing buffer too short.";
1874 *(Buffer++) = 0;
1875 }
1876
1877 if(*url == ':')
1878 {
1879 ++url;
1880 args->port = Buffer;
1881 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1882 *(Buffer++) = *(url++);
1883 if(Buffer == args->port)
1884 return "Port cannot be empty.";
1885 else if(Buffer >= Bufend-1)
1886 return "Parsing buffer too short.";
1887 *(Buffer++) = 0;
1888 }
1889
1890 if(*url == '@') /* proxy */
1891 {
1892 ++url;
1893 args->proxyhost = Buffer;
1894 while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
1895 *(Buffer++) = *(url++);
1896 if(Buffer == args->proxyhost)
1897 return "Proxy servername cannot be empty.";
1898 else if(Buffer >= Bufend-1)
1899 return "Parsing buffer too short.";
1900 *(Buffer++) = 0;
1901
1902 if(*url == ':')
1903 {
1904 ++url;
1905 args->proxyport = Buffer;
1906 while(*url && *url != ';' && Buffer != Bufend)
1907 *(Buffer++) = *(url++);
1908 if(Buffer == args->proxyport)
1909 return "Proxy port cannot be empty.";
1910 else if(Buffer >= Bufend-1)
1911 return "Parsing buffer too short.";
1912 *(Buffer++) = 0;
1913 }
1914 }
1915 }
1916 if(*url == ';') /* NMEA */
1917 {
1918 args->nmea = ++url;
1919 while(*url)
1920 ++url;
1921 }
1922
1923 return *url ? "Garbage at end of server string." : 0;
1924}
1925
1926static int getargs(int argc, char **argv, struct Args *args)
1927{
1928 int res = 1;
1929 int getoptr;
1930 int help = 0;
1931 char *t;
1932
1933 args->server = "www.euref-ip.net";
1934 args->port = "2101";
1935 args->timeout = 60;
1936 args->user = "";
1937 args->password = "";
1938 args->data = 0;
1939 args->headerfile = 0;
1940 args->gpsephemeris = 0;
1941 args->glonassephemeris = 0;
1942 args->rinex3 = 0;
1943 args->nmea = 0;
1944 args->proxyhost = 0;
1945 args->proxyport = "2101";
1946 args->mode = AUTO;
1947 help = 0;
1948
1949 do
1950 {
1951
1952#ifdef NO_LONG_OPTS
1953 switch((getoptr = getopt(argc, argv, ARGOPT)))
1954#else
1955 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
1956#endif
1957 {
1958 case 's': args->server = optarg; break;
1959 case 'u': args->user = optarg; break;
1960 case 'p': args->password = optarg; break;
1961 case 'd': args->data = optarg; break;
1962 case 'f': args->headerfile = optarg; break;
1963 case 'E': args->gpsephemeris = optarg; break;
1964 case 'G': args->glonassephemeris = optarg; break;
1965 case 'r': args->port = optarg; break;
1966 case '3': args->rinex3 = 1; break;
1967 case 'S': args->proxyhost = optarg; break;
1968 case 'n': args->nmea = optarg; break;
1969 case 'R': args->proxyport = optarg; break;
1970 case 'h': help=1; break;
1971 case 'M':
1972 args->mode = 0;
1973 if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
1974 args->mode = NTRIP1;
1975 else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
1976 args->mode = HTTP;
1977 else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
1978 args->mode = RTSP;
1979 else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
1980 args->mode = AUTO;
1981 else args->mode = atoi(optarg);
1982 if((args->mode == 0) || (args->mode >= END))
1983 {
1984 fprintf(stderr, "Mode %s unknown\n", optarg);
1985 res = 0;
1986 }
1987 break;
1988 case 't':
1989 args->timeout = strtoul(optarg, &t, 10);
1990 if((t && *t) || args->timeout < 0)
1991 res = 0;
1992 break;
1993
1994 case 1:
1995 {
1996 const char *err;
1997 if((err = geturl(optarg, args)))
1998 {
1999 RTCM3Error("%s\n\n", err);
2000 res = 0;
2001 }
2002 }
2003 break;
2004 case -1: break;
2005 }
2006 } while(getoptr != -1 || !res);
2007
2008 datestr[0] = datestr[7];
2009 datestr[1] = datestr[8];
2010 datestr[2] = datestr[9];
2011 datestr[3] = datestr[10];
2012 datestr[5] = datestr[12];
2013 datestr[6] = datestr[13];
2014 datestr[8] = datestr[15];
2015 datestr[9] = datestr[16];
2016 datestr[4] = datestr[7] = '-';
2017 datestr[10] = 0;
2018
2019 if(args->gpsephemeris && args->glonassephemeris && args->rinex3)
2020 {
2021 RTCM3Error("RINEX3 produces a combined ephemeris file, but 2 files were specified.\n"
2022 "Please specify only one navigation file.\n");
2023 res = 0;
2024 }
2025 else if(!res || help)
2026 {
2027 RTCM3Error("Version %s (%s) GPL" COMPILEDATE
2028 "\nUsage: %s -s server -u user ...\n"
2029 " -d " LONG_OPT("--data ") "the requested data set\n"
2030 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
2031 " -s " LONG_OPT("--server ") "the server name or address\n"
2032 " -p " LONG_OPT("--password ") "the login password\n"
2033 " -r " LONG_OPT("--port ") "the server port number (default 2101)\n"
2034 " -t " LONG_OPT("--timeout ") "timeout in seconds (default 60)\n"
2035 " -u " LONG_OPT("--user ") "the user name\n"
2036 " -E " LONG_OPT("--gpsephemeris ") "output file for GPS ephemeris data\n"
2037 " -G " LONG_OPT("--glonassephemeris ") "output file for GLONASS ephemeris data\n"
2038 " -3 " LONG_OPT("--rinex3 ") "output RINEX type 3 data\n"
2039 " -S " LONG_OPT("--proxyhost ") "proxy name or address\n"
2040 " -R " LONG_OPT("--proxyport ") "proxy port, optional (default 2101)\n"
2041 " -n " LONG_OPT("--nmea ") "NMEA string for sending to server\n"
2042 " -M " LONG_OPT("--mode ") "mode for data request\n"
2043 " Valid modes are:\n"
2044 " 1, h, http NTRIP Version 2.0 Caster in TCP/IP mode\n"
2045 " 2, r, rtsp NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
2046 " 3, n, ntrip1 NTRIP Version 1.0 Caster\n"
2047 " 4, a, auto automatic detection (default)\n"
2048 "or using an URL:\n%s ntrip:data[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
2049 , revisionstr, datestr, argv[0], argv[0]);
2050 exit(1);
2051 }
2052 return res;
2053}
2054
2055/* let the output complete a block if necessary */
2056static void signalhandler(int sig)
2057{
2058 if(!stop)
2059 {
2060 RTCM3Error("Stop signal number %d received. "
2061 "Trying to terminate gentle.\n", sig);
2062 stop = 1;
2063 alarm(1);
2064 }
2065}
2066
2067#ifndef WINDOWSVERSION
2068static void WaitMicro(int mic)
2069{
2070 struct timeval tv;
2071 tv.tv_sec = mic/1000000;
2072 tv.tv_usec = mic%1000000;
2073#ifdef DEBUG
2074 fprintf(stderr, "Waiting %d micro seconds\n", mic);
2075#endif
2076 select(0, 0, 0, 0, &tv);
2077}
2078#else /* WINDOWSVERSION */
2079void WaitMicro(int mic)
2080{
2081 Sleep(mic/1000);
2082}
2083#endif /* WINDOWSVERSION */
2084
2085#define ALARMTIME (2*60)
2086
2087/* for some reason we had to abort hard (maybe waiting for data */
2088#ifdef __GNUC__
2089static __attribute__ ((noreturn)) void signalhandler_alarm(
2090int sig __attribute__((__unused__)))
2091#else /* __GNUC__ */
2092static void signalhandler_alarm(int sig)
2093#endif /* __GNUC__ */
2094{
2095 RTCM3Error("Programm forcefully terminated.\n");
2096 exit(1);
2097}
2098
2099int main(int argc, char **argv)
2100{
2101 struct Args args;
2102 struct RTCM3ParserData Parser;
2103
2104 setbuf(stdout, 0);
2105 setbuf(stdin, 0);
2106 setbuf(stderr, 0);
2107
2108 fixrevision();
2109
2110 signal(SIGINT, signalhandler);
2111 signal(SIGALRM,signalhandler_alarm);
2112 signal(SIGQUIT,signalhandler);
2113 signal(SIGTERM,signalhandler);
2114 signal(SIGPIPE,signalhandler);
2115 memset(&Parser, 0, sizeof(Parser));
2116 {
2117 time_t tim;
2118 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
2119 Parser.GPSWeek = tim/(7*24*60*60);
2120 Parser.GPSTOW = tim%(7*24*60*60);
2121 }
2122
2123 if(getargs(argc, argv, &args))
2124 {
2125 int sockfd, numbytes;
2126 char buf[MAXDATASIZE];
2127 struct sockaddr_in their_addr; /* connector's address information */
2128 struct hostent *he;
2129 struct servent *se;
2130 const char *server, *port, *proxyserver = 0;
2131 char proxyport[6];
2132 char *b;
2133 long i;
2134 struct timeval tv;
2135
2136 alarm(ALARMTIME);
2137
2138 Parser.headerfile = args.headerfile;
2139 Parser.glonassephemeris = args.glonassephemeris;
2140 Parser.gpsephemeris = args.gpsephemeris;
2141 Parser.rinex3 = args.rinex3;
2142
2143 if(args.proxyhost)
2144 {
2145 int p;
2146 if((i = strtol(args.port, &b, 10)) && (!b || !*b))
2147 p = i;
2148 else if(!(se = getservbyname(args.port, 0)))
2149 {
2150 RTCM3Error("Can't resolve port %s.", args.port);
2151 exit(1);
2152 }
2153 else
2154 {
2155 p = ntohs(se->s_port);
2156 }
2157 snprintf(proxyport, sizeof(proxyport), "%d", p);
2158 port = args.proxyport;
2159 proxyserver = args.server;
2160 server = args.proxyhost;
2161 }
2162 else
2163 {
2164 server = args.server;
2165 port = args.port;
2166 }
2167
2168 memset(&their_addr, 0, sizeof(struct sockaddr_in));
2169 if((i = strtol(port, &b, 10)) && (!b || !*b))
2170 their_addr.sin_port = htons(i);
2171 else if(!(se = getservbyname(port, 0)))
2172 {
2173 RTCM3Error("Can't resolve port %s.", port);
2174 exit(1);
2175 }
2176 else
2177 {
2178 their_addr.sin_port = se->s_port;
2179 }
2180 if(!(he=gethostbyname(server)))
2181 {
2182 RTCM3Error("Server name lookup failed for '%s'.\n", server);
2183 exit(1);
2184 }
2185 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
2186 {
2187 perror("socket");
2188 exit(1);
2189 }
2190
2191 tv.tv_sec = args.timeout;
2192 tv.tv_usec = 0;
2193 if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval) ) == -1)
2194 {
2195 RTCM3Error("Function setsockopt: %s\n", strerror(errno));
2196 exit(1);
2197 }
2198
2199 their_addr.sin_family = AF_INET;
2200 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2201
2202 if(args.data && args.mode == RTSP)
2203 {
2204 struct sockaddr_in local;
2205 int sockudp, localport;
2206 int cseq = 1;
2207 socklen_t len;
2208
2209 if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
2210 {
2211 perror("socket");
2212 exit(1);
2213 }
2214 /* fill structure with local address information for UDP */
2215 memset(&local, 0, sizeof(local));
2216 local.sin_family = AF_INET;
2217 local.sin_port = htons(0);
2218 local.sin_addr.s_addr = htonl(INADDR_ANY);
2219 len = sizeof(local);
2220 /* bind() in order to get a random RTP client_port */
2221 if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
2222 {
2223 perror("bind");
2224 exit(1);
2225 }
2226 if((getsockname(sockudp, (struct sockaddr*)&local, &len)) != -1)
2227 {
2228 localport = ntohs(local.sin_port);
2229 }
2230 else
2231 {
2232 perror("local access failed");
2233 exit(1);
2234 }
2235 if(connect(sockfd, (struct sockaddr *)&their_addr,
2236 sizeof(struct sockaddr)) == -1)
2237 {
2238 perror("connect");
2239 exit(1);
2240 }
2241 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2242 "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"
2243 "CSeq: %d\r\n"
2244 "Ntrip-Version: Ntrip/2.0\r\n"
2245 "Ntrip-Component: Ntripclient\r\n"
2246 "User-Agent: %s/%s\r\n"
2247 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
2248 "Authorization: Basic ",
2249 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2250 args.data, cseq++, AGENTSTRING, revisionstr, localport);
2251 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
2252 {
2253 RTCM3Error("Requested data too long\n");
2254 exit(1);
2255 }
2256 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
2257 if(i > MAXDATASIZE-4)
2258 {
2259 RTCM3Error("Username and/or password too long\n");
2260 exit(1);
2261 }
2262 buf[i++] = '\r';
2263 buf[i++] = '\n';
2264 buf[i++] = '\r';
2265 buf[i++] = '\n';
2266 if(args.nmea)
2267 {
2268 int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
2269 if(j >= 0 && j < MAXDATASIZE-i)
2270 i += j;
2271 else
2272 {
2273 RTCM3Error("NMEA string too long\n");
2274 exit(1);
2275 }
2276 }
2277 if(send(sockfd, buf, (size_t)i, 0) != i)
2278 {
2279 perror("send");
2280 exit(1);
2281 }
2282 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2283 {
2284 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2285 {
2286 int serverport = 0, session = 0;
2287 const char *portcheck = "server_port=";
2288 const char *sessioncheck = "session: ";
2289 int l = strlen(portcheck)-1;
2290 int j=0;
2291 for(i = 0; j != l && i < numbytes-l; ++i)
2292 {
2293 for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
2294 ;
2295 }
2296 if(i == numbytes-l)
2297 {
2298 RTCM3Error("No server port number found\n");
2299 exit(1);
2300 }
2301 else
2302 {
2303 i+=l;
2304 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2305 serverport = serverport * 10 + buf[i++]-'0';
2306 if(buf[i] != '\r' && buf[i] != ';')
2307 {
2308 RTCM3Error("Could not extract server port\n");
2309 exit(1);
2310 }
2311 }
2312 l = strlen(sessioncheck)-1;
2313 j=0;
2314 for(i = 0; j != l && i < numbytes-l; ++i)
2315 {
2316 for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
2317 ;
2318 }
2319 if(i == numbytes-l)
2320 {
2321 RTCM3Error("No session number found\n");
2322 exit(1);
2323 }
2324 else
2325 {
2326 i+=l;
2327 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2328 session = session * 10 + buf[i++]-'0';
2329 if(buf[i] != '\r')
2330 {
2331 RTCM3Error("Could not extract session number\n");
2332 exit(1);
2333 }
2334 }
2335
2336 i = snprintf(buf, MAXDATASIZE,
2337 "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"
2338 "CSeq: %d\r\n"
2339 "Session: %d\r\n"
2340 "\r\n",
2341 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2342 args.data, cseq++, session);
2343
2344 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2345 {
2346 RTCM3Error("Requested data too long\n");
2347 exit(1);
2348 }
2349 if(send(sockfd, buf, (size_t)i, 0) != i)
2350 {
2351 perror("send");
2352 exit(1);
2353 }
2354 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2355 {
2356 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2357 {
2358 struct sockaddr_in addrRTP;
2359 /* fill structure with caster address information for UDP */
2360 memset(&addrRTP, 0, sizeof(addrRTP));
2361 addrRTP.sin_family = AF_INET;
2362 addrRTP.sin_port = htons(serverport);
2363 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2364 len = sizeof(addrRTP);
2365 int ts = 0;
2366 int sn = 0;
2367 int ssrc = 0;
2368 int init = 0;
2369 int u, v, w;
2370 while(!stop && (i = recvfrom(sockudp, buf, 1526, 0,
2371 (struct sockaddr*) &addrRTP, &len)) > 0)
2372 {
2373 alarm(ALARMTIME);
2374 if(i >= 12+1 && (unsigned char)buf[0] == (2 << 6) && buf[1] == 0x60)
2375 {
2376 u= ((unsigned char)buf[2]<<8)+(unsigned char)buf[3];
2377 v = ((unsigned char)buf[4]<<24)+((unsigned char)buf[5]<<16)
2378 +((unsigned char)buf[6]<<8)+(unsigned char)buf[7];
2379 w = ((unsigned char)buf[8]<<24)+((unsigned char)buf[9]<<16)
2380 +((unsigned char)buf[10]<<8)+(unsigned char)buf[11];
2381
2382 if(init)
2383 {
2384 int z;
2385 if(u < -30000 && sn > 30000) sn -= 0xFFFF;
2386 if(ssrc != w || ts > v)
2387 {
2388 RTCM3Error("Illegal UDP data received.\n");
2389 exit(1);
2390 }
2391 if(u > sn) /* don't show out-of-order packets */
2392 for(z = 12; z < i && !stop; ++z)
2393 HandleByte(&Parser, (unsigned int) buf[z]);
2394 }
2395 sn = u; ts = v; ssrc = w; init = 1;
2396 }
2397 else
2398 {
2399 RTCM3Error("Illegal UDP header.\n");
2400 exit(1);
2401 }
2402 }
2403 }
2404 i = snprintf(buf, MAXDATASIZE,
2405 "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"
2406 "CSeq: %d\r\n"
2407 "Session: %d\r\n"
2408 "\r\n",
2409 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2410 args.data, cseq++, session);
2411
2412 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2413 {
2414 RTCM3Error("Requested data too long\n");
2415 exit(1);
2416 }
2417 if(send(sockfd, buf, (size_t)i, 0) != i)
2418 {
2419 perror("send");
2420 exit(1);
2421 }
2422 }
2423 else
2424 {
2425 RTCM3Error("Could not start data stream.\n");
2426 exit(1);
2427 }
2428 }
2429 else
2430 {
2431 RTCM3Error("Could not setup initial control connection.\n");
2432 exit(1);
2433 }
2434 }
2435 else
2436 {
2437 perror("recv");
2438 exit(1);
2439 }
2440 }
2441 else
2442 {
2443 if(connect(sockfd, (struct sockaddr *)&their_addr,
2444 sizeof(struct sockaddr)) == -1)
2445 {
2446 perror("connect");
2447 exit(1);
2448 }
2449 if(!args.data)
2450 {
2451 i = snprintf(buf, MAXDATASIZE,
2452 "GET %s%s%s%s/ HTTP/1.0\r\n"
2453 "Host: %s\r\n%s"
2454 "User-Agent: %s/%s\r\n"
2455 "Connection: close\r\n"
2456 "\r\n"
2457 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
2458 proxyserver ? ":" : "", proxyserver ? proxyport : "",
2459 args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
2460 AGENTSTRING, revisionstr);
2461 }
2462 else
2463 {
2464 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2465 "GET %s%s%s%s/%s HTTP/1.0\r\n"
2466 "Host: %s\r\n%s"
2467 "User-Agent: %s/%s\r\n"
2468 "Connection: close\r\n"
2469 "Authorization: Basic "
2470 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
2471 proxyserver ? ":" : "", proxyserver ? proxyport : "",
2472 args.data, args.server,
2473 args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
2474 AGENTSTRING, revisionstr);
2475 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
2476 {
2477 RTCM3Error("Requested data too long\n");
2478 exit(1);
2479 }
2480 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
2481 if(i > MAXDATASIZE-4)
2482 {
2483 RTCM3Error("Username and/or password too long\n");
2484 exit(1);
2485 }
2486 buf[i++] = '\r';
2487 buf[i++] = '\n';
2488 buf[i++] = '\r';
2489 buf[i++] = '\n';
2490 if(args.nmea)
2491 {
2492 int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
2493 if(j >= 0 && j < MAXDATASIZE-i)
2494 i += j;
2495 else
2496 {
2497 RTCM3Error("NMEA string too long\n");
2498 exit(1);
2499 }
2500 }
2501 }
2502 if(send(sockfd, buf, (size_t)i, 0) != i)
2503 {
2504 perror("send");
2505 exit(1);
2506 }
2507 if(args.data)
2508 {
2509 int k = 0;
2510 int chunkymode = 0;
2511 int starttime = time(0);
2512 int lastout = starttime;
2513 int totalbytes = 0;
2514 int chunksize = 0;
2515
2516 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2517 {
2518 if(numbytes > 0)
2519 alarm(ALARMTIME);
2520 else
2521 {
2522 WaitMicro(100);
2523 continue;
2524 }
2525 if(!k)
2526 {
2527 if(numbytes > 17 && (!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17)
2528 || !strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)))
2529 {
2530 const char *datacheck = "Content-Type: gnss/data\r\n";
2531 const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
2532 int l = strlen(datacheck)-1;
2533 int j=0;
2534 for(i = 0; j != l && i < numbytes-l; ++i)
2535 {
2536 for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
2537 ;
2538 }
2539 if(i == numbytes-l)
2540 {
2541 RTCM3Error("No 'Content-Type: gnss/data' found\n");
2542 exit(1);
2543 }
2544 l = strlen(chunkycheck)-1;
2545 j=0;
2546 for(i = 0; j != l && i < numbytes-l; ++i)
2547 {
2548 for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
2549 ;
2550 }
2551 if(i < numbytes-l)
2552 chunkymode = 1;
2553 }
2554 else if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
2555 {
2556 RTCM3Error("Could not get the requested data: ");
2557 for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
2558 {
2559 RTCM3Error("%c", isprint(buf[k]) ? buf[k] : '.');
2560 }
2561 RTCM3Error("\n");
2562 exit(1);
2563 }
2564 else if(args.mode != NTRIP1)
2565 {
2566 if(args.mode != AUTO)
2567 {
2568 RTCM3Error("NTRIP version 2 HTTP connection failed%s.\n",
2569 args.mode == AUTO ? ", falling back to NTRIP1" : "");
2570 }
2571 if(args.mode == HTTP)
2572 exit(1);
2573 }
2574 ++k;
2575 }
2576 else
2577 {
2578 if(chunkymode)
2579 {
2580 int stop = 0;
2581 int pos = 0;
2582 while(!stop && pos < numbytes)
2583 {
2584 switch(chunkymode)
2585 {
2586 case 1: /* reading number starts */
2587 chunksize = 0;
2588 ++chunkymode; /* no break */
2589 case 2: /* during reading number */
2590 i = buf[pos++];
2591 if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
2592 else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
2593 else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
2594 else if(i == '\r') ++chunkymode;
2595 else if(i == ';') chunkymode = 5;
2596 else stop = 1;
2597 break;
2598 case 3: /* scanning for return */
2599 if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
2600 else stop = 1;
2601 break;
2602 case 4: /* output data */
2603 i = numbytes-pos;
2604 if(i > chunksize) i = chunksize;
2605 {
2606 int z;
2607 for(z = 0; z < i && !stop; ++z)
2608 HandleByte(&Parser, (unsigned int) buf[pos+z]);
2609 }
2610 totalbytes += i;
2611 chunksize -= i;
2612 pos += i;
2613 if(!chunksize)
2614 chunkymode = 1;
2615 break;
2616 case 5:
2617 if(i == '\r') chunkymode = 3;
2618 break;
2619 }
2620 }
2621 if(stop)
2622 {
2623 RTCM3Error("Error in chunky transfer encoding\n");
2624 break;
2625 }
2626 }
2627 else
2628 {
2629 totalbytes += numbytes;
2630 {
2631 int z;
2632 for(z = 0; z < numbytes && !stop; ++z)
2633 HandleByte(&Parser, (unsigned int) buf[z]);
2634 }
2635 }
2636 if(totalbytes < 0) /* overflow */
2637 {
2638 totalbytes = 0;
2639 starttime = time(0);
2640 lastout = starttime;
2641 }
2642 }
2643 }
2644 }
2645 else
2646 {
2647 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
2648 {
2649 alarm(ALARMTIME);
2650 fwrite(buf, (size_t)numbytes, 1, stdout);
2651 }
2652 }
2653 close(sockfd);
2654 }
2655 }
2656 return 0;
2657}
2658#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.