Changeset 502 in ntrip


Ignore:
Timestamp:
Oct 8, 2007, 2:51:24 PM (15 years ago)
Author:
stoecker
Message:

update to RINEX3 and epohemeris support

Location:
trunk/rtcm3torinex
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/rtcm3torinex/rtcm3torinex.c

    r498 r502  
    11/*
    22  Converter for RTCM3 data to RINEX.
    3   $Id: rtcm3torinex.c,v 1.21 2007/08/14 10:14:37 stoecker Exp $
    4   Copyright (C) 2005-2006 by Dirk Stoecker <stoecker@euronik.eu>
     3  $Id: rtcm3torinex.c,v 1.22 2007/10/01 11:07:08 stoecker Exp $
     4  Copyright (C) 2005-2006 by Dirk Stoecker <stoecker@alberding.eu>
    55
    66  This software is a complete NTRIP-RTCM3 to RINEX converter as well as
     
    5151
    5252/* CVS revision and version */
    53 static char revisionstr[] = "$Revision: 1.21 $";
     53static char revisionstr[] = "$Revision: 1.22 $";
    5454
    5555#ifndef COMPILEDATE
     
    139139}
    140140
     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
    141159/* extract bits from data stream
    142160   b = variable to store result, a = number of bits */
     
    146164  b = ((int64_t)(bitfield<<(64-numbits)))>>(64-(a)); \
    147165  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; \
    148175}
    149176
     
    209236}
    210237
    211 static void updatetime(int *week, int *tow, int tk)
     238static void updatetime(int *week, int *tow, int tk, int fixnumleap)
    212239{
    213   int y,m,d,k,l;
     240  int y,m,d,k,l, nul;
    214241  unsigned int j = *week*(7*24*60*60) + *tow + 5*24*60*60+3*60*60;
    215242  int glo_daynumber = 0, glo_timeofday;
     
    227254    j -= 24*60*60;
    228255  glo_daynumber -= 16*365+4-d;
    229   glo_timeofday = j-gnumleap(y, m, d);
     256  nul = gnumleap(y, m, d);
     257  glo_timeofday = j-nul;
    230258
    231259  if(tk < 5*60*1000 && glo_timeofday > 23*60*60)
     
    234262    *tow -= 24*60*60;
    235263  *tow += tk/1000-glo_timeofday;
     264  if(fixnumleap)
     265    *tow -= nul;
    236266  if(*tow < 0) {*tow += 24*60*60*7; --*week; }
    237267  if(*tow >= 24*60*60*7) {*tow -= 24*60*60*7; ++*week; }
     
    254284    switch(type)
    255285    {
     286    case 1019:
     287      {
     288        struct gpsephemeris *ge;
     289        int sv;
     290
     291        ge = &handle->ephemerisGPS;
     292        memset(ge, 0, sizeof(*ge));
     293
     294        GETBITS(sv, 6)
     295        ge->satellite = (sv < 40 ? sv : sv+80);
     296        GETBITS(ge->GPSweek, 10)
     297        ge->GPSweek += 1024;
     298        GETBITS(ge->URAindex, 4)
     299        GETBITS(sv, 2)
     300        if(sv & 1)
     301          ge->flags |= GPSEPHF_L2PCODE;
     302        if(sv & 2)
     303          ge->flags |= GPSEPHF_L2CACODE;
     304        GETFLOATSIGN(ge->IDOT, 14, PI/(double)(1<<30)/(double)(1<<13))
     305        GETBITS(ge->IODE, 8)
     306        GETBITS(ge->TOC, 16)
     307        ge->TOC <<= 4;
     308        GETFLOATSIGN(ge->clock_driftrate, 8, 1.0/(double)(1<<30)/(double)(1<<25))
     309        GETFLOATSIGN(ge->clock_drift, 16, 1.0/(double)(1<<30)/(double)(1<<13))
     310        GETFLOATSIGN(ge->clock_bias, 22, 1.0/(double)(1<<30)/(double)(1<<1))
     311        GETBITS(ge->IODC, 10)
     312        GETFLOATSIGN(ge->Crs, 16, 1.0/(double)(1<<5))
     313        GETFLOATSIGN(ge->Delta_n, 16, PI/(double)(1<<30)/(double)(1<<13))
     314        GETFLOATSIGN(ge->M0, 32, PI/(double)(1<<30)/(double)(1<<1))
     315        GETFLOATSIGN(ge->Cuc, 16, 1.0/(double)(1<<29))
     316        GETFLOAT(ge->e, 32, 1.0/(double)(1<<30)/(double)(1<<3))
     317        GETFLOATSIGN(ge->Cus, 16, 1.0/(double)(1<<29))
     318        GETFLOAT(ge->sqrt_A, 32, 1.0/(double)(1<<19))
     319        GETBITS(ge->TOE, 16)
     320        ge->TOE <<= 4;
     321
     322        GETFLOATSIGN(ge->Cic, 16, 1.0/(double)(1<<29))
     323        GETFLOATSIGN(ge->OMEGA0, 32, PI/(double)(1<<30)/(double)(1<<1))
     324        GETFLOATSIGN(ge->Cis, 16, 1.0/(double)(1<<29))
     325        GETFLOATSIGN(ge->i0, 32, PI/(double)(1<<30)/(double)(1<<1))
     326        GETFLOATSIGN(ge->Crc, 16, 1.0/(double)(1<<5))
     327        GETFLOATSIGN(ge->omega, 32, PI/(double)(1<<30)/(double)(1<<1))
     328        GETFLOATSIGN(ge->OMEGADOT, 24, PI/(double)(1<<30)/(double)(1<<13))
     329        GETFLOATSIGN(ge->TGD, 8, 1.0/(double)(1<<30)/(double)(1<<1))
     330        GETBITS(ge->SVhealth, 6)
     331        GETBITS(sv, 1)
     332        if(sv)
     333          ge->flags |= GPSEPHF_L2PCODEDATA;
     334
     335        ret = 1019;
     336      }
     337      break;
     338    case 1020:
     339      {
     340        struct glonassephemeris *ge;
     341        int i;
     342
     343        ge = &handle->ephemerisGLONASS;
     344        memset(ge, 0, sizeof(*ge));
     345
     346        ge->flags |= GLOEPHF_PAVAILABLE;
     347        GETBITS(ge->almanac_number, 6)
     348        GETBITS(i, 5)
     349        ge->frequency_number = i-7;
     350        GETBITS(i, 1)
     351        if(i)
     352          ge->flags |= GLOEPHF_ALMANACHEALTHY;
     353        GETBITS(i, 1)
     354        if(i)
     355          ge->flags |= GLOEPHF_ALMANACHEALTHOK;
     356        GETBITS(i, 2)
     357        if(i & 1)
     358          ge->flags |= GLOEPHF_P10TRUE;
     359        if(i & 2)
     360          ge->flags |= GLOEPHF_P11TRUE;
     361        GETBITS(i, 5)
     362        ge->tk = i*60*60;
     363        GETBITS(i, 6)
     364        ge->tk += i*60;
     365        GETBITS(i, 1)
     366        ge->tk += i*30;
     367        GETBITS(i, 1)
     368        if(i)
     369          ge->flags |= GLOEPHF_UNHEALTHY;
     370        GETBITS(i, 1)
     371        if(i)
     372          ge->flags |= GLOEPHF_P2TRUE;
     373        GETBITS(i, 7)
     374        ge->tb = i*15*60;
     375        GETFLOATSIGNM(ge->x_velocity, 24, 1.0/(double)(1<<20))
     376        GETFLOATSIGNM(ge->x_pos, 27, 1.0/(double)(1<<11))
     377        GETFLOATSIGNM(ge->x_acceleration, 5, 1.0/(double)(1<<30))
     378        GETFLOATSIGNM(ge->y_velocity, 24, 1.0/(double)(1<<20))
     379        GETFLOATSIGNM(ge->y_pos, 27, 1.0/(double)(1<<11))
     380        GETFLOATSIGNM(ge->y_acceleration, 5, 1.0/(double)(1<<30))
     381        GETFLOATSIGNM(ge->z_velocity, 24, 1.0/(double)(1<<20))
     382        GETFLOATSIGNM(ge->z_pos, 27, 1.0/(double)(1<<11))
     383        GETFLOATSIGNM(ge->z_acceleration, 5, 1.0/(double)(1<<30))
     384        GETBITS(i, 1)
     385        if(i)
     386          ge->flags |= GLOEPHF_P3TRUE;
     387        GETFLOATSIGNM(ge->gamma, 11, 1.0/(double)(1<<30)/(double)(1<<10))
     388        SKIPBITS(3) /* GLONASS-M P, GLONASS-M ln (third string) */
     389        GETFLOATSIGNM(ge->tau, 22, 1.0/(double)(1<<30)) /* GLONASS tau n(tb) */
     390        SKIPBITS(5) /* GLONASS-M delta tau n(tb) */
     391        GETBITS(ge->E, 5)
     392        /* GETBITS(b, 1) / * GLONASS-M P4 */
     393        /* GETBITS(b, 4) / * GLONASS-M Ft */
     394        /* GETBITS(b, 11) / * GLONASS-M Nt */
     395        /* GETBITS(b, 2) / * GLONASS-M M */
     396        /* GETBITS(b, 1) / * GLONASS-M The Availability of Additional Data */
     397        /* GETBITS(b, 11) / * GLONASS-M Na */
     398        /* GETFLOATSIGNM(b, 32, 1.0/(double)(1<<30)/(double)(1<<1)) / * GLONASS tau c */
     399        /* GETBITS(b, 5) / * GLONASS-M N4 */
     400        /* GETFLOATSIGNM(b, 22, 1.0/(double)(1<<30)/(double)(1<<1)) / * GLONASS-M tau GPS */
     401        /* GETBITS(b, 1) / * GLONASS-M ln (fifth string) */
     402        ge->GPSWeek = handle->GPSWeek;
     403        ge->GPSTOW = handle->GPSTOW;
     404        ret = 1020;
     405      }
     406      break;
    256407    case 1001: case 1002: case 1003: case 1004:
    257408      if(handle->GPSWeek)
     
    429580        GETBITS(i,27) /* tk */
    430581
    431         updatetime(&handle->GPSWeek, &handle->GPSTOW, i);
     582        updatetime(&handle->GPSWeek, &handle->GPSTOW, i, 0);
    432583        i = handle->GPSTOW*1000;
    433584        if(gnss->week && (gnss->timeofweek != i || gnss->week
     
    597748  const char *wavelength;
    598749  const char *typesofobs; /* should not be modified outside */
     750  const char *typesofobsG; /* should not be modified outside */
     751  const char *typesofobsR; /* should not be modified outside */
     752  const char *typesofobsS; /* should not be modified outside */
    599753  const char *timeoffirstobs; /* should not be modified outside */
    600754};
     
    659813}
    660814
     815static int HandleRunBy(char *buffer, int buffersize, const char **u)
     816{
     817  const char *user;
     818  time_t t;
     819  struct tm * t2;
     820
     821#ifdef NO_RTCM3_MAIN
     822  if(revisionstr[0] == '$')
     823  {
     824    char *a;
     825    int i=0;
     826    for(a = revisionstr+11; *a && *a != ' '; ++a)
     827      revisionstr[i++] = *a;
     828    revisionstr[i] = 0;
     829  }
     830#endif
     831
     832  user= getenv("USER");
     833  if(!user) user = "";
     834  t = time(&t);
     835  t2 = gmtime(&t);
     836  if(u) *u = user;
     837  return 1+snprintf(buffer, buffersize,
     838  "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d    "
     839  "PGM / RUN BY / DATE", revisionstr, user, 1900+t2->tm_year,
     840  t2->tm_mon+1, t2->tm_mday, t2->tm_hour, t2->tm_min);
     841}
     842
    661843#define NUMSTARTSKIP 3
    662844void HandleHeader(struct RTCM3ParserData *Parser)
     
    668850  int i;
    669851
    670   hdata.data.named.version =
    671   "     2.11           OBSERVATION DATA    M (Mixed)"
    672   "           RINEX VERSION / TYPE";
     852  hdata.data.named.version = buffer;
     853  i = 1+snprintf(buffer, buffersize,
     854  "%9.2f           OBSERVATION DATA    M (Mixed)"
     855  "           RINEX VERSION / TYPE", Parser->rinex3 ? 3.0 : 2.11);
     856  buffer += i; buffersize -= i;
    673857
    674858  {
    675859    const char *str;
    676     time_t t;
    677     struct tm * t2;
    678 
    679 #ifdef NO_RTCM3_MAIN
    680     if(revisionstr[0] == '$')
    681     {
    682       char *a;
    683       int i=0;
    684       for(a = revisionstr+11; *a && *a != ' '; ++a)
    685         revisionstr[i++] = *a;
    686       revisionstr[i] = 0;
    687     }
    688 #endif
    689 
    690     str = getenv("USER");
    691     if(!str) str = "";
    692     t = time(&t);
    693     t2 = gmtime(&t);
    694860    hdata.data.named.pgm = buffer;
    695     i = 1+snprintf(buffer, buffersize,
    696     "RTCM3TORINEX %-7.7s%-20.20s%04d-%02d-%02d %02d:%02d    "
    697     "PGM / RUN BY / DATE",
    698     revisionstr, str, 1900+t2->tm_year, t2->tm_mon+1, t2->tm_mday, t2->tm_hour,
    699     t2->tm_min);
     861    i = HandleRunBy(buffer, buffersize, &str);
    700862    buffer += i; buffersize -= i;
    701 
    702863    hdata.data.named.observer = buffer;
    703864    i = 1+snprintf(buffer, buffersize,
     
    727888  "ANTENNA: DELTA H/E/N";
    728889 
    729   hdata.data.named.wavelength =
     890  hdata.data.named.wavelength = Parser->rinex3 ? 0 :
    730891  "     1     1                                                "
    731892  "WAVELENGTH FACT L1/2";
    732893
     894  if(Parser->rinex3)
     895  {
     896#define CHECKFLAGSNEW(a, b, c) \
     897    if(flags & GNSSDF_##b##DATA) \
     898    { \
     899      Parser->dataflag##a[Parser->numdatatypes##a] = GNSSDF_##b##DATA; \
     900      Parser->datapos##a[Parser->numdatatypes##a] = GNSSENTRY_##b##DATA; \
     901      ++Parser->numdatatypes##a; \
     902      snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, " "#c); \
     903      tbufferpos += 4; \
     904    }
     905
     906    int flags = Parser->startflags;
     907    char tbuffer[6*RINEXENTRY_NUMBER+1];
     908    int tbufferpos = 0;
     909    for(i = 0; i < Parser->Data.numsats; ++i)
     910      flags |= Parser->Data.dataflags[i];
     911
     912    CHECKFLAGSNEW(GPS, C1,  C1C)
     913    CHECKFLAGSNEW(GPS, L1C, L1C)
     914    CHECKFLAGSNEW(GPS, D1C, D1C)
     915    CHECKFLAGSNEW(GPS, S1C, S1C)
     916    CHECKFLAGSNEW(GPS, P1,  C1P)
     917    CHECKFLAGSNEW(GPS, L1P, L1P)
     918    CHECKFLAGSNEW(GPS, D1P, D1P)
     919    CHECKFLAGSNEW(GPS, S1P, S1P)
     920
     921    hdata.data.named.typesofobsS = buffer;
     922    i = 1+snprintf(buffer, buffersize,
     923    "S  %3d%-52.52s  SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
     924    buffer += i; buffersize -= i;
     925
     926    CHECKFLAGSNEW(GPS, P2,  C2P)
     927    CHECKFLAGSNEW(GPS, L2P, L2P)
     928    CHECKFLAGSNEW(GPS, D2P, D2P)
     929    CHECKFLAGSNEW(GPS, S2P, S2P)
     930    CHECKFLAGSNEW(GPS, C2,  C2X)
     931    CHECKFLAGSNEW(GPS, L2C, L2X)
     932    CHECKFLAGSNEW(GPS, D2C, D2X)
     933    CHECKFLAGSNEW(GPS, S2C, S2X)
     934
     935    hdata.data.named.typesofobsG = buffer;
     936    i = 1+snprintf(buffer, buffersize,
     937    "G  %3d%-52.52s  SYS / # / OBS TYPES", Parser->numdatatypesGPS, tbuffer);
     938    if(Parser->numdatatypesGPS>13)
     939    {
     940      i += snprintf(buffer+i-1, buffersize,
     941      "\n      %-52.52s  SYS / # / OBS TYPES", tbuffer+13*4);
     942    }
     943    buffer += i; buffersize -= i;
     944
     945    tbufferpos = 0;
     946
     947    CHECKFLAGSNEW(GLO, C1,  C1C)
     948    CHECKFLAGSNEW(GLO, L1C, L1C)
     949    CHECKFLAGSNEW(GLO, D1C, D1C)
     950    CHECKFLAGSNEW(GLO, S1C, S1C)
     951    CHECKFLAGSNEW(GLO, P1,  C1P)
     952    CHECKFLAGSNEW(GLO, L1P, L1P)
     953    CHECKFLAGSNEW(GLO, D1P, D1P)
     954    CHECKFLAGSNEW(GLO, S1P, S1P)
     955    CHECKFLAGSNEW(GLO, P2,  C2P)
     956    CHECKFLAGSNEW(GLO, L2P, L2P)
     957    CHECKFLAGSNEW(GLO, D2P, D2P)
     958    CHECKFLAGSNEW(GLO, S2P, S2P)
     959    CHECKFLAGSNEW(GLO, C2,  C2C)
     960    CHECKFLAGSNEW(GLO, L2C, L2C)
     961    CHECKFLAGSNEW(GLO, D2C, D2C)
     962    CHECKFLAGSNEW(GLO, S2C, S2C)
     963
     964    hdata.data.named.typesofobsR = buffer;
     965    i = 1+snprintf(buffer, buffersize,
     966    "R  %3d%-52.52s  SYS / # / OBS TYPES", Parser->numdatatypesGLO, tbuffer);
     967    if(Parser->numdatatypesGLO>13)
     968    {
     969      i += snprintf(buffer+i-1, buffersize,
     970      "\n      %-52.52s  SYS / # / OBS TYPES", tbuffer+13*4);
     971    }
     972    buffer += i; buffersize -= i;
     973  }
     974  else
    733975  {
    734976#define CHECKFLAGS(a, b) \
     
    737979      if(data[RINEXENTRY_##b##DATA]) \
    738980      { \
    739         Parser->dataflag2[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
    740         Parser->datapos2[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
     981        Parser->dataflagGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSDF_##a##DATA; \
     982        Parser->dataposGPS[data[RINEXENTRY_##b##DATA]-1] = GNSSENTRY_##a##DATA; \
    741983      } \
    742984      else \
    743985      { \
    744         Parser->dataflag[Parser->numdatatypes] = GNSSDF_##a##DATA; \
    745         Parser->datapos[Parser->numdatatypes] = GNSSENTRY_##a##DATA; \
    746         data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypes; \
     986        Parser->dataflag[Parser->numdatatypesGPS] = GNSSDF_##a##DATA; \
     987        Parser->datapos[Parser->numdatatypesGPS] = GNSSENTRY_##a##DATA; \
     988        data[RINEXENTRY_##b##DATA] = ++Parser->numdatatypesGPS; \
    747989        snprintf(tbuffer+tbufferpos, sizeof(tbuffer)-tbufferpos, "    "#b); \
    748990        tbufferpos += 6; \
     
    7781020    hdata.data.named.typesofobs = buffer;
    7791021    i = 1+snprintf(buffer, buffersize,
    780     "%6i%-54.54s# / TYPES OF OBSERV", Parser->numdatatypes, tbuffer);
    781     if(Parser->numdatatypes>9)
     1022    "%6d%-54.54s# / TYPES OF OBSERV", Parser->numdatatypesGPS, tbuffer);
     1023    if(Parser->numdatatypesGPS>9)
    7821024    {
    7831025      i += snprintf(buffer+i-1, buffersize,
     
    7921034    (int)floor(Parser->Data.timeofweek/1000.0));
    7931035    hdata.data.named.timeoffirstobs = buffer;
    794       i = 1+snprintf(buffer, buffersize,
     1036    i = 1+snprintf(buffer, buffersize,
    7951037    "  %4d    %2d    %2d    %2d    %2d   %10.7f     GPS         "
    7961038    "TIME OF FIRST OBS", cti.year, cti.month, cti.day, cti.hour,
     
    8001042  }
    8011043
    802   hdata.numheaders = 11;
     1044  hdata.numheaders = 14;
    8031045
    8041046  if(Parser->headerfile)
     
    8881130#ifndef NO_RTCM3_MAIN
    8891131  for(i = 0; i < hdata.numheaders; ++i)
    890     RTCM3Text("%s\n", hdata.data.unnamed[i]);
     1132  {
     1133    if(hdata.data.unnamed[i] && hdata.data.unnamed[i][0])
     1134      RTCM3Text("%s\n", hdata.data.unnamed[i]);
     1135  }
    8911136  RTCM3Text("                                                            "
    8921137  "END OF HEADER\n");
     
    8941139}
    8951140
     1141static void ConvLine(FILE *file, const char *fmt, ...)
     1142{
     1143  char buffer[100], *b;
     1144  va_list v;
     1145  va_start(v, fmt);
     1146  vsnprintf(buffer, sizeof(buffer), fmt, v);
     1147  for(b = buffer; *b; ++b)
     1148  {
     1149    if(*b == 'e') *b = 'D';
     1150  }
     1151  fprintf(file, "%s", buffer);
     1152  va_end(v);
     1153}
     1154
    8961155void HandleByte(struct RTCM3ParserData *Parser, unsigned int byte)
    8971156{
     
    9021161    while((r = RTCM3Parser(Parser)))
    9031162    {
    904       int i, j, o;
    905       struct converttimeinfo cti;
    906 
    907       if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
    908       {
    909         ++Parser->init;
    910 
    911         if(Parser->init == NUMSTARTSKIP)
    912           HandleHeader(Parser);
     1163      if(r == 1020 || r == 1019)
     1164      {
     1165        FILE *file = 0;
     1166
     1167        if(Parser->rinex3 && !(file = Parser->gpsfile))
     1168        {
     1169          const char *n = Parser->gpsephemeris ? Parser->gpsephemeris : Parser->glonassephemeris;
     1170          if(n)
     1171          {
     1172            if(!(Parser->gpsfile = fopen(n, "w")))
     1173            {
     1174              RTCM3Error("Could not open ephemeris output file.\n");
     1175            }
     1176            else
     1177            {
     1178              char buffer[100];
     1179              fprintf(Parser->gpsfile,
     1180              "%9.2f%11sN: GNSS NAV DATA    M: Mixed%12sRINEX VERSION / TYPE\n", 3.0, "", "");
     1181              HandleRunBy(buffer, sizeof(buffer), 0);
     1182              fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
     1183            }
     1184            Parser->gpsephemeris = 0;
     1185            Parser->glonassephemeris = 0;
     1186            file = Parser->gpsfile;
     1187          }
     1188        }
    9131189        else
    9141190        {
     1191          if(r == 1020)
     1192          {
     1193            if(Parser->glonassephemeris)
     1194            {
     1195              if(!(Parser->glonassfile = fopen(Parser->glonassephemeris, "w")))
     1196              {
     1197                RTCM3Error("Could not open GLONASS ephemeris output file.\n");
     1198              }
     1199              else
     1200              {
     1201                char buffer[100];
     1202                fprintf(Parser->glonassfile,
     1203                "%9.2f%11sG: GLONASS NAV DATA%21sRINEX VERSION / TYPE\n", 2.1, "", "");
     1204                HandleRunBy(buffer, sizeof(buffer), 0);
     1205                fprintf(Parser->glonassfile, "%s\n%60sEND OF HEADER\n", buffer, "");
     1206              }
     1207              Parser->glonassephemeris = 0;
     1208            }
     1209            file = Parser->glonassfile;
     1210          }
     1211          else if(r == 1019)
     1212          {
     1213            if(Parser->gpsephemeris)
     1214            {
     1215              if(!(Parser->gpsfile = fopen(Parser->gpsephemeris, "w")))
     1216              {
     1217                RTCM3Error("Could not open GPS ephemeris output file.\n");
     1218              }
     1219              else
     1220              {
     1221                char buffer[100];
     1222                fprintf(Parser->gpsfile,
     1223                "%9.2f%11sN: GPS NAV DATA%25sRINEX VERSION / TYPE\n", 2.1, "", "");
     1224                HandleRunBy(buffer, sizeof(buffer), 0);
     1225                fprintf(Parser->gpsfile, "%s\n%60sEND OF HEADER\n", buffer, "");
     1226              }
     1227              Parser->gpsephemeris = 0;
     1228            }
     1229            file = Parser->gpsfile;
     1230          }
     1231        }
     1232        if(file)
     1233        {
     1234          if(r == 1020)
     1235          {
     1236            struct glonassephemeris *e = &Parser->ephemerisGLONASS;
     1237            int w = e->GPSWeek, tow = e->GPSTOW, i;
     1238            struct converttimeinfo cti;
     1239
     1240            updatetime(&w, &tow, e->tb*1000, 1);
     1241            converttime(&cti, w, tow);
     1242
     1243            i = e->tk-3*60*60; if(i < 0) i += 86400;
     1244
     1245            if(Parser->rinex3)
     1246              ConvLine(file, "R%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
     1247              e->almanac_number, cti.year, cti.month, cti.day, cti.hour, cti.minute,
     1248              cti.second, -e->tau, e->gamma, (double) i);
     1249            else
     1250              ConvLine(file, "%02d %02d %02d %02d %02d %02d%5.1f%19.12e%19.12e%19.12e\n",
     1251              e->almanac_number, cti.year%100, cti.month, cti.day, cti.hour, cti.minute,
     1252              (double) cti.second, -e->tau, e->gamma, (double) i);
     1253            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->x_pos,
     1254            e->x_velocity, e->x_acceleration, (e->flags & GLOEPHF_UNHEALTHY) ? 1.0 : 0.0);
     1255            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->y_pos,
     1256            e->y_velocity, e->y_acceleration, (double) e->frequency_number);
     1257            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->z_pos,
     1258            e->z_velocity, e->z_acceleration, (double) e->E);
     1259          }
     1260          else /* if(r == 1019) */
     1261          {
     1262            struct gpsephemeris *e = &Parser->ephemerisGPS;
     1263            double d;                 /* temporary variable */
     1264            unsigned long int i;       /* temporary variable */
     1265            struct converttimeinfo cti;
     1266            converttime(&cti, e->GPSweek, e->TOC);
     1267
     1268            if(Parser->rinex3)
     1269              ConvLine(file, "G%02d %04d %02d %02d %02d %02d %02d%19.12e%19.12e%19.12e\n",
     1270              e->satellite, cti.year, cti.month, cti.day, cti.hour,
     1271              cti.minute, cti.second, e->clock_bias, e->clock_drift,
     1272              e->clock_driftrate);
     1273            else
     1274              ConvLine(file, "%02d %02d %02d %02d %02d %02d%05.1f%19.12e%19.12e%19.12e\n",
     1275              e->satellite, cti.year%100, cti.month, cti.day, cti.hour,
     1276              cti.minute, (double) cti.second, e->clock_bias, e->clock_drift,
     1277              e->clock_driftrate);
     1278            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", (double)e->IODE,
     1279            e->Crs, e->Delta_n, e->M0);
     1280            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->Cuc,
     1281            e->e, e->Cus, e->sqrt_A);
     1282            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n",
     1283            (double) e->TOE, e->Cic, e->OMEGA0, e->Cis);
     1284            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->i0,
     1285            e->Crc, e->omega, e->OMEGADOT);
     1286            d = 0;
     1287            i = e->flags;
     1288            if(i & GPSEPHF_L2CACODE)
     1289              d += 2.0;
     1290            if(i & GPSEPHF_L2PCODE)
     1291              d += 1.0;
     1292            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", e->IDOT, d,
     1293            (double) e->GPSweek, i & GPSEPHF_L2PCODEDATA ? 1.0 : 0.0);
     1294            if(e->URAindex <= 6) /* URA index */
     1295              d = ceil(10.0*pow(2.0, 1.0+((double)e->URAindex)/2.0))/10.0;
     1296            else
     1297              d = ceil(10.0*pow(2.0, ((double)e->URAindex)/2.0))/10.0;
     1298            /* 15 indicates not to use satellite. We can't handle this special
     1299               case, so we create a high "non"-accuracy value. */
     1300            ConvLine(file, "   %19.12e%19.12e%19.12e%19.12e\n", d,
     1301            ((double) e->SVhealth), e->TGD, ((double) e->IODC));
     1302
     1303            ConvLine(file, "   %19.12e%19.12e\n", ((double)e->TOW), 0.0);
     1304            /* TOW */
     1305          }
     1306        }
     1307      }
     1308      else
     1309      {
     1310        int i, j, o;
     1311        struct converttimeinfo cti;
     1312
     1313        if(Parser->init < NUMSTARTSKIP) /* skip first epochs to detect correct data types */
     1314        {
     1315          ++Parser->init;
     1316
     1317          if(Parser->init == NUMSTARTSKIP)
     1318            HandleHeader(Parser);
     1319          else
     1320          {
     1321            for(i = 0; i < Parser->Data.numsats; ++i)
     1322              Parser->startflags |= Parser->Data.dataflags[i];
     1323            continue;
     1324          }
     1325        }
     1326        if(r == 2 && !Parser->validwarning)
     1327        {
     1328          RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
     1329          "           COMMENT\n");
     1330          Parser->validwarning = 1;
     1331        }
     1332
     1333        converttime(&cti, Parser->Data.week,
     1334        (int)floor(Parser->Data.timeofweek/1000.0));
     1335        if(Parser->rinex3)
     1336        {
     1337          RTCM3Text("> %04d %02d %02d %02d %02d%11.7f  0%3d\n",
     1338          cti.year, cti.month, cti.day, cti.hour, cti.minute, cti.second
     1339          + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
    9151340          for(i = 0; i < Parser->Data.numsats; ++i)
    916             Parser->startflags |= Parser->Data.dataflags[i];
    917           continue;
    918         }
    919       }
    920       if(r == 2 && !Parser->validwarning)
    921       {
    922         RTCM3Text("No valid RINEX! All values are modulo 299792.458!"
    923         "           COMMENT\n");
    924         Parser->validwarning = 1;
    925       }
    926 
    927       converttime(&cti, Parser->Data.week,
    928       (int)floor(Parser->Data.timeofweek/1000.0));
    929       RTCM3Text(" %02d %2d %2d %2d %2d %10.7f  0%3d",
    930       cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
    931       + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
    932       for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
    933       {
    934         if(Parser->Data.satellites[i] <= PRN_GPS_END)
    935           RTCM3Text("G%02d", Parser->Data.satellites[i]);
    936         else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
    937         && Parser->Data.satellites[i] <= PRN_GLONASS_END)
    938           RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
    939         else if(Parser->Data.satellites[i] >= PRN_WAAS_START
    940         && Parser->Data.satellites[i] <= PRN_WAAS_END)
    941           RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
     1341          {
     1342            int glo = 0;
     1343            if(Parser->Data.satellites[i] <= PRN_GPS_END)
     1344              RTCM3Text("G%02d", Parser->Data.satellites[i]);
     1345            else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
     1346            && Parser->Data.satellites[i] <= PRN_GLONASS_END)
     1347            {
     1348              RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
     1349              glo = 1;
     1350            }
     1351            else if(Parser->Data.satellites[i] >= PRN_WAAS_START
     1352            && Parser->Data.satellites[i] <= PRN_WAAS_END)
     1353              RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
     1354            else
     1355              RTCM3Text("%3d", Parser->Data.satellites[i]);
     1356
     1357            if(glo)
     1358            {
     1359              for(j = 0; j < Parser->numdatatypesGLO; ++j)
     1360              {
     1361                int df = Parser->dataflagGLO[j];
     1362                int pos = Parser->dataposGLO[j];
     1363                if((Parser->Data.dataflags[i] & df)
     1364                && !isnan(Parser->Data.measdata[i][pos])
     1365                && !isinf(Parser->Data.measdata[i][pos]))
     1366                {
     1367                  char lli = ' ';
     1368                  char snr = ' ';
     1369                  if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
     1370                  {
     1371                    if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
     1372                      lli = '1';
     1373                    snr = '0'+Parser->Data.snrL1[i];
     1374                  }
     1375                  if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
     1376                  {
     1377                    if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
     1378                      lli = '1';
     1379                    snr = '0'+Parser->Data.snrL2[i];
     1380                  }
     1381                  RTCM3Text("%14.3f%c%c",
     1382                  Parser->Data.measdata[i][pos],lli,snr);
     1383                }
     1384                else
     1385                { /* no or illegal data */
     1386                  RTCM3Text("                ");
     1387                }
     1388              }
     1389            }
     1390            else
     1391            {
     1392              for(j = 0; j < Parser->numdatatypesGPS; ++j)
     1393              {
     1394                int df = Parser->dataflagGPS[j];
     1395                int pos = Parser->dataposGPS[j];
     1396                if((Parser->Data.dataflags[i] & df)
     1397                && !isnan(Parser->Data.measdata[i][pos])
     1398                && !isinf(Parser->Data.measdata[i][pos]))
     1399                {
     1400                  char lli = ' ';
     1401                  char snr = ' ';
     1402                  if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
     1403                  {
     1404                    if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
     1405                      lli = '1';
     1406                    snr = '0'+Parser->Data.snrL1[i];
     1407                  }
     1408                  if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
     1409                  {
     1410                    if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
     1411                      lli = '1';
     1412                    snr = '0'+Parser->Data.snrL2[i];
     1413                  }
     1414                  RTCM3Text("%14.3f%c%c",
     1415                  Parser->Data.measdata[i][pos],lli,snr);
     1416                }
     1417                else
     1418                { /* no or illegal data */
     1419                  RTCM3Text("                ");
     1420                }
     1421              }
     1422            }
     1423            RTCM3Text("\n");
     1424          }
     1425        }
    9421426        else
    943           RTCM3Text("%3d", Parser->Data.satellites[i]);
    944       }
    945       RTCM3Text("\n");
    946       o = 12;
    947       j = Parser->Data.numsats - 12;
    948       while(j > 0)
    949       {
    950         RTCM3Text("                                ");
    951         for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
    952         {
    953           if(Parser->Data.satellites[i] <= PRN_GPS_END)
    954             RTCM3Text("G%02d", Parser->Data.satellites[i]);
    955           else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
    956           && Parser->Data.satellites[i] <= PRN_GLONASS_END)
    957             RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
    958           else if(Parser->Data.satellites[i] >= PRN_WAAS_START
    959           && Parser->Data.satellites[i] <= PRN_WAAS_END)
    960             RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
    961           else
    962             RTCM3Text("%3d", Parser->Data.satellites[i]);
    963         }
    964         RTCM3Text("\n");
    965         j -= 12;
    966         o += 12;
    967       }
    968       for(i = 0; i < Parser->Data.numsats; ++i)
    969       {
    970         for(j = 0; j < Parser->numdatatypes; ++j)
    971         {
    972           int v = 0;
    973           int df = Parser->dataflag[j];
    974           int pos = Parser->datapos[j];
    975           if((Parser->Data.dataflags[i] & df)
    976           && !isnan(Parser->Data.measdata[i][pos])
    977           && !isinf(Parser->Data.measdata[i][pos]))
    978           {
    979             v = 1;
    980           }
    981           else
    982           {
    983             df = Parser->dataflag2[j];
    984             pos = Parser->datapos2[j];
    985 
    986             if((Parser->Data.dataflags[i] & df)
    987             && !isnan(Parser->Data.measdata[i][pos])
    988             && !isinf(Parser->Data.measdata[i][pos]))
    989             {
    990               v = 1;
    991             }
    992           }
    993 
    994           if(!v)
    995           { /* no or illegal data */
    996             RTCM3Text("                ");
    997           }
    998           else
    999           {
    1000             char lli = ' ';
    1001             char snr = ' ';
    1002             if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
    1003             {
    1004               if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
    1005                 lli = '1';
    1006               snr = '0'+Parser->Data.snrL1[i];
    1007             }
    1008             if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
    1009             {
    1010               if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
    1011                 lli = '1';
    1012               snr = '0'+Parser->Data.snrL2[i];
    1013             }
    1014             RTCM3Text("%14.3f%c%c",
    1015             Parser->Data.measdata[i][pos],lli,snr);
    1016           }
    1017           if(j%5 == 4 || j == Parser->numdatatypes-1)
     1427        {
     1428          RTCM3Text(" %02d %2d %2d %2d %2d %10.7f  0%3d",
     1429          cti.year%100, cti.month, cti.day, cti.hour, cti.minute, cti.second
     1430          + fmod(Parser->Data.timeofweek/1000.0,1.0), Parser->Data.numsats);
     1431          for(i = 0; i < 12 && i < Parser->Data.numsats; ++i)
     1432          {
     1433            if(Parser->Data.satellites[i] <= PRN_GPS_END)
     1434              RTCM3Text("G%02d", Parser->Data.satellites[i]);
     1435            else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
     1436            && Parser->Data.satellites[i] <= PRN_GLONASS_END)
     1437              RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
     1438            else if(Parser->Data.satellites[i] >= PRN_WAAS_START
     1439            && Parser->Data.satellites[i] <= PRN_WAAS_END)
     1440              RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
     1441            else
     1442              RTCM3Text("%3d", Parser->Data.satellites[i]);
     1443          }
     1444          RTCM3Text("\n");
     1445          o = 12;
     1446          j = Parser->Data.numsats - 12;
     1447          while(j > 0)
     1448          {
     1449            RTCM3Text("                                ");
     1450            for(i = o; i < o+12 && i < Parser->Data.numsats; ++i)
     1451            {
     1452              if(Parser->Data.satellites[i] <= PRN_GPS_END)
     1453                RTCM3Text("G%02d", Parser->Data.satellites[i]);
     1454              else if(Parser->Data.satellites[i] >= PRN_GLONASS_START
     1455              && Parser->Data.satellites[i] <= PRN_GLONASS_END)
     1456                RTCM3Text("R%02d", Parser->Data.satellites[i] - (PRN_GLONASS_START-1));
     1457              else if(Parser->Data.satellites[i] >= PRN_WAAS_START
     1458              && Parser->Data.satellites[i] <= PRN_WAAS_END)
     1459                RTCM3Text("S%02d", Parser->Data.satellites[i] - PRN_WAAS_START+20);
     1460              else
     1461                RTCM3Text("%3d", Parser->Data.satellites[i]);
     1462            }
    10181463            RTCM3Text("\n");
     1464            j -= 12;
     1465            o += 12;
     1466          }
     1467          for(i = 0; i < Parser->Data.numsats; ++i)
     1468          {
     1469            for(j = 0; j < Parser->numdatatypesGPS; ++j)
     1470            {
     1471              int v = 0;
     1472              int df = Parser->dataflag[j];
     1473              int pos = Parser->datapos[j];
     1474              if((Parser->Data.dataflags[i] & df)
     1475              && !isnan(Parser->Data.measdata[i][pos])
     1476              && !isinf(Parser->Data.measdata[i][pos]))
     1477              {
     1478                v = 1;
     1479              }
     1480              else
     1481              {
     1482                df = Parser->dataflagGPS[j];
     1483                pos = Parser->dataposGPS[j];
     1484
     1485                if((Parser->Data.dataflags[i] & df)
     1486                && !isnan(Parser->Data.measdata[i][pos])
     1487                && !isinf(Parser->Data.measdata[i][pos]))
     1488                {
     1489                  v = 1;
     1490                }
     1491              }
     1492
     1493              if(!v)
     1494              { /* no or illegal data */
     1495                RTCM3Text("                ");
     1496              }
     1497              else
     1498              {
     1499                char lli = ' ';
     1500                char snr = ' ';
     1501                if(df & (GNSSDF_L1CDATA|GNSSDF_L1PDATA))
     1502                {
     1503                  if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL1)
     1504                    lli = '1';
     1505                  snr = '0'+Parser->Data.snrL1[i];
     1506                }
     1507                if(df & (GNSSDF_L2CDATA|GNSSDF_L2PDATA))
     1508                {
     1509                  if(Parser->Data.dataflags[i] & GNSSDF_LOCKLOSSL2)
     1510                    lli = '1';
     1511                  snr = '0'+Parser->Data.snrL2[i];
     1512                }
     1513                RTCM3Text("%14.3f%c%c",
     1514                Parser->Data.measdata[i][pos],lli,snr);
     1515              }
     1516              if(j%5 == 4 || j == Parser->numdatatypesGPS-1)
     1517                RTCM3Text("\n");
     1518            }
     1519          }
    10191520        }
    10201521      }
     
    10241525
    10251526#ifndef NO_RTCM3_MAIN
    1026 static char datestr[]     = "$Date: 2007/08/14 10:14:37 $";
     1527static char datestr[]     = "$Date: 2007/10/01 11:07:08 $";
    10271528
    10281529/* The string, which is send as agent in HTTP request */
     
    10851586{
    10861587  const char *server;
    1087   int         port;
     1588  const char *port;
     1589  int         mode;
    10881590  int         timeout;
     1591  int         rinex3;
    10891592  const char *user;
    10901593  const char *password;
     1594  const char *proxyhost;
     1595  const char *proxyport;
     1596  const char *nmea;
    10911597  const char *data;
    10921598  const char *headerfile;
     1599  const char *gpsephemeris;
     1600  const char *glonassephemeris;
    10931601};
    10941602
     
    10991607#define LONG_OPT(a) a
    11001608static struct option opts[] = {
    1101 { "data",       required_argument, 0, 'd'},
    1102 { "server",     required_argument, 0, 's'},
    1103 { "password",   required_argument, 0, 'p'},
    1104 { "port",       required_argument, 0, 'r'},
    1105 { "timeout",    required_argument, 0, 't'},
    1106 { "header",     required_argument, 0, 'f'},
    1107 { "user",       required_argument, 0, 'u'},
    1108 { "help",       no_argument,       0, 'h'},
     1609{ "data",             required_argument, 0, 'd'},
     1610{ "server",           required_argument, 0, 's'},
     1611{ "password",         required_argument, 0, 'p'},
     1612{ "port",             required_argument, 0, 'r'},
     1613{ "timeout",          required_argument, 0, 't'},
     1614{ "header",           required_argument, 0, 'f'},
     1615{ "user",             required_argument, 0, 'u'},
     1616{ "gpsephemeris",     required_argument, 0, 'E'},
     1617{ "glonassephemeris", required_argument, 0, 'G'},
     1618{ "rinex3",           no_argument,       0, '3'},
     1619{ "proxyport",        required_argument, 0, 'R'},
     1620{ "proxyhost",        required_argument, 0, 'S'},
     1621{ "nmea",             required_argument, 0, 'n'},
     1622{ "mode",             required_argument, 0, 'M'},
     1623{ "help",             no_argument,       0, 'h'},
    11091624{0,0,0,0}};
    11101625#endif
    1111 #define ARGOPT "-d:s:p:r:t:f:u:h"
     1626#define ARGOPT "-d:s:p:r:t:f:u:E:G:M:S:R:n:h3"
     1627
     1628enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };
    11121629
    11131630static const char *geturl(const char *url, struct Args *args)
     
    11251642    /* scan for mountpoint */
    11261643    args->data = Buffer;
    1127     while(*url && *url != '@' && *url != '/' && Buffer != Bufend)
     1644    while(*url && *url != '@' &&  *url != ';' &&*url != '/' && Buffer != Bufend)
    11281645      *(Buffer++) = *(url++);
    11291646    if(Buffer == args->data)
     
    11381655    ++url;
    11391656    args->user = Buffer;
    1140     while(*url && *url != '@' && *url != ':' && Buffer != Bufend)
     1657    while(*url && *url != '@' && *url != ';' && *url != ':' && Buffer != Bufend)
    11411658      *(Buffer++) = *(url++);
    11421659    if(Buffer == args->user)
     
    11491666
    11501667    args->password = Buffer;
    1151     while(*url && *url != '@' && Buffer != Bufend)
     1668    while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
    11521669      *(Buffer++) = *(url++);
    11531670    if(Buffer == args->password)
     
    11611678  {
    11621679    ++url;
    1163     args->server = Buffer;
    1164     while(*url && *url != ':' && Buffer != Bufend)
    1165       *(Buffer++) = *(url++);
    1166     if(Buffer == args->server)
    1167       return "Servername cannot be empty.";
    1168     else if(Buffer >= Bufend-1)
    1169       return "Parsing buffer too short.";
    1170     *(Buffer++) = 0;
     1680    if(*url != '@' && *url != ':')
     1681    {
     1682      args->server = Buffer;
     1683      while(*url && *url != '@' && *url != ':' && *url != ';' && Buffer != Bufend)
     1684        *(Buffer++) = *(url++);
     1685      if(Buffer == args->server)
     1686        return "Servername cannot be empty.";
     1687      else if(Buffer >= Bufend-1)
     1688        return "Parsing buffer too short.";
     1689      *(Buffer++) = 0;
     1690    }
    11711691
    11721692    if(*url == ':')
    11731693    {
    1174       char *s2 = 0;
    1175       args->port = strtol(++url, &s2, 10);
    1176       if(*s2 || args->port <= 0 || args->port > 0xFFFF)
    1177         return "Illegal port number.";
    1178       url = s2;
    1179     }
     1694      ++url;
     1695      args->port = Buffer;
     1696      while(*url && *url != '@' && *url != ';' && Buffer != Bufend)
     1697        *(Buffer++) = *(url++);
     1698      if(Buffer == args->port)
     1699        return "Port cannot be empty.";
     1700      else if(Buffer >= Bufend-1)
     1701        return "Parsing buffer too short.";
     1702      *(Buffer++) = 0;
     1703    }
     1704
     1705    if(*url == '@') /* proxy */
     1706    {
     1707      ++url;
     1708      args->proxyhost = Buffer;
     1709      while(*url && *url != ':' && *url != ';' && Buffer != Bufend)
     1710        *(Buffer++) = *(url++);
     1711      if(Buffer == args->proxyhost)
     1712        return "Proxy servername cannot be empty.";
     1713      else if(Buffer >= Bufend-1)
     1714        return "Parsing buffer too short.";
     1715      *(Buffer++) = 0;
     1716
     1717      if(*url == ':')
     1718      {
     1719        ++url;
     1720        args->proxyport = Buffer;
     1721        while(*url && *url != ';' && Buffer != Bufend)
     1722          *(Buffer++) = *(url++);
     1723        if(Buffer == args->proxyport)
     1724          return "Proxy port cannot be empty.";
     1725        else if(Buffer >= Bufend-1)
     1726          return "Parsing buffer too short.";
     1727        *(Buffer++) = 0;
     1728      }
     1729    }
     1730  }
     1731  if(*url == ';') /* NMEA */
     1732  {
     1733    args->nmea = ++url;
     1734    while(*url)
     1735      ++url;
    11801736  }
    11811737
     
    11911747
    11921748  args->server = "www.euref-ip.net";
    1193   args->port = 2101;
     1749  args->port = "2101";
    11941750  args->timeout = 60;
    11951751  args->user = "";
     
    11971753  args->data = 0;
    11981754  args->headerfile = 0;
     1755  args->gpsephemeris = 0;
     1756  args->glonassephemeris = 0;
     1757  args->rinex3 = 0;
     1758  args->nmea = 0;
     1759  args->proxyhost = 0;
     1760  args->proxyport = "2101";
     1761  args->mode = AUTO;
    11991762  help = 0;
    12001763
     
    12131776    case 'd': args->data = optarg; break;
    12141777    case 'f': args->headerfile = optarg; break;
     1778    case 'E': args->gpsephemeris = optarg; break;
     1779    case 'G': args->glonassephemeris = optarg; break;
     1780    case 'r': args->port = optarg; break;
     1781    case '3': args->rinex3 = 1; break;
     1782    case 'S': args->proxyhost = optarg; break;
     1783    case 'n': args->nmea = optarg; break;
     1784    case 'R': args->proxyport = optarg; break;
    12151785    case 'h': help=1; break;
    1216     case 'r':
    1217       args->port = strtoul(optarg, &t, 10);
    1218       if((t && *t) || args->port < 1 || args->port > 65535)
     1786    case 'M':
     1787      args->mode = 0;
     1788      if (!strcmp(optarg,"n") || !strcmp(optarg,"ntrip1"))
     1789        args->mode = NTRIP1;
     1790      else if(!strcmp(optarg,"h") || !strcmp(optarg,"http"))
     1791        args->mode = HTTP;
     1792      else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp"))
     1793        args->mode = RTSP;
     1794      else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto"))
     1795        args->mode = AUTO;
     1796      else args->mode = atoi(optarg);
     1797      if((args->mode == 0) || (args->mode >= END))
     1798      {
     1799        fprintf(stderr, "Mode %s unknown\n", optarg);
    12191800        res = 0;
     1801      }
    12201802      break;
    1221     case 't': 
     1803    case 't':
    12221804      args->timeout = strtoul(optarg, &t, 10);
    12231805      if((t && *t) || args->timeout < 0)
     
    12501832  datestr[10] = 0;
    12511833
    1252   if(!res || help)
     1834  if(args->gpsephemeris && args->glonassephemeris && args->rinex3)
     1835  {
     1836    RTCM3Error("RINEX3 produces a combined ephemeris file, but 2 files were specified.\n");
     1837    res = 0;
     1838  }
     1839  else if(!res || help)
    12531840  {
    12541841    RTCM3Error("Version %s (%s) GPL" COMPILEDATE
    12551842    "\nUsage: %s -s server -u user ...\n"
    1256     " -d " LONG_OPT("--data       ") "the requested data set\n"
    1257     " -f " LONG_OPT("--headerfile ") "file for RINEX header information\n"
    1258     " -s " LONG_OPT("--server     ") "the server name or address\n"
    1259     " -p " LONG_OPT("--password   ") "the login password\n"
    1260     " -r " LONG_OPT("--port       ") "the server port number (default 2101)\n"
    1261     " -t " LONG_OPT("--timeout    ") "timeout in seconds (default 60)\n"
    1262     " -u " LONG_OPT("--user       ") "the user name\n"
    1263     "or using an URL:\n%s ntrip:mountpoint[/username[:password]][@server[:port]]\n"
     1843    " -d " LONG_OPT("--data             ") "the requested data set\n"
     1844    " -f " LONG_OPT("--headerfile       ") "file for RINEX header information\n"
     1845    " -s " LONG_OPT("--server           ") "the server name or address\n"
     1846    " -p " LONG_OPT("--password         ") "the login password\n"
     1847    " -r " LONG_OPT("--port             ") "the server port number (default 2101)\n"
     1848    " -t " LONG_OPT("--timeout          ") "timeout in seconds (default 60)\n"
     1849    " -u " LONG_OPT("--user             ") "the user name\n"
     1850    " -E " LONG_OPT("--gpsephemeris     ") "output file for GPS ephemeris data\n"
     1851    " -G " LONG_OPT("--glonassephemeris ") "output file for GLONASS ephemeris data\n"
     1852    " -3 " LONG_OPT("--rinex3           ") "output RINEX type 3 data\n"
     1853    " -S " LONG_OPT("--proxyhost        ") "proxy name or address\n"
     1854    " -R " LONG_OPT("--proxyport        ") "proxy port, optional (default 2101)\n"
     1855    " -n " LONG_OPT("--nmea             ") "NMEA string for sending to server\n"
     1856    " -M " LONG_OPT("--mode             ") "mode for data request\n"
     1857    "     Valid modes are:\n"
     1858    "     1, h, http     NTRIP Version 2.0 Caster in TCP/IP mode\n"
     1859    "     2, r, rtsp     NTRIP Version 2.0 Caster in RTSP/RTP mode\n"
     1860    "     3, n, ntrip1   NTRIP Version 1.0 Caster\n"
     1861    "     4, a, auto     automatic detection (default)\n"
     1862    "or using an URL:\n%s ntrip:data[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n"
    12641863    , revisionstr, datestr, argv[0], argv[0]);
    12651864    exit(1);
     
    12791878  }
    12801879}
     1880
     1881#define ALARMTIME   (2*60)
    12811882
    12821883/* for some reason we had to abort hard (maybe waiting for data */
     
    12971898  struct RTCM3ParserData Parser;
    12981899
    1299   struct timeval tv;
    1300 
    13011900  setbuf(stdout, 0);
    13021901  setbuf(stdin, 0);
     
    13261925  if(getargs(argc, argv, &args))
    13271926  {
    1328     int i, sockfd, numbytes; 
     1927    int sockfd, numbytes; 
    13291928    char buf[MAXDATASIZE];
     1929    struct sockaddr_in their_addr; /* connector's address information */
    13301930    struct hostent *he;
    1331     struct sockaddr_in their_addr; /* connector's address information */
     1931    struct servent *se;
     1932    const char *server, *port, *proxyserver = 0;
     1933    char proxyport[6];
     1934    char *b;
     1935    long i;
     1936    struct timeval tv;
     1937
     1938    alarm(ALARMTIME);
    13321939
    13331940    Parser.headerfile = args.headerfile;
    1334 
    1335     if(!(he=gethostbyname(args.server)))
     1941    Parser.glonassephemeris = args.glonassephemeris;
     1942    Parser.gpsephemeris = args.gpsephemeris;
     1943    Parser.rinex3 = args.rinex3;
     1944
     1945    if(args.proxyhost)
    13361946    {
    1337       RTCM3Error("Function gethostbyname: %s\n", strerror(errno));
     1947      int p;
     1948      if((i = strtol(args.port, &b, 10)) && (!b || !*b))
     1949        p = i;
     1950      else if(!(se = getservbyname(args.port, 0)))
     1951      {
     1952        RTCM3Error("Can't resolve port %s.", args.port);
     1953        exit(1);
     1954      }
     1955      else
     1956      {
     1957        p = ntohs(se->s_port);
     1958      }
     1959      snprintf(proxyport, sizeof(proxyport), "%d", p);
     1960      port = args.proxyport;
     1961      proxyserver = args.server;
     1962      server = args.proxyhost;
     1963    }
     1964    else
     1965    {
     1966      server = args.server;
     1967      port = args.port;
     1968    }
     1969
     1970    memset(&their_addr, 0, sizeof(struct sockaddr_in));
     1971    if((i = strtol(port, &b, 10)) && (!b || !*b))
     1972      their_addr.sin_port = htons(i);
     1973    else if(!(se = getservbyname(port, 0)))
     1974    {
     1975      RTCM3Error("Can't resolve port %s.", port);
     1976      exit(1);
     1977    }
     1978    else
     1979    {
     1980      their_addr.sin_port = se->s_port;
     1981    }
     1982    if(!(he=gethostbyname(server)))
     1983    {
     1984      RTCM3Error("Server name lookup failed for '%s'.\n", server);
    13381985      exit(1);
    13391986    }
    13401987    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    13411988    {
    1342       RTCM3Error("Function socket: %s\n", strerror(errno));
     1989      perror("socket");
    13431990      exit(1);
    13441991    }
     
    13521999    }
    13532000
    1354     their_addr.sin_family = AF_INET;    /* host byte order */
    1355     their_addr.sin_port = htons(args.port);  /* short, network byte order */
     2001    their_addr.sin_family = AF_INET;
    13562002    their_addr.sin_addr = *((struct in_addr *)he->h_addr);
    1357     memset(&(their_addr.sin_zero), '\0', 8);
    1358     if(connect(sockfd, (struct sockaddr *)&their_addr,
    1359     sizeof(struct sockaddr)) == -1)
     2003
     2004    if(args.data && args.mode == RTSP)
    13602005    {
    1361       RTCM3Error("Function connect: %s\n", strerror(errno));
    1362       exit(1);
    1363     }
    1364 
    1365     if(!args.data)
    1366     {
    1367       i = snprintf(buf, MAXDATASIZE,
    1368       "GET / HTTP/1.0\r\n"
     2006      struct sockaddr_in local;
     2007      int sockudp, localport;
     2008      int cseq = 1;
     2009      socklen_t len;
     2010
     2011      if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
     2012      {
     2013        perror("socket");
     2014        exit(1);
     2015      }
     2016      /* fill structure with local address information for UDP */
     2017      memset(&local, 0, sizeof(local));
     2018      local.sin_family = AF_INET;       
     2019      local.sin_port = htons(0);
     2020      local.sin_addr.s_addr = htonl(INADDR_ANY);
     2021      len = sizeof(local);
     2022      /* bind() in order to get a random RTP client_port */
     2023      if((bind(sockudp, (struct sockaddr *)&local, len)) < 0)
     2024      {
     2025        perror("bind");
     2026        exit(1);
     2027      }
     2028      if((getsockname(sockudp, (struct sockaddr*)&local, &len)) != -1)
     2029      {
     2030        localport = ntohs(local.sin_port);
     2031      }
     2032      else
     2033      {
     2034        perror("local access failed");
     2035        exit(1);
     2036      }
     2037      if(connect(sockfd, (struct sockaddr *)&their_addr,
     2038      sizeof(struct sockaddr)) == -1)
     2039      {
     2040        perror("connect");
     2041        exit(1);
     2042      }
     2043      i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
     2044      "SETUP rtsp://%s%s%s/%s RTSP/1.0\r\n"             
     2045      "CSeq: %d\r\n"           
     2046      "Ntrip-Version: Ntrip/2.0\r\n"
     2047      "Ntrip-Component: Ntripclient\r\n"
    13692048      "User-Agent: %s/%s\r\n"
    1370 #ifdef UNUSED
    1371       "Accept: */*\r\n"
    1372       "Connection: close\r\n"
    1373 #endif
    1374       "\r\n"
    1375       , AGENTSTRING, revisionstr);
    1376     }
    1377     else
    1378     {
    1379       i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
    1380       "GET /%s HTTP/1.0\r\n"
    1381       "User-Agent: %s/%s\r\n"
    1382 #ifdef UNUSED
    1383       "Accept: */*\r\n"
    1384       "Connection: close\r\n"
    1385 #endif
    1386       "Authorization: Basic "
    1387       , args.data, AGENTSTRING, revisionstr);
     2049      "Transport: RTP/GNSS;unicast;client_port=%u\r\n"
     2050      "Authorization: Basic ",
     2051      args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
     2052      args.data, cseq++, AGENTSTRING, revisionstr, localport);
    13882053      if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
    13892054      {
     
    14012066      buf[i++] = '\r';
    14022067      buf[i++] = '\n';
    1403     }
    1404     if(send(sockfd, buf, (size_t)i, 0) != i)
    1405     {
    1406       RTCM3Error("Function send: %s\n", strerror(errno));
    1407       exit(1);
    1408     }
    1409     if(args.data)
    1410     {
    1411       int k = 0;
    1412       while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
    1413       {
    1414         if(!k)
    1415         {
    1416           if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
    1417           {
    1418             RTCM3Error("Could not get the requested data: ");
    1419             for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
    1420             {
    1421               RTCM3Error("%c", isprint(buf[k]) ? buf[k] : '.');
    1422             }
    1423             RTCM3Error("\n");
     2068      if(args.nmea)
     2069      {
     2070        int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
     2071        if(j >= 0 && j < MAXDATASIZE-i)
     2072          i += j;
     2073        else
     2074        {
     2075          RTCM3Error("NMEA string too long\n");
     2076          exit(1);
     2077        }
     2078      }
     2079      if(send(sockfd, buf, (size_t)i, 0) != i)
     2080      {
     2081        perror("send");
     2082        exit(1);
     2083      }
     2084      if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
     2085      {
     2086        if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
     2087        {
     2088          int serverport = 0, session = 0;
     2089          const char *portcheck = "server_port=";
     2090          const char *sessioncheck = "session: ";
     2091          int l = strlen(portcheck)-1;
     2092          int j=0;
     2093          for(i = 0; j != l && i < numbytes-l; ++i)
     2094          {
     2095            for(j = 0; j < l && tolower(buf[i+j]) == portcheck[j]; ++j)
     2096              ;
     2097          }
     2098          if(i == numbytes-l)
     2099          {
     2100            RTCM3Error("No server port number found\n");
    14242101            exit(1);
    14252102          }
    1426           ++k;
     2103          else
     2104          {
     2105            i+=l;
     2106            while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
     2107              serverport = serverport * 10 + buf[i++]-'0';
     2108            if(buf[i] != '\r' && buf[i] != ';')
     2109            {
     2110              RTCM3Error("Could not extract server port\n");
     2111              exit(1);
     2112            }
     2113          }
     2114          l = strlen(sessioncheck)-1;
     2115          j=0;
     2116          for(i = 0; j != l && i < numbytes-l; ++i)
     2117          {
     2118            for(j = 0; j < l && tolower(buf[i+j]) == sessioncheck[j]; ++j)
     2119              ;
     2120          }
     2121          if(i == numbytes-l)
     2122          {
     2123            RTCM3Error("No session number found\n");
     2124            exit(1);
     2125          }
     2126          else
     2127          {
     2128            i+=l;
     2129            while(i < numbytes && buf[i] >= '0' && buf[i] <= '9')
     2130              session = session * 10 + buf[i++]-'0';
     2131            if(buf[i] != '\r')
     2132            {
     2133              RTCM3Error("Could not extract session number\n");
     2134              exit(1);
     2135            }
     2136          }
     2137
     2138          i = snprintf(buf, MAXDATASIZE,
     2139          "PLAY rtsp://%s%s%s/%s RTSP/1.0\r\n"         
     2140          "CSeq: %d\r\n"
     2141          "Session: %d\r\n"
     2142          "\r\n",
     2143          args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
     2144          args.data, cseq++, session);
     2145
     2146          if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
     2147          {
     2148            RTCM3Error("Requested data too long\n");
     2149            exit(1);
     2150          }
     2151          if(send(sockfd, buf, (size_t)i, 0) != i)
     2152          {
     2153            perror("send");
     2154            exit(1);
     2155          }
     2156          if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
     2157          {
     2158            if(numbytes >= 17 && !strncmp(buf, "RTSP/1.0 200 OK\r\n", 17))
     2159            {
     2160              struct sockaddr_in addrRTP;
     2161              /* fill structure with caster address information for UDP */
     2162              memset(&addrRTP, 0, sizeof(addrRTP));
     2163              addrRTP.sin_family = AF_INET; 
     2164              addrRTP.sin_port   = htons(serverport);
     2165              their_addr.sin_addr = *((struct in_addr *)he->h_addr);
     2166              len = sizeof(addrRTP);
     2167              int ts = 0;
     2168              int sn = 0;
     2169              int ssrc = 0;
     2170              int init = 0;
     2171              int u, v, w;
     2172              while(!stop && (i = recvfrom(sockudp, buf, 1526, 0,
     2173              (struct sockaddr*) &addrRTP, &len)) > 0)
     2174              {
     2175                alarm(ALARMTIME);
     2176                if(i >= 12+1 && (unsigned char)buf[0] == (2 << 6) && buf[1] == 0x60)
     2177                {
     2178                  u= ((unsigned char)buf[2]<<8)+(unsigned char)buf[3];
     2179                  v = ((unsigned char)buf[4]<<24)+((unsigned char)buf[5]<<16)
     2180                  +((unsigned char)buf[6]<<8)+(unsigned char)buf[7];
     2181                  w = ((unsigned char)buf[8]<<24)+((unsigned char)buf[9]<<16)
     2182                  +((unsigned char)buf[10]<<8)+(unsigned char)buf[11];
     2183
     2184                  if(init)
     2185                  {
     2186                    if(u < -30000 && sn > 30000) sn -= 0xFFFF;
     2187                    if(ssrc != w || ts > v)
     2188                    {
     2189                      RTCM3Error("Illegal UDP data received.\n");
     2190                      exit(1);
     2191                    }
     2192                    if(u > sn) /* don't show out-of-order packets */
     2193                      fwrite(buf+12, (size_t)i-12, 1, stdout);
     2194                  }
     2195                  sn = u; ts = v; ssrc = w; init = 1;
     2196                }
     2197                else
     2198                {
     2199                  RTCM3Error("Illegal UDP header.\n");
     2200                  exit(1);
     2201                }
     2202              }
     2203            }
     2204            i = snprintf(buf, MAXDATASIZE,
     2205            "TEARDOWN rtsp://%s%s%s/%s RTSP/1.0\r\n"           
     2206            "CSeq: %d\r\n"
     2207            "Session: %d\r\n"
     2208            "\r\n",
     2209            args.server, proxyserver ? ":" : "", proxyserver ? args.port : "",
     2210            args.data, cseq++, session);
     2211
     2212            if(i > MAXDATASIZE || i < 0) /* second check for old glibc */
     2213            {
     2214              RTCM3Error("Requested data too long\n");
     2215              exit(1);
     2216            }
     2217            if(send(sockfd, buf, (size_t)i, 0) != i)
     2218            {
     2219              perror("send");
     2220              exit(1);
     2221            }
     2222          }
     2223          else
     2224          {
     2225            RTCM3Error("Could not start data stream.\n");
     2226            exit(1);
     2227          }
    14272228        }
    14282229        else
    14292230        {
    1430           int z;
    1431           for(z = 0; z < numbytes && !stop; ++z)
    1432             HandleByte(&Parser, (unsigned int) buf[z]);
    1433         }
     2231          RTCM3Error("Could not setup initial control connection.\n");
     2232          exit(1);
     2233        }
     2234      }
     2235      else
     2236      {
     2237        perror("recv");
     2238        exit(1);
    14342239      }
    14352240    }
    14362241    else
    14372242    {
    1438       while((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
    1439       {
    1440         fwrite(buf, (size_t)numbytes, 1, stdout);
    1441       }
    1442     }
    1443 
    1444     close(sockfd);
     2243      if(connect(sockfd, (struct sockaddr *)&their_addr,
     2244      sizeof(struct sockaddr)) == -1)
     2245      {
     2246        perror("connect");
     2247        exit(1);
     2248      }
     2249      if(!args.data)
     2250      {
     2251        i = snprintf(buf, MAXDATASIZE,
     2252        "GET %s%s%s%s/ HTTP/1.0\r\n"
     2253        "Host: %s\r\n%s"
     2254        "User-Agent: %s/%s\r\n"
     2255        "\r\n"
     2256        , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
     2257        proxyserver ? ":" : "", proxyserver ? proxyport : "",
     2258        args.server, args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
     2259        AGENTSTRING, revisionstr);
     2260      }
     2261      else
     2262      {
     2263        i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */
     2264        "GET %s%s%s%s/%s HTTP/1.0\r\n"
     2265        "Host: %s\r\n%s"
     2266        "User-Agent: %s/%s\r\n"
     2267        "Authorization: Basic "
     2268        , proxyserver ? "http://" : "", proxyserver ? proxyserver : "",
     2269        proxyserver ? ":" : "", proxyserver ? proxyport : "",
     2270        args.data, args.server,
     2271        args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n",
     2272        AGENTSTRING, revisionstr);
     2273        if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */
     2274        {
     2275          RTCM3Error("Requested data too long\n");
     2276          exit(1);
     2277        }
     2278        i += encode(buf+i, MAXDATASIZE-i-4, args.user, args.password);
     2279        if(i > MAXDATASIZE-4)
     2280        {
     2281          RTCM3Error("Username and/or password too long\n");
     2282          exit(1);
     2283        }
     2284        buf[i++] = '\r';
     2285        buf[i++] = '\n';
     2286        buf[i++] = '\r';
     2287        buf[i++] = '\n';
     2288        if(args.nmea)
     2289        {
     2290          int j = snprintf(buf+i, MAXDATASIZE-i, "%s\r\n", args.nmea);
     2291          if(j >= 0 && j < MAXDATASIZE-i)
     2292            i += j;
     2293          else
     2294          {
     2295            RTCM3Error("NMEA string too long\n");
     2296            exit(1);
     2297          }
     2298        }
     2299      }
     2300      if(send(sockfd, buf, (size_t)i, 0) != i)
     2301      {
     2302        perror("send");
     2303        exit(1);
     2304      }
     2305      if(args.data)
     2306      {
     2307        int k = 0;
     2308        int chunkymode = 0;
     2309        int starttime = time(0);
     2310        int lastout = starttime;
     2311        int totalbytes = 0;
     2312        int chunksize = 0;
     2313
     2314        while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) != -1)
     2315        {
     2316          alarm(ALARMTIME);
     2317          if(!k)
     2318          {
     2319            if(numbytes > 17 && (!strncmp(buf, "HTTP/1.1 200 OK\r\n", 17)
     2320            || !strncmp(buf, "HTTP/1.0 200 OK\r\n", 17)))
     2321            {
     2322              const char *datacheck = "Content-Type: gnss/data\r\n";
     2323              const char *chunkycheck = "Transfer-Encoding: chunked\r\n";
     2324              int l = strlen(datacheck)-1;
     2325              int j=0;
     2326              for(i = 0; j != l && i < numbytes-l; ++i)
     2327              {
     2328                for(j = 0; j < l && buf[i+j] == datacheck[j]; ++j)
     2329                  ;
     2330              }
     2331              if(i == numbytes-l)
     2332              {
     2333                RTCM3Error("No 'Content-Type: gnss/data' found\n");
     2334                exit(1);
     2335              }
     2336              l = strlen(chunkycheck)-1;
     2337              j=0;
     2338              for(i = 0; j != l && i < numbytes-l; ++i)
     2339              {
     2340                for(j = 0; j < l && buf[i+j] == chunkycheck[j]; ++j)
     2341                  ;
     2342              }
     2343              if(i < numbytes-l)
     2344                chunkymode = 1;
     2345            }
     2346            else if(numbytes < 12 || strncmp("ICY 200 OK\r\n", buf, 12))
     2347            {
     2348              RTCM3Error("Could not get the requested data: ");
     2349              for(k = 0; k < numbytes && buf[k] != '\n' && buf[k] != '\r'; ++k)
     2350              {
     2351                RTCM3Error("%c", isprint(buf[k]) ? buf[k] : '.');
     2352              }
     2353              RTCM3Error("\n");
     2354              exit(1);
     2355            }
     2356            else if(args.mode != NTRIP1)
     2357            {
     2358              if(args.mode != AUTO)
     2359              {
     2360                RTCM3Error("NTRIP version 2 HTTP connection failed%s.\n",
     2361                args.mode == AUTO ? ", falling back to NTRIP1" : "");
     2362              }
     2363              if(args.mode == HTTP)
     2364                exit(1);
     2365            }
     2366            ++k;
     2367          }
     2368          else
     2369          {
     2370            if(chunkymode)
     2371            {
     2372              int stop = 0;
     2373              int pos = 0;
     2374              while(!stop && pos < numbytes)
     2375              {
     2376                switch(chunkymode)
     2377                {
     2378                case 1: /* reading number starts */
     2379                  chunksize = 0;
     2380                  ++chunkymode; /* no break */
     2381                case 2: /* during reading number */
     2382                  i = buf[pos++];
     2383                  if(i >= '0' && i <= '9') chunksize = chunksize*16+i-'0';
     2384                  else if(i >= 'a' && i <= 'f') chunksize = chunksize*16+i-'a'+10;
     2385                  else if(i >= 'A' && i <= 'F') chunksize = chunksize*16+i-'A'+10;
     2386                  else if(i == '\r') ++chunkymode;
     2387                  else stop = 1;
     2388                  break;
     2389                case 3: /* scanning for return */
     2390                  if(buf[pos++] == '\n') chunkymode = chunksize ? 4 : 1;
     2391                  else stop = 1;
     2392                  break;
     2393                case 4: /* output data */
     2394                  i = numbytes-pos;
     2395                  if(i > chunksize) i = chunksize;
     2396                  {
     2397                    int z;
     2398                    for(z = 0; z < i && !stop; ++z)
     2399                      HandleByte(&Parser, (unsigned int) buf[pos+z]);
     2400                  }
     2401                  totalbytes += i;
     2402                  chunksize -= i;
     2403                  pos += i;
     2404                  if(!chunksize)
     2405                    chunkymode = 1;
     2406                  break;
     2407                }
     2408              }
     2409              if(stop)
     2410              {
     2411                RTCM3Error("Error in chunky transfer encoding\n");
     2412                break;
     2413              }
     2414            }
     2415            else
     2416            {
     2417              totalbytes += numbytes;
     2418              {
     2419                int z;
     2420                for(z = 0; z < numbytes && !stop; ++z)
     2421                  HandleByte(&Parser, (unsigned int) buf[z]);
     2422              }
     2423            }
     2424            if(totalbytes < 0) /* overflow */
     2425            {
     2426              totalbytes = 0;
     2427              starttime = time(0);
     2428              lastout = starttime;
     2429            }
     2430          }
     2431        }
     2432      }
     2433      else
     2434      {
     2435        while(!stop && (numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) > 0)
     2436        {
     2437          alarm(ALARMTIME);
     2438          fwrite(buf, (size_t)numbytes, 1, stdout);
     2439        }
     2440      }
     2441      close(sockfd);
     2442    }
    14452443  }
    14462444  return 0;
  • trunk/rtcm3torinex/rtcm3torinex.h

    r365 r502  
    44/*
    55  Converter for RTCM3 data to RINEX.
    6   $Id: rtcm3torinex.h,v 1.5 2007/01/11 14:10:13 stoecker Exp $
    7   Copyright (C) 2005-2006 by Dirk Stoecker <stoecker@euronik.eu>
     6  $Id: rtcm3torinex.h,v 1.6 2007/01/15 13:01:40 stoecker Exp $
     7  Copyright (C) 2005-2006 by Dirk Stoecker <stoecker@alberding.eu>
    88
    99  This program is free software; you can redistribute it and/or modify
     
    110110};
    111111
     112#define GPSEPHF_L2PCODEDATA    (1<<0) /* set, if NAV data OFF on L2 P-code, s1w4b01 */
     113#define GPSEPHF_L2PCODE        (1<<1) /* set, if P-code available, s1w3b12 */
     114#define GPSEPHF_L2CACODE       (1<<2) /* set, if CA-code available, s1w3b11 */
     115#define GPSEPHF_VALIDATED      (1<<3) /* data is completely valid */
     116
     117#define PI          3.1415926535898
     118
     119struct gpsephemeris {
     120  int    flags;            /* GPSEPHF_xxx */
     121  int    satellite;        /*  SV ID   ICD-GPS data position */
     122  int    IODE;             /*          [s2w3b01-08]              */
     123  int    URAindex;         /*  [1..15] [s1w3b13-16]              */
     124  int    SVhealth;         /*          [s1w3b17-22]              */
     125  int    GPSweek;          /*          [s1w3b01-10]              */
     126  int    IODC;             /*          [s1w3b23-32,w8b01-08]     */
     127  int    TOW;              /*  [s]     [s1w2b01-17]              */
     128  int    TOC;              /*  [s]     [s1w8b09-24]              */
     129  int    TOE;              /*  [s]     [s2w10b1-16]              */
     130  double clock_bias;       /*  [s]     [s1w10b1-22, af0]         */
     131  double clock_drift;      /*  [s/s]   [s1w9b09-24, af1]         */
     132  double clock_driftrate;  /*  [s/s^2] [s1w9b01-08, af2]         */
     133  double Crs;              /*  [m]     [s2w3b09-24]              */
     134  double Delta_n;          /*  [rad/s] [s2w4b01-16 * Pi]         */
     135  double M0;               /*  [rad]   [s2w4b17-24,w5b01-24 * Pi]*/
     136  double Cuc;              /*  [rad]   [s2w6b01-16]              */
     137  double e;                /*          [s2w6b17-24,w6b01-24]     */
     138  double Cus;              /*  [rad]   [s2w8b01-16]              */
     139  double sqrt_A;           /*  [m^0.5] [s2w8b16-24,w9b01-24]     */
     140  double Cic;              /*  [rad]   [s3w3b01-16]              */
     141  double OMEGA0;           /*  [rad]   [s3w3b17-24,w4b01-24 * Pi]*/
     142  double Cis;              /*  [rad]   [s3w5b01-16]              */
     143  double i0;               /*  [rad]   [s3w5b17-24,w6b01-24 * Pi]*/
     144  double Crc;              /*  [m]     [s3w701-16]               */
     145  double omega;            /*  [rad]   [s3w7b17-24,w8b01-24 * Pi]*/
     146  double OMEGADOT;         /*  [rad/s] [s3w9b01-24 * Pi]         */
     147  double IDOT;             /*  [rad/s] [s3w10b9-22 * Pi]         */
     148  double TGD;              /*  [s]     [s1w7b17-24]              */
     149};
     150
     151#define GLOEPHF_UNHEALTHY       (1<<0) /* set if unhealty satellite, f2b78 */
     152#define GLOEPHF_ALMANACHEALTHOK (1<<1) /* set if ALM health is available */
     153#define GLOEPHF_ALMANACHEALTHY  (1<<2) /* set if Cn word is true */
     154#define GLOEPHF_PAVAILABLE      (1<<3) /* set if the 3 P flags are available */
     155#define GLOEPHF_P10TRUE         (1<<4)
     156#define GLOEPHF_P11TRUE         (1<<5)
     157#define GLOEPHF_P2TRUE          (1<<6)
     158#define GLOEPHF_P3TRUE          (1<<7)
     159
     160struct glonassephemeris {
     161  int    GPSWeek;
     162  int    GPSTOW;
     163  int    flags;              /* GLOEPHF_xxx */
     164  int    almanac_number;
     165  int    frequency_number;   /* ICD-GLONASS data position */
     166  int    tb;                 /* [s]     [f2b70-76] */
     167  int    tk;                 /* [s]     [f1b65-76] */
     168  int    E;                  /* [days]  [f4b49-53] */
     169  double tau;                /* [s]     [f4b59-80] */
     170  double gamma;              /*         [f3b69-79] */
     171  double x_pos;              /* [km]    [f1b09-35] */
     172  double x_velocity;         /* [km/s]  [f1b41-64] */
     173  double x_acceleration;     /* [km/s^2][f1b36-40] */
     174  double y_pos;              /* [km]    [f2b09-35] */
     175  double y_velocity;         /* [km/s]  [f2b41-64] */
     176  double y_acceleration;     /* [km/s^2][f2b36-40] */
     177  double z_pos;              /* [km]    [f3b09-35] */
     178  double z_velocity;         /* [km/s]  [f3b41-64] */
     179  double z_acceleration;     /* [km/s^2][f3b36-40] */
     180};
     181
    112182struct RTCM3ParserData {
    113183  unsigned char Message[2048]; /* input-buffer */
     
    118188  int    GPSTOW;        /* in seconds */
    119189  struct gnssdata Data;
     190  struct gpsephemeris ephemerisGPS;
     191  struct glonassephemeris ephemerisGLONASS;
    120192  struct gnssdata DataNew;
    121193  int    size;
     
    124196  int    datapos[RINEXENTRY_NUMBER];
    125197  int    dataflag[RINEXENTRY_NUMBER];
    126   int    datapos2[RINEXENTRY_NUMBER];
    127   int    dataflag2[RINEXENTRY_NUMBER];
    128   int    numdatatypes;
     198  /* for RINEX2 GPS and GLO are both handled in GPS */
     199  int    dataposGPS[RINEXENTRY_NUMBER]; /* SBAS has same entries */
     200  int    dataflagGPS[RINEXENTRY_NUMBER];
     201  int    dataposGLO[RINEXENTRY_NUMBER]; /* only used for RINEX3 */
     202  int    dataflagGLO[RINEXENTRY_NUMBER];
     203  int    numdatatypesGPS;
     204  int    numdatatypesGLO; /* only used for RINEX3 */
    129205  int    validwarning;
    130206  int    init;
    131207  int    startflags;
     208  int    rinex3;
    132209  const char * headerfile;
     210  const char * glonassephemeris;
     211  const char * gpsephemeris;
     212  FILE *glonassfile;
     213  FILE *gpsfile;
    133214};
    134215
  • trunk/rtcm3torinex/rtcm3torinex.txt

    r318 r502  
    22221012  GLONASS L1 and L2 code and phase and ambiguities and carrier to noise ratio
    23231013  Modified julian date, leep second, configured message types and intervall
    24 1014-1017 Network RTK (MAK) messages (under development)
    25 1019  GPS Ephemeris (under development)
    26 1020  GLONASS Ephemeris (under development)
     241014-1017 Network RTK (MAK) messages
     251019  GPS Ephemeris
     261020  GLONASS Ephemeris
    27274088-4095 Proprietary messages (under development)
    2828
    2929Note that this version of rtcm3torinex only handles RTCM3 message types 1001,
    30 1002, 1003, 1004, 1009, 1010, 1011 and 1012.
     301002, 1003, 1004, 1009, 1010, 1011, 1012, 1019 and 1020.
    3131
    3232The generated RINEX is somewhat limited due to the streaming character of the
     
    3737   additional fields cannot be provided.
    3838 - The number of observables cannot change during the program runtime. Only
    39    the observables, which exist in the first epoch are outputted. If there
     39   the observables, which exist in the first epoch are output. If there
    4040   are new observables later on, these are ignored.
    4141 - Only known message types are interpreted. This means only GPS data at the
     
    4848   easy positioning algorithm).
    4949
    50 Usage: rtcm3torinex -s server -u user ...
    51  -d --data       the requested data set
    52  -f --headerfile file for RINEX header information
    53  -s --server     the server name or address
    54  -p --password   the login password
    55  -r --port       the server port number (default 80)
    56  -u --user       the user name
     50Usage: ./rtcm3torinex -s server -u user ...
     51 -d --data             the requested data set
     52 -f --headerfile       file for RINEX header information
     53 -s --server           the server name or address
     54 -p --password         the login password
     55 -r --port             the server port number (default 2101)
     56 -t --timeout          timeout in seconds (default 60)
     57 -u --user             the user name
     58 -E --gpsephemeris     output file for GPS ephemeris data
     59 -G --glonassephemeris output file for GLONASS ephemeris data
     60 -3 --rinex3           output RINEX type 3 data
     61 -S --proxyhost        proxy name or address
     62 -R --proxyport        proxy port, optional (default 2101)
     63 -n --nmea             NMEA string for sending to server
     64 -M --mode             mode for data request
     65     Valid modes are:
     66     1, h, http     NTRIP Version 2.0 Caster in TCP/IP mode
     67     2, r, rtsp     NTRIP Version 2.0 Caster in RTSP/RTP mode
     68     3, n, ntrip1   NTRIP Version 1.0 Caster
     69     4, a, auto     automatic detection (default)
    5770
    5871The fields --user and --password are used to specify the access data for the
    5972NTRIP server. The arguments --server and --port are used to specify the NTRIP
    60 server itself (defaults to "www.euref-ip.net" port 80). The Argument --data
     73server itself (defaults to "www.euref-ip.net" port 2101). The Argument --data
    6174must be used to specify the RTCM3 input data stream. If it is not given, you
    6275will be shown the source table of the selected NTRIP caster.
    6376
    6477Alternatively a single text of the form
    65 "ntrip:mountpoint[/username[:password]][@server[:port]]"
     78"ntrip:data[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]"
    6679can be used. Everything in brackets is optional.
    6780
     
    101114
    102115Dirk Stoecker
    103 Euronik GmbH
    104 http://www.euronik.eu/
     116Alberding GmbH
     117http://www.alberding.eu/
    105118
    106119for
     
    111124http://igs.bkg.bund.de/index_ntrip.htm
    112125
    113 Contact Dirk Stoecker [stoecker@euronik.eu] or [euref-ip@bkg.bund.de]
     126Contact Dirk Stoecker [stoecker@alberding.eu] or [euref-ip@bkg.bund.de]
    114127with your comments, suggestions, improvements, patches, ...
Note: See TracChangeset for help on using the changeset viewer.