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

Last change on this file since 1070 was 959, checked in by stoecker, 16 years ago

added leap second

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