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

Last change on this file since 638 was 551, 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.25 2007/10/25 09:37:42 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.25 $";
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
238void 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
778void 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
808void RTCM3Text(const char *fmt, ...)
809{
810 va_list v;
811 va_start(v, fmt);
812 vprintf(fmt, v);
813 va_end(v);
814}
815
816int HandleRunBy(char *buffer, int buffersize, const char **u,
817int rinex3)
818{
819 const char *user;
820 time_t t;
821 struct tm * t2;
822
823#ifdef NO_RTCM3_MAIN
824 if(revisionstr[0] == '$')
825 {
826 char *a;
827 int i=0;
828 for(a = revisionstr+11; *a && *a != ' '; ++a)
829 revisionstr[i++] = *a;
830 revisionstr[i] = 0;
831 }
832#endif
833
834 user= getenv("USER");
835 if(!user) user = "";
836 t = time(&t);
837 t2 = gmtime(&t);
838 if(u) *u = user;
839 return 1+snprintf(buffer, buffersize,
840 rinex3 ?
841 "RTCM3TORINEX %-7.7s%-20.20s%04d%02d%02d %02d%02d%02d UTC "
842 "PGM / RUN BY / DATE" :
843 "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d "
844 "PGM / RUN BY / DATE", revisionstr, user, 1900+t2->tm_year,
845 t2->tm_mon+1, t2->tm_mday, t2->tm_hour, t2->tm_min, t2->tm_sec);
846}
847
848#define NUMSTARTSKIP 3
849void HandleHeader(struct RTCM3ParserData *Parser)
850{
851 struct HeaderData hdata;
852 char thebuffer[MAXHEADERBUFFERSIZE];
853 char *buffer = thebuffer;
854 size_t buffersize = sizeof(thebuffer);
855 int i;
856
857 memset(&hdata, 0, sizeof(hdata));
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#ifndef NO_RTCM3_MAIN
1142 for(i = 0; i < hdata.numheaders; ++i)
1143 {
1144 if(hdata.data.unnamed[i] && hdata.data.unnamed[i][0])
1145 RTCM3Text("%s\n", hdata.data.unnamed[i]);
1146 }
1147 RTCM3Text(" "
1148 "END OF HEADER\n");
1149#endif
1150}
1151
1152static void ConvLine(FILE *file, const char *fmt, ...)
1153{
1154 char buffer[100], *b;
1155 va_list v;
1156 va_start(v, fmt);
1157 vsnprintf(buffer, sizeof(buffer), fmt, v);
1158 for(b = buffer; *b; ++b)
1159 {
1160 if(*b == 'e') *b = 'D';
1161 }
1162 fprintf(file, "%s", buffer);
1163 va_end(v);
1164}
1165
1166void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
1167{
1168 Parser->Message[Parser->MessageSize++] = byte;
1169 if(Parser->MessageSize >= Parser->NeedBytes)
1170 {
1171 int r;
1172 while((r = RTCM3Parser(Parser)))
1173 {
1174 if(r == 1020 || r == 1019)
1175 {
1176 FILE *file = 0;
1177
1178 if(Parser->rinex3 && !(file = Parser->gpsfile))
1179 {
1180 const char *n = Parser->gpsephemeris ? Parser->gpsephemeris : Parser->glonassephemeris;
1181 if(n)
1182 {
1183 if(!(Parser->gpsfile = fopen(n, "w")))
1184 {
1185 RTCM3Error("Could not open ephemeris output file.\n");
1186 }
1187 else
1188 {
1189 char buffer[100];
1190 fprintf(Parser->gpsfile,
1191 "%9.2f%11sN: GNSS NAV DATA M: Mixed%12sRINEX VERSION / TYPE\n", 3.0, "", "");
1192 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1193 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1194 }
1195 Parser->gpsephemeris = 0;
1196 Parser->glonassephemeris = 0;
1197 file = Parser->gpsfile;
1198 }
1199 }
1200 else
1201 {
1202 if(r == 1020)
1203 {
1204 if(Parser->glonassephemeris)
1205 {
1206 if(!(Parser->glonassfile = fopen(Parser->glonassephemeris, "w")))
1207 {
1208 RTCM3Error("Could not open GLONASS ephemeris output file.\n");
1209 }
1210 else
1211 {
1212 char buffer[100];
1213 fprintf(Parser->glonassfile,
1214 "%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n", 2.1, "", "");
1215 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1216 fprintf(Parser->glonassfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1217 }
1218 Parser->glonassephemeris = 0;
1219 }
1220 file = Parser->glonassfile;
1221 }
1222 else if(r == 1019)
1223 {
1224 if(Parser->gpsephemeris)
1225 {
1226 if(!(Parser->gpsfile = fopen(Parser->gpsephemeris, "w")))
1227 {
1228 RTCM3Error("Could not open GPS ephemeris output file.\n");
1229 }
1230 else
1231 {
1232 char buffer[100];
1233 fprintf(Parser->gpsfile,
1234 "%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 2.1, "", "");
1235 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1236 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1237 }
1238 Parser->gpsephemeris = 0;
1239 }
1240 file = Parser->gpsfile;
1241 }
1242 }
1243 if(file)
1244 {
1245 if(r == 1020)
1246 {
1247 struct glonassephemeris *e = &Parser->ephemerisGLONASS;
1248 int w = e->GPSWeek, tow = e->GPSTOW, i;
1249 struct converttimeinfo cti;
1250
1251 updatetime(&w, &tow, e->tb*1000, 1);
1252 converttime(&cti, w, tow);
1253
1254 i = e->tk-3*60*60; if(i < 0) i += 86400;
1255
1256 if(Parser->rinex3)
1257 ConvLine(file, "R%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1258 e->almanac_number, cti.year, cti.month, cti.day, cti.hour, cti.minute,
1259 cti.second, -e->tau, e->gamma, (double) i);
1260 else
1261 ConvLine(file, "%02d %02d %02d %02d %02d %02d%5.1f%19.12e%19.12e%19.12e\n",
1262 e->almanac_number, cti.year%100, cti.month, cti.day, cti.hour, cti.minute,
1263 (double) cti.second, -e->tau, e->gamma, (double) i);
1264 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->x_pos,
1265 e->x_velocity, e->x_acceleration, (e->flags & GLOEPHF_UNHEALTHY) ? 1.0 : 0.0);
1266 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->y_pos,
1267 e->y_velocity, e->y_acceleration, (double) e->frequency_number);
1268 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->z_pos,
1269 e->z_velocity, e->z_acceleration, (double) e->E);
1270 }
1271 else /* if(r == 1019) */
1272 {
1273 struct gpsephemeris *e = &Parser->ephemerisGPS;
1274 double d; /* temporary variable */
1275 unsigned long int i; /* temporary variable */
1276 struct converttimeinfo cti;
1277 converttime(&cti, e->GPSweek, e->TOC);
1278
1279 if(Parser->rinex3)
1280 ConvLine(file, "G%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1281 e->satellite, cti.year, cti.month, cti.day, cti.hour,
1282 cti.minute, cti.second, e->clock_bias, e->clock_drift,
1283 e->clock_driftrate);
1284 else
1285 ConvLine(file, "%02d %02d %02d %02d %02d %02d%05.1f%19.12e%19.12e%19.12e\n",
1286 e->satellite, cti.year%100, cti.month, cti.day, cti.hour,
1287 cti.minute, (double) cti.second, e->clock_bias, e->clock_drift,
1288 e->clock_driftrate);
1289 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", (double)e->IODE,
1290 e->Crs, e->Delta_n, e->M0);
1291 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->Cuc,
1292 e->e, e->Cus, e->sqrt_A);
1293 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n",
1294 (double) e->TOE, e->Cic, e->OMEGA0, e->Cis);
1295 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->i0,
1296 e->Crc, e->omega, e->OMEGADOT);
1297 d = 0;
1298 i = e->flags;
1299 if(i & GPSEPHF_L2CACODE)
1300 d += 2.0;
1301 if(i & GPSEPHF_L2PCODE)
1302 d += 1.0;
1303 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->IDOT, d,
1304 (double) e->GPSweek, i & GPSEPHF_L2PCODEDATA ? 1.0 : 0.0);
1305 if(e->URAindex <= 6) /* URA index */
1306 d = ceil(10.0*pow(2.0, 1.0+((double)e->URAindex)/2.0))/10.0;
1307 else
1308 d = ceil(10.0*pow(2.0, ((double)e->URAindex)/2.0))/10.0;
1309 /* 15 indicates not to use satellite. We can't handle this special
1310 case, so we create a high "non"-accuracy value. */
1311 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", d,
1312 ((double) e->SVhealth), e->TGD, ((double) e->IODC));
1313
1314 ConvLine(file, " %19.12e%19.12e\n", ((double)e->TOW), 0.0);
1315 /* TOW */
1316 }
1317 }
1318 }
1319 else
1320 {
1321 int i, j, o;
1322 struct converttimeinfo cti;
1323
1324 if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
1325 {
1326 ++Parser->init;
1327
1328 if(Parser->init == NUMSTARTSKIP)
1329 HandleHeader(Parser);
1330 else
1331 {
1332 for(i = 0; i < Parser->Data.numsats; ++i)
1333 Parser->startflags |= Parser->Data.dataflags[i];
1334 continue;
1335 }
1336 }
1337 if(r == 2 && !Parser->validwarning)
1338 {
1339 RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
1340 " COMMENT\n");
1341 Parser->validwarning = 1;
1342 }
1343
1344 converttime(&cti, Parser->Data.week,
1345 (int)floor(Parser->Data.timeofweek/1000.0));
1346 if(Parser->rinex3)
1347 {
1348 RTCM3Text("> %04d %02d %02d %02d %02d%11.7f 0%3d\n",
1349 cti.year, cti.month, cti.day, cti.hour, cti.minute, cti.second
1350 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1351 for(i = 0; i < Parser->Data.numsats; ++i)
1352 {
1353 int glo = 0;
1354 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1355 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1356 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1357 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1358 {
1359 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1360 glo = 1;
1361 }
1362 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1363 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1364 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1365 else
1366 RTCM3Text("%3d", Parser->Data.satellites[i]);
1367
1368 if(glo)
1369 {
1370 for(j = 0; j < Parser->numdatatypesGLO; ++j)
1371 {
1372 int df = Parser->dataflagGLO[j];
1373 int pos = Parser->dataposGLO[j];
1374 if((Parser->Data.dataflags[i] & df)
1375 && !isnan(Parser->Data.measdata[i][pos])
1376 && !isinf(Parser->Data.measdata[i][pos]))
1377 {
1378 char lli = ' ';
1379 char snr = ' ';
1380 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1381 {
1382 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1383 lli = '1';
1384 snr = '0'+Parser->Data.snrL1[i];
1385 }
1386 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1387 {
1388 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1389 lli = '1';
1390 snr = '0'+Parser->Data.snrL2[i];
1391 }
1392 RTCM3Text("%14.3f%c%c",
1393 Parser->Data.measdata[i][pos],lli,snr);
1394 }
1395 else
1396 { /* no or illegal data */
1397 RTCM3Text(" ");
1398 }
1399 }
1400 }
1401 else
1402 {
1403 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1404 {
1405 int df = Parser->dataflagGPS[j];
1406 int pos = Parser->dataposGPS[j];
1407 if((Parser->Data.dataflags[i] & df)
1408 && !isnan(Parser->Data.measdata[i][pos])
1409 && !isinf(Parser->Data.measdata[i][pos]))
1410 {
1411 char lli = ' ';
1412 char snr = ' ';
1413 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1414 {
1415 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1416 lli = '1';
1417 snr = '0'+Parser->Data.snrL1[i];
1418 }
1419 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1420 {
1421 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1422 lli = '1';
1423 snr = '0'+Parser->Data.snrL2[i];
1424 }
1425 RTCM3Text("%14.3f%c%c",
1426 Parser->Data.measdata[i][pos],lli,snr);
1427 }
1428 else
1429 { /* no or illegal data */
1430 RTCM3Text(" ");
1431 }
1432 }
1433 }
1434 RTCM3Text("\n");
1435 }
1436 }
1437 else
1438 {
1439 RTCM3Text(" %02d %2d %2d %2d %2d %10.7f 0%3d",
1440 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
1441 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1442 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
1443 {
1444 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1445 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1446 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1447 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1448 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1449 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1450 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1451 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1452 else
1453 RTCM3Text("%3d", Parser->Data.satellites[i]);
1454 }
1455 RTCM3Text("\n");
1456 o = 12;
1457 j = Parser->Data.numsats - 12;
1458 while(j > 0)
1459 {
1460 RTCM3Text(" ");
1461 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
1462 {
1463 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1464 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1465 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1466 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1467 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1468 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1469 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1470 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1471 else
1472 RTCM3Text("%3d", Parser->Data.satellites[i]);
1473 }
1474 RTCM3Text("\n");
1475 j -= 12;
1476 o += 12;
1477 }
1478 for(i = 0; i < Parser->Data.numsats; ++i)
1479 {
1480 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1481 {
1482 int v = 0;
1483 int df = Parser->dataflag[j];
1484 int pos = Parser->datapos[j];
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 else
1492 {
1493 df = Parser->dataflagGPS[j];
1494 pos = Parser->dataposGPS[j];
1495
1496 if((Parser->Data.dataflags[i] & df)
1497 && !isnan(Parser->Data.measdata[i][pos])
1498 && !isinf(Parser->Data.measdata[i][pos]))
1499 {
1500 v = 1;
1501 }
1502 }
1503
1504 if(!v)
1505 { /* no or illegal data */
1506 RTCM3Text(" ");
1507 }
1508 else
1509 {
1510 char lli = ' ';
1511 char snr = ' ';
1512 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1513 {
1514 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1515 lli = '1';
1516 snr = '0'+Parser->Data.snrL1[i];
1517 }
1518 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1519 {
1520 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1521 lli = '1';
1522 snr = '0'+Parser->Data.snrL2[i];
1523 }
1524 RTCM3Text("%14.3f%c%c",
1525 Parser->Data.measdata[i][pos],lli,snr);
1526 }
1527 if(j%5 == 4 || j == Parser->numdatatypesGPS-1)
1528 RTCM3Text("\n");
1529 }
1530 }
1531 }
1532 }
1533 }
1534 }
1535}
1536
1537#ifndef NO_RTCM3_MAIN
1538static char datestr[] = "$Date: 2007/10/25 09:37:42 $";
1539
1540/* The string, which is send as agent in HTTP request */
1541#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
1542
1543#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
1544
1545static const char encodingTable [64] = {
1546 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1547 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1548 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1549 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1550};
1551
1552/* does not buffer overrun, but breaks directly after an error */
1553/* returns the number of required bytes */
1554static int encode(char *buf, int size, const char *user, const char *pwd)
1555{
1556 unsigned char inbuf[3];
1557 char *out = buf;
1558 int i, sep = 0, fill = 0, bytes = 0;
1559
1560 while(*user || *pwd)
1561 {
1562 i = 0;
1563 while(i < 3 && *user) inbuf[i++] = *(user++);
1564 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1565 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1566 while(i < 3) {inbuf[i++] = 0; ++fill; }
1567 if(out-buf < size-1)
1568 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1569 if(out-buf < size-1)
1570 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1571 | ((inbuf [1] & 0xF0) >> 4)];
1572 if(out-buf < size-1)
1573 {
1574 if(fill == 2)
1575 *(out++) = '=';
1576 else
1577 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1578 | ((inbuf [2] & 0xC0) >> 6)];
1579 }
1580 if(out-buf < size-1)
1581 {
1582 if(fill >= 1)
1583 *(out++) = '=';
1584 else
1585 *(out++) = encodingTable[inbuf [2] & 0x3F];
1586 }
1587 bytes += 4;
1588 }
1589 if(out-buf < size)
1590 *out = 0;
1591 return bytes;
1592}
1593
1594static int stop = 0;
1595
1596struct Args
1597{
1598 const char *server;
1599 const char *port;
1600 int mode;
1601 int timeout;
1602 int rinex3;
1603 const char *user;
1604 const char *password;
1605 const char *proxyhost;
1606 const char *proxyport;
1607 const char *nmea;
1608 const char *data;
1609 const char *headerfile;
1610 const char *gpsephemeris;
1611 const char *glonassephemeris;
1612};
1613
1614/* option parsing */
1615#ifdef NO_LONG_OPTS
1616#define LONG_OPT(a)
1617#else
1618#define LONG_OPT(a) a
1619static struct option opts[] = {
1620{ "data", required_argument, 0, 'd'},
1621{ "server", required_argument, 0, 's'},
1622{ "password", required_argument, 0, 'p'},
1623{ "port", required_argument, 0, 'r'},
1624{ "timeout", required_argument, 0, 't'},
1625{ "header", required_argument, 0, 'f'},
1626{ "user", required_argument, 0, 'u'},
1627{ "gpsephemeris", required_argument, 0, 'E'},
1628{ "glonassephemeris", required_argument, 0, 'G'},
1629{ "rinex3", no_argument, 0, '3'},
1630{ "proxyport", required_argument, 0, 'R'},
1631{ "proxyhost", required_argument, 0, 'S'},
1632{ "nmea", required_argument, 0, 'n'},
1633{ "mode", required_argument, 0, 'M'},
1634{ "help", no_argument, 0, 'h'},
1635{0,0,0,0}};
1636#endif
1637#define ARGOPT "-d:s:p:r:t:f:u:E:G:M:S:R:n:h3"
1638
1639enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };
1640
1641static const char *geturl(const char *url, struct Args *args)
1642{
1643 static char buf[1000];
1644 static char *Buffer = buf;
1645 static char *Bufend = buf+sizeof(buf);
1646
1647 if(strncmp("ntrip:", url, 6))
1648 return "URL must start with 'ntrip:'.";
1649 url += 6; /* skip ntrip: */
1650
1651 if(*url != '@' && *url != '/')
1652 {
1653 /* scan for mountpoint */
1654 args->data = Buffer;
1655 while(*url && *url != '@' && *url != ';' &&*url != '/' && Buffer != Bufend)
1656 *(Buffer++) = *(url++);
1657 if(Buffer == args->data)
1658 return "Mountpoint required.";
1659 else if(Buffer >= Bufend-1)
1660 return "Parsing buffer too short.";
1661 *(Buffer++) = 0;
1662 }
1663
1664 if(*url == '/') /* username and password */
1665 {
1666 ++url;
1667 args->user = Buffer;
1668 while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
1669 *(Buffer++) = *(url++);
1670 if(Buffer == args->user)
1671 return "Username cannot be empty.";
1672 else if(Buffer >= Bufend-1)
1673 return "Parsing buffer too short.";
1674 *(Buffer++) = 0;
1675
1676 if(*url == ':') ++url;
1677
1678 args->password = Buffer;
1679 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1680 *(Buffer++) = *(url++);
1681 if(Buffer == args->password)
1682 return "Password cannot be empty.";
1683 else if(Buffer >= Bufend-1)
1684 return "Parsing buffer too short.";
1685 *(Buffer++) = 0;
1686 }
1687
1688 if(*url == '@') /* server */
1689 {
1690 ++url;
1691 if(*url != '@' && *url != ':')
1692 {
1693 args->server = Buffer;
1694 while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
1695 *(Buffer++) = *(url++);
1696 if(Buffer == args->server)
1697 return "Servername cannot be empty.";
1698 else if(Buffer >= Bufend-1)
1699 return "Parsing buffer too short.";
1700 *(Buffer++) = 0;
1701 }
1702
1703 if(*url == ':')
1704 {
1705 ++url;
1706 args->port = Buffer;
1707 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1708 *(Buffer++) = *(url++);
1709 if(Buffer == args->port)
1710 return "Port cannot be empty.";
1711 else if(Buffer >= Bufend-1)
1712 return "Parsing buffer too short.";
1713 *(Buffer++) = 0;
1714 }
1715
1716 if(*url == '@') /* proxy */
1717 {
1718 ++url;
1719 args->proxyhost = Buffer;
1720 while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
1721 *(Buffer++) = *(url++);
1722 if(Buffer == args->proxyhost)
1723 return "Proxy servername cannot be empty.";
1724 else if(Buffer >= Bufend-1)
1725 return "Parsing buffer too short.";
1726 *(Buffer++) = 0;
1727
1728 if(*url == ':')
1729 {
1730 ++url;
1731 args->proxyport = Buffer;
1732 while(*url && *url != ';' && Buffer != Bufend)
1733 *(Buffer++) = *(url++);
1734 if(Buffer == args->proxyport)
1735 return "Proxy port cannot be empty.";
1736 else if(Buffer >= Bufend-1)
1737 return "Parsing buffer too short.";
1738 *(Buffer++) = 0;
1739 }
1740 }
1741 }
1742 if(*url == ';') /* NMEA */
1743 {
1744 args->nmea = ++url;
1745 while(*url)
1746 ++url;
1747 }
1748
1749 return *url ? "Garbage at end of server string." : 0;
1750}
1751
1752static int getargs(int argc, char **argv, struct Args *args)
1753{
1754 int res = 1;
1755 int getoptr;
1756 int help = 0;
1757 char *t;
1758
1759 args->server = "www.euref-ip.net";
1760 args->port = "2101";
1761 args->timeout = 60;
1762 args->user = "";
1763 args->password = "";
1764 args->data = 0;
1765 args->headerfile = 0;
1766 args->gpsephemeris = 0;
1767 args->glonassephemeris = 0;
1768 args->rinex3 = 0;
1769 args->nmea = 0;
1770 args->proxyhost = 0;
1771 args->proxyport = "2101";
1772 args->mode = AUTO;
1773 help = 0;
1774
1775 do
1776 {
1777
1778#ifdef NO_LONG_OPTS
1779 switch((getoptr = getopt(argc, argv, ARGOPT)))
1780#else
1781 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
1782#endif
1783 {
1784 case 's': args->server = optarg; break;
1785 case 'u': args->user = optarg; break;
1786 case 'p': args->password = optarg; break;
1787 case 'd': args->data = optarg; break;
1788 case 'f': args->headerfile = optarg; break;
1789 case 'E': args->gpsephemeris = optarg; break;
1790 case 'G': args->glonassephemeris = optarg; break;
1791 case 'r': args->port = optarg; break;
1792 case '3': args->rinex3 = 1; break;
1793 case 'S': args->proxyhost = optarg; break;
1794 case 'n': args->nmea = optarg; break;
1795 case 'R': args->proxyport = optarg; break;
1796 case 'h': help=1; break;
1797 case 'M':
1798 args->mode = 0;
1799 if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
1800 args->mode = NTRIP1;
1801 else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
1802 args->mode = HTTP;
1803 else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
1804 args->mode = RTSP;
1805 else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
1806 args->mode = AUTO;
1807 else args->mode = atoi(optarg);
1808 if((args->mode == 0) || (args->mode >= END))
1809 {
1810 fprintf(stderr, "Mode %s unknown\n", optarg);
1811 res = 0;
1812 }
1813 break;
1814 case 't':
1815 args->timeout = strtoul(optarg, &t, 10);
1816 if((t && *t) || args->timeout < 0)
1817 res = 0;
1818 break;
1819
1820 case 1:
1821 {
1822 const char *err;
1823 if((err = geturl(optarg, args)))
1824 {
1825 RTCM3Error("%s\n\n", err);
1826 res = 0;
1827 }
1828 }
1829 break;
1830 case -1: break;
1831 }
1832 } while(getoptr != -1 || !res);
1833
1834 datestr[0] = datestr[7];
1835 datestr[1] = datestr[8];
1836 datestr[2] = datestr[9];
1837 datestr[3] = datestr[10];
1838 datestr[5] = datestr[12];
1839 datestr[6] = datestr[13];
1840 datestr[8] = datestr[15];
1841 datestr[9] = datestr[16];
1842 datestr[4] = datestr[7] = '-';
1843 datestr[10] = 0;
1844
1845 if(args->gpsephemeris && args->glonassephemeris && args->rinex3)
1846 {
1847 RTCM3Error("RINEX3 produces a combined ephemeris file, but 2 files were specified.\n"
1848 "Please specify only one navigation file.\n");
1849 res = 0;
1850 }
1851 else if(!res || help)
1852 {
1853 RTCM3Error("Version %s (%s) GPL" COMPILEDATE
1854 "\nUsage: %s -s server -u user ...\n"
1855 " -d " LONG_OPT("--data ") "the requested data set\n"
1856 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
1857 " -s " LONG_OPT("--server ") "the server name or address\n"
1858 " -p " LONG_OPT("--password ") "the login password\n"
1859 " -r " LONG_OPT("--port ") "the server port number (default 2101)\n"
1860 " -t " LONG_OPT("--timeout ") "timeout in seconds (default 60)\n"
1861 " -u " LONG_OPT("--user ") "the user name\n"
1862 " -E " LONG_OPT("--gpsephemeris ") "output file for GPS ephemeris data\n"
1863 " -G " LONG_OPT("--glonassephemeris ") "output file for GLONASS ephemeris data\n"
1864 " -3 " LONG_OPT("--rinex3 ") "output RINEX type 3 data\n"
1865 " -S " LONG_OPT("--proxyhost ") "proxy name or address\n"
1866 " -R " LONG_OPT("--proxyport ") "proxy port, optional (default 2101)\n"
1867 " -n " LONG_OPT("--nmea ") "NMEA string for sending to server\n"
1868 " -M " LONG_OPT("--mode ") "mode for data request\n"
1869 " Valid modes are:\n"
1870 " 1, h, http NTRIP Version 2.0 Caster in TCP/IP mode\n"
1871 " 2, r, rtsp NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
1872 " 3, n, ntrip1 NTRIP Version 1.0 Caster\n"
1873 " 4, a, auto automatic detection (default)\n"
1874 "or using an URL:\n%s ntrip:data[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
1875 , revisionstr, datestr, argv[0], argv[0]);
1876 exit(1);
1877 }
1878 return res;
1879}
1880
1881/* let the output complete a block if necessary */
1882static void signalhandler(int sig)
1883{
1884 if(!stop)
1885 {
1886 RTCM3Error("Stop signal number %d received. "
1887 "Trying to terminate gentle.\n", sig);
1888 stop = 1;
1889 alarm(1);
1890 }
1891}
1892
1893#define ALARMTIME (2*60)
1894
1895/* for some reason we had to abort hard (maybe waiting for data */
1896#ifdef __GNUC__
1897static __attribute__ ((noreturn)) void signalhandler_alarm(
1898int sig __attribute__((__unused__)))
1899#else /* __GNUC__ */
1900static void signalhandler_alarm(int sig)
1901#endif /* __GNUC__ */
1902{
1903 RTCM3Error("Programm forcefully terminated.\n");
1904 exit(1);
1905}
1906
1907int main(int argc, char **argv)
1908{
1909 struct Args args;
1910 struct RTCM3ParserData Parser;
1911
1912 setbuf(stdout, 0);
1913 setbuf(stdin, 0);
1914 setbuf(stderr, 0);
1915
1916 {
1917 char *a;
1918 int i=0;
1919 for(a = revisionstr+11; *a && *a != ' '; ++a)
1920 revisionstr[i++] = *a;
1921 revisionstr[i] = 0;
1922 }
1923
1924 signal(SIGINT, signalhandler);
1925 signal(SIGALRM,signalhandler_alarm);
1926 signal(SIGQUIT,signalhandler);
1927 signal(SIGTERM,signalhandler);
1928 signal(SIGPIPE,signalhandler);
1929 memset(&Parser, 0, sizeof(Parser));
1930 {
1931 time_t tim;
1932 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
1933 Parser.GPSWeek = tim/(7*24*60*60);
1934 Parser.GPSTOW = tim%(7*24*60*60);
1935 }
1936
1937 if(getargs(argc, argv, &args))
1938 {
1939 int sockfd, numbytes;
1940 char buf[MAXDATASIZE];
1941 struct sockaddr_in their_addr; /* connector's address information */
1942 struct hostent *he;
1943 struct servent *se;
1944 const char *server, *port, *proxyserver = 0;
1945 char proxyport[6];
1946 char *b;
1947 long i;
1948 struct timeval tv;
1949
1950 alarm(ALARMTIME);
1951
1952 Parser.headerfile = args.headerfile;
1953 Parser.glonassephemeris = args.glonassephemeris;
1954 Parser.gpsephemeris = args.gpsephemeris;
1955 Parser.rinex3 = args.rinex3;
1956
1957 if(args.proxyhost)
1958 {
1959 int p;
1960 if((i = strtol(args.port, &b, 10)) && (!b || !*b))
1961 p = i;
1962 else if(!(se = getservbyname(args.port, 0)))
1963 {
1964 RTCM3Error("Can't resolve port %s.", args.port);
1965 exit(1);
1966 }
1967 else
1968 {
1969 p = ntohs(se->s_port);
1970 }
1971 snprintf(proxyport, sizeof(proxyport), "%d", p);
1972 port = args.proxyport;
1973 proxyserver = args.server;
1974 server = args.proxyhost;
1975 }
1976 else
1977 {
1978 server = args.server;
1979 port = args.port;
1980 }
1981
1982 memset(&their_addr, 0, sizeof(struct sockaddr_in));
1983 if((i = strtol(port, &b, 10)) && (!b || !*b))
1984 their_addr.sin_port = htons(i);
1985 else if(!(se = getservbyname(port, 0)))
1986 {
1987 RTCM3Error("Can't resolve port %s.", port);
1988 exit(1);
1989 }
1990 else
1991 {
1992 their_addr.sin_port = se->s_port;
1993 }
1994 if(!(he=gethostbyname(server)))
1995 {
1996 RTCM3Error("Server name lookup failed for '%s'.\n", server);
1997 exit(1);
1998 }
1999 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
2000 {
2001 perror("socket");
2002 exit(1);
2003 }
2004
2005 tv.tv_sec = args.timeout;
2006 tv.tv_usec = 0;
2007 if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval) ) == -1)
2008 {
2009 RTCM3Error("Function setsockopt: %s\n", strerror(errno));
2010 exit(1);
2011 }
2012
2013 their_addr.sin_family = AF_INET;
2014 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2015
2016 if(args.data && args.mode == RTSP)
2017 {
2018 struct sockaddr_in local;
2019 int sockudp, localport;
2020 int cseq = 1;
2021 socklen_t len;
2022
2023 if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
2024 {
2025 perror("socket");
2026 exit(1);
2027 }
2028 /* fill structure with local address information for UDP */
2029 memset(&local, 0, sizeof(local));
2030 local.sin_family = AF_INET;
2031 local.sin_port = htons(0);
2032 local.sin_addr.s_addr = htonl(INADDR_ANY);
2033 len = sizeof(local);
2034 /* bind() in order to get a random RTP client_port */
2035 if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
2036 {
2037 perror("bind");
2038 exit(1);
2039 }
2040 if((getsockname(sockudp, (struct sockaddr*)&local, &len)) != -1)
2041 {
2042 localport = ntohs(local.sin_port);
2043 }
2044 else
2045 {
2046 perror("local access failed");
2047 exit(1);
2048 }
2049 if(connect(sockfd, (struct sockaddr *)&their_addr,
2050 sizeof(struct sockaddr)) == -1)
2051 {
2052 perror("connect");
2053 exit(1);
2054 }
2055 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2056 "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"
2057 "CSeq: %d\r\n"
2058 "Ntrip-Version: Ntrip/2.0\r\n"
2059 "Ntrip-Component: Ntripclient\r\n"
2060 "User-Agent: %s/%s\r\n"
2061 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
2062 "Authorization: Basic ",
2063 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2064 args.data, cseq++, AGENTSTRING, revisionstr, localport);
2065 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
2066 {
2067 RTCM3Error("Requested data too long\n");
2068 exit(1);
2069 }
2070 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
2071 if(i > MAXDATASIZE-4)
2072 {
2073 RTCM3Error("Username and/or password too long\n");
2074 exit(1);
2075 }
2076 buf[i++] = '\r';
2077 buf[i++] = '\n';
2078 buf[i++] = '\r';
2079 buf[i++] = '\n';
2080 if(args.nmea)
2081 {
2082 int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
2083 if(j >= 0 && j < MAXDATASIZE-i)
2084 i += j;
2085 else
2086 {
2087 RTCM3Error("NMEA string too long\n");
2088 exit(1);
2089 }
2090 }
2091 if(send(sockfd, buf, (size_t)i, 0) != i)
2092 {
2093 perror("send");
2094 exit(1);
2095 }
2096 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2097 {
2098 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2099 {
2100 int serverport = 0, session = 0;
2101 const char *portcheck = "server_port=";
2102 const char *sessioncheck = "session: ";
2103 int l = strlen(portcheck)-1;
2104 int j=0;
2105 for(i = 0; j != l && i < numbytes-l; ++i)
2106 {
2107 for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
2108 ;
2109 }
2110 if(i == numbytes-l)
2111 {
2112 RTCM3Error("No server port number found\n");
2113 exit(1);
2114 }
2115 else
2116 {
2117 i+=l;
2118 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2119 serverport = serverport * 10 + buf[i++]-'0';
2120 if(buf[i] != '\r' && buf[i] != ';')
2121 {
2122 RTCM3Error("Could not extract server port\n");
2123 exit(1);
2124 }
2125 }
2126 l = strlen(sessioncheck)-1;
2127 j=0;
2128 for(i = 0; j != l && i < numbytes-l; ++i)
2129 {
2130 for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
2131 ;
2132 }
2133 if(i == numbytes-l)
2134 {
2135 RTCM3Error("No session number found\n");
2136 exit(1);
2137 }
2138 else
2139 {
2140 i+=l;
2141 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2142 session = session * 10 + buf[i++]-'0';
2143 if(buf[i] != '\r')
2144 {
2145 RTCM3Error("Could not extract session number\n");
2146 exit(1);
2147 }
2148 }
2149
2150 i = snprintf(buf, MAXDATASIZE,
2151 "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"
2152 "CSeq: %d\r\n"
2153 "Session: %d\r\n"
2154 "\r\n",
2155 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2156 args.data, cseq++, session);
2157
2158 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2159 {
2160 RTCM3Error("Requested data too long\n");
2161 exit(1);
2162 }
2163 if(send(sockfd, buf, (size_t)i, 0) != i)
2164 {
2165 perror("send");
2166 exit(1);
2167 }
2168 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2169 {
2170 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2171 {
2172 struct sockaddr_in addrRTP;
2173 /* fill structure with caster address information for UDP */
2174 memset(&addrRTP, 0, sizeof(addrRTP));
2175 addrRTP.sin_family = AF_INET;
2176 addrRTP.sin_port = htons(serverport);
2177 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2178 len = sizeof(addrRTP);
2179 int ts = 0;
2180 int sn = 0;
2181 int ssrc = 0;
2182 int init = 0;
2183 int u, v, w;
2184 while(!stop && (i = recvfrom(sockudp, buf, 1526, 0,
2185 (struct sockaddr*) &addrRTP, &len)) > 0)
2186 {
2187 alarm(ALARMTIME);
2188 if(i >= 12+1 && (unsigned char)buf[0] == (2 << 6) && buf[1] == 0x60)
2189 {
2190 u= ((unsigned char)buf[2]<<8)+(unsigned char)buf[3];
2191 v = ((unsigned char)buf[4]<<24)+((unsigned char)buf[5]<<16)
2192 +((unsigned char)buf[6]<<8)+(unsigned char)buf[7];
2193 w = ((unsigned char)buf[8]<<24)+((unsigned char)buf[9]<<16)
2194 +((unsigned char)buf[10]<<8)+(unsigned char)buf[11];
2195
2196 if(init)
2197 {
2198 if(u < -30000 && sn > 30000) sn -= 0xFFFF;
2199 if(ssrc != w || ts > v)
2200 {
2201 RTCM3Error("Illegal UDP data received.\n");
2202 exit(1);
2203 }
2204 if(u > sn) /* don't show out-of-order packets */
2205 fwrite(buf+12, (size_t)i-12, 1, stdout);
2206 }
2207 sn = u; ts = v; ssrc = w; init = 1;
2208 }
2209 else
2210 {
2211 RTCM3Error("Illegal UDP header.\n");
2212 exit(1);
2213 }
2214 }
2215 }
2216 i = snprintf(buf, MAXDATASIZE,
2217 "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"
2218 "CSeq: %d\r\n"
2219 "Session: %d\r\n"
2220 "\r\n",
2221 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2222 args.data, cseq++, session);
2223
2224 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2225 {
2226 RTCM3Error("Requested data too long\n");
2227 exit(1);
2228 }
2229 if(send(sockfd, buf, (size_t)i, 0) != i)
2230 {
2231 perror("send");
2232 exit(1);
2233 }
2234 }
2235 else
2236 {
2237 RTCM3Error("Could not start data stream.\n");
2238 exit(1);
2239 }
2240 }
2241 else
2242 {
2243 RTCM3Error("Could not setup initial control connection.\n");
2244 exit(1);
2245 }
2246 }
2247 else
2248 {
2249 perror("recv");
2250 exit(1);
2251 }
2252 }
2253 else
2254 {
2255 if(connect(sockfd, (struct sockaddr *)&their_addr,
2256 sizeof(struct sockaddr)) == -1)
2257 {
2258 perror("connect");
2259 exit(1);
2260 }
2261 if(!args.data)
2262 {
2263 i = snprintf(buf, MAXDATASIZE,
2264 "GET %s%s%s%s/ HTTP/1.0\r\n"
2265 "Host: %s\r\n%s"
2266 "User-Agent: %s/%s\r\n"
2267 "\r\n"
2268 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
2269 proxyserver ? ":" : "", proxyserver ? proxyport : "",
2270 args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
2271 AGENTSTRING, revisionstr);
2272 }
2273 else
2274 {
2275 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2276 "GET %s%s%s%s/%s HTTP/1.0\r\n"
2277 "Host: %s\r\n%s"
2278 "User-Agent: %s/%s\r\n"
2279 "Authorization: Basic "
2280 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
2281 proxyserver ? ":" : "", proxyserver ? proxyport : "",
2282 args.data, args.server,
2283 args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
2284 AGENTSTRING, revisionstr);
2285 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
2286 {
2287 RTCM3Error("Requested data too long\n");
2288 exit(1);
2289 }
2290 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
2291 if(i > MAXDATASIZE-4)
2292 {
2293 RTCM3Error("Username and/or password too long\n");
2294 exit(1);
2295 }
2296 buf[i++] = '\r';
2297 buf[i++] = '\n';
2298 buf[i++] = '\r';
2299 buf[i++] = '\n';
2300 if(args.nmea)
2301 {
2302 int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
2303 if(j >= 0 && j < MAXDATASIZE-i)
2304 i += j;
2305 else
2306 {
2307 RTCM3Error("NMEA string too long\n");
2308 exit(1);
2309 }
2310 }
2311 }
2312 if(send(sockfd, buf, (size_t)i, 0) != i)
2313 {
2314 perror("send");
2315 exit(1);
2316 }
2317 if(args.data)
2318 {
2319 int k = 0;
2320 int chunkymode = 0;
2321 int starttime = time(0);
2322 int lastout = starttime;
2323 int totalbytes = 0;
2324 int chunksize = 0;
2325
2326 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2327 {
2328 alarm(ALARMTIME);
2329 if(!k)
2330 {
2331 if(numbytes > 17 && (!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17)
2332 || !strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)))
2333 {
2334 const char *datacheck = "Content-Type: gnss/data\r\n";
2335 const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
2336 int l = strlen(datacheck)-1;
2337 int j=0;
2338 for(i = 0; j != l && i < numbytes-l; ++i)
2339 {
2340 for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
2341 ;
2342 }
2343 if(i == numbytes-l)
2344 {
2345 RTCM3Error("No 'Content-Type: gnss/data' found\n");
2346 exit(1);
2347 }
2348 l = strlen(chunkycheck)-1;
2349 j=0;
2350 for(i = 0; j != l && i < numbytes-l; ++i)
2351 {
2352 for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
2353 ;
2354 }
2355 if(i < numbytes-l)
2356 chunkymode = 1;
2357 }
2358 else if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
2359 {
2360 RTCM3Error("Could not get the requested data: ");
2361 for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
2362 {
2363 RTCM3Error("%c", isprint(buf[k]) ? buf[k] : '.');
2364 }
2365 RTCM3Error("\n");
2366 exit(1);
2367 }
2368 else if(args.mode != NTRIP1)
2369 {
2370 if(args.mode != AUTO)
2371 {
2372 RTCM3Error("NTRIP version 2 HTTP connection failed%s.\n",
2373 args.mode == AUTO ? ", falling back to NTRIP1" : "");
2374 }
2375 if(args.mode == HTTP)
2376 exit(1);
2377 }
2378 ++k;
2379 }
2380 else
2381 {
2382 if(chunkymode)
2383 {
2384 int stop = 0;
2385 int pos = 0;
2386 while(!stop && pos < numbytes)
2387 {
2388 switch(chunkymode)
2389 {
2390 case 1: /* reading number starts */
2391 chunksize = 0;
2392 ++chunkymode; /* no break */
2393 case 2: /* during reading number */
2394 i = buf[pos++];
2395 if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
2396 else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
2397 else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
2398 else if(i == '\r') ++chunkymode;
2399 else stop = 1;
2400 break;
2401 case 3: /* scanning for return */
2402 if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
2403 else stop = 1;
2404 break;
2405 case 4: /* output data */
2406 i = numbytes-pos;
2407 if(i > chunksize) i = chunksize;
2408 {
2409 int z;
2410 for(z = 0; z < i && !stop; ++z)
2411 HandleByte(&Parser, (unsigned int) buf[pos+z]);
2412 }
2413 totalbytes += i;
2414 chunksize -= i;
2415 pos += i;
2416 if(!chunksize)
2417 chunkymode = 1;
2418 break;
2419 }
2420 }
2421 if(stop)
2422 {
2423 RTCM3Error("Error in chunky transfer encoding\n");
2424 break;
2425 }
2426 }
2427 else
2428 {
2429 totalbytes += numbytes;
2430 {
2431 int z;
2432 for(z = 0; z < numbytes && !stop; ++z)
2433 HandleByte(&Parser, (unsigned int) buf[z]);
2434 }
2435 }
2436 if(totalbytes < 0) /* overflow */
2437 {
2438 totalbytes = 0;
2439 starttime = time(0);
2440 lastout = starttime;
2441 }
2442 }
2443 }
2444 }
2445 else
2446 {
2447 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
2448 {
2449 alarm(ALARMTIME);
2450 fwrite(buf, (size_t)numbytes, 1, stdout);
2451 }
2452 }
2453 close(sockfd);
2454 }
2455 }
2456 return 0;
2457}
2458#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.