diff --git a/src/convrnx.c b/src/convrnx.c index d017eded6056fbf0c7237409952369914ee9b92e..4cf6816c7ba28e013aca377bfddbe935948f3819 100644 --- a/src/convrnx.c +++ b/src/convrnx.c @@ -1004,7 +1004,12 @@ static void convobs(FILE **ofp, rnxopt_t *opt, strfile_t *str, int *staid, } } /* output rinex obs */ - outrnxobsb(ofp[0],opt,str->obs->data,str->obs->n,0); + outrnxobsb(ofp[0],opt,str->obs); + /* n[NOUTFILE+1] - count of events converted to rinex */ + if (str->obs->flag == 5) + n[NOUTFILE+1]++; + /* set to zero flag for the next iteration (initialization) */ + str->obs->flag = 0; if (opt->tstart.time==0) opt->tstart=time; opt->tend=time; @@ -1215,7 +1220,7 @@ static void setapppos(strfile_t *str, rnxopt_t *opt) /* show status message -------------------------------------------------------*/ static int showstat(int sess, gtime_t ts, gtime_t te, int *n) { - const char type[]="ONGHQLCISE"; + const char type[]="ONGHQLCISET"; char msg[1024]="",*p=msg,s[64]; int i; @@ -1232,9 +1237,10 @@ static int showstat(int sess, gtime_t ts, gtime_t te, int *n) } p+=sprintf(p,": "); - for (i=0;i<NOUTFILE+1;i++) { + /* +2 to NOUTFILE for counters of errors and events */ + for (i=0;i<NOUTFILE+2;i++) { if (n[i]==0) continue; - p+=sprintf(p,"%c=%d%s",type[i],n[i],i<NOUTFILE?" ":""); + p+=sprintf(p,"%c=%d%s",type[i],n[i],i<NOUTFILE+1?" ":""); } return showmsg(msg); } @@ -1248,7 +1254,7 @@ static int convrnx_s(int sess, int format, rnxopt_t *opt, const char *file, halfc_t halfc={{{0}}}; gtime_t ts={0},te={0},tend={0},time={0}; unsigned char slips[MAXSAT][NFREQ+NEXOBS]={{0}}; - int i,j,nf,type,n[NOUTFILE+1]={0},staid=-1,abort=0; + int i,j,nf,type,n[NOUTFILE+2]={0},staid=-1,abort=0; char path[1024],*paths[NOUTFILE],s[NOUTFILE][1024]; char *epath[MAXEXFILE]={0},*staname=*opt->staid?opt->staid:"0000"; diff --git a/src/rcv/swiftnav.c b/src/rcv/swiftnav.c index 6fe1989fde9a9c60d8abe3e2e8f2801467e88065..07fd6b5560b3890efc1d8d9aae9d115923d1be10 100644 --- a/src/rcv/swiftnav.c +++ b/src/rcv/swiftnav.c @@ -30,6 +30,7 @@ static const char rcsid[] = "$Id: Swiftnav SBP,v 1.0 2017/02/01 FT $"; #define ID_MSGEPHGLO 0x008B /* Glonass L1/L2 OF nav message */ #define ID_MSGIONGPS 0x0090 /* GPS ionospheric parameters */ #define ID_MSG_SBAS_RAW 0x7777 /* SBAS data */ +#define ID_MSG_EXT_EVENT 0x101 /* external event */ #define SEC_DAY 86400.0 @@ -294,6 +295,15 @@ static int flushobuf(raw_t *raw) { trace(3, "flushobuf: n=%d\n", raw->obuf.n); + /* copy events from data buffer */ + if (raw->obuf.eventime.time>0) { + raw->obs.eventime = raw->obuf.eventime; + raw->obs.timevalid = raw->obuf.timevalid; + raw->obs.flag = raw->obuf.flag; + raw->obs.rcvcount = raw->obuf.rcvcount; + raw->obs.tmcount=raw->obuf.tmcount; + } + /* copy observation data buffer */ for (i = 0; i < raw->obuf.n && i < MAXOBS; i++) { if (!satsys(raw->obuf.data[i].sat, NULL)) @@ -304,6 +314,11 @@ static int flushobuf(raw_t *raw) { } raw->obs.n = n; + /* clear events from data buffer */ + raw->obuf.eventime = time0; + raw->obuf.flag = raw->obuf.timevalid=0; + raw->obuf.rcvcount = raw->obuf.tmcount=0; + /* clear observation data buffer */ for (i = 0; i < MAXOBS; i++) { raw->obuf.data[i].time = time0; @@ -1132,6 +1147,39 @@ static int decode_snav(raw_t *raw) { return 3; } +/* decode external event -----------------------------------------------*/ +static int decode_event(raw_t *raw) { + gtime_t eventime; + uint8_t *puiTmp = (raw->buff) + 6; + uint16_t wn; + uint32_t tow; + int32_t ns_residual; + uint8_t flags,pin; + + trace(4, "MSG_EXT_EVENT: len=%d\n", raw->len); + + if ((raw->len) < 20) { + trace(2, "SBP decode_event length error: len=%d\n", raw->len); + return -1; + } + +/* get message fields */ + wn = U2(puiTmp + 0); + tow = U4(puiTmp + 2); + ns_residual = I4(puiTmp + 6); + flags = U1(puiTmp + 10); + pin = U1(puiTmp + 11); + +/* write to event variables */ + eventime = gpst2time(wn,tow*1E-3+ns_residual*1E-9); + raw->obuf.flag = 5; /* event flag */ + raw->obuf.eventime = eventime; + raw->obuf.tmcount++; + raw->obuf.timevalid = (flags & 0x02)>>1; + + return 0; +} + /* decode SBF raw message --------------------------------------------------*/ static int decode_sbp(raw_t *raw) { uint16_t crc, uCalcCrc; @@ -1182,6 +1230,8 @@ static int decode_sbp(raw_t *raw) { return decode_gpsion(raw); case ID_MSG_SBAS_RAW: return decode_snav(raw); + case ID_MSG_EXT_EVENT: + return decode_event(raw); default: trace(4, "decode_sbp: unused frame type=%04x len=%d\n", type, raw->len); diff --git a/src/rcv/ublox.c b/src/rcv/ublox.c index e1dd2d4bc7239ed6d1879fa6ce22dbf2a0394997..c1b329caa4d0b1d6859ffde04c7132b09d78c990 100644 --- a/src/rcv/ublox.c +++ b/src/rcv/ublox.c @@ -71,6 +71,7 @@ #define ID_TRKD5 0x030A /* ubx message id: trace mesurement data */ #define ID_TRKMEAS 0x0310 /* ubx message id: trace mesurement data */ #define ID_TRKSFRBX 0x030F /* ubx message id: trace subframe buffer */ +#define ID_TIMTM2 0x0D03 /* ubx message id: time mark data */ #define FU1 1 /* ubx message field types */ #define FU2 2 @@ -1071,6 +1072,52 @@ static int decode_trksfrbx(raw_t *raw) } return 0; } +/* decode ubx-tim-tm2: time mark data ----------------------------------------*/ +static int decode_timtm2(raw_t *raw) +{ + gtime_t eventime; + char ch, flags; + unsigned int count, wnR, wnF; + unsigned long towMsR, towSubMsR, towMsF, towSubMsF, accEst; + int time, timeBase, newRisingEdge, newFallingEdge; + unsigned char *p=raw->buff+6; + + trace(4, "decode_timtm2: len=%d\n", raw->len); + + if (raw->outtype) { + sprintf(raw->msgtype, "UBX TIM-TM2 (%4d)", raw->len); + } + ch = U1(p); + flags = *(p+1); + count = U2(p+2); + wnR = U2(p+4); + wnF = U2(p+6); + towMsR = U4(p+8); + towSubMsR = U4(p+12); + towMsF = U4(p+16); + towSubMsF = U4(p+20); + accEst = U4(p+24); + + /* extract flags to variables */ + newFallingEdge = ((flags >> 2) & 0x01); + timeBase = ((flags >> 3) & 0x03); + time = ((flags >> 6) & 0x01); + newRisingEdge = ((flags >> 7) & 0x01); + + if (newFallingEdge) + { + eventime = gpst2time(wnF,towMsF*1E-3+towSubMsF*1E-9); + raw->obs.flag = 5; /* Event flag */ + raw->obs.eventime = eventime; + raw->obs.rcvcount = count; + raw->obs.tmcount++; + raw->obs.timevalid = time; + } else { + raw->obs.flag = 0; + } + return 0; +} + /* decode ublox raw message --------------------------------------------------*/ static int decode_ubx(raw_t *raw) { @@ -1093,6 +1140,7 @@ static int decode_ubx(raw_t *raw) case ID_TRKMEAS : return decode_trkmeas (raw); case ID_TRKD5 : return decode_trkd5 (raw); case ID_TRKSFRBX: return decode_trksfrbx(raw); + case ID_TIMTM2 : return decode_timtm2 (raw); } if (raw->outtype) { sprintf(raw->msgtype,"UBX 0x%02X 0x%02X (%4d)",type>>8,type&0xF, @@ -1107,7 +1155,7 @@ static int sync_ubx(unsigned char *buff, unsigned char data) return buff[0]==UBXSYNC1&&buff[1]==UBXSYNC2; } /* input ublox raw message from stream ----------------------------------------- -* fetch next ublox raw data and input a mesasge from stream +* fetch next ublox raw data and input a message from stream * args : raw_t *raw IO receiver raw data control struct * unsigned char data I stream data (1 byte) * return : status (-1: error message, 0: no message, 1: input observation data, diff --git a/src/rinex.c b/src/rinex.c index ced5a615dd32e405f7f9e8d9517804d44a84fc04..a04c8e0d72a5e184481db66da5f779fb9e8deaa6 100644 --- a/src/rinex.c +++ b/src/rinex.c @@ -14,7 +14,7 @@ * Version 2.12, June 23, 2009 * [5] W.Gurtner and L.Estey, RINEX The Receiver Independent Exchange Format * Version 3.01, June 22, 2009 -* [6] J.Ray and W.Gurtner, RINEX extentions to handle clock information +* [6] J.Ray and W.Gurtner, RINEX extensions to handle clock information * version 3.02, September 2, 2010 * [7] RINEX The Receiver Independent Exchange Format Version 3.02, * International GNSS Service (IGS), RINEX Working Group and Radio @@ -544,7 +544,7 @@ static void decode_gnavh(char *buff, nav_t *nav) trace(4,"decode_gnavh:\n"); - if (strstr(label,"CORR TO SYTEM TIME" )) ; /* opt */ + if (strstr(label,"CORR TO SYSTEM TIME" )) ; /* opt */ else if (strstr(label,"LEAP SECONDS" )) { /* opt */ if (nav) nav->leaps=(int)str2num(buff,0,6); } @@ -556,7 +556,7 @@ static void decode_hnavh(char *buff, nav_t *nav) trace(4,"decode_hnavh:\n"); - if (strstr(label,"CORR TO SYTEM TIME" )) ; /* opt */ + if (strstr(label,"CORR TO SYSTEM TIME" )) ; /* opt */ else if (strstr(label,"D-UTC A0,A1,T,W,S,U" )) ; /* opt */ else if (strstr(label,"LEAP SECONDS" )) { /* opt */ if (nav) nav->leaps=(int)str2num(buff,0,6); @@ -2038,6 +2038,27 @@ static int obsindex(double ver, int sys, const unsigned char *code, } return -1; } +/* output rinex event time ---------------------------------------------------*/ +static void outrinexevent(FILE *fp, const rnxopt_t *opt, const obs_t *obs, + const double epdiff) +{ + int n; + double epe[6]; + + time2epoch(obs->eventime,epe); + n = obs->timevalid ? 0 : 1; + + if (opt->rnxver<=2.99) { /* ver.2 */ + if (epdiff < 0) fprintf(fp,"\n"); + fprintf(fp," %02d %2.0f %2.0f %2.0f %2.0f%11.7f %d%3d", + (int)epe[0]%100,epe[1],epe[2],epe[3],epe[4],epe[5],5,n); + if (epdiff >= 0) fprintf(fp,"\n"); + } else { /* ver.3 */ + fprintf(fp,"> %04.0f %2.0f %2.0f %2.0f %2.0f%11.7f %d%3d\n", + epe[0],epe[1],epe[2],epe[3],epe[4],epe[5],5,n); + } + if (n) fprintf(fp,"%-60.60s%-20s\n"," Time mark is not valid","COMMENT"); +} /* output rinex obs body ------------------------------------------------------- * output rinex obs body * args : FILE *fp I output file pointer @@ -2047,22 +2068,21 @@ static int obsindex(double ver, int sys, const unsigned char *code, * int flag I epoch flag (0:ok,1:power failure,>1:event flag) * return : status (1:ok, 0:output error) *-----------------------------------------------------------------------------*/ -extern int outrnxobsb(FILE *fp, const rnxopt_t *opt, const obsd_t *obs, int n, - int flag) +extern int outrnxobsb(FILE *fp, const rnxopt_t *opt, const obs_t *obs) { const char *mask; - double ep[6]; + double epdiff,ep[6]; char sats[MAXOBS][4]={""}; int i,j,k,m,ns,sys,ind[MAXOBS],s[MAXOBS]={0}; + + trace(3,"outrnxobsb: n=%d\n",obs->n); + + time2epoch(obs->data[0].time,ep); - trace(3,"outrnxobsb: n=%d\n",n); - - time2epoch(obs[0].time,ep); - - for (i=ns=0;i<n&&ns<MAXOBS;i++) { - sys=satsys(obs[i].sat,NULL); - if (!(sys&opt->navsys)||opt->exsats[obs[i].sat-1]) continue; - if (!sat2code(obs[i].sat,sats[ns])) continue; + for (i=ns=0;i<obs->n&&ns<MAXOBS;i++) { + sys=satsys(obs->data[i].sat,NULL); + if (!(sys&opt->navsys)||opt->exsats[obs->data[i].sat-1]) continue; + if (!sat2code(obs->data[i].sat,sats[ns])) continue; switch (sys) { case SYS_GPS: s[ns]=0; break; case SYS_GLO: s[ns]=1; break; @@ -2075,9 +2095,17 @@ extern int outrnxobsb(FILE *fp, const rnxopt_t *opt, const obsd_t *obs, int n, if (!opt->nobs[opt->rnxver<=2.99?0:s[ns]]) continue; ind[ns++]=i; } + + /* if epoch of event less than epoch of observation, then first output + time mark, else first output observation record */ + epdiff = timediff(obs->data[0].time,obs->eventime); + if (obs->flag == 5 && epdiff >= 0) { + outrinexevent(fp, opt, obs, epdiff); + } + if (opt->rnxver<=2.99) { /* ver.2 */ fprintf(fp," %02d %2.0f %2.0f %2.0f %2.0f%11.7f %d%3d", - (int)ep[0]%100,ep[1],ep[2],ep[3],ep[4],ep[5],flag,ns); + (int)ep[0]%100,ep[1],ep[2],ep[3],ep[4],ep[5],0,ns); for (i=0;i<ns;i++) { if (i>0&&i%12==0) fprintf(fp,"\n%32s",""); fprintf(fp,"%-3s",sats[i]); @@ -2085,10 +2113,10 @@ extern int outrnxobsb(FILE *fp, const rnxopt_t *opt, const obsd_t *obs, int n, } else { /* ver.3 */ fprintf(fp,"> %04.0f %2.0f %2.0f %2.0f %2.0f%11.7f %d%3d%21s\n", - ep[0],ep[1],ep[2],ep[3],ep[4],ep[5],flag,ns,""); + ep[0],ep[1],ep[2],ep[3],ep[4],ep[5],0,ns,""); } for (i=0;i<ns;i++) { - sys=satsys(obs[ind[i]].sat,NULL); + sys=satsys(obs->data[ind[i]].sat,NULL); if (opt->rnxver<=2.99) { /* ver.2 */ m=0; @@ -2105,7 +2133,7 @@ extern int outrnxobsb(FILE *fp, const rnxopt_t *opt, const obsd_t *obs, int n, if (j%5==0) fprintf(fp,"\n"); } /* search obs data index */ - if ((k=obsindex(opt->rnxver,sys,obs[ind[i]].code,opt->tobs[m][j], + if ((k=obsindex(opt->rnxver,sys,obs->data[ind[i]].code,opt->tobs[m][j], mask))<0) { outrnxobsf(fp,0.0,-1,-1); continue; @@ -2113,14 +2141,19 @@ extern int outrnxobsb(FILE *fp, const rnxopt_t *opt, const obsd_t *obs, int n, /* output field */ switch (opt->tobs[m][j][0]) { case 'C': - case 'P': outrnxobsf(fp,obs[ind[i]].P[k],-1,obs[ind[i]].qualP[k]); break; - case 'L': outrnxobsf(fp,obs[ind[i]].L[k],obs[ind[i]].LLI[k],obs[ind[i]].qualL[k]); break; - case 'D': outrnxobsf(fp,obs[ind[i]].D[k],-1,-1); break; - case 'S': outrnxobsf(fp,obs[ind[i]].SNR[k]*0.25,-1,-1); break; + case 'P': outrnxobsf(fp,obs->data[ind[i]].P[k],-1,obs->data[ind[i]].qualP[k]); break; + case 'L': outrnxobsf(fp,obs->data[ind[i]].L[k],obs->data[ind[i]].LLI[k],obs->data[ind[i]].qualL[k]); break; + case 'D': outrnxobsf(fp,obs->data[ind[i]].D[k],-1,-1); break; + case 'S': outrnxobsf(fp,obs->data[ind[i]].SNR[k]*0.25,-1,-1); break; } } if (opt->rnxver>2.99&&fprintf(fp,"\n")==EOF) return 0; } + + if (obs->flag == 5 && epdiff < 0) { + outrinexevent(fp, opt, obs, epdiff); + } + if (opt->rnxver>2.99) return 1; return fprintf(fp,"\n")!=EOF; @@ -2581,7 +2614,7 @@ extern int outrnxlnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav) return fprintf(fp,"%60s%-20s\n","","END OF HEADER")!=EOF; } /* output rinex qzss nav header ------------------------------------------------ -* output rinex qzss nav file header (2.12 extention and 3.02) +* output rinex qzss nav file header (2.12 extension and 3.02) * args : FILE *fp I output file pointer * rnxopt_t *opt I rinex options * nav_t nav I navigation data (NULL: no input) @@ -2609,7 +2642,7 @@ extern int outrnxqnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav) return fprintf(fp,"%60s%-20s\n","","END OF HEADER")!=EOF; } /* output rinex beidou nav header ---------------------------------------------- -* output rinex beidou nav file header (2.12 extention and 3.02) +* output rinex beidou nav file header (2.12 extension and 3.02) * args : FILE *fp I output file pointer * rnxopt_t *opt I rinex options * nav_t nav I navigation data (NULL: no input) diff --git a/src/rtklib.h b/src/rtklib.h index 30c592826480921b6ca677bf4974216cb9c2848b..f2307fbcf4719d1a05fc79781bdc15420eeaf3fc 100644 --- a/src/rtklib.h +++ b/src/rtklib.h @@ -557,6 +557,11 @@ typedef struct { /* observation data record */ } obsd_t; typedef struct { /* observation data */ + gtime_t eventime; /* time of event (GPST) */ + int timevalid; /* time is valid (Valid GNSS fix) for time mark */ + int flag; /* epoch flag (0:ok,1:power failure,>1:event flag) */ + int rcvcount; /* count of rcv event */ + int tmcount; /* time mark count */ int n,nmax; /* number of obervation data/allocated */ obsd_t *data; /* observation data records */ } obs_t; @@ -1608,8 +1613,7 @@ EXPORT int readrnxt(const char *file, int rcv, gtime_t ts, gtime_t te, sta_t *sta); EXPORT int readrnxc(const char *file, nav_t *nav); EXPORT int outrnxobsh(FILE *fp, const rnxopt_t *opt, const nav_t *nav); -EXPORT int outrnxobsb(FILE *fp, const rnxopt_t *opt, const obsd_t *obs, int n, - int epflag); +EXPORT int outrnxobsb(FILE *fp, const rnxopt_t *opt, const obs_t *obs); EXPORT int outrnxnavh (FILE *fp, const rnxopt_t *opt, const nav_t *nav); EXPORT int outrnxgnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav); EXPORT int outrnxhnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav);