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

Last change on this file since 502 was 502, checked in by stoecker, 17 years ago

update to RINEX3 and epohemeris support

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