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

Last change on this file since 46 was 33, checked in by stoecker, 18 years ago

added types 1001-1003

File size: 29.8 KB
RevLine 
[27]1/*
2 Converter for RTCM3 data to RINEX.
[33]3 $Id: rtcm3torinex.c,v 1.3 2006/04/20 08:37:23 stoecker Exp $
[29]4 Copyright (C) 2005-2006 by Dirk Stoecker <stoecker@euronav.de>
[27]5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 or read http://www.gnu.org/licenses/gpl.txt
20*/
21
22#include <ctype.h>
23#include <errno.h>
24#include <getopt.h>
25#include <math.h>
26#include <netdb.h>
27#include <netinet/in.h>
28#include <signal.h>
29#include <stdint.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <sys/socket.h>
34#include <sys/types.h>
35#include <time.h>
36#include <unistd.h>
37
38/* The string, which is send as agent in HTTP request */
39#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
40
41#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
42
43/* CVS revision and version */
[33]44static char revisionstr[] = "$Revision: 1.3 $";
45static char datestr[] = "$Date: 2006/04/20 08:37:23 $";
[27]46static int stop = 0;
47
48/* unimportant, only for approx. time needed */
49#define LEAPSECONDS 14
50
51struct converttimeinfo {
52 int second; /* seconds of GPS time [0..59] */
53 int minute; /* minutes of GPS time [0..59] */
54 int hour; /* hour of GPS time [0..24] */
55 int day; /* day of GPS time [1..28..30(31)*/
56 int month; /* month of GPS time [1..12]*/
57 int year; /* year of GPS time [1980..] */
58};
59
60#define PRN_GPS_START 1
61#define PRN_GPS_END 32
62#define PRN_GLONASS_START 38
63#define PRN_GLONASS_END 61
64
65#define GNSSENTRY_C1DATA 0
66#define GNSSENTRY_C2DATA 1
67#define GNSSENTRY_P1DATA 2
68#define GNSSENTRY_P2DATA 3
69#define GNSSENTRY_L1CDATA 4
70#define GNSSENTRY_L1PDATA 5
71#define GNSSENTRY_L2CDATA 6
72#define GNSSENTRY_L2PDATA 7
73#define GNSSENTRY_D1CDATA 8
74#define GNSSENTRY_D1PDATA 9
75#define GNSSENTRY_D2CDATA 10
76#define GNSSENTRY_D2PDATA 11
77#define GNSSENTRY_S1CDATA 12
78#define GNSSENTRY_S1PDATA 13
79#define GNSSENTRY_S2CDATA 14
80#define GNSSENTRY_S2PDATA 15
81#define GNSSENTRY_NUMBER 16 /* number of types!!! */
82
83/* Data flags. These flags are used in the dataflags field of gpsdata structure
84 and are used the determine, which data fields are filled with valid data. */
85#define GNSSDF_C1DATA (1<<GNSSENTRY_C1DATA)
86#define GNSSDF_C2DATA (1<<GNSSENTRY_C2DATA)
87#define GNSSDF_P1DATA (1<<GNSSENTRY_P1DATA)
88#define GNSSDF_P2DATA (1<<GNSSENTRY_P2DATA)
89#define GNSSDF_L1CDATA (1<<GNSSENTRY_L1CDATA)
90#define GNSSDF_L1PDATA (1<<GNSSENTRY_L1PDATA)
91#define GNSSDF_L2CDATA (1<<GNSSENTRY_L2CDATA)
92#define GNSSDF_L2PDATA (1<<GNSSENTRY_L2PDATA)
93#define GNSSDF_D1CDATA (1<<GNSSENTRY_D1CDATA)
94#define GNSSDF_D1PDATA (1<<GNSSENTRY_D1PDATA)
95#define GNSSDF_D2CDATA (1<<GNSSENTRY_D2CDATA)
96#define GNSSDF_D2PDATA (1<<GNSSENTRY_D2PDATA)
97#define GNSSDF_S1CDATA (1<<GNSSENTRY_S1CDATA)
98#define GNSSDF_S1PDATA (1<<GNSSENTRY_S1PDATA)
99#define GNSSDF_S2CDATA (1<<GNSSENTRY_S2CDATA)
100#define GNSSDF_S2PDATA (1<<GNSSENTRY_S2PDATA)
101
102#define RINEXENTRY_C1DATA 0
103#define RINEXENTRY_C2DATA 1
104#define RINEXENTRY_P1DATA 2
105#define RINEXENTRY_P2DATA 3
106#define RINEXENTRY_L1DATA 4
107#define RINEXENTRY_L2DATA 5
108#define RINEXENTRY_D1DATA 6
109#define RINEXENTRY_D2DATA 7
110#define RINEXENTRY_S1DATA 8
111#define RINEXENTRY_S2DATA 9
112#define RINEXENTRY_NUMBER 10
113
114/* Additional flags for the data field, which tell us more. */
115#define GNSSDF_LOCKLOSSL1 (1<<29) /* lost lock on L1 */
116#define GNSSDF_LOCKLOSSL2 (1<<30) /* lost lock on L2 */
117
118struct gnssdata {
119 int flags; /* GPSF_xxx */
120 int week; /* week number of GPS date */
121 int numsats;
122 double timeofweek; /* milliseconds in GPS week */
123 double measdata[24][GNSSENTRY_NUMBER]; /* data fields */
124 int dataflags[24]; /* GPSDF_xxx */
125 int satellites[24]; /* SV - IDs */
126 int snrL1[24]; /* Important: all the 5 SV-specific fields must */
127 int snrL2[24]; /* have the same SV-order */
128};
129
130struct RTCM3ParserData {
131 unsigned char Message[2048]; /* input-buffer */
132 int MessageSize; /* current buffer size */
133 int NeedBytes; /* bytes wanted for next run */
134 int SkipBytes; /* bytes to skip in next round */
135 int GPSWeek;
136 int GPSTOW; /* in seconds */
137 struct gnssdata Data;
138 int size;
139 int lastlockl1[64];
140 int lastlockl2[64];
141 int datapos[RINEXENTRY_NUMBER];
142 int dataflag[RINEXENTRY_NUMBER];
143 int numdatatypes;
144 int validwarning;
145 int init;
146 const char * headerfile;
147};
148
149struct Args
150{
151 const char *server;
152 int port;
153 const char *user;
154 const char *password;
155 const char *data;
156 const char *headerfile;
157};
158
159/* option parsing */
160#ifdef NO_LONG_OPTS
161#define LONG_OPT(a)
162#else
163#define LONG_OPT(a) a
164static struct option opts[] = {
165{ "data", required_argument, 0, 'd'},
166{ "server", required_argument, 0, 's'},
167{ "password", required_argument, 0, 'p'},
168{ "port", required_argument, 0, 'r'},
169{ "header", required_argument, 0, 'f'},
170{ "user", required_argument, 0, 'u'},
171{ "help", no_argument, 0, 'h'},
172{0,0,0,0}};
173#endif
174#define ARGOPT "d:hp:r:s:u:f:"
175
176static int getargs(int argc, char **argv, struct Args *args)
177{
178 int res = 1;
179 int getoptr;
180 int help = 0;
181 char *t;
182
183 args->server = "www.euref-ip.net";
184 args->port = 80;
185 args->user = "";
186 args->password = "";
187 args->data = 0;
188 args->headerfile = 0;
189 help = 0;
190
191 do
192 {
193#ifdef NO_LONG_OPTS
194 switch((getoptr = getopt(argc, argv, ARGOPT)))
195#else
196 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
197#endif
198 {
199 case 's': args->server = optarg; break;
200 case 'u': args->user = optarg; break;
201 case 'p': args->password = optarg; break;
202 case 'd': args->data = optarg; break;
203 case 'f': args->headerfile = optarg; break;
204 case 'h': help=1; break;
205 case 'r':
206 args->port = strtoul(optarg, &t, 10);
207 if((t && *t) || args->port < 1 || args->port > 65535)
208 res = 0;
209 break;
210 case -1: break;
211 }
212 } while(getoptr != -1 || !res);
213
214 datestr[0] = datestr[7];
215 datestr[1] = datestr[8];
216 datestr[2] = datestr[9];
217 datestr[3] = datestr[10];
218 datestr[5] = datestr[12];
219 datestr[6] = datestr[13];
220 datestr[8] = datestr[15];
221 datestr[9] = datestr[16];
222 datestr[4] = datestr[7] = '-';
223 datestr[10] = 0;
224
225 if(!res || help)
226 {
227 fprintf(stderr, "Version %s (%s) GPL\nUsage: %s -s server -u user ...\n"
228 " -d " LONG_OPT("--data ") "the requested data set\n"
229 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
230 " -s " LONG_OPT("--server ") "the server name or address\n"
231 " -p " LONG_OPT("--password ") "the login password\n"
232 " -r " LONG_OPT("--port ") "the server port number (default 80)\n"
233 " -u " LONG_OPT("--user ") "the user name\n"
234 , revisionstr, datestr, argv[0]);
235 exit(1);
236 }
237 return res;
238}
239
240static const char encodingTable [64] = {
241 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
242 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
243 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
244 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
245};
246
247/* does not buffer overrun, but breaks directly after an error */
248/* returns the number of required bytes */
249static int encode(char *buf, int size, const char *user, const char *pwd)
250{
251 unsigned char inbuf[3];
252 char *out = buf;
253 int i, sep = 0, fill = 0, bytes = 0;
254
255 while(*user || *pwd)
256 {
257 i = 0;
258 while(i < 3 && *user) inbuf[i++] = *(user++);
259 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
260 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
261 while(i < 3) {inbuf[i++] = 0; ++fill; }
262 if(out-buf < size-1)
263 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
264 if(out-buf < size-1)
265 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
266 | ((inbuf [1] & 0xF0) >> 4)];
267 if(out-buf < size-1)
268 {
269 if(fill == 2)
270 *(out++) = '=';
271 else
272 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
273 | ((inbuf [2] & 0xC0) >> 6)];
274 }
275 if(out-buf < size-1)
276 {
277 if(fill >= 1)
278 *(out++) = '=';
279 else
280 *(out++) = encodingTable[inbuf [2] & 0x3F];
281 }
282 bytes += 4;
283 }
284 if(out-buf < size)
285 *out = 0;
286 return bytes;
287}
288
289static uint32_t CRC24(long size, const unsigned char *buf)
290{
291 uint32_t crc = 0;
292 int i;
293
294 while(size--)
295 {
296 crc ^= (*buf++) << (16);
297 for(i = 0; i < 8; i++)
298 {
299 crc <<= 1;
300 if(crc & 0x1000000)
301 crc ^= 0x01864cfb;
302 }
303 }
304 return crc;
305}
306
307static int GetMessage(struct RTCM3ParserData *handle)
308{
309 unsigned char *m, *e;
310 int i;
311
312 m = handle->Message+handle->SkipBytes;
313 e = handle->Message+handle->MessageSize;
314 handle->NeedBytes = handle->SkipBytes = 0;
315 while(e-m >= 3)
316 {
317 if(m[0] == 0xD3)
318 {
319 handle->size = ((m[1]&3)<<8)|m[2];
320 if(e-m >= handle->size+6)
321 {
322 if((uint32_t)((m[3+handle->size]<<16)|(m[3+handle->size+1]<<8)
323 |(m[3+handle->size+2])) == CRC24(handle->size+3, m))
324 {
325 handle->SkipBytes = handle->size;
326 break;
327 }
328 else
329 ++m;
330 }
331 else
332 {
333 handle->NeedBytes = handle->size+6;
334 break;
335 }
336 }
337 else
338 ++m;
339 }
340 if(e-m < 3)
341 handle->NeedBytes = 3;
342
343 /* copy buffer to front */
344 i = m - handle->Message;
345 if(i && m < e)
346 memmove(handle->Message, m, handle->MessageSize-i);
347 handle->MessageSize -= i;
348
349 return !handle->NeedBytes;
350}
351
352#define LOADBITS(a) \
353{ \
354 while((a) > numbits) \
355 { \
356 if(!size--) break; \
357 bitfield = (bitfield<<8)|*(data++); \
358 numbits += 8; \
359 } \
360}
361
362/* extract bits from data stream
363 b = variable to store result, a = number of bits */
364#define GETBITS(b, a) \
365{ \
366 LOADBITS(a) \
367 b = (bitfield<<(64-numbits))>>(64-(a)); \
368 numbits -= (a); \
369}
370
371/* extract bits from data stream
372 b = variable to store result, a = number of bits */
373#define GETBITSSIGN(b, a) \
374{ \
375 LOADBITS(a) \
376 b = ((int64_t)(bitfield<<(64-numbits)))>>(64-(a)); \
377 numbits -= (a); \
378}
379
380#define SKIPBITS(b) { LOADBITS(b) numbits -= (b); }
381
382static int RTCM3Parser(struct RTCM3ParserData *handle)
383{
384 int ret=0;
385
386 while(!ret && GetMessage(handle))
387 {
388 /* using 64 bit integer types, as it is much easier than handling
389 the long datatypes in 32 bit */
390 uint64_t numbits = 0, bitfield = 0;
391 int size = handle->size, type;
392 unsigned char *data = handle->Message+3;
393
394 GETBITS(type,12)
395 switch(type)
396 {
[33]397 case 1001: case 1002: case 1003: case 1004:
[27]398 if(handle->GPSWeek)
399 {
400 int lastlockl1[64];
401 int lastlockl2[64];
402 struct gnssdata *gnss;
403 int i, num, wasamb=0;
404
405 for(i = 0; i < 64; ++i)
406 lastlockl1[i] = lastlockl2[i] = 0;
407
408 gnss = &handle->Data;
409 memset(gnss, 0, sizeof(*gnss));
410
411 SKIPBITS(12) /* id */
412 GETBITS(i,30)
413 if(i/1000 < (int)handle->GPSTOW - 86400)
414 ++handle->GPSWeek;
415 handle->GPSTOW = i/1000;
416 gnss->timeofweek = i;
417 gnss->week = handle->GPSWeek;
418
419 SKIPBITS(1) /* sync */
420 GETBITS(i,5)
421 gnss->numsats = i;
422 SKIPBITS(4) /* smind, smint */
423
424 for(num = 0; num < gnss->numsats; ++num)
425 {
[33]426 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
[27]427
428 GETBITS(sv, 6);
429 gnss->satellites[num] = (sv < 40 ? sv : sv+80);
430 /* L1 */
431 GETBITS(code, 1);
432 if(code)
433 {
434 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
435 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
436 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
437 }
438 else
439 {
440 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
441 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
442 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
443 }
444 GETBITS(l1range, 24);
445 if(l1range != 0x80000)
446 {
447 gnss->dataflags[num] |= c;
448 gnss->measdata[num][ce] = l1range*0.02;
449 }
450 GETBITSSIGN(i, 20);
451 if(i != 0x80000)
452 {
453 gnss->dataflags[num] |= l;
454 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
455 }
456 GETBITS(i, 7);
457 lastlockl1[sv] = i;
458 if(handle->lastlockl1[sv] > i)
459 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
[33]460 if(type == 1002 || type == 1004)
[27]461 {
[33]462 GETBITS(amb,8);
463 if(amb && (gnss->dataflags[num] & c))
464 {
465 gnss->measdata[num][ce] += amb*299792.458;
466 gnss->measdata[num][le] += amb*299792.458;
467 ++wasamb;
468 }
469 GETBITS(i, 8);
470 if(i)
471 {
472 gnss->dataflags[num] |= s;
473 gnss->measdata[num][se] = i*0.25;
474 i /= 4*4;
475 if(i > 9) i = 9;
476 else if(i < 1) i = 1;
477 gnss->snrL1[num] = i;
478 }
[27]479 }
[33]480 if(type == 1003 || type == 1004)
[27]481 {
[33]482 /* L2 */
483 GETBITS(code,2);
484 if(code)
485 {
486 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
487 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
488 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
489 }
490 else
491 {
492 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
493 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
494 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
495 }
496 GETBITSSIGN(i,14);
497 if(i != 0x2000)
498 {
499 gnss->dataflags[num] |= c;
500 gnss->measdata[num][ce] = l1range*0.02+i*0.02
501 +amb*299792.458;
502 }
503 GETBITSSIGN(i,20);
504 if(i != 0x80000)
505 {
506 gnss->dataflags[num] |= l;
507 gnss->measdata[num][le] = l1range*0.02+i*0.0005
508 +amb*299792.458;
509 }
510 GETBITS(i,7);
511 lastlockl2[sv] = i;
512 if(handle->lastlockl2[sv] > i)
513 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
514 if(type == 1004)
515 {
516 GETBITS(i, 8);
517 if(i)
518 {
519 gnss->dataflags[num] |= s;
520 gnss->measdata[num][se] = i*0.25;
521 i /= 4*4;
522 if(i > 9) i = 9;
523 else if(i < 1) i = 1;
524 gnss->snrL2[num] = i;
525 }
526 }
[27]527 }
528 }
529 for(i = 0; i < 64; ++i)
530 {
531 handle->lastlockl1[i] = lastlockl1[i];
532 handle->lastlockl2[i] = lastlockl2[i];
533 }
534 if(wasamb) /* not RINEX compatible without */
535 ret = 1;
536 else
537 ret = 2;
538 }
539 break;
540 }
541 }
542 return ret;
543}
544
545static int longyear(int year, int month)
546{
547 if(!(year % 4) && (!(year % 400) || (year % 100)))
548 {
549 if(!month || month == 2)
550 return 1;
551 }
552 return 0;
553}
554
555static void converttime(struct converttimeinfo *c, int week, int tow)
556{
557 /* static variables */
558 static const int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
559
560 int i, k, doy, j; /* temporary variables */
561 j = week*(7*24*60*60) + tow + 5*24*60*60;
562 for(i = 1980; j >= (k = (365+longyear(i,0))*24*60*60); ++i)
563 j -= k;
564 c->year = i;
565 doy = 1+ (j / (24*60*60));
566 j %= (24*60*60);
567 c->hour = j / (60*60);
568 j %= (60*60);
569 c->minute = j / 60;
570 c->second = j % 60;
571 j = 0;
572 for(i = 1; j + (k = months[i] + longyear(c->year,i)) < doy; ++i)
573 j += k;
574 c->month = i;
575 c->day = doy - j;
576}
577
578struct Header
579{
580 const char *version;
581 const char *pgm;
582 const char *marker;
583 const char *observer;
584 const char *receiver;
585 const char *antenna;
586 const char *position;
587 const char *antennaposition;
588 const char *wavelength;
589 const char *typesofobs; /* should not be modified outside */
590 const char *timeoffirstobs; /* should not be modified outside */
591};
592
593#define MAXHEADERLINES 50
594#define MAXHEADERBUFFERSIZE 4096
595struct HeaderData
596{
597 union
598 {
599 struct Header named;
600 const char *unnamed[MAXHEADERLINES];
601 } data;
602 int numheaders;
603};
604
605static void HandleHeader(struct RTCM3ParserData *Parser)
606{
607 struct HeaderData hdata;
608 char thebuffer[MAXHEADERBUFFERSIZE];
609 char *buffer = thebuffer;
610 int buffersize = sizeof(thebuffer);
611 int i;
612
613 hdata.data.named.version =
614 " 2.11 OBSERVATION DATA M (Mixed)"
615 " RINEX VERSION / TYPE";
616
617 {
[30]618 const char *str;
[27]619 time_t t;
620 struct tm * t2;
621
622 str = getenv("USER");
623 if(!str) str = "";
624 t = time(&t);
625 t2 = gmtime(&t);
626 hdata.data.named.pgm = buffer;
627 i = 1+snprintf(buffer, buffersize,
628 "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d "
629 "PGM / RUN BY / DATE",
630 revisionstr, str, 1900+t2->tm_year, t2->tm_mon+1, t2->tm_mday, t2->tm_hour,
631 t2->tm_min);
632 buffer += i; buffersize -= i;
633
634 hdata.data.named.observer = buffer;
635 i = 1+snprintf(buffer, buffersize,
636 "%-20.20s "
637 "OBSERVER / AGENCY", str);
638 buffer += i; buffersize -= i;
639 }
640
641 hdata.data.named.marker =
642 "RTCM3TORINEX "
643 "MARKER NAME";
644
645 hdata.data.named.receiver =
646 " "
647 "REC # / TYPE / VERS";
648
649 hdata.data.named.antenna =
650 " "
651 "ANT # / TYPE";
652
653 hdata.data.named.position =
654 " .0000 .0000 .0000 "
655 "APPROX POSITION XYZ";
656
657 hdata.data.named.antennaposition =
658 " .0000 .0000 .0000 "
659 "ANTENNA: DELTA H/E/N";
660
661 hdata.data.named.wavelength =
662 " 1 1 "
663 "WAVELENGTH FACT L1/2";
664
665 {
666#define CHECKFLAGS(a, b) \
667 if(flags & GNSSDF_##a##DATA \
668 && !data[RINEXENTRY_##b##DATA]) \
669 { \
670 Parser->dataflag[Parser->numdatatypes] = GNSSDF_##a##DATA; \
671 Parser->datapos[Parser->numdatatypes++] = data[RINEXENTRY_##b##DATA] \
672 = GNSSENTRY_##a##DATA; \
673 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#b); \
674 tbufferpos += 6; \
675 }
676
677 int flags = 0;
678 int data[RINEXENTRY_NUMBER];
679 char tbuffer[6*RINEXENTRY_NUMBER+1];
680 int tbufferpos = 0;
681 for(i = 0; i < RINEXENTRY_NUMBER; ++i)
682 data[i] = 0;
683 for(i = 0; i < Parser->Data.numsats; ++i)
684 flags |= Parser->Data.dataflags[i];
685
686 CHECKFLAGS(C1,C1)
687 CHECKFLAGS(C2,C2)
688 CHECKFLAGS(P1,P1)
689 CHECKFLAGS(P2,P2)
690 CHECKFLAGS(L1C,L1)
691 CHECKFLAGS(L1P,L1)
692 CHECKFLAGS(L2C,L2)
693 CHECKFLAGS(L2P,L2)
694 CHECKFLAGS(D1C,D1)
695 CHECKFLAGS(D1P,D1)
696 CHECKFLAGS(D2C,D2)
697 CHECKFLAGS(D2P,D2)
698 CHECKFLAGS(S1C,S1)
699 CHECKFLAGS(S1P,S1)
700 CHECKFLAGS(S2C,S2)
701 CHECKFLAGS(S2P,S2)
702
703 hdata.data.named.typesofobs = buffer;
704 i = 1+snprintf(buffer, buffersize,
705 "%6i%-54.54s# / TYPES OF OBSERV", Parser->numdatatypes, tbuffer);
706 if(Parser->numdatatypes>9)
707 {
708 i += snprintf(buffer+i-1, buffersize,
709 "\n %-54.54s# / TYPES OF OBSERV", tbuffer+9*6);
710 }
711 buffer += i; buffersize -= i;
712 }
713
714 {
715 struct converttimeinfo cti;
716 converttime(&cti, Parser->Data.week,
717 floor(Parser->Data.timeofweek/1000.0));
718 hdata.data.named.timeoffirstobs = buffer;
719 i = 1+snprintf(buffer, buffersize,
720 " %4d %2d %2d %2d %2d %10.7f GPS "
721 "TIME OF FIRST OBS", cti.year%100, cti.month, cti.day, cti.hour,
722 cti.minute, cti.second + fmod(Parser->Data.timeofweek/1000.0,1.0));
723
724 buffer += i; buffersize -= i;
725 }
726
727 hdata.numheaders = 11;
728
729 if(Parser->headerfile)
730 {
731 FILE *fh;
732 if((fh = fopen(Parser->headerfile, "r")))
733 {
734 int siz;
735 char *lastblockstart;
736 if((siz = fread(buffer, 1, buffersize-1, fh)) > 0)
737 {
738 buffer[siz] = '\n';
739 if(siz == buffersize)
740 {
741 fprintf(stderr, "Header file is too large. Only %d bytes read.",
742 siz);
743 }
744 /* scan the file line by line and enter the entries in the list */
745 /* warn for "# / TYPES OF OBSERV" and "TIME OF FIRST OBS" */
746 /* overwrites entries, except for comments */
747 lastblockstart = buffer;
748 for(i = 0; i < siz; ++i)
749 {
750 if(buffer[i] == '\n')
751 { /* we found a line */
752 char *end;
753 while(buffer[i+1] == '\r')
754 ++i; /* skip \r in case there are any */
755 end = buffer+i;
756 while(*end == '\t' || *end == ' ' || *end == '\r' || *end == '\n')
757 *(end--) = 0;
758 if(end-lastblockstart < 60+5) /* short line */
759 fprintf(stderr, "Short Header line '%s' ignored.\n", lastblockstart);
760 else
761 {
762 int pos;
763 if(!strcmp("COMMENT", lastblockstart+60))
764 pos = hdata.numheaders;
765 else
766 {
767 for(pos = 0; pos < hdata.numheaders; ++pos)
768 {
769 if(!strcmp(hdata.data.unnamed[pos]+60, lastblockstart+60))
770 break;
771 }
772 if(!strcmp("# / TYPES OF OBSERV", lastblockstart+60)
773 || !strcmp("TIME OF FIRST OBS", lastblockstart+60))
774 {
775 fprintf(stderr, "Overwriting header '%s' is dangerous.\n",
776 lastblockstart+60);
777 }
778 }
779 if(pos >= MAXHEADERLINES)
780 {
781 fprintf(stderr,
782 "Maximum number of header lines of %d reached.\n",
783 MAXHEADERLINES);
784 }
785 else if(!strcmp("END OF HEADER", lastblockstart+60))
786 {
787 fprintf(stderr, "End of header ignored.\n");
788 }
789 else
790 {
791 hdata.data.unnamed[pos] = lastblockstart;
792 if(pos == hdata.numheaders)
793 ++hdata.numheaders;
794 }
795 }
796 lastblockstart = buffer+i+1;
797 }
798 }
799 }
800 else
801 {
802 fprintf(stderr, "Could not read data from headerfile '%s'.\n",
803 Parser->headerfile);
804 }
805 fclose(fh);
806 }
807 else
808 {
809 fprintf(stderr, "Could not open header datafile '%s'.\n",
810 Parser->headerfile);
811 }
812 }
813
814 for(i = 0; i < hdata.numheaders; ++i)
815 printf("%s\n", hdata.data.unnamed[i]);
816 printf(" "
817 "END OF HEADER\n");
818}
819
820/* let the output complete a block if necessary */
[30]821static void signalhandler(int sig)
[27]822{
823 if(!stop)
824 {
825 fprintf(stderr, "Stop signal number %d received. "
[30]826 "Trying to terminate gentle.\n", sig);
[27]827 stop = 1;
828 alarm(1);
829 }
830}
831
832/* for some reason we had to abort hard (maybe waiting for data */
833#ifdef __GNUC__
834static __attribute__ ((noreturn)) void signalhandler_alarm(
[30]835int sig __attribute__((__unused__)))
[27]836#else /* __GNUC__ */
[30]837static void signalhandler_alarm(int sig)
[27]838#endif /* __GNUC__ */
839{
840 fprintf(stderr, "Programm forcefully terminated.\n");
841 exit(1);
842}
843
844static void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
845{
846 Parser->Message[Parser->MessageSize++] = byte;
847 if(Parser->MessageSize >= Parser->NeedBytes)
848 {
849 int r;
850 while((r = RTCM3Parser(Parser)))
851 {
852 int i, j, o;
853 struct converttimeinfo cti;
854
855 if(!Parser->init)
856 {
857 HandleHeader(Parser);
858 Parser->init = 1;
859 }
860 if(r == 2 && !Parser->validwarning)
861 {
862 printf("No valid RINEX! All values are modulo 299792.458!"
863 " COMMENT\n");
864 Parser->validwarning = 1;
865 }
866
867 converttime(&cti, Parser->Data.week,
868 floor(Parser->Data.timeofweek/1000.0));
869 printf(" %02d %2d %2d %2d %2d %10.7f 0%3d",
870 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
871 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
872 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
873 {
874 if(Parser->Data.satellites[i] <= PRN_GPS_END)
875 printf("G%02d", Parser->Data.satellites[i]);
876 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
877 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
878 printf("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
879 else
880 printf("%3d", Parser->Data.satellites[i]);
881 }
882 printf("\n");
883 o = 12;
884 j = Parser->Data.numsats - 12;
885 while(j > 0)
886 {
887 printf(" ");
888 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
889 {
890 if(Parser->Data.satellites[i] <= PRN_GPS_END)
891 printf("G%02d", Parser->Data.satellites[i]);
892 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
893 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
894 printf("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
895 else
896 printf("%3d", Parser->Data.satellites[i]);
897 }
898 printf("\n");
899 j -= 12;
900 o += 12;
901 }
902 for(i = 0; i < Parser->Data.numsats; ++i)
903 {
904 for(j = 0; j < Parser->numdatatypes; ++j)
905 {
906 if(!(Parser->Data.dataflags[i] & Parser->dataflag[j])
907 || isnan(Parser->Data.measdata[i][Parser->datapos[j]])
908 || isinf(Parser->Data.measdata[i][Parser->datapos[j]]))
909 { /* no or illegal data */
910 printf(" ");
911 }
912 else
913 {
914 char lli = ' ';
915 char snr = ' ';
916 if(Parser->dataflag[j] & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
917 {
918 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
919 lli = '1';
920 snr = '0'+Parser->Data.snrL1[i];
921 }
922 if(Parser->dataflag[j] & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
923 {
924 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
925 lli = '1';
926 snr = '0'+Parser->Data.snrL2[i];
927 }
928 printf("%14.3f%c%c",
929 Parser->Data.measdata[i][Parser->datapos[j]],lli,snr);
930 }
931 if(j%5 == 4 || j == Parser->numdatatypes-1)
932 printf("\n");
933 }
934 }
935 }
936 }
937}
938
939int main(int argc, char **argv)
940{
941 struct Args args;
942 struct RTCM3ParserData Parser;
943
944 setbuf(stdout, 0);
945 setbuf(stdin, 0);
946 setbuf(stderr, 0);
947
948 {
949 char *a;
950 int i=0;
951 for(a = revisionstr+11; *a && *a != ' '; ++a)
952 revisionstr[i++] = *a;
953 revisionstr[i] = 0;
954 }
955
956 signal(SIGINT, signalhandler);
957 signal(SIGALRM,signalhandler_alarm);
958 signal(SIGQUIT,signalhandler);
959 signal(SIGTERM,signalhandler);
960 signal(SIGPIPE,signalhandler);
961 memset(&Parser, 0, sizeof(Parser));
962 {
963 time_t tim;
964 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
965 Parser.GPSWeek = tim/(7*24*60*60);
966 Parser.GPSTOW = tim%(7*24*60*60);
967 }
968
969 if(getargs(argc, argv, &args))
970 {
971 int i, sockfd, numbytes;
972 char buf[MAXDATASIZE];
973 struct hostent *he;
974 struct sockaddr_in their_addr; /* connector's address information */
975
976 Parser.headerfile = args.headerfile;
977
978 if(!(he=gethostbyname(args.server)))
979 {
980 perror("gethostbyname");
981 exit(1);
982 }
983 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
984 {
985 perror("socket");
986 exit(1);
987 }
988 their_addr.sin_family = AF_INET; /* host byte order */
989 their_addr.sin_port = htons(args.port); /* short, network byte order */
990 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
991 memset(&(their_addr.sin_zero), '\0', 8);
992 if(connect(sockfd, (struct sockaddr *)&their_addr,
993 sizeof(struct sockaddr)) == -1)
994 {
995 perror("connect");
996 exit(1);
997 }
998
999 if(!args.data)
1000 {
1001 i = snprintf(buf, MAXDATASIZE,
1002 "GET / HTTP/1.0\r\n"
1003 "User-Agent: %s/%s\r\n"
1004#ifdef UNUSED
1005 "Accept: */*\r\n"
1006 "Connection: close\r\n"
1007#endif
1008 "\r\n"
1009 , AGENTSTRING, revisionstr);
1010 }
1011 else
1012 {
1013 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
1014 "GET /%s HTTP/1.0\r\n"
1015 "User-Agent: %s/%s\r\n"
1016#ifdef UNUSED
1017 "Accept: */*\r\n"
1018 "Connection: close\r\n"
1019#endif
1020 "Authorization: Basic "
1021 , args.data, AGENTSTRING, revisionstr);
1022 if(i > MAXDATASIZE-40 && i < 0) /* second check for old glibc */
1023 {
1024 fprintf(stderr, "Requested data too long\n");
1025 exit(1);
1026 }
1027 i += encode(buf+i, MAXDATASIZE-i-5, args.user, args.password);
1028 if(i > MAXDATASIZE-5)
1029 {
1030 fprintf(stderr, "Username and/or password too long\n");
1031 exit(1);
1032 }
1033 snprintf(buf+i, 5, "\r\n\r\n");
1034 i += 5;
1035 }
1036 if(send(sockfd, buf, (size_t)i, 0) != i)
1037 {
1038 perror("send");
1039 exit(1);
1040 }
1041 if(args.data)
1042 {
1043 int k = 0;
1044 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
1045 {
1046 if(!k)
1047 {
1048 if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
1049 {
1050 fprintf(stderr, "Could not get the requested data: ");
1051 for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
1052 {
1053 fprintf(stderr, "%c", isprint(buf[k]) ? buf[k] : '.');
1054 }
1055 fprintf(stderr, "\n");
1056 exit(1);
1057 }
1058 ++k;
1059 }
1060 else
1061 {
1062 int z;
1063 for(z = 0; z < numbytes && !stop; ++z)
1064 HandleByte(&Parser, buf[z]);
1065 }
1066 }
1067 }
1068 else
1069 {
1070 while((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
1071 {
1072 fwrite(buf, (size_t)numbytes, 1, stdout);
1073 }
1074 }
1075
1076 close(sockfd);
1077 }
1078 return 0;
1079}
Note: See TracBrowser for help on using the repository browser.