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

Last change on this file since 1184 was 1184, checked in by weber, 15 years ago

* empty log message *

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