MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_rcv_novatel.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_rcv_novatel.c : NovAtel 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#define LLI_SLIP 0x01 /* LLI: cycle-slip */
79#define LLI_HALFC 0x02 /* LLI: half-cycle not resolved */
80#define LLI_BOCTRK 0x04 /* LLI: boc tracking of mboc signal */
81#define LLI_HALFA 0x40 /* LLI: half-cycle added */
82#define LLI_HALFS 0x80 /* LLI: half-cycle subtracted */
83
84/* Power-of-2 constants */
85#define P2_5 0.03125
86#define P2_6 0.015625
87#define P2_11 4.882812500000000E-04
88#define P2_15 3.051757812500000E-05
89#define P2_17 7.629394531250000E-06
90#define P2_19 1.907348632812500E-06
91#define P2_20 9.536743164062500E-07
92#define P2_21 4.768371582031250E-07
93#define P2_23 1.192092895507810E-07
94#define P2_24 5.960464477539063E-08
95#define P2_27 7.450580596923828E-09
96#define P2_29 1.862645149230957E-09
97#define P2_30 9.313225746154785E-10
98#define P2_31 4.656612873077393E-10
99#define P2_32 2.328306436538696E-10
100#define P2_33 1.164153218269348E-10
101#define P2_34 5.820766091346740E-11
102#define P2_35 2.910383045673370E-11
103#define P2_38 3.637978807091710E-12
104#define P2_40 9.094947017729280E-13
105#define P2_43 1.136868377216160E-13
106#define P2_46 1.421085471520200E-14
107#define P2_50 8.881784197001252E-16
108#define P2_55 2.775557561562891E-17
109#define P2_59 1.734723475976810E-18
110
111/* Forward declarations for functions in rtklib (resolved at link time) */
112
113#define OEM4SYNC1 0xAA /* oem7/6/4 message start sync code 1 */
114#define OEM4SYNC2 0x44 /* oem7/6/4 message start sync code 2 */
115#define OEM4SYNC3 0x12 /* oem7/6/4 message start sync code 3 */
116#define OEM3SYNC1 0xAA /* oem3 message start sync code 1 */
117#define OEM3SYNC2 0x44 /* oem3 message start sync code 2 */
118#define OEM3SYNC3 0x11 /* oem3 message start sync code 3 */
119#define OEM4HLEN 28 /* oem7/6/4 message header length (bytes) */
120#define OEM3HLEN 12 /* oem3 message header length (bytes) */
121
122/* message IDs */
123#define ID_RANGECMP 140 /* oem7/6/4 range compressed */
124#define ID_RANGE 43 /* oem7/6/4 range measurement */
125#define ID_RAWEPHEM 41 /* oem7/6/4 raw ephemeris */
126#define ID_IONUTC 8 /* oem7/6/4 iono and utc data */
127#define ID_RAWWAASFRAME 287 /* oem7/6/4 raw waas frame */
128#define ID_RAWSBASFRAME 973 /* oem7/6 raw sbas frame */
129#define ID_GPSEPHEM 7 /* oem7/6/4 decoded gps ephemeris */
130#define ID_GLOEPHEMERIS 723 /* oem7/6/4 glonass ephemeris */
131#define ID_GALEPHEMERIS 1122 /* oem7/6 decoded galileo ephemeris */
132#define ID_GALINAVEPHEMERIS 1309 /* oem7/6 decoded galileo inav ephemeris */
133#define ID_GALIONO 1127 /* oem7/6 decoded galileo iono corrections */
134#define ID_GALCLOCK 1121 /* oem7/6 galileo clock information */
135#define ID_QZSSRAWEPHEM 1331 /* oem7/6 qzss raw ephemeris */
136#define ID_QZSSRAWSUBFRAME 1330 /* oem7/6 qzss raw subframe */
137#define ID_QZSSEPHEMERIS 1336 /* oem7/6 decoded qzss ephemeris */
138#define ID_QZSSIONUTC 1347 /* oem7/6 qzss ion/utc parameters */
139#define ID_BDSEPHEMERIS 1696 /* oem7/6 decoded bds ephemeris */
140#define ID_NAVICEPHEMERIS 2123 /* oem7 decoded navic ephemeris */
141
142#define ID_ALMB 18 /* oem3 decoded almanac */
143#define ID_IONB 16 /* oem3 iono parameters */
144#define ID_UTCB 17 /* oem3 utc parameters */
145#define ID_FRMB 54 /* oem3 framed raw navigation data */
146#define ID_RALB 15 /* oem3 raw almanac */
147#define ID_RASB 66 /* oem3 raw almanac set */
148#define ID_REPB 14 /* oem3 raw ephemeris */
149#define ID_RGEB 32 /* oem3 range measurement */
150#define ID_RGED 65 /* oem3 range compressed */
151
152#define WL1 0.1902936727984
153#define WL2 0.2442102134246
154#define MAXVAL 8388608.0
155#define OFF_FRQNO -7 /* F/W ver.3.620 */
156
157#define SQR(x) ((x) * (x))
158
159/* get fields (little-endian) ------------------------------------------------*/
160#define U1(p) (*((uint8_t*)(p)))
161#define I1(p) (*((int8_t*)(p)))
162static uint16_t U2(uint8_t* p) {
163 uint16_t u;
164 memcpy(&u, p, 2);
165 return u;
166}
167static uint32_t U4(uint8_t* p) {
168 uint32_t u;
169 memcpy(&u, p, 4);
170 return u;
171}
172static int32_t I4(uint8_t* p) {
173 int32_t i;
174 memcpy(&i, p, 4);
175 return i;
176}
177static float R4(uint8_t* p) {
178 float r;
179 memcpy(&r, p, 4);
180 return r;
181}
182static double R8(uint8_t* p) {
183 double r;
184 memcpy(&r, p, 8);
185 return r;
186}
187
188/* extend sign ---------------------------------------------------------------*/
189static int32_t exsign(uint32_t v, int bits) { return (int32_t)(v & (1 << (bits - 1)) ? v | (~0u << bits) : v); }
190/* checksum ------------------------------------------------------------------*/
191static uint8_t chksum(const uint8_t* buff, int len) {
192 uint8_t sum = 0;
193 int i;
194 for (i = 0; i < len; i++) {
195 sum ^= buff[i];
196 }
197 return sum;
198}
199/* adjust weekly rollover of GPS time ----------------------------------------*/
200static gtime_t adjweek(gtime_t time, double tow) {
201 double tow_p;
202 int week;
203 tow_p = time2gpst(time, &week);
204 if (tow < tow_p - 302400.0) {
205 tow += 604800.0;
206 } else if (tow > tow_p + 302400.0) {
207 tow -= 604800.0;
208 }
209 return gpst2time(week, tow);
210}
211/* UTC 8-bit week -> full week -----------------------------------------------*/
212static void adj_utcweek(gtime_t time, double* utc) {
213 int week;
214
215 time2gpst(time, &week);
216 utc[3] += week / 256 * 256;
217 if (utc[3] < week - 127) {
218 utc[3] += 256.0;
219 } else if (utc[3] > week + 127) {
220 utc[3] -= 256.0;
221 }
222 utc[5] += utc[3] / 256 * 256;
223 if (utc[5] < utc[3] - 127) {
224 utc[5] += 256.0;
225 } else if (utc[5] > utc[3] + 127) {
226 utc[5] -= 256.0;
227 }
228}
229/* get observation data index ------------------------------------------------*/
230static int obsindex(obs_t* obs, gtime_t time, int sat) {
231 int i, j;
232
233 if (obs->n >= MAXOBS) {
234 return -1;
235 }
236 for (i = 0; i < obs->n; i++) {
237 if (obs->data[i].sat == sat) {
238 return i;
239 }
240 }
241 obs->data[i].time = time;
242 obs->data[i].sat = sat;
243 for (j = 0; j < NFREQ + NEXOBS; j++) {
244 obs->data[i].L[j] = obs->data[i].P[j] = 0.0;
245 obs->data[i].D[j] = 0.0;
246 obs->data[i].SNR[j] = obs->data[i].LLI[j] = 0;
247 obs->data[i].code[j] = CODE_NONE;
248 }
249 obs->n++;
250 return i;
251}
252/* URA value (m) to URA index ------------------------------------------------*/
253static int uraindex(double value) {
254 static const double ura_eph[] = {2.4, 3.4, 4.85, 6.85, 9.65, 13.65, 24.0, 48.0,
255 96.0, 192.0, 384.0, 768.0, 1536.0, 3072.0, 6144.0, 0.0};
256 int i;
257 for (i = 0; i < 15; i++) {
258 if (ura_eph[i] >= value) {
259 break;
260 }
261 }
262 return i;
263}
264/* signal type to obs code ---------------------------------------------------*/
265static int sig2code(int sys, int sigtype) {
266 if (sys == SYS_GPS) {
267 switch (sigtype) {
268 case 0:
269 return CODE_L1C; /* L1C/A */
270 case 5:
271 return CODE_L2P; /* L2P (OEM7) */
272 case 9:
273 return CODE_L2W; /* L2P(Y),semi-codeless */
274 case 14:
275 return CODE_L5Q; /* L5Q (OEM6) */
276 case 16:
277 return CODE_L1L; /* L1C(P) (OEM7) */
278 case 17:
279 return CODE_L2S; /* L2C(M) (OEM7) */
280 }
281 } else if (sys == SYS_GLO) {
282 switch (sigtype) {
283 case 0:
284 return CODE_L1C; /* L1C/A */
285 case 1:
286 return CODE_L2C; /* L2C/A (OEM6) */
287 case 5:
288 return CODE_L2P; /* L2P */
289 case 6:
290 return CODE_L3Q; /* L3Q (OEM7) */
291 }
292 } else if (sys == SYS_GAL) {
293 switch (sigtype) {
294 case 1:
295 return CODE_L1B; /* E1B (OEM6) */
296 case 2:
297 return CODE_L1C; /* E1C (OEM6) */
298 case 6:
299 return CODE_L6B; /* E6B (OEM7) */
300 case 7:
301 return CODE_L6C; /* E6C (OEM7) */
302 case 12:
303 return CODE_L5Q; /* E5aQ (OEM6) */
304 case 17:
305 return CODE_L7Q; /* E5bQ (OEM6) */
306 case 20:
307 return CODE_L8Q; /* AltBOCQ (OEM6) */
308 }
309 } else if (sys == SYS_QZS) {
310 switch (sigtype) {
311 case 0:
312 return CODE_L1C; /* L1C/A */
313 case 14:
314 return CODE_L5Q; /* L5Q (OEM6) */
315 case 16:
316 return CODE_L1L; /* L1C(P) (OEM7) */
317 case 17:
318 return CODE_L2S; /* L2C(M) (OEM7) */
319 case 27:
320 return CODE_L6L; /* L6P (OEM7) */
321 }
322 } else if (sys == SYS_CMP) {
323 switch (sigtype) {
324 case 0:
325 return CODE_L2I; /* B1I with D1 (OEM6) */
326 case 1:
327 return CODE_L7I; /* B2I with D1 (OEM6) */
328 case 2:
329 return CODE_L6I; /* B3I with D1 (OEM7) */
330 case 4:
331 return CODE_L2I; /* B1I with D2 (OEM6) */
332 case 5:
333 return CODE_L7I; /* B2I with D2 (OEM6) */
334 case 6:
335 return CODE_L6I; /* B3I with D2 (OEM7) */
336 case 7:
337 return CODE_L1P; /* B1C(P) (OEM7) */
338 case 9:
339 return CODE_L5P; /* B2a(P) (OEM7) */
340 case 11:
341 return CODE_L7D; /* B2b(I) (OEM7,F/W 7.08) */
342 }
343 } else if (sys == SYS_IRN) {
344 switch (sigtype) {
345 case 0:
346 return CODE_L5A; /* L5 (OEM7) */
347 }
348 } else if (sys == SYS_SBS) {
349 switch (sigtype) {
350 case 0:
351 return CODE_L1C; /* L1C/A */
352 case 6:
353 return CODE_L5I; /* L5I (OEM6) */
354 }
355 }
356 return 0;
357}
358/* decode receiver tracking status ---------------------------------------------
359 * decode receiver tracking status
360 * args : uint32_t stat I tracking status field
361 * int *sys O system (SYS_???)
362 * int *code O signal code (CODE_L??)
363 * int *track O tracking state
364 * (OEM4/5)
365 * 0=L1 idle 8=L2 idle
366 * 1=L1 sky search 9=L2 p-code align
367 * 2=L1 wide freq pull-in 10=L2 search
368 * 3=L1 narrow freq pull-in 11=L2 pll
369 * 4=L1 pll 12=L2 steering
370 * 5=L1 reacq
371 * 6=L1 steering
372 * 7=L1 fll
373 * (OEM6/7)
374 * 0=idle 7=freq-lock loop
375 * 2=wide freq band pull-in 9=channel alignment
376 * 3=narrow freq band pull-in 10=code search
377 * 4=phase lock loop 11=aided phase lock loop
378 * int *plock O phase-lock flag (0=not locked, 1=locked)
379 * int *clock O code-lock flag (0=not locked, 1=locked)
380 * int *parity O parity known flag (0=not known, 1=known)
381 * int *halfc O phase measurement (0=half-cycle not added,
382 * 1=added)
383 * return : freq-index (-1:error)
384 * notes : refer [1][3]
385 *-----------------------------------------------------------------------------*/
386static int decode_track_stat(uint32_t stat, int* sys, int* code, int* track, int* plock, int* clock, int* parity,
387 int* halfc) {
388 int satsys, sigtype, idx = -1;
389
390 *code = CODE_NONE;
391 *track = stat & 0x1F;
392 *plock = (stat >> 10) & 1;
393 *parity = (stat >> 11) & 1;
394 *clock = (stat >> 12) & 1;
395 satsys = (stat >> 16) & 7;
396 *halfc = (stat >> 28) & 1;
397 sigtype = (stat >> 21) & 0x1F;
398
399 switch (satsys) {
400 case 0:
401 *sys = SYS_GPS;
402 break;
403 case 1:
404 *sys = SYS_GLO;
405 break;
406 case 2:
407 *sys = SYS_SBS;
408 break;
409 case 3:
410 *sys = SYS_GAL;
411 break; /* OEM6 */
412 case 4:
413 *sys = SYS_CMP;
414 break; /* OEM6 F/W 6.400 */
415 case 5:
416 *sys = SYS_QZS;
417 break; /* OEM6 */
418 case 6:
419 *sys = SYS_IRN;
420 break; /* OEM7 */
421 default:
422 trace(NULL, 2, "oem4 unknown system: sys=%d\n", satsys);
423 return -1;
424 }
425 if (!(*code = sig2code(*sys, sigtype)) || (idx = code2freq_idx(*sys, *code)) < 0) {
426 trace(NULL, 2, "oem4 signal type error: sys=%d sigtype=%d\n", *sys, sigtype);
427 return -1;
428 }
429 return idx;
430}
431/* check code priority and return freq-index ---------------------------------*/
432static int checkpri(const char* opt, int sys, int code, int idx) {
433 int nex = NEXOBS;
434
435 if (sys == SYS_GPS) {
436 if (strstr(opt, "-GL1L") && idx == 0) {
437 return (code == CODE_L1L) ? 0 : -1;
438 }
439 if (strstr(opt, "-GL2S") && idx == 1) {
440 return (code == CODE_L2X) ? 1 : -1;
441 }
442 if (strstr(opt, "-GL2P") && idx == 1) {
443 return (code == CODE_L2P) ? 1 : -1;
444 }
445 if (code == CODE_L1L) {
446 return (nex < 1) ? -1 : NFREQ;
447 }
448 if (code == CODE_L2S) {
449 return (nex < 2) ? -1 : NFREQ + 1;
450 }
451 if (code == CODE_L2P) {
452 return (nex < 3) ? -1 : NFREQ + 2;
453 }
454 } else if (sys == SYS_GLO) {
455 if (strstr(opt, "-RL2C") && idx == 1) {
456 return (code == CODE_L2C) ? 1 : -1;
457 }
458 if (code == CODE_L2C) {
459 return (nex < 1) ? -1 : NFREQ;
460 }
461 } else if (sys == SYS_GAL) {
462 if (strstr(opt, "-EL6B") && idx == 3) {
463 return (code == CODE_L6B) ? 3 : -1;
464 }
465 if (code == CODE_L6B) {
466 return (nex < 2) ? -1 : NFREQ;
467 }
468 } else if (sys == SYS_QZS) {
469 if (strstr(opt, "-JL1L") && idx == 0) {
470 return (code == CODE_L1L) ? 0 : -1;
471 }
472 if (strstr(opt, "-JL1Z") && idx == 0) {
473 return (code == CODE_L1Z) ? 0 : -1;
474 }
475 if (code == CODE_L1L) {
476 return (nex < 1) ? -1 : NFREQ;
477 }
478 if (code == CODE_L1Z) {
479 return (nex < 2) ? -1 : NFREQ + 1;
480 }
481 } else if (sys == SYS_CMP) {
482 if (strstr(opt, "-CL1P") && idx == 0) {
483 return (code == CODE_L1P) ? 0 : -1;
484 }
485 if (strstr(opt, "-CL7D") && idx == 0) {
486 return (code == CODE_L7D) ? 0 : -1;
487 }
488 if (code == CODE_L1P) {
489 return (nex < 1) ? -1 : NFREQ;
490 }
491 if (code == CODE_L7D) {
492 return (nex < 2) ? -1 : NFREQ + 1;
493 }
494 }
495 return idx < NFREQ ? idx : -1;
496}
497/* decode RANGECMPB ----------------------------------------------------------*/
498static int decode_rangecmpb(raw_t* raw) {
499 uint8_t* p = raw->buff + OEM4HLEN;
500 char* q;
501 double psr, adr, adr_rolls, lockt, tt, dop, snr, freq, glo_bias = 0.0;
502 int i, index, nobs, prn, sat, sys, code, idx, track, plock, clock, parity, halfc, lli;
503
504 if ((q = strstr(raw->opt, "-GLOBIAS="))) {
505 sscanf(q, "-GLOBIAS=%lf", &glo_bias);
506 }
507
508 nobs = U4(p);
509 if (raw->len < OEM4HLEN + 4 + nobs * 24) {
510 trace(NULL, 2, "oem4 rangecmpb length error: len=%d nobs=%d\n", raw->len, nobs);
511 return -1;
512 }
513 if (raw->outtype) {
514 sprintf(raw->msgtype + strlen(raw->msgtype), " nobs=%d", nobs);
515 }
516 for (i = 0, p += 4; i < nobs; i++, p += 24) {
517 if ((idx = decode_track_stat(U4(p), &sys, &code, &track, &plock, &clock, &parity, &halfc)) < 0) {
518 continue;
519 }
520 prn = U1(p + 17);
521 if (sys == SYS_GLO) {
522 prn -= 37;
523 } else if (sys == SYS_SBS && prn >= MINPRNQZS_S && prn <= MAXPRNQZS_S && code == CODE_L1C) {
524 sys = SYS_QZS;
525 prn += 10;
526 code = CODE_L1Z; /* QZS L1S */
527 } else if (sys == SYS_CMP && prn >= 161 && prn <= 197) {
528 prn -= 160; /* Tersus BX */
529 }
530 if (!(sat = satno(sys, prn))) {
531 trace(NULL, 3, "oem4 rangecmpb satellite number error: sys=%d,prn=%d\n", sys, prn);
532 continue;
533 }
534 if (sys == SYS_GLO && !parity) {
535 continue; /* invalid if GLO parity unknown */
536 }
537
538 if ((idx = checkpri(raw->opt, sys, code, idx)) < 0) {
539 continue;
540 }
541
542 dop = exsign(U4(p + 4) & 0xFFFFFFF, 28) / 256.0;
543 psr = (U4(p + 7) >> 4) / 128.0 + U1(p + 11) * 2097152.0;
544
545 if ((freq = sat2freq(sat, (uint8_t)code, &raw->nav)) != 0.0) {
546 adr = I4(p + 12) / 256.0;
547 adr_rolls = (psr * freq / CLIGHT + adr) / MAXVAL;
548 adr = -adr + MAXVAL * floor(adr_rolls + (adr_rolls <= 0 ? -0.5 : 0.5));
549 if (sys == SYS_GLO) {
550 adr += glo_bias * freq / CLIGHT;
551 }
552 } else {
553 adr = 1e-9;
554 }
555 lockt = (U4(p + 18) & 0x1FFFFF) / 32.0; /* lock time */
556
557 if (raw->tobs[sat - 1][idx].time != 0) {
558 tt = timediff(raw->time, raw->tobs[sat - 1][idx]);
559 lli = (lockt < 65535.968 && lockt - raw->lockt[sat - 1][idx] + 0.05 <= tt) ? LLI_SLIP : 0;
560 } else {
561 lli = 0;
562 }
563 if (!parity) {
564 lli |= LLI_HALFC;
565 }
566 if (halfc) {
567 lli |= LLI_HALFA;
568 }
569 raw->tobs[sat - 1][idx] = raw->time;
570 raw->lockt[sat - 1][idx] = lockt;
571 raw->halfc[sat - 1][idx] = halfc;
572
573 snr = ((U2(p + 20) & 0x3FF) >> 5) + 20.0;
574 if (!clock) {
575 psr = 0.0; /* code unlock */
576 }
577 if (!plock) {
578 adr = dop = 0.0; /* phase unlock */
579 }
580
581 if (fabs(timediff(raw->obs.data[0].time, raw->time)) > 1E-9) {
582 raw->obs.n = 0;
583 }
584 if ((index = obsindex(&raw->obs, raw->time, sat)) >= 0) {
585 raw->obs.data[index].L[idx] = adr;
586 raw->obs.data[index].P[idx] = psr;
587 raw->obs.data[index].D[idx] = (float)dop;
588 raw->obs.data[index].SNR[idx] = (uint16_t)(snr / SNR_UNIT + 0.5);
589 raw->obs.data[index].LLI[idx] = (uint8_t)lli;
590 raw->obs.data[index].code[idx] = (uint8_t)code;
591 }
592 }
593 return 1;
594}
595/* decode RANGEB -------------------------------------------------------------*/
596static int decode_rangeb(raw_t* raw) {
597 uint8_t* p = raw->buff + OEM4HLEN;
598 char* q;
599 double psr, adr, dop, snr, lockt, tt, freq, glo_bias = 0.0;
600 int i, index, nobs, prn, sat, sys, code, idx, track, plock, clock, parity, halfc, lli;
601 int gfrq;
602
603 if ((q = strstr(raw->opt, "-GLOBIAS="))) {
604 sscanf(q, "-GLOBIAS=%lf", &glo_bias);
605 }
606
607 nobs = U4(p);
608 if (raw->len < OEM4HLEN + 4 + nobs * 44) {
609 trace(NULL, 2, "oem4 rangeb length error: len=%d nobs=%d\n", raw->len, nobs);
610 return -1;
611 }
612 if (raw->outtype) {
613 sprintf(raw->msgtype + strlen(raw->msgtype), " nobs=%d", nobs);
614 }
615 for (i = 0, p += 4; i < nobs; i++, p += 44) {
616 if ((idx = decode_track_stat(U4(p + 40), &sys, &code, &track, &plock, &clock, &parity, &halfc)) < 0) {
617 continue;
618 }
619 prn = U2(p);
620 if (sys == SYS_GLO) {
621 prn -= 37;
622 } else if (sys == SYS_SBS && prn >= MINPRNQZS_S && prn <= MAXPRNQZS_S && code == CODE_L1C) {
623 sys = SYS_QZS;
624 prn += 10;
625 code = CODE_L1Z; /* QZS L1S */
626 } else if (sys == SYS_CMP && prn >= 161 && prn <= 197) {
627 prn -= 160; /* Tersus BX */
628 }
629 if (!(sat = satno(sys, prn))) {
630 trace(NULL, 3, "oem4 rangeb satellite number error: sys=%d,prn=%d\n", sys, prn);
631 continue;
632 }
633 if (sys == SYS_GLO && !parity) {
634 continue;
635 }
636
637 if ((idx = checkpri(raw->opt, sys, code, idx)) < 0) {
638 continue;
639 }
640
641 gfrq = U2(p + 2); /* GLONASS FCN+8 */
642 psr = R8(p + 4);
643 adr = R8(p + 16);
644 dop = R4(p + 28);
645 snr = R4(p + 32);
646 lockt = R4(p + 36);
647
648 if (sys == SYS_GLO) {
649 freq = sat2freq(sat, (uint8_t)code, &raw->nav);
650 adr -= glo_bias * freq / CLIGHT;
651 if (!raw->nav.glo_fcn[prn - 1]) {
652 raw->nav.glo_fcn[prn - 1] = gfrq; /* fcn+8 */
653 }
654 }
655 if (raw->tobs[sat - 1][idx].time != 0) {
656 tt = timediff(raw->time, raw->tobs[sat - 1][idx]);
657 lli = lockt - raw->lockt[sat - 1][idx] + 0.05 <= tt ? LLI_SLIP : 0;
658 } else {
659 lli = 0;
660 }
661 if (!parity) {
662 lli |= LLI_HALFC;
663 }
664 if (halfc) {
665 lli |= LLI_HALFA;
666 }
667 raw->tobs[sat - 1][idx] = raw->time;
668 raw->lockt[sat - 1][idx] = lockt;
669 raw->halfc[sat - 1][idx] = halfc;
670
671 if (!clock) {
672 psr = 0.0; /* code unlock */
673 }
674 if (!plock) {
675 adr = dop = 0.0; /* phase unlock */
676 }
677
678 if (fabs(timediff(raw->obs.data[0].time, raw->time)) > 1E-9) {
679 raw->obs.n = 0;
680 }
681 if ((index = obsindex(&raw->obs, raw->time, sat)) >= 0) {
682 raw->obs.data[index].L[idx] = -adr;
683 raw->obs.data[index].P[idx] = psr;
684 raw->obs.data[index].D[idx] = (float)dop;
685 raw->obs.data[index].SNR[idx] = (uint16_t)(snr / SNR_UNIT + 0.5);
686 raw->obs.data[index].LLI[idx] = (uint8_t)lli;
687 raw->obs.data[index].code[idx] = (uint8_t)code;
688 }
689 }
690 return 1;
691}
692/* decode RAWEPHEMB ----------------------------------------------------------*/
693static int decode_rawephemb(raw_t* raw) {
694 eph_t eph = {0};
695 uint8_t *p = raw->buff + OEM4HLEN, subframe[30 * 5] = {0};
696 int prn, sat;
697
698 if (raw->len < OEM4HLEN + 102) {
699 trace(NULL, 2, "oem4 rawephemb length error: len=%d\n", raw->len);
700 return -1;
701 }
702 prn = U4(p);
703 if (!(sat = satno(SYS_GPS, prn))) {
704 trace(NULL, 2, "oem4 rawephemb satellite number error: prn=%d\n", prn);
705 return -1;
706 }
707 if (raw->outtype) {
708 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
709 }
710 memcpy(subframe, p + 12, 30 * 3); /* subframe 1-3 */
711
712 if (!decode_frame(subframe, &eph, NULL, NULL, NULL)) {
713 trace(NULL, 2, "oem4 rawephemb subframe error: prn=%d\n", prn);
714 return -1;
715 }
716 if (!strstr(raw->opt, "-EPHALL")) {
717 if (eph.iode == raw->nav.eph[sat - 1].iode && eph.iodc == raw->nav.eph[sat - 1].iodc) {
718 return 0;
719 }
720 }
721 eph.sat = sat;
722 raw->nav.eph[sat - 1] = eph;
723 raw->ephsat = sat;
724 raw->ephset = 0;
725 return 2;
726}
727/* decode IONUTCB ------------------------------------------------------------*/
728static int decode_ionutcb(raw_t* raw) {
729 uint8_t* p = raw->buff + OEM4HLEN;
730 int i;
731
732 if (raw->len < OEM4HLEN + 108) {
733 trace(NULL, 2, "oem4 ionutcb length error: len=%d\n", raw->len);
734 return -1;
735 }
736 for (i = 0; i < 8; i++) {
737 raw->nav.ion_gps[i] = R8(p + i * 8);
738 }
739 raw->nav.utc_gps[0] = R8(p + 72); /* A0 */
740 raw->nav.utc_gps[1] = R8(p + 80); /* A1 */
741 raw->nav.utc_gps[2] = U4(p + 68); /* tot */
742 raw->nav.utc_gps[3] = U4(p + 64); /* WNt */
743 raw->nav.utc_gps[4] = I4(p + 96); /* dt_LS */
744 raw->nav.utc_gps[5] = U4(p + 88); /* WN_LSF */
745 raw->nav.utc_gps[6] = U4(p + 92); /* DN */
746 raw->nav.utc_gps[7] = I4(p + 100); /* dt_LSF */
747 return 9;
748}
749/* decode RAWWAASFRAMEB ------------------------------------------------------*/
750static int decode_rawwaasframeb(raw_t* raw) {
751 uint8_t* p = raw->buff + OEM4HLEN;
752 int prn;
753
754 if (raw->len < OEM4HLEN + 48) {
755 trace(NULL, 2, "oem4 rawwaasframeb length error: len=%d\n", raw->len);
756 return -1;
757 }
758 prn = U4(p + 4);
759 if ((prn < MINPRNSBS || prn > MAXPRNSBS) && (prn < MINPRNQZS_S || prn > MAXPRNQZS_S)) {
760 return 0;
761 }
762 if (raw->outtype) {
763 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
764 }
765 raw->sbsmsg.tow = (int)time2gpst(raw->time, &raw->sbsmsg.week);
766 raw->sbsmsg.prn = prn;
767 memcpy(raw->sbsmsg.msg, p + 12, 29);
768 raw->sbsmsg.msg[28] &= 0xC0;
769 return 3;
770}
771/* decode RAWSBASFRAMEB ------------------------------------------------------*/
772static int decode_rawsbasframeb(raw_t* raw) { return decode_rawwaasframeb(raw); }
773/* decode GPSEPHEMB ----------------------------------------------------------*/
774static int decode_gpsephemb(raw_t* raw) {
775 eph_t eph = {0};
776 uint8_t* p = raw->buff + OEM4HLEN;
777 double tow, toc, ura;
778 int prn, sat, week, iode2, N;
779
780 if (raw->len < OEM4HLEN + 224) {
781 trace(NULL, 2, "oem4 gpsephemb length error: len=%d\n", raw->len);
782 return -1;
783 }
784 prn = U4(p);
785 p += 4;
786 tow = R8(p);
787 p += 8;
788 eph.svh = U4(p);
789 p += 4;
790 eph.iode = U4(p);
791 p += 4; /* IODE1 */
792 iode2 = U4(p);
793 p += 4; /* IODE2 */
794 eph.week = U4(p);
795 p += 4; /* toe week */
796 week = U4(p);
797 p += 4; /* z-count week */
798 eph.toes = R8(p);
799 p += 8;
800 eph.A = R8(p);
801 p += 8;
802 eph.deln = R8(p);
803 p += 8;
804 eph.M0 = R8(p);
805 p += 8;
806 eph.e = R8(p);
807 p += 8;
808 eph.omg = R8(p);
809 p += 8;
810 eph.cuc = R8(p);
811 p += 8;
812 eph.cus = R8(p);
813 p += 8;
814 eph.crc = R8(p);
815 p += 8;
816 eph.crs = R8(p);
817 p += 8;
818 eph.cic = R8(p);
819 p += 8;
820 eph.cis = R8(p);
821 p += 8;
822 eph.i0 = R8(p);
823 p += 8;
824 eph.idot = R8(p);
825 p += 8;
826 eph.OMG0 = R8(p);
827 p += 8;
828 eph.OMGd = R8(p);
829 p += 8;
830 eph.iodc = U4(p);
831 p += 4;
832 toc = R8(p);
833 p += 8;
834 eph.tgd[0] = R8(p);
835 p += 8; /* TGD */
836 eph.f0 = R8(p);
837 p += 8;
838 eph.f1 = R8(p);
839 p += 8;
840 eph.f2 = R8(p);
841 p += 8;
842 eph.code = U4(p);
843 p += 4; /* AS on */
844 N = R8(p);
845 p += 8;
846 ura = R8(p);
847
848 if (toc != eph.toes) { /* toe and toc should be matched */
849 trace(NULL, 2, "oem4 gpsephemb toe and toc unmatch prn=%d\n", prn);
850 return -1;
851 }
852 if (iode2 != eph.iode) { /* iodes should be matched */
853 trace(NULL, 2, "oem4 gpsephemb iode unmatch prn=%d iode=%d %d\n", prn, eph.iode, iode2);
854 return -1;
855 }
856 if (!(sat = satno(SYS_GPS, prn))) {
857 trace(NULL, 2, "oemv gpsephemb satellite error: prn=%d\n", prn);
858 return 0;
859 }
860 if (raw->outtype) {
861 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
862 }
863 eph.sat = sat;
864 eph.type = 0; /* ephemeris type = LNAV */
865 eph.sva = uraindex((ura <= 0.0) ? 6144.0 : sqrt(ura));
866 eph.toe = gpst2time(eph.week, eph.toes);
867 eph.toc = gpst2time(eph.week, toc);
868 eph.ttr = raw->time;
869
870 if (!strstr(raw->opt, "-EPHALL")) {
871 if (timediff(raw->nav.eph[sat - 1].toe, eph.toe) == 0.0 && raw->nav.eph[sat - 1].iode == eph.iode) {
872 return 0; /* unchanged */
873 }
874 }
875 raw->nav.eph[sat - 1] = eph;
876 raw->ephsat = sat;
877 raw->ephset = 0;
878 return 2;
879}
880/* decode GLOEPHEMERISB ------------------------------------------------------*/
881static int decode_gloephemerisb(raw_t* raw) {
882 uint8_t* p = raw->buff + OEM4HLEN;
883 geph_t geph = {0};
884 double tow, tof, toff;
885 int prn, sat, week, type, P, flags;
886
887 if (raw->len < OEM4HLEN + 144) {
888 trace(NULL, 2, "oem4 gloephemerisb length error: len=%d\n", raw->len);
889 return -1;
890 }
891 prn = U2(p) - 37;
892
893 if (!(sat = satno(SYS_GLO, prn))) {
894 trace(NULL, 2, "oem4 gloephemerisb prn error: prn=%d\n", prn);
895 return -1;
896 }
897 if (raw->outtype) {
898 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
899 }
900 geph.frq = U2(p + 2) + OFF_FRQNO;
901 type = U1(p + 4); /* 0:GLO,1:GLO-M,2:GLO-K */
902 week = U2(p + 6);
903 tow = floor(U4(p + 8) / 1000.0 + 0.5); /* rounded to integer sec */
904 toff = U4(p + 12);
905 geph.iode = U4(p + 20) & 0x7F;
906 geph.svh = (U4(p + 24) < 4) ? 0 : 1; /* 0:healthy,1:unhealthy */
907 geph.pos[0] = R8(p + 28);
908 geph.pos[1] = R8(p + 36);
909 geph.pos[2] = R8(p + 44);
910 geph.vel[0] = R8(p + 52);
911 geph.vel[1] = R8(p + 60);
912 geph.vel[2] = R8(p + 68);
913 geph.acc[0] = R8(p + 76);
914 geph.acc[1] = R8(p + 84);
915 geph.acc[2] = R8(p + 92);
916 geph.taun = R8(p + 100);
917 geph.dtaun = R8(p + 108);
918 geph.gamn = R8(p + 116);
919 tof = U4(p + 124) - toff; /* glonasst->gpst */
920 P = U4(p + 128) & 3;
921 geph.sva = U4(p + 132); /* F_T */
922 geph.age = U4(p + 136);
923 flags = U4(p + 140); /* P3(1)+P2(1)+P1(2) */
924 geph.flags = (((type >= 1) ? 1 : 0) << 7) + (flags << 2) + P;
925 geph.toe = gpst2time(week, tow);
926 tof += floor(tow / 86400.0) * 86400;
927 if (tof < tow - 43200.0) {
928 tof += 86400.0;
929 } else if (tof > tow + 43200.0) {
930 tof -= 86400.0;
931 }
932 geph.tof = gpst2time(week, tof);
933
934 if (!strstr(raw->opt, "-EPHALL")) {
935 if (fabs(timediff(geph.toe, raw->nav.geph[prn - 1].toe)) < 1.0 && geph.svh == raw->nav.geph[prn - 1].svh) {
936 return 0; /* unchanged */
937 }
938 }
939 geph.sat = sat;
940 raw->nav.geph[prn - 1] = geph;
941 raw->ephsat = sat;
942 raw->ephset = 0;
943 return 2;
944}
945/* decode QZSSRAWEPHEMB ------------------------------------------------------*/
946static int decode_qzssrawephemb(raw_t* raw) {
947 eph_t eph = {0};
948 uint8_t *p = raw->buff + OEM4HLEN, subfrm[90];
949 int prn, sat;
950
951 if (raw->len < OEM4HLEN + 102) {
952 trace(NULL, 2, "oem4 qzssrawephemb length error: len=%d\n", raw->len);
953 return -1;
954 }
955 prn = U4(p);
956 if (!(sat = satno(SYS_QZS, prn))) {
957 trace(NULL, 2, "oem4 qzssrawephemb satellite number error: prn=%d\n", prn);
958 return -1;
959 }
960 if (raw->outtype) {
961 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
962 }
963 memcpy(subfrm, p + 12, 90);
964
965 if (!decode_frame(subfrm, &eph, NULL, NULL, NULL)) {
966 trace(NULL, 3, "oem4 qzssrawephemb ephemeris error: prn=%d\n", prn);
967 return 0;
968 }
969 if (!strstr(raw->opt, "-EPHALL")) {
970 if (eph.iodc == raw->nav.eph[sat - 1].iodc && eph.iode == raw->nav.eph[sat - 1].iode) {
971 return 0; /* unchanged */
972 }
973 }
974 eph.sat = sat;
975 raw->nav.eph[sat - 1] = eph;
976 raw->ephsat = sat;
977 raw->ephset = 0;
978 return 2;
979}
980/* decode QZSSRAWSUBFRAMEB ---------------------------------------------------*/
982 eph_t eph = {0};
983 double ion[8], utc[8];
984 uint8_t* p = raw->buff + OEM4HLEN;
985 int prn, sat, id;
986
987 if (raw->len < OEM4HLEN + 44) {
988 trace(NULL, 2, "oem4 qzssrawsubframeb length error: len=%d\n", raw->len);
989 return -1;
990 }
991 prn = U4(p);
992 id = U4(p + 4);
993 if (!(sat = satno(SYS_QZS, prn))) {
994 trace(NULL, 2, "oem4 qzssrawsubframeb satellite error: prn=%d\n", prn);
995 return -1;
996 }
997 if (raw->outtype) {
998 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d id=%d", prn, id);
999 }
1000 if (id < 1 || id > 5) {
1001 trace(NULL, 2, "oem4 qzssrawsubframeb subfrm id error: prn=%d id=%d\n", prn, id);
1002 return -1;
1003 }
1004 memcpy(raw->subfrm[sat - 1] + 30 * (id - 1), p + 8, 30);
1005
1006 if (id == 3) {
1007 if (!decode_frame(raw->subfrm[sat - 1], &eph, NULL, NULL, NULL)) {
1008 return 0;
1009 }
1010 if (!strstr(raw->opt, "-EPHALL")) {
1011 if (eph.iodc == raw->nav.eph[sat - 1].iodc && eph.iode == raw->nav.eph[sat - 1].iode) {
1012 return 0; /* unchanged */
1013 }
1014 }
1015 eph.sat = sat;
1016 raw->nav.eph[sat - 1] = eph;
1017 raw->ephsat = sat;
1018 raw->ephset = 0;
1019 return 2;
1020 } else if (id == 4 || id == 5) {
1021 if (!decode_frame(raw->subfrm[sat - 1], NULL, NULL, ion, utc)) {
1022 return 0;
1023 }
1024 adj_utcweek(raw->time, utc);
1025 matcpy(raw->nav.ion_qzs, ion, 8, 1);
1026 matcpy(raw->nav.utc_qzs, utc, 8, 1);
1027 return 9;
1028 }
1029 return 0;
1030}
1031/* decode QZSSEPHEMERISB -----------------------------------------------------*/
1033 eph_t eph = {0};
1034 uint8_t* p = raw->buff + OEM4HLEN;
1035 double tow, toc, ura;
1036 int prn, sat, week, iode2, as, N, fit;
1037
1038 if (raw->len < OEM4HLEN + 228) {
1039 trace(NULL, 2, "oem4 qzssephemerisb length error: len=%d\n", raw->len);
1040 return -1;
1041 }
1042 prn = U4(p);
1043 p += 4;
1044 tow = R8(p);
1045 p += 8;
1046 eph.svh = U4(p);
1047 p += 4;
1048 eph.iode = U4(p);
1049 p += 4; /* IODE1 */
1050 iode2 = U4(p);
1051 p += 4; /* IODE2 */
1052 eph.week = U4(p);
1053 p += 4; /* toe week */
1054 week = U4(p);
1055 p += 4; /* z-count week */
1056 eph.toes = R8(p);
1057 p += 8;
1058 eph.A = R8(p);
1059 p += 8;
1060 eph.deln = R8(p);
1061 p += 8;
1062 eph.M0 = R8(p);
1063 p += 8;
1064 eph.e = R8(p);
1065 p += 8;
1066 eph.omg = R8(p);
1067 p += 8;
1068 eph.cuc = R8(p);
1069 p += 8;
1070 eph.cus = R8(p);
1071 p += 8;
1072 eph.crc = R8(p);
1073 p += 8;
1074 eph.crs = R8(p);
1075 p += 8;
1076 eph.cic = R8(p);
1077 p += 8;
1078 eph.cis = R8(p);
1079 p += 8;
1080 eph.i0 = R8(p);
1081 p += 8;
1082 eph.idot = R8(p);
1083 p += 8;
1084 eph.OMG0 = R8(p);
1085 p += 8;
1086 eph.OMGd = R8(p);
1087 p += 8;
1088 eph.iodc = U4(p);
1089 p += 4;
1090 toc = R8(p);
1091 p += 8;
1092 eph.tgd[0] = R8(p);
1093 p += 8; /* TGD */
1094 eph.f0 = R8(p);
1095 p += 8;
1096 eph.f1 = R8(p);
1097 p += 8;
1098 eph.f2 = R8(p);
1099 p += 8;
1100 as = U4(p);
1101 p += 4;
1102 N = R8(p);
1103 p += 8;
1104 ura = R8(p);
1105 p += 8;
1106 fit = U1(p);
1107
1108 if (iode2 != eph.iode) { /* iodes should be matched */
1109 trace(NULL, 2, "oem4 qzssephemerisb iode unmatch prn=%d iode=%d %d\n", prn, eph.iode, iode2);
1110 return -1;
1111 }
1112 if (!(sat = satno(SYS_QZS, prn))) {
1113 trace(NULL, 2, "oemv qzssephemerisb satellite error: prn=%d\n", prn);
1114 return 0;
1115 }
1116 if (raw->outtype) {
1117 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
1118 }
1119 eph.sat = sat;
1120 eph.type = 0; /* ephemeris type = LNAV */
1121 eph.sva = uraindex(ura <= 0 ? 6144.0 : sqrt(ura));
1122 eph.fit = fit ? 4.0 : 2.0;
1123 eph.code = 2;
1124 eph.flag = 1;
1125 eph.toe = gpst2time(eph.week, eph.toes);
1126 eph.toc = gpst2time(eph.week, toc);
1127 eph.ttr = raw->time;
1128
1129 if (!strstr(raw->opt, "-EPHALL")) {
1130 if (timediff(raw->nav.eph[sat - 1].toe, eph.toe) == 0.0 && raw->nav.eph[sat - 1].iode == eph.iode) {
1131 return 0; /* unchanged */
1132 }
1133 }
1134 raw->nav.eph[sat - 1] = eph;
1135 raw->ephsat = sat;
1136 raw->ephset = 0;
1137 return 2;
1138}
1139/* decode QZSSIONUTCB --------------------------------------------------------*/
1140static int decode_qzssionutcb(raw_t* raw) {
1141 uint8_t* p = raw->buff + OEM4HLEN;
1142 int i;
1143
1144 if (raw->len < OEM4HLEN + 108) {
1145 trace(NULL, 2, "oem4 qzssionutcb length error: len=%d\n", raw->len);
1146 return -1;
1147 }
1148 for (i = 0; i < 8; i++) {
1149 raw->nav.ion_qzs[i] = R8(p + i * 8);
1150 }
1151 raw->nav.utc_qzs[0] = R8(p + 72);
1152 raw->nav.utc_qzs[1] = R8(p + 80);
1153 raw->nav.utc_qzs[2] = U4(p + 68);
1154 raw->nav.utc_qzs[3] = U4(p + 64);
1155 raw->nav.utc_qzs[4] = I4(p + 96);
1156 return 9;
1157}
1158/* decode GALEPHEMERISB ------------------------------------------------------*/
1159static int decode_galephemerisb(raw_t* raw) {
1160 eph_t eph = {0};
1161 uint8_t* p = raw->buff + OEM4HLEN;
1162 double tow, sqrtA, af0_fnav, af1_fnav, af2_fnav, af0_inav, af1_inav, af2_inav, tt;
1163 int prn, sat, week, rcv_fnav, rcv_inav, svh_e1b, svh_e5a, svh_e5b, dvs_e1b, dvs_e5a;
1164 int dvs_e5b, toc_fnav, toc_inav, set, sel_eph = 3; /* 1:I/NAV+2:F/NAV */
1165
1166 if (strstr(raw->opt, "-GALINAV")) {
1167 sel_eph = 1;
1168 }
1169 if (strstr(raw->opt, "-GALFNAV")) {
1170 sel_eph = 2;
1171 }
1172
1173 if (raw->len < OEM4HLEN + 220) {
1174 trace(NULL, 2, "oem4 galephemrisb length error: len=%d\n", raw->len);
1175 return -1;
1176 }
1177 prn = U4(p);
1178 p += 4;
1179 rcv_fnav = U4(p) & 1;
1180 p += 4;
1181 rcv_inav = U4(p) & 1;
1182 p += 4;
1183 svh_e1b = U1(p) & 3;
1184 p += 1;
1185 svh_e5a = U1(p) & 3;
1186 p += 1;
1187 svh_e5b = U1(p) & 3;
1188 p += 1;
1189 dvs_e1b = U1(p) & 1;
1190 p += 1;
1191 dvs_e5a = U1(p) & 1;
1192 p += 1;
1193 dvs_e5b = U1(p) & 1;
1194 p += 1;
1195 eph.sva = U1(p);
1196 p += 1 + 1; /* SISA index */
1197 eph.iode = U4(p);
1198 p += 4; /* IODNav */
1199 eph.toes = U4(p);
1200 p += 4;
1201 sqrtA = R8(p);
1202 p += 8;
1203 eph.deln = R8(p);
1204 p += 8;
1205 eph.M0 = R8(p);
1206 p += 8;
1207 eph.e = R8(p);
1208 p += 8;
1209 eph.omg = R8(p);
1210 p += 8;
1211 eph.cuc = R8(p);
1212 p += 8;
1213 eph.cus = R8(p);
1214 p += 8;
1215 eph.crc = R8(p);
1216 p += 8;
1217 eph.crs = R8(p);
1218 p += 8;
1219 eph.cic = R8(p);
1220 p += 8;
1221 eph.cis = R8(p);
1222 p += 8;
1223 eph.i0 = R8(p);
1224 p += 8;
1225 eph.idot = R8(p);
1226 p += 8;
1227 eph.OMG0 = R8(p);
1228 p += 8;
1229 eph.OMGd = R8(p);
1230 p += 8;
1231 toc_fnav = U4(p);
1232 p += 4;
1233 af0_fnav = R8(p);
1234 p += 8;
1235 af1_fnav = R8(p);
1236 p += 8;
1237 af2_fnav = R8(p);
1238 p += 8;
1239 toc_inav = U4(p);
1240 p += 4;
1241 af0_inav = R8(p);
1242 p += 8;
1243 af1_inav = R8(p);
1244 p += 8;
1245 af2_inav = R8(p);
1246 p += 8;
1247 eph.tgd[0] = R8(p);
1248 p += 8; /* BGD: E5A-E1 (s) */
1249 eph.tgd[1] = R8(p); /* BGD: E5B-E1 (s) */
1250
1251 if (!(sat = satno(SYS_GAL, prn))) {
1252 trace(NULL, 2, "oemv galephemeris satellite error: prn=%d\n", prn);
1253 return -1;
1254 }
1255 if (raw->outtype) {
1256 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
1257 }
1258 set = rcv_fnav ? 1 : 0; /* 0:I/NAV,1:F/NAV */
1259 if (!(sel_eph & 1) && set == 0) {
1260 return 0;
1261 }
1262 if (!(sel_eph & 2) && set == 1) {
1263 return 0;
1264 }
1265
1266 eph.sat = sat;
1267 eph.type = set; /* ephemeris type = I/NAV or F/NAV */
1268 eph.A = SQR(sqrtA);
1269 eph.f0 = set ? af0_fnav : af0_inav;
1270 eph.f1 = set ? af1_fnav : af1_inav;
1271 eph.f2 = set ? af2_fnav : af2_inav;
1272 eph.svh = ((svh_e5b << 7) | (dvs_e5b << 6) | (svh_e5a << 4) | (dvs_e5a << 3) | (svh_e1b << 1) | dvs_e1b);
1273 eph.code = set ? ((1 << 1) + (1 << 8)) : ((1 << 0) + (1 << 2) + (1 << 9));
1274 eph.iodc = eph.iode;
1275 tow = time2gpst(raw->time, &week);
1276 eph.week = week; /* gps-week = gal-week */
1277 eph.toe = gpst2time(eph.week, eph.toes);
1278
1279 tt = timediff(eph.toe, raw->time);
1280 if (tt < -302400.0) {
1281 eph.week++;
1282 } else if (tt > 302400.0) {
1283 eph.week--;
1284 }
1285 eph.toe = gpst2time(eph.week, eph.toes);
1286 eph.toc = adjweek(raw->time, set ? toc_fnav : toc_inav);
1287 eph.ttr = raw->time;
1288
1289 if (!strstr(raw->opt, "-EPHALL")) {
1290 if (eph.iode == raw->nav.eph[sat - 1 + MAXSAT * set].iode &&
1291 timediff(eph.toe, raw->nav.eph[sat - 1 + MAXSAT * set].toe) == 0.0 &&
1292 timediff(eph.toc, raw->nav.eph[sat - 1 + MAXSAT * set].toc) == 0.0) {
1293 return 0; /* unchanged */
1294 }
1295 }
1296 raw->nav.eph[sat - 1 + MAXSAT * set] = eph;
1297 raw->ephsat = sat;
1298 raw->ephset = set;
1299 return 2;
1300}
1301/* decode GALINAVEPHEMERISB ------------------------------------------------------*/
1303 eph_t eph = {0};
1304 uint8_t* p = raw->buff + OEM4HLEN;
1305 double tow, sqrtA, tt;
1306 int prn, sat, week, svh_e1b, svh_e5b, dvs_e1b, src_inav;
1307 int dvs_e5b, toc_inav;
1308
1309 if (raw->len < OEM4HLEN + 184) {
1310 trace(NULL, 2, "oem4 galinavephemrisb length error: len=%d\n", raw->len);
1311 return -1;
1312 }
1313 prn = U4(p);
1314 p += 4;
1315 svh_e5b = U1(p) & 3;
1316 p += 1;
1317 dvs_e5b = U1(p) & 1;
1318 p += 1 + 1 + 1;
1319 svh_e1b = U1(p) & 3;
1320 p += 1;
1321 dvs_e1b = U1(p) & 1;
1322 p += 1 + 1 + 1;
1323 eph.iode = U2(p);
1324 p += 2; /* IODNav */
1325 eph.sva = U1(p);
1326 p += 1; /* SISA index */
1327 src_inav = U1(p);
1328 p += 1; /* INAV Source */
1329 eph.toes = U4(p);
1330 p += 4;
1331 toc_inav = U4(p);
1332 p += 4;
1333 eph.M0 = R8(p);
1334 p += 8;
1335 eph.deln = R8(p);
1336 p += 8;
1337 eph.e = R8(p);
1338 p += 8;
1339 sqrtA = R8(p);
1340 p += 8;
1341 eph.i0 = R8(p);
1342 p += 8;
1343 eph.idot = R8(p);
1344 p += 8;
1345 eph.OMG0 = R8(p);
1346 p += 8;
1347 eph.omg = R8(p);
1348 p += 8;
1349 eph.OMGd = R8(p);
1350 p += 8;
1351 eph.cuc = R8(p);
1352 p += 8;
1353 eph.cus = R8(p);
1354 p += 8;
1355 eph.crc = R8(p);
1356 p += 8;
1357 eph.crs = R8(p);
1358 p += 8;
1359 eph.cic = R8(p);
1360 p += 8;
1361 eph.cis = R8(p);
1362 p += 8;
1363 eph.f0 = R8(p);
1364 p += 8;
1365 eph.f1 = R8(p);
1366 p += 8;
1367 eph.f2 = R8(p);
1368 p += 8;
1369 eph.tgd[0] = R8(p);
1370 p += 8; /* BGD: E5A-E1 (s) */
1371 eph.tgd[1] = R8(p); /* BGD: E5B-E1 (s) */
1372
1373 if (!(sat = satno(SYS_GAL, prn))) {
1374 trace(NULL, 2, "oemv galephemeris satellite error: prn=%d\n", prn);
1375 return -1;
1376 }
1377 if (raw->outtype) {
1378 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
1379 }
1380
1381 eph.sat = sat;
1382 eph.type = 0; /* ephemeris type = I/NAV */
1383 eph.A = SQR(sqrtA);
1384 eph.svh = ((svh_e5b << 4) | (dvs_e5b << 3) | (svh_e1b << 1) |
1385 dvs_e1b); /* bit0:E1-B DVS bit1-2:E1-B SVH bit3:E5b DVS bit4-5:E5b SVH*/
1386 eph.code = ((src_inav & 1 << 0) + (src_inav & 2 << 2) + (1 << 9)); /* Data sources */
1387 eph.iodc = eph.iode;
1388 tow = time2gpst(raw->time, &week);
1389 eph.week = week; /* gps-week = gal-week */
1390 eph.toe = gpst2time(eph.week, eph.toes);
1391
1392 tt = timediff(eph.toe, raw->time);
1393 if (tt < -302400.0) {
1394 eph.week++;
1395 } else if (tt > 302400.0) {
1396 eph.week--;
1397 }
1398 eph.toe = gpst2time(eph.week, eph.toes);
1399 eph.toc = adjweek(raw->time, toc_inav);
1400 eph.ttr = raw->time;
1401
1402 if (!strstr(raw->opt, "-EPHALL")) {
1403 if (eph.iode == raw->nav.eph[sat - 1 + MAXSAT].iode &&
1404 timediff(eph.toe, raw->nav.eph[sat - 1 + MAXSAT].toe) == 0.0 &&
1405 timediff(eph.toc, raw->nav.eph[sat - 1 + MAXSAT].toc) == 0.0) {
1406 return 0; /* unchanged */
1407 }
1408 }
1409 raw->nav.eph[sat - 1] = eph;
1410 raw->ephsat = sat;
1411 raw->ephset = 0;
1412 return 2;
1413}
1414/* decode GALCLOCKB ----------------------------------------------------------*/
1415static int decode_galclockb(raw_t* raw) {
1416 uint8_t* p = raw->buff + OEM4HLEN;
1417 double a0, a1, a0g, a1g;
1418 int dtls, tot, wnt, wnlsf, dn, dtlsf, t0g, wn0g;
1419
1420 if (raw->len < OEM4HLEN + 64) {
1421 trace(NULL, 2, "oem4 galclockb length error: len=%d\n", raw->len);
1422 return -1;
1423 }
1424 a0 = R8(p);
1425 p += 8;
1426 a1 = R8(p);
1427 p += 8;
1428 dtls = I4(p);
1429 p += 4;
1430 tot = U4(p);
1431 p += 4;
1432 wnt = U4(p);
1433 p += 4;
1434 wnlsf = U4(p);
1435 p += 4;
1436 dn = U4(p);
1437 p += 4;
1438 dtlsf = U4(p);
1439 p += 4;
1440 a0g = R8(p);
1441 p += 8;
1442 a1g = R8(p);
1443 p += 8;
1444 t0g = U4(p);
1445 p += 4;
1446 wn0g = U4(p);
1447 raw->nav.utc_gal[0] = a0;
1448 raw->nav.utc_gal[1] = a1;
1449 raw->nav.utc_gal[2] = tot;
1450 raw->nav.utc_gal[3] = wnt;
1451 raw->nav.utc_gal[4] = dtls;
1452 raw->nav.utc_gal[5] = wnlsf;
1453 raw->nav.utc_gal[6] = dn;
1454 raw->nav.utc_gal[7] = dtlsf;
1455 return 9;
1456}
1457/* decode GALIONOB -----------------------------------------------------------*/
1458static int decode_galionob(raw_t* raw) {
1459 uint8_t* p = raw->buff + OEM4HLEN;
1460 double ai[3];
1461 int i, sf[5];
1462
1463 if (raw->len < OEM4HLEN + 29) {
1464 trace(NULL, 2, "oem4 galionob length error: len=%d\n", raw->len);
1465 return -1;
1466 }
1467 ai[0] = R8(p);
1468 p += 8;
1469 ai[1] = R8(p);
1470 p += 8;
1471 ai[2] = R8(p);
1472 p += 8;
1473 sf[0] = U1(p);
1474 p += 1;
1475 sf[1] = U1(p);
1476 p += 1;
1477 sf[2] = U1(p);
1478 p += 1;
1479 sf[3] = U1(p);
1480 p += 1;
1481 sf[4] = U1(p);
1482
1483 for (i = 0; i < 3; i++) {
1484 raw->nav.ion_gal[i] = ai[i];
1485 }
1486 return 9;
1487}
1488/* decode BDSEPHEMERISB ------------------------------------------------------*/
1489static int decode_bdsephemerisb(raw_t* raw) {
1490 eph_t eph = {0};
1491 uint8_t* p = raw->buff + OEM4HLEN;
1492 double ura, sqrtA;
1493 int prn, sat, toc;
1494
1495 if (raw->len < OEM4HLEN + 196) {
1496 trace(NULL, 2, "oem4 bdsephemrisb length error: len=%d\n", raw->len);
1497 return -1;
1498 }
1499 prn = U4(p);
1500 p += 4;
1501 eph.week = U4(p);
1502 p += 4;
1503 ura = R8(p);
1504 p += 8;
1505 eph.svh = U4(p) & 1;
1506 p += 4;
1507 eph.tgd[0] = R8(p);
1508 p += 8; /* TGD1 for B1 (s) */
1509 eph.tgd[1] = R8(p);
1510 p += 8; /* TGD2 for B2 (s) */
1511 eph.iodc = U4(p);
1512 p += 4; /* AODC */
1513 toc = U4(p);
1514 p += 4;
1515 eph.f0 = R8(p);
1516 p += 8;
1517 eph.f1 = R8(p);
1518 p += 8;
1519 eph.f2 = R8(p);
1520 p += 8;
1521 eph.iode = U4(p);
1522 p += 4; /* AODE */
1523 eph.toes = U4(p);
1524 p += 4;
1525 sqrtA = R8(p);
1526 p += 8;
1527 eph.e = R8(p);
1528 p += 8;
1529 eph.omg = R8(p);
1530 p += 8;
1531 eph.deln = R8(p);
1532 p += 8;
1533 eph.M0 = R8(p);
1534 p += 8;
1535 eph.OMG0 = R8(p);
1536 p += 8;
1537 eph.OMGd = R8(p);
1538 p += 8;
1539 eph.i0 = R8(p);
1540 p += 8;
1541 eph.idot = R8(p);
1542 p += 8;
1543 eph.cuc = R8(p);
1544 p += 8;
1545 eph.cus = R8(p);
1546 p += 8;
1547 eph.crc = R8(p);
1548 p += 8;
1549 eph.crs = R8(p);
1550 p += 8;
1551 eph.cic = R8(p);
1552 p += 8;
1553 eph.cis = R8(p);
1554
1555 if (!(sat = satno(SYS_CMP, prn))) {
1556 trace(NULL, 2, "oemv bdsephemeris satellite error: prn=%d\n", prn);
1557 return -1;
1558 }
1559 if (raw->outtype) {
1560 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
1561 }
1562 eph.sat = sat;
1563 eph.type = (prn >= 6 && prn <= 58) ? 0 : 1; /* ephemeris type = D1 or D2 */
1564 eph.A = SQR(sqrtA);
1565 eph.sva = uraindex(ura);
1566 eph.toe = bdt2gpst(bdt2time(eph.week, eph.toes)); /* bdt -> gpst */
1567 eph.toc = bdt2gpst(bdt2time(eph.week, toc)); /* bdt -> gpst */
1568 eph.ttr = raw->time;
1569
1570 if (!strstr(raw->opt, "-EPHALL")) {
1571 if (timediff(raw->nav.eph[sat - 1].toe, eph.toe) == 0.0 &&
1572 timediff(raw->nav.eph[sat - 1].toc, eph.toc) == 0.0) {
1573 return 0;
1574 }
1575 }
1576 raw->nav.eph[sat - 1] = eph;
1577 raw->ephsat = sat;
1578 raw->ephset = 0;
1579 return 2;
1580}
1581/* decode NAVICEPHEMERISB ----------------------------------------------------*/
1583 eph_t eph = {0};
1584 uint8_t* p = raw->buff + OEM4HLEN;
1585 double sqrtA;
1586 int prn, sat, toc, rsv, l5_health, s_health, alert, autonav;
1587
1588 if (raw->len < OEM4HLEN + 204) {
1589 trace(NULL, 2, "oem4 navicephemrisb length error: len=%d\n", raw->len);
1590 return -1;
1591 }
1592 prn = U4(p);
1593 p += 4;
1594 eph.week = U4(p);
1595 p += 4;
1596 eph.f0 = R8(p);
1597 p += 8;
1598 eph.f1 = R8(p);
1599 p += 8;
1600 eph.f2 = R8(p);
1601 p += 8;
1602 eph.sva = U4(p);
1603 p += 4; /* URA index */
1604 toc = U4(p);
1605 p += 4;
1606 eph.tgd[0] = R8(p);
1607 p += 8; /* TGD */
1608 eph.deln = R8(p);
1609 p += 8;
1610 eph.iode = U4(p);
1611 p += 4; /* IODEC */
1612 rsv = U4(p);
1613 p += 4;
1614 l5_health = U4(p) & 1;
1615 p += 4;
1616 s_health = U4(p) & 1;
1617 p += 4;
1618 eph.cuc = R8(p);
1619 p += 8;
1620 eph.cus = R8(p);
1621 p += 8;
1622 eph.cic = R8(p);
1623 p += 8;
1624 eph.cis = R8(p);
1625 p += 8;
1626 eph.crc = R8(p);
1627 p += 8;
1628 eph.crs = R8(p);
1629 p += 8;
1630 eph.idot = R8(p);
1631 p += 8;
1632 rsv = U4(p);
1633 p += 4;
1634 eph.M0 = R8(p);
1635 p += 8;
1636 eph.toes = U4(p);
1637 p += 4;
1638 eph.e = R8(p);
1639 p += 8;
1640 sqrtA = R8(p);
1641 p += 8;
1642 eph.OMG0 = R8(p);
1643 p += 8;
1644 eph.omg = R8(p);
1645 p += 8;
1646 eph.OMGd = R8(p);
1647 p += 8;
1648 eph.i0 = R8(p);
1649 p += 8;
1650 rsv = U4(p);
1651 p += 4;
1652 alert = U4(p);
1653 p += 4;
1654 autonav = U4(p);
1655
1656 if (toc != eph.toes) { /* toe and toc should be matched */
1657 trace(NULL, 2, "oem4 navicephemrisb toe and toc unmatch prn=%d\n", prn);
1658 return -1;
1659 }
1660 if (!(sat = satno(SYS_IRN, prn))) {
1661 trace(NULL, 2, "oemv navicephemeris satellite error: prn=%d\n", prn);
1662 return 0;
1663 }
1664 if (raw->outtype) {
1665 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
1666 }
1667 eph.sat = sat;
1668 eph.type = 0; /* ephemeris type = LNAV */
1669 eph.A = SQR(sqrtA);
1670 eph.svh = (l5_health << 1) | s_health;
1671 eph.iodc = eph.iode;
1672 eph.week += 1024; /* irnss-week -> gps-week */
1673 eph.toe = gpst2time(eph.week, eph.toes);
1674 eph.toc = gpst2time(eph.week, toc);
1675 eph.ttr = raw->time;
1676 eph.tgd[1] = 0.0;
1677
1678 if (!strstr(raw->opt, "-EPHALL")) {
1679 if (timediff(raw->nav.eph[sat - 1].toe, eph.toe) == 0.0 && raw->nav.eph[sat - 1].iode == eph.iode) {
1680 return 0; /* unchanged */
1681 }
1682 }
1683 raw->nav.eph[sat - 1] = eph;
1684 raw->ephsat = sat;
1685 raw->ephset = 0;
1686 return 2;
1687}
1688/* decode RGEB ---------------------------------------------------------------*/
1689static int decode_rgeb(raw_t* raw) {
1690 uint8_t* p = raw->buff + OEM3HLEN;
1691 double tow, psr, adr, tt, lockt, dop, snr;
1692 int i, week, nobs, prn, sat, stat, sys, parity, lli, index, freq;
1693
1694 week = adjgpsweek(U4(p));
1695 tow = R8(p + 4);
1696 nobs = U4(p + 12);
1697 raw->time = gpst2time(week, tow);
1698
1699 if (raw->len != OEM3HLEN + 20 + nobs * 44) {
1700 trace(NULL, 2, "oem3 regb length error: len=%d nobs=%d\n", raw->len, nobs);
1701 return -1;
1702 }
1703 for (i = 0, p += 20; i < nobs; i++, p += 44) {
1704 prn = U4(p);
1705 psr = R8(p + 4);
1706 adr = R8(p + 16);
1707 dop = R4(p + 28);
1708 snr = R4(p + 32);
1709 lockt = R4(p + 36); /* lock time (s) */
1710 stat = I4(p + 40); /* tracking status */
1711 freq = (stat >> 20) & 1; /* L1:0,L2:1 */
1712 sys = (stat >> 15) & 7; /* satellite sys (0:GPS,1:GLONASS,2:WAAS) */
1713 parity = (stat >> 10) & 1; /* parity known */
1714 if (!(sat = satno(sys == 1 ? SYS_GLO : (sys == 2 ? SYS_SBS : SYS_GPS), prn))) {
1715 trace(NULL, 2, "oem3 regb satellite number error: sys=%d prn=%d\n", sys, prn);
1716 continue;
1717 }
1718 if (raw->tobs[sat - 1][freq].time != 0) {
1719 tt = timediff(raw->time, raw->tobs[sat - 1][freq]);
1720 lli = lockt - raw->lockt[sat - 1][freq] + 0.05 < tt || parity != raw->halfc[sat - 1][freq];
1721 } else {
1722 lli = 0;
1723 }
1724 if (!parity) {
1725 lli |= 2;
1726 }
1727 raw->tobs[sat - 1][freq] = raw->time;
1728 raw->lockt[sat - 1][freq] = lockt;
1729 raw->halfc[sat - 1][freq] = parity;
1730
1731 if (fabs(timediff(raw->obs.data[0].time, raw->time)) > 1E-9) {
1732 raw->obs.n = 0;
1733 }
1734 if ((index = obsindex(&raw->obs, raw->time, sat)) >= 0) {
1735 raw->obs.data[index].L[freq] = -adr; /* flip sign */
1736 raw->obs.data[index].P[freq] = psr;
1737 raw->obs.data[index].D[freq] = (float)dop;
1738 raw->obs.data[index].SNR[freq] = 0.0 <= snr && snr < 255.0 ? (uint16_t)(snr / SNR_UNIT + 0.5) : 0;
1739 raw->obs.data[index].LLI[freq] = (uint8_t)lli;
1740 raw->obs.data[index].code[freq] = freq == 0 ? CODE_L1C : CODE_L2P;
1741 }
1742 }
1743 return 1;
1744}
1745/* decode RGED ---------------------------------------------------------------*/
1746static int decode_rged(raw_t* raw) {
1747 uint32_t word;
1748 uint8_t* p = raw->buff + OEM3HLEN;
1749 double tow, psrh, psrl, psr, adr, adr_rolls, tt, lockt, dop;
1750 int i, week, nobs, prn, sat, stat, sys, parity, lli, index, freq, snr;
1751
1752 nobs = U2(p);
1753 week = adjgpsweek(U2(p + 2));
1754 tow = U4(p + 4) / 100.0;
1755 raw->time = gpst2time(week, tow);
1756 if (raw->len != OEM3HLEN + 12 + nobs * 20) {
1757 trace(NULL, 2, "oem3 regd length error: len=%d nobs=%d\n", raw->len, nobs);
1758 return -1;
1759 }
1760 for (i = 0, p += 12; i < nobs; i++, p += 20) {
1761 word = U4(p);
1762 prn = word & 0x3F;
1763 snr = ((word >> 6) & 0x1F) + 20;
1764 lockt = (word >> 11) / 32.0;
1765 adr = -I4(p + 4) / 256.0;
1766 word = U4(p + 8);
1767 psrh = word & 0xF;
1768 dop = exsign(word >> 4, 28) / 256.0;
1769 psrl = U4(p + 12);
1770 stat = U4(p + 16) >> 8;
1771 freq = (stat >> 20) & 1; /* L1:0,L2:1 */
1772 sys = (stat >> 15) & 7; /* satellite sys (0:GPS,1:GLONASS,2:WAAS) */
1773 parity = (stat >> 10) & 1; /* parity known */
1774 if (!(sat = satno(sys == 1 ? SYS_GLO : (sys == 2 ? SYS_SBS : SYS_GPS), prn))) {
1775 trace(NULL, 2, "oem3 regd satellite number error: sys=%d prn=%d\n", sys, prn);
1776 continue;
1777 }
1778 psr = (psrh * 4294967296.0 + psrl) / 128.0;
1779 adr_rolls = floor((psr / (freq == 0 ? WL1 : WL2) - adr) / MAXVAL + 0.5);
1780 adr = adr + MAXVAL * adr_rolls;
1781
1782 if (raw->tobs[sat - 1][freq].time != 0) {
1783 tt = timediff(raw->time, raw->tobs[sat - 1][freq]);
1784 lli = lockt - raw->lockt[sat - 1][freq] + 0.05 < tt || parity != raw->halfc[sat - 1][freq];
1785 } else {
1786 lli = 0;
1787 }
1788 if (!parity) {
1789 lli |= 2;
1790 }
1791 raw->tobs[sat - 1][freq] = raw->time;
1792 raw->lockt[sat - 1][freq] = lockt;
1793 raw->halfc[sat - 1][freq] = parity;
1794
1795 if (fabs(timediff(raw->obs.data[0].time, raw->time)) > 1E-9) {
1796 raw->obs.n = 0;
1797 }
1798 if ((index = obsindex(&raw->obs, raw->time, sat)) >= 0) {
1799 raw->obs.data[index].L[freq] = adr;
1800 raw->obs.data[index].P[freq] = psr;
1801 raw->obs.data[index].D[freq] = (float)dop;
1802 raw->obs.data[index].SNR[freq] = (uint16_t)(snr / SNR_UNIT + 0.5);
1803 raw->obs.data[index].LLI[freq] = (uint8_t)lli;
1804 raw->obs.data[index].code[freq] = freq == 0 ? CODE_L1C : CODE_L2P;
1805 }
1806 }
1807 return 1;
1808}
1809/* decode REPB ---------------------------------------------------------------*/
1810static int decode_repb(raw_t* raw) {
1811 uint8_t* p = raw->buff + OEM3HLEN;
1812 eph_t eph = {0};
1813 int prn, sat;
1814
1815 if (raw->len != OEM3HLEN + 96) {
1816 trace(NULL, 2, "oem3 repb length error: len=%d\n", raw->len);
1817 return -1;
1818 }
1819 prn = U4(p);
1820 if (!(sat = satno(SYS_GPS, prn))) {
1821 trace(NULL, 2, "oem3 repb satellite number error: prn=%d\n", prn);
1822 return -1;
1823 }
1824 if (!decode_frame(p + 4, &eph, NULL, NULL, NULL)) {
1825 trace(NULL, 2, "oem3 repb subframe error: prn=%d\n", prn);
1826 return -1;
1827 }
1828 if (!strstr(raw->opt, "-EPHALL")) {
1829 if (eph.iode == raw->nav.eph[sat - 1].iode) {
1830 return 0; /* unchanged */
1831 }
1832 }
1833 eph.sat = sat;
1834 raw->nav.eph[sat - 1] = eph;
1835 raw->ephsat = sat;
1836 raw->ephset = 0;
1837 return 2;
1838}
1839/* decode FRMB --------------------------------------------------------------*/
1840static int decode_frmb(raw_t* raw) {
1841 uint8_t* p = raw->buff + OEM3HLEN;
1842 double tow;
1843 int i, week, prn, nbit;
1844
1845 trace(NULL, 3, "decode_frmb: len=%d\n", raw->len);
1846
1847 week = adjgpsweek(U4(p));
1848 tow = R8(p + 4);
1849 prn = U4(p + 12);
1850 nbit = U4(p + 20);
1851 raw->time = gpst2time(week, tow);
1852 if (nbit != 250) {
1853 return 0;
1854 }
1855 if (prn < MINPRNSBS || MAXPRNSBS < prn) {
1856 trace(NULL, 2, "oem3 frmb satellite number error: prn=%d\n", prn);
1857 return -1;
1858 }
1859 raw->sbsmsg.week = week;
1860 raw->sbsmsg.tow = (int)tow;
1861 raw->sbsmsg.prn = prn;
1862 for (i = 0; i < 29; i++) {
1863 raw->sbsmsg.msg[i] = p[24 + i];
1864 }
1865 return 3;
1866}
1867/* decode IONB ---------------------------------------------------------------*/
1868static int decode_ionb(raw_t* raw) {
1869 uint8_t* p = raw->buff + OEM3HLEN;
1870 int i;
1871
1872 if (raw->len != 64 + OEM3HLEN) {
1873 trace(NULL, 2, "oem3 ionb length error: len=%d\n", raw->len);
1874 return -1;
1875 }
1876 for (i = 0; i < 8; i++) {
1877 raw->nav.ion_gps[i] = R8(p + i * 8);
1878 }
1879 return 9;
1880}
1881/* decode UTCB ---------------------------------------------------------------*/
1882static int decode_utcb(raw_t* raw) {
1883 uint8_t* p = raw->buff + OEM3HLEN;
1884
1885 if (raw->len != 40 + OEM3HLEN) {
1886 trace(NULL, 2, "oem3 utcb length error: len=%d\n", raw->len);
1887 return -1;
1888 }
1889 raw->nav.utc_gps[0] = R8(p);
1890 raw->nav.utc_gps[1] = R8(p + 8);
1891 raw->nav.utc_gps[2] = U4(p + 16);
1892 raw->nav.utc_gps[3] = adjgpsweek(U4(p + 20));
1893 raw->nav.utc_gps[4] = I4(p + 28);
1894 return 9;
1895}
1896/* decode NovAtel OEM4/V/6/7 message -----------------------------------------*/
1897static int decode_oem4(raw_t* raw) {
1898 double tow;
1899 char tstr[32];
1900 int msg, stat, week, type = U2(raw->buff + 4);
1901
1902 trace(NULL, 3, "decode_oem4: type=%3d len=%d\n", type, raw->len);
1903
1904 /* check crc32 */
1905 if (rtk_crc32(raw->buff, raw->len) != U4(raw->buff + raw->len)) {
1906 trace(NULL, 2, "oem4 crc error: type=%3d len=%d\n", type, raw->len);
1907 return -1;
1908 }
1909 msg = (U1(raw->buff + 6) >> 4) & 0x3; /* message type: 0=binary,1=ascii */
1910 stat = U1(raw->buff + 13);
1911 week = U2(raw->buff + 14);
1912
1913 if (stat == 20 || week == 0) {
1914 trace(NULL, 3, "oem4 time error: type=%3d msg=%d stat=%d week=%d\n", type, msg, stat, week);
1915 return 0;
1916 }
1917 week = adjgpsweek(week);
1918 tow = U4(raw->buff + 16) * 0.001;
1919 raw->time = gpst2time(week, tow);
1920 if (msg != 0) {
1921 return 0;
1922 }
1923
1924 if (raw->outtype) {
1925 time2str(gpst2time(week, tow), tstr, 2);
1926 sprintf(raw->msgtype, "OEM4 %4d (%4d): %s", type, raw->len, tstr);
1927 }
1928 switch (type) {
1929 case ID_RANGECMP:
1930 return decode_rangecmpb(raw);
1931 case ID_RANGE:
1932 return decode_rangeb(raw);
1933 case ID_RAWEPHEM:
1934 return decode_rawephemb(raw);
1935 case ID_IONUTC:
1936 return decode_ionutcb(raw);
1937 case ID_RAWWAASFRAME:
1938 return decode_rawwaasframeb(raw);
1939 case ID_RAWSBASFRAME:
1940 return decode_rawsbasframeb(raw);
1941 case ID_GPSEPHEM:
1942 return decode_gpsephemb(raw);
1943 case ID_GLOEPHEMERIS:
1944 return decode_gloephemerisb(raw);
1945 case ID_GALEPHEMERIS:
1946 return decode_galephemerisb(raw);
1948 return decode_galinavephemerisb(raw);
1949 case ID_GALIONO:
1950 return decode_galionob(raw);
1951 case ID_GALCLOCK:
1952 return decode_galclockb(raw);
1953 case ID_QZSSRAWEPHEM:
1954 return decode_qzssrawephemb(raw);
1955 case ID_QZSSRAWSUBFRAME:
1956 return decode_qzssrawsubframeb(raw);
1957 case ID_QZSSEPHEMERIS:
1958 return decode_qzssephemerisb(raw);
1959 case ID_QZSSIONUTC:
1960 return decode_qzssionutcb(raw);
1961 case ID_BDSEPHEMERIS:
1962 return decode_bdsephemerisb(raw);
1963 case ID_NAVICEPHEMERIS:
1964 return decode_navicephemerisb(raw);
1965 }
1966 return 0;
1967}
1968/* decode NovAtel OEM3 message -----------------------------------------------*/
1969static int decode_oem3(raw_t* raw) {
1970 int type = U4(raw->buff + 4);
1971
1972 trace(NULL, 3, "decode_oem3: type=%3d len=%d\n", type, raw->len);
1973
1974 /* checksum */
1975 if (chksum(raw->buff, raw->len)) {
1976 trace(NULL, 2, "oem3 checksum error: type=%3d len=%d\n", type, raw->len);
1977 return -1;
1978 }
1979 if (raw->outtype) {
1980 sprintf(raw->msgtype, "OEM3 %4d (%4d):", type, raw->len);
1981 }
1982 switch (type) {
1983 case ID_RGEB:
1984 return decode_rgeb(raw);
1985 case ID_RGED:
1986 return decode_rged(raw);
1987 case ID_REPB:
1988 return decode_repb(raw);
1989 case ID_FRMB:
1990 return decode_frmb(raw);
1991 case ID_IONB:
1992 return decode_ionb(raw);
1993 case ID_UTCB:
1994 return decode_utcb(raw);
1995 }
1996 return 0;
1997}
1998/* sync header ---------------------------------------------------------------*/
1999static int sync_oem4(uint8_t* buff, uint8_t data) {
2000 buff[0] = buff[1];
2001 buff[1] = buff[2];
2002 buff[2] = data;
2003 return buff[0] == OEM4SYNC1 && buff[1] == OEM4SYNC2 && buff[2] == OEM4SYNC3;
2004}
2005static int sync_oem3(uint8_t* buff, uint8_t data) {
2006 buff[0] = buff[1];
2007 buff[1] = buff[2];
2008 buff[2] = data;
2009 return buff[0] == OEM3SYNC1 && buff[1] == OEM3SYNC2 && buff[2] == OEM3SYNC3;
2010}
2011/* input NovAtel OEM4/V/6/7 raw data from stream -------------------------------
2012 * fetch next NovAtel OEM4/V/6/7 raw data and input a mesasge from stream
2013 * args : raw_t *raw IO receiver raw data control struct
2014 * uint8_t data I stream data (1 byte)
2015 * return : status (-1: error message, 0: no message, 1: input observation data,
2016 * 2: input ephemeris, 3: input sbas message,
2017 * 9: input ion/utc parameter)
2018 *
2019 * notes : to specify input options for oem4, set raw->opt to the following
2020 * option strings separated by spaces.
2021 *
2022 * -EPHALL : input all ephemerides
2023 * -GL1L : select 1L for GPS L1 (default 1C)
2024 * -GL2S : select 2S for GPS L2 (default 2W)
2025 * -GL2P : select 2P for GPS L2 (default 2W)
2026 * -RL2C : select 2C for GLO G2 (default 2P)
2027 * -EL6B : select 6B for GAL E6 (default 6C)
2028 * -JL1L : select 1L for QZS L1 (default 1C)
2029 * -JL1Z : select 1Z for QZS L1 (default 1C)
2030 * -CL1P : select 1P for BDS B1 (default 2I)
2031 * -CL7D : select 7D for BDS B2 (default 7I)
2032 * -GALINAV: select I/NAV for Galileo ephemeris (default: all)
2033 * -GALFNAV: select F/NAV for Galileo ephemeris (default: all)
2034 * -GLOBIAS=bias: GLONASS code-phase bias (m)
2035 *-----------------------------------------------------------------------------*/
2036extern int input_oem4(raw_t* raw, uint8_t data) {
2037 trace(NULL, 5, "input_oem4: data=%02x\n", data);
2038
2039 /* synchronize frame */
2040 if (raw->nbyte == 0) {
2041 if (sync_oem4(raw->buff, data)) {
2042 raw->nbyte = 3;
2043 }
2044 return 0;
2045 }
2046 raw->buff[raw->nbyte++] = data;
2047
2048 if (raw->nbyte == 10 && (raw->len = U2(raw->buff + 8) + OEM4HLEN) > MAXRAWLEN - 4) {
2049 trace(NULL, 2, "oem4 length error: len=%d\n", raw->len);
2050 raw->nbyte = 0;
2051 return -1;
2052 }
2053 if (raw->nbyte < 10 || raw->nbyte < raw->len + 4) {
2054 return 0;
2055 }
2056 raw->nbyte = 0;
2057
2058 /* decode oem7/6/4 message */
2059 return decode_oem4(raw);
2060}
2061/* input NovAtel OEM3 raw data from stream -------------------------------------
2062 * fetch next NovAtel OEM3 raw data and input a mesasge from stream
2063 * args : raw_t *raw IO receiver raw data control struct
2064 * uint8_t data I stream data (1 byte)
2065 * return : same as above
2066 *-----------------------------------------------------------------------------*/
2067extern int input_oem3(raw_t* raw, uint8_t data) {
2068 trace(NULL, 5, "input_oem3: data=%02x\n", data);
2069
2070 /* synchronize frame */
2071 if (raw->nbyte == 0) {
2072 if (sync_oem3(raw->buff, data)) {
2073 raw->nbyte = 3;
2074 }
2075 return 0;
2076 }
2077 raw->buff[raw->nbyte++] = data;
2078
2079 if (raw->nbyte == 12 && (raw->len = U4(raw->buff + 8)) > MAXRAWLEN) {
2080 trace(NULL, 2, "oem3 length error: len=%d\n", raw->len);
2081 raw->nbyte = 0;
2082 return -1;
2083 }
2084 if (raw->nbyte < 12 || raw->nbyte < raw->len) {
2085 return 0;
2086 }
2087 raw->nbyte = 0;
2088
2089 /* decode oem3 message */
2090 return decode_oem3(raw);
2091}
2092/* input NovAtel OEM4/V/6/7 raw data from file ---------------------------------
2093 * fetch next NovAtel OEM4/V/6/7 raw data and input a message from file
2094 * args : raw_t *raw IO receiver raw data control struct
2095 * FILE *fp I file pointer
2096 * return : status(-2: end of file, -1...9: same as above)
2097 *-----------------------------------------------------------------------------*/
2098extern int input_oem4f(raw_t* raw, FILE* fp) {
2099 int i, data;
2100
2101 trace(NULL, 4, "input_oem4f:\n");
2102
2103 /* synchronize frame */
2104 if (raw->nbyte == 0) {
2105 for (i = 0;; i++) {
2106 if ((data = fgetc(fp)) == EOF) {
2107 return -2;
2108 }
2109 if (sync_oem4(raw->buff, (uint8_t)data)) {
2110 break;
2111 }
2112 if (i >= 4096) {
2113 return 0;
2114 }
2115 }
2116 }
2117 if (fread(raw->buff + 3, 7, 1, fp) < 1) {
2118 return -2;
2119 }
2120 raw->nbyte = 10;
2121
2122 if ((raw->len = U2(raw->buff + 8) + OEM4HLEN) > MAXRAWLEN - 4) {
2123 trace(NULL, 2, "oem4 length error: len=%d\n", raw->len);
2124 raw->nbyte = 0;
2125 return -1;
2126 }
2127 if (fread(raw->buff + 10, raw->len - 6, 1, fp) < 1) {
2128 return -2;
2129 }
2130 raw->nbyte = 0;
2131
2132 /* decode NovAtel OEM4/V/6/7 message */
2133 return decode_oem4(raw);
2134}
2135/* input NovAtel OEM3 raw data from file ---------------------------------------
2136 * fetch next NovAtel OEM3 raw data and input a message from file
2137 * args : raw_t *raw IO receiver raw data control struct
2138 * FILE *fp I file pointer
2139 * return : status(-2: end of file, -1...9: same as above)
2140 *-----------------------------------------------------------------------------*/
2141extern int input_oem3f(raw_t* raw, FILE* fp) {
2142 int i, data;
2143
2144 trace(NULL, 4, "input_oem3f:\n");
2145
2146 /* synchronize frame */
2147 if (raw->nbyte == 0) {
2148 for (i = 0;; i++) {
2149 if ((data = fgetc(fp)) == EOF) {
2150 return -2;
2151 }
2152 if (sync_oem3(raw->buff, (uint8_t)data)) {
2153 break;
2154 }
2155 if (i >= 4096) {
2156 return 0;
2157 }
2158 }
2159 }
2160 if (fread(raw->buff + 3, 1, 9, fp) < 9) {
2161 return -2;
2162 }
2163 raw->nbyte = 12;
2164
2165 if ((raw->len = U4(raw->buff + 8)) > MAXRAWLEN) {
2166 trace(NULL, 2, "oem3 length error: len=%d\n", raw->len);
2167 raw->nbyte = 0;
2168 return -1;
2169 }
2170 if (fread(raw->buff + 12, 1, raw->len - 12, fp) < (size_t)(raw->len - 12)) {
2171 return -2;
2172 }
2173 raw->nbyte = 0;
2174
2175 /* decode oem3 message */
2176 return decode_oem3(raw);
2177}
uint32_t rtk_crc32(const uint8_t *buff, int len)
Compute CRC-32 parity for NovAtel raw data.
Definition mrtk_bits.c:156
MRTKLIB Bits Module — Binary bit operations and CRC functions.
double sat2freq(int sat, uint8_t code, const nav_t *nav)
Definition mrtk_obs.c:244
#define CLIGHT
Definition mrtk_coords.c:41
#define MAXSAT
Definition mrtk_coords.c:45
int satsys(int sat, int *prn)
Definition mrtk_nav.c:117
#define SYS_GPS
Definition mrtk_eph.c:65
#define SYS_SBS
Definition mrtk_eph.c:66
#define SYS_QZS
Definition mrtk_eph.c:69
#define SYS_IRN
Definition mrtk_eph.c:71
#define SYS_CMP
Definition mrtk_eph.c:70
#define SYS_GAL
Definition mrtk_eph.c:68
#define SYS_GLO
Definition mrtk_eph.c:67
MRTKLIB Broadcast Ephemeris Module — Satellite orbit/clock types and Kepler/GLONASS/SBAS orbit comput...
#define SNR_UNIT
#define CODE_L5Q
#define CODE_L6C
#define MAXPRNQZS_S
#define CODE_L5I
#define CODE_L2X
#define CODE_L1L
#define MAXOBS
#define CODE_L2P
#define CODE_L2I
#define MINPRNQZS_S
#define CODE_L1C
#define CODE_L6I
#define CODE_L2C
#define CODE_L7I
#define CODE_NONE
#define CODE_L8Q
#define CODE_L5P
#define CODE_L3Q
#define CODE_L1B
#define CODE_L7D
#define CODE_L2S
#define MAXRAWLEN
#define CODE_L6L
#define CODE_L7Q
#define CODE_L6B
#define CODE_L2W
#define CODE_L1Z
#define CODE_L5A
#define CODE_L1P
void matcpy(double *A, const double *B, int n, int m)
Copy matrix.
Definition mrtk_mat.c:205
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.
int code2freq_idx(int sys, uint8_t code)
Convert system and obs code to frequency index (obsdef-based).
Definition mrtk_obs.c:225
MRTKLIB Observation Module — Observation data types and utility functions.
#define MAXPRNSBS
#define MINPRNSBS
static int decode_galclockb(raw_t *raw)
#define ID_RANGE
static int decode_rged(raw_t *raw)
#define OFF_FRQNO
static int sync_oem4(uint8_t *buff, uint8_t data)
#define WL1
#define U1(p)
#define ID_GLOEPHEMERIS
static gtime_t adjweek(gtime_t time, double tow)
static int decode_navicephemerisb(raw_t *raw)
static int decode_oem4(raw_t *raw)
static int decode_gpsephemb(raw_t *raw)
static int uraindex(double value)
static int decode_rangecmpb(raw_t *raw)
#define OEM3HLEN
static int decode_qzssrawephemb(raw_t *raw)
#define ID_FRMB
#define ID_RAWEPHEM
#define OEM4SYNC1
static int checkpri(const char *opt, int sys, int code, int idx)
#define ID_UTCB
static int decode_qzssephemerisb(raw_t *raw)
static int decode_galionob(raw_t *raw)
int input_oem4(raw_t *raw, uint8_t data)
#define ID_GALIONO
#define ID_RAWSBASFRAME
static int32_t exsign(uint32_t v, int bits)
static int decode_repb(raw_t *raw)
#define ID_NAVICEPHEMERIS
static void adj_utcweek(gtime_t time, double *utc)
static int decode_rgeb(raw_t *raw)
#define OEM4SYNC3
static int decode_rawwaasframeb(raw_t *raw)
static int decode_gloephemerisb(raw_t *raw)
#define OEM3SYNC3
int input_oem4f(raw_t *raw, FILE *fp)
#define ID_GALEPHEMERIS
#define ID_RGEB
#define WL2
static int sync_oem3(uint8_t *buff, uint8_t data)
int input_oem3f(raw_t *raw, FILE *fp)
static int decode_rawsbasframeb(raw_t *raw)
static int decode_qzssrawsubframeb(raw_t *raw)
#define ID_QZSSIONUTC
#define ID_IONUTC
static uint8_t chksum(const uint8_t *buff, int len)
static int sig2code(int sys, int sigtype)
#define ID_GALCLOCK
static int decode_galephemerisb(raw_t *raw)
static int decode_qzssionutcb(raw_t *raw)
static int decode_rangeb(raw_t *raw)
#define ID_IONB
#define SQR(x)
static int decode_frmb(raw_t *raw)
static int decode_track_stat(uint32_t stat, int *sys, int *code, int *track, int *plock, int *clock, int *parity, int *halfc)
static int decode_utcb(raw_t *raw)
static int decode_oem3(raw_t *raw)
static int decode_bdsephemerisb(raw_t *raw)
#define ID_RGED
#define ID_QZSSEPHEMERIS
#define OEM3SYNC1
#define OEM4HLEN
#define MAXVAL
static int decode_ionutcb(raw_t *raw)
static int obsindex(obs_t *obs, gtime_t time, int sat)
#define ID_BDSEPHEMERIS
static int decode_galinavephemerisb(raw_t *raw)
static int decode_rawephemb(raw_t *raw)
#define ID_QZSSRAWSUBFRAME
#define ID_QZSSRAWEPHEM
#define ID_RAWWAASFRAME
#define OEM4SYNC2
#define ID_RANGECMP
#define OEM3SYNC2
#define ID_GPSEPHEM
#define ID_REPB
static int decode_ionb(raw_t *raw)
int input_oem3(raw_t *raw, uint8_t data)
#define ID_GALINAVEPHEMERIS
#define R8(p)
#define U4(p)
#define I4(p)
#define R4(p)
#define U2(p)
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...
#define LLI_HALFC
Definition mrtk_rinex.c:57
static const double ura_eph[]
Definition mrtk_rinex.c:84
#define LLI_SLIP
Definition mrtk_rinex.c:56
#define LLI_HALFA
Definition mrtk_rinex.c:59
MRTKLIB RTCM Module — RTCM message types and functions.
MRTKLIB System Module — OS/filesystem utility functions.
gtime_t bdt2time(int week, double sec)
Convert BeiDou time week/tow to gtime_t.
Definition mrtk_time.c:229
gtime_t gpst2time(int week, double sec)
Convert GPS week/tow to gtime_t.
Definition mrtk_time.c:165
void time2str(gtime_t t, char *s, int n)
Convert gtime_t struct to string.
Definition mrtk_time.c:507
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
Definition mrtk_time.c:279
double time2gpst(gtime_t t, int *week)
Convert gtime_t to GPS week/tow.
Definition mrtk_time.c:181
int adjgpsweek(int week)
Adjust GPS week number using CPU time.
Definition mrtk_time.c:553
gtime_t bdt2gpst(gtime_t t)
Convert BeiDou time to GPS time.
Definition mrtk_time.c:465
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
double OMG0
Definition mrtk_eph.h:90
double omg
Definition mrtk_eph.h:90
int sat
Definition mrtk_eph.h:78
gtime_t ttr
Definition mrtk_eph.h:88
double OMGd
Definition mrtk_eph.h:90
double f1
Definition mrtk_eph.h:94
double f0
Definition mrtk_eph.h:94
int svh
Definition mrtk_eph.h:81
double e
Definition mrtk_eph.h:90
double idot
Definition mrtk_eph.h:90
double M0
Definition mrtk_eph.h:90
double A
Definition mrtk_eph.h:90
double cis
Definition mrtk_eph.h:91
int flag
Definition mrtk_eph.h:86
gtime_t toe
Definition mrtk_eph.h:88
double fit
Definition mrtk_eph.h:93
int week
Definition mrtk_eph.h:82
gtime_t toc
Definition mrtk_eph.h:88
double cic
Definition mrtk_eph.h:91
double tgd[6]
Definition mrtk_eph.h:95
double cus
Definition mrtk_eph.h:91
double cuc
Definition mrtk_eph.h:91
double toes
Definition mrtk_eph.h:92
int code
Definition mrtk_eph.h:83
int type
Definition mrtk_eph.h:100
double crs
Definition mrtk_eph.h:91
double i0
Definition mrtk_eph.h:90
int iode
Definition mrtk_eph.h:79
int sva
Definition mrtk_eph.h:80
double deln
Definition mrtk_eph.h:90
double crc
Definition mrtk_eph.h:91
double f2
Definition mrtk_eph.h:94
int iodc
Definition mrtk_eph.h:79
GLONASS broadcast ephemeris type.
Definition mrtk_eph.h:111
double vel[3]
Definition mrtk_eph.h:121
double dtaun
Definition mrtk_eph.h:124
gtime_t toe
Definition mrtk_eph.h:118
double pos[3]
Definition mrtk_eph.h:120
int sva
Definition mrtk_eph.h:117
int flags
Definition mrtk_eph.h:116
int iode
Definition mrtk_eph.h:113
double gamn
Definition mrtk_eph.h:123
double acc[3]
Definition mrtk_eph.h:122
int age
Definition mrtk_eph.h:117
int svh
Definition mrtk_eph.h:115
double taun
Definition mrtk_eph.h:123
gtime_t tof
Definition mrtk_eph.h:119
int sat
Definition mrtk_eph.h:112
int frq
Definition mrtk_eph.h:114
GNSS time representation.
Definition mrtk_time.h:49
time_t time
Definition mrtk_time.h:50
int glo_fcn[32]
Definition mrtk_nav.h:426
double utc_qzs[8]
Definition mrtk_nav.h:417
double utc_gal[8]
Definition mrtk_nav.h:416
double utc_gps[8]
Definition mrtk_nav.h:414
geph_t * geph
Definition mrtk_nav.h:407
double ion_gal[4]
Definition mrtk_nav.h:422
eph_t * eph
Definition mrtk_nav.h:400
double ion_gps[8]
Definition mrtk_nav.h:421
double ion_qzs[8]
Definition mrtk_nav.h:423
Observation data collection.
Definition mrtk_obs.h:59
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
uint8_t subfrm[MAXSAT][380]
Definition mrtk_rcvraw.h:89
nav_t nav
Definition mrtk_rcvraw.h:83
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
uint8_t halfc[MAXSAT][5+5]
Definition mrtk_rcvraw.h:93
char opt[256]
gtime_t tobs[MAXSAT][5+5]
Definition mrtk_rcvraw.h:80
int ephsat
Definition mrtk_rcvraw.h:85
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