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

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

fixed dir layout for better SVN integration

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