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

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

switched to port 2101

File size: 37.5 KB
Line 
1/*
2 Converter for RTCM3 data to RINEX.
3 $Id: rtcm3torinex.c,v 1.11 2006/11/21 08:27:35 stoecker Exp $
4 Copyright (C) 2005-2006 by Dirk Stoecker <stoecker@euronik.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.11 $";
54
55static uint32_t CRC24(long size, const unsigned char *buf)
56{
57 uint32_t crc = 0;
58 int i;
59
60 while(size--)
61 {
62 crc ^= (*buf++) << (16);
63 for(i = 0; i < 8; i++)
64 {
65 crc <<= 1;
66 if(crc & 0x1000000)
67 crc ^= 0x01864cfb;
68 }
69 }
70 return crc;
71}
72
73static int GetMessage(struct RTCM3ParserData *handle)
74{
75 unsigned char *m, *e;
76 int i;
77
78 m = handle->Message+handle->SkipBytes;
79 e = handle->Message+handle->MessageSize;
80 handle->NeedBytes = handle->SkipBytes = 0;
81 while(e-m >= 3)
82 {
83 if(m[0] == 0xD3)
84 {
85 handle->size = ((m[1]&3)<<8)|m[2];
86 if(e-m >= handle->size+6)
87 {
88 if((uint32_t)((m[3+handle->size]<<16)|(m[3+handle->size+1]<<8)
89 |(m[3+handle->size+2])) == CRC24(handle->size+3, m))
90 {
91 handle->SkipBytes = handle->size;
92 break;
93 }
94 else
95 ++m;
96 }
97 else
98 {
99 handle->NeedBytes = handle->size+6;
100 break;
101 }
102 }
103 else
104 ++m;
105 }
106 if(e-m < 3)
107 handle->NeedBytes = 3;
108
109 /* copy buffer to front */
110 i = m - handle->Message;
111 if(i && m < e)
112 memmove(handle->Message, m, (size_t)(handle->MessageSize-i));
113 handle->MessageSize -= i;
114
115 return !handle->NeedBytes;
116}
117
118#define LOADBITS(a) \
119{ \
120 while((a) > numbits) \
121 { \
122 if(!size--) break; \
123 bitfield = (bitfield<<8)|*(data++); \
124 numbits += 8; \
125 } \
126}
127
128/* extract bits from data stream
129 b = variable to store result, a = number of bits */
130#define GETBITS(b, a) \
131{ \
132 LOADBITS(a) \
133 b = (bitfield<<(64-numbits))>>(64-(a)); \
134 numbits -= (a); \
135}
136
137/* extract bits from data stream
138 b = variable to store result, a = number of bits */
139#define GETBITSSIGN(b, a) \
140{ \
141 LOADBITS(a) \
142 b = ((int64_t)(bitfield<<(64-numbits)))>>(64-(a)); \
143 numbits -= (a); \
144}
145
146#define SKIPBITS(b) { LOADBITS(b) numbits -= (b); }
147
148struct leapseconds { /* specify the day of leap second */
149 int day; /* this is the day, where 23:59:59 exists 2 times */
150 int month; /* not the next day! */
151 int year;
152 int taicount;
153};
154static const int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
155static const struct leapseconds leap[] = {
156/*{31, 12, 1971, 11},*/
157/*{31, 12, 1972, 12},*/
158/*{31, 12, 1973, 13},*/
159/*{31, 12, 1974, 14},*/
160/*{31, 12, 1975, 15},*/
161/*{31, 12, 1976, 16},*/
162/*{31, 12, 1977, 17},*/
163/*{31, 12, 1978, 18},*/
164/*{31, 12, 1979, 19},*/
165{30, 06, 1981,20},
166{30, 06, 1982,21},
167{30, 06, 1983,22},
168{30, 06, 1985,23},
169{31, 12, 1987,24},
170{31, 12, 1989,25},
171{31, 12, 1990,26},
172{30, 06, 1992,27},
173{30, 06, 1993,28},
174{30, 06, 1994,29},
175{31, 12, 1995,30},
176{30, 06, 1997,31},
177{31, 12, 1998,32},
178{31, 12, 2005,33},
179{0,0,0,0} /* end marker */
180};
181#define GPSLEAPSTART 19 /* 19 leap seconds existed at 6.1.1980 */
182
183static int longyear(int year, int month)
184{
185 if(!(year % 4) && (!(year % 400) || (year % 100)))
186 {
187 if(!month || month == 2)
188 return 1;
189 }
190 return 0;
191}
192
193static int gnumleap(int year, int month, int day)
194{
195 int ls = 0;
196 const struct leapseconds *l;
197
198 for(l = leap; l->taicount && year >= l->year; ++l)
199 {
200 if(year > l->year || month > l->month || day > l->day)
201 ls = l->taicount - GPSLEAPSTART;
202 }
203 return ls;
204}
205
206static void updatetime(int *week, int *tow, int tk)
207{
208 int y,m,d,k,l;
209 unsigned int j = *week*(7*24*60*60) + *tow + 5*24*60*60+3*60*60;
210 int glo_daynumber = 0, glo_timeofday;
211 for(y = 1980; j >= (unsigned int)(k = (l = (365+longyear(y,0)))*24*60*60)
212 + gnumleap(y+1,1,1); ++y)
213 {
214 j -= k; glo_daynumber += l;
215 }
216 for(m = 1; j >= (unsigned int)(k = (l = months[m]+longyear(y, m))*24*60*60)
217 + gnumleap(y, m+1, 1); ++m)
218 {
219 j -= k; glo_daynumber += l;
220 }
221 for(d = 1; j >= 24UL*60UL*60UL + gnumleap(y, m, d+1); ++d)
222 j -= 24*60*60;
223 glo_daynumber -= 16*365+4-d;
224 glo_timeofday = j-gnumleap(y, m, d);
225
226 if(tk < 5*60*1000 && glo_timeofday > 23*60*60)
227 *tow += 24*60*60;
228 else if(glo_timeofday < 5*60 && tk > 23*60*60*1000)
229 *tow -= 24*60*60;
230 *tow += tk/1000-glo_timeofday;
231 if(*tow < 0) {*tow += 24*60*60*7; --*week; }
232 if(*tow >= 24*60*60*7) {*tow -= 24*60*60*7; ++*week; }
233}
234
235int RTCM3Parser(struct RTCM3ParserData *handle)
236{
237 int ret=0;
238
239 while(!ret && GetMessage(handle))
240 {
241 /* using 64 bit integer types, as it is much easier than handling
242 the long datatypes in 32 bit */
243 uint64_t numbits = 0, bitfield = 0;
244 int size = handle->size, type;
245 int syncf, old = 0;
246 unsigned char *data = handle->Message+3;
247
248 GETBITS(type,12)
249 switch(type)
250 {
251 case 1001: case 1002: case 1003: case 1004:
252 if(handle->GPSWeek)
253 {
254 int lastlockl1[64];
255 int lastlockl2[64];
256 struct gnssdata *gnss;
257 int i, num, wasamb=0;
258
259 for(i = 0; i < 64; ++i)
260 lastlockl1[i] = lastlockl2[i] = 0;
261
262 gnss = &handle->DataNew;
263
264 SKIPBITS(12) /* id */
265 GETBITS(i,30)
266 if(i/1000 < (int)handle->GPSTOW - 86400)
267 ++handle->GPSWeek;
268 handle->GPSTOW = i/1000;
269 if(gnss->week && (gnss->timeofweek != i || gnss->week
270 != handle->GPSWeek))
271 {
272 handle->Data = *gnss;
273 memset(gnss, 0, sizeof(*gnss));
274 old = 1;
275 }
276 gnss->timeofweek = i;
277 gnss->week = handle->GPSWeek;
278
279 GETBITS(syncf,1) /* sync */
280 GETBITS(i,5)
281 gnss->numsats = i;
282 SKIPBITS(4) /* smind, smint */
283
284 for(num = 0; num < gnss->numsats; ++num)
285 {
286 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
287
288 GETBITS(sv, 6);
289 gnss->satellites[num] = (sv < 40 ? sv : sv+80);
290 /* L1 */
291 GETBITS(code, 1);
292 if(code)
293 {
294 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
295 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
296 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
297 }
298 else
299 {
300 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
301 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
302 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
303 }
304 GETBITS(l1range, 24);
305 if((l1range&((1<<24)-1)) != 0x80000)
306 {
307 gnss->dataflags[num] |= c;
308 gnss->measdata[num][ce] = l1range*0.02;
309 }
310 GETBITSSIGN(i, 20);
311 if((i&((1<<20)-1)) != 0x80000)
312 {
313 gnss->dataflags[num] |= l;
314 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
315 }
316 GETBITS(i, 7);
317 lastlockl1[sv] = i;
318 if(handle->lastlockl1[sv] > i)
319 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
320 if(type == 1002 || type == 1004)
321 {
322 GETBITS(amb,8);
323 if(amb && (gnss->dataflags[num] & c))
324 {
325 gnss->measdata[num][ce] += amb*299792.458;
326 gnss->measdata[num][le] += amb*299792.458;
327 ++wasamb;
328 }
329 GETBITS(i, 8);
330 if(i)
331 {
332 gnss->dataflags[num] |= s;
333 gnss->measdata[num][se] = i*0.25;
334 i /= 4*4;
335 if(i > 9) i = 9;
336 else if(i < 1) i = 1;
337 gnss->snrL1[num] = i;
338 }
339 }
340 gnss->measdata[num][le] /= GPS_WAVELENGTH_L1;
341 if(type == 1003 || type == 1004)
342 {
343 /* L2 */
344 GETBITS(code,2);
345 if(code)
346 {
347 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
348 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
349 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
350 }
351 else
352 {
353 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
354 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
355 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
356 }
357 GETBITSSIGN(i,14);
358 if((i&((1<<14)-1)) != 0x2000)
359 {
360 gnss->dataflags[num] |= c;
361 gnss->measdata[num][ce] = l1range*0.02+i*0.02
362 +amb*299792.458;
363 }
364 GETBITSSIGN(i,20);
365 if((i&((1<<20)-1)) != 0x80000)
366 {
367 gnss->dataflags[num] |= l;
368 gnss->measdata[num][le] = l1range*0.02+i*0.0005
369 +amb*299792.458;
370 }
371 GETBITS(i,7);
372 lastlockl2[sv] = i;
373 if(handle->lastlockl2[sv] > i)
374 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
375 if(type == 1004)
376 {
377 GETBITS(i, 8);
378 if(i)
379 {
380 gnss->dataflags[num] |= s;
381 gnss->measdata[num][se] = i*0.25;
382 i /= 4*4;
383 if(i > 9) i = 9;
384 else if(i < 1) i = 1;
385 gnss->snrL2[num] = i;
386 }
387 }
388 gnss->measdata[num][le] /= GPS_WAVELENGTH_L2;
389 }
390 }
391 for(i = 0; i < 64; ++i)
392 {
393 handle->lastlockl1[i] = lastlockl1[i];
394 handle->lastlockl2[i] = lastlockl2[i];
395 }
396 if(!syncf && !old)
397 {
398 handle->Data = *gnss;
399 memset(gnss, 0, sizeof(*gnss));
400 }
401 if(!syncf || old)
402 {
403 if(wasamb) /* not RINEX compatible without */
404 ret = 1;
405 else
406 ret = 2;
407 }
408 }
409 break;
410 case 1009: case 1010: case 1011: case 1012:
411 {
412 int lastlockl1[64];
413 int lastlockl2[64];
414 struct gnssdata *gnss;
415 int i, num;
416 int wasamb=0;
417
418 for(i = 0; i < 64; ++i)
419 lastlockl1[i] = lastlockl2[i] = 0;
420
421 gnss = &handle->DataNew;
422
423 SKIPBITS(12) /* id */;
424 GETBITS(i,27) /* tk */
425
426 updatetime(&handle->GPSWeek, &handle->GPSTOW, i);
427 i = handle->GPSTOW*1000;
428 if(gnss->week && (gnss->timeofweek != i || gnss->week
429 != handle->GPSWeek))
430 {
431 handle->Data = *gnss;
432 memset(gnss, 0, sizeof(*gnss));
433 old = 1;
434 }
435
436 gnss->timeofweek = i;
437 gnss->week = handle->GPSWeek;
438
439 GETBITS(syncf,1) /* sync */
440 GETBITS(i,5)
441 gnss->numsats += i;
442
443 SKIPBITS(4) /* smind, smint */
444
445 for(num = gnss->numsats-i; num < gnss->numsats; ++num)
446 {
447 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
448 int freq;
449
450 GETBITS(sv, 6)
451 gnss->satellites[num] = sv-1 + PRN_GLONASS_START;
452 /* L1 */
453 GETBITS(code, 1)
454 GETBITS(freq, 5)
455 if(code)
456 {
457 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
458 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
459 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
460 }
461 else
462 {
463 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
464 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
465 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
466 }
467 GETBITS(l1range, 25)
468 if((l1range&((1<<25)-1)) != 0x80000)
469 {
470 gnss->dataflags[num] |= c;
471 gnss->measdata[num][ce] = l1range*0.02;
472 }
473 GETBITSSIGN(i, 20)
474 if((i&((1<<20)-1)) != 0x80000)
475 {
476 gnss->dataflags[num] |= l;
477 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
478 }
479 GETBITS(i, 7)
480 lastlockl1[sv] = i;
481 if(handle->lastlockl1[sv] > i)
482 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
483 if(type == 1010 || type == 1012)
484 {
485 GETBITS(amb,7)
486 if(amb && (gnss->dataflags[num] & c))
487 {
488 gnss->measdata[num][ce] += amb*599584.916;
489 gnss->measdata[num][le] += amb*599584.916;
490 ++wasamb;
491 }
492 GETBITS(i, 8)
493 if(i)
494 {
495 gnss->dataflags[num] |= s;
496 gnss->measdata[num][se] = i*0.25;
497 i /= 4*4;
498 if(i > 9) i = 9;
499 else if(i < 1) i = 1;
500 gnss->snrL1[num] = i;
501 }
502 }
503 gnss->measdata[num][le] /= GLO_WAVELENGTH_L1(freq-7);
504 if(type == 1011 || type == 1012)
505 {
506 /* L2 */
507 GETBITS(code,2)
508 if(code)
509 {
510 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
511 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
512 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
513 }
514 else
515 {
516 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
517 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
518 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
519 }
520 GETBITSSIGN(i,14)
521 if((i&((1<<14)-1)) != 0x2000)
522 {
523 gnss->dataflags[num] |= c;
524 gnss->measdata[num][ce] = l1range*0.02+i*0.02
525 +amb*599584.916;
526 }
527 GETBITSSIGN(i,20)
528 if((i&((1<<20)-1)) != 0x80000)
529 {
530 gnss->dataflags[num] |= l;
531 gnss->measdata[num][le] = l1range*0.02+i*0.0005
532 +amb*599584.915;
533 }
534 GETBITS(i,7)
535 lastlockl2[sv] = i;
536 if(handle->lastlockl2[sv] > i)
537 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
538 if(type == 1012)
539 {
540 GETBITS(i, 8)
541 if(i)
542 {
543 gnss->dataflags[num] |= s;
544 gnss->measdata[num][se] = i*0.25;
545 i /= 4*4;
546 if(i > 9) i = 9;
547 else if(i < 1) i = 1;
548 gnss->snrL2[num] = i;
549 }
550 }
551 gnss->measdata[num][le] /= GLO_WAVELENGTH_L2(freq-7);
552 }
553 if(!sv || sv > 24)
554 {
555 --num; --gnss->numsats;
556 }
557 }
558 for(i = 0; i < 64; ++i)
559 {
560 handle->lastlockl1[i] = lastlockl1[i];
561 handle->lastlockl2[i] = lastlockl2[i];
562 }
563 if(!syncf && !old)
564 {
565 handle->Data = *gnss;
566 memset(gnss, 0, sizeof(*gnss));
567 }
568 if(!syncf || old)
569 {
570 if(wasamb) /* not RINEX compatible without */
571 ret = 1;
572 else
573 ret = 2;
574 }
575 }
576 break;
577 }
578 }
579 return ret;
580}
581
582struct Header
583{
584 const char *version;
585 const char *pgm;
586 const char *marker;
587 const char *observer;
588 const char *receiver;
589 const char *antenna;
590 const char *position;
591 const char *antennaposition;
592 const char *wavelength;
593 const char *typesofobs; /* should not be modified outside */
594 const char *timeoffirstobs; /* should not be modified outside */
595};
596
597#define MAXHEADERLINES 50
598#define MAXHEADERBUFFERSIZE 4096
599struct HeaderData
600{
601 union
602 {
603 struct Header named;
604 const char *unnamed[MAXHEADERLINES];
605 } data;
606 int numheaders;
607};
608
609struct converttimeinfo {
610 int second; /* seconds of GPS time [0..59] */
611 int minute; /* minutes of GPS time [0..59] */
612 int hour; /* hour of GPS time [0..24] */
613 int day; /* day of GPS time [1..28..30(31)*/
614 int month; /* month of GPS time [1..12]*/
615 int year; /* year of GPS time [1980..] */
616};
617
618static void converttime(struct converttimeinfo *c, int week, int tow)
619{
620 int i, k, doy, j; /* temporary variables */
621 j = week*(7*24*60*60) + tow + 5*24*60*60;
622 for(i = 1980; j >= (k = (365+longyear(i,0))*24*60*60); ++i)
623 j -= k;
624 c->year = i;
625 doy = 1+ (j / (24*60*60));
626 j %= (24*60*60);
627 c->hour = j / (60*60);
628 j %= (60*60);
629 c->minute = j / 60;
630 c->second = j % 60;
631 j = 0;
632 for(i = 1; j + (k = months[i] + longyear(c->year,i)) < doy; ++i)
633 j += k;
634 c->month = i;
635 c->day = doy - j;
636}
637
638#ifndef NO_RTCM3_MAIN
639void RTCM3Error(const char *fmt, ...)
640{
641 va_list v;
642 va_start(v, fmt);
643 vfprintf(stderr, fmt, v);
644 va_end(v);
645}
646#endif
647
648void RTCM3Text(const char *fmt, ...)
649{
650 va_list v;
651 va_start(v, fmt);
652 vprintf(fmt, v);
653 va_end(v);
654}
655
656#define NUMSTARTSKIP 3
657void HandleHeader(struct RTCM3ParserData *Parser)
658{
659 struct HeaderData hdata;
660 char thebuffer[MAXHEADERBUFFERSIZE];
661 char *buffer = thebuffer;
662 size_t buffersize = sizeof(thebuffer);
663 int i;
664
665 hdata.data.named.version =
666 " 2.11 OBSERVATION DATA M (Mixed)"
667 " RINEX VERSION / TYPE";
668
669 {
670 const char *str;
671 time_t t;
672 struct tm * t2;
673
674#ifdef NO_RTCM3_MAIN
675 if(revisionstr[0] == '$')
676 {
677 char *a;
678 int i=0;
679 for(a = revisionstr+11; *a && *a != ' '; ++a)
680 revisionstr[i++] = *a;
681 revisionstr[i] = 0;
682 }
683#endif
684
685 str = getenv("USER");
686 if(!str) str = "";
687 t = time(&t);
688 t2 = gmtime(&t);
689 hdata.data.named.pgm = buffer;
690 i = 1+snprintf(buffer, buffersize,
691 "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d "
692 "PGM / RUN BY / DATE",
693 revisionstr, str, 1900+t2->tm_year, t2->tm_mon+1, t2->tm_mday, t2->tm_hour,
694 t2->tm_min);
695 buffer += i; buffersize -= i;
696
697 hdata.data.named.observer = buffer;
698 i = 1+snprintf(buffer, buffersize,
699 "%-20.20s "
700 "OBSERVER / AGENCY", str);
701 buffer += i; buffersize -= i;
702 }
703
704 hdata.data.named.marker =
705 "RTCM3TORINEX "
706 "MARKER NAME";
707
708 hdata.data.named.receiver =
709 " "
710 "REC # / TYPE / VERS";
711
712 hdata.data.named.antenna =
713 " "
714 "ANT # / TYPE";
715
716 hdata.data.named.position =
717 " .0000 .0000 .0000 "
718 "APPROX POSITION XYZ";
719
720 hdata.data.named.antennaposition =
721 " .0000 .0000 .0000 "
722 "ANTENNA: DELTA H/E/N";
723
724 hdata.data.named.wavelength =
725 " 1 1 "
726 "WAVELENGTH FACT L1/2";
727
728 {
729#define CHECKFLAGS(a, b) \
730 if(flags & GNSSDF_##a##DATA \
731 && !data[RINEXENTRY_##b##DATA]) \
732 { \
733 Parser->dataflag[Parser->numdatatypes] = GNSSDF_##a##DATA; \
734 Parser->datapos[Parser->numdatatypes++] = data[RINEXENTRY_##b##DATA] \
735 = GNSSENTRY_##a##DATA; \
736 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#b); \
737 tbufferpos += 6; \
738 }
739
740 int flags = Parser->startflags;
741 int data[RINEXENTRY_NUMBER];
742 char tbuffer[6*RINEXENTRY_NUMBER+1];
743 int tbufferpos = 0;
744 for(i = 0; i < RINEXENTRY_NUMBER; ++i)
745 data[i] = 0;
746 for(i = 0; i < Parser->Data.numsats; ++i)
747 flags |= Parser->Data.dataflags[i];
748
749 CHECKFLAGS(C1,C1)
750 CHECKFLAGS(C2,C2)
751 CHECKFLAGS(P1,P1)
752 CHECKFLAGS(P2,P2)
753 CHECKFLAGS(L1C,L1)
754 CHECKFLAGS(L1P,L1)
755 CHECKFLAGS(L2C,L2)
756 CHECKFLAGS(L2P,L2)
757 CHECKFLAGS(D1C,D1)
758 CHECKFLAGS(D1P,D1)
759 CHECKFLAGS(D2C,D2)
760 CHECKFLAGS(D2P,D2)
761 CHECKFLAGS(S1C,S1)
762 CHECKFLAGS(S1P,S1)
763 CHECKFLAGS(S2C,S2)
764 CHECKFLAGS(S2P,S2)
765
766 hdata.data.named.typesofobs = buffer;
767 i = 1+snprintf(buffer, buffersize,
768 "%6i%-54.54s# / TYPES OF OBSERV", Parser->numdatatypes, tbuffer);
769 if(Parser->numdatatypes>9)
770 {
771 i += snprintf(buffer+i-1, buffersize,
772 "\n %-54.54s# / TYPES OF OBSERV", tbuffer+9*6);
773 }
774 buffer += i; buffersize -= i;
775 }
776
777 {
778 struct converttimeinfo cti;
779 converttime(&cti, Parser->Data.week,
780 (int)floor(Parser->Data.timeofweek/1000.0));
781 hdata.data.named.timeoffirstobs = buffer;
782 i = 1+snprintf(buffer, buffersize,
783 " %4d %2d %2d %2d %2d %10.7f GPS "
784 "TIME OF FIRST OBS", cti.year%100, cti.month, cti.day, cti.hour,
785 cti.minute, cti.second + fmod(Parser->Data.timeofweek/1000.0,1.0));
786
787 buffer += i; buffersize -= i;
788 }
789
790 hdata.numheaders = 11;
791
792 if(Parser->headerfile)
793 {
794 FILE *fh;
795 if((fh = fopen(Parser->headerfile, "r")))
796 {
797 size_t siz;
798 char *lastblockstart;
799 if((siz = fread(buffer, 1, buffersize-1, fh)) > 0)
800 {
801 buffer[siz] = '\n';
802 if(siz == buffersize)
803 {
804 RTCM3Error("Header file is too large. Only %d bytes read.",
805 siz);
806 }
807 /* scan the file line by line and enter the entries in the list */
808 /* warn for "# / TYPES OF OBSERV" and "TIME OF FIRST OBS" */
809 /* overwrites entries, except for comments */
810 lastblockstart = buffer;
811 for(i = 0; i < (int)siz; ++i)
812 {
813 if(buffer[i] == '\n')
814 { /* we found a line */
815 char *end;
816 while(buffer[i+1] == '\r')
817 ++i; /* skip \r in case there are any */
818 end = buffer+i;
819 while(*end == '\t' || *end == ' ' || *end == '\r' || *end == '\n')
820 *(end--) = 0;
821 if(end-lastblockstart < 60+5) /* short line */
822 RTCM3Error("Short Header line '%s' ignored.\n", lastblockstart);
823 else
824 {
825 int pos;
826 if(!strcmp("COMMENT", lastblockstart+60))
827 pos = hdata.numheaders;
828 else
829 {
830 for(pos = 0; pos < hdata.numheaders; ++pos)
831 {
832 if(!strcmp(hdata.data.unnamed[pos]+60, lastblockstart+60))
833 break;
834 }
835 if(!strcmp("# / TYPES OF OBSERV", lastblockstart+60)
836 || !strcmp("TIME OF FIRST OBS", lastblockstart+60))
837 {
838 RTCM3Error("Overwriting header '%s' is dangerous.\n",
839 lastblockstart+60);
840 }
841 }
842 if(pos >= MAXHEADERLINES)
843 {
844 RTCM3Error("Maximum number of header lines of %d reached.\n",
845 MAXHEADERLINES);
846 }
847 else if(!strcmp("END OF HEADER", lastblockstart+60))
848 {
849 RTCM3Error("End of header ignored.\n");
850 }
851 else
852 {
853 hdata.data.unnamed[pos] = lastblockstart;
854 if(pos == hdata.numheaders)
855 ++hdata.numheaders;
856 }
857 }
858 lastblockstart = buffer+i+1;
859 }
860 }
861 }
862 else
863 {
864 RTCM3Error("Could not read data from headerfile '%s'.\n",
865 Parser->headerfile);
866 }
867 fclose(fh);
868 }
869 else
870 {
871 RTCM3Error("Could not open header datafile '%s'.\n",
872 Parser->headerfile);
873 }
874 }
875
876#ifndef NO_RTCM3_MAIN
877 for(i = 0; i < hdata.numheaders; ++i)
878 RTCM3Text("%s\n", hdata.data.unnamed[i]);
879 RTCM3Text(" "
880 "END OF HEADER\n");
881#endif
882}
883
884void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
885{
886 Parser->Message[Parser->MessageSize++] = byte;
887 if(Parser->MessageSize >= Parser->NeedBytes)
888 {
889 int r;
890 while((r = RTCM3Parser(Parser)))
891 {
892 int i, j, o;
893 struct converttimeinfo cti;
894
895 if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
896 {
897 ++Parser->init;
898
899 if(Parser->init == NUMSTARTSKIP)
900 HandleHeader(Parser);
901 else
902 {
903 for(i = 0; i < Parser->Data.numsats; ++i)
904 Parser->startflags |= Parser->Data.dataflags[i];
905 continue;
906 }
907 }
908 if(r == 2 && !Parser->validwarning)
909 {
910 RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
911 " COMMENT\n");
912 Parser->validwarning = 1;
913 }
914
915 converttime(&cti, Parser->Data.week,
916 (int)floor(Parser->Data.timeofweek/1000.0));
917 RTCM3Text(" %02d %2d %2d %2d %2d %10.7f 0%3d",
918 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
919 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
920 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
921 {
922 if(Parser->Data.satellites[i] <= PRN_GPS_END)
923 RTCM3Text("G%02d", Parser->Data.satellites[i]);
924 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
925 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
926 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
927 else
928 RTCM3Text("%3d", Parser->Data.satellites[i]);
929 }
930 RTCM3Text("\n");
931 o = 12;
932 j = Parser->Data.numsats - 12;
933 while(j > 0)
934 {
935 RTCM3Text(" ");
936 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
937 {
938 if(Parser->Data.satellites[i] <= PRN_GPS_END)
939 RTCM3Text("G%02d", Parser->Data.satellites[i]);
940 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
941 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
942 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
943 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
944 && Parser->Data.satellites[i] <= PRN_WAAS_END)
945 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START);
946 else
947 RTCM3Text("%3d", Parser->Data.satellites[i]);
948 }
949 RTCM3Text("\n");
950 j -= 12;
951 o += 12;
952 }
953 for(i = 0; i < Parser->Data.numsats; ++i)
954 {
955 for(j = 0; j < Parser->numdatatypes; ++j)
956 {
957 if(!(Parser->Data.dataflags[i] & Parser->dataflag[j])
958 || isnan(Parser->Data.measdata[i][Parser->datapos[j]])
959 || isinf(Parser->Data.measdata[i][Parser->datapos[j]]))
960 { /* no or illegal data */
961 RTCM3Text(" ");
962 }
963 else
964 {
965 char lli = ' ';
966 char snr = ' ';
967 if(Parser->dataflag[j] & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
968 {
969 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
970 lli = '1';
971 snr = '0'+Parser->Data.snrL1[i];
972 }
973 if(Parser->dataflag[j] & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
974 {
975 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
976 lli = '1';
977 snr = '0'+Parser->Data.snrL2[i];
978 }
979 RTCM3Text("%14.3f%c%c",
980 Parser->Data.measdata[i][Parser->datapos[j]],lli,snr);
981 }
982 if(j%5 == 4 || j == Parser->numdatatypes-1)
983 RTCM3Text("\n");
984 }
985 }
986 }
987 }
988}
989
990#ifndef NO_RTCM3_MAIN
991static char datestr[] = "$Date: 2006/11/21 08:27:35 $";
992
993/* The string, which is send as agent in HTTP request */
994#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
995
996#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
997
998static const char encodingTable [64] = {
999 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1000 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1001 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1002 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1003};
1004
1005/* does not buffer overrun, but breaks directly after an error */
1006/* returns the number of required bytes */
1007static int encode(char *buf, int size, const char *user, const char *pwd)
1008{
1009 unsigned char inbuf[3];
1010 char *out = buf;
1011 int i, sep = 0, fill = 0, bytes = 0;
1012
1013 while(*user || *pwd)
1014 {
1015 i = 0;
1016 while(i < 3 && *user) inbuf[i++] = *(user++);
1017 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1018 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1019 while(i < 3) {inbuf[i++] = 0; ++fill; }
1020 if(out-buf < size-1)
1021 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1022 if(out-buf < size-1)
1023 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1024 | ((inbuf [1] & 0xF0) >> 4)];
1025 if(out-buf < size-1)
1026 {
1027 if(fill == 2)
1028 *(out++) = '=';
1029 else
1030 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1031 | ((inbuf [2] & 0xC0) >> 6)];
1032 }
1033 if(out-buf < size-1)
1034 {
1035 if(fill >= 1)
1036 *(out++) = '=';
1037 else
1038 *(out++) = encodingTable[inbuf [2] & 0x3F];
1039 }
1040 bytes += 4;
1041 }
1042 if(out-buf < size)
1043 *out = 0;
1044 return bytes;
1045}
1046
1047static int stop = 0;
1048
1049struct Args
1050{
1051 const char *server;
1052 int port;
1053 const char *user;
1054 const char *password;
1055 const char *data;
1056 const char *headerfile;
1057};
1058
1059/* option parsing */
1060#ifdef NO_LONG_OPTS
1061#define LONG_OPT(a)
1062#else
1063#define LONG_OPT(a) a
1064static struct option opts[] = {
1065{ "data", required_argument, 0, 'd'},
1066{ "server", required_argument, 0, 's'},
1067{ "password", required_argument, 0, 'p'},
1068{ "port", required_argument, 0, 'r'},
1069{ "header", required_argument, 0, 'f'},
1070{ "user", required_argument, 0, 'u'},
1071{ "help", no_argument, 0, 'h'},
1072{0,0,0,0}};
1073#endif
1074#define ARGOPT "-d:hp:r:s:u:f:"
1075
1076static const char *geturl(const char *url, struct Args *args)
1077{
1078 static char buf[1000];
1079 static char *Buffer = buf;
1080 static char *Bufend = buf+sizeof(buf);
1081
1082 if(strncmp("ntrip:", url, 6))
1083 return "URL must start with 'ntrip:'.";
1084 url += 6; /* skip ntrip: */
1085
1086 if(*url != '@' && *url != '/')
1087 {
1088 /* scan for mountpoint */
1089 args->data = Buffer;
1090 while(*url && *url != '@' && *url != '/' && Buffer != Bufend)
1091 *(Buffer++) = *(url++);
1092 if(Buffer == args->data)
1093 return "Mountpoint required.";
1094 else if(Buffer >= Bufend-1)
1095 return "Parsing buffer too short.";
1096 *(Buffer++) = 0;
1097 }
1098
1099 if(*url == '/') /* username and password */
1100 {
1101 ++url;
1102 args->user = Buffer;
1103 while(*url && *url != '@' && *url != ':' && Buffer != Bufend)
1104 *(Buffer++) = *(url++);
1105 if(Buffer == args->user)
1106 return "Username cannot be empty.";
1107 else if(Buffer >= Bufend-1)
1108 return "Parsing buffer too short.";
1109 *(Buffer++) = 0;
1110
1111 if(*url == ':') ++url;
1112
1113 args->password = Buffer;
1114 while(*url && *url != '@' && Buffer != Bufend)
1115 *(Buffer++) = *(url++);
1116 if(Buffer == args->password)
1117 return "Password cannot be empty.";
1118 else if(Buffer >= Bufend-1)
1119 return "Parsing buffer too short.";
1120 *(Buffer++) = 0;
1121 }
1122
1123 if(*url == '@') /* server */
1124 {
1125 ++url;
1126 args->server = Buffer;
1127 while(*url && *url != ':' && Buffer != Bufend)
1128 *(Buffer++) = *(url++);
1129 if(Buffer == args->server)
1130 return "Servername cannot be empty.";
1131 else if(Buffer >= Bufend-1)
1132 return "Parsing buffer too short.";
1133 *(Buffer++) = 0;
1134
1135 if(*url == ':')
1136 {
1137 char *s2 = 0;
1138 args->port = strtol(++url, &s2, 10);
1139 if(*s2 || args->port <= 0 || args->port > 0xFFFF)
1140 return "Illegal port number.";
1141 url = s2;
1142 }
1143 }
1144
1145 return *url ? "Garbage at end of server string." : 0;
1146}
1147
1148static int getargs(int argc, char **argv, struct Args *args)
1149{
1150 int res = 1;
1151 int getoptr;
1152 int help = 0;
1153 char *t;
1154
1155 args->server = "www.euref-ip.net";
1156 args->port = 2101;
1157 args->user = "";
1158 args->password = "";
1159 args->data = 0;
1160 args->headerfile = 0;
1161 help = 0;
1162
1163 do
1164 {
1165#ifdef NO_LONG_OPTS
1166 switch((getoptr = getopt(argc, argv, ARGOPT)))
1167#else
1168 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
1169#endif
1170 {
1171 case 's': args->server = optarg; break;
1172 case 'u': args->user = optarg; break;
1173 case 'p': args->password = optarg; break;
1174 case 'd': args->data = optarg; break;
1175 case 'f': args->headerfile = optarg; break;
1176 case 'h': help=1; break;
1177 case 'r':
1178 args->port = strtoul(optarg, &t, 10);
1179 if((t && *t) || args->port < 1 || args->port > 65535)
1180 res = 0;
1181 break;
1182 case 1:
1183 {
1184 const char *err;
1185 if((err = geturl(optarg, args)))
1186 {
1187 RTCM3Error("%s\n\n", err);
1188 res = 0;
1189 }
1190 }
1191 break;
1192 case -1: break;
1193 }
1194 } while(getoptr != -1 || !res);
1195
1196 datestr[0] = datestr[7];
1197 datestr[1] = datestr[8];
1198 datestr[2] = datestr[9];
1199 datestr[3] = datestr[10];
1200 datestr[5] = datestr[12];
1201 datestr[6] = datestr[13];
1202 datestr[8] = datestr[15];
1203 datestr[9] = datestr[16];
1204 datestr[4] = datestr[7] = '-';
1205 datestr[10] = 0;
1206
1207 if(!res || help)
1208 {
1209 RTCM3Error("Version %s (%s) GPL\nUsage: %s -s server -u user ...\n"
1210 " -d " LONG_OPT("--data ") "the requested data set\n"
1211 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
1212 " -s " LONG_OPT("--server ") "the server name or address\n"
1213 " -p " LONG_OPT("--password ") "the login password\n"
1214 " -r " LONG_OPT("--port ") "the server port number (default 2101)\n"
1215 " -u " LONG_OPT("--user ") "the user name\n"
1216 "or using an URL:\n%s ntrip:mountpoint[/username[:password]][@server[:port]]\n"
1217 , revisionstr, datestr, argv[0], argv[0]);
1218 exit(1);
1219 }
1220 return res;
1221}
1222
1223/* let the output complete a block if necessary */
1224static void signalhandler(int sig)
1225{
1226 if(!stop)
1227 {
1228 RTCM3Error("Stop signal number %d received. "
1229 "Trying to terminate gentle.\n", sig);
1230 stop = 1;
1231 alarm(1);
1232 }
1233}
1234
1235/* for some reason we had to abort hard (maybe waiting for data */
1236#ifdef __GNUC__
1237static __attribute__ ((noreturn)) void signalhandler_alarm(
1238int sig __attribute__((__unused__)))
1239#else /* __GNUC__ */
1240static void signalhandler_alarm(int sig)
1241#endif /* __GNUC__ */
1242{
1243 RTCM3Error("Programm forcefully terminated.\n");
1244 exit(1);
1245}
1246
1247int main(int argc, char **argv)
1248{
1249 struct Args args;
1250 struct RTCM3ParserData Parser;
1251
1252 setbuf(stdout, 0);
1253 setbuf(stdin, 0);
1254 setbuf(stderr, 0);
1255
1256 {
1257 char *a;
1258 int i=0;
1259 for(a = revisionstr+11; *a && *a != ' '; ++a)
1260 revisionstr[i++] = *a;
1261 revisionstr[i] = 0;
1262 }
1263
1264 signal(SIGINT, signalhandler);
1265 signal(SIGALRM,signalhandler_alarm);
1266 signal(SIGQUIT,signalhandler);
1267 signal(SIGTERM,signalhandler);
1268 signal(SIGPIPE,signalhandler);
1269 memset(&Parser, 0, sizeof(Parser));
1270 {
1271 time_t tim;
1272 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
1273 Parser.GPSWeek = tim/(7*24*60*60);
1274 Parser.GPSTOW = tim%(7*24*60*60);
1275 }
1276
1277 if(getargs(argc, argv, &args))
1278 {
1279 int i, sockfd, numbytes;
1280 char buf[MAXDATASIZE];
1281 struct hostent *he;
1282 struct sockaddr_in their_addr; /* connector's address information */
1283
1284 Parser.headerfile = args.headerfile;
1285
1286 if(!(he=gethostbyname(args.server)))
1287 {
1288 RTCM3Error("Function gethostbyname: %s\n", strerror(errno));
1289 exit(1);
1290 }
1291 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
1292 {
1293 RTCM3Error("Function socket: %s\n", strerror(errno));
1294 exit(1);
1295 }
1296 their_addr.sin_family = AF_INET; /* host byte order */
1297 their_addr.sin_port = htons(args.port); /* short, network byte order */
1298 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
1299 memset(&(their_addr.sin_zero), '\0', 8);
1300 if(connect(sockfd, (struct sockaddr *)&their_addr,
1301 sizeof(struct sockaddr)) == -1)
1302 {
1303 RTCM3Error("Function connect: %s\n", strerror(errno));
1304 exit(1);
1305 }
1306
1307 if(!args.data)
1308 {
1309 i = snprintf(buf, MAXDATASIZE,
1310 "GET / HTTP/1.0\r\n"
1311 "User-Agent: %s/%s\r\n"
1312#ifdef UNUSED
1313 "Accept: */*\r\n"
1314 "Connection: close\r\n"
1315#endif
1316 "\r\n"
1317 , AGENTSTRING, revisionstr);
1318 }
1319 else
1320 {
1321 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
1322 "GET /%s HTTP/1.0\r\n"
1323 "User-Agent: %s/%s\r\n"
1324#ifdef UNUSED
1325 "Accept: */*\r\n"
1326 "Connection: close\r\n"
1327#endif
1328 "Authorization: Basic "
1329 , args.data, AGENTSTRING, revisionstr);
1330 if(i > MAXDATASIZE-40 && i < 0) /* second check for old glibc */
1331 {
1332 RTCM3Error("Requested data too long\n");
1333 exit(1);
1334 }
1335 i += encode(buf+i, MAXDATASIZE-i-5, args.user, args.password);
1336 if(i > MAXDATASIZE-5)
1337 {
1338 RTCM3Error("Username and/or password too long\n");
1339 exit(1);
1340 }
1341 snprintf(buf+i, 5, "\r\n\r\n");
1342 i += 5;
1343 }
1344 if(send(sockfd, buf, (size_t)i, 0) != i)
1345 {
1346 RTCM3Error("Function send: %s\n", strerror(errno));
1347 exit(1);
1348 }
1349 if(args.data)
1350 {
1351 int k = 0;
1352 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
1353 {
1354 if(!k)
1355 {
1356 if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
1357 {
1358 RTCM3Error("Could not get the requested data: ");
1359 for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
1360 {
1361 RTCM3Error("%c", isprint(buf[k]) ? buf[k] : '.');
1362 }
1363 RTCM3Error("\n");
1364 exit(1);
1365 }
1366 ++k;
1367 }
1368 else
1369 {
1370 int z;
1371 for(z = 0; z < numbytes && !stop; ++z)
1372 HandleByte(&Parser, (unsigned int) buf[z]);
1373 }
1374 }
1375 }
1376 else
1377 {
1378 while((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
1379 {
1380 fwrite(buf, (size_t)numbytes, 1, stdout);
1381 }
1382 }
1383
1384 close(sockfd);
1385 }
1386 return 0;
1387}
1388#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.