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

Last change on this file since 506 was 506, checked in by mervart, 17 years ago

* empty log message *

File size: 73.9 KB
Line 
1/*
2 Converter for RTCM3 data to RINEX.
3 $Id: rtcm3torinex.c,v 1.2 2007/10/14 14:59:27 mervart 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.2 $";
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 *markertype;
744 const char *observer;
745 const char *receiver;
746 const char *antenna;
747 const char *position;
748 const char *antennaposition;
749 const char *wavelength;
750 const char *typesofobs; /* should not be modified outside */
751 const char *typesofobsG; /* should not be modified outside */
752 const char *typesofobsR; /* should not be modified outside */
753 const char *typesofobsS; /* should not be modified outside */
754 const char *timeoffirstobs; /* should not be modified outside */
755};
756
757#define MAXHEADERLINES 50
758#define MAXHEADERBUFFERSIZE 4096
759struct HeaderData
760{
761 union
762 {
763 struct Header named;
764 const char *unnamed[MAXHEADERLINES];
765 } data;
766 int numheaders;
767};
768
769struct converttimeinfo {
770 int second; /* seconds of GPS time [0..59] */
771 int minute; /* minutes of GPS time [0..59] */
772 int hour; /* hour of GPS time [0..24] */
773 int day; /* day of GPS time [1..28..30(31)*/
774 int month; /* month of GPS time [1..12]*/
775 int year; /* year of GPS time [1980..] */
776};
777
778static void converttime(struct converttimeinfo *c, int week, int tow)
779{
780 int i, k, doy, j; /* temporary variables */
781 j = week*(7*24*60*60) + tow + 5*24*60*60;
782 for(i = 1980; j >= (k = (365+longyear(i,0))*24*60*60); ++i)
783 j -= k;
784 c->year = i;
785 doy = 1+ (j / (24*60*60));
786 j %= (24*60*60);
787 c->hour = j / (60*60);
788 j %= (60*60);
789 c->minute = j / 60;
790 c->second = j % 60;
791 j = 0;
792 for(i = 1; j + (k = months[i] + longyear(c->year,i)) < doy; ++i)
793 j += k;
794 c->month = i;
795 c->day = doy - j;
796}
797
798#ifndef NO_RTCM3_MAIN
799void RTCM3Error(const char *fmt, ...)
800{
801 va_list v;
802 va_start(v, fmt);
803 vfprintf(stderr, fmt, v);
804 va_end(v);
805}
806#endif
807
808#ifndef NO_RTCM3_MAIN
809void RTCM3Text(const char *fmt, ...)
810{
811 va_list v;
812 va_start(v, fmt);
813 vprintf(fmt, v);
814 va_end(v);
815}
816#endif
817
818static int HandleRunBy(char *buffer, int buffersize, const char **u,
819int rinex3)
820{
821 const char *user;
822 time_t t;
823 struct tm * t2;
824
825#ifdef NO_RTCM3_MAIN
826 if(revisionstr[0] == '$')
827 {
828 char *a;
829 int i=0;
830 for(a = revisionstr+11; *a && *a != ' '; ++a)
831 revisionstr[i++] = *a;
832 revisionstr[i] = 0;
833 }
834#endif
835
836 user= getenv("USER");
837 if(!user) user = "";
838 t = time(&t);
839 t2 = gmtime(&t);
840 if(u) *u = user;
841 return 1+snprintf(buffer, buffersize,
842 rinex3 ?
843 "RTCM3TORINEX %-7.7s%-20.20s%04d%02d%02d %02d%02d%02d UTC "
844 "PGM / RUN BY / DATE" :
845 "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d "
846 "PGM / RUN BY / DATE", revisionstr, user, 1900+t2->tm_year,
847 t2->tm_mon+1, t2->tm_mday, t2->tm_hour, t2->tm_min, t2->tm_sec);
848}
849
850#define NUMSTARTSKIP 3
851void HandleHeader(struct RTCM3ParserData *Parser)
852{
853 struct HeaderData hdata;
854 char thebuffer[MAXHEADERBUFFERSIZE];
855 char *buffer = thebuffer;
856 size_t buffersize = sizeof(thebuffer);
857 int i;
858
859 hdata.data.named.version = buffer;
860 i = 1+snprintf(buffer, buffersize,
861 "%9.2f OBSERVATION DATA M (Mixed)"
862 " RINEX VERSION / TYPE", Parser->rinex3 ? 3.0 : 2.11);
863 buffer += i; buffersize -= i;
864
865 {
866 const char *str;
867 hdata.data.named.pgm = buffer;
868 i = HandleRunBy(buffer, buffersize, &str, Parser->rinex3);
869 buffer += i; buffersize -= i;
870 hdata.data.named.observer = buffer;
871 i = 1+snprintf(buffer, buffersize,
872 "%-20.20s "
873 "OBSERVER / AGENCY", str);
874 buffer += i; buffersize -= i;
875 }
876
877 hdata.data.named.marker =
878 "RTCM3TORINEX "
879 "MARKER NAME";
880
881 hdata.data.named.markertype = !Parser->rinex3 ? 0 :
882 "GEODETIC "
883 "MARKER TYPE";
884
885 hdata.data.named.receiver =
886 " "
887 "REC # / TYPE / VERS";
888
889 hdata.data.named.antenna =
890 " "
891 "ANT # / TYPE";
892
893 hdata.data.named.position =
894 " .0000 .0000 .0000 "
895 "APPROX POSITION XYZ";
896
897 hdata.data.named.antennaposition =
898 " .0000 .0000 .0000 "
899 "ANTENNA: DELTA H/E/N";
900
901 hdata.data.named.wavelength = Parser->rinex3 ? 0 :
902 " 1 1 "
903 "WAVELENGTH FACT L1/2";
904
905 if(Parser->rinex3)
906 {
907#define CHECKFLAGSNEW(a, b, c) \
908 if(flags & GNSSDF_##b##DATA) \
909 { \
910 Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
911 Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
912 ++Parser->numdatatypes##a; \
913 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#c); \
914 tbufferpos += 4; \
915 }
916
917 int flags = Parser->startflags;
918 char tbuffer[6*RINEXENTRY_NUMBER+1];
919 int tbufferpos = 0;
920 for(i = 0; i < Parser->Data.numsats; ++i)
921 flags |= Parser->Data.dataflags[i];
922
923 CHECKFLAGSNEW(GPS, C1, C1C)
924 CHECKFLAGSNEW(GPS, L1C, L1C)
925 CHECKFLAGSNEW(GPS, D1C, D1C)
926 CHECKFLAGSNEW(GPS, S1C, S1C)
927 CHECKFLAGSNEW(GPS, P1, C1P)
928 CHECKFLAGSNEW(GPS, L1P, L1P)
929 CHECKFLAGSNEW(GPS, D1P, D1P)
930 CHECKFLAGSNEW(GPS, S1P, S1P)
931
932 hdata.data.named.typesofobsS = buffer;
933 i = 1+snprintf(buffer, buffersize,
934 "S %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
935 buffer += i; buffersize -= i;
936
937 CHECKFLAGSNEW(GPS, P2, C2P)
938 CHECKFLAGSNEW(GPS, L2P, L2P)
939 CHECKFLAGSNEW(GPS, D2P, D2P)
940 CHECKFLAGSNEW(GPS, S2P, S2P)
941 CHECKFLAGSNEW(GPS, C2, C2X)
942 CHECKFLAGSNEW(GPS, L2C, L2X)
943 CHECKFLAGSNEW(GPS, D2C, D2X)
944 CHECKFLAGSNEW(GPS, S2C, S2X)
945
946 hdata.data.named.typesofobsG = buffer;
947 i = 1+snprintf(buffer, buffersize,
948 "G %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
949 if(Parser->numdatatypesGPS>13)
950 {
951 i += snprintf(buffer+i-1, buffersize,
952 "\n %-52.52s SYS / # / OBS TYPES", tbuffer+13*4);
953 }
954 buffer += i; buffersize -= i;
955
956 tbufferpos = 0;
957
958 CHECKFLAGSNEW(GLO, C1, C1C)
959 CHECKFLAGSNEW(GLO, L1C, L1C)
960 CHECKFLAGSNEW(GLO, D1C, D1C)
961 CHECKFLAGSNEW(GLO, S1C, S1C)
962 CHECKFLAGSNEW(GLO, P1, C1P)
963 CHECKFLAGSNEW(GLO, L1P, L1P)
964 CHECKFLAGSNEW(GLO, D1P, D1P)
965 CHECKFLAGSNEW(GLO, S1P, S1P)
966 CHECKFLAGSNEW(GLO, P2, C2P)
967 CHECKFLAGSNEW(GLO, L2P, L2P)
968 CHECKFLAGSNEW(GLO, D2P, D2P)
969 CHECKFLAGSNEW(GLO, S2P, S2P)
970 CHECKFLAGSNEW(GLO, C2, C2C)
971 CHECKFLAGSNEW(GLO, L2C, L2C)
972 CHECKFLAGSNEW(GLO, D2C, D2C)
973 CHECKFLAGSNEW(GLO, S2C, S2C)
974
975 hdata.data.named.typesofobsR = buffer;
976 i = 1+snprintf(buffer, buffersize,
977 "R %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGLO, tbuffer);
978 if(Parser->numdatatypesGLO>13)
979 {
980 i += snprintf(buffer+i-1, buffersize,
981 "\n %-52.52s SYS / # / OBS TYPES", tbuffer+13*4);
982 }
983 buffer += i; buffersize -= i;
984 }
985 else
986 {
987#define CHECKFLAGS(a, b) \
988 if(flags & GNSSDF_##a##DATA) \
989 { \
990 if(data[RINEXENTRY_##b##DATA]) \
991 { \
992 Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
993 Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
994 } \
995 else \
996 { \
997 Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
998 Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
999 data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
1000 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#b); \
1001 tbufferpos += 6; \
1002 } \
1003 }
1004
1005 int flags = Parser->startflags;
1006 int data[RINEXENTRY_NUMBER];
1007 char tbuffer[6*RINEXENTRY_NUMBER+1];
1008 int tbufferpos = 0;
1009 for(i = 0; i < RINEXENTRY_NUMBER; ++i)
1010 data[i] = 0;
1011 for(i = 0; i < Parser->Data.numsats; ++i)
1012 flags |= Parser->Data.dataflags[i];
1013
1014 CHECKFLAGS(C1,C1)
1015 CHECKFLAGS(C2,C2)
1016 CHECKFLAGS(P1,P1)
1017 CHECKFLAGS(P2,P2)
1018 CHECKFLAGS(L1C,L1)
1019 CHECKFLAGS(L1P,L1)
1020 CHECKFLAGS(L2C,L2)
1021 CHECKFLAGS(L2P,L2)
1022 CHECKFLAGS(D1C,D1)
1023 CHECKFLAGS(D1P,D1)
1024 CHECKFLAGS(D2C,D2)
1025 CHECKFLAGS(D2P,D2)
1026 CHECKFLAGS(S1C,S1)
1027 CHECKFLAGS(S1P,S1)
1028 CHECKFLAGS(S2C,S2)
1029 CHECKFLAGS(S2P,S2)
1030
1031 hdata.data.named.typesofobs = buffer;
1032 i = 1+snprintf(buffer, buffersize,
1033 "%6d%-54.54s# / TYPES OF OBSERV", Parser->numdatatypesGPS, tbuffer);
1034 if(Parser->numdatatypesGPS>9)
1035 {
1036 i += snprintf(buffer+i-1, buffersize,
1037 "\n %-54.54s# / TYPES OF OBSERV", tbuffer+9*6);
1038 }
1039 buffer += i; buffersize -= i;
1040 }
1041
1042 {
1043 struct converttimeinfo cti;
1044 converttime(&cti, Parser->Data.week,
1045 (int)floor(Parser->Data.timeofweek/1000.0));
1046 hdata.data.named.timeoffirstobs = buffer;
1047 i = 1+snprintf(buffer, buffersize,
1048 " %4d %2d %2d %2d %2d %10.7f GPS "
1049 "TIME OF FIRST OBS", cti.year, cti.month, cti.day, cti.hour,
1050 cti.minute, cti.second + fmod(Parser->Data.timeofweek/1000.0,1.0));
1051
1052 buffer += i; buffersize -= i;
1053 }
1054
1055 hdata.numheaders = 15;
1056
1057 if(Parser->headerfile)
1058 {
1059 FILE *fh;
1060 if((fh = fopen(Parser->headerfile, "r")))
1061 {
1062 size_t siz;
1063 char *lastblockstart;
1064 if((siz = fread(buffer, 1, buffersize-1, fh)) > 0)
1065 {
1066 buffer[siz] = '\n';
1067 if(siz == buffersize)
1068 {
1069 RTCM3Error("Header file is too large. Only %d bytes read.",
1070 (int)siz);
1071 }
1072 /* scan the file line by line and enter the entries in the list */
1073 /* warn for "# / TYPES OF OBSERV" and "TIME OF FIRST OBS" */
1074 /* overwrites entries, except for comments */
1075 lastblockstart = buffer;
1076 for(i = 0; i < (int)siz; ++i)
1077 {
1078 if(buffer[i] == '\n')
1079 { /* we found a line */
1080 char *end;
1081 while(buffer[i+1] == '\r')
1082 ++i; /* skip \r in case there are any */
1083 end = buffer+i;
1084 while(*end == '\t' || *end == ' ' || *end == '\r' || *end == '\n')
1085 *(end--) = 0;
1086 if(end-lastblockstart < 60+5) /* short line */
1087 RTCM3Error("Short Header line '%s' ignored.\n", lastblockstart);
1088 else
1089 {
1090 int pos;
1091 if(!strcmp("COMMENT", lastblockstart+60))
1092 pos = hdata.numheaders;
1093 else
1094 {
1095 for(pos = 0; pos < hdata.numheaders; ++pos)
1096 {
1097 if(!strcmp(hdata.data.unnamed[pos]+60, lastblockstart+60))
1098 break;
1099 }
1100 if(!strcmp("# / TYPES OF OBSERV", lastblockstart+60)
1101 || !strcmp("TIME OF FIRST OBS", lastblockstart+60))
1102 {
1103 RTCM3Error("Overwriting header '%s' is dangerous.\n",
1104 lastblockstart+60);
1105 }
1106 }
1107 if(pos >= MAXHEADERLINES)
1108 {
1109 RTCM3Error("Maximum number of header lines of %d reached.\n",
1110 MAXHEADERLINES);
1111 }
1112 else if(!strcmp("END OF HEADER", lastblockstart+60))
1113 {
1114 RTCM3Error("End of header ignored.\n");
1115 }
1116 else
1117 {
1118 hdata.data.unnamed[pos] = lastblockstart;
1119 if(pos == hdata.numheaders)
1120 ++hdata.numheaders;
1121 }
1122 }
1123 lastblockstart = buffer+i+1;
1124 }
1125 }
1126 }
1127 else
1128 {
1129 RTCM3Error("Could not read data from headerfile '%s'.\n",
1130 Parser->headerfile);
1131 }
1132 fclose(fh);
1133 }
1134 else
1135 {
1136 RTCM3Error("Could not open header datafile '%s'.\n",
1137 Parser->headerfile);
1138 }
1139 }
1140
1141 for(i = 0; i < hdata.numheaders; ++i)
1142 {
1143 if(hdata.data.unnamed[i] && hdata.data.unnamed[i][0])
1144 RTCM3Text("%s\n", hdata.data.unnamed[i]);
1145 }
1146 RTCM3Text(" "
1147 "END OF HEADER\n");
1148}
1149
1150static void ConvLine(FILE *file, const char *fmt, ...)
1151{
1152 char buffer[100], *b;
1153 va_list v;
1154 va_start(v, fmt);
1155 vsnprintf(buffer, sizeof(buffer), fmt, v);
1156 for(b = buffer; *b; ++b)
1157 {
1158 if(*b == 'e') *b = 'D';
1159 }
1160 fprintf(file, "%s", buffer);
1161 va_end(v);
1162}
1163
1164void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
1165{
1166 Parser->Message[Parser->MessageSize++] = byte;
1167 if(Parser->MessageSize >= Parser->NeedBytes)
1168 {
1169 int r;
1170 while((r = RTCM3Parser(Parser)))
1171 {
1172 if(r == 1020 || r == 1019)
1173 {
1174 FILE *file = 0;
1175
1176 if(Parser->rinex3 && !(file = Parser->gpsfile))
1177 {
1178 const char *n = Parser->gpsephemeris ? Parser->gpsephemeris : Parser->glonassephemeris;
1179 if(n)
1180 {
1181 if(!(Parser->gpsfile = fopen(n, "w")))
1182 {
1183 RTCM3Error("Could not open ephemeris output file.\n");
1184 }
1185 else
1186 {
1187 char buffer[100];
1188 fprintf(Parser->gpsfile,
1189 "%9.2f%11sN: GNSS NAV DATA M: Mixed%12sRINEX VERSION / TYPE\n", 3.0, "", "");
1190 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1191 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1192 }
1193 Parser->gpsephemeris = 0;
1194 Parser->glonassephemeris = 0;
1195 file = Parser->gpsfile;
1196 }
1197 }
1198 else
1199 {
1200 if(r == 1020)
1201 {
1202 if(Parser->glonassephemeris)
1203 {
1204 if(!(Parser->glonassfile = fopen(Parser->glonassephemeris, "w")))
1205 {
1206 RTCM3Error("Could not open GLONASS ephemeris output file.\n");
1207 }
1208 else
1209 {
1210 char buffer[100];
1211 fprintf(Parser->glonassfile,
1212 "%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n", 2.1, "", "");
1213 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1214 fprintf(Parser->glonassfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1215 }
1216 Parser->glonassephemeris = 0;
1217 }
1218 file = Parser->glonassfile;
1219 }
1220 else if(r == 1019)
1221 {
1222 if(Parser->gpsephemeris)
1223 {
1224 if(!(Parser->gpsfile = fopen(Parser->gpsephemeris, "w")))
1225 {
1226 RTCM3Error("Could not open GPS ephemeris output file.\n");
1227 }
1228 else
1229 {
1230 char buffer[100];
1231 fprintf(Parser->gpsfile,
1232 "%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 2.1, "", "");
1233 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1234 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1235 }
1236 Parser->gpsephemeris = 0;
1237 }
1238 file = Parser->gpsfile;
1239 }
1240 }
1241 if(file)
1242 {
1243 if(r == 1020)
1244 {
1245 struct glonassephemeris *e = &Parser->ephemerisGLONASS;
1246 int w = e->GPSWeek, tow = e->GPSTOW, i;
1247 struct converttimeinfo cti;
1248
1249 updatetime(&w, &tow, e->tb*1000, 1);
1250 converttime(&cti, w, tow);
1251
1252 i = e->tk-3*60*60; if(i < 0) i += 86400;
1253
1254 if(Parser->rinex3)
1255 ConvLine(file, "R%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1256 e->almanac_number, cti.year, cti.month, cti.day, cti.hour, cti.minute,
1257 cti.second, -e->tau, e->gamma, (double) i);
1258 else
1259 ConvLine(file, "%02d %02d %02d %02d %02d %02d%5.1f%19.12e%19.12e%19.12e\n",
1260 e->almanac_number, cti.year%100, cti.month, cti.day, cti.hour, cti.minute,
1261 (double) cti.second, -e->tau, e->gamma, (double) i);
1262 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->x_pos,
1263 e->x_velocity, e->x_acceleration, (e->flags & GLOEPHF_UNHEALTHY) ? 1.0 : 0.0);
1264 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->y_pos,
1265 e->y_velocity, e->y_acceleration, (double) e->frequency_number);
1266 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->z_pos,
1267 e->z_velocity, e->z_acceleration, (double) e->E);
1268 }
1269 else /* if(r == 1019) */
1270 {
1271 struct gpsephemeris *e = &Parser->ephemerisGPS;
1272 double d; /* temporary variable */
1273 unsigned long int i; /* temporary variable */
1274 struct converttimeinfo cti;
1275 converttime(&cti, e->GPSweek, e->TOC);
1276
1277 if(Parser->rinex3)
1278 ConvLine(file, "G%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1279 e->satellite, cti.year, cti.month, cti.day, cti.hour,
1280 cti.minute, cti.second, e->clock_bias, e->clock_drift,
1281 e->clock_driftrate);
1282 else
1283 ConvLine(file, "%02d %02d %02d %02d %02d %02d%05.1f%19.12e%19.12e%19.12e\n",
1284 e->satellite, cti.year%100, cti.month, cti.day, cti.hour,
1285 cti.minute, (double) cti.second, e->clock_bias, e->clock_drift,
1286 e->clock_driftrate);
1287 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", (double)e->IODE,
1288 e->Crs, e->Delta_n, e->M0);
1289 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->Cuc,
1290 e->e, e->Cus, e->sqrt_A);
1291 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n",
1292 (double) e->TOE, e->Cic, e->OMEGA0, e->Cis);
1293 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->i0,
1294 e->Crc, e->omega, e->OMEGADOT);
1295 d = 0;
1296 i = e->flags;
1297 if(i & GPSEPHF_L2CACODE)
1298 d += 2.0;
1299 if(i & GPSEPHF_L2PCODE)
1300 d += 1.0;
1301 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->IDOT, d,
1302 (double) e->GPSweek, i & GPSEPHF_L2PCODEDATA ? 1.0 : 0.0);
1303 if(e->URAindex <= 6) /* URA index */
1304 d = ceil(10.0*pow(2.0, 1.0+((double)e->URAindex)/2.0))/10.0;
1305 else
1306 d = ceil(10.0*pow(2.0, ((double)e->URAindex)/2.0))/10.0;
1307 /* 15 indicates not to use satellite. We can't handle this special
1308 case, so we create a high "non"-accuracy value. */
1309 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", d,
1310 ((double) e->SVhealth), e->TGD, ((double) e->IODC));
1311
1312 ConvLine(file, " %19.12e%19.12e\n", ((double)e->TOW), 0.0);
1313 /* TOW */
1314 }
1315 }
1316 }
1317 else
1318 {
1319 int i, j, o;
1320 struct converttimeinfo cti;
1321
1322 if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
1323 {
1324 ++Parser->init;
1325
1326 if(Parser->init == NUMSTARTSKIP)
1327 HandleHeader(Parser);
1328 else
1329 {
1330 for(i = 0; i < Parser->Data.numsats; ++i)
1331 Parser->startflags |= Parser->Data.dataflags[i];
1332 continue;
1333 }
1334 }
1335 if(r == 2 && !Parser->validwarning)
1336 {
1337 RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
1338 " COMMENT\n");
1339 Parser->validwarning = 1;
1340 }
1341
1342 converttime(&cti, Parser->Data.week,
1343 (int)floor(Parser->Data.timeofweek/1000.0));
1344 if(Parser->rinex3)
1345 {
1346 RTCM3Text("> %04d %02d %02d %02d %02d%11.7f 0%3d\n",
1347 cti.year, cti.month, cti.day, cti.hour, cti.minute, cti.second
1348 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1349 for(i = 0; i < Parser->Data.numsats; ++i)
1350 {
1351 int glo = 0;
1352 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1353 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1354 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1355 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1356 {
1357 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1358 glo = 1;
1359 }
1360 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1361 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1362 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1363 else
1364 RTCM3Text("%3d", Parser->Data.satellites[i]);
1365
1366 if(glo)
1367 {
1368 for(j = 0; j < Parser->numdatatypesGLO; ++j)
1369 {
1370 int df = Parser->dataflagGLO[j];
1371 int pos = Parser->dataposGLO[j];
1372 if((Parser->Data.dataflags[i] & df)
1373 && !isnan(Parser->Data.measdata[i][pos])
1374 && !isinf(Parser->Data.measdata[i][pos]))
1375 {
1376 char lli = ' ';
1377 char snr = ' ';
1378 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1379 {
1380 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1381 lli = '1';
1382 snr = '0'+Parser->Data.snrL1[i];
1383 }
1384 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1385 {
1386 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1387 lli = '1';
1388 snr = '0'+Parser->Data.snrL2[i];
1389 }
1390 RTCM3Text("%14.3f%c%c",
1391 Parser->Data.measdata[i][pos],lli,snr);
1392 }
1393 else
1394 { /* no or illegal data */
1395 RTCM3Text(" ");
1396 }
1397 }
1398 }
1399 else
1400 {
1401 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1402 {
1403 int df = Parser->dataflagGPS[j];
1404 int pos = Parser->dataposGPS[j];
1405 if((Parser->Data.dataflags[i] & df)
1406 && !isnan(Parser->Data.measdata[i][pos])
1407 && !isinf(Parser->Data.measdata[i][pos]))
1408 {
1409 char lli = ' ';
1410 char snr = ' ';
1411 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1412 {
1413 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1414 lli = '1';
1415 snr = '0'+Parser->Data.snrL1[i];
1416 }
1417 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1418 {
1419 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1420 lli = '1';
1421 snr = '0'+Parser->Data.snrL2[i];
1422 }
1423 RTCM3Text("%14.3f%c%c",
1424 Parser->Data.measdata[i][pos],lli,snr);
1425 }
1426 else
1427 { /* no or illegal data */
1428 RTCM3Text(" ");
1429 }
1430 }
1431 }
1432 RTCM3Text("\n");
1433 }
1434 }
1435 else
1436 {
1437 RTCM3Text(" %02d %2d %2d %2d %2d %10.7f 0%3d",
1438 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
1439 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1440 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
1441 {
1442 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1443 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1444 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1445 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1446 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1447 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1448 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1449 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1450 else
1451 RTCM3Text("%3d", Parser->Data.satellites[i]);
1452 }
1453 RTCM3Text("\n");
1454 o = 12;
1455 j = Parser->Data.numsats - 12;
1456 while(j > 0)
1457 {
1458 RTCM3Text(" ");
1459 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
1460 {
1461 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1462 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1463 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1464 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1465 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1466 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1467 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1468 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1469 else
1470 RTCM3Text("%3d", Parser->Data.satellites[i]);
1471 }
1472 RTCM3Text("\n");
1473 j -= 12;
1474 o += 12;
1475 }
1476 for(i = 0; i < Parser->Data.numsats; ++i)
1477 {
1478 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1479 {
1480 int v = 0;
1481 int df = Parser->dataflag[j];
1482 int pos = Parser->datapos[j];
1483 if((Parser->Data.dataflags[i] & df)
1484 && !isnan(Parser->Data.measdata[i][pos])
1485 && !isinf(Parser->Data.measdata[i][pos]))
1486 {
1487 v = 1;
1488 }
1489 else
1490 {
1491 df = Parser->dataflagGPS[j];
1492 pos = Parser->dataposGPS[j];
1493
1494 if((Parser->Data.dataflags[i] & df)
1495 && !isnan(Parser->Data.measdata[i][pos])
1496 && !isinf(Parser->Data.measdata[i][pos]))
1497 {
1498 v = 1;
1499 }
1500 }
1501
1502 if(!v)
1503 { /* no or illegal data */
1504 RTCM3Text(" ");
1505 }
1506 else
1507 {
1508 char lli = ' ';
1509 char snr = ' ';
1510 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1511 {
1512 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1513 lli = '1';
1514 snr = '0'+Parser->Data.snrL1[i];
1515 }
1516 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1517 {
1518 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1519 lli = '1';
1520 snr = '0'+Parser->Data.snrL2[i];
1521 }
1522 RTCM3Text("%14.3f%c%c",
1523 Parser->Data.measdata[i][pos],lli,snr);
1524 }
1525 if(j%5 == 4 || j == Parser->numdatatypesGPS-1)
1526 RTCM3Text("\n");
1527 }
1528 }
1529 }
1530 }
1531 }
1532 }
1533}
1534
1535#ifndef NO_RTCM3_MAIN
1536static char datestr[] = "$Date: 2007/10/14 14:59:27 $";
1537
1538/* The string, which is send as agent in HTTP request */
1539#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
1540
1541#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
1542
1543static const char encodingTable [64] = {
1544 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1545 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1546 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1547 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1548};
1549
1550/* does not buffer overrun, but breaks directly after an error */
1551/* returns the number of required bytes */
1552static int encode(char *buf, int size, const char *user, const char *pwd)
1553{
1554 unsigned char inbuf[3];
1555 char *out = buf;
1556 int i, sep = 0, fill = 0, bytes = 0;
1557
1558 while(*user || *pwd)
1559 {
1560 i = 0;
1561 while(i < 3 && *user) inbuf[i++] = *(user++);
1562 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1563 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1564 while(i < 3) {inbuf[i++] = 0; ++fill; }
1565 if(out-buf < size-1)
1566 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1567 if(out-buf < size-1)
1568 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1569 | ((inbuf [1] & 0xF0) >> 4)];
1570 if(out-buf < size-1)
1571 {
1572 if(fill == 2)
1573 *(out++) = '=';
1574 else
1575 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1576 | ((inbuf [2] & 0xC0) >> 6)];
1577 }
1578 if(out-buf < size-1)
1579 {
1580 if(fill >= 1)
1581 *(out++) = '=';
1582 else
1583 *(out++) = encodingTable[inbuf [2] & 0x3F];
1584 }
1585 bytes += 4;
1586 }
1587 if(out-buf < size)
1588 *out = 0;
1589 return bytes;
1590}
1591
1592static int stop = 0;
1593
1594struct Args
1595{
1596 const char *server;
1597 const char *port;
1598 int mode;
1599 int timeout;
1600 int rinex3;
1601 const char *user;
1602 const char *password;
1603 const char *proxyhost;
1604 const char *proxyport;
1605 const char *nmea;
1606 const char *data;
1607 const char *headerfile;
1608 const char *gpsephemeris;
1609 const char *glonassephemeris;
1610};
1611
1612/* option parsing */
1613#ifdef NO_LONG_OPTS
1614#define LONG_OPT(a)
1615#else
1616#define LONG_OPT(a) a
1617static struct option opts[] = {
1618{ "data", required_argument, 0, 'd'},
1619{ "server", required_argument, 0, 's'},
1620{ "password", required_argument, 0, 'p'},
1621{ "port", required_argument, 0, 'r'},
1622{ "timeout", required_argument, 0, 't'},
1623{ "header", required_argument, 0, 'f'},
1624{ "user", required_argument, 0, 'u'},
1625{ "gpsephemeris", required_argument, 0, 'E'},
1626{ "glonassephemeris", required_argument, 0, 'G'},
1627{ "rinex3", no_argument, 0, '3'},
1628{ "proxyport", required_argument, 0, 'R'},
1629{ "proxyhost", required_argument, 0, 'S'},
1630{ "nmea", required_argument, 0, 'n'},
1631{ "mode", required_argument, 0, 'M'},
1632{ "help", no_argument, 0, 'h'},
1633{0,0,0,0}};
1634#endif
1635#define ARGOPT "-d:s:p:r:t:f:u:E:G:M:S:R:n:h3"
1636
1637enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };
1638
1639static const char *geturl(const char *url, struct Args *args)
1640{
1641 static char buf[1000];
1642 static char *Buffer = buf;
1643 static char *Bufend = buf+sizeof(buf);
1644
1645 if(strncmp("ntrip:", url, 6))
1646 return "URL must start with 'ntrip:'.";
1647 url += 6; /* skip ntrip: */
1648
1649 if(*url != '@' && *url != '/')
1650 {
1651 /* scan for mountpoint */
1652 args->data = Buffer;
1653 while(*url && *url != '@' && *url != ';' &&*url != '/' && Buffer != Bufend)
1654 *(Buffer++) = *(url++);
1655 if(Buffer == args->data)
1656 return "Mountpoint required.";
1657 else if(Buffer >= Bufend-1)
1658 return "Parsing buffer too short.";
1659 *(Buffer++) = 0;
1660 }
1661
1662 if(*url == '/') /* username and password */
1663 {
1664 ++url;
1665 args->user = Buffer;
1666 while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
1667 *(Buffer++) = *(url++);
1668 if(Buffer == args->user)
1669 return "Username cannot be empty.";
1670 else if(Buffer >= Bufend-1)
1671 return "Parsing buffer too short.";
1672 *(Buffer++) = 0;
1673
1674 if(*url == ':') ++url;
1675
1676 args->password = Buffer;
1677 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1678 *(Buffer++) = *(url++);
1679 if(Buffer == args->password)
1680 return "Password cannot be empty.";
1681 else if(Buffer >= Bufend-1)
1682 return "Parsing buffer too short.";
1683 *(Buffer++) = 0;
1684 }
1685
1686 if(*url == '@') /* server */
1687 {
1688 ++url;
1689 if(*url != '@' && *url != ':')
1690 {
1691 args->server = Buffer;
1692 while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
1693 *(Buffer++) = *(url++);
1694 if(Buffer == args->server)
1695 return "Servername cannot be empty.";
1696 else if(Buffer >= Bufend-1)
1697 return "Parsing buffer too short.";
1698 *(Buffer++) = 0;
1699 }
1700
1701 if(*url == ':')
1702 {
1703 ++url;
1704 args->port = Buffer;
1705 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1706 *(Buffer++) = *(url++);
1707 if(Buffer == args->port)
1708 return "Port cannot be empty.";
1709 else if(Buffer >= Bufend-1)
1710 return "Parsing buffer too short.";
1711 *(Buffer++) = 0;
1712 }
1713
1714 if(*url == '@') /* proxy */
1715 {
1716 ++url;
1717 args->proxyhost = Buffer;
1718 while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
1719 *(Buffer++) = *(url++);
1720 if(Buffer == args->proxyhost)
1721 return "Proxy servername cannot be empty.";
1722 else if(Buffer >= Bufend-1)
1723 return "Parsing buffer too short.";
1724 *(Buffer++) = 0;
1725
1726 if(*url == ':')
1727 {
1728 ++url;
1729 args->proxyport = Buffer;
1730 while(*url && *url != ';' && Buffer != Bufend)
1731 *(Buffer++) = *(url++);
1732 if(Buffer == args->proxyport)
1733 return "Proxy port cannot be empty.";
1734 else if(Buffer >= Bufend-1)
1735 return "Parsing buffer too short.";
1736 *(Buffer++) = 0;
1737 }
1738 }
1739 }
1740 if(*url == ';') /* NMEA */
1741 {
1742 args->nmea = ++url;
1743 while(*url)
1744 ++url;
1745 }
1746
1747 return *url ? "Garbage at end of server string." : 0;
1748}
1749
1750static int getargs(int argc, char **argv, struct Args *args)
1751{
1752 int res = 1;
1753 int getoptr;
1754 int help = 0;
1755 char *t;
1756
1757 args->server = "www.euref-ip.net";
1758 args->port = "2101";
1759 args->timeout = 60;
1760 args->user = "";
1761 args->password = "";
1762 args->data = 0;
1763 args->headerfile = 0;
1764 args->gpsephemeris = 0;
1765 args->glonassephemeris = 0;
1766 args->rinex3 = 0;
1767 args->nmea = 0;
1768 args->proxyhost = 0;
1769 args->proxyport = "2101";
1770 args->mode = AUTO;
1771 help = 0;
1772
1773 do
1774 {
1775
1776#ifdef NO_LONG_OPTS
1777 switch((getoptr = getopt(argc, argv, ARGOPT)))
1778#else
1779 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
1780#endif
1781 {
1782 case 's': args->server = optarg; break;
1783 case 'u': args->user = optarg; break;
1784 case 'p': args->password = optarg; break;
1785 case 'd': args->data = optarg; break;
1786 case 'f': args->headerfile = optarg; break;
1787 case 'E': args->gpsephemeris = optarg; break;
1788 case 'G': args->glonassephemeris = optarg; break;
1789 case 'r': args->port = optarg; break;
1790 case '3': args->rinex3 = 1; break;
1791 case 'S': args->proxyhost = optarg; break;
1792 case 'n': args->nmea = optarg; break;
1793 case 'R': args->proxyport = optarg; break;
1794 case 'h': help=1; break;
1795 case 'M':
1796 args->mode = 0;
1797 if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
1798 args->mode = NTRIP1;
1799 else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
1800 args->mode = HTTP;
1801 else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
1802 args->mode = RTSP;
1803 else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
1804 args->mode = AUTO;
1805 else args->mode = atoi(optarg);
1806 if((args->mode == 0) || (args->mode >= END))
1807 {
1808 fprintf(stderr, "Mode %s unknown\n", optarg);
1809 res = 0;
1810 }
1811 break;
1812 case 't':
1813 args->timeout = strtoul(optarg, &t, 10);
1814 if((t && *t) || args->timeout < 0)
1815 res = 0;
1816 break;
1817
1818 case 1:
1819 {
1820 const char *err;
1821 if((err = geturl(optarg, args)))
1822 {
1823 RTCM3Error("%s\n\n", err);
1824 res = 0;
1825 }
1826 }
1827 break;
1828 case -1: break;
1829 }
1830 } while(getoptr != -1 || !res);
1831
1832 datestr[0] = datestr[7];
1833 datestr[1] = datestr[8];
1834 datestr[2] = datestr[9];
1835 datestr[3] = datestr[10];
1836 datestr[5] = datestr[12];
1837 datestr[6] = datestr[13];
1838 datestr[8] = datestr[15];
1839 datestr[9] = datestr[16];
1840 datestr[4] = datestr[7] = '-';
1841 datestr[10] = 0;
1842
1843 if(args->gpsephemeris && args->glonassephemeris && args->rinex3)
1844 {
1845 RTCM3Error("RINEX3 produces a combined ephemeris file, but 2 files were specified.\n"
1846 "Please specify only one navigation file.\n");
1847 res = 0;
1848 }
1849 else if(!res || help)
1850 {
1851 RTCM3Error("Version %s (%s) GPL" COMPILEDATE
1852 "\nUsage: %s -s server -u user ...\n"
1853 " -d " LONG_OPT("--data ") "the requested data set\n"
1854 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
1855 " -s " LONG_OPT("--server ") "the server name or address\n"
1856 " -p " LONG_OPT("--password ") "the login password\n"
1857 " -r " LONG_OPT("--port ") "the server port number (default 2101)\n"
1858 " -t " LONG_OPT("--timeout ") "timeout in seconds (default 60)\n"
1859 " -u " LONG_OPT("--user ") "the user name\n"
1860 " -E " LONG_OPT("--gpsephemeris ") "output file for GPS ephemeris data\n"
1861 " -G " LONG_OPT("--glonassephemeris ") "output file for GLONASS ephemeris data\n"
1862 " -3 " LONG_OPT("--rinex3 ") "output RINEX type 3 data\n"
1863 " -S " LONG_OPT("--proxyhost ") "proxy name or address\n"
1864 " -R " LONG_OPT("--proxyport ") "proxy port, optional (default 2101)\n"
1865 " -n " LONG_OPT("--nmea ") "NMEA string for sending to server\n"
1866 " -M " LONG_OPT("--mode ") "mode for data request\n"
1867 " Valid modes are:\n"
1868 " 1, h, http NTRIP Version 2.0 Caster in TCP/IP mode\n"
1869 " 2, r, rtsp NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
1870 " 3, n, ntrip1 NTRIP Version 1.0 Caster\n"
1871 " 4, a, auto automatic detection (default)\n"
1872 "or using an URL:\n%s ntrip:data[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
1873 , revisionstr, datestr, argv[0], argv[0]);
1874 exit(1);
1875 }
1876 return res;
1877}
1878
1879/* let the output complete a block if necessary */
1880static void signalhandler(int sig)
1881{
1882 if(!stop)
1883 {
1884 RTCM3Error("Stop signal number %d received. "
1885 "Trying to terminate gentle.\n", sig);
1886 stop = 1;
1887 alarm(1);
1888 }
1889}
1890
1891#define ALARMTIME (2*60)
1892
1893/* for some reason we had to abort hard (maybe waiting for data */
1894#ifdef __GNUC__
1895static __attribute__ ((noreturn)) void signalhandler_alarm(
1896int sig __attribute__((__unused__)))
1897#else /* __GNUC__ */
1898static void signalhandler_alarm(int sig)
1899#endif /* __GNUC__ */
1900{
1901 RTCM3Error("Programm forcefully terminated.\n");
1902 exit(1);
1903}
1904
1905int main(int argc, char **argv)
1906{
1907 struct Args args;
1908 struct RTCM3ParserData Parser;
1909
1910 setbuf(stdout, 0);
1911 setbuf(stdin, 0);
1912 setbuf(stderr, 0);
1913
1914 {
1915 char *a;
1916 int i=0;
1917 for(a = revisionstr+11; *a && *a != ' '; ++a)
1918 revisionstr[i++] = *a;
1919 revisionstr[i] = 0;
1920 }
1921
1922 signal(SIGINT, signalhandler);
1923 signal(SIGALRM,signalhandler_alarm);
1924 signal(SIGQUIT,signalhandler);
1925 signal(SIGTERM,signalhandler);
1926 signal(SIGPIPE,signalhandler);
1927 memset(&Parser, 0, sizeof(Parser));
1928 {
1929 time_t tim;
1930 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
1931 Parser.GPSWeek = tim/(7*24*60*60);
1932 Parser.GPSTOW = tim%(7*24*60*60);
1933 }
1934
1935 if(getargs(argc, argv, &args))
1936 {
1937 int sockfd, numbytes;
1938 char buf[MAXDATASIZE];
1939 struct sockaddr_in their_addr; /* connector's address information */
1940 struct hostent *he;
1941 struct servent *se;
1942 const char *server, *port, *proxyserver = 0;
1943 char proxyport[6];
1944 char *b;
1945 long i;
1946 struct timeval tv;
1947
1948 alarm(ALARMTIME);
1949
1950 Parser.headerfile = args.headerfile;
1951 Parser.glonassephemeris = args.glonassephemeris;
1952 Parser.gpsephemeris = args.gpsephemeris;
1953 Parser.rinex3 = args.rinex3;
1954
1955 if(args.proxyhost)
1956 {
1957 int p;
1958 if((i = strtol(args.port, &b, 10)) && (!b || !*b))
1959 p = i;
1960 else if(!(se = getservbyname(args.port, 0)))
1961 {
1962 RTCM3Error("Can't resolve port %s.", args.port);
1963 exit(1);
1964 }
1965 else
1966 {
1967 p = ntohs(se->s_port);
1968 }
1969 snprintf(proxyport, sizeof(proxyport), "%d", p);
1970 port = args.proxyport;
1971 proxyserver = args.server;
1972 server = args.proxyhost;
1973 }
1974 else
1975 {
1976 server = args.server;
1977 port = args.port;
1978 }
1979
1980 memset(&their_addr, 0, sizeof(struct sockaddr_in));
1981 if((i = strtol(port, &b, 10)) && (!b || !*b))
1982 their_addr.sin_port = htons(i);
1983 else if(!(se = getservbyname(port, 0)))
1984 {
1985 RTCM3Error("Can't resolve port %s.", port);
1986 exit(1);
1987 }
1988 else
1989 {
1990 their_addr.sin_port = se->s_port;
1991 }
1992 if(!(he=gethostbyname(server)))
1993 {
1994 RTCM3Error("Server name lookup failed for '%s'.\n", server);
1995 exit(1);
1996 }
1997 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
1998 {
1999 perror("socket");
2000 exit(1);
2001 }
2002
2003 tv.tv_sec = args.timeout;
2004 tv.tv_usec = 0;
2005 if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval) ) == -1)
2006 {
2007 RTCM3Error("Function setsockopt: %s\n", strerror(errno));
2008 exit(1);
2009 }
2010
2011 their_addr.sin_family = AF_INET;
2012 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2013
2014 if(args.data && args.mode == RTSP)
2015 {
2016 struct sockaddr_in local;
2017 int sockudp, localport;
2018 int cseq = 1;
2019 socklen_t len;
2020
2021 if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
2022 {
2023 perror("socket");
2024 exit(1);
2025 }
2026 /* fill structure with local address information for UDP */
2027 memset(&local, 0, sizeof(local));
2028 local.sin_family = AF_INET;
2029 local.sin_port = htons(0);
2030 local.sin_addr.s_addr = htonl(INADDR_ANY);
2031 len = sizeof(local);
2032 /* bind() in order to get a random RTP client_port */
2033 if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
2034 {
2035 perror("bind");
2036 exit(1);
2037 }
2038 if((getsockname(sockudp, (struct sockaddr*)&local, &len)) != -1)
2039 {
2040 localport = ntohs(local.sin_port);
2041 }
2042 else
2043 {
2044 perror("local access failed");
2045 exit(1);
2046 }
2047 if(connect(sockfd, (struct sockaddr *)&their_addr,
2048 sizeof(struct sockaddr)) == -1)
2049 {
2050 perror("connect");
2051 exit(1);
2052 }
2053 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2054 "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"
2055 "CSeq: %d\r\n"
2056 "Ntrip-Version: Ntrip/2.0\r\n"
2057 "Ntrip-Component: Ntripclient\r\n"
2058 "User-Agent: %s/%s\r\n"
2059 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
2060 "Authorization: Basic ",
2061 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2062 args.data, cseq++, AGENTSTRING, revisionstr, localport);
2063 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
2064 {
2065 RTCM3Error("Requested data too long\n");
2066 exit(1);
2067 }
2068 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
2069 if(i > MAXDATASIZE-4)
2070 {
2071 RTCM3Error("Username and/or password too long\n");
2072 exit(1);
2073 }
2074 buf[i++] = '\r';
2075 buf[i++] = '\n';
2076 buf[i++] = '\r';
2077 buf[i++] = '\n';
2078 if(args.nmea)
2079 {
2080 int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
2081 if(j >= 0 && j < MAXDATASIZE-i)
2082 i += j;
2083 else
2084 {
2085 RTCM3Error("NMEA string too long\n");
2086 exit(1);
2087 }
2088 }
2089 if(send(sockfd, buf, (size_t)i, 0) != i)
2090 {
2091 perror("send");
2092 exit(1);
2093 }
2094 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2095 {
2096 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2097 {
2098 int serverport = 0, session = 0;
2099 const char *portcheck = "server_port=";
2100 const char *sessioncheck = "session: ";
2101 int l = strlen(portcheck)-1;
2102 int j=0;
2103 for(i = 0; j != l && i < numbytes-l; ++i)
2104 {
2105 for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
2106 ;
2107 }
2108 if(i == numbytes-l)
2109 {
2110 RTCM3Error("No server port number found\n");
2111 exit(1);
2112 }
2113 else
2114 {
2115 i+=l;
2116 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2117 serverport = serverport * 10 + buf[i++]-'0';
2118 if(buf[i] != '\r' && buf[i] != ';')
2119 {
2120 RTCM3Error("Could not extract server port\n");
2121 exit(1);
2122 }
2123 }
2124 l = strlen(sessioncheck)-1;
2125 j=0;
2126 for(i = 0; j != l && i < numbytes-l; ++i)
2127 {
2128 for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
2129 ;
2130 }
2131 if(i == numbytes-l)
2132 {
2133 RTCM3Error("No session number found\n");
2134 exit(1);
2135 }
2136 else
2137 {
2138 i+=l;
2139 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2140 session = session * 10 + buf[i++]-'0';
2141 if(buf[i] != '\r')
2142 {
2143 RTCM3Error("Could not extract session number\n");
2144 exit(1);
2145 }
2146 }
2147
2148 i = snprintf(buf, MAXDATASIZE,
2149 "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"
2150 "CSeq: %d\r\n"
2151 "Session: %d\r\n"
2152 "\r\n",
2153 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2154 args.data, cseq++, session);
2155
2156 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2157 {
2158 RTCM3Error("Requested data too long\n");
2159 exit(1);
2160 }
2161 if(send(sockfd, buf, (size_t)i, 0) != i)
2162 {
2163 perror("send");
2164 exit(1);
2165 }
2166 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2167 {
2168 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2169 {
2170 struct sockaddr_in addrRTP;
2171 /* fill structure with caster address information for UDP */
2172 memset(&addrRTP, 0, sizeof(addrRTP));
2173 addrRTP.sin_family = AF_INET;
2174 addrRTP.sin_port = htons(serverport);
2175 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2176 len = sizeof(addrRTP);
2177 int ts = 0;
2178 int sn = 0;
2179 int ssrc = 0;
2180 int init = 0;
2181 int u, v, w;
2182 while(!stop && (i = recvfrom(sockudp, buf, 1526, 0,
2183 (struct sockaddr*) &addrRTP, &len)) > 0)
2184 {
2185 alarm(ALARMTIME);
2186 if(i >= 12+1 && (unsigned char)buf[0] == (2 << 6) && buf[1] == 0x60)
2187 {
2188 u= ((unsigned char)buf[2]<<8)+(unsigned char)buf[3];
2189 v = ((unsigned char)buf[4]<<24)+((unsigned char)buf[5]<<16)
2190 +((unsigned char)buf[6]<<8)+(unsigned char)buf[7];
2191 w = ((unsigned char)buf[8]<<24)+((unsigned char)buf[9]<<16)
2192 +((unsigned char)buf[10]<<8)+(unsigned char)buf[11];
2193
2194 if(init)
2195 {
2196 if(u < -30000 && sn > 30000) sn -= 0xFFFF;
2197 if(ssrc != w || ts > v)
2198 {
2199 RTCM3Error("Illegal UDP data received.\n");
2200 exit(1);
2201 }
2202 if(u > sn) /* don't show out-of-order packets */
2203 fwrite(buf+12, (size_t)i-12, 1, stdout);
2204 }
2205 sn = u; ts = v; ssrc = w; init = 1;
2206 }
2207 else
2208 {
2209 RTCM3Error("Illegal UDP header.\n");
2210 exit(1);
2211 }
2212 }
2213 }
2214 i = snprintf(buf, MAXDATASIZE,
2215 "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"
2216 "CSeq: %d\r\n"
2217 "Session: %d\r\n"
2218 "\r\n",
2219 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2220 args.data, cseq++, session);
2221
2222 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2223 {
2224 RTCM3Error("Requested data too long\n");
2225 exit(1);
2226 }
2227 if(send(sockfd, buf, (size_t)i, 0) != i)
2228 {
2229 perror("send");
2230 exit(1);
2231 }
2232 }
2233 else
2234 {
2235 RTCM3Error("Could not start data stream.\n");
2236 exit(1);
2237 }
2238 }
2239 else
2240 {
2241 RTCM3Error("Could not setup initial control connection.\n");
2242 exit(1);
2243 }
2244 }
2245 else
2246 {
2247 perror("recv");
2248 exit(1);
2249 }
2250 }
2251 else
2252 {
2253 if(connect(sockfd, (struct sockaddr *)&their_addr,
2254 sizeof(struct sockaddr)) == -1)
2255 {
2256 perror("connect");
2257 exit(1);
2258 }
2259 if(!args.data)
2260 {
2261 i = snprintf(buf, MAXDATASIZE,
2262 "GET %s%s%s%s/ HTTP/1.0\r\n"
2263 "Host: %s\r\n%s"
2264 "User-Agent: %s/%s\r\n"
2265 "\r\n"
2266 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
2267 proxyserver ? ":" : "", proxyserver ? proxyport : "",
2268 args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
2269 AGENTSTRING, revisionstr);
2270 }
2271 else
2272 {
2273 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2274 "GET %s%s%s%s/%s HTTP/1.0\r\n"
2275 "Host: %s\r\n%s"
2276 "User-Agent: %s/%s\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 stop = 1;
2398 break;
2399 case 3: /* scanning for return */
2400 if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
2401 else stop = 1;
2402 break;
2403 case 4: /* output data */
2404 i = numbytes-pos;
2405 if(i > chunksize) i = chunksize;
2406 {
2407 int z;
2408 for(z = 0; z < i && !stop; ++z)
2409 HandleByte(&Parser, (unsigned int) buf[pos+z]);
2410 }
2411 totalbytes += i;
2412 chunksize -= i;
2413 pos += i;
2414 if(!chunksize)
2415 chunkymode = 1;
2416 break;
2417 }
2418 }
2419 if(stop)
2420 {
2421 RTCM3Error("Error in chunky transfer encoding\n");
2422 break;
2423 }
2424 }
2425 else
2426 {
2427 totalbytes += numbytes;
2428 {
2429 int z;
2430 for(z = 0; z < numbytes && !stop; ++z)
2431 HandleByte(&Parser, (unsigned int) buf[z]);
2432 }
2433 }
2434 if(totalbytes < 0) /* overflow */
2435 {
2436 totalbytes = 0;
2437 starttime = time(0);
2438 lastout = starttime;
2439 }
2440 }
2441 }
2442 }
2443 else
2444 {
2445 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
2446 {
2447 alarm(ALARMTIME);
2448 fwrite(buf, (size_t)numbytes, 1, stdout);
2449 }
2450 }
2451 close(sockfd);
2452 }
2453 }
2454 return 0;
2455}
2456#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.