/*!
* \file rtklib_rtcm2.cc
* \brief RTCM functions for v2
* \authors
* - 2007-2013, T. Takasu
*
- 2017, Javier Arribas
*
- 2017, Carles Fernandez
*
*
* This is a derived work from RTKLIB http://www.rtklib.com/
* The original source code at https://github.com/tomojitakasu/RTKLIB is
* released under the BSD 2-clause license with an additional exclusive clause
* that does not apply here. This additional clause is reproduced below:
*
* " The software package includes some companion executive binaries or shared
* libraries necessary to execute APs on Windows. These licenses succeed to the
* original ones of these software. "
*
* Neither the executive binaries nor the shared libraries are required by, used
* or included in GNSS-SDR.
*
* -------------------------------------------------------------------------
* Copyright (C) 2007-2013, T. Takasu
* Copyright (C) 2017, Javier Arribas
* Copyright (C) 2017, Carles Fernandez
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*----------------------------------------------------------------------------*/
#include "rtklib_rtcm2.h"
#include "rtklib_rtcm3.h"
#include "rtklib_rtkcmn.h"
/* adjust hourly rollover of rtcm 2 time -------------------------------------*/
void adjhour(rtcm_t *rtcm, double zcnt)
{
double tow, hour, sec;
int week;
/* if no time, get cpu time */
if (rtcm->time.time == 0) rtcm->time = utc2gpst(timeget());
tow = time2gpst(rtcm->time, &week);
hour = floor(tow/3600.0);
sec = tow-hour*3600.0;
if (zcntsec+1800.0) zcnt-=3600.0;
rtcm->time = gpst2time(week, hour*3600+zcnt);
}
/* get observation data index ------------------------------------------------*/
int obsindex(obs_t *obs, gtime_t time, int sat)
{
int i, j;
for (i = 0; in; i++)
{
if (obs->data[i].sat == sat) return i; /* field already exists */
}
if (i >= MAXOBS) return -1; /* overflow */
/* add new field */
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] = obs->data[i].code[j] = 0;
}
obs->n++;
return i;
}
/* decode type 1/9: differential gps correction/partial correction set -------*/
int decode_type1(rtcm_t *rtcm)
{
int i = 48, fact, udre, prn, sat, iod;
double prc, rrc;
trace(4, "decode_type1: len=%d\n", rtcm->len);
while (i+40 <= rtcm->len*8)
{
fact = getbitu(rtcm->buff, i, 1); i += 1;
udre = getbitu(rtcm->buff, i, 2); i += 2;
prn = getbitu(rtcm->buff, i, 5); i += 5;
prc = getbits(rtcm->buff, i, 16); i += 16;
rrc = getbits(rtcm->buff, i, 8); i += 8;
iod = getbits(rtcm->buff, i, 8); i += 8;
if (prn == 0) prn = 32;
if (prc == 0x80000000||rrc == 0xFFFF8000)
{
trace(2, "rtcm2 1 prc/rrc indicates satellite problem: prn=%d\n", prn);
continue;
}
if (rtcm->dgps)
{
sat = satno(SYS_GPS, prn);
rtcm->dgps[sat-1].t0 = rtcm->time;
rtcm->dgps[sat-1].prc = prc*(fact?0.32:0.02);
rtcm->dgps[sat-1].rrc = rrc*(fact?0.032:0.002);
rtcm->dgps[sat-1].iod = iod;
rtcm->dgps[sat-1].udre = udre;
}
}
return 7;
}
/* decode type 3: reference station parameter --------------------------------*/
int decode_type3(rtcm_t *rtcm)
{
int i = 48;
trace(4, "decode_type3: len=%d\n", rtcm->len);
if (i+96 <= rtcm->len*8)
{
rtcm->sta.pos[0] = getbits(rtcm->buff, i, 32)*0.01; i += 32;
rtcm->sta.pos[1] = getbits(rtcm->buff, i, 32)*0.01; i += 32;
rtcm->sta.pos[2] = getbits(rtcm->buff, i, 32)*0.01;
}
else
{
trace(2, "rtcm2 3 length error: len=%d\n", rtcm->len);
return -1;
}
return 5;
}
/* decode type 14: gps time of week ------------------------------------------*/
int decode_type14(rtcm_t *rtcm)
{
double zcnt;
int i = 48, week, hour, leaps;
trace(4, "decode_type14: len=%d\n", rtcm->len);
zcnt = getbitu(rtcm->buff, 24, 13);
if (i+24 <= rtcm->len*8)
{
week = getbitu(rtcm->buff, i, 10); i += 10;
hour = getbitu(rtcm->buff, i, 8); i += 8;
leaps = getbitu(rtcm->buff, i, 6);
}
else
{
trace(2, "rtcm2 14 length error: len=%d\n", rtcm->len);
return -1;
}
week = adjgpsweek(week);
rtcm->time = gpst2time(week, hour*3600.0+zcnt*0.6);
rtcm->nav.leaps = leaps;
return 6;
}
/* decode type 16: gps special message ---------------------------------------*/
int decode_type16(rtcm_t *rtcm)
{
int i = 48, n = 0;
trace(4, "decode_type16: len=%d\n", rtcm->len);
while (i+8 <= rtcm->len*8 && n<90)
{
rtcm->msg[n++] = getbitu(rtcm->buff, i, 8); i += 8;
}
rtcm->msg[n] = '\0';
trace(3, "rtcm2 16 message: %s\n", rtcm->msg);
return 9;
}
/* decode type 17: gps ephemerides -------------------------------------------*/
int decode_type17(rtcm_t *rtcm)
{
eph_t eph = {0};
double toc, sqrtA;
int i = 48, week, prn, sat;
trace(4, "decode_type17: len=%d\n", rtcm->len);
if (i+480 <= rtcm->len*8)
{
week = getbitu(rtcm->buff, i, 10); i += 10;
eph.idot = getbits(rtcm->buff, i, 14)*TWO_N43*SC2RAD; i += 14;
eph.iode = getbitu(rtcm->buff, i, 8); i += 8;
toc = getbitu(rtcm->buff, i, 16)*16.0; i += 16;
eph.f1 = getbits(rtcm->buff, i, 16)*TWO_N43; i += 16;
eph.f2 = getbits(rtcm->buff, i, 8)*TWO_N55; i += 8;
eph.crs = getbits(rtcm->buff, i, 16)*TWO_N5; i += 16;
eph.deln = getbits(rtcm->buff, i, 16)*TWO_N43*SC2RAD; i += 16;
eph.cuc = getbits(rtcm->buff, i, 16)*TWO_N29; i += 16;
eph.e = getbitu(rtcm->buff, i, 32)*TWO_N33; i += 32;
eph.cus = getbits(rtcm->buff, i, 16); i += 16;
sqrtA = getbitu(rtcm->buff, i, 32)*TWO_N19; i += 32;
eph.toes = getbitu(rtcm->buff, i, 16); i += 16;
eph.OMG0 = getbits(rtcm->buff, i, 32)*TWO_N31*SC2RAD; i += 32;
eph.cic = getbits(rtcm->buff, i, 16)*TWO_N29; i += 16;
eph.i0 = getbits(rtcm->buff, i, 32)*TWO_N31*SC2RAD; i += 32;
eph.cis = getbits(rtcm->buff, i, 16)*TWO_N29; i += 16;
eph.omg = getbits(rtcm->buff, i, 32)*TWO_N31*SC2RAD; i += 32;
eph.crc = getbits(rtcm->buff, i, 16)*TWO_N5; i += 16;
eph.OMGd = getbits(rtcm->buff, i, 24)*TWO_N43*SC2RAD; i += 24;
eph.M0 = getbits(rtcm->buff, i, 32)*TWO_N31*SC2RAD; i += 32;
eph.iodc = getbitu(rtcm->buff, i, 10); i += 10;
eph.f0 = getbits(rtcm->buff, i, 22)*TWO_N31; i += 22;
prn = getbitu(rtcm->buff, i, 5); i += 5+3;
eph.tgd[0] = getbits(rtcm->buff, i, 8)*TWO_N31; i += 8;
eph.code = getbitu(rtcm->buff, i, 2); i += 2;
eph.sva = getbitu(rtcm->buff, i, 4); i += 4;
eph.svh = getbitu(rtcm->buff, i, 6); i += 6;
eph.flag = getbitu(rtcm->buff, i, 1);
}
else
{
trace(2, "rtcm2 17 length error: len=%d\n", rtcm->len);
return -1;
}
if (prn == 0) prn = 32;
sat = satno(SYS_GPS, prn);
eph.sat = sat;
eph.week = adjgpsweek(week);
eph.toe = gpst2time(eph.week, eph.toes);
eph.toc = gpst2time(eph.week, toc);
eph.ttr = rtcm->time;
eph.A = sqrtA*sqrtA;
rtcm->nav.eph[sat-1] = eph;
rtcm->ephsat = sat;
return 2;
}
/* decode type 18: rtk uncorrected carrier-phase -----------------------------*/
int decode_type18(rtcm_t *rtcm)
{
gtime_t time;
double usec, cp, tt;
int i = 48, index, freq, sync = 1, code, sys, prn, sat, loss;
trace(4, "decode_type18: len=%d\n", rtcm->len);
if (i+24 <= rtcm->len*8)
{
freq = getbitu(rtcm->buff, i, 2); i += 2+2;
usec = getbitu(rtcm->buff, i, 20); i += 20;
}
else
{
trace(2, "rtcm2 18 length error: len=%d\n", rtcm->len);
return -1;
}
if (freq&0x1)
{
trace(2, "rtcm2 18 not supported frequency: freq=%d\n", freq);
return -1;
}
freq>>= 1;
while (i+48 <= rtcm->len*8 && rtcm->obs.nbuff, i, 1); i += 1;
code = getbitu(rtcm->buff, i, 1); i += 1;
sys = getbitu(rtcm->buff, i, 1); i += 1;
prn = getbitu(rtcm->buff, i, 5); i += 5+3;
loss = getbitu(rtcm->buff, i, 5); i += 5;
cp = getbits(rtcm->buff, i, 32); i += 32;
if (prn == 0) prn = 32;
if (!(sat = satno(sys?SYS_GLO:SYS_GPS, prn)))
{
trace(2, "rtcm2 18 satellite number error: sys=%d prn=%d\n", sys, prn);
continue;
}
time = timeadd(rtcm->time, usec*1E-6);
if (sys) time = utc2gpst(time); /* convert glonass time to gpst */
tt = timediff(rtcm->obs.data[0].time, time);
if (rtcm->obsflag||fabs(tt)>1E-9)
{
rtcm->obs.n = rtcm->obsflag = 0;
}
if ((index = obsindex(&rtcm->obs, time, sat)) >= 0)
{
rtcm->obs.data[index].L[freq] = -cp/256.0;
rtcm->obs.data[index].LLI[freq] = rtcm->loss[sat-1][freq] != loss;
rtcm->obs.data[index].code[freq] =
!freq?(code?CODE_L1P:CODE_L1C):(code?CODE_L2P:CODE_L2C);
rtcm->loss[sat-1][freq] = loss;
}
}
rtcm->obsflag = !sync;
return sync?0:1;
}
/* decode type 19: rtk uncorrected pseudorange -------------------------------*/
int decode_type19(rtcm_t *rtcm)
{
gtime_t time;
double usec, pr, tt;
int i = 48, index, freq, sync = 1, code, sys, prn, sat;
trace(4, "decode_type19: len=%d\n", rtcm->len);
if (i+24 <= rtcm->len*8)
{
freq = getbitu(rtcm->buff, i, 2); i += 2+2;
usec = getbitu(rtcm->buff, i, 20); i += 20;
}
else
{
trace(2, "rtcm2 19 length error: len=%d\n", rtcm->len);
return -1;
}
if (freq&0x1)
{
trace(2, "rtcm2 19 not supported frequency: freq=%d\n", freq);
return -1;
}
freq>>=1;
while (i+48 <= rtcm->len*8 && rtcm->obs.nbuff, i, 1); i += 1;
code = getbitu(rtcm->buff, i, 1); i += 1;
sys = getbitu(rtcm->buff, i, 1); i += 1;
prn = getbitu(rtcm->buff, i, 5); i += 5+8;
pr = getbitu(rtcm->buff, i, 32); i += 32;
if (prn == 0) prn = 32;
if (!(sat = satno(sys?SYS_GLO:SYS_GPS, prn)))
{
trace(2, "rtcm2 19 satellite number error: sys=%d prn=%d\n", sys, prn);
continue;
}
time = timeadd(rtcm->time, usec*1E-6);
if (sys) time = utc2gpst(time); /* convert glonass time to gpst */
tt = timediff(rtcm->obs.data[0].time, time);
if (rtcm->obsflag||fabs(tt)>1E-9)
{
rtcm->obs.n = rtcm->obsflag = 0;
}
if ((index = obsindex(&rtcm->obs, time, sat)) >= 0)
{
rtcm->obs.data[index].P[freq] = pr*0.02;
rtcm->obs.data[index].code[freq] =
!freq?(code?CODE_L1P:CODE_L1C):(code?CODE_L2P:CODE_L2C);
}
}
rtcm->obsflag = !sync;
return sync?0:1;
}
/* decode type 22: extended reference station parameter ----------------------*/
int decode_type22(rtcm_t *rtcm)
{
double del[2][3] = {{0}}, hgt = 0.0;
int i = 48, j, noh;
trace(4, "decode_type22: len=%d\n", rtcm->len);
if (i+24 <= rtcm->len*8)
{
del[0][0] = getbits(rtcm->buff, i, 8)/25600.0; i += 8;
del[0][1] = getbits(rtcm->buff, i, 8)/25600.0; i += 8;
del[0][2] = getbits(rtcm->buff, i, 8)/25600.0; i += 8;
}
else
{
trace(2, "rtcm2 22 length error: len=%d\n", rtcm->len);
return -1;
}
if (i+24 <= rtcm->len*8)
{
i += 5; noh = getbits(rtcm->buff, i, 1); i += 1;
hgt = noh?0.0:getbitu(rtcm->buff, i, 18)/25600.0;
i += 18;
}
if (i+24 <= rtcm->len*8)
{
del[1][0] = getbits(rtcm->buff, i, 8)/1600.0; i += 8;
del[1][1] = getbits(rtcm->buff, i, 8)/1600.0; i += 8;
del[1][2] = getbits(rtcm->buff, i, 8)/1600.0;
}
rtcm->sta.deltype = 1; /* xyz */
for (j = 0; j<3; j++) rtcm->sta.del[j] = del[0][j];
rtcm->sta.hgt = hgt;
return 5;
}
/* decode type 23: antenna type definition record ----------------------------*/
int decode_type23(rtcm_t *rtcm)
{
return 0;
}
/* decode type 24: antenna reference point (arp) -----------------------------*/
int decode_type24(rtcm_t *rtcm)
{
return 0;
}
/* decode type 31: differential glonass correction ---------------------------*/
int decode_type31(rtcm_t *rtcm)
{
return 0;
}
/* decode type 32: differential glonass reference station parameters ---------*/
int decode_type32(rtcm_t *rtcm)
{
return 0;
}
/* decode type 34: glonass partial differential correction set ---------------*/
int decode_type34(rtcm_t *rtcm)
{
return 0;
}
/* decode type 36: glonass special message -----------------------------------*/
int decode_type36(rtcm_t *rtcm)
{
return 0;
}
/* decode type 37: gnss system time offset -----------------------------------*/
int decode_type37(rtcm_t *rtcm)
{
return 0;
}
/* decode type 59: proprietary message ---------------------------------------*/
int decode_type59(rtcm_t *rtcm)
{
return 0;
}
/* decode rtcm ver.2 message -------------------------------------------------*/
int decode_rtcm2(rtcm_t *rtcm)
{
double zcnt;
int staid, seqno, stah, ret = 0, type = getbitu(rtcm->buff, 8, 6);
trace(3, "decode_rtcm2: type=%2d len=%3d\n", type, rtcm->len);
if ((zcnt = getbitu(rtcm->buff, 24, 13)*0.6) >= 3600.0)
{
trace(2, "rtcm2 modified z-count error: zcnt=%.1f\n", zcnt);
return -1;
}
adjhour(rtcm, zcnt);
staid = getbitu(rtcm->buff, 14, 10);
seqno = getbitu(rtcm->buff, 37, 3);
stah = getbitu(rtcm->buff, 45, 3);
if (seqno-rtcm->seqno != 1 && seqno-rtcm->seqno != -7)
{
trace(2, "rtcm2 message outage: seqno=%d->%d\n", rtcm->seqno, seqno);
}
rtcm->seqno = seqno;
rtcm->stah = stah;
if (rtcm->outtype)
{
sprintf(rtcm->msgtype, "RTCM %2d (%4d) zcnt=%7.1f staid=%3d seqno=%d",
type, rtcm->len, zcnt, staid, seqno);
}
if (type == 3||type == 22||type == 23||type == 24)
{
if (rtcm->staid != 0 && staid != rtcm->staid)
{
trace(2, "rtcm2 station id changed: %d->%d\n", rtcm->staid, staid);
}
rtcm->staid = staid;
}
if (rtcm->staid != 0 && staid != rtcm->staid)
{
trace(2, "rtcm2 station id invalid: %d %d\n", staid, rtcm->staid);
return -1;
}
switch (type)
{
case 1: ret = decode_type1 (rtcm); break;
case 3: ret = decode_type3 (rtcm); break;
case 9: ret = decode_type1 (rtcm); break;
case 14: ret = decode_type14(rtcm); break;
case 16: ret = decode_type16(rtcm); break;
case 17: ret = decode_type17(rtcm); break;
case 18: ret = decode_type18(rtcm); break;
case 19: ret = decode_type19(rtcm); break;
case 22: ret = decode_type22(rtcm); break;
case 23: ret = decode_type23(rtcm); break; /* not supported */
case 24: ret = decode_type24(rtcm); break; /* not supported */
case 31: ret = decode_type31(rtcm); break; /* not supported */
case 32: ret = decode_type32(rtcm); break; /* not supported */
case 34: ret = decode_type34(rtcm); break; /* not supported */
case 36: ret = decode_type36(rtcm); break; /* not supported */
case 37: ret = decode_type37(rtcm); break; /* not supported */
case 59: ret = decode_type59(rtcm); break; /* not supported */
}
if (ret >= 0)
{
if (1 <= type && type <= 99) rtcm->nmsg2[type]++; else rtcm->nmsg2[0]++;
}
return ret;
}