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

Last change on this file since 1037 was 1037, checked in by weber, 16 years ago

* empty log message *

File size: 77.1 KB
Line 
1/*
2 Converter for RTCM3 data to RINEX.
3 $Id: rtcm3torinex.c,v 1.14 2008/08/11 14:01:54 weber Exp $
4 Copyright (C) 2005-2008 by Dirk Stöcker <stoecker@alberding.eu>
5
6 This software is a complete NTRIP-RTCM3 to RINEX converter as well as
7 a module of the BNC tool for multiformat conversion. Contact Dirk
8 Stöcker for suggestions and bug reports related to the RTCM3 to RINEX
9 conversion problems and the author of BNC for all the other problems.
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 or read http://www.gnu.org/licenses/gpl.txt
25*/
26
27#include <ctype.h>
28#include <errno.h>
29#include <math.h>
30#include <signal.h>
31#include <stdarg.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/types.h>
36#include <time.h>
37#include <unistd.h>
38
39#ifndef NO_RTCM3_MAIN
40#include <getopt.h>
41#include <netdb.h>
42#include <netinet/in.h>
43#include <sys/socket.h>
44#endif
45
46#ifndef sparc
47#include <stdint.h>
48#endif
49
50#include "rtcm3torinex.h"
51
52/* CVS revision and version */
53static char revisionstr[] = "$Revision: 1.14 $";
54
55#ifndef COMPILEDATE
56#define COMPILEDATE " built " __DATE__
57#endif
58
59static uint32_t CRC24(long size, const unsigned char *buf)
60{
61 uint32_t crc = 0;
62 int i;
63
64 while(size--)
65 {
66 crc ^= (*buf++) << (16);
67 for(i = 0; i < 8; i++)
68 {
69 crc <<= 1;
70 if(crc & 0x1000000)
71 crc ^= 0x01864cfb;
72 }
73 }
74 return crc;
75}
76
77static int GetMessage(struct RTCM3ParserData *handle)
78{
79 unsigned char *m, *e;
80 int i;
81
82 m = handle->Message+handle->SkipBytes;
83 e = handle->Message+handle->MessageSize;
84 handle->NeedBytes = handle->SkipBytes = 0;
85 while(e-m >= 3)
86 {
87 if(m[0] == 0xD3)
88 {
89 handle->size = ((m[1]&3)<<8)|m[2];
90 if(e-m >= handle->size+6)
91 {
92 if((uint32_t)((m[3+handle->size]<<16)|(m[3+handle->size+1]<<8)
93 |(m[3+handle->size+2])) == CRC24(handle->size+3, m))
94 {
95 handle->SkipBytes = handle->size;
96 break;
97 }
98 else
99 ++m;
100 }
101 else
102 {
103 handle->NeedBytes = handle->size+6;
104 break;
105 }
106 }
107 else
108 ++m;
109 }
110 if(e-m < 3)
111 handle->NeedBytes = 3;
112
113 /* copy buffer to front */
114 i = m - handle->Message;
115 if(i && m < e)
116 memmove(handle->Message, m, (size_t)(handle->MessageSize-i));
117 handle->MessageSize -= i;
118
119 return !handle->NeedBytes;
120}
121
122#define LOADBITS(a) \
123{ \
124 while((a) > numbits) \
125 { \
126 if(!size--) break; \
127 bitfield = (bitfield<<8)|*(data++); \
128 numbits += 8; \
129 } \
130}
131
132/* extract bits from data stream
133 b = variable to store result, a = number of bits */
134#define GETBITS(b, a) \
135{ \
136 LOADBITS(a) \
137 b = (bitfield<<(64-numbits))>>(64-(a)); \
138 numbits -= (a); \
139}
140
141/* extract floating value from data stream
142 b = variable to store result, a = number of bits */
143#define GETFLOAT(b, a, c) \
144{ \
145 LOADBITS(a) \
146 b = ((double)((bitfield<<(64-numbits))>>(64-(a))))*(c); \
147 numbits -= (a); \
148}
149
150/* extract signed floating value from data stream
151 b = variable to store result, a = number of bits */
152#define GETFLOATSIGN(b, a, c) \
153{ \
154 LOADBITS(a) \
155 b = ((double)(((int64_t)(bitfield<<(64-numbits)))>>(64-(a))))*(c); \
156 numbits -= (a); \
157}
158
159/* extract bits from data stream
160 b = variable to store result, a = number of bits */
161#define GETBITSSIGN(b, a) \
162{ \
163 LOADBITS(a) \
164 b = ((int64_t)(bitfield<<(64-numbits)))>>(64-(a)); \
165 numbits -= (a); \
166}
167
168#define GETFLOATSIGNM(b, a, c) \
169{ int l; \
170 LOADBITS(a) \
171 l = (bitfield<<(64-numbits))>>(64-1); \
172 b = ((double)(((bitfield<<(64-(numbits-1))))>>(64-(a-1))))*(c); \
173 numbits -= (a); \
174 if(l) b *= -1.0; \
175}
176
177#define SKIPBITS(b) { LOADBITS(b) numbits -= (b); }
178
179struct leapseconds { /* specify the day of leap second */
180 int day; /* this is the day, where 23:59:59 exists 2 times */
181 int month; /* not the next day! */
182 int year;
183 int taicount;
184};
185static const int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
186static const struct leapseconds leap[] = {
187/*{31, 12, 1971, 11},*/
188/*{31, 12, 1972, 12},*/
189/*{31, 12, 1973, 13},*/
190/*{31, 12, 1974, 14},*/
191/*{31, 12, 1975, 15},*/
192/*{31, 12, 1976, 16},*/
193/*{31, 12, 1977, 17},*/
194/*{31, 12, 1978, 18},*/
195/*{31, 12, 1979, 19},*/
196{30, 06, 1981,20},
197{30, 06, 1982,21},
198{30, 06, 1983,22},
199{30, 06, 1985,23},
200{31, 12, 1987,24},
201{31, 12, 1989,25},
202{31, 12, 1990,26},
203{30, 06, 1992,27},
204{30, 06, 1993,28},
205{30, 06, 1994,29},
206{31, 12, 1995,30},
207{30, 06, 1997,31},
208{31, 12, 1998,32},
209{31, 12, 2005,33},
210{31, 12, 2008,34},
211{0,0,0,0} /* end marker */
212};
213#define LEAPSECONDS 14 /* only needed for approx. time */
214#define GPSLEAPSTART 19 /* 19 leap seconds existed at 6.1.1980 */
215
216static int longyear(int year, int month)
217{
218 if(!(year % 4) && (!(year % 400) || (year % 100)))
219 {
220 if(!month || month == 2)
221 return 1;
222 }
223 return 0;
224}
225
226static int gnumleap(int year, int month, int day)
227{
228 int ls = 0;
229 const struct leapseconds *l;
230
231 for(l = leap; l->taicount && year >= l->year; ++l)
232 {
233 if(year > l->year || month > l->month || day > l->day)
234 ls = l->taicount - GPSLEAPSTART;
235 }
236 return ls;
237}
238
239void updatetime(int *week, int *tow, int tk, int fixnumleap)
240{
241 int y,m,d,k,l, nul;
242 unsigned int j = *week*(7*24*60*60) + *tow + 5*24*60*60+3*60*60;
243 int glo_daynumber = 0, glo_timeofday;
244 for(y = 1980; j >= (unsigned int)(k = (l = (365+longyear(y,0)))*24*60*60)
245 + gnumleap(y+1,1,1); ++y)
246 {
247 j -= k; glo_daynumber += l;
248 }
249 for(m = 1; j >= (unsigned int)(k = (l = months[m]+longyear(y, m))*24*60*60)
250 + gnumleap(y, m+1, 1); ++m)
251 {
252 j -= k; glo_daynumber += l;
253 }
254 for(d = 1; j >= 24UL*60UL*60UL + gnumleap(y, m, d+1); ++d)
255 j -= 24*60*60;
256 glo_daynumber -= 16*365+4-d;
257 nul = gnumleap(y, m, d);
258 glo_timeofday = j-nul;
259
260 if(tk < 5*60*1000 && glo_timeofday > 23*60*60)
261 *tow += 24*60*60;
262 else if(glo_timeofday < 5*60 && tk > 23*60*60*1000)
263 *tow -= 24*60*60;
264 *tow += tk/1000-glo_timeofday;
265 if(fixnumleap)
266 *tow -= nul;
267 if(*tow < 0) {*tow += 24*60*60*7; --*week; }
268 if(*tow >= 24*60*60*7) {*tow -= 24*60*60*7; ++*week; }
269}
270
271int RTCM3Parser(struct RTCM3ParserData *handle)
272{
273 int ret=0;
274
275 while(!ret && GetMessage(handle))
276 {
277 /* using 64 bit integer types, as it is much easier than handling
278 the long datatypes in 32 bit */
279 uint64_t numbits = 0, bitfield = 0;
280 int size = handle->size, type;
281 int syncf, old = 0;
282 unsigned char *data = handle->Message+3;
283
284 GETBITS(type,12)
285 handle->typeList[handle->typeSize] = type; /* RTCM message types */
286 if(handle->typeSize < 100) {handle->typeSize += 1;} /* RTCM message types */
287 switch(type)
288 {
289 case 1019:
290 {
291 struct gpsephemeris *ge;
292 int sv;
293
294 ge = &handle->ephemerisGPS;
295 memset(ge, 0, sizeof(*ge));
296
297 GETBITS(sv, 6)
298 ge->satellite = (sv < 40 ? sv : sv+80);
299 GETBITS(ge->GPSweek, 10)
300 ge->GPSweek += 1024;
301 GETBITS(ge->URAindex, 4)
302 GETBITS(sv, 2)
303 if(sv & 1)
304 ge->flags |= GPSEPHF_L2PCODE;
305 if(sv & 2)
306 ge->flags |= GPSEPHF_L2CACODE;
307 GETFLOATSIGN(ge->IDOT, 14, PI/(double)(1<<30)/(double)(1<<13))
308 GETBITS(ge->IODE, 8)
309 GETBITS(ge->TOC, 16)
310 ge->TOC <<= 4;
311 GETFLOATSIGN(ge->clock_driftrate, 8, 1.0/(double)(1<<30)/(double)(1<<25))
312 GETFLOATSIGN(ge->clock_drift, 16, 1.0/(double)(1<<30)/(double)(1<<13))
313 GETFLOATSIGN(ge->clock_bias, 22, 1.0/(double)(1<<30)/(double)(1<<1))
314 GETBITS(ge->IODC, 10)
315 GETFLOATSIGN(ge->Crs, 16, 1.0/(double)(1<<5))
316 GETFLOATSIGN(ge->Delta_n, 16, PI/(double)(1<<30)/(double)(1<<13))
317 GETFLOATSIGN(ge->M0, 32, PI/(double)(1<<30)/(double)(1<<1))
318 GETFLOATSIGN(ge->Cuc, 16, 1.0/(double)(1<<29))
319 GETFLOAT(ge->e, 32, 1.0/(double)(1<<30)/(double)(1<<3))
320 GETFLOATSIGN(ge->Cus, 16, 1.0/(double)(1<<29))
321 GETFLOAT(ge->sqrt_A, 32, 1.0/(double)(1<<19))
322 GETBITS(ge->TOE, 16)
323 ge->TOE <<= 4;
324
325 GETFLOATSIGN(ge->Cic, 16, 1.0/(double)(1<<29))
326 GETFLOATSIGN(ge->OMEGA0, 32, PI/(double)(1<<30)/(double)(1<<1))
327 GETFLOATSIGN(ge->Cis, 16, 1.0/(double)(1<<29))
328 GETFLOATSIGN(ge->i0, 32, PI/(double)(1<<30)/(double)(1<<1))
329 GETFLOATSIGN(ge->Crc, 16, 1.0/(double)(1<<5))
330 GETFLOATSIGN(ge->omega, 32, PI/(double)(1<<30)/(double)(1<<1))
331 GETFLOATSIGN(ge->OMEGADOT, 24, PI/(double)(1<<30)/(double)(1<<13))
332 GETFLOATSIGN(ge->TGD, 8, 1.0/(double)(1<<30)/(double)(1<<1))
333 GETBITS(ge->SVhealth, 6)
334 GETBITS(sv, 1)
335 if(sv)
336 ge->flags |= GPSEPHF_L2PCODEDATA;
337
338 ret = 1019;
339 }
340 break;
341 case 1020:
342 {
343 struct glonassephemeris *ge;
344 int i;
345
346 ge = &handle->ephemerisGLONASS;
347 memset(ge, 0, sizeof(*ge));
348
349 ge->flags |= GLOEPHF_PAVAILABLE;
350 GETBITS(ge->almanac_number, 6)
351 GETBITS(i, 5)
352 ge->frequency_number = i-7;
353 GETBITS(i, 1)
354 if(i)
355 ge->flags |= GLOEPHF_ALMANACHEALTHY;
356 GETBITS(i, 1)
357 if(i)
358 ge->flags |= GLOEPHF_ALMANACHEALTHOK;
359 GETBITS(i, 2)
360 if(i & 1)
361 ge->flags |= GLOEPHF_P10TRUE;
362 if(i & 2)
363 ge->flags |= GLOEPHF_P11TRUE;
364 GETBITS(i, 5)
365 ge->tk = i*60*60;
366 GETBITS(i, 6)
367 ge->tk += i*60;
368 GETBITS(i, 1)
369 ge->tk += i*30;
370 GETBITS(i, 1)
371 if(i)
372 ge->flags |= GLOEPHF_UNHEALTHY;
373 GETBITS(i, 1)
374 if(i)
375 ge->flags |= GLOEPHF_P2TRUE;
376 GETBITS(i, 7)
377 ge->tb = i*15*60;
378 GETFLOATSIGNM(ge->x_velocity, 24, 1.0/(double)(1<<20))
379 GETFLOATSIGNM(ge->x_pos, 27, 1.0/(double)(1<<11))
380 GETFLOATSIGNM(ge->x_acceleration, 5, 1.0/(double)(1<<30))
381 GETFLOATSIGNM(ge->y_velocity, 24, 1.0/(double)(1<<20))
382 GETFLOATSIGNM(ge->y_pos, 27, 1.0/(double)(1<<11))
383 GETFLOATSIGNM(ge->y_acceleration, 5, 1.0/(double)(1<<30))
384 GETFLOATSIGNM(ge->z_velocity, 24, 1.0/(double)(1<<20))
385 GETFLOATSIGNM(ge->z_pos, 27, 1.0/(double)(1<<11))
386 GETFLOATSIGNM(ge->z_acceleration, 5, 1.0/(double)(1<<30))
387 GETBITS(i, 1)
388 if(i)
389 ge->flags |= GLOEPHF_P3TRUE;
390 GETFLOATSIGNM(ge->gamma, 11, 1.0/(double)(1<<30)/(double)(1<<10))
391 SKIPBITS(3) /* GLONASS-M P, GLONASS-M ln (third string) */
392 GETFLOATSIGNM(ge->tau, 22, 1.0/(double)(1<<30)) /* GLONASS tau n(tb) */
393 SKIPBITS(5) /* GLONASS-M delta tau n(tb) */
394 GETBITS(ge->E, 5)
395 /* GETBITS(b, 1) / * GLONASS-M P4 */
396 /* GETBITS(b, 4) / * GLONASS-M Ft */
397 /* GETBITS(b, 11) / * GLONASS-M Nt */
398 /* GETBITS(b, 2) / * GLONASS-M M */
399 /* GETBITS(b, 1) / * GLONASS-M The Availability of Additional Data */
400 /* GETBITS(b, 11) / * GLONASS-M Na */
401 /* GETFLOATSIGNM(b, 32, 1.0/(double)(1<<30)/(double)(1<<1)) / * GLONASS tau c */
402 /* GETBITS(b, 5) / * GLONASS-M N4 */
403 /* GETFLOATSIGNM(b, 22, 1.0/(double)(1<<30)/(double)(1<<1)) / * GLONASS-M tau GPS */
404 /* GETBITS(b, 1) / * GLONASS-M ln (fifth string) */
405 ge->GPSWeek = handle->GPSWeek;
406 ge->GPSTOW = handle->GPSTOW;
407 ret = 1020;
408 }
409 break;
410 case 1001: case 1002: case 1003: case 1004:
411 if(handle->GPSWeek)
412 {
413 int lastlockl1[64];
414 int lastlockl2[64];
415 struct gnssdata *gnss;
416 int i, num, 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,30)
425 if(i/1000 < (int)handle->GPSTOW - 86400)
426 ++handle->GPSWeek;
427 handle->GPSTOW = i/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 gnss->timeofweek = i;
436 gnss->week = handle->GPSWeek;
437
438 GETBITS(syncf,1) /* sync */
439 GETBITS(i,5)
440 // gnss->numsats = i;
441 gnss->numsats += i; // If GLONASS observations come first, Weber
442 SKIPBITS(4) /* smind, smint */
443
444 // for(num = 0; num < gnss->numsats; ++num)
445 for(num = gnss->numsats-i; num < gnss->numsats; ++num) // If GLONASS observations come first, Weber
446 {
447 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
448
449 GETBITS(sv, 6);
450 gnss->satellites[num] = (sv < 40 ? sv : sv+80);
451 /* L1 */
452 GETBITS(code, 1);
453 if(code)
454 {
455 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
456 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
457 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
458 }
459 else
460 {
461 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
462 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
463 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
464 }
465 GETBITS(l1range, 24);
466 GETBITSSIGN(i, 20);
467 if((i&((1<<20)-1)) != 0x80000)
468 {
469 gnss->dataflags[num] |= (c|l);
470 gnss->measdata[num][ce] = l1range*0.02;
471 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
472 }
473 GETBITS(i, 7);
474 lastlockl1[sv] = i;
475 if(handle->lastlockl1[sv] > i)
476 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
477 if(type == 1002 || type == 1004)
478 {
479 GETBITS(amb,8);
480 if(amb && (gnss->dataflags[num] & c))
481 {
482 gnss->measdata[num][ce] += amb*299792.458;
483 gnss->measdata[num][le] += amb*299792.458;
484 ++wasamb;
485 }
486 GETBITS(i, 8);
487 if(i)
488 {
489 gnss->dataflags[num] |= s;
490 gnss->measdata[num][se] = i*0.25;
491 i /= 4*4;
492 if(i > 9) i = 9;
493 else if(i < 1) i = 1;
494 gnss->snrL1[num] = i;
495 }
496 }
497 gnss->measdata[num][le] /= GPS_WAVELENGTH_L1;
498 if(type == 1003 || type == 1004)
499 {
500 /* L2 */
501 GETBITS(code,2);
502 if(code)
503 {
504 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
505 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
506 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
507 }
508 else
509 {
510 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
511 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
512 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
513 }
514 GETBITSSIGN(i,14);
515 if((i&((1<<14)-1)) != 0x2000)
516 {
517 gnss->dataflags[num] |= c;
518 gnss->measdata[num][ce] = l1range*0.02+i*0.02
519 +amb*299792.458;
520 }
521 GETBITSSIGN(i,20);
522 if((i&((1<<20)-1)) != 0x80000)
523 {
524 gnss->dataflags[num] |= l;
525 gnss->measdata[num][le] = l1range*0.02+i*0.0005
526 +amb*299792.458;
527 }
528 GETBITS(i,7);
529 lastlockl2[sv] = i;
530 if(handle->lastlockl2[sv] > i)
531 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
532 if(type == 1004)
533 {
534 GETBITS(i, 8);
535 if(i)
536 {
537 gnss->dataflags[num] |= s;
538 gnss->measdata[num][se] = i*0.25;
539 i /= 4*4;
540 if(i > 9) i = 9;
541 else if(i < 1) i = 1;
542 gnss->snrL2[num] = i;
543 }
544 }
545 gnss->measdata[num][le] /= GPS_WAVELENGTH_L2;
546 }
547 }
548 for(i = 0; i < 64; ++i)
549 {
550 handle->lastlockl1[i] = lastlockl1[i];
551 handle->lastlockl2[i] = lastlockl2[i];
552 }
553 if(!syncf && !old)
554 {
555 handle->Data = *gnss;
556 memset(gnss, 0, sizeof(*gnss));
557 }
558 if(!syncf || old)
559 {
560 if(wasamb) /* not RINEX compatible without */
561 ret = 1;
562 else
563 ret = 2;
564 }
565 }
566 break;
567 case 1009: case 1010: case 1011: case 1012:
568 {
569 int lastlockl1[64];
570 int lastlockl2[64];
571 struct gnssdata *gnss;
572 int i, num;
573 int wasamb=0;
574
575 for(i = 0; i < 64; ++i)
576 lastlockl1[i] = lastlockl2[i] = 0;
577
578 gnss = &handle->DataNew;
579
580 SKIPBITS(12) /* id */;
581 GETBITS(i,27) /* tk */
582
583 updatetime(&handle->GPSWeek, &handle->GPSTOW, i, 0);
584 i = handle->GPSTOW*1000;
585 if(gnss->week && (gnss->timeofweek != i || gnss->week
586 != handle->GPSWeek))
587 {
588 handle->Data = *gnss;
589 memset(gnss, 0, sizeof(*gnss));
590 old = 1;
591 }
592
593 gnss->timeofweek = i;
594 gnss->week = handle->GPSWeek;
595
596 GETBITS(syncf,1) /* sync */
597 GETBITS(i,5)
598 gnss->numsats += i;
599
600 SKIPBITS(4) /* smind, smint */
601
602 for(num = gnss->numsats-i; num < gnss->numsats; ++num)
603 {
604 int sv, code, l1range, c,l,s,ce,le,se,amb=0;
605 int freq;
606
607 GETBITS(sv, 6)
608 gnss->satellites[num] = sv-1 + PRN_GLONASS_START;
609 /* L1 */
610 GETBITS(code, 1)
611 GETBITS(freq, 5)
612 if(code)
613 {
614 c = GNSSDF_P1DATA; ce = GNSSENTRY_P1DATA;
615 l = GNSSDF_L1PDATA; le = GNSSENTRY_L1PDATA;
616 s = GNSSDF_S1PDATA; se = GNSSENTRY_S1PDATA;
617 }
618 else
619 {
620 c = GNSSDF_C1DATA; ce = GNSSENTRY_C1DATA;
621 l = GNSSDF_L1CDATA; le = GNSSENTRY_L1CDATA;
622 s = GNSSDF_S1CDATA; se = GNSSENTRY_S1CDATA;
623 }
624 GETBITS(l1range, 25)
625 GETBITSSIGN(i, 20)
626 if((i&((1<<20)-1)) != 0x80000)
627 {
628 /* Handle this like GPS. Actually for GLONASS L1 range is always
629 valid. To be on the save side, we handle it as invalid like we
630 do for GPS and also remove range in case of 0x80000. */
631 gnss->dataflags[num] |= (c|l);
632 gnss->measdata[num][ce] = l1range*0.02;
633 gnss->measdata[num][le] = l1range*0.02+i*0.0005;
634 }
635 GETBITS(i, 7)
636 lastlockl1[sv] = i;
637 if(handle->lastlockl1[sv] > i)
638 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL1;
639 if(type == 1010 || type == 1012)
640 {
641 GETBITS(amb,7)
642 if(amb && (gnss->dataflags[num] & c))
643 {
644 gnss->measdata[num][ce] += amb*599584.916;
645 gnss->measdata[num][le] += amb*599584.916;
646 ++wasamb;
647 }
648 GETBITS(i, 8)
649 if(i)
650 {
651 gnss->dataflags[num] |= s;
652 gnss->measdata[num][se] = i*0.25;
653 i /= 4*4;
654 if(i > 9) i = 9;
655 else if(i < 1) i = 1;
656 gnss->snrL1[num] = i;
657 }
658 }
659 gnss->measdata[num][le] /= GLO_WAVELENGTH_L1(freq-7);
660 if(type == 1011 || type == 1012)
661 {
662 /* L2 */
663 GETBITS(code,2)
664 if(code)
665 {
666 c = GNSSDF_P2DATA; ce = GNSSENTRY_P2DATA;
667 l = GNSSDF_L2PDATA; le = GNSSENTRY_L2PDATA;
668 s = GNSSDF_S2PDATA; se = GNSSENTRY_S2PDATA;
669 }
670 else
671 {
672 c = GNSSDF_C2DATA; ce = GNSSENTRY_C2DATA;
673 l = GNSSDF_L2CDATA; le = GNSSENTRY_L2CDATA;
674 s = GNSSDF_S2CDATA; se = GNSSENTRY_S2CDATA;
675 }
676 GETBITSSIGN(i,14)
677 if((i&((1<<14)-1)) != 0x2000)
678 {
679 gnss->dataflags[num] |= c;
680 gnss->measdata[num][ce] = l1range*0.02+i*0.02
681 +amb*599584.916;
682 }
683 GETBITSSIGN(i,20)
684 if((i&((1<<20)-1)) != 0x80000)
685 {
686 gnss->dataflags[num] |= l;
687 gnss->measdata[num][le] = l1range*0.02+i*0.0005
688 +amb*599584.916;
689 }
690 GETBITS(i,7)
691 lastlockl2[sv] = i;
692 if(handle->lastlockl2[sv] > i)
693 gnss->dataflags[num] |= GNSSDF_LOCKLOSSL2;
694 if(type == 1012)
695 {
696 GETBITS(i, 8)
697 if(i)
698 {
699 gnss->dataflags[num] |= s;
700 gnss->measdata[num][se] = i*0.25;
701 i /= 4*4;
702 if(i > 9) i = 9;
703 else if(i < 1) i = 1;
704 gnss->snrL2[num] = i;
705 }
706 }
707 gnss->measdata[num][le] /= GLO_WAVELENGTH_L2(freq-7);
708 }
709 if(!sv || sv > 24)
710 {
711 --num; --gnss->numsats;
712 }
713 }
714 for(i = 0; i < 64; ++i)
715 {
716 handle->lastlockl1[i] = lastlockl1[i];
717 handle->lastlockl2[i] = lastlockl2[i];
718 }
719 if(!syncf && !old)
720 {
721 handle->Data = *gnss;
722 memset(gnss, 0, sizeof(*gnss));
723 }
724 if(!syncf || old)
725 {
726 if(wasamb) /* not RINEX compatible without */
727 ret = 1;
728 else
729 ret = 2;
730 }
731 }
732 break;
733 }
734 }
735 return ret;
736}
737
738struct Header
739{
740 const char *version;
741 const char *pgm;
742 const char *marker;
743 const char *markertype;
744 const char *observer;
745 const char *receiver;
746 const char *antenna;
747 const char *position;
748 const char *antennaposition;
749 const char *wavelength;
750 const char *typesofobs; /* should not be modified outside */
751 const char *typesofobsG; /* should not be modified outside */
752 const char *typesofobsR; /* should not be modified outside */
753 const char *typesofobsS; /* should not be modified outside */
754 const char *timeoffirstobs; /* should not be modified outside */
755};
756
757#define MAXHEADERLINES 50
758#define MAXHEADERBUFFERSIZE 4096
759struct HeaderData
760{
761 union
762 {
763 struct Header named;
764 const char *unnamed[MAXHEADERLINES];
765 } data;
766 int numheaders;
767};
768
769struct converttimeinfo {
770 int second; /* seconds of GPS time [0..59] */
771 int minute; /* minutes of GPS time [0..59] */
772 int hour; /* hour of GPS time [0..24] */
773 int day; /* day of GPS time [1..28..30(31)*/
774 int month; /* month of GPS time [1..12]*/
775 int year; /* year of GPS time [1980..] */
776};
777
778void converttime(struct converttimeinfo *c, int week, int tow)
779{
780 int i, k, doy, j; /* temporary variables */
781 j = week*(7*24*60*60) + tow + 5*24*60*60;
782 for(i = 1980; j >= (k = (365+longyear(i,0))*24*60*60); ++i)
783 j -= k;
784 c->year = i;
785 doy = 1+ (j / (24*60*60));
786 j %= (24*60*60);
787 c->hour = j / (60*60);
788 j %= (60*60);
789 c->minute = j / 60;
790 c->second = j % 60;
791 j = 0;
792 for(i = 1; j + (k = months[i] + longyear(c->year,i)) < doy; ++i)
793 j += k;
794 c->month = i;
795 c->day = doy - j;
796}
797
798#ifndef NO_RTCM3_MAIN
799void RTCM3Error(const char *fmt, ...)
800{
801 va_list v;
802 va_start(v, fmt);
803 vfprintf(stderr, fmt, v);
804 va_end(v);
805}
806#endif
807
808void RTCM3Text(const char *fmt, ...)
809{
810 va_list v;
811 va_start(v, fmt);
812 vprintf(fmt, v);
813 va_end(v);
814}
815
816static int HandleRunBy(char *buffer, int buffersize, const char **u,
817int rinex3)
818{
819 const char *user;
820 time_t t;
821 struct tm * t2;
822
823#ifdef NO_RTCM3_MAIN
824 if(revisionstr[0] == '$')
825 {
826 char *a;
827 int i=0;
828 for(a = revisionstr+11; *a && *a != ' '; ++a)
829 revisionstr[i++] = *a;
830 revisionstr[i] = 0;
831 }
832#endif
833
834 user= getenv("USER");
835 if(!user) user = "";
836 t = time(&t);
837 t2 = gmtime(&t);
838 if(u) *u = user;
839 return 1+snprintf(buffer, buffersize,
840 rinex3 ?
841 "RTCM3TORINEX %-7.7s%-20.20s%04d%02d%02d %02d%02d%02d UTC "
842 "PGM / RUN BY / DATE" :
843 "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d "
844 "PGM / RUN BY / DATE", revisionstr, user, 1900+t2->tm_year,
845 t2->tm_mon+1, t2->tm_mday, t2->tm_hour, t2->tm_min, t2->tm_sec);
846}
847
848// Inserted parts for BNC Perlt
849#ifdef NO_RTCM3_MAIN
850#define NUMSTARTSKIP 1
851#else
852#define NUMSTARTSKIP 3
853#endif
854
855void HandleHeader(struct RTCM3ParserData *Parser)
856{
857#ifdef NO_RTCM3_MAIN
858// Part of Handle Header for data request for BNC (independently on actually delivered data), original is commented out by ifndef NO_RTCM3_MAIN. Perlt
859 int i;
860 if(Parser->rinex3)
861 {
862#define CHECKFLAGSNEW(a, b, c) \
863 { \
864 Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
865 Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
866 ++Parser->numdatatypes##a; \
867 }
868
869 CHECKFLAGSNEW(GPS, C1, C1C)
870 CHECKFLAGSNEW(GPS, L1C, L1C)
871 CHECKFLAGSNEW(GPS, D1C, D1C)
872 CHECKFLAGSNEW(GPS, S1C, S1C)
873 CHECKFLAGSNEW(GPS, P1, C1P)
874 CHECKFLAGSNEW(GPS, L1P, L1P)
875 CHECKFLAGSNEW(GPS, D1P, D1P)
876 CHECKFLAGSNEW(GPS, S1P, S1P)
877 CHECKFLAGSNEW(GPS, P2, C2P)
878 CHECKFLAGSNEW(GPS, L2P, L2P)
879 CHECKFLAGSNEW(GPS, D2P, D2P)
880 CHECKFLAGSNEW(GPS, S2P, S2P)
881 CHECKFLAGSNEW(GPS, C2, C2X)
882 CHECKFLAGSNEW(GPS, L2C, L2X)
883 CHECKFLAGSNEW(GPS, D2C, D2X)
884 CHECKFLAGSNEW(GPS, S2C, S2X)
885 CHECKFLAGSNEW(GLO, C1, C1C)
886 CHECKFLAGSNEW(GLO, L1C, L1C)
887 CHECKFLAGSNEW(GLO, D1C, D1C)
888 CHECKFLAGSNEW(GLO, S1C, S1C)
889 CHECKFLAGSNEW(GLO, P1, C1P)
890 CHECKFLAGSNEW(GLO, L1P, L1P)
891 CHECKFLAGSNEW(GLO, D1P, D1P)
892 CHECKFLAGSNEW(GLO, S1P, S1P)
893 CHECKFLAGSNEW(GLO, P2, C2P)
894 CHECKFLAGSNEW(GLO, L2P, L2P)
895 CHECKFLAGSNEW(GLO, D2P, D2P)
896 CHECKFLAGSNEW(GLO, S2P, S2P)
897 CHECKFLAGSNEW(GLO, C2, C2C)
898 CHECKFLAGSNEW(GLO, L2C, L2C)
899 CHECKFLAGSNEW(GLO, D2C, D2C)
900 CHECKFLAGSNEW(GLO, S2C, S2C)
901
902 }
903 else
904 {
905#define CHECKFLAGS(a, b) \
906 { \
907 if(data[RINEXENTRY_##b##DATA]) \
908 { \
909 Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
910 Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
911 } \
912 else \
913 { \
914 Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
915 Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
916 data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
917 } \
918 }
919
920 int data[RINEXENTRY_NUMBER];
921 for(i = 0; i < RINEXENTRY_NUMBER; ++i) data[i] = 0;
922
923 CHECKFLAGS(C1,C1)
924 CHECKFLAGS(C2,C2)
925 CHECKFLAGS(P1,P1)
926 CHECKFLAGS(P2,P2)
927 CHECKFLAGS(L1C,L1)
928 CHECKFLAGS(L1P,L1)
929 CHECKFLAGS(L2C,L2)
930 CHECKFLAGS(L2P,L2)
931 CHECKFLAGS(D1C,D1)
932 CHECKFLAGS(D1P,D1)
933 CHECKFLAGS(D2C,D2)
934 CHECKFLAGS(D2P,D2)
935 CHECKFLAGS(S1C,S1)
936 CHECKFLAGS(S1P,S1)
937 CHECKFLAGS(S2C,S2)
938 CHECKFLAGS(S2P,S2)
939 }
940// End Part of Handle Header for BNC Perlt
941#endif
942
943#ifndef NO_RTCM3_MAIN
944 struct HeaderData hdata;
945 char thebuffer[MAXHEADERBUFFERSIZE];
946 char *buffer = thebuffer;
947 size_t buffersize = sizeof(thebuffer);
948 int i;
949
950 memset(&hdata, 0, sizeof(hdata));
951
952 hdata.data.named.version = buffer;
953 i = 1+snprintf(buffer, buffersize,
954 "%9.2f OBSERVATION DATA M (Mixed)"
955 " RINEX VERSION / TYPE", Parser->rinex3 ? 3.0 : 2.11);
956 buffer += i; buffersize -= i;
957
958 {
959 const char *str;
960 hdata.data.named.pgm = buffer;
961 i = HandleRunBy(buffer, buffersize, &str, Parser->rinex3);
962 buffer += i; buffersize -= i;
963 hdata.data.named.observer = buffer;
964 i = 1+snprintf(buffer, buffersize,
965 "%-20.20s "
966 "OBSERVER / AGENCY", str);
967 buffer += i; buffersize -= i;
968 }
969
970 hdata.data.named.marker =
971 "RTCM3TORINEX "
972 "MARKER NAME";
973
974 hdata.data.named.markertype = !Parser->rinex3 ? 0 :
975 "GEODETIC "
976 "MARKER TYPE";
977
978 hdata.data.named.receiver =
979 " "
980 "REC # / TYPE / VERS";
981
982 hdata.data.named.antenna =
983 " "
984 "ANT # / TYPE";
985
986 hdata.data.named.position =
987 " .0000 .0000 .0000 "
988 "APPROX POSITION XYZ";
989
990 hdata.data.named.antennaposition =
991 " .0000 .0000 .0000 "
992 "ANTENNA: DELTA H/E/N";
993
994 hdata.data.named.wavelength = Parser->rinex3 ? 0 :
995 " 1 1 "
996 "WAVELENGTH FACT L1/2";
997
998 if(Parser->rinex3)
999 {
1000#define CHECKFLAGSNEW(a, b, c) \
1001 if(flags & GNSSDF_##b##DATA) \
1002 { \
1003 Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
1004 Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
1005 ++Parser->numdatatypes##a; \
1006 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#c); \
1007 tbufferpos += 4; \
1008 }
1009
1010 int flags = Parser->startflags;
1011 char tbuffer[6*RINEXENTRY_NUMBER+1];
1012 int tbufferpos = 0;
1013 for(i = 0; i < Parser->Data.numsats; ++i)
1014 flags |= Parser->Data.dataflags[i];
1015
1016 CHECKFLAGSNEW(GPS, C1, C1C)
1017 CHECKFLAGSNEW(GPS, L1C, L1C)
1018 CHECKFLAGSNEW(GPS, D1C, D1C)
1019 CHECKFLAGSNEW(GPS, S1C, S1C)
1020 CHECKFLAGSNEW(GPS, P1, C1P)
1021 CHECKFLAGSNEW(GPS, L1P, L1P)
1022 CHECKFLAGSNEW(GPS, D1P, D1P)
1023 CHECKFLAGSNEW(GPS, S1P, S1P)
1024
1025 hdata.data.named.typesofobsS = buffer;
1026 i = 1+snprintf(buffer, buffersize,
1027 "S %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
1028 buffer += i; buffersize -= i;
1029
1030 CHECKFLAGSNEW(GPS, P2, C2P)
1031 CHECKFLAGSNEW(GPS, L2P, L2P)
1032 CHECKFLAGSNEW(GPS, D2P, D2P)
1033 CHECKFLAGSNEW(GPS, S2P, S2P)
1034 CHECKFLAGSNEW(GPS, C2, C2X)
1035 CHECKFLAGSNEW(GPS, L2C, L2X)
1036 CHECKFLAGSNEW(GPS, D2C, D2X)
1037 CHECKFLAGSNEW(GPS, S2C, S2X)
1038
1039 hdata.data.named.typesofobsG = buffer;
1040 i = 1+snprintf(buffer, buffersize,
1041 "G %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
1042 if(Parser->numdatatypesGPS>13)
1043 {
1044 i += snprintf(buffer+i-1, buffersize,
1045 "\n %-52.52s SYS / # / OBS TYPES", tbuffer+13*4);
1046 }
1047 buffer += i; buffersize -= i;
1048
1049 tbufferpos = 0;
1050
1051 CHECKFLAGSNEW(GLO, C1, C1C)
1052 CHECKFLAGSNEW(GLO, L1C, L1C)
1053 CHECKFLAGSNEW(GLO, D1C, D1C)
1054 CHECKFLAGSNEW(GLO, S1C, S1C)
1055 CHECKFLAGSNEW(GLO, P1, C1P)
1056 CHECKFLAGSNEW(GLO, L1P, L1P)
1057 CHECKFLAGSNEW(GLO, D1P, D1P)
1058 CHECKFLAGSNEW(GLO, S1P, S1P)
1059 CHECKFLAGSNEW(GLO, P2, C2P)
1060 CHECKFLAGSNEW(GLO, L2P, L2P)
1061 CHECKFLAGSNEW(GLO, D2P, D2P)
1062 CHECKFLAGSNEW(GLO, S2P, S2P)
1063 CHECKFLAGSNEW(GLO, C2, C2C)
1064 CHECKFLAGSNEW(GLO, L2C, L2C)
1065 CHECKFLAGSNEW(GLO, D2C, D2C)
1066 CHECKFLAGSNEW(GLO, S2C, S2C)
1067
1068 hdata.data.named.typesofobsR = buffer;
1069 i = 1+snprintf(buffer, buffersize,
1070 "R %3d%-52.52s SYS / # / OBS TYPES", Parser->numdatatypesGLO, tbuffer);
1071 if(Parser->numdatatypesGLO>13)
1072 {
1073 i += snprintf(buffer+i-1, buffersize,
1074 "\n %-52.52s SYS / # / OBS TYPES", tbuffer+13*4);
1075 }
1076 buffer += i; buffersize -= i;
1077 }
1078 else
1079 {
1080#define CHECKFLAGS(a, b) \
1081 if(flags & GNSSDF_##a##DATA) \
1082 { \
1083 if(data[RINEXENTRY_##b##DATA]) \
1084 { \
1085 Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
1086 Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
1087 } \
1088 else \
1089 { \
1090 Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
1091 Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
1092 data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
1093 snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#b); \
1094 tbufferpos += 6; \
1095 } \
1096 }
1097
1098 int flags = Parser->startflags;
1099 int data[RINEXENTRY_NUMBER];
1100 char tbuffer[6*RINEXENTRY_NUMBER+1];
1101 int tbufferpos = 0;
1102 for(i = 0; i < RINEXENTRY_NUMBER; ++i)
1103 data[i] = 0;
1104 for(i = 0; i < Parser->Data.numsats; ++i)
1105 flags |= Parser->Data.dataflags[i];
1106
1107 CHECKFLAGS(C1,C1)
1108 CHECKFLAGS(C2,C2)
1109 CHECKFLAGS(P1,P1)
1110 CHECKFLAGS(P2,P2)
1111 CHECKFLAGS(L1C,L1)
1112 CHECKFLAGS(L1P,L1)
1113 CHECKFLAGS(L2C,L2)
1114 CHECKFLAGS(L2P,L2)
1115 CHECKFLAGS(D1C,D1)
1116 CHECKFLAGS(D1P,D1)
1117 CHECKFLAGS(D2C,D2)
1118 CHECKFLAGS(D2P,D2)
1119 CHECKFLAGS(S1C,S1)
1120 CHECKFLAGS(S1P,S1)
1121 CHECKFLAGS(S2C,S2)
1122 CHECKFLAGS(S2P,S2)
1123
1124 hdata.data.named.typesofobs = buffer;
1125 i = 1+snprintf(buffer, buffersize,
1126 "%6d%-54.54s# / TYPES OF OBSERV", Parser->numdatatypesGPS, tbuffer);
1127 if(Parser->numdatatypesGPS>9)
1128 {
1129 i += snprintf(buffer+i-1, buffersize,
1130 "\n %-54.54s# / TYPES OF OBSERV", tbuffer+9*6);
1131 }
1132 buffer += i; buffersize -= i;
1133 }
1134
1135 {
1136 struct converttimeinfo cti;
1137 converttime(&cti, Parser->Data.week,
1138 (int)floor(Parser->Data.timeofweek/1000.0));
1139 hdata.data.named.timeoffirstobs = buffer;
1140 i = 1+snprintf(buffer, buffersize,
1141 " %4d %2d %2d %2d %2d %10.7f GPS "
1142 "TIME OF FIRST OBS", cti.year, cti.month, cti.day, cti.hour,
1143 cti.minute, cti.second + fmod(Parser->Data.timeofweek/1000.0,1.0));
1144
1145 buffer += i; buffersize -= i;
1146 }
1147
1148 hdata.numheaders = 15;
1149
1150 if(Parser->headerfile)
1151 {
1152 FILE *fh;
1153 if((fh = fopen(Parser->headerfile, "r")))
1154 {
1155 size_t siz;
1156 char *lastblockstart;
1157 if((siz = fread(buffer, 1, buffersize-1, fh)) > 0)
1158 {
1159 buffer[siz] = '\n';
1160 if(siz == buffersize)
1161 {
1162 RTCM3Error("Header file is too large. Only %d bytes read.",
1163 (int)siz);
1164 }
1165 /* scan the file line by line and enter the entries in the list */
1166 /* warn for "# / TYPES OF OBSERV" and "TIME OF FIRST OBS" */
1167 /* overwrites entries, except for comments */
1168 lastblockstart = buffer;
1169 for(i = 0; i < (int)siz; ++i)
1170 {
1171 if(buffer[i] == '\n')
1172 { /* we found a line */
1173 char *end;
1174 while(buffer[i+1] == '\r')
1175 ++i; /* skip \r in case there are any */
1176 end = buffer+i;
1177 while(*end == '\t' || *end == ' ' || *end == '\r' || *end == '\n')
1178 *(end--) = 0;
1179 if(end-lastblockstart < 60+5) /* short line */
1180 RTCM3Error("Short Header line '%s' ignored.\n", lastblockstart);
1181 else
1182 {
1183 int pos;
1184 if(!strcmp("COMMENT", lastblockstart+60))
1185 pos = hdata.numheaders;
1186 else
1187 {
1188 for(pos = 0; pos < hdata.numheaders; ++pos)
1189 {
1190 if(!strcmp(hdata.data.unnamed[pos]+60, lastblockstart+60))
1191 break;
1192 }
1193 if(!strcmp("# / TYPES OF OBSERV", lastblockstart+60)
1194 || !strcmp("TIME OF FIRST OBS", lastblockstart+60))
1195 {
1196 RTCM3Error("Overwriting header '%s' is dangerous.\n",
1197 lastblockstart+60);
1198 }
1199 }
1200 if(pos >= MAXHEADERLINES)
1201 {
1202 RTCM3Error("Maximum number of header lines of %d reached.\n",
1203 MAXHEADERLINES);
1204 }
1205 else if(!strcmp("END OF HEADER", lastblockstart+60))
1206 {
1207 RTCM3Error("End of header ignored.\n");
1208 }
1209 else
1210 {
1211 hdata.data.unnamed[pos] = lastblockstart;
1212 if(pos == hdata.numheaders)
1213 ++hdata.numheaders;
1214 }
1215 }
1216 lastblockstart = buffer+i+1;
1217 }
1218 }
1219 }
1220 else
1221 {
1222 RTCM3Error("Could not read data from headerfile '%s'.\n",
1223 Parser->headerfile);
1224 }
1225 fclose(fh);
1226 }
1227 else
1228 {
1229 RTCM3Error("Could not open header datafile '%s'.\n",
1230 Parser->headerfile);
1231 }
1232 }
1233
1234 for(i = 0; i < hdata.numheaders; ++i)
1235 {
1236 if(hdata.data.unnamed[i] && hdata.data.unnamed[i][0])
1237 RTCM3Text("%s\n", hdata.data.unnamed[i]);
1238 }
1239 RTCM3Text(" "
1240 "END OF HEADER\n");
1241#endif
1242}
1243
1244static void ConvLine(FILE *file, const char *fmt, ...)
1245{
1246 char buffer[100], *b;
1247 va_list v;
1248 va_start(v, fmt);
1249 vsnprintf(buffer, sizeof(buffer), fmt, v);
1250 for(b = buffer; *b; ++b)
1251 {
1252 if(*b == 'e') *b = 'D';
1253 }
1254 fprintf(file, "%s", buffer);
1255 va_end(v);
1256}
1257
1258void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
1259{
1260 Parser->Message[Parser->MessageSize++] = byte;
1261 if(Parser->MessageSize >= Parser->NeedBytes)
1262 {
1263 int r;
1264 while((r = RTCM3Parser(Parser)))
1265 {
1266 if(r == 1020 || r == 1019)
1267 {
1268 FILE *file = 0;
1269
1270 if(Parser->rinex3 && !(file = Parser->gpsfile))
1271 {
1272 const char *n = Parser->gpsephemeris ? Parser->gpsephemeris : Parser->glonassephemeris;
1273 if(n)
1274 {
1275 if(!(Parser->gpsfile = fopen(n, "w")))
1276 {
1277 RTCM3Error("Could not open ephemeris output file.\n");
1278 }
1279 else
1280 {
1281 char buffer[100];
1282 fprintf(Parser->gpsfile,
1283 "%9.2f%11sN: GNSS NAV DATA M: Mixed%12sRINEX VERSION / TYPE\n", 3.0, "", "");
1284 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1285 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1286 }
1287 Parser->gpsephemeris = 0;
1288 Parser->glonassephemeris = 0;
1289 file = Parser->gpsfile;
1290 }
1291 }
1292 else
1293 {
1294 if(r == 1020)
1295 {
1296 if(Parser->glonassephemeris)
1297 {
1298 if(!(Parser->glonassfile = fopen(Parser->glonassephemeris, "w")))
1299 {
1300 RTCM3Error("Could not open GLONASS ephemeris output file.\n");
1301 }
1302 else
1303 {
1304 char buffer[100];
1305 fprintf(Parser->glonassfile,
1306 "%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n", 2.1, "", "");
1307 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1308 fprintf(Parser->glonassfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1309 }
1310 Parser->glonassephemeris = 0;
1311 }
1312 file = Parser->glonassfile;
1313 }
1314 else if(r == 1019)
1315 {
1316 if(Parser->gpsephemeris)
1317 {
1318 if(!(Parser->gpsfile = fopen(Parser->gpsephemeris, "w")))
1319 {
1320 RTCM3Error("Could not open GPS ephemeris output file.\n");
1321 }
1322 else
1323 {
1324 char buffer[100];
1325 fprintf(Parser->gpsfile,
1326 "%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 2.1, "", "");
1327 HandleRunBy(buffer, sizeof(buffer), 0, Parser->rinex3);
1328 fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
1329 }
1330 Parser->gpsephemeris = 0;
1331 }
1332 file = Parser->gpsfile;
1333 }
1334 }
1335 if(file)
1336 {
1337 if(r == 1020)
1338 {
1339 struct glonassephemeris *e = &Parser->ephemerisGLONASS;
1340 int w = e->GPSWeek, tow = e->GPSTOW, i;
1341 struct converttimeinfo cti;
1342
1343 updatetime(&w, &tow, e->tb*1000, 1);
1344 converttime(&cti, w, tow);
1345
1346 i = e->tk-3*60*60; if(i < 0) i += 86400;
1347
1348 if(Parser->rinex3)
1349 ConvLine(file, "R%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1350 e->almanac_number, cti.year, cti.month, cti.day, cti.hour, cti.minute,
1351 cti.second, -e->tau, e->gamma, (double) i);
1352 else
1353 ConvLine(file, "%02d %02d %02d %02d %02d %02d%5.1f%19.12e%19.12e%19.12e\n",
1354 e->almanac_number, cti.year%100, cti.month, cti.day, cti.hour, cti.minute,
1355 (double) cti.second, -e->tau, e->gamma, (double) i);
1356 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->x_pos,
1357 e->x_velocity, e->x_acceleration, (e->flags & GLOEPHF_UNHEALTHY) ? 1.0 : 0.0);
1358 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->y_pos,
1359 e->y_velocity, e->y_acceleration, (double) e->frequency_number);
1360 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->z_pos,
1361 e->z_velocity, e->z_acceleration, (double) e->E);
1362 }
1363 else /* if(r == 1019) */
1364 {
1365 struct gpsephemeris *e = &Parser->ephemerisGPS;
1366 double d; /* temporary variable */
1367 unsigned long int i; /* temporary variable */
1368 struct converttimeinfo cti;
1369 converttime(&cti, e->GPSweek, e->TOC);
1370
1371 if(Parser->rinex3)
1372 ConvLine(file, "G%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
1373 e->satellite, cti.year, cti.month, cti.day, cti.hour,
1374 cti.minute, cti.second, e->clock_bias, e->clock_drift,
1375 e->clock_driftrate);
1376 else
1377 ConvLine(file, "%02d %02d %02d %02d %02d %02d%05.1f%19.12e%19.12e%19.12e\n",
1378 e->satellite, cti.year%100, cti.month, cti.day, cti.hour,
1379 cti.minute, (double) cti.second, e->clock_bias, e->clock_drift,
1380 e->clock_driftrate);
1381 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", (double)e->IODE,
1382 e->Crs, e->Delta_n, e->M0);
1383 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->Cuc,
1384 e->e, e->Cus, e->sqrt_A);
1385 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n",
1386 (double) e->TOE, e->Cic, e->OMEGA0, e->Cis);
1387 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->i0,
1388 e->Crc, e->omega, e->OMEGADOT);
1389 d = 0;
1390 i = e->flags;
1391 if(i & GPSEPHF_L2CACODE)
1392 d += 2.0;
1393 if(i & GPSEPHF_L2PCODE)
1394 d += 1.0;
1395 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", e->IDOT, d,
1396 (double) e->GPSweek, i & GPSEPHF_L2PCODEDATA ? 1.0 : 0.0);
1397 if(e->URAindex <= 6) /* URA index */
1398 d = ceil(10.0*pow(2.0, 1.0+((double)e->URAindex)/2.0))/10.0;
1399 else
1400 d = ceil(10.0*pow(2.0, ((double)e->URAindex)/2.0))/10.0;
1401 /* 15 indicates not to use satellite. We can't handle this special
1402 case, so we create a high "non"-accuracy value. */
1403 ConvLine(file, " %19.12e%19.12e%19.12e%19.12e\n", d,
1404 ((double) e->SVhealth), e->TGD, ((double) e->IODC));
1405
1406 ConvLine(file, " %19.12e%19.12e\n", ((double)e->TOW), 0.0);
1407 /* TOW */
1408 }
1409 }
1410 }
1411 else
1412 {
1413 int i, j, o;
1414 struct converttimeinfo cti;
1415
1416 if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
1417 {
1418 ++Parser->init;
1419
1420 if(Parser->init == NUMSTARTSKIP)
1421 HandleHeader(Parser);
1422 else
1423 {
1424 for(i = 0; i < Parser->Data.numsats; ++i)
1425 Parser->startflags |= Parser->Data.dataflags[i];
1426 continue;
1427 }
1428 }
1429 if(r == 2 && !Parser->validwarning)
1430 {
1431 RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
1432 " COMMENT\n");
1433 Parser->validwarning = 1;
1434 }
1435
1436 converttime(&cti, Parser->Data.week,
1437 (int)floor(Parser->Data.timeofweek/1000.0));
1438 if(Parser->rinex3)
1439 {
1440 RTCM3Text("> %04d %02d %02d %02d %02d%11.7f 0%3d\n",
1441 cti.year, cti.month, cti.day, cti.hour, cti.minute, cti.second
1442 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1443 for(i = 0; i < Parser->Data.numsats; ++i)
1444 {
1445 int glo = 0;
1446 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1447 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1448 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1449 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1450 {
1451 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1452 glo = 1;
1453 }
1454 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1455 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1456 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1457 else
1458 RTCM3Text("%3d", Parser->Data.satellites[i]);
1459
1460 if(glo)
1461 {
1462 for(j = 0; j < Parser->numdatatypesGLO; ++j)
1463 {
1464 int df = Parser->dataflagGLO[j];
1465 int pos = Parser->dataposGLO[j];
1466 if((Parser->Data.dataflags[i] & df)
1467 && !isnan(Parser->Data.measdata[i][pos])
1468 && !isinf(Parser->Data.measdata[i][pos]))
1469 {
1470 char lli = ' ';
1471 char snr = ' ';
1472 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1473 {
1474 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1475 lli = '1';
1476 snr = '0'+Parser->Data.snrL1[i];
1477 }
1478 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1479 {
1480 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1481 lli = '1';
1482 snr = '0'+Parser->Data.snrL2[i];
1483 }
1484 RTCM3Text("%14.3f%c%c",
1485 Parser->Data.measdata[i][pos],lli,snr);
1486 }
1487 else
1488 { /* no or illegal data */
1489 RTCM3Text(" ");
1490 }
1491 }
1492 }
1493 else
1494 {
1495 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1496 {
1497 int df = Parser->dataflagGPS[j];
1498 int pos = Parser->dataposGPS[j];
1499 if((Parser->Data.dataflags[i] & df)
1500 && !isnan(Parser->Data.measdata[i][pos])
1501 && !isinf(Parser->Data.measdata[i][pos]))
1502 {
1503 char lli = ' ';
1504 char snr = ' ';
1505 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1506 {
1507 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1508 lli = '1';
1509 snr = '0'+Parser->Data.snrL1[i];
1510 }
1511 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1512 {
1513 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1514 lli = '1';
1515 snr = '0'+Parser->Data.snrL2[i];
1516 }
1517 RTCM3Text("%14.3f%c%c",
1518 Parser->Data.measdata[i][pos],lli,snr);
1519 }
1520 else
1521 { /* no or illegal data */
1522 RTCM3Text(" ");
1523 }
1524 }
1525 }
1526 RTCM3Text("\n");
1527 }
1528 }
1529 else
1530 {
1531 RTCM3Text(" %02d %2d %2d %2d %2d %10.7f 0%3d",
1532 cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
1533 + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
1534 for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
1535 {
1536 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1537 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1538 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1539 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1540 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1541 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1542 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1543 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1544 else
1545 RTCM3Text("%3d", Parser->Data.satellites[i]);
1546 }
1547 RTCM3Text("\n");
1548 o = 12;
1549 j = Parser->Data.numsats - 12;
1550 while(j > 0)
1551 {
1552 RTCM3Text(" ");
1553 for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
1554 {
1555 if(Parser->Data.satellites[i] <= PRN_GPS_END)
1556 RTCM3Text("G%02d", Parser->Data.satellites[i]);
1557 else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
1558 && Parser->Data.satellites[i] <= PRN_GLONASS_END)
1559 RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
1560 else if(Parser->Data.satellites[i] >= PRN_WAAS_START
1561 && Parser->Data.satellites[i] <= PRN_WAAS_END)
1562 RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
1563 else
1564 RTCM3Text("%3d", Parser->Data.satellites[i]);
1565 }
1566 RTCM3Text("\n");
1567 j -= 12;
1568 o += 12;
1569 }
1570 for(i = 0; i < Parser->Data.numsats; ++i)
1571 {
1572 for(j = 0; j < Parser->numdatatypesGPS; ++j)
1573 {
1574 int v = 0;
1575 int df = Parser->dataflag[j];
1576 int pos = Parser->datapos[j];
1577 if((Parser->Data.dataflags[i] & df)
1578 && !isnan(Parser->Data.measdata[i][pos])
1579 && !isinf(Parser->Data.measdata[i][pos]))
1580 {
1581 v = 1;
1582 }
1583 else
1584 {
1585 df = Parser->dataflagGPS[j];
1586 pos = Parser->dataposGPS[j];
1587
1588 if((Parser->Data.dataflags[i] & df)
1589 && !isnan(Parser->Data.measdata[i][pos])
1590 && !isinf(Parser->Data.measdata[i][pos]))
1591 {
1592 v = 1;
1593 }
1594 }
1595
1596 if(!v)
1597 { /* no or illegal data */
1598 RTCM3Text(" ");
1599 }
1600 else
1601 {
1602 char lli = ' ';
1603 char snr = ' ';
1604 if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
1605 {
1606 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
1607 lli = '1';
1608 snr = '0'+Parser->Data.snrL1[i];
1609 }
1610 if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
1611 {
1612 if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
1613 lli = '1';
1614 snr = '0'+Parser->Data.snrL2[i];
1615 }
1616 RTCM3Text("%14.3f%c%c",
1617 Parser->Data.measdata[i][pos],lli,snr);
1618 }
1619 if(j%5 == 4 || j == Parser->numdatatypesGPS-1)
1620 RTCM3Text("\n");
1621 }
1622 }
1623 }
1624 }
1625 }
1626 }
1627}
1628
1629#ifndef NO_RTCM3_MAIN
1630static char datestr[] = "$Date: 2008/08/11 14:01:54 $";
1631
1632/* The string, which is send as agent in HTTP request */
1633#define AGENTSTRING "NTRIP NtripRTCM3ToRINEX"
1634
1635#define MAXDATASIZE 1000 /* max number of bytes we can get at once */
1636
1637static const char encodingTable [64] = {
1638 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1639 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1640 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1641 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1642};
1643
1644/* does not buffer overrun, but breaks directly after an error */
1645/* returns the number of required bytes */
1646static int encode(char *buf, int size, const char *user, const char *pwd)
1647{
1648 unsigned char inbuf[3];
1649 char *out = buf;
1650 int i, sep = 0, fill = 0, bytes = 0;
1651
1652 while(*user || *pwd)
1653 {
1654 i = 0;
1655 while(i < 3 && *user) inbuf[i++] = *(user++);
1656 if(i < 3 && !sep) {inbuf[i++] = ':'; ++sep; }
1657 while(i < 3 && *pwd) inbuf[i++] = *(pwd++);
1658 while(i < 3) {inbuf[i++] = 0; ++fill; }
1659 if(out-buf < size-1)
1660 *(out++) = encodingTable[(inbuf [0] & 0xFC) >> 2];
1661 if(out-buf < size-1)
1662 *(out++) = encodingTable[((inbuf [0] & 0x03) << 4)
1663 | ((inbuf [1] & 0xF0) >> 4)];
1664 if(out-buf < size-1)
1665 {
1666 if(fill == 2)
1667 *(out++) = '=';
1668 else
1669 *(out++) = encodingTable[((inbuf [1] & 0x0F) << 2)
1670 | ((inbuf [2] & 0xC0) >> 6)];
1671 }
1672 if(out-buf < size-1)
1673 {
1674 if(fill >= 1)
1675 *(out++) = '=';
1676 else
1677 *(out++) = encodingTable[inbuf [2] & 0x3F];
1678 }
1679 bytes += 4;
1680 }
1681 if(out-buf < size)
1682 *out = 0;
1683 return bytes;
1684}
1685
1686static int stop = 0;
1687
1688struct Args
1689{
1690 const char *server;
1691 const char *port;
1692 int mode;
1693 int timeout;
1694 int rinex3;
1695 const char *user;
1696 const char *password;
1697 const char *proxyhost;
1698 const char *proxyport;
1699 const char *nmea;
1700 const char *data;
1701 const char *headerfile;
1702 const char *gpsephemeris;
1703 const char *glonassephemeris;
1704};
1705
1706/* option parsing */
1707#ifdef NO_LONG_OPTS
1708#define LONG_OPT(a)
1709#else
1710#define LONG_OPT(a) a
1711static struct option opts[] = {
1712{ "data", required_argument, 0, 'd'},
1713{ "server", required_argument, 0, 's'},
1714{ "password", required_argument, 0, 'p'},
1715{ "port", required_argument, 0, 'r'},
1716{ "timeout", required_argument, 0, 't'},
1717{ "header", required_argument, 0, 'f'},
1718{ "user", required_argument, 0, 'u'},
1719{ "gpsephemeris", required_argument, 0, 'E'},
1720{ "glonassephemeris", required_argument, 0, 'G'},
1721{ "rinex3", no_argument, 0, '3'},
1722{ "proxyport", required_argument, 0, 'R'},
1723{ "proxyhost", required_argument, 0, 'S'},
1724{ "nmea", required_argument, 0, 'n'},
1725{ "mode", required_argument, 0, 'M'},
1726{ "help", no_argument, 0, 'h'},
1727{0,0,0,0}};
1728#endif
1729#define ARGOPT "-d:s:p:r:t:f:u:E:G:M:S:R:n:h3"
1730
1731enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };
1732
1733static const char *geturl(const char *url, struct Args *args)
1734{
1735 static char buf[1000];
1736 static char *Buffer = buf;
1737 static char *Bufend = buf+sizeof(buf);
1738
1739 if(strncmp("ntrip:", url, 6))
1740 return "URL must start with 'ntrip:'.";
1741 url += 6; /* skip ntrip: */
1742
1743 if(*url != '@' && *url != '/')
1744 {
1745 /* scan for mountpoint */
1746 args->data = Buffer;
1747 while(*url && *url != '@' && *url != ';' &&*url != '/' && Buffer != Bufend)
1748 *(Buffer++) = *(url++);
1749 if(Buffer == args->data)
1750 return "Mountpoint required.";
1751 else if(Buffer >= Bufend-1)
1752 return "Parsing buffer too short.";
1753 *(Buffer++) = 0;
1754 }
1755
1756 if(*url == '/') /* username and password */
1757 {
1758 ++url;
1759 args->user = Buffer;
1760 while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
1761 *(Buffer++) = *(url++);
1762 if(Buffer == args->user)
1763 return "Username cannot be empty.";
1764 else if(Buffer >= Bufend-1)
1765 return "Parsing buffer too short.";
1766 *(Buffer++) = 0;
1767
1768 if(*url == ':') ++url;
1769
1770 args->password = Buffer;
1771 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1772 *(Buffer++) = *(url++);
1773 if(Buffer == args->password)
1774 return "Password cannot be empty.";
1775 else if(Buffer >= Bufend-1)
1776 return "Parsing buffer too short.";
1777 *(Buffer++) = 0;
1778 }
1779
1780 if(*url == '@') /* server */
1781 {
1782 ++url;
1783 if(*url != '@' && *url != ':')
1784 {
1785 args->server = Buffer;
1786 while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
1787 *(Buffer++) = *(url++);
1788 if(Buffer == args->server)
1789 return "Servername cannot be empty.";
1790 else if(Buffer >= Bufend-1)
1791 return "Parsing buffer too short.";
1792 *(Buffer++) = 0;
1793 }
1794
1795 if(*url == ':')
1796 {
1797 ++url;
1798 args->port = Buffer;
1799 while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
1800 *(Buffer++) = *(url++);
1801 if(Buffer == args->port)
1802 return "Port cannot be empty.";
1803 else if(Buffer >= Bufend-1)
1804 return "Parsing buffer too short.";
1805 *(Buffer++) = 0;
1806 }
1807
1808 if(*url == '@') /* proxy */
1809 {
1810 ++url;
1811 args->proxyhost = Buffer;
1812 while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
1813 *(Buffer++) = *(url++);
1814 if(Buffer == args->proxyhost)
1815 return "Proxy servername cannot be empty.";
1816 else if(Buffer >= Bufend-1)
1817 return "Parsing buffer too short.";
1818 *(Buffer++) = 0;
1819
1820 if(*url == ':')
1821 {
1822 ++url;
1823 args->proxyport = Buffer;
1824 while(*url && *url != ';' && Buffer != Bufend)
1825 *(Buffer++) = *(url++);
1826 if(Buffer == args->proxyport)
1827 return "Proxy port cannot be empty.";
1828 else if(Buffer >= Bufend-1)
1829 return "Parsing buffer too short.";
1830 *(Buffer++) = 0;
1831 }
1832 }
1833 }
1834 if(*url == ';') /* NMEA */
1835 {
1836 args->nmea = ++url;
1837 while(*url)
1838 ++url;
1839 }
1840
1841 return *url ? "Garbage at end of server string." : 0;
1842}
1843
1844static int getargs(int argc, char **argv, struct Args *args)
1845{
1846 int res = 1;
1847 int getoptr;
1848 int help = 0;
1849 char *t;
1850
1851 args->server = "www.euref-ip.net";
1852 args->port = "2101";
1853 args->timeout = 60;
1854 args->user = "";
1855 args->password = "";
1856 args->data = 0;
1857 args->headerfile = 0;
1858 args->gpsephemeris = 0;
1859 args->glonassephemeris = 0;
1860 args->rinex3 = 0;
1861 args->nmea = 0;
1862 args->proxyhost = 0;
1863 args->proxyport = "2101";
1864 args->mode = AUTO;
1865 help = 0;
1866
1867 do
1868 {
1869
1870#ifdef NO_LONG_OPTS
1871 switch((getoptr = getopt(argc, argv, ARGOPT)))
1872#else
1873 switch((getoptr = getopt_long(argc, argv, ARGOPT, opts, 0)))
1874#endif
1875 {
1876 case 's': args->server = optarg; break;
1877 case 'u': args->user = optarg; break;
1878 case 'p': args->password = optarg; break;
1879 case 'd': args->data = optarg; break;
1880 case 'f': args->headerfile = optarg; break;
1881 case 'E': args->gpsephemeris = optarg; break;
1882 case 'G': args->glonassephemeris = optarg; break;
1883 case 'r': args->port = optarg; break;
1884 case '3': args->rinex3 = 1; break;
1885 case 'S': args->proxyhost = optarg; break;
1886 case 'n': args->nmea = optarg; break;
1887 case 'R': args->proxyport = optarg; break;
1888 case 'h': help=1; break;
1889 case 'M':
1890 args->mode = 0;
1891 if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
1892 args->mode = NTRIP1;
1893 else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
1894 args->mode = HTTP;
1895 else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
1896 args->mode = RTSP;
1897 else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
1898 args->mode = AUTO;
1899 else args->mode = atoi(optarg);
1900 if((args->mode == 0) || (args->mode >= END))
1901 {
1902 fprintf(stderr, "Mode %s unknown\n", optarg);
1903 res = 0;
1904 }
1905 break;
1906 case 't':
1907 args->timeout = strtoul(optarg, &t, 10);
1908 if((t && *t) || args->timeout < 0)
1909 res = 0;
1910 break;
1911
1912 case 1:
1913 {
1914 const char *err;
1915 if((err = geturl(optarg, args)))
1916 {
1917 RTCM3Error("%s\n\n", err);
1918 res = 0;
1919 }
1920 }
1921 break;
1922 case -1: break;
1923 }
1924 } while(getoptr != -1 || !res);
1925
1926 datestr[0] = datestr[7];
1927 datestr[1] = datestr[8];
1928 datestr[2] = datestr[9];
1929 datestr[3] = datestr[10];
1930 datestr[5] = datestr[12];
1931 datestr[6] = datestr[13];
1932 datestr[8] = datestr[15];
1933 datestr[9] = datestr[16];
1934 datestr[4] = datestr[7] = '-';
1935 datestr[10] = 0;
1936
1937 if(args->gpsephemeris && args->glonassephemeris && args->rinex3)
1938 {
1939 RTCM3Error("RINEX3 produces a combined ephemeris file, but 2 files were specified.\n"
1940 "Please specify only one navigation file.\n");
1941 res = 0;
1942 }
1943 else if(!res || help)
1944 {
1945 RTCM3Error("Version %s (%s) GPL" COMPILEDATE
1946 "\nUsage: %s -s server -u user ...\n"
1947 " -d " LONG_OPT("--data ") "the requested data set\n"
1948 " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
1949 " -s " LONG_OPT("--server ") "the server name or address\n"
1950 " -p " LONG_OPT("--password ") "the login password\n"
1951 " -r " LONG_OPT("--port ") "the server port number (default 2101)\n"
1952 " -t " LONG_OPT("--timeout ") "timeout in seconds (default 60)\n"
1953 " -u " LONG_OPT("--user ") "the user name\n"
1954 " -E " LONG_OPT("--gpsephemeris ") "output file for GPS ephemeris data\n"
1955 " -G " LONG_OPT("--glonassephemeris ") "output file for GLONASS ephemeris data\n"
1956 " -3 " LONG_OPT("--rinex3 ") "output RINEX type 3 data\n"
1957 " -S " LONG_OPT("--proxyhost ") "proxy name or address\n"
1958 " -R " LONG_OPT("--proxyport ") "proxy port, optional (default 2101)\n"
1959 " -n " LONG_OPT("--nmea ") "NMEA string for sending to server\n"
1960 " -M " LONG_OPT("--mode ") "mode for data request\n"
1961 " Valid modes are:\n"
1962 " 1, h, http NTRIP Version 2.0 Caster in TCP/IP mode\n"
1963 " 2, r, rtsp NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
1964 " 3, n, ntrip1 NTRIP Version 1.0 Caster\n"
1965 " 4, a, auto automatic detection (default)\n"
1966 "or using an URL:\n%s ntrip:data[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
1967 , revisionstr, datestr, argv[0], argv[0]);
1968 exit(1);
1969 }
1970 return res;
1971}
1972
1973/* let the output complete a block if necessary */
1974static void signalhandler(int sig)
1975{
1976 if(!stop)
1977 {
1978 RTCM3Error("Stop signal number %d received. "
1979 "Trying to terminate gentle.\n", sig);
1980 stop = 1;
1981 alarm(1);
1982 }
1983}
1984
1985#define ALARMTIME (2*60)
1986
1987/* for some reason we had to abort hard (maybe waiting for data */
1988#ifdef __GNUC__
1989static __attribute__ ((noreturn)) void signalhandler_alarm(
1990int sig __attribute__((__unused__)))
1991#else /* __GNUC__ */
1992static void signalhandler_alarm(int sig)
1993#endif /* __GNUC__ */
1994{
1995 RTCM3Error("Programm forcefully terminated.\n");
1996 exit(1);
1997}
1998
1999int main(int argc, char **argv)
2000{
2001 struct Args args;
2002 struct RTCM3ParserData Parser;
2003
2004 setbuf(stdout, 0);
2005 setbuf(stdin, 0);
2006 setbuf(stderr, 0);
2007
2008 {
2009 char *a;
2010 int i=0;
2011 for(a = revisionstr+11; *a && *a != ' '; ++a)
2012 revisionstr[i++] = *a;
2013 revisionstr[i] = 0;
2014 }
2015
2016 signal(SIGINT, signalhandler);
2017 signal(SIGALRM,signalhandler_alarm);
2018 signal(SIGQUIT,signalhandler);
2019 signal(SIGTERM,signalhandler);
2020 signal(SIGPIPE,signalhandler);
2021 memset(&Parser, 0, sizeof(Parser));
2022 {
2023 time_t tim;
2024 tim = time(0) - ((10*365+2+5)*24*60*60+LEAPSECONDS);
2025 Parser.GPSWeek = tim/(7*24*60*60);
2026 Parser.GPSTOW = tim%(7*24*60*60);
2027 }
2028
2029 if(getargs(argc, argv, &args))
2030 {
2031 int sockfd, numbytes;
2032 char buf[MAXDATASIZE];
2033 struct sockaddr_in their_addr; /* connector's address information */
2034 struct hostent *he;
2035 struct servent *se;
2036 const char *server, *port, *proxyserver = 0;
2037 char proxyport[6];
2038 char *b;
2039 long i;
2040 struct timeval tv;
2041
2042 alarm(ALARMTIME);
2043
2044 Parser.headerfile = args.headerfile;
2045 Parser.glonassephemeris = args.glonassephemeris;
2046 Parser.gpsephemeris = args.gpsephemeris;
2047 Parser.rinex3 = args.rinex3;
2048
2049 if(args.proxyhost)
2050 {
2051 int p;
2052 if((i = strtol(args.port, &b, 10)) && (!b || !*b))
2053 p = i;
2054 else if(!(se = getservbyname(args.port, 0)))
2055 {
2056 RTCM3Error("Can't resolve port %s.", args.port);
2057 exit(1);
2058 }
2059 else
2060 {
2061 p = ntohs(se->s_port);
2062 }
2063 snprintf(proxyport, sizeof(proxyport), "%d", p);
2064 port = args.proxyport;
2065 proxyserver = args.server;
2066 server = args.proxyhost;
2067 }
2068 else
2069 {
2070 server = args.server;
2071 port = args.port;
2072 }
2073
2074 memset(&their_addr, 0, sizeof(struct sockaddr_in));
2075 if((i = strtol(port, &b, 10)) && (!b || !*b))
2076 their_addr.sin_port = htons(i);
2077 else if(!(se = getservbyname(port, 0)))
2078 {
2079 RTCM3Error("Can't resolve port %s.", port);
2080 exit(1);
2081 }
2082 else
2083 {
2084 their_addr.sin_port = se->s_port;
2085 }
2086 if(!(he=gethostbyname(server)))
2087 {
2088 RTCM3Error("Server name lookup failed for '%s'.\n", server);
2089 exit(1);
2090 }
2091 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
2092 {
2093 perror("socket");
2094 exit(1);
2095 }
2096
2097 tv.tv_sec = args.timeout;
2098 tv.tv_usec = 0;
2099 if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval) ) == -1)
2100 {
2101 RTCM3Error("Function setsockopt: %s\n", strerror(errno));
2102 exit(1);
2103 }
2104
2105 their_addr.sin_family = AF_INET;
2106 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2107
2108 if(args.data && args.mode == RTSP)
2109 {
2110 struct sockaddr_in local;
2111 int sockudp, localport;
2112 int cseq = 1;
2113 socklen_t len;
2114
2115 if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
2116 {
2117 perror("socket");
2118 exit(1);
2119 }
2120 /* fill structure with local address information for UDP */
2121 memset(&local, 0, sizeof(local));
2122 local.sin_family = AF_INET;
2123 local.sin_port = htons(0);
2124 local.sin_addr.s_addr = htonl(INADDR_ANY);
2125 len = sizeof(local);
2126 /* bind() in order to get a random RTP client_port */
2127 if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
2128 {
2129 perror("bind");
2130 exit(1);
2131 }
2132 if((getsockname(sockudp, (struct sockaddr*)&local, &len)) != -1)
2133 {
2134 localport = ntohs(local.sin_port);
2135 }
2136 else
2137 {
2138 perror("local access failed");
2139 exit(1);
2140 }
2141 if(connect(sockfd, (struct sockaddr *)&their_addr,
2142 sizeof(struct sockaddr)) == -1)
2143 {
2144 perror("connect");
2145 exit(1);
2146 }
2147 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2148 "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"
2149 "CSeq: %d\r\n"
2150 "Ntrip-Version: Ntrip/2.0\r\n"
2151 "Ntrip-Component: Ntripclient\r\n"
2152 "User-Agent: %s/%s\r\n"
2153 "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
2154 "Authorization: Basic ",
2155 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2156 args.data, cseq++, AGENTSTRING, revisionstr, localport);
2157 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
2158 {
2159 RTCM3Error("Requested data too long\n");
2160 exit(1);
2161 }
2162 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
2163 if(i > MAXDATASIZE-4)
2164 {
2165 RTCM3Error("Username and/or password too long\n");
2166 exit(1);
2167 }
2168 buf[i++] = '\r';
2169 buf[i++] = '\n';
2170 buf[i++] = '\r';
2171 buf[i++] = '\n';
2172 if(args.nmea)
2173 {
2174 int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
2175 if(j >= 0 && j < MAXDATASIZE-i)
2176 i += j;
2177 else
2178 {
2179 RTCM3Error("NMEA string too long\n");
2180 exit(1);
2181 }
2182 }
2183 if(send(sockfd, buf, (size_t)i, 0) != i)
2184 {
2185 perror("send");
2186 exit(1);
2187 }
2188 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2189 {
2190 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2191 {
2192 int serverport = 0, session = 0;
2193 const char *portcheck = "server_port=";
2194 const char *sessioncheck = "session: ";
2195 int l = strlen(portcheck)-1;
2196 int j=0;
2197 for(i = 0; j != l && i < numbytes-l; ++i)
2198 {
2199 for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
2200 ;
2201 }
2202 if(i == numbytes-l)
2203 {
2204 RTCM3Error("No server port number found\n");
2205 exit(1);
2206 }
2207 else
2208 {
2209 i+=l;
2210 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2211 serverport = serverport * 10 + buf[i++]-'0';
2212 if(buf[i] != '\r' && buf[i] != ';')
2213 {
2214 RTCM3Error("Could not extract server port\n");
2215 exit(1);
2216 }
2217 }
2218 l = strlen(sessioncheck)-1;
2219 j=0;
2220 for(i = 0; j != l && i < numbytes-l; ++i)
2221 {
2222 for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
2223 ;
2224 }
2225 if(i == numbytes-l)
2226 {
2227 RTCM3Error("No session number found\n");
2228 exit(1);
2229 }
2230 else
2231 {
2232 i+=l;
2233 while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
2234 session = session * 10 + buf[i++]-'0';
2235 if(buf[i] != '\r')
2236 {
2237 RTCM3Error("Could not extract session number\n");
2238 exit(1);
2239 }
2240 }
2241
2242 i = snprintf(buf, MAXDATASIZE,
2243 "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"
2244 "CSeq: %d\r\n"
2245 "Session: %d\r\n"
2246 "\r\n",
2247 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2248 args.data, cseq++, session);
2249
2250 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2251 {
2252 RTCM3Error("Requested data too long\n");
2253 exit(1);
2254 }
2255 if(send(sockfd, buf, (size_t)i, 0) != i)
2256 {
2257 perror("send");
2258 exit(1);
2259 }
2260 if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2261 {
2262 if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
2263 {
2264 struct sockaddr_in addrRTP;
2265 /* fill structure with caster address information for UDP */
2266 memset(&addrRTP, 0, sizeof(addrRTP));
2267 addrRTP.sin_family = AF_INET;
2268 addrRTP.sin_port = htons(serverport);
2269 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
2270 len = sizeof(addrRTP);
2271 int ts = 0;
2272 int sn = 0;
2273 int ssrc = 0;
2274 int init = 0;
2275 int u, v, w;
2276 while(!stop && (i = recvfrom(sockudp, buf, 1526, 0,
2277 (struct sockaddr*) &addrRTP, &len)) > 0)
2278 {
2279 alarm(ALARMTIME);
2280 if(i >= 12+1 && (unsigned char)buf[0] == (2 << 6) && buf[1] == 0x60)
2281 {
2282 u= ((unsigned char)buf[2]<<8)+(unsigned char)buf[3];
2283 v = ((unsigned char)buf[4]<<24)+((unsigned char)buf[5]<<16)
2284 +((unsigned char)buf[6]<<8)+(unsigned char)buf[7];
2285 w = ((unsigned char)buf[8]<<24)+((unsigned char)buf[9]<<16)
2286 +((unsigned char)buf[10]<<8)+(unsigned char)buf[11];
2287
2288 if(init)
2289 {
2290 if(u < -30000 && sn > 30000) sn -= 0xFFFF;
2291 if(ssrc != w || ts > v)
2292 {
2293 RTCM3Error("Illegal UDP data received.\n");
2294 exit(1);
2295 }
2296 if(u > sn) /* don't show out-of-order packets */
2297 fwrite(buf+12, (size_t)i-12, 1, stdout);
2298 }
2299 sn = u; ts = v; ssrc = w; init = 1;
2300 }
2301 else
2302 {
2303 RTCM3Error("Illegal UDP header.\n");
2304 exit(1);
2305 }
2306 }
2307 }
2308 i = snprintf(buf, MAXDATASIZE,
2309 "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"
2310 "CSeq: %d\r\n"
2311 "Session: %d\r\n"
2312 "\r\n",
2313 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
2314 args.data, cseq++, session);
2315
2316 if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
2317 {
2318 RTCM3Error("Requested data too long\n");
2319 exit(1);
2320 }
2321 if(send(sockfd, buf, (size_t)i, 0) != i)
2322 {
2323 perror("send");
2324 exit(1);
2325 }
2326 }
2327 else
2328 {
2329 RTCM3Error("Could not start data stream.\n");
2330 exit(1);
2331 }
2332 }
2333 else
2334 {
2335 RTCM3Error("Could not setup initial control connection.\n");
2336 exit(1);
2337 }
2338 }
2339 else
2340 {
2341 perror("recv");
2342 exit(1);
2343 }
2344 }
2345 else
2346 {
2347 if(connect(sockfd, (struct sockaddr *)&their_addr,
2348 sizeof(struct sockaddr)) == -1)
2349 {
2350 perror("connect");
2351 exit(1);
2352 }
2353 if(!args.data)
2354 {
2355 i = snprintf(buf, MAXDATASIZE,
2356 "GET %s%s%s%s/ HTTP/1.0\r\n"
2357 "Host: %s\r\n%s"
2358 "User-Agent: %s/%s\r\n"
2359 "Connection: close\r\n"
2360 "\r\n"
2361 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
2362 proxyserver ? ":" : "", proxyserver ? proxyport : "",
2363 args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
2364 AGENTSTRING, revisionstr);
2365 }
2366 else
2367 {
2368 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
2369 "GET %s%s%s%s/%s HTTP/1.0\r\n"
2370 "Host: %s\r\n%s"
2371 "User-Agent: %s/%s\r\n"
2372 "Connection: close\r\n"
2373 "Authorization: Basic "
2374 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
2375 proxyserver ? ":" : "", proxyserver ? proxyport : "",
2376 args.data, args.server,
2377 args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
2378 AGENTSTRING, revisionstr);
2379 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
2380 {
2381 RTCM3Error("Requested data too long\n");
2382 exit(1);
2383 }
2384 i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
2385 if(i > MAXDATASIZE-4)
2386 {
2387 RTCM3Error("Username and/or password too long\n");
2388 exit(1);
2389 }
2390 buf[i++] = '\r';
2391 buf[i++] = '\n';
2392 buf[i++] = '\r';
2393 buf[i++] = '\n';
2394 if(args.nmea)
2395 {
2396 int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
2397 if(j >= 0 && j < MAXDATASIZE-i)
2398 i += j;
2399 else
2400 {
2401 RTCM3Error("NMEA string too long\n");
2402 exit(1);
2403 }
2404 }
2405 }
2406 if(send(sockfd, buf, (size_t)i, 0) != i)
2407 {
2408 perror("send");
2409 exit(1);
2410 }
2411 if(args.data)
2412 {
2413 int k = 0;
2414 int chunkymode = 0;
2415 int starttime = time(0);
2416 int lastout = starttime;
2417 int totalbytes = 0;
2418 int chunksize = 0;
2419
2420 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
2421 {
2422 alarm(ALARMTIME);
2423 if(!k)
2424 {
2425 if(numbytes > 17 && (!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17)
2426 || !strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)))
2427 {
2428 const char *datacheck = "Content-Type: gnss/data\r\n";
2429 const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
2430 int l = strlen(datacheck)-1;
2431 int j=0;
2432 for(i = 0; j != l && i < numbytes-l; ++i)
2433 {
2434 for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
2435 ;
2436 }
2437 if(i == numbytes-l)
2438 {
2439 RTCM3Error("No 'Content-Type: gnss/data' found\n");
2440 exit(1);
2441 }
2442 l = strlen(chunkycheck)-1;
2443 j=0;
2444 for(i = 0; j != l && i < numbytes-l; ++i)
2445 {
2446 for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
2447 ;
2448 }
2449 if(i < numbytes-l)
2450 chunkymode = 1;
2451 }
2452 else if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
2453 {
2454 RTCM3Error("Could not get the requested data: ");
2455 for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
2456 {
2457 RTCM3Error("%c", isprint(buf[k]) ? buf[k] : '.');
2458 }
2459 RTCM3Error("\n");
2460 exit(1);
2461 }
2462 else if(args.mode != NTRIP1)
2463 {
2464 if(args.mode != AUTO)
2465 {
2466 RTCM3Error("NTRIP version 2 HTTP connection failed%s.\n",
2467 args.mode == AUTO ? ", falling back to NTRIP1" : "");
2468 }
2469 if(args.mode == HTTP)
2470 exit(1);
2471 }
2472 ++k;
2473 }
2474 else
2475 {
2476 if(chunkymode)
2477 {
2478 int stop = 0;
2479 int pos = 0;
2480 while(!stop && pos < numbytes)
2481 {
2482 switch(chunkymode)
2483 {
2484 case 1: /* reading number starts */
2485 chunksize = 0;
2486 ++chunkymode; /* no break */
2487 case 2: /* during reading number */
2488 i = buf[pos++];
2489 if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
2490 else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
2491 else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
2492 else if(i == '\r') ++chunkymode;
2493 else if(i == ';') chunkymode = 5;
2494 else stop = 1;
2495 break;
2496 case 3: /* scanning for return */
2497 if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
2498 else stop = 1;
2499 break;
2500 case 4: /* output data */
2501 i = numbytes-pos;
2502 if(i > chunksize) i = chunksize;
2503 {
2504 int z;
2505 for(z = 0; z < i && !stop; ++z)
2506 HandleByte(&Parser, (unsigned int) buf[pos+z]);
2507 }
2508 totalbytes += i;
2509 chunksize -= i;
2510 pos += i;
2511 if(!chunksize)
2512 chunkymode = 1;
2513 break;
2514 case 5:
2515 if(i == '\r') chunkymode = 3;
2516 break;
2517 }
2518 }
2519 if(stop)
2520 {
2521 RTCM3Error("Error in chunky transfer encoding\n");
2522 break;
2523 }
2524 }
2525 else
2526 {
2527 totalbytes += numbytes;
2528 {
2529 int z;
2530 for(z = 0; z < numbytes && !stop; ++z)
2531 HandleByte(&Parser, (unsigned int) buf[z]);
2532 }
2533 }
2534 if(totalbytes < 0) /* overflow */
2535 {
2536 totalbytes = 0;
2537 starttime = time(0);
2538 lastout = starttime;
2539 }
2540 }
2541 }
2542 }
2543 else
2544 {
2545 while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
2546 {
2547 alarm(ALARMTIME);
2548 fwrite(buf, (size_t)numbytes, 1, stdout);
2549 }
2550 }
2551 close(sockfd);
2552 }
2553 }
2554 return 0;
2555}
2556#endif /* NO_RTCM3_MAIN */
Note: See TracBrowser for help on using the repository browser.