/*------------------------------------------------------------------------------ * notvatel.c : NovAtel OEM7/OEM6/OEM5/OEM4/OEM3 receiver functions * * Copyright (C) 2007-2020 by T.TAKASU, All rights reserved. * * reference : * [1] NovAtel, OM-20000094 Rev6 OEMV Family Firmware Reference Manual, 2008 * [2] NovAtel, OM-20000053 Rev2 MiLLennium GPSCard Software Versions 4.503 * and 4.52 Command Descriptions Manual, 2001 * [3] NovAtel, OM-20000129 Rev2 OEM6 Family Firmware Reference Manual, 2011 * [4] NovAtel, OM-20000127 Rev1 OEMStar Firmware Reference Manual, 2009 * [5] NovAtel, OM-20000129 Rev6 OEM6 Family Firmware Reference Manual, 2014 * [6] NovAtel, OM-20000169 v15C OEM7 Commands and Logs Reference Manual, * June 2020 * * version : $Revision: 1.2 $ $Date: 2008/07/14 00:05:05 $ * history : 2007/10/08 1.0 new * 2008/05/09 1.1 fix bug lli flag outage * 2008/06/16 1.2 separate common functions to rcvcmn.c * 2009/04/01 1.3 add prn number check for raw obs data * 2009/04/10 1.4 refactored * add oem3, oem4 rangeb support * 2009/06/06 1.5 fix bug on numerical exception with illegal snr * support oem3 regd message * 2009/12/09 1.6 support oem4 gloephemerisb message * invalid if parity unknown in GLONASS range * fix bug of dopper polarity inversion for oem3 regd * 2010/04/29 1.7 add tod field in geph_t * 2011/05/27 1.8 support RAWALM for oem4/v * add almanac decoding * add -EPHALL option * fix problem on ARM compiler * 2012/05/02 1.9 support OEM6,L5,QZSS * 2012/10/18 1.10 change obs codes * support Galileo * support rawsbasframeb,galephemerisb,galalmanacb, * galclockb,galionob * 2012/11/08 1.11 support galfnavrawpageb, galinavrawword * 2012/11/19 1.12 fix bug on decodeing rangeb * 2013/02/23 1.13 fix memory access violation problem on arm * 2013/03/28 1.14 fix invalid phase if glonass wavelen unavailable * 2013/06/02 1.15 fix bug on reading galephemrisb,galalmanacb, * galclockb,galionob * fix bug on decoding rawwaasframeb for qzss-saif * 2014/05/24 1.16 support beidou * 2014/07/01 1.17 fix problem on decoding of bdsephemerisb * fix bug on beidou tracking codes * 2014/10/20 1.11 fix bug on receiver option -GL*,-RL*,-EL* * 2016/01/28 1.12 precede I/NAV for galileo ephemeris * add option -GALINAV and -GALFNAV * 2016/07/31 1.13 add week number check to decode oem4 messages * 2017/04/11 1.14 (char *) -> (signed char *) * improve unchange-test of beidou ephemeris * 2017/06/15 1.15 add output half-cycle-ambiguity status to LLI * improve slip-detection by lock-time rollback * 2018/10/10 1.16 fix problem on data souce for galileo ephemeris * output L2W instead of L2D for L2Pcodeless * test toc difference to output beidou ephemeris * 2019/05/10 1.17 save galileo E5b data to obs index 2 * 2020/11/30 1.18 support OEM7 receiver (ref [6]) * support NavIC/IRNSS * support GPS/QZS L1C, GLO L3, GAL E6, QZS L6, BDS B3, * B1C, B2a, B2b * support message NAVICEPHEMERISB * support QZS L1S in RANGEB and RANGECMPB * no support message GALALMANACB * add receiver option -GL1L,-GL2S,-GL2P,-EL6B,-JL1L, * -JL1Z,-CL1P,-CL7D,-GLOBIAS=bias * delete receiver option -GL1P,-GL2X,EL2C * fix bug on reading SVH in GLOEPHEMERISB * add reading of dtaun field in GLOEPHEMERISB * output GAL I/NAV or F/NAV to seperated ephem sets * use API sat2freq() to get carrier-frequency * use API code2idx() to get freq-index * use integer types in stdint.h *-----------------------------------------------------------------------------*/ #include "rtklib.h" #define OEM4SYNC1 0xAA /* oem7/6/4 message start sync code 1 */ #define OEM4SYNC2 0x44 /* oem7/6/4 message start sync code 2 */ #define OEM4SYNC3 0x12 /* oem7/6/4 message start sync code 3 */ #define OEM3SYNC1 0xAA /* oem3 message start sync code 1 */ #define OEM3SYNC2 0x44 /* oem3 message start sync code 2 */ #define OEM3SYNC3 0x11 /* oem3 message start sync code 3 */ #define OEM4HLEN 28 /* oem7/6/4 message header length (bytes) */ #define OEM3HLEN 12 /* oem3 message header length (bytes) */ /* message IDs */ #define ID_RANGECMP 140 /* oem7/6/4 range compressed */ #define ID_RANGE 43 /* oem7/6/4 range measurement */ #define ID_RAWEPHEM 41 /* oem7/6/4 raw ephemeris */ #define ID_IONUTC 8 /* oem7/6/4 iono and utc data */ #define ID_RAWWAASFRAME 287 /* oem7/6/4 raw waas frame */ #define ID_RAWSBASFRAME 973 /* oem7/6 raw sbas frame */ #define ID_GLOEPHEMERIS 723 /* oem7/6/4 glonass ephemeris */ #define ID_GALEPHEMERIS 1122 /* oem7/6 decoded galileo ephemeris */ #define ID_GALIONO 1127 /* oem7/6 decoded galileo iono corrections */ #define ID_GALCLOCK 1121 /* oem7/6 galileo clock information */ #define ID_QZSSRAWEPHEM 1331 /* oem7/6 qzss raw ephemeris */ #define ID_QZSSRAWSUBFRAME 1330 /* oem7/6 qzss raw subframe */ #define ID_QZSSIONUTC 1347 /* oem7/6 qzss ion/utc parameters */ #define ID_BDSEPHEMERIS 1696 /* oem7/6 decoded bds ephemeris */ #define ID_NAVICEPHEMERIS 2123 /* oem7 decoded navic ephemeris */ #define ID_ALMB 18 /* oem3 decoded almanac */ #define ID_IONB 16 /* oem3 iono parameters */ #define ID_UTCB 17 /* oem3 utc parameters */ #define ID_FRMB 54 /* oem3 framed raw navigation data */ #define ID_RALB 15 /* oem3 raw almanac */ #define ID_RASB 66 /* oem3 raw almanac set */ #define ID_REPB 14 /* oem3 raw ephemeris */ #define ID_RGEB 32 /* oem3 range measurement */ #define ID_RGED 65 /* oem3 range compressed */ #define WL1 0.1902936727984 #define WL2 0.2442102134246 #define MAXVAL 8388608.0 #define OFF_FRQNO -7 /* F/W ver.3.620 */ #define SQR(x) ((x)*(x)) /* get fields (little-endian) ------------------------------------------------*/ #define U1(p) (*((uint8_t *)(p))) #define I1(p) (*((int8_t *)(p))) static uint16_t U2(uint8_t *p) {uint16_t u; memcpy(&u,p,2); return u;} static uint32_t U4(uint8_t *p) {uint32_t u; memcpy(&u,p,4); return u;} static int32_t I4(uint8_t *p) {int32_t i; memcpy(&i,p,4); return i;} static float R4(uint8_t *p) {float r; memcpy(&r,p,4); return r;} static double R8(uint8_t *p) {double r; memcpy(&r,p,8); return r;} /* extend sign ---------------------------------------------------------------*/ static int32_t exsign(uint32_t v, int bits) { return (int32_t)(v&(1<<(bits-1))?v|(~0u<tow_p+302400.0) tow-=604800.0; return gpst2time(week,tow); } /* UTC 8-bit week -> full week -----------------------------------------------*/ static void adj_utcweek(gtime_t time, double *utc) { int week; time2gpst(time,&week); utc[3]+=week/256*256; if (utc[3]week+127) utc[3]-=256.0; utc[5]+=utc[3]/256*256; if (utc[5]utc[3]+127) utc[5]-=256.0; } /* get observation data index ------------------------------------------------*/ static int obsindex(obs_t *obs, gtime_t time, int sat) { int i,j; if (obs->n>=MAXOBS) return -1; for (i=0;in;i++) { if (obs->data[i].sat==sat) return i; } obs->data[i].time=time; obs->data[i].sat=sat; for (j=0;jdata[i].L[j]=obs->data[i].P[j]=0.0; obs->data[i].D[j]=0.0; obs->data[i].SNR[j]=obs->data[i].LLI[j]=0; obs->data[i].code[j]=CODE_NONE; } obs->n++; return i; } /* URA value (m) to URA index ------------------------------------------------*/ static int uraindex(double value) { static const double ura_eph[]={ 2.4,3.4,4.85,6.85,9.65,13.65,24.0,48.0,96.0,192.0,384.0,768.0,1536.0, 3072.0,6144.0,0.0 }; int i; for (i=0;i<15;i++) if (ura_eph[i]>=value) break; return i; } /* signal type to obs code ---------------------------------------------------*/ static int sig2code(int sys, int sigtype) { if (sys==SYS_GPS) { switch (sigtype) { case 0: return CODE_L1C; /* L1C/A */ case 5: return CODE_L2P; /* L2P (OEM7) */ case 9: return CODE_L2W; /* L2P(Y),semi-codeless */ case 14: return CODE_L5Q; /* L5Q (OEM6) */ case 16: return CODE_L1L; /* L1C(P) (OEM7) */ case 17: return CODE_L2S; /* L2C(M) (OEM7) */ } } else if (sys==SYS_GLO) { switch (sigtype) { case 0: return CODE_L1C; /* L1C/A */ case 1: return CODE_L2C; /* L2C/A (OEM6) */ case 5: return CODE_L2P; /* L2P */ case 6: return CODE_L3Q; /* L3Q (OEM7) */ } } else if (sys==SYS_GAL) { switch (sigtype) { case 2: return CODE_L1C; /* E1C (OEM6) */ case 6: return CODE_L6B; /* E6B (OEM7) */ case 7: return CODE_L6C; /* E6C (OEM7) */ case 12: return CODE_L5Q; /* E5aQ (OEM6) */ case 17: return CODE_L7Q; /* E5bQ (OEM6) */ case 20: return CODE_L8Q; /* AltBOCQ (OEM6) */ } } else if (sys==SYS_QZS) { switch (sigtype) { case 0: return CODE_L1C; /* L1C/A */ case 14: return CODE_L5Q; /* L5Q (OEM6) */ case 16: return CODE_L1L; /* L1C(P) (OEM7) */ case 17: return CODE_L2S; /* L2C(M) (OEM7) */ case 27: return CODE_L6L; /* L6P (OEM7) */ } } else if (sys==SYS_CMP) { switch (sigtype) { case 0: return CODE_L2I; /* B1I with D1 (OEM6) */ case 1: return CODE_L7I; /* B2I with D1 (OEM6) */ case 2: return CODE_L6I; /* B3I with D1 (OEM7) */ case 4: return CODE_L2I; /* B1I with D2 (OEM6) */ case 5: return CODE_L7I; /* B2I with D2 (OEM6) */ case 6: return CODE_L6I; /* B3I with D2 (OEM7) */ case 7: return CODE_L1P; /* B1C(P) (OEM7) */ case 9: return CODE_L5P; /* B2a(P) (OEM7) */ case 11: return CODE_L7D; /* B2b(I) (OEM7,F/W 7.08) */ } } else if (sys==SYS_IRN) { switch (sigtype) { case 0: return CODE_L5A; /* L5 (OEM7) */ } } else if (sys==SYS_SBS) { switch (sigtype) { case 0: return CODE_L1C; /* L1C/A */ case 6: return CODE_L5I; /* L5I (OEM6) */ } } return 0; } /* decode receiver tracking status --------------------------------------------- * decode receiver tracking status * args : uint32_t stat I tracking status field * int *sys O system (SYS_???) * int *code O signal code (CODE_L??) * int *track O tracking state * (OEM4/5) * 0=L1 idle 8=L2 idle * 1=L1 sky search 9=L2 p-code align * 2=L1 wide freq pull-in 10=L2 search * 3=L1 narrow freq pull-in 11=L2 pll * 4=L1 pll 12=L2 steering * 5=L1 reacq * 6=L1 steering * 7=L1 fll * (OEM6/7) * 0=idle 7=freq-lock loop * 2=wide freq band pull-in 9=channel alignment * 3=narrow freq band pull-in 10=code search * 4=phase lock loop 11=aided phase lock loop * int *plock O phase-lock flag (0=not locked, 1=locked) * int *clock O code-lock flag (0=not locked, 1=locked) * int *parity O parity known flag (0=not known, 1=known) * int *halfc O phase measurement (0=half-cycle not added, * 1=added) * return : freq-index (-1:error) * notes : refer [1][3] *-----------------------------------------------------------------------------*/ static int decode_track_stat(uint32_t stat, int *sys, int *code, int *track, int *plock, int *clock, int *parity, int *halfc) { int satsys,sigtype,idx=-1; *code=CODE_NONE; *track =stat&0x1F; *plock =(stat>>10)&1; *parity=(stat>>11)&1; *clock =(stat>>12)&1; satsys =(stat>>16)&7; *halfc =(stat>>28)&1; sigtype=(stat>>21)&0x1F; switch (satsys) { case 0: *sys=SYS_GPS; break; case 1: *sys=SYS_GLO; break; case 2: *sys=SYS_SBS; break; case 3: *sys=SYS_GAL; break; /* OEM6 */ case 4: *sys=SYS_CMP; break; /* OEM6 F/W 6.400 */ case 5: *sys=SYS_QZS; break; /* OEM6 */ case 6: *sys=SYS_IRN; break; /* OEM7 */ default: trace(2,"oem4 unknown system: sys=%d\n",satsys); return -1; } if (!(*code=sig2code(*sys,sigtype))||(idx=code2idx(*sys,*code))<0) { trace(2,"oem4 signal type error: sys=%d sigtype=%d\n",*sys,sigtype); return -1; } return idx; } /* check code priority and return freq-index ---------------------------------*/ static int checkpri(const char *opt, int sys, int code, int idx) { int nex=NEXOBS; if (sys==SYS_GPS) { if (strstr(opt,"-GL1L")&&idx==0) return (code==CODE_L1L)?0:-1; if (strstr(opt,"-GL2S")&&idx==1) return (code==CODE_L2X)?1:-1; if (strstr(opt,"-GL2P")&&idx==1) return (code==CODE_L2P)?1:-1; if (code==CODE_L1L) return (nex<1)?-1:NFREQ; if (code==CODE_L2S) return (nex<2)?-1:NFREQ+1; if (code==CODE_L2P) return (nex<3)?-1:NFREQ+2; } else if (sys==SYS_GLO) { if (strstr(opt,"-RL2C")&&idx==1) return (code==CODE_L2C)?1:-1; if (code==CODE_L2C) return (nex<1)?-1:NFREQ; } else if (sys==SYS_GAL) { if (strstr(opt,"-EL6B")&&idx==3) return (code==CODE_L6B)?3:-1; if (code==CODE_L6B) return (nex<2)?-1:NFREQ; } else if (sys==SYS_QZS) { if (strstr(opt,"-JL1L")&&idx==0) return (code==CODE_L1L)?0:-1; if (strstr(opt,"-JL1Z")&&idx==0) return (code==CODE_L1Z)?0:-1; if (code==CODE_L1L) return (nex<1)?-1:NFREQ; if (code==CODE_L1Z) return (nex<2)?-1:NFREQ+1; } else if (sys==SYS_CMP) { if (strstr(opt,"-CL1P")&&idx==0) return (code==CODE_L1P)?0:-1; if (strstr(opt,"-CL7D")&&idx==0) return (code==CODE_L7D)?0:-1; if (code==CODE_L1P) return (nex<1)?-1:NFREQ; if (code==CODE_L7D) return (nex<2)?-1:NFREQ+1; } return idxbuff+OEM4HLEN; char *q; double psr,adr,adr_rolls,lockt,tt,dop,snr,freq,glo_bias=0.0; int i,index,nobs,prn,sat,sys,code,idx,track,plock,clock,parity,halfc,lli; if ((q=strstr(raw->opt,"-GLOBIAS="))) sscanf(q,"-GLOBIAS=%lf",&glo_bias); nobs=U4(p); if (raw->lenlen,nobs); return -1; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," nobs=%d",nobs); } for (i=0,p+=4;i=MINPRNQZS_S&&prn<=MAXPRNQZS_S&&code==CODE_L1C) { sys=SYS_QZS; prn+=10; code=CODE_L1Z; /* QZS L1S */ } if (!(sat=satno(sys,prn))) { trace(3,"oem4 rangecmpb satellite number error: sys=%d,prn=%d\n",sys,prn); continue; } if (sys==SYS_GLO&&!parity) continue; /* invalid if GLO parity unknown */ if ((idx=checkpri(raw->opt,sys,code,idx))<0) continue; dop=exsign(U4(p+4)&0xFFFFFFF,28)/256.0; psr=(U4(p+7)>>4)/128.0+U1(p+11)*2097152.0; if ((freq=sat2freq(sat,(uint8_t)code,&raw->nav))!=0.0) { adr=I4(p+12)/256.0; adr_rolls=(psr*freq/CLIGHT+adr)/MAXVAL; adr=-adr+MAXVAL*floor(adr_rolls+(adr_rolls<=0?-0.5:0.5)); if (sys==SYS_GLO) adr+=glo_bias*freq/CLIGHT; } else { adr=1e-9; } lockt=(U4(p+18)&0x1FFFFF)/32.0; /* lock time */ if (raw->tobs[sat-1][idx].time!=0) { tt=timediff(raw->time,raw->tobs[sat-1][idx]); lli=(lockt<65535.968&&lockt-raw->lockt[sat-1][idx]+0.05<=tt)?LLI_SLIP:0; } else { lli=0; } if (!parity) lli|=LLI_HALFC; if (halfc ) lli|=LLI_HALFA; raw->tobs [sat-1][idx]=raw->time; raw->lockt[sat-1][idx]=lockt; raw->halfc[sat-1][idx]=halfc; snr=((U2(p+20)&0x3FF)>>5)+20.0; if (!clock) psr=0.0; /* code unlock */ if (!plock) adr=dop=0.0; /* phase unlock */ if (fabs(timediff(raw->obs.data[0].time,raw->time))>1E-9) { raw->obs.n=0; } if ((index=obsindex(&raw->obs,raw->time,sat))>=0) { raw->obs.data[index].L [idx]=adr; raw->obs.data[index].P [idx]=psr; raw->obs.data[index].D [idx]=(float)dop; raw->obs.data[index].SNR[idx]=(uint16_t)(snr/SNR_UNIT+0.5); raw->obs.data[index].LLI[idx]=(uint8_t)lli; raw->obs.data[index].code[idx]=(uint8_t)code; } } return 1; } /* decode RANGEB -------------------------------------------------------------*/ static int decode_rangeb(raw_t *raw) { uint8_t *p=raw->buff+OEM4HLEN; char *q; double psr,adr,dop,snr,lockt,tt,freq,glo_bias=0.0; int i,index,nobs,prn,sat,sys,code,idx,track,plock,clock,parity,halfc,lli; int gfrq; if ((q=strstr(raw->opt,"-GLOBIAS="))) sscanf(q,"-GLOBIAS=%lf",&glo_bias); nobs=U4(p); if (raw->lenlen,nobs); return -1; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," nobs=%d",nobs); } for (i=0,p+=4;i=MINPRNQZS_S&&prn<=MAXPRNQZS_S&&code==CODE_L1C) { sys=SYS_QZS; prn+=10; code=CODE_L1Z; /* QZS L1S */ } if (!(sat=satno(sys,prn))) { trace(3,"oem4 rangeb satellite number error: sys=%d,prn=%d\n",sys,prn); continue; } if (sys==SYS_GLO&&!parity) continue; if ((idx=checkpri(raw->opt,sys,code,idx))<0) continue; gfrq =U2(p+ 2); /* GLONASS FCN+8 */ psr =R8(p+ 4); adr =R8(p+16); dop =R4(p+28); snr =R4(p+32); lockt=R4(p+36); if (sys==SYS_GLO) { freq=sat2freq(sat,(uint8_t)code,&raw->nav); adr-=glo_bias*freq/CLIGHT; if (!raw->nav.glo_fcn[prn-1]) { raw->nav.glo_fcn[prn-1]=gfrq; /* fcn+8 */ } } if (raw->tobs[sat-1][idx].time!=0) { tt=timediff(raw->time,raw->tobs[sat-1][idx]); lli=lockt-raw->lockt[sat-1][idx]+0.05<=tt?LLI_SLIP:0; } else { lli=0; } if (!parity) lli|=LLI_HALFC; if (halfc ) lli|=LLI_HALFA; raw->tobs [sat-1][idx]=raw->time; raw->lockt[sat-1][idx]=lockt; raw->halfc[sat-1][idx]=halfc; if (!clock) psr=0.0; /* code unlock */ if (!plock) adr=dop=0.0; /* phase unlock */ if (fabs(timediff(raw->obs.data[0].time,raw->time))>1E-9) { raw->obs.n=0; } if ((index=obsindex(&raw->obs,raw->time,sat))>=0) { raw->obs.data[index].L [idx]=-adr; raw->obs.data[index].P [idx]=psr; raw->obs.data[index].D [idx]=(float)dop; raw->obs.data[index].SNR[idx]=(uint16_t)(snr/SNR_UNIT+0.5); raw->obs.data[index].LLI[idx]=(uint8_t)lli; raw->obs.data[index].code[idx]=(uint8_t)code; } } return 1; } /* decode RAWEPHEMB ----------------------------------------------------------*/ static int decode_rawephemb(raw_t *raw) { eph_t eph={0}; uint8_t *p=raw->buff+OEM4HLEN,subframe[30*5]={0}; int prn,sat; if (raw->lenlen); return -1; } prn=U4(p); if (!(sat=satno(SYS_GPS,prn))) { trace(2,"oem4 rawephemb satellite number error: prn=%d\n",prn); return -1; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," prn=%d",prn); } memcpy(subframe,p+12,30*3); /* subframe 1-3 */ if (!decode_frame(subframe,&eph,NULL,NULL,NULL)) { trace(2,"oem4 rawephemb subframe error: prn=%d\n",prn); return -1; } if (!strstr(raw->opt,"-EPHALL")) { if (eph.iode==raw->nav.eph[sat-1].iode&& eph.iodc==raw->nav.eph[sat-1].iodc) return 0; } eph.sat=sat; raw->nav.eph[sat-1]=eph; raw->ephsat=sat; raw->ephset=0; return 2; } /* decode IONUTCB ------------------------------------------------------------*/ static int decode_ionutcb(raw_t *raw) { uint8_t *p=raw->buff+OEM4HLEN; int i; if (raw->lenlen); return -1; } for (i=0;i<8;i++) raw->nav.ion_gps[i]=R8(p+i*8); raw->nav.utc_gps[0]=R8(p+ 72); /* A0 */ raw->nav.utc_gps[1]=R8(p+ 80); /* A1 */ raw->nav.utc_gps[2]=U4(p+ 68); /* tot */ raw->nav.utc_gps[3]=U4(p+ 64); /* WNt */ raw->nav.utc_gps[4]=I4(p+ 96); /* dt_LS */ raw->nav.utc_gps[5]=U4(p+ 88); /* WN_LSF */ raw->nav.utc_gps[6]=U4(p+ 92); /* DN */ raw->nav.utc_gps[7]=I4(p+100); /* dt_LSF */ return 9; } /* decode RAWWAASFRAMEB ------------------------------------------------------*/ static int decode_rawwaasframeb(raw_t *raw) { uint8_t *p=raw->buff+OEM4HLEN; int prn; if (raw->lenlen); return -1; } prn=U4(p+4); if ((prnMAXPRNSBS)&&(prnMAXPRNQZS_S)) { return 0; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," prn=%d",prn); } raw->sbsmsg.tow=(int)time2gpst(raw->time,&raw->sbsmsg.week); raw->sbsmsg.prn=prn; memcpy(raw->sbsmsg.msg,p+12,29); raw->sbsmsg.msg[28]&=0xC0; return 3; } /* decode RAWSBASFRAMEB ------------------------------------------------------*/ static int decode_rawsbasframeb(raw_t *raw) { return decode_rawwaasframeb(raw); } /* decode GLOEPHEMERISB ------------------------------------------------------*/ static int decode_gloephemerisb(raw_t *raw) { uint8_t *p=raw->buff+OEM4HLEN; geph_t geph={0}; double tow,tof,toff; int prn,sat,week; if (raw->lenlen); return -1; } prn=U2(p)-37; if (!(sat=satno(SYS_GLO,prn))) { trace(2,"oem4 gloephemerisb prn error: prn=%d\n",prn); return -1; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," prn=%d",prn); } geph.frq =U2(p+ 2)+OFF_FRQNO; week =U2(p+ 6); tow =floor(U4(p+8)/1000.0+0.5); /* rounded to integer sec */ toff =U4(p+ 12); geph.iode =U4(p+ 20)&0x7F; geph.svh =(U4(p+24)<4)?0:1; /* 0:healthy,1:unhealthy */ geph.pos[0]=R8(p+ 28); geph.pos[1]=R8(p+ 36); geph.pos[2]=R8(p+ 44); geph.vel[0]=R8(p+ 52); geph.vel[1]=R8(p+ 60); geph.vel[2]=R8(p+ 68); geph.acc[0]=R8(p+ 76); geph.acc[1]=R8(p+ 84); geph.acc[2]=R8(p+ 92); geph.taun =R8(p+100); geph.dtaun =R8(p+108); geph.gamn =R8(p+116); tof =U4(p+124)-toff; /* glonasst->gpst */ geph.age =U4(p+136); geph.toe=gpst2time(week,tow); tof+=floor(tow/86400.0)*86400; if (toftow+43200.0) tof-=86400.0; geph.tof=gpst2time(week,tof); if (!strstr(raw->opt,"-EPHALL")) { if (fabs(timediff(geph.toe,raw->nav.geph[prn-1].toe))<1.0&& geph.svh==raw->nav.geph[prn-1].svh) return 0; /* unchanged */ } geph.sat=sat; raw->nav.geph[prn-1]=geph; raw->ephsat=sat; raw->ephset=0; return 2; } /* decode QZSSRAWEPHEMB ------------------------------------------------------*/ static int decode_qzssrawephemb(raw_t *raw) { eph_t eph={0}; uint8_t *p=raw->buff+OEM4HLEN,subfrm[90]; int prn,sat; if (raw->lenlen); return -1; } prn=U4(p); if (!(sat=satno(SYS_QZS,prn))) { trace(2,"oem4 qzssrawephemb satellite number error: prn=%d\n",prn); return -1; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," prn=%d",prn); } memcpy(subfrm,p+12,90); if (!decode_frame(subfrm,&eph,NULL,NULL,NULL)) { trace(3,"oem4 qzssrawephemb ephemeris error: prn=%d\n",prn); return 0; } if (!strstr(raw->opt,"-EPHALL")) { if (eph.iodc==raw->nav.eph[sat-1].iodc&& eph.iode==raw->nav.eph[sat-1].iode) return 0; /* unchanged */ } eph.sat=sat; raw->nav.eph[sat-1]=eph; raw->ephsat=sat; raw->ephset=0; return 2; } /* decode QZSSRAWSUBFRAMEB ---------------------------------------------------*/ static int decode_qzssrawsubframeb(raw_t *raw) { eph_t eph={0}; double ion[8],utc[8]; uint8_t *p=raw->buff+OEM4HLEN; int prn,sat,id; if (raw->lenlen); return -1; } prn=U4(p); id =U4(p+4); if (!(sat=satno(SYS_QZS,prn))) { trace(2,"oem4 qzssrawsubframeb satellite error: prn=%d\n",prn); return -1; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," prn=%d id=%d",prn,id); } if (id<1||id>5) { trace(2,"oem4 qzssrawsubframeb subfrm id error: prn=%d id=%d\n",prn,id); return -1; } memcpy(raw->subfrm[sat-1]+30*(id-1),p+8,30); if (id==3) { if (!decode_frame(raw->subfrm[sat-1],&eph,NULL,NULL,NULL)) return 0; if (!strstr(raw->opt,"-EPHALL")) { if (eph.iodc==raw->nav.eph[sat-1].iodc&& eph.iode==raw->nav.eph[sat-1].iode) return 0; /* unchanged */ } eph.sat=sat; raw->nav.eph[sat-1]=eph; raw->ephsat=sat; raw->ephset=0; return 2; } else if (id==4||id==5) { if (!decode_frame(raw->subfrm[sat-1],NULL,NULL,ion,utc)) return 0; adj_utcweek(raw->time,utc); matcpy(raw->nav.ion_qzs,ion,8,1); matcpy(raw->nav.utc_qzs,utc,8,1); return 9; } return 0; } /* decode QZSSIONUTCB --------------------------------------------------------*/ static int decode_qzssionutcb(raw_t *raw) { uint8_t *p=raw->buff+OEM4HLEN; int i; if (raw->lenlen); return -1; } for (i=0;i<8;i++) raw->nav.ion_qzs[i]=R8(p+i*8); raw->nav.utc_qzs[0]=R8(p+72); raw->nav.utc_qzs[1]=R8(p+80); raw->nav.utc_qzs[2]=U4(p+68); raw->nav.utc_qzs[3]=U4(p+64); raw->nav.utc_qzs[4]=I4(p+96); return 9; } /* decode GALEPHEMERISB ------------------------------------------------------*/ static int decode_galephemerisb(raw_t *raw) { eph_t eph={0}; uint8_t *p=raw->buff+OEM4HLEN; double tow,sqrtA,af0_fnav,af1_fnav,af2_fnav,af0_inav,af1_inav,af2_inav,tt; int prn,sat,week,rcv_fnav,rcv_inav,svh_e1b,svh_e5a,svh_e5b,dvs_e1b,dvs_e5a; int dvs_e5b,toc_fnav,toc_inav,set,sel_eph=3; /* 1:I/NAV+2:F/NAV */ if (strstr(raw->opt,"-GALINAV")) sel_eph=1; if (strstr(raw->opt,"-GALFNAV")) sel_eph=2; if (raw->lenlen); return -1; } prn =U4(p); p+=4; rcv_fnav =U4(p)&1; p+=4; rcv_inav =U4(p)&1; p+=4; svh_e1b =U1(p)&3; p+=1; svh_e5a =U1(p)&3; p+=1; svh_e5b =U1(p)&3; p+=1; dvs_e1b =U1(p)&1; p+=1; dvs_e5a =U1(p)&1; p+=1; dvs_e5b =U1(p)&1; p+=1; eph.sva =U1(p); p+=1+1; /* SISA index */ eph.iode =U4(p); p+=4; /* IODNav */ eph.toes =U4(p); p+=4; sqrtA =R8(p); p+=8; eph.deln =R8(p); p+=8; eph.M0 =R8(p); p+=8; eph.e =R8(p); p+=8; eph.omg =R8(p); p+=8; eph.cuc =R8(p); p+=8; eph.cus =R8(p); p+=8; eph.crc =R8(p); p+=8; eph.crs =R8(p); p+=8; eph.cic =R8(p); p+=8; eph.cis =R8(p); p+=8; eph.i0 =R8(p); p+=8; eph.idot =R8(p); p+=8; eph.OMG0 =R8(p); p+=8; eph.OMGd =R8(p); p+=8; toc_fnav =U4(p); p+=4; af0_fnav =R8(p); p+=8; af1_fnav =R8(p); p+=8; af2_fnav =R8(p); p+=8; toc_inav =U4(p); p+=4; af0_inav =R8(p); p+=8; af1_inav =R8(p); p+=8; af2_inav =R8(p); p+=8; eph.tgd[0]=R8(p); p+=8; /* BGD: E5A-E1 (s) */ eph.tgd[1]=R8(p); /* BGD: E5B-E1 (s) */ if (!(sat=satno(SYS_GAL,prn))) { trace(2,"oemv galephemeris satellite error: prn=%d\n",prn); return -1; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," prn=%d",prn); } set=rcv_fnav?1:0; /* 0:I/NAV,1:F/NAV */ if (!(sel_eph&1)&&set==0) return 0; if (!(sel_eph&2)&&set==1) return 0; eph.sat =sat; eph.A =SQR(sqrtA); eph.f0 =set?af0_fnav:af0_inav; eph.f1 =set?af1_fnav:af1_inav; eph.f2 =set?af2_fnav:af2_inav; eph.svh =((svh_e5b<<7)|(dvs_e5b<<6)|(svh_e5a<<4)|(dvs_e5a<<3)| (svh_e1b<<1)|dvs_e1b); eph.code=set?((1<<1)+(1<<8)):((1<<0)+(1<<2)+(1<<9)); eph.iodc=eph.iode; tow=time2gpst(raw->time,&week); eph.week=week; /* gps-week = gal-week */ eph.toe=gpst2time(eph.week,eph.toes); tt=timediff(eph.toe,raw->time); if (tt<-302400.0) eph.week++; else if (tt> 302400.0) eph.week--; eph.toe=gpst2time(eph.week,eph.toes); eph.toc=adjweek(raw->time,set?toc_fnav:toc_inav); eph.ttr=raw->time; if (!strstr(raw->opt,"-EPHALL")) { if (eph.iode==raw->nav.eph[sat-1+MAXSAT*set].iode&& timediff(eph.toe,raw->nav.eph[sat-1+MAXSAT*set].toe)==0.0&& timediff(eph.toc,raw->nav.eph[sat-1+MAXSAT*set].toc)==0.0) { return 0; /* unchanged */ } } raw->nav.eph[sat-1+MAXSAT*set]=eph; raw->ephsat=sat; raw->ephset=set; return 2; } /* decode GALCLOCKB ----------------------------------------------------------*/ static int decode_galclockb(raw_t *raw) { uint8_t *p=raw->buff+OEM4HLEN; double a0,a1,a0g,a1g; int dtls,tot,wnt,wnlsf,dn,dtlsf,t0g,wn0g; if (raw->lenlen); return -1; } a0 =R8(p); p+=8; a1 =R8(p); p+=8; dtls =I4(p); p+=4; tot =U4(p); p+=4; wnt =U4(p); p+=4; wnlsf=U4(p); p+=4; dn =U4(p); p+=4; dtlsf=U4(p); p+=4; a0g =R8(p); p+=8; a1g =R8(p); p+=8; t0g =U4(p); p+=4; wn0g =U4(p); raw->nav.utc_gal[0]=a0; raw->nav.utc_gal[1]=a1; raw->nav.utc_gal[2]=tot; raw->nav.utc_gal[3]=wnt; raw->nav.utc_gal[4]=dtls; raw->nav.utc_gal[5]=wnlsf; raw->nav.utc_gal[6]=dn; raw->nav.utc_gal[7]=dtlsf; return 9; } /* decode GALIONOB -----------------------------------------------------------*/ static int decode_galionob(raw_t *raw) { uint8_t *p=raw->buff+OEM4HLEN; double ai[3]; int i,sf[5]; if (raw->lenlen); return -1; } ai[0]=R8(p); p+=8; ai[1]=R8(p); p+=8; ai[2]=R8(p); p+=8; sf[0]=U1(p); p+=1; sf[1]=U1(p); p+=1; sf[2]=U1(p); p+=1; sf[3]=U1(p); p+=1; sf[4]=U1(p); for (i=0;i<3;i++) raw->nav.ion_gal[i]=ai[i]; return 9; } /* decode BDSEPHEMERISB ------------------------------------------------------*/ static int decode_bdsephemerisb(raw_t *raw) { eph_t eph={0}; uint8_t *p=raw->buff+OEM4HLEN; double ura,sqrtA; int prn,sat,toc; if (raw->lenlen); return -1; } prn =U4(p); p+=4; eph.week =U4(p); p+=4; ura =R8(p); p+=8; eph.svh =U4(p)&1; p+=4; eph.tgd[0]=R8(p); p+=8; /* TGD1 for B1 (s) */ eph.tgd[1]=R8(p); p+=8; /* TGD2 for B2 (s) */ eph.iodc =U4(p); p+=4; /* AODC */ toc =U4(p); p+=4; eph.f0 =R8(p); p+=8; eph.f1 =R8(p); p+=8; eph.f2 =R8(p); p+=8; eph.iode =U4(p); p+=4; /* AODE */ eph.toes =U4(p); p+=4; sqrtA =R8(p); p+=8; eph.e =R8(p); p+=8; eph.omg =R8(p); p+=8; eph.deln =R8(p); p+=8; eph.M0 =R8(p); p+=8; eph.OMG0 =R8(p); p+=8; eph.OMGd =R8(p); p+=8; eph.i0 =R8(p); p+=8; eph.idot =R8(p); p+=8; eph.cuc =R8(p); p+=8; eph.cus =R8(p); p+=8; eph.crc =R8(p); p+=8; eph.crs =R8(p); p+=8; eph.cic =R8(p); p+=8; eph.cis =R8(p); if (!(sat=satno(SYS_CMP,prn))) { trace(2,"oemv bdsephemeris satellite error: prn=%d\n",prn); return -1; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," prn=%d",prn); } eph.sat=sat; eph.A =SQR(sqrtA); eph.sva=uraindex(ura); eph.toe=bdt2gpst(bdt2time(eph.week,eph.toes)); /* bdt -> gpst */ eph.toc=bdt2gpst(bdt2time(eph.week,toc)); /* bdt -> gpst */ eph.ttr=raw->time; if (!strstr(raw->opt,"-EPHALL")) { if (timediff(raw->nav.eph[sat-1].toe,eph.toe)==0.0&& timediff(raw->nav.eph[sat-1].toc,eph.toc)==0.0) return 0; } raw->nav.eph[sat-1]=eph; raw->ephsat=sat; raw->ephset=0; return 2; } /* decode NAVICEPHEMERISB ----------------------------------------------------*/ static int decode_navicephemerisb(raw_t *raw) { eph_t eph={0}; uint8_t *p=raw->buff+OEM4HLEN; double sqrtA; int prn,sat,toc,rsv,l5_health,s_health,alert,autonav; if (raw->lenlen); return -1; } prn =U4(p); p+=4; eph.week =U4(p); p+=4; eph.f0 =R8(p); p+=8; eph.f1 =R8(p); p+=8; eph.f2 =R8(p); p+=8; eph.sva =U4(p); p+=4; /* URA index */ toc =U4(p); p+=4; eph.tgd[0]=R8(p); p+=8; /* TGD */ eph.deln =R8(p); p+=8; eph.iode =U4(p); p+=4; /* IODEC */ rsv =U4(p); p+=4; l5_health =U4(p)&1; p+=4; s_health =U4(p)&1; p+=4; eph.cuc =R8(p); p+=8; eph.cus =R8(p); p+=8; eph.cic =R8(p); p+=8; eph.cis =R8(p); p+=8; eph.crc =R8(p); p+=8; eph.crs =R8(p); p+=8; eph.idot =R8(p); p+=8; rsv =U4(p); p+=4; eph.M0 =R8(p); p+=8; eph.toes =U4(p); p+=4; eph.e =R8(p); p+=8; sqrtA =R8(p); p+=8; eph.OMG0 =R8(p); p+=8; eph.omg =R8(p); p+=8; eph.OMGd =R8(p); p+=8; eph.i0 =R8(p); p+=8; rsv =U4(p); p+=4; alert =U4(p); p+=4; autonav =U4(p); if (toc!=eph.toes) { /* toe and toc should be matched */ trace(2,"oem4 navicephemrisb toe and toc unmatch prn=%d\n",prn); return -1; } if (!(sat=satno(SYS_IRN,prn))) { trace(2,"oemv navicephemeris satellite error: prn=%d\n",prn); return 0; } if (raw->outtype) { sprintf(raw->msgtype+strlen(raw->msgtype)," prn=%d",prn); } eph.sat =sat; eph.A =SQR(sqrtA); eph.svh =(l5_health<<1)|s_health; eph.iodc=eph.iode; eph.week+=1024; /* irnss-week -> gps-week */ eph.toe=gpst2time(eph.week,eph.toes); eph.toc=gpst2time(eph.week,toc); eph.ttr=raw->time; eph.tgd[1]=0.0; if (!strstr(raw->opt,"-EPHALL")) { if (timediff(raw->nav.eph[sat-1].toe,eph.toe)==0.0&& raw->nav.eph[sat-1].iode==eph.iode) return 0; /* unchanged */ } raw->nav.eph[sat-1]=eph; raw->ephsat=sat; raw->ephset=0; return 2; } /* decode RGEB ---------------------------------------------------------------*/ static int decode_rgeb(raw_t *raw) { uint8_t *p=raw->buff+OEM3HLEN; double tow,psr,adr,tt,lockt,dop,snr; int i,week,nobs,prn,sat,stat,sys,parity,lli,index,freq; week=adjgpsweek(U4(p)); tow =R8(p+ 4); nobs=U4(p+12); raw->time=gpst2time(week,tow); if (raw->len!=OEM3HLEN+20+nobs*44) { trace(2,"oem3 regb length error: len=%d nobs=%d\n",raw->len,nobs); return -1; } for (i=0,p+=20;i>20)&1; /* L1:0,L2:1 */ sys =(stat>>15)&7; /* satellite sys (0:GPS,1:GLONASS,2:WAAS) */ parity=(stat>>10)&1; /* parity known */ if (!(sat=satno(sys==1?SYS_GLO:(sys==2?SYS_SBS:SYS_GPS),prn))) { trace(2,"oem3 regb satellite number error: sys=%d prn=%d\n",sys,prn); continue; } if (raw->tobs[sat-1][freq].time!=0) { tt=timediff(raw->time,raw->tobs[sat-1][freq]); lli=lockt-raw->lockt[sat-1][freq]+0.05halfc[sat-1][freq]; } else { lli=0; } if (!parity) lli|=2; raw->tobs [sat-1][freq]=raw->time; raw->lockt[sat-1][freq]=lockt; raw->halfc[sat-1][freq]=parity; if (fabs(timediff(raw->obs.data[0].time,raw->time))>1E-9) { raw->obs.n=0; } if ((index=obsindex(&raw->obs,raw->time,sat))>=0) { raw->obs.data[index].L [freq]=-adr; /* flip sign */ raw->obs.data[index].P [freq]=psr; raw->obs.data[index].D [freq]=(float)dop; raw->obs.data[index].SNR[freq]= 0.0<=snr&&snr<255.0?(uint16_t)(snr/SNR_UNIT+0.5):0; raw->obs.data[index].LLI[freq]=(uint8_t)lli; raw->obs.data[index].code[freq]=freq==0?CODE_L1C:CODE_L2P; } } return 1; } /* decode RGED ---------------------------------------------------------------*/ static int decode_rged(raw_t *raw) { uint32_t word; uint8_t *p=raw->buff+OEM3HLEN; double tow,psrh,psrl,psr,adr,adr_rolls,tt,lockt,dop; int i,week,nobs,prn,sat,stat,sys,parity,lli,index,freq,snr; nobs=U2(p); week=adjgpsweek(U2(p+2)); tow =U4(p+4)/100.0; raw->time=gpst2time(week,tow); if (raw->len!=OEM3HLEN+12+nobs*20) { trace(2,"oem3 regd length error: len=%d nobs=%d\n",raw->len,nobs); return -1; } for (i=0,p+=12;i>6)&0x1F)+20; lockt =(word>>11)/32.0; adr =-I4(p+4)/256.0; word =U4(p+8); psrh =word&0xF; dop =exsign(word>>4,28)/256.0; psrl =U4(p+12); stat =U4(p+16)>>8; freq =(stat>>20)&1; /* L1:0,L2:1 */ sys =(stat>>15)&7; /* satellite sys (0:GPS,1:GLONASS,2:WAAS) */ parity=(stat>>10)&1; /* parity known */ if (!(sat=satno(sys==1?SYS_GLO:(sys==2?SYS_SBS:SYS_GPS),prn))) { trace(2,"oem3 regd satellite number error: sys=%d prn=%d\n",sys,prn); continue; } psr=(psrh*4294967296.0+psrl)/128.0; adr_rolls=floor((psr/(freq==0?WL1:WL2)-adr)/MAXVAL+0.5); adr=adr+MAXVAL*adr_rolls; if (raw->tobs[sat-1][freq].time!=0) { tt=timediff(raw->time,raw->tobs[sat-1][freq]); lli=lockt-raw->lockt[sat-1][freq]+0.05halfc[sat-1][freq]; } else { lli=0; } if (!parity) lli|=2; raw->tobs [sat-1][freq]=raw->time; raw->lockt[sat-1][freq]=lockt; raw->halfc[sat-1][freq]=parity; if (fabs(timediff(raw->obs.data[0].time,raw->time))>1E-9) { raw->obs.n=0; } if ((index=obsindex(&raw->obs,raw->time,sat))>=0) { raw->obs.data[index].L [freq]=adr; raw->obs.data[index].P [freq]=psr; raw->obs.data[index].D [freq]=(float)dop; raw->obs.data[index].SNR[freq]=(uint16_t)(snr/SNR_UNIT+0.5); raw->obs.data[index].LLI[freq]=(uint8_t)lli; raw->obs.data[index].code[freq]=freq==0?CODE_L1C:CODE_L2P; } } return 1; } /* decode REPB ---------------------------------------------------------------*/ static int decode_repb(raw_t *raw) { uint8_t *p=raw->buff+OEM3HLEN; eph_t eph={0}; int prn,sat; if (raw->len!=OEM3HLEN+96) { trace(2,"oem3 repb length error: len=%d\n",raw->len); return -1; } prn=U4(p); if (!(sat=satno(SYS_GPS,prn))) { trace(2,"oem3 repb satellite number error: prn=%d\n",prn); return -1; } if (!decode_frame(p+4,&eph,NULL,NULL,NULL)) { trace(2,"oem3 repb subframe error: prn=%d\n",prn); return -1; } if (!strstr(raw->opt,"-EPHALL")) { if (eph.iode==raw->nav.eph[sat-1].iode) return 0; /* unchanged */ } eph.sat=sat; raw->nav.eph[sat-1]=eph; raw->ephsat=sat; raw->ephset=0; return 2; } /* decode FRMB --------------------------------------------------------------*/ static int decode_frmb(raw_t *raw) { uint8_t *p=raw->buff+OEM3HLEN; double tow; int i,week,prn,nbit; trace(3,"decode_frmb: len=%d\n",raw->len); week=adjgpsweek(U4(p)); tow =R8(p+ 4); prn =U4(p+12); nbit=U4(p+20); raw->time=gpst2time(week,tow); if (nbit!=250) return 0; if (prnsbsmsg.week=week; raw->sbsmsg.tow=(int)tow; raw->sbsmsg.prn=prn; for (i=0;i<29;i++) raw->sbsmsg.msg[i]=p[24+i]; return 3; } /* decode IONB ---------------------------------------------------------------*/ static int decode_ionb(raw_t *raw) { uint8_t *p=raw->buff+OEM3HLEN; int i; if (raw->len!=64+OEM3HLEN) { trace(2,"oem3 ionb length error: len=%d\n",raw->len); return -1; } for (i=0;i<8;i++) raw->nav.ion_gps[i]=R8(p+i*8); return 9; } /* decode UTCB ---------------------------------------------------------------*/ static int decode_utcb(raw_t *raw) { uint8_t *p=raw->buff+OEM3HLEN; if (raw->len!=40+OEM3HLEN) { trace(2,"oem3 utcb length error: len=%d\n",raw->len); return -1; } raw->nav.utc_gps[0]=R8(p ); raw->nav.utc_gps[1]=R8(p+ 8); raw->nav.utc_gps[2]=U4(p+16); raw->nav.utc_gps[3]=adjgpsweek(U4(p+20)); raw->nav.utc_gps[4]=I4(p+28); return 9; } /* decode NovAtel OEM4/V/6/7 message -----------------------------------------*/ static int decode_oem4(raw_t *raw) { double tow; char tstr[32]; int msg,stat,week,type=U2(raw->buff+4); trace(3,"decode_oem4: type=%3d len=%d\n",type,raw->len); /* check crc32 */ if (rtk_crc32(raw->buff,raw->len)!=U4(raw->buff+raw->len)) { trace(2,"oem4 crc error: type=%3d len=%d\n",type,raw->len); return -1; } msg =(U1(raw->buff+6)>>4)&0x3; /* message type: 0=binary,1=ascii */ stat=U1(raw->buff+13); week=U2(raw->buff+14); if (stat==20||week==0) { trace(3,"oem4 time error: type=%3d msg=%d stat=%d week=%d\n",type,msg, stat,week); return 0; } week=adjgpsweek(week); tow =U4(raw->buff+16)*0.001; raw->time=gpst2time(week,tow); if (msg!=0) return 0; if (raw->outtype) { time2str(gpst2time(week,tow),tstr,2); sprintf(raw->msgtype,"OEM4 %4d (%4d): %s",type,raw->len,tstr); } switch (type) { case ID_RANGECMP : return decode_rangecmpb (raw); case ID_RANGE : return decode_rangeb (raw); case ID_RAWEPHEM : return decode_rawephemb (raw); case ID_IONUTC : return decode_ionutcb (raw); case ID_RAWWAASFRAME : return decode_rawwaasframeb (raw); case ID_RAWSBASFRAME : return decode_rawsbasframeb (raw); case ID_GLOEPHEMERIS : return decode_gloephemerisb (raw); case ID_GALEPHEMERIS : return decode_galephemerisb (raw); case ID_GALIONO : return decode_galionob (raw); case ID_GALCLOCK : return decode_galclockb (raw); case ID_QZSSRAWEPHEM : return decode_qzssrawephemb (raw); case ID_QZSSRAWSUBFRAME: return decode_qzssrawsubframeb(raw); case ID_QZSSIONUTC : return decode_qzssionutcb (raw); case ID_BDSEPHEMERIS : return decode_bdsephemerisb (raw); case ID_NAVICEPHEMERIS : return decode_navicephemerisb (raw); } return 0; } /* decode NovAtel OEM3 message -----------------------------------------------*/ static int decode_oem3(raw_t *raw) { int type=U4(raw->buff+4); trace(3,"decode_oem3: type=%3d len=%d\n",type,raw->len); /* checksum */ if (chksum(raw->buff,raw->len)) { trace(2,"oem3 checksum error: type=%3d len=%d\n",type,raw->len); return -1; } if (raw->outtype) { sprintf(raw->msgtype,"OEM3 %4d (%4d):",type,raw->len); } switch (type) { case ID_RGEB: return decode_rgeb(raw); case ID_RGED: return decode_rged(raw); case ID_REPB: return decode_repb(raw); case ID_FRMB: return decode_frmb(raw); case ID_IONB: return decode_ionb(raw); case ID_UTCB: return decode_utcb(raw); } return 0; } /* sync header ---------------------------------------------------------------*/ static int sync_oem4(uint8_t *buff, uint8_t data) { buff[0]=buff[1]; buff[1]=buff[2]; buff[2]=data; return buff[0]==OEM4SYNC1&&buff[1]==OEM4SYNC2&&buff[2]==OEM4SYNC3; } static int sync_oem3(uint8_t *buff, uint8_t data) { buff[0]=buff[1]; buff[1]=buff[2]; buff[2]=data; return buff[0]==OEM3SYNC1&&buff[1]==OEM3SYNC2&&buff[2]==OEM3SYNC3; } /* input NovAtel OEM4/V/6/7 raw data from stream ------------------------------- * fetch next NovAtel OEM4/V/6/7 raw data and input a mesasge from stream * args : raw_t *raw IO receiver raw data control struct * uint8_t data I stream data (1 byte) * return : status (-1: error message, 0: no message, 1: input observation data, * 2: input ephemeris, 3: input sbas message, * 9: input ion/utc parameter) * * notes : to specify input options for oem4, set raw->opt to the following * option strings separated by spaces. * * -EPHALL : input all ephemerides * -GL1L : select 1L for GPS L1 (default 1C) * -GL2S : select 2S for GPS L2 (default 2W) * -GL2P : select 2P for GPS L2 (default 2W) * -RL2C : select 2C for GLO G2 (default 2P) * -EL6B : select 6B for GAL E6 (default 6C) * -JL1L : select 1L for QZS L1 (default 1C) * -JL1Z : select 1Z for QZS L1 (default 1C) * -CL1P : select 1P for BDS B1 (default 2I) * -CL7D : select 7D for BDS B2 (default 7I) * -GALINAV: select I/NAV for Galileo ephemeris (default: all) * -GALFNAV: select F/NAV for Galileo ephemeris (default: all) * -GLOBIAS=bias: GLONASS code-phase bias (m) *-----------------------------------------------------------------------------*/ extern int input_oem4(raw_t *raw, uint8_t data) { trace(5,"input_oem4: data=%02x\n",data); /* synchronize frame */ if (raw->nbyte==0) { if (sync_oem4(raw->buff,data)) raw->nbyte=3; return 0; } raw->buff[raw->nbyte++]=data; if (raw->nbyte==10&&(raw->len=U2(raw->buff+8)+OEM4HLEN)>MAXRAWLEN-4) { trace(2,"oem4 length error: len=%d\n",raw->len); raw->nbyte=0; return -1; } if (raw->nbyte<10||raw->nbytelen+4) return 0; raw->nbyte=0; /* decode oem7/6/4 message */ return decode_oem4(raw); } /* input NovAtel OEM3 raw data from stream ------------------------------------- * fetch next NovAtel OEM3 raw data and input a mesasge from stream * args : raw_t *raw IO receiver raw data control struct * uint8_t data I stream data (1 byte) * return : same as above *-----------------------------------------------------------------------------*/ extern int input_oem3(raw_t *raw, uint8_t data) { trace(5,"input_oem3: data=%02x\n",data); /* synchronize frame */ if (raw->nbyte==0) { if (sync_oem3(raw->buff,data)) raw->nbyte=3; return 0; } raw->buff[raw->nbyte++]=data; if (raw->nbyte==12&&(raw->len=U4(raw->buff+8))>MAXRAWLEN) { trace(2,"oem3 length error: len=%d\n",raw->len); raw->nbyte=0; return -1; } if (raw->nbyte<12||raw->nbytelen) return 0; raw->nbyte=0; /* decode oem3 message */ return decode_oem3(raw); } /* input NovAtel OEM4/V/6/7 raw data from file --------------------------------- * fetch next NovAtel OEM4/V/6/7 raw data and input a message from file * args : raw_t *raw IO receiver raw data control struct * FILE *fp I file pointer * return : status(-2: end of file, -1...9: same as above) *-----------------------------------------------------------------------------*/ extern int input_oem4f(raw_t *raw, FILE *fp) { int i,data; trace(4,"input_oem4f:\n"); /* synchronize frame */ if (raw->nbyte==0) { for (i=0;;i++) { if ((data=fgetc(fp))==EOF) return -2; if (sync_oem4(raw->buff,(uint8_t)data)) break; if (i>=4096) return 0; } } if (fread(raw->buff+3,7,1,fp)<1) return -2; raw->nbyte=10; if ((raw->len=U2(raw->buff+8)+OEM4HLEN)>MAXRAWLEN-4) { trace(2,"oem4 length error: len=%d\n",raw->len); raw->nbyte=0; return -1; } if (fread(raw->buff+10,raw->len-6,1,fp)<1) return -2; raw->nbyte=0; /* decode NovAtel OEM4/V/6/7 message */ return decode_oem4(raw); } /* input NovAtel OEM3 raw data from file --------------------------------------- * fetch next NovAtel OEM3 raw data and input a message from file * args : raw_t *raw IO receiver raw data control struct * FILE *fp I file pointer * return : status(-2: end of file, -1...9: same as above) *-----------------------------------------------------------------------------*/ extern int input_oem3f(raw_t *raw, FILE *fp) { int i,data; trace(4,"input_oem3f:\n"); /* synchronize frame */ if (raw->nbyte==0) { for (i=0;;i++) { if ((data=fgetc(fp))==EOF) return -2; if (sync_oem3(raw->buff,(uint8_t)data)) break; if (i>=4096) return 0; } } if (fread(raw->buff+3,1,9,fp)<9) return -2; raw->nbyte=12; if ((raw->len=U4(raw->buff+8))>MAXRAWLEN) { trace(2,"oem3 length error: len=%d\n",raw->len); raw->nbyte=0; return -1; } if (fread(raw->buff+12,1,raw->len-12,fp)<(size_t)(raw->len-12)) return -2; raw->nbyte=0; /* decode oem3 message */ return decode_oem3(raw); }