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

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

cleanup

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