MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_rcv_ss2.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_rcv_ss2.c : NovAtel Superstar II receiver raw data decoder
3 *
4 * Copyright (C) 2026 H.SHIONO (MRTKLIB Project)
5 * Copyright (C) 2023-2025 Cabinet Office, Japan
6 * Copyright (C) 2024-2025 Lighthouse Technology & Consulting Co. Ltd.
7 * Copyright (C) 2023-2025 Japan Aerospace Exploration Agency
8 * Copyright (C) 2023-2025 TOSHIBA ELECTRONIC TECHNOLOGIES CORPORATION
9 * Copyright (C) 2015- Mitsubishi Electric Corp.
10 * Copyright (C) 2014 Geospatial Information Authority of Japan
11 * Copyright (C) 2014 T.SUZUKI
12 * Copyright (C) 2007-2023 T.TAKASU
13 *
14 * SPDX-License-Identifier: BSD-2-Clause
15 *----------------------------------------------------------------------------*/
16#include <ctype.h>
17#include <math.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include "mrtklib/mrtk_bits.h"
23#include "mrtklib/mrtk_eph.h"
24#include "mrtklib/mrtk_mat.h"
25#include "mrtklib/mrtk_nav.h"
26#include "mrtklib/mrtk_obs.h"
27#include "mrtklib/mrtk_rcvraw.h"
28#include "mrtklib/mrtk_rtcm.h"
29#include "mrtklib/mrtk_sys.h"
30#include "mrtklib/mrtk_time.h"
31#include "mrtklib/mrtk_trace.h"
32
33/* Local constants (duplicated from rtklib.h to avoid dependency) */
34#define PI 3.1415926535897932 /* pi */
35#define D2R (PI / 180.0) /* deg to rad */
36#define R2D (180.0 / PI) /* rad to deg */
37#define CLIGHT 299792458.0 /* speed of light (m/s) */
38#define SC2RAD 3.1415926535898 /* semi-circle to radian (IS-GPS) */
39
40#define SYS_NONE 0x00
41#define SYS_GPS 0x01
42#define SYS_SBS 0x02
43#define SYS_GLO 0x04
44#define SYS_GAL 0x08
45#define SYS_QZS 0x10
46#define SYS_CMP 0x20
47#define SYS_IRN 0x40
48
49#define TSYS_GPS 0
50#define TSYS_UTC 1
51#define TSYS_GLO 2
52#define TSYS_GAL 3
53#define TSYS_QZS 4
54#define TSYS_CMP 5
55#define TSYS_IRN 6
56
57#define FREQ1 1.57542E9 /* L1/E1/B1C frequency (Hz) */
58#define FREQ2 1.22760E9 /* L2 frequency (Hz) */
59#define FREQ5 1.17645E9 /* L5/E5a/B2a frequency (Hz) */
60#define FREQ6 1.27875E9 /* E6/L6 frequency (Hz) */
61#define FREQ7 1.20714E9 /* E5b/B2I frequency (Hz) */
62#define FREQ8 1.191795E9 /* E5ab/B2ab frequency (Hz) */
63#define FREQ9 2.492028E9 /* S frequency (Hz) */
64#define FREQ1_GLO 1.60200E9 /* GLONASS G1 base frequency (Hz) */
65#define DFRQ1_GLO 0.56250E6 /* GLONASS G1 bias frequency (Hz/n) */
66#define FREQ2_GLO 1.24600E9 /* GLONASS G2 base frequency (Hz) */
67#define DFRQ2_GLO 0.43750E6 /* GLONASS G2 bias frequency (Hz/n) */
68#define FREQ3_GLO 1.202025E9 /* GLONASS G3 frequency (Hz) */
69#define FREQ1a_GLO 1.600995E9 /* GLONASS G1a frequency (Hz) */
70#define FREQ2a_GLO 1.248060E9 /* GLONASS G2a frequency (Hz) */
71#define FREQ1_CMP 1.561098E9 /* BDS B1I frequency (Hz) */
72
73#define MINPRNGPS 1
74#define MAXPRNGPS 32
75#define MINPRNSBS 120
76#define MAXPRNSBS 158
77
78/* Power-of-2 constants */
79#define P2_5 0.03125
80#define P2_6 0.015625
81#define P2_11 4.882812500000000E-04
82#define P2_15 3.051757812500000E-05
83#define P2_17 7.629394531250000E-06
84#define P2_19 1.907348632812500E-06
85#define P2_20 9.536743164062500E-07
86#define P2_21 4.768371582031250E-07
87#define P2_23 1.192092895507810E-07
88#define P2_24 5.960464477539063E-08
89#define P2_27 7.450580596923828E-09
90#define P2_29 1.862645149230957E-09
91#define P2_30 9.313225746154785E-10
92#define P2_31 4.656612873077393E-10
93#define P2_32 2.328306436538696E-10
94#define P2_33 1.164153218269348E-10
95#define P2_34 5.820766091346740E-11
96#define P2_35 2.910383045673370E-11
97#define P2_38 3.637978807091710E-12
98#define P2_40 9.094947017729280E-13
99#define P2_43 1.136868377216160E-13
100#define P2_46 1.421085471520200E-14
101#define P2_50 8.881784197001252E-16
102#define P2_55 2.775557561562891E-17
103#define P2_59 1.734723475976810E-18
104
105/* Forward declarations for functions in rtklib (resolved at link time) */
106
107#define SS2SOH 0x01 /* ss2 start of header */
108
109#define ID_SS2LLH 20 /* ss2 message ID#20 navigation data (user) */
110#define ID_SS2ECEF 21 /* ss2 message ID#21 navigation data (ecef) */
111#define ID_SS2EPH 22 /* ss2 message ID#22 ephemeris data */
112#define ID_SS2RAW 23 /* ss2 message ID#23 measurement block */
113#define ID_SS2SBAS 67 /* ss2 message ID#67 sbas data */
114
115/* get/set fields (little-endian) --------------------------------------------*/
116#define U1(p) (*((uint8_t*)(p)))
117static uint16_t U2(uint8_t* p) {
118 uint16_t u;
119 memcpy(&u, p, 2);
120 return u;
121}
122static uint32_t U4(uint8_t* p) {
123 uint32_t u;
124 memcpy(&u, p, 4);
125 return u;
126}
127static double R8(uint8_t* p) {
128 double r;
129 memcpy(&r, p, 8);
130 return r;
131}
132
133/* checksum ------------------------------------------------------------------*/
134static int chksum(const uint8_t* buff, int len) {
135 int i;
136 uint16_t sum = 0;
137
138 for (i = 0; i < len - 2; i++) {
139 sum += buff[i];
140 }
141 return (sum >> 8) == buff[len - 1] && (sum & 0xFF) == buff[len - 2];
142}
143/* adjust week ---------------------------------------------------------------*/
144static int adjweek(raw_t* raw, double sec) {
145 double tow;
146 int week;
147
148 if (raw->time.time == 0) {
149 return 0;
150 }
151 tow = time2gpst(raw->time, &week);
152 if (sec < tow - 302400.0) {
153 sec += 604800.0;
154 } else if (sec > tow + 302400.0) {
155 sec -= 604800.0;
156 }
157 raw->time = gpst2time(week, sec);
158 return 1;
159}
160/* decode id#20 navigation data (user) ---------------------------------------*/
161static int decode_ss2llh(raw_t* raw) {
162 double ep[6];
163 uint8_t* p = raw->buff + 4;
164
165 trace(NULL, 4, "decode_ss2llh: len=%d\n", raw->len);
166
167 if (raw->len != 77) {
168 trace(NULL, 2, "ss2 id#20 length error: len=%d\n", raw->len);
169 return -1;
170 }
171 ep[3] = U1(p);
172 ep[4] = U1(p + 1);
173 ep[5] = R8(p + 2);
174 ep[2] = U1(p + 10);
175 ep[1] = U1(p + 11);
176 ep[0] = U2(p + 12);
177 raw->time = utc2gpst(epoch2time(ep));
178 return 0;
179}
180/* decode id#21 navigation data (ecef) ---------------------------------------*/
181static int decode_ss2ecef(raw_t* raw) {
182 uint8_t* p = raw->buff + 4;
183
184 trace(NULL, 4, "decode_ss2ecef: len=%d\n", raw->len);
185
186 if (raw->len != 85) {
187 trace(NULL, 2, "ss2 id#21 length error: len=%d\n", raw->len);
188 return -1;
189 }
190 raw->time = gpst2time(U2(p + 8), R8(p));
191 return 0;
192}
193/* decode id#23 measurement block --------------------------------------------*/
194static int decode_ss2meas(raw_t* raw) {
195 const double freqif = 1.405396825E6, tslew = 1.75E-7;
196 double tow, slew, code, icp, d;
197 int i, j, n, prn, sat, nobs;
198 uint8_t* p = raw->buff + 4;
199 uint32_t sc;
200
201 trace(NULL, 4, "decode_ss2meas: len=%d\n", raw->len);
202
203 nobs = U1(p + 2);
204 if (17 + nobs * 11 != raw->len) {
205 trace(NULL, 2, "ss2 id#23 message length error: len=%d\n", raw->len);
206 return -1;
207 }
208 tow = floor(R8(p + 3) * 1000.0 + 0.5) / 1000.0; /* rounded by 1ms */
209 if (!adjweek(raw, tow)) {
210 trace(NULL, 2, "ss2 id#23 message time adjustment error\n");
211 return -1;
212 }
213 /* time slew defined as uchar (ref [1]) but minus value appears in some f/w */
214 slew = *(char*)(p)*tslew;
215
216 raw->icpc += 4.5803 - freqif * slew - FREQ1 * (slew - 1E-6); /* phase correction */
217
218 for (i = n = 0, p += 11; i < nobs && n < MAXOBS; i++, p += 11) {
219 prn = (p[0] & 0x1F) + 1;
220 if (!(sat = satno(p[0] & 0x20 ? SYS_SBS : SYS_GPS, prn))) {
221 trace(NULL, 2, "ss2 id#23 satellite number error: prn=%d\n", prn);
222 continue;
223 }
224 raw->obs.data[n].time = raw->time;
225 raw->obs.data[n].sat = sat;
226 code = (tow - floor(tow)) - (double)(U4(p + 2)) / 2095104000.0;
227 raw->obs.data[n].P[0] = CLIGHT * (code + (code < 0.0 ? 1.0 : 0.0));
228 icp = (double)(U4(p + 6) >> 2) / 1024.0 + raw->off[sat - 1]; /* unwrap */
229 if (fabs(icp - raw->icpp[sat - 1]) > 524288.0) {
230 d = icp > raw->icpp[sat - 1] ? -1048576.0 : 1048576.0;
231 raw->off[sat - 1] += d;
232 icp += d;
233 }
234 raw->icpp[sat - 1] = icp;
235 raw->obs.data[n].L[0] = icp + raw->icpc;
236 raw->obs.data[n].D[0] = 0.0;
237 raw->obs.data[n].SNR[0] = (uint16_t)(U1(p + 1) * 0.25 / SNR_UNIT + 0.5);
238 sc = U1(p + 10);
239 raw->obs.data[n].LLI[0] = (int)((uint8_t)sc - (uint8_t)raw->lockt[sat - 1][0]) > 0;
240 raw->obs.data[n].LLI[0] |= U1(p + 6) & 1 ? 2 : 0;
241 raw->obs.data[n].code[0] = CODE_L1C;
242 raw->lockt[sat - 1][0] = sc;
243
244 for (j = 1; j < NFREQ; j++) {
245 raw->obs.data[n].L[j] = raw->obs.data[n].P[j] = 0.0;
246 raw->obs.data[n].D[j] = 0.0;
247 raw->obs.data[n].SNR[j] = raw->obs.data[n].LLI[j] = 0;
248 raw->obs.data[n].code[j] = CODE_NONE;
249 }
250 n++;
251 }
252 raw->obs.n = n;
253 return 1;
254}
255/* decode id#22 ephemeris data ------------------------------------------------*/
256static int decode_ss2eph(raw_t* raw) {
257 eph_t eph = {0};
258 uint32_t tow;
259 uint8_t *p = raw->buff + 4, buff[90] = {0};
260 int i, j, prn, sat;
261
262 trace(NULL, 4, "decode_ss2eph: len=%d\n", raw->len);
263
264 if (raw->len != 79) {
265 trace(NULL, 2, "ss2 id#22 length error: len=%d\n", raw->len);
266 return -1;
267 }
268 prn = (U4(p) & 0x1F) + 1;
269 if (!(sat = satno(SYS_GPS, prn))) {
270 trace(NULL, 2, "ss2 id#22 satellite number error: prn=%d\n", prn);
271 return -1;
272 }
273 if (raw->time.time == 0) {
274 trace(NULL, 2, "ss2 id#22 week number unknown error\n");
275 return -1;
276 }
277 tow = (uint32_t)(time2gpst(raw->time, NULL) / 6.0);
278 for (i = 0; i < 3; i++) {
279 buff[30 * i + 3] = (uint8_t)(tow >> 9); /* add tow + subframe id */
280 buff[30 * i + 4] = (uint8_t)(tow >> 1);
281 buff[30 * i + 5] = (uint8_t)(((tow & 1) << 7) + ((i + 1) << 2));
282 for (j = 0; j < 24; j++) {
283 buff[30 * i + 6 + j] = p[1 + 24 * i + j];
284 }
285 }
286 if (!decode_frame(buff, &eph, NULL, NULL, NULL)) {
287 trace(NULL, 2, "ss2 id#22 subframe error: prn=%d\n", prn);
288 return -1;
289 }
290 if (!strstr(raw->opt, "-EPHALL")) {
291 if (eph.iode == raw->nav.eph[sat - 1].iode) {
292 return 0; /* unchanged */
293 }
294 }
295 eph.sat = sat;
296 eph.ttr = raw->time;
297 raw->nav.eph[sat - 1] = eph;
298 raw->ephsat = sat;
299 raw->ephset = 0;
300 return 2;
301}
302/* decode id#67 sbas data ----------------------------------------------------*/
303static int decode_ss2sbas(raw_t* raw) {
304 gtime_t time;
305 int i, prn;
306 uint8_t* p = raw->buff + 4;
307
308 trace(NULL, 4, "decode_ss2sbas: len=%d\n", raw->len);
309
310 if (raw->len != 54) {
311 trace(NULL, 2, "ss2 id#67 length error: len=%d\n", raw->len);
312 return -1;
313 }
314 prn = U4(p + 12);
315 if (prn < MINPRNSBS || MAXPRNSBS < prn) {
316 trace(NULL, 3, "ss2 id#67 prn error: prn=%d\n", prn);
317 return 0;
318 }
319 raw->sbsmsg.week = U4(p);
320 raw->sbsmsg.tow = (int)R8(p + 4);
321 time = gpst2time(raw->sbsmsg.week, raw->sbsmsg.tow);
322 raw->sbsmsg.prn = prn;
323 for (i = 0; i < 29; i++) {
324 raw->sbsmsg.msg[i] = p[16 + i];
325 }
326 return 3;
327}
328/* decode superstar 2 raw message --------------------------------------------*/
329static int decode_ss2(raw_t* raw) {
330 uint8_t* p = raw->buff;
331 int type = U1(p + 1);
332
333 trace(NULL, 3, "decode_ss2: type=%2d\n", type);
334
335 if (!chksum(raw->buff, raw->len)) {
336 trace(NULL, 2, "ss2 message checksum error: type=%d len=%d\n", type, raw->len);
337 return -1;
338 }
339 if (raw->outtype) {
340 sprintf(raw->msgtype, "SS2 %2d (%4d):", type, raw->len);
341 }
342 switch (type) {
343 case ID_SS2LLH:
344 return decode_ss2llh(raw);
345 case ID_SS2ECEF:
346 return decode_ss2ecef(raw);
347 case ID_SS2RAW:
348 return decode_ss2meas(raw);
349 case ID_SS2EPH:
350 return decode_ss2eph(raw);
351 case ID_SS2SBAS:
352 return decode_ss2sbas(raw);
353 }
354 return 0;
355}
356/* sync code -----------------------------------------------------------------*/
357static int sync_ss2(uint8_t* buff, uint8_t data) {
358 buff[0] = buff[1];
359 buff[1] = buff[2];
360 buff[2] = data;
361 return buff[0] == SS2SOH && (buff[1] ^ buff[2]) == 0xFF;
362}
363/* input superstar 2 raw message from stream -----------------------------------
364 * input next superstar 2 raw message from stream
365 * args : raw_t *raw IO receiver raw data control struct
366 * uint8_t data I stream data (1 byte)
367 * return : status (-1: error message, 0: no message, 1: input observation data,
368 * 2: input ephemeris, 3: input sbas message,
369 * 9: input ion/utc parameter)
370 * notes : needs #20 or #21 message to get proper week number of #23 raw
371 * observation data
372 *-----------------------------------------------------------------------------*/
373extern int input_ss2(raw_t* raw, uint8_t data) {
374 trace(NULL, 5, "input_ss2: data=%02x\n", data);
375
376 /* synchronize frame */
377 if (raw->nbyte == 0) {
378 if (!sync_ss2(raw->buff, data)) {
379 return 0;
380 }
381 raw->nbyte = 3;
382 return 0;
383 }
384 raw->buff[raw->nbyte++] = data;
385
386 if (raw->nbyte == 4) {
387 if ((raw->len = U1(raw->buff + 3) + 6) > MAXRAWLEN) {
388 trace(NULL, 2, "ss2 length error: len=%d\n", raw->len);
389 raw->nbyte = 0;
390 return -1;
391 }
392 }
393 if (raw->nbyte < 4 || raw->nbyte < raw->len) {
394 return 0;
395 }
396 raw->nbyte = 0;
397
398 /* decode superstar 2 raw message */
399 return decode_ss2(raw);
400}
401/* input superstar 2 raw message from file -------------------------------------
402 * input next superstar 2 raw message from file
403 * args : raw_t *raw IO receiver raw data control struct
404 * FILE *fp I file pointer
405 * return : status(-2: end of file, -1...9: same as above)
406 *-----------------------------------------------------------------------------*/
407extern int input_ss2f(raw_t* raw, FILE* fp) {
408 int i, data;
409
410 trace(NULL, 4, "input_ss2f:\n");
411
412 /* synchronize frame */
413 if (raw->nbyte == 0) {
414 for (i = 0;; i++) {
415 if ((data = fgetc(fp)) == EOF) {
416 return -2;
417 }
418 if (sync_ss2(raw->buff, (uint8_t)data)) {
419 break;
420 }
421 if (i >= 4096) {
422 return 0;
423 }
424 }
425 }
426 if (fread(raw->buff + 3, 1, 1, fp) < 1) {
427 return -2;
428 }
429 raw->nbyte = 4;
430
431 if ((raw->len = U1(raw->buff + 3) + 6) > MAXRAWLEN) {
432 trace(NULL, 2, "ss2 length error: len=%d\n", raw->len);
433 raw->nbyte = 0;
434 return -1;
435 }
436 if (fread(raw->buff + 4, 1, raw->len - 4, fp) < (size_t)(raw->len - 4)) {
437 return -2;
438 }
439 raw->nbyte = 0;
440
441 /* decode superstar 2 raw message */
442 return decode_ss2(raw);
443}
MRTKLIB Bits Module — Binary bit operations and CRC functions.
#define CLIGHT
Definition mrtk_coords.c:41
#define SYS_GPS
Definition mrtk_eph.c:65
#define SYS_SBS
Definition mrtk_eph.c:66
MRTKLIB Broadcast Ephemeris Module — Satellite orbit/clock types and Kepler/GLONASS/SBAS orbit comput...
#define SNR_UNIT
#define MAXOBS
#define CODE_L1C
#define CODE_NONE
#define MAXRAWLEN
MRTKLIB Matrix Module — Matrix/vector operations and estimation.
int satno(int sys, int prn)
Convert satellite system+prn/slot number to satellite number.
Definition mrtk_nav.c:58
MRTKLIB Navigation Module — Navigation data types and satellite/nav utility functions.
#define FREQ1
Definition mrtk_obs.c:67
MRTKLIB Observation Module — Observation data types and utility functions.
#define U1(p)
#define MAXPRNSBS
#define MINPRNSBS
#define R8(p)
#define U4(p)
#define U2(p)
static int sync_ss2(uint8_t *buff, uint8_t data)
#define U1(p)
static int decode_ss2eph(raw_t *raw)
#define SS2SOH
#define ID_SS2RAW
static int decode_ss2meas(raw_t *raw)
#define ID_SS2SBAS
int input_ss2f(raw_t *raw, FILE *fp)
static int decode_ss2(raw_t *raw)
int input_ss2(raw_t *raw, uint8_t data)
static int decode_ss2ecef(raw_t *raw)
static int chksum(const uint8_t *buff, int len)
#define ID_SS2ECEF
static int adjweek(raw_t *raw, double sec)
#define ID_SS2LLH
static int decode_ss2llh(raw_t *raw)
static int decode_ss2sbas(raw_t *raw)
#define ID_SS2EPH
int decode_frame(const uint8_t *buff, eph_t *eph, alm_t *alm, double *ion, double *utc)
MRTKLIB Receiver Raw Data Module — Receiver raw data types and decoder functions for various GNSS rec...
MRTKLIB RTCM Module — RTCM message types and functions.
MRTKLIB System Module — OS/filesystem utility functions.
gtime_t epoch2time(const double *ep)
Convert calendar day/time to gtime_t struct.
Definition mrtk_time.c:113
gtime_t gpst2time(int week, double sec)
Convert GPS week/tow to gtime_t.
Definition mrtk_time.c:165
double time2gpst(gtime_t t, int *week)
Convert gtime_t to GPS week/tow.
Definition mrtk_time.c:181
gtime_t utc2gpst(gtime_t t)
Convert UTC to GPS time considering leap seconds.
Definition mrtk_time.c:440
MRTKLIB Time Module — GNSS time types and conversion functions.
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
Definition mrtk_trace.c:78
MRTKLIB Trace Module — debug trace and logging functions.
GPS/GAL/QZS/BDS/IRN broadcast ephemeris type.
Definition mrtk_eph.h:77
int sat
Definition mrtk_eph.h:78
gtime_t ttr
Definition mrtk_eph.h:88
int iode
Definition mrtk_eph.h:79
GNSS time representation.
Definition mrtk_time.h:49
time_t time
Definition mrtk_time.h:50
eph_t * eph
Definition mrtk_nav.h:400
obsd_t * data
Definition mrtk_obs.h:61
int n
Definition mrtk_obs.h:60
float D[5+5]
Definition mrtk_obs.h:52
gtime_t time
Definition mrtk_obs.h:45
uint8_t sat
Definition mrtk_obs.h:46
uint8_t LLI[5+5]
Definition mrtk_obs.h:48
double L[5+5]
Definition mrtk_obs.h:50
double P[5+5]
Definition mrtk_obs.h:51
uint16_t SNR[5+5]
Definition mrtk_obs.h:47
uint8_t code[5+5]
Definition mrtk_obs.h:49
Receiver raw data control type.
Definition mrtk_rcvraw.h:78
sbsmsg_t sbsmsg
Definition mrtk_rcvraw.h:87
nav_t nav
Definition mrtk_rcvraw.h:83
double icpp[MAXSAT]
Definition mrtk_rcvraw.h:91
double lockt[MAXSAT][5+5]
Definition mrtk_rcvraw.h:90
int ephset
Definition mrtk_rcvraw.h:86
int outtype
obs_t obs
Definition mrtk_rcvraw.h:81
int len
Definition mrtk_rcvraw.h:96
uint8_t buff[MAXRAWLEN]
char msgtype[256]
Definition mrtk_rcvraw.h:88
int nbyte
Definition mrtk_rcvraw.h:95
char opt[256]
double icpc
Definition mrtk_rcvraw.h:91
int ephsat
Definition mrtk_rcvraw.h:85
double off[MAXSAT]
Definition mrtk_rcvraw.h:91
gtime_t time
Definition mrtk_rcvraw.h:79
int tow
Definition mrtk_nav.h:102
uint8_t msg[29]
Definition mrtk_nav.h:104
uint8_t prn
Definition mrtk_nav.h:103
int week
Definition mrtk_nav.h:102