1496 lines
53 KiB
C
1496 lines
53 KiB
C
|
/*------------------------------------------------------------------------------
|
||
|
* 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<<bits):v);
|
||
|
}
|
||
|
/* checksum ------------------------------------------------------------------*/
|
||
|
static uint8_t chksum(const uint8_t *buff, int len)
|
||
|
{
|
||
|
uint8_t sum=0;
|
||
|
int i;
|
||
|
for (i=0;i<len;i++) sum^=buff[i];
|
||
|
return sum;
|
||
|
}
|
||
|
/* adjust weekly rollover of GPS time ----------------------------------------*/
|
||
|
static gtime_t adjweek(gtime_t time, double tow)
|
||
|
{
|
||
|
double tow_p;
|
||
|
int week;
|
||
|
tow_p=time2gpst(time,&week);
|
||
|
if (tow<tow_p-302400.0) tow+=604800.0;
|
||
|
else if (tow>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;
|
||
|
else 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;
|
||
|
else 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;i<obs->n;i++) {
|
||
|
if (obs->data[i].sat==sat) return i;
|
||
|
}
|
||
|
obs->data[i].time=time;
|
||
|
obs->data[i].sat=sat;
|
||
|
for (j=0;j<NFREQ+NEXOBS;j++) {
|
||
|
obs->data[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 idx<NFREQ?idx:-1;
|
||
|
}
|
||
|
/* decode RANGECMPB ----------------------------------------------------------*/
|
||
|
static int decode_rangecmpb(raw_t *raw)
|
||
|
{
|
||
|
uint8_t *p=raw->buff+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->len<OEM4HLEN+4+nobs*24) {
|
||
|
trace(2,"oem4 rangecmpb length error: len=%d nobs=%d\n",raw->len,nobs);
|
||
|
return -1;
|
||
|
}
|
||
|
if (raw->outtype) {
|
||
|
sprintf(raw->msgtype+strlen(raw->msgtype)," nobs=%d",nobs);
|
||
|
}
|
||
|
for (i=0,p+=4;i<nobs;i++,p+=24) {
|
||
|
if ((idx=decode_track_stat(U4(p),&sys,&code,&track,&plock,&clock,
|
||
|
&parity,&halfc))<0) {
|
||
|
continue;
|
||
|
}
|
||
|
prn=U1(p+17);
|
||
|
if (sys==SYS_GLO) prn-=37;
|
||
|
if (sys==SYS_SBS&&prn>=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->len<OEM4HLEN+4+nobs*44) {
|
||
|
trace(2,"oem4 rangeb length error: len=%d nobs=%d\n",raw->len,nobs);
|
||
|
return -1;
|
||
|
}
|
||
|
if (raw->outtype) {
|
||
|
sprintf(raw->msgtype+strlen(raw->msgtype)," nobs=%d",nobs);
|
||
|
}
|
||
|
for (i=0,p+=4;i<nobs;i++,p+=44) {
|
||
|
if ((idx=decode_track_stat(U4(p+40),&sys,&code,&track,&plock,&clock,
|
||
|
&parity,&halfc))<0) {
|
||
|
continue;
|
||
|
}
|
||
|
prn=U2(p);
|
||
|
if (sys==SYS_GLO) prn-=37;
|
||
|
if (sys==SYS_SBS&&prn>=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->len<OEM4HLEN+102) {
|
||
|
trace(2,"oem4 rawephemb length error: len=%d\n",raw->len);
|
||
|
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->len<OEM4HLEN+108) {
|
||
|
trace(2,"oem4 ionutcb length error: len=%d\n",raw->len);
|
||
|
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->len<OEM4HLEN+48) {
|
||
|
trace(2,"oem4 rawwaasframeb length error: len=%d\n",raw->len);
|
||
|
return -1;
|
||
|
}
|
||
|
prn=U4(p+4);
|
||
|
if ((prn<MINPRNSBS||prn>MAXPRNSBS)&&(prn<MINPRNQZS_S||prn>MAXPRNQZS_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->len<OEM4HLEN+144) {
|
||
|
trace(2,"oem4 gloephemerisb length error: len=%d\n",raw->len);
|
||
|
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 (tof<tow-43200.0) tof+=86400.0;
|
||
|
else if (tof>tow+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->len<OEM4HLEN+106) {
|
||
|
trace(2,"oem4 qzssrawephemb length error: len=%d\n",raw->len);
|
||
|
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->len<OEM4HLEN+44) {
|
||
|
trace(2,"oem4 qzssrawsubframeb length error: len=%d\n",raw->len);
|
||
|
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->len<OEM4HLEN+108) {
|
||
|
trace(2,"oem4 qzssionutcb length error: len=%d\n",raw->len);
|
||
|
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->len<OEM4HLEN+220) {
|
||
|
trace(2,"oem4 galephemrisb length error: len=%d\n",raw->len);
|
||
|
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->len<OEM4HLEN+64) {
|
||
|
trace(2,"oem4 galclockb length error: len=%d\n",raw->len);
|
||
|
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->len<OEM4HLEN+29) {
|
||
|
trace(2,"oem4 galionob length error: len=%d\n",raw->len);
|
||
|
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->len<OEM4HLEN+196) {
|
||
|
trace(2,"oem4 bdsephemrisb length error: len=%d\n",raw->len);
|
||
|
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->len<OEM4HLEN+204) {
|
||
|
trace(2,"oem4 navicephemrisb length error: len=%d\n",raw->len);
|
||
|
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<nobs;i++,p+=44) {
|
||
|
prn =U4(p );
|
||
|
psr =R8(p+ 4);
|
||
|
adr =R8(p+16);
|
||
|
dop =R4(p+28);
|
||
|
snr =R4(p+32);
|
||
|
lockt =R4(p+36); /* lock time (s) */
|
||
|
stat =I4(p+40); /* tracking status */
|
||
|
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 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.05<tt||
|
||
|
parity!=raw->halfc[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<nobs;i++,p+=20) {
|
||
|
word =U4(p);
|
||
|
prn =word&0x3F;
|
||
|
snr =((word>>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.05<tt||
|
||
|
parity!=raw->halfc[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 (prn<MINPRNSBS||MAXPRNSBS<prn) {
|
||
|
trace(2,"oem3 frmb satellite number error: prn=%d\n",prn);
|
||
|
return -1;
|
||
|
}
|
||
|
raw->sbsmsg.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->nbyte<raw->len+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->nbyte<raw->len) 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);
|
||
|
}
|