MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_rcv_ublox.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_rcv_ublox.c : u-blox 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_madoca.h"
25#include "mrtklib/mrtk_mat.h"
26#include "mrtklib/mrtk_nav.h"
27#include "mrtklib/mrtk_obs.h"
28#include "mrtklib/mrtk_rcvraw.h"
29#include "mrtklib/mrtk_rtcm.h"
30#include "mrtklib/mrtk_sbas.h"
31#include "mrtklib/mrtk_sys.h"
32#include "mrtklib/mrtk_time.h"
33#include "mrtklib/mrtk_trace.h"
34
35/* Local constants (duplicated from rtklib.h to avoid dependency) */
36#define PI 3.1415926535897932 /* pi */
37#define D2R (PI / 180.0) /* deg to rad */
38#define R2D (180.0 / PI) /* rad to deg */
39#define CLIGHT 299792458.0 /* speed of light (m/s) */
40#define SC2RAD 3.1415926535898 /* semi-circle to radian (IS-GPS) */
41
42#define SYS_NONE 0x00
43#define SYS_GPS 0x01
44#define SYS_SBS 0x02
45#define SYS_GLO 0x04
46#define SYS_GAL 0x08
47#define SYS_QZS 0x10
48#define SYS_CMP 0x20
49#define SYS_IRN 0x40
50
51#define TSYS_GPS 0
52#define TSYS_UTC 1
53#define TSYS_GLO 2
54#define TSYS_GAL 3
55#define TSYS_QZS 4
56#define TSYS_CMP 5
57#define TSYS_IRN 6
58
59#define FREQ1 1.57542E9 /* L1/E1/B1C frequency (Hz) */
60#define FREQ2 1.22760E9 /* L2 frequency (Hz) */
61#define FREQ5 1.17645E9 /* L5/E5a/B2a frequency (Hz) */
62#define FREQ6 1.27875E9 /* E6/L6 frequency (Hz) */
63#define FREQ7 1.20714E9 /* E5b/B2I frequency (Hz) */
64#define FREQ8 1.191795E9 /* E5ab/B2ab frequency (Hz) */
65#define FREQ9 2.492028E9 /* S frequency (Hz) */
66#define FREQ1_GLO 1.60200E9 /* GLONASS G1 base frequency (Hz) */
67#define DFRQ1_GLO 0.56250E6 /* GLONASS G1 bias frequency (Hz/n) */
68#define FREQ2_GLO 1.24600E9 /* GLONASS G2 base frequency (Hz) */
69#define DFRQ2_GLO 0.43750E6 /* GLONASS G2 bias frequency (Hz/n) */
70#define FREQ3_GLO 1.202025E9 /* GLONASS G3 frequency (Hz) */
71#define FREQ1a_GLO 1.600995E9 /* GLONASS G1a frequency (Hz) */
72#define FREQ2a_GLO 1.248060E9 /* GLONASS G2a frequency (Hz) */
73#define FREQ1_CMP 1.561098E9 /* BDS B1I frequency (Hz) */
74
75#define MINPRNGPS 1
76#define MAXPRNGPS 32
77#define MINPRNSBS 120
78#define MAXPRNSBS 158
79
80#define LLI_SLIP 0x01 /* LLI: cycle-slip */
81#define LLI_HALFC 0x02 /* LLI: half-cycle not resolved */
82#define LLI_BOCTRK 0x04 /* LLI: boc tracking of mboc signal */
83#define LLI_HALFA 0x40 /* LLI: half-cycle added */
84#define LLI_HALFS 0x80 /* LLI: half-cycle subtracted */
85
86/* Power-of-2 constants */
87#define P2_5 0.03125
88#define P2_6 0.015625
89#define P2_11 4.882812500000000E-04
90#define P2_15 3.051757812500000E-05
91#define P2_17 7.629394531250000E-06
92#define P2_19 1.907348632812500E-06
93#define P2_20 9.536743164062500E-07
94#define P2_21 4.768371582031250E-07
95#define P2_23 1.192092895507810E-07
96#define P2_24 5.960464477539063E-08
97#define P2_27 7.450580596923828E-09
98#define P2_29 1.862645149230957E-09
99#define P2_30 9.313225746154785E-10
100#define P2_31 4.656612873077393E-10
101#define P2_32 2.328306436538696E-10
102#define P2_33 1.164153218269348E-10
103#define P2_34 5.820766091346740E-11
104#define P2_35 2.910383045673370E-11
105#define P2_38 3.637978807091710E-12
106#define P2_40 9.094947017729280E-13
107#define P2_43 1.136868377216160E-13
108#define P2_46 1.421085471520200E-14
109#define P2_50 8.881784197001252E-16
110#define P2_55 2.775557561562891E-17
111#define P2_59 1.734723475976810E-18
112
113/* Forward declarations for functions in rtklib (resolved at link time) */
114
115#define UBXSYNC1 0xB5 /* ubx message sync code 1 */
116#define UBXSYNC2 0x62 /* ubx message sync code 2 */
117#define UBXCFG 0x06 /* ubx message cfg-??? */
118
119#define PREAMB_CNAV 0x8B /* cnav preamble */
120
121#define ID_NAVSOL 0x0106 /* ubx message id: nav solution info */
122#define ID_NAVTIME 0x0120 /* ubx message id: nav time gps */
123#define ID_RXMRAW 0x0210 /* ubx message id: raw measurement data */
124#define ID_RXMSFRB 0x0211 /* ubx message id: subframe buffer */
125#define ID_RXMSFRBX 0x0213 /* ubx message id: raw subframe data */
126#define ID_RXMRAWX 0x0215 /* ubx message id: multi-gnss raw meas data */
127#define ID_RXMQZSSL6 0x0273 /* ubx message id: qzss L6 message */
128#define ID_TRKD5 0x030A /* ubx message id: trace mesurement data */
129#define ID_TRKMEAS 0x0310 /* ubx message id: trace mesurement data */
130#define ID_TRKSFRBX 0x030F /* ubx message id: trace subframe buffer */
131
132#define FU1 1 /* ubx message field types */
133#define FU2 2
134#define FU4 3
135#define FI1 4
136#define FI2 5
137#define FI4 6
138#define FR4 7
139#define FR8 8
140#define FS32 9
141
142#define P2_10 0.0009765625 /* 2^-10 */
143
144#if 0
145#define CPSTD_VALID 5 /* std-dev threshold of carrier-phase valid */
146#else
147#define CPSTD_VALID 14 /* std-dev threshold of carrier-phase valid */
148#endif
149
150#define ROUND(x) (int)floor((x) + 0.5)
151
152/* get fields (little-endian) ------------------------------------------------*/
153#define U1(p) (*((uint8_t*)(p)))
154#define I1(p) (*((int8_t*)(p)))
155static uint16_t U2(uint8_t* p) {
156 uint16_t u;
157 memcpy(&u, p, 2);
158 return u;
159}
160static uint32_t U4(uint8_t* p) {
161 uint32_t u;
162 memcpy(&u, p, 4);
163 return u;
164}
165static int32_t I4(uint8_t* p) {
166 int32_t u;
167 memcpy(&u, p, 4);
168 return u;
169}
170static float R4(uint8_t* p) {
171 float r;
172 memcpy(&r, p, 4);
173 return r;
174}
175static double R8(uint8_t* p) {
176 double r;
177 memcpy(&r, p, 8);
178 return r;
179}
180static double I8(uint8_t* p) { return I4(p + 4) * 4294967296.0 + U4(p); }
181
182/* set fields (little-endian) ------------------------------------------------*/
183static void setU1(uint8_t* p, uint8_t u) { *p = u; }
184static void setU2(uint8_t* p, uint16_t u) { memcpy(p, &u, 2); }
185static void setU4(uint8_t* p, uint32_t u) { memcpy(p, &u, 4); }
186static void setI1(uint8_t* p, int8_t i) { *p = (uint8_t)i; }
187static void setI2(uint8_t* p, int16_t i) { memcpy(p, &i, 2); }
188static void setI4(uint8_t* p, int32_t i) { memcpy(p, &i, 4); }
189static void setR4(uint8_t* p, float r) { memcpy(p, &r, 4); }
190static void setR8(uint8_t* p, double r) { memcpy(p, &r, 8); }
191
192/* checksum ------------------------------------------------------------------*/
193static int checksum(uint8_t* buff, int len) {
194 uint8_t cka = 0, ckb = 0;
195 int i;
196
197 for (i = 2; i < len - 2; i++) {
198 cka += buff[i];
199 ckb += cka;
200 }
201 return cka == buff[len - 2] && ckb == buff[len - 1];
202}
203static void setcs(uint8_t* buff, int len) {
204 uint8_t cka = 0, ckb = 0;
205 int i;
206
207 for (i = 2; i < len - 2; i++) {
208 cka += buff[i];
209 ckb += cka;
210 }
211 buff[len - 2] = cka;
212 buff[len - 1] = ckb;
213}
214/* UBX GNSSId to system (ref [2] 25) -----------------------------------------*/
215static int ubx_sys(int gnssid) {
216 switch (gnssid) {
217 case 0:
218 return SYS_GPS;
219 case 1:
220 return SYS_SBS;
221 case 2:
222 return SYS_GAL;
223 case 3:
224 return SYS_CMP;
225 case 5:
226 return SYS_QZS;
227 case 6:
228 return SYS_GLO;
229 }
230 return 0;
231}
232/* UBX SigId to signal (ref [5] 1.5.4) ---------------------------------------*/
233static int ubx_sig(int sys, int sigid) {
234 if (sys == SYS_GPS) {
235 if (sigid == 0) {
236 return CODE_L1C; /* L1C/A */
237 }
238 if (sigid == 3) {
239 return CODE_L2L; /* L2CL */
240 }
241 if (sigid == 4) {
242 return CODE_L2S; /* L2CM */
243 }
244 if (sigid == 7) {
245 return CODE_L5Q; /* L5Q */
246 }
247 } else if (sys == SYS_GLO) {
248 if (sigid == 0) {
249 return CODE_L1C; /* G1C/A (GLO L1 OF) */
250 }
251 if (sigid == 2) {
252 return CODE_L2C; /* G2C/A (GLO L2 OF) */
253 }
254 } else if (sys == SYS_GAL) {
255 if (sigid == 0) {
256 return CODE_L1C; /* E1C */
257 }
258 if (sigid == 1) {
259 return CODE_L1B; /* E1B */
260 }
261 if (sigid == 4) {
262 return CODE_L5Q; /* E5aQ */
263 }
264 if (sigid == 5) {
265 return CODE_L7I; /* E5bI */
266 }
267 if (sigid == 6) {
268 return CODE_L7Q; /* E5bQ */
269 }
270 if (sigid == 8) {
271 return CODE_L6B; /* E6B (X20) */
272 }
273 } else if (sys == SYS_QZS) {
274 if (sigid == 0) {
275 return CODE_L1C; /* L1C/A */
276 }
277 if (sigid == 1) {
278 return CODE_L1Z; /* L1S */
279 }
280 if (sigid == 4) {
281 return CODE_L2S; /* L2CM */
282 }
283 if (sigid == 5) {
284 return CODE_L2L; /* L2CL */
285 }
286 if (sigid == 9) {
287 return CODE_L5Q; /* L5Q */
288 }
289 } else if (sys == SYS_CMP) {
290 if (sigid == 0) {
291 return CODE_L2I; /* B1I D1 */
292 }
293 if (sigid == 1) {
294 return CODE_L2I; /* B1I D2 */
295 }
296 if (sigid == 2) {
297 return CODE_L7I; /* B2I D1 */
298 }
299 if (sigid == 3) {
300 return CODE_L7I; /* B2I D2 */
301 }
302 if (sigid == 4) {
303 return CODE_L6I; /* B3I (X20) */
304 }
305 if (sigid == 5) {
306 return CODE_L1P; /* B1C pilot (X20) */
307 }
308 if (sigid == 7) {
309 return CODE_L5P; /* B2a pilot (X20) */
310 }
311 } else if (sys == SYS_SBS) {
312 if (sigid == 0) {
313 return CODE_L1C; /* L1C/A */
314 }
315 }
316 return CODE_NONE;
317}
318/* signal index in obs data --------------------------------------------------*/
319static int sig_idx(int sys, uint8_t code) {
320 int idx = code2freq_idx(sys, code), nex = NEXOBS;
321
322 if (sys == SYS_GPS) {
323 if (code == CODE_L2S) {
324 return (nex < 1) ? -1 : NFREQ; /* L2CM */
325 }
326 } else if (sys == SYS_GAL) {
327 if (code == CODE_L1B) {
328 return (nex < 1) ? -1 : NFREQ; /* E1B */
329 }
330 if (code == CODE_L7I) {
331 return (nex < 2) ? -1 : NFREQ + 1; /* E5bI */
332 }
333 } else if (sys == SYS_QZS) {
334 if (code == CODE_L2S) {
335 return (nex < 1) ? -1 : NFREQ; /* L2CM */
336 }
337 if (code == CODE_L1Z) {
338 return (nex < 2) ? -1 : NFREQ + 1; /* L1S */
339 }
340 }
341 return (idx < NFREQ) ? idx : -1;
342}
343/* decode UBX-RXM-RAW: raw measurement data ----------------------------------*/
344static int decode_rxmraw(raw_t* raw) {
345 uint8_t* p = raw->buff + 6;
346 gtime_t time;
347 double tow, tt, tadj = 0.0, toff = 0.0, tn;
348 int i, j, prn, sat, n = 0, nsat, week;
349 char* q;
350
351 if (raw->outtype) {
352 sprintf(raw->msgtype, "UBX RXM-RAW (%4d): nsat=%d", raw->len, U1(p + 6));
353 }
354 /* time tag adjustment option (-TADJ) */
355 if ((q = strstr(raw->opt, "-TADJ="))) {
356 sscanf(q, "-TADJ=%lf", &tadj);
357 }
358 nsat = U1(p + 6);
359 if (raw->len < 12 + 24 * nsat) {
360 trace(NULL, 2, "ubx rxmraw length error: len=%d nsat=%d\n", raw->len, nsat);
361 return -1;
362 }
363 tow = U4(p);
364 week = U2(p + 4);
365 time = gpst2time(week, tow * 0.001);
366
367 if (week == 0) {
368 trace(NULL, 3, "ubx rxmraw week=0 error: len=%d nsat=%d\n", raw->len, nsat);
369 return 0;
370 }
371 /* time tag adjustment */
372 if (tadj > 0.0) {
373 tn = time2gpst(time, &week) / tadj;
374 toff = (tn - floor(tn + 0.5)) * tadj;
375 time = timeadd(time, -toff);
376 }
377 tt = timediff(time, raw->time);
378
379 for (i = 0, p += 8; i < nsat && i < MAXOBS; i++, p += 24) {
380 raw->obs.data[n].time = time;
381 raw->obs.data[n].L[0] = R8(p) - toff * FREQ1;
382 raw->obs.data[n].P[0] = R8(p + 8) - toff * CLIGHT;
383 raw->obs.data[n].D[0] = R4(p + 16);
384 prn = U1(p + 20);
385 raw->obs.data[n].SNR[0] = (uint16_t)(I1(p + 22) * 1.0 / SNR_UNIT + 0.5);
386 raw->obs.data[n].LLI[0] = U1(p + 23);
387 raw->obs.data[n].code[0] = CODE_L1C;
388
389 /* phase polarity flip option (-INVCP) */
390 if (strstr(raw->opt, "-INVCP")) {
391 raw->obs.data[n].L[0] = -raw->obs.data[n].L[0];
392 }
393 if (!(sat = satno(MINPRNSBS <= prn ? SYS_SBS : SYS_GPS, prn))) {
394 trace(NULL, 2, "ubx rxmraw sat number error: prn=%d\n", prn);
395 continue;
396 }
397 raw->obs.data[n].sat = sat;
398
399 if (raw->obs.data[n].LLI[0] & 1) {
400 raw->lockt[sat - 1][0] = 0.0;
401 } else if (tt < 1.0 || 10.0 < tt) {
402 raw->lockt[sat - 1][0] = 0.0;
403 } else {
404 raw->lockt[sat - 1][0] += tt;
405 }
406
407 for (j = 1; j < NFREQ + NEXOBS; j++) {
408 raw->obs.data[n].L[j] = raw->obs.data[n].P[j] = 0.0;
409 raw->obs.data[n].D[j] = 0.0;
410 raw->obs.data[n].SNR[j] = raw->obs.data[n].LLI[j] = 0;
411 raw->obs.data[n].code[j] = CODE_NONE;
412 }
413 n++;
414 }
415 raw->time = time;
416 raw->obs.n = n;
417 return 1;
418}
419/* decode UBX-RXM-RAWX: multi-GNSS raw measurement data (ref [3][4][5]) ------*/
420static int decode_rxmrawx(raw_t* raw) {
421 uint8_t* p = raw->buff + 6;
422 gtime_t time;
423 char *q, tstr[64];
424 double tow, P, L, D, tn, tadj = 0.0, toff = 0.0;
425 int i, j, k, idx, sys, prn, sat, code, slip, halfv, halfc, LLI, n = 0, std_slip = 0;
426 int week, nmeas, ver, gnss, svid, sigid, frqid, lockt, cn0, cpstd, tstat;
427
428 if (raw->len < 24) {
429 trace(NULL, 2, "ubx rxmrawx length error: len=%d\n", raw->len);
430 return -1;
431 }
432 tow = R8(p); /* rcvTow (s) */
433 week = U2(p + 8); /* week */
434 nmeas = U1(p + 11); /* numMeas */
435 ver = U1(p + 13); /* version ([5] 5.15.3.1) */
436
437 if (raw->len < 24 + 32 * nmeas) {
438 trace(NULL, 2, "ubx rxmrawx length error: len=%d nmeas=%d\n", raw->len, nmeas);
439 return -1;
440 }
441 if (week == 0) {
442 trace(NULL, 3, "ubx rxmrawx week=0 error: len=%d nmeas=%d\n", raw->len, nmeas);
443 return 0;
444 }
445 time = gpst2time(week, tow);
446
447 if (raw->outtype) {
448 time2str(time, tstr, 2);
449 sprintf(raw->msgtype, "UBX RXM-RAWX (%4d): time=%s nmeas=%d ver=%d", raw->len, tstr, nmeas, ver);
450 }
451 /* time tag adjustment option (-TADJ) */
452 if ((q = strstr(raw->opt, "-TADJ="))) {
453 sscanf(q, "-TADJ=%lf", &tadj);
454 }
455 /* slip threshold of std-dev of carreir-phase (-STD_SLIP) */
456 if ((q = strstr(raw->opt, "-STD_SLIP="))) {
457 sscanf(q, "-STD_SLIP=%d", &std_slip);
458 }
459 /* time tag adjustment */
460 if (tadj > 0.0) {
461 tn = time2gpst(time, &week) / tadj;
462 toff = (tn - floor(tn + 0.5)) * tadj;
463 time = timeadd(time, -toff);
464 }
465 for (i = 0, p += 16; i < nmeas && n < MAXOBS; i++, p += 32) {
466 P = R8(p); /* prMes (m) */
467 L = R8(p + 8); /* cpMes (cyc) */
468 D = R4(p + 16); /* doMes (hz) */
469 gnss = U1(p + 20); /* gnssId */
470 svid = U1(p + 21); /* svId */
471 sigid = U1(p + 22); /* sigId ([5] 5.15.3.1) */
472 frqid = U1(p + 23); /* freqId (fcn + 7) */
473 lockt = U2(p + 24); /* locktime (ms) */
474 cn0 = U1(p + 26); /* cn0 (dBHz) */
475 cpstd = U1(p + 28) & 15; /* cpStdev (m) */
476 tstat = U1(p + 30); /* trkStat */
477 if (!(tstat & 1)) {
478 P = 0.0;
479 }
480 if (!(tstat & 2) || L == -0.5 || cpstd > CPSTD_VALID) {
481 L = 0.0;
482 }
483
484 if (!(sys = ubx_sys(gnss))) {
485 trace(NULL, 2, "ubx rxmrawx: system error gnss=%d\n", gnss);
486 continue;
487 }
488 prn = svid + (sys == SYS_QZS ? 192 : 0);
489 if (!(sat = satno(sys, prn))) {
490 if (sys == SYS_GLO && prn == 255) {
491 continue; /* suppress warning for unknown glo satellite */
492 }
493 trace(NULL, 2, "ubx rxmrawx sat number error: sys=%2d prn=%2d\n", sys, prn);
494 continue;
495 }
496 if (sys == SYS_GLO && !raw->nav.glo_fcn[prn - 1]) {
497 raw->nav.glo_fcn[prn - 1] = frqid - 7 + 8;
498 }
499 if (ver >= 1) {
500 code = ubx_sig(sys, sigid);
501 } else {
502 code = (sys == SYS_CMP) ? CODE_L2I : ((sys == SYS_GAL) ? CODE_L1X : CODE_L1C);
503 }
504 /* signal index in obs data */
505 if ((idx = sig_idx(sys, code)) < 0) {
506 trace(NULL, 2, "ubx rxmrawx signal error: sat=%2d sigid=%d\n", sat, sigid);
507 continue;
508 }
509 /* offset by time tag adjustment */
510 if (toff != 0.0) {
511 if (P != 0.0) {
512 P -= toff * CLIGHT;
513 }
514 if (L != 0.0) {
515 L -= toff * code2freq(sys, code, frqid - 7);
516 }
517 }
518 /* half-cycle shift correction for BDS GEO */
519 if (sys == SYS_CMP && (prn <= 5 || prn >= 59) && L != 0.0) {
520 L += 0.5;
521 }
522 halfv = (tstat & 4) ? 1 : 0; /* half cycle valid */
523 halfc = (tstat & 8) ? 1 : 0; /* half cycle subtracted from phase */
524 slip = lockt == 0 || lockt * 1E-3 < raw->lockt[sat - 1][idx] || halfc != raw->halfc[sat - 1][idx] ||
525 (std_slip && cpstd >= std_slip);
526 raw->lockt[sat - 1][idx] = lockt * 1E-3;
527 raw->halfc[sat - 1][idx] = halfc;
528 LLI = (slip ? LLI_SLIP : 0) | (!halfv ? LLI_HALFC : 0) | (halfc ? LLI_HALFS : 0);
529
530 for (j = 0; j < n; j++) {
531 if (raw->obs.data[j].sat == sat) {
532 break;
533 }
534 }
535 if (j >= n) {
536 raw->obs.data[n].time = time;
537 raw->obs.data[n].sat = sat;
538 raw->obs.data[n].rcv = 0;
539 for (k = 0; k < NFREQ + NEXOBS; k++) {
540 raw->obs.data[n].L[k] = raw->obs.data[n].P[k] = 0.0;
541 raw->obs.data[n].D[k] = 0.0;
542 raw->obs.data[n].SNR[k] = raw->obs.data[n].LLI[k] = 0;
543 raw->obs.data[n].code[k] = CODE_NONE;
544 }
545 n++;
546 }
547 raw->obs.data[j].L[idx] = L;
548 raw->obs.data[j].P[idx] = P;
549 raw->obs.data[j].D[idx] = (float)D;
550 raw->obs.data[j].SNR[idx] = (uint16_t)(cn0 * 1.0 / SNR_UNIT + 0.5);
551 raw->obs.data[j].LLI[idx] = (uint8_t)LLI;
552 raw->obs.data[j].code[idx] = (uint8_t)code;
553 }
554 raw->time = time;
555 raw->obs.n = n;
556 return 1;
557}
558/* decode UBX-NAV-SOL: navigation solution -----------------------------------*/
559static int decode_navsol(raw_t* raw) {
560 uint8_t* p = raw->buff + 6;
561 int itow, ftow, week;
562
563 trace(NULL, 4, "decode_navsol: len=%d\n", raw->len);
564
565 if (raw->outtype) {
566 sprintf(raw->msgtype, "UBX NAV-SOL (%4d):", raw->len);
567 }
568 itow = U4(p);
569 ftow = I4(p + 4);
570 week = U2(p + 8);
571 if ((U1(p + 11) & 0x0C) == 0x0C) {
572 raw->time = gpst2time(week, itow * 1E-3 + ftow * 1E-9);
573 }
574 return 0;
575}
576/* decode UBX-NAV-TIMEGPS: GPS time solution ---------------------------------*/
577static int decode_navtime(raw_t* raw) {
578 double ep[6];
579 int itow, ftow, week;
580 char str[32];
581 uint8_t* p = raw->buff + 6;
582
583 trace(NULL, 4, "decode_navtime: len=%d\n", raw->len);
584
585 itow = U4(p);
586 ftow = I4(p + 4);
587 week = U2(p + 8);
588 if ((U1(p + 11) & 0x03) == 0x03) {
589 raw->time = gpst2time(week, itow * 1E-3 + ftow * 1E-9);
590 }
591 if (raw->outtype) {
592 time2str(raw->time, str, 3);
593 sprintf(raw->msgtype, "UBX NAV-TIME (%4d): time=%s", raw->len, str);
594 }
595 if (strstr(raw->opt, "-OUT_QZSSL6")) {
596 time2epoch(gpst2utc(raw->time), ep);
597 trace(NULL, 2, "$TIME,%.0f,%.0f,%.0f,%.0f,%.0f,%.6f\n", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]);
598 }
599 return 0;
600}
601/* decode UBX-TRK-MEAS: trace measurement data (unofficial) ------------------*/
602static int decode_trkmeas(raw_t* raw) {
603 static double adrs[MAXSAT] = {0};
604 uint8_t* p = raw->buff + 6;
605 gtime_t time;
606 double ts, tr = -1.0, t, tau, utc_gpst, snr, adr, dop;
607 int i, j, n = 0, nch, sys, prn, sat, qi, frq, flag, lock1, lock2, week;
608
609 trace(NULL, 4, "decode_trkmeas: len=%d\n", raw->len);
610
611 if (raw->outtype) {
612 sprintf(raw->msgtype, "UBX TRK-MEAS (%4d):", raw->len);
613 }
614 if (!raw->time.time) {
615 return 0;
616 }
617
618 /* number of channels */
619 nch = U1(p + 2);
620
621 if (raw->len < 112 + nch * 56) {
622 trace(NULL, 2, "decode_trkmeas: length error len=%d nch=%2d\n", raw->len, nch);
623 return -1;
624 }
625 /* time-tag = max(transmission time + 0.08) rounded by 100 ms */
626 for (i = 0, p = raw->buff + 110; i < nch; i++, p += 56) {
627 if (U1(p + 1) < 4 || ubx_sys(U1(p + 4)) != SYS_GPS) {
628 continue;
629 }
630 if ((t = I8(p + 24) * P2_32 / 1000.0) > tr) {
631 tr = t;
632 }
633 }
634 if (tr < 0.0) {
635 return 0;
636 }
637
638 tr = ROUND((tr + 0.08) / 0.1) * 0.1;
639
640 /* adjust week handover */
641 t = time2gpst(raw->time, &week);
642 if (tr < t - 302400.0) {
643 week++;
644 } else if (tr > t + 302400.0) {
645 week--;
646 }
647 time = gpst2time(week, tr);
648
649 utc_gpst = timediff(gpst2utc(time), time);
650
651 for (i = 0, p = raw->buff + 110; i < nch; i++, p += 56) {
652 /* quality indicator (0:idle,1:search,2:aquired,3:unusable, */
653 /* 4:code lock,5,6,7:code/carrier lock) */
654 qi = U1(p + 1);
655 if (qi < 4 || 7 < qi) {
656 continue;
657 }
658
659 /* system and satellite number */
660 if (!(sys = ubx_sys(U1(p + 4)))) {
661 trace(NULL, 2, "ubx trkmeas: system error\n");
662 continue;
663 }
664 prn = U1(p + 5) + (sys == SYS_QZS ? 192 : 0);
665 if (!(sat = satno(sys, prn))) {
666 trace(NULL, 2, "ubx trkmeas sat number error: sys=%2d prn=%2d\n", sys, prn);
667 continue;
668 }
669 /* transmission time */
670 ts = I8(p + 24) * P2_32 / 1000.0;
671 if (sys == SYS_CMP) {
672 ts += 14.0; /* bdt -> gpst */
673 } else if (sys == SYS_GLO) {
674 ts -= 10800.0 + utc_gpst; /* glot -> gpst */
675 }
676
677 /* signal travel time */
678 tau = tr - ts;
679 if (tau < -302400.0) {
680 tau += 604800.0;
681 } else if (tau > 302400.0) {
682 tau -= 604800.0;
683 }
684
685 frq = U1(p + 7) - 7; /* frequency */
686 flag = U1(p + 8); /* tracking status */
687 lock1 = U1(p + 16); /* code lock count */
688 lock2 = U1(p + 17); /* phase lock count */
689 snr = U2(p + 20) / 256.0;
690 adr = I8(p + 32) * P2_32 + (flag & 0x40 ? 0.5 : 0.0);
691 dop = I4(p + 40) * P2_10 * 10.0;
692
693 /* set slip flag */
694 if (lock2 == 0 || lock2 < raw->lockt[sat - 1][0]) {
695 raw->lockt[sat - 1][1] = 1.0;
696 }
697 raw->lockt[sat - 1][0] = lock2;
698
699#if 0 /* for debug */
700 trace(NULL,2,"[%2d] qi=%d sys=%d prn=%3d frq=%2d flag=%02X ?=%02X %02X "
701 "%02X %02X %02X %02X %02X lock=%3d %3d ts=%10.3f snr=%4.1f "
702 "dop=%9.3f adr=%13.3f %6.3f\n",U1(p),qi,U1(p+4),prn,frq,flag,
703 U1(p+9),U1(p+10),U1(p+11),U1(p+12),U1(p+13),U1(p+14),U1(p+15),
704 lock1,lock2,ts,snr,dop,adr,
705 adrs[sat-1]==0.0||dop==0.0?0.0:(adr-adrs[sat-1])-dop);
706#endif
707 adrs[sat - 1] = adr;
708
709 /* check phase lock */
710 if (!(flag & 0x20)) {
711 continue;
712 }
713
714 raw->obs.data[n].time = time;
715 raw->obs.data[n].sat = sat;
716 raw->obs.data[n].P[0] = tau * CLIGHT;
717 raw->obs.data[n].L[0] = -adr;
718 raw->obs.data[n].D[0] = (float)dop;
719 raw->obs.data[n].SNR[0] = (uint16_t)(snr / SNR_UNIT + 0.5);
720 raw->obs.data[n].code[0] = sys == SYS_CMP ? CODE_L2I : CODE_L1C;
721 raw->obs.data[n].LLI[0] = raw->lockt[sat - 1][1] > 0.0 ? 1 : 0;
722 if (sys == SYS_SBS) { /* half-cycle valid */
723 raw->obs.data[n].LLI[0] |= lock2 > 142 ? 0 : 2;
724 } else {
725 raw->obs.data[n].LLI[0] |= flag & 0x80 ? 0 : 2;
726 }
727 raw->lockt[sat - 1][1] = 0.0;
728
729 for (j = 1; j < NFREQ + NEXOBS; j++) {
730 raw->obs.data[n].L[j] = raw->obs.data[n].P[j] = 0.0;
731 raw->obs.data[n].D[j] = 0.0;
732 raw->obs.data[n].SNR[j] = raw->obs.data[n].LLI[j] = 0;
733 raw->obs.data[n].code[j] = CODE_NONE;
734 }
735 n++;
736 }
737 if (n <= 0) {
738 return 0;
739 }
740 raw->time = time;
741 raw->obs.n = n;
742 return 1;
743}
744/* decode UBX-TRKD5: trace measurement data (unofficial) ---------------------*/
745static int decode_trkd5(raw_t* raw) {
746 static double adrs[MAXSAT] = {0};
747 gtime_t time;
748 double ts, tr = -1.0, t, tau, adr, dop, snr, utc_gpst;
749 int i, j, n = 0, type, off, len, sys, prn, sat, qi, frq, flag, week;
750 uint8_t* p = raw->buff + 6;
751
752 trace(NULL, 4, "decode_trkd5: len=%d\n", raw->len);
753
754 if (raw->outtype) {
755 sprintf(raw->msgtype, "UBX TRK-D5 (%4d):", raw->len);
756 }
757 if (!raw->time.time) {
758 return 0;
759 }
760
761 utc_gpst = timediff(gpst2utc(raw->time), raw->time);
762
763 switch ((type = U1(p))) {
764 case 3:
765 off = 86;
766 len = 56;
767 break;
768 case 6:
769 off = 86;
770 len = 64;
771 break; /* u-blox 7 */
772 default:
773 off = 78;
774 len = 56;
775 break;
776 }
777 for (i = 0, p = raw->buff + off; p - raw->buff < raw->len - 2; i++, p += len) {
778 qi = U1(p + 41) & 7;
779 if (qi < 4 || 7 < qi) {
780 continue;
781 }
782 t = I8(p) * P2_32 / 1000.0;
783 if (ubx_sys(U1(p + 56)) == SYS_GLO) {
784 t -= 10800.0 + utc_gpst;
785 }
786 if (t > tr) {
787 tr = t;
788 break;
789 }
790 }
791 if (tr < 0.0) {
792 return 0;
793 }
794
795 tr = ROUND((tr + 0.08) / 0.1) * 0.1;
796
797 /* adjust week handover */
798 t = time2gpst(raw->time, &week);
799 if (tr < t - 302400.0) {
800 week++;
801 } else if (tr > t + 302400.0) {
802 week--;
803 }
804 time = gpst2time(week, tr);
805
806 trace(NULL, 4, "time=%s\n", time_str(time, 0));
807
808 for (i = 0, p = raw->buff + off; p - raw->buff < raw->len - 2; i++, p += len) {
809 /* quality indicator */
810 qi = U1(p + 41) & 7;
811 if (qi < 4 || 7 < qi) {
812 continue;
813 }
814
815 if (type == 6) {
816 if (!(sys = ubx_sys(U1(p + 56)))) {
817 trace(NULL, 2, "ubx trkd5: system error\n");
818 continue;
819 }
820 prn = U1(p + 57) + (sys == SYS_QZS ? 192 : 0);
821 frq = U1(p + 59) - 7;
822 } else {
823 prn = U1(p + 34);
824 sys = prn < MINPRNSBS ? SYS_GPS : SYS_SBS;
825 }
826 if (!(sat = satno(sys, prn))) {
827 trace(NULL, 2, "ubx trkd5 sat number error: sys=%2d prn=%2d\n", sys, prn);
828 continue;
829 }
830 /* transmission time */
831 ts = I8(p) * P2_32 / 1000.0;
832 if (sys == SYS_GLO) {
833 ts -= 10800.0 + utc_gpst; /* glot -> gpst */
834 }
835
836 /* signal travel time */
837 tau = tr - ts;
838 if (tau < -302400.0) {
839 tau += 604800.0;
840 } else if (tau > 302400.0) {
841 tau -= 604800.0;
842 }
843
844 flag = U1(p + 54); /* tracking status */
845 if (qi < 6) {
846 adr = 0.0;
847 } else {
848 adr = I8(p + 8) * P2_32;
849 if (flag & 0x01) {
850 adr += 0.5;
851 }
852 }
853 dop = I4(p + 16) * P2_10 / 4.0;
854 snr = U2(p + 32) / 256.0;
855
856 if (snr <= 10.0) {
857 raw->lockt[sat - 1][1] = 1.0;
858 }
859
860#if 0 /* for debug */
861 trace(NULL,2,"[%2d] qi=%d sys=%d prn=%3d frq=%2d flag=%02X ts=%1.3f "
862 "snr=%4.1f dop=%9.3f adr=%13.3f %6.3f\n",U1(p+35),qi,U1(p+56),
863 prn,frq,flag,ts,snr,dop,adr,
864 adrs[sat-1]==0.0||dop==0.0?0.0:(adr-adrs[sat-1])-dop);
865#endif
866 adrs[sat - 1] = adr;
867
868 /* check phase lock */
869 if (!(flag & 0x08)) {
870 continue;
871 }
872
873 raw->obs.data[n].time = time;
874 raw->obs.data[n].sat = sat;
875 raw->obs.data[n].P[0] = tau * CLIGHT;
876 raw->obs.data[n].L[0] = -adr;
877 raw->obs.data[n].D[0] = (float)dop;
878 raw->obs.data[n].SNR[0] = (uint16_t)(snr / SNR_UNIT + 0.5);
879 raw->obs.data[n].code[0] = sys == SYS_CMP ? CODE_L2I : CODE_L1C;
880 raw->obs.data[n].LLI[0] = raw->lockt[sat - 1][1] > 0.0 ? 1 : 0;
881 raw->lockt[sat - 1][1] = 0.0;
882
883 for (j = 1; j < NFREQ + NEXOBS; j++) {
884 raw->obs.data[n].L[j] = raw->obs.data[n].P[j] = 0.0;
885 raw->obs.data[n].D[j] = 0.0;
886 raw->obs.data[n].SNR[j] = raw->obs.data[n].LLI[j] = 0;
887 raw->obs.data[n].code[j] = CODE_NONE;
888 }
889 n++;
890 }
891 if (n <= 0) {
892 return 0;
893 }
894 raw->time = time;
895 raw->obs.n = n;
896 return 1;
897}
898/* UTC 8-bit week -> full week -----------------------------------------------*/
899static void adj_utcweek(gtime_t time, double* utc) {
900 int week;
901
902 time2gpst(time, &week);
903 utc[3] += week / 256 * 256;
904 if (utc[3] < week - 127) {
905 utc[3] += 256.0;
906 } else if (utc[3] > week + 127) {
907 utc[3] -= 256.0;
908 }
909 utc[5] += utc[3] / 256 * 256;
910 if (utc[5] < utc[3] - 127) {
911 utc[5] += 256.0;
912 } else if (utc[5] > utc[3] + 127) {
913 utc[5] -= 256.0;
914 }
915}
916/* decode GPS/QZSS ephemeris -------------------------------------------------*/
917static int decode_eph(raw_t* raw, int sat) {
918 eph_t eph = {0};
919
920 if (!decode_frame(raw->subfrm[sat - 1], &eph, NULL, NULL, NULL)) {
921 return 0;
922 }
923
924 if (!strstr(raw->opt, "-EPHALL")) {
925 if (eph.iode == raw->nav.eph[sat - 1].iode && eph.iodc == raw->nav.eph[sat - 1].iodc &&
926 timediff(eph.toe, raw->nav.eph[sat - 1].toe) == 0.0 &&
927 timediff(eph.toc, raw->nav.eph[sat - 1].toc) == 0.0) {
928 return 0;
929 }
930 }
931 eph.sat = sat;
932 raw->nav.eph[sat - 1] = eph;
933 raw->ephsat = sat;
934 raw->ephset = 0;
935 return 2;
936}
937/* decode GPS/QZSS ION/UTC parameters ----------------------------------------*/
938static int decode_ionutc(raw_t* raw, int sat) {
939 double ion[8], utc[8];
940 int sys = satsys(sat, NULL);
941
942 if (!decode_frame(raw->subfrm[sat - 1], NULL, NULL, ion, utc)) {
943 return 0;
944 }
945
946 adj_utcweek(raw->time, utc);
947 if (sys == SYS_QZS) {
948 matcpy(raw->nav.ion_qzs, ion, 8, 1);
949 matcpy(raw->nav.utc_qzs, utc, 8, 1);
950 } else {
951 matcpy(raw->nav.ion_gps, ion, 8, 1);
952 matcpy(raw->nav.utc_gps, utc, 8, 1);
953 }
954 return 9;
955}
956/* decode GPS/QZSS navigation data -------------------------------------------*/
957static int decode_nav(raw_t* raw, int sat, int off) {
958 uint8_t *p = raw->buff + 6 + off, buff[30];
959 int i, id, ret;
960
961 if (raw->len < 48 + off) {
962 trace(NULL, 2, "ubx rxmsfrbx nav length error: sat=%d len=%d\n", sat, raw->len);
963 return -1;
964 }
965 if ((U4(p) >> 24) == PREAMB_CNAV) {
966 trace(NULL, 3, "ubx rxmsfrbx nav unsupported sat=%d len=%d\n", sat, raw->len);
967 return 0;
968 }
969 for (i = 0; i < 10; i++, p += 4) { /* 24 x 10 bits w/o parity */
970 setbitu(buff, 24 * i, 24, U4(p) >> 6);
971 }
972 id = getbitu(buff, 43, 3);
973 if (id < 1 || id > 5) {
974 trace(NULL, 2, "ubx rxmsfrbx nav subframe id error: sat=%d id=%d\n", sat, id);
975 return -1;
976 }
977 memcpy(raw->subfrm[sat - 1] + (id - 1) * 30, buff, 30);
978
979 if (id == 3) {
980 return decode_eph(raw, sat);
981 }
982 if (id == 4 || id == 5) {
983 ret = decode_ionutc(raw, sat);
984 memset(raw->subfrm[sat - 1] + (id - 1) * 30, 0, 30);
985 return ret;
986 }
987 return 0;
988}
989/* decode Galileo I/NAV navigation data --------------------------------------*/
990static int decode_enav(raw_t* raw, int sat, int off) {
991 eph_t eph = {0};
992 double ion[4] = {0}, utc[8] = {0};
993 uint8_t *p = raw->buff + 6 + off, buff[32], crc_buff[26] = {0};
994 int i, j, part1, page1, part2, page2, type;
995
996 if (raw->len < 40 + off) {
997 trace(NULL, 2, "ubx rxmsfrbx enav length error: sat=%d len=%d\n", sat, raw->len);
998 return -1;
999 }
1000 for (i = 0; i < 8; i++, p += 4) {
1001 setbitu(buff, 32 * i, 32, U4(p));
1002 }
1003 part1 = getbitu(buff, 0, 1);
1004 page1 = getbitu(buff, 1, 1);
1005 part2 = getbitu(buff, 128, 1);
1006 page2 = getbitu(buff, 129, 1);
1007
1008 if (part1 != 0 || part2 != 1) {
1009 trace(NULL, 3, "ubx rxmsfrbx enav page even/odd error: sat=%d\n", sat);
1010 return -1;
1011 }
1012 if (page1 == 1 || page2 == 1) {
1013 return 0; /* alert page */
1014 }
1015
1016 /* test crc (4(pad) + 114 + 82 bits) */
1017 for (i = 0, j = 4; i < 15; i++, j += 8) {
1018 setbitu(crc_buff, j, 8, getbitu(buff, i * 8, 8));
1019 }
1020 for (i = 0, j = 118; i < 11; i++, j += 8) {
1021 setbitu(crc_buff, j, 8, getbitu(buff, i * 8 + 128, 8));
1022 }
1023 if (rtk_crc24q(crc_buff, 25) != getbitu(buff, 128 + 82, 24)) {
1024 trace(NULL, 2, "ubx rxmsfrbx enav crc error: sat=%d\n", sat);
1025 return -1;
1026 }
1027 type = getbitu(buff, 2, 6); /* word type */
1028
1029 if (type > 6) {
1030 return 0;
1031 }
1032
1033 /* save 128 (112:even+16:odd) bits word */
1034 for (i = 0, j = 2; i < 14; i++, j += 8) {
1035 raw->subfrm[sat - 1][type * 16 + i] = getbitu(buff, j, 8);
1036 }
1037 for (i = 14, j = 130; i < 16; i++, j += 8) {
1038 raw->subfrm[sat - 1][type * 16 + i] = getbitu(buff, j, 8);
1039 }
1040 if (type != 5) {
1041 return 0;
1042 }
1043 if (!decode_gal_inav(raw->subfrm[sat - 1], &eph, ion, utc)) {
1044 return 0;
1045 }
1046
1047 if (eph.sat != sat) {
1048 trace(NULL, 2, "ubx rxmsfrbx enav satellite error: sat=%d %d\n", sat, eph.sat);
1049 return -1;
1050 }
1051 eph.code |= (1 << 0) | (1 << 2); /* data source: E1 and E5b */
1052
1053 adj_utcweek(raw->time, utc);
1054 matcpy(raw->nav.ion_gal, ion, 4, 1);
1055 matcpy(raw->nav.utc_gal, utc, 8, 1);
1056
1057 if (!strstr(raw->opt, "-EPHALL")) {
1058 if (eph.iode == raw->nav.eph[sat - 1].iode && timediff(eph.toe, raw->nav.eph[sat - 1].toe) == 0.0 &&
1059 timediff(eph.toc, raw->nav.eph[sat - 1].toc) == 0.0) {
1060 return 0;
1061 }
1062 }
1063 raw->nav.eph[sat - 1] = eph;
1064 raw->ephsat = sat;
1065 raw->ephset = 0; /* 0:I/NAV */
1066 return 2;
1067}
1068/* decode BDS navigation data ------------------------------------------------*/
1069static int decode_cnav(raw_t* raw, int sat, int off) {
1070 eph_t eph = {0};
1071 double ion[8], utc[8];
1072 uint8_t *p = raw->buff + 6 + off, buff[38] = {0};
1073 int i, id, pgn, prn;
1074
1075 if (raw->len < 48 + off) {
1076 trace(NULL, 2, "ubx rxmsfrbx cnav length error: sat=%d len=%d\n", sat, raw->len);
1077 return -1;
1078 }
1079 for (i = 0; i < 10; i++, p += 4) {
1080 setbitu(buff, 30 * i, 30, U4(p));
1081 }
1082 id = getbitu(buff, 15, 3); /* subframe ID */
1083 if (id < 1 || 5 < id) {
1084 trace(NULL, 2, "ubx rxmsfrbx cnav subframe id error: sat=%2d\n", sat);
1085 return -1;
1086 }
1087 satsys(sat, &prn);
1088
1089 if (prn >= 6 && prn <= 58) { /* IGSO/MEO */
1090 memcpy(raw->subfrm[sat - 1] + (id - 1) * 38, buff, 38);
1091
1092 if (id == 3) {
1093 if (!decode_bds_d1(raw->subfrm[sat - 1], &eph, NULL, NULL)) {
1094 return 0;
1095 }
1096 } else if (id == 5) {
1097 if (!decode_bds_d1(raw->subfrm[sat - 1], NULL, ion, utc)) {
1098 return 0;
1099 }
1100 matcpy(raw->nav.ion_cmp, ion, 8, 1);
1101 matcpy(raw->nav.utc_cmp, utc, 8, 1);
1102 return 9;
1103 } else {
1104 return 0;
1105 }
1106 } else { /* GEO */
1107 pgn = getbitu(buff, 42, 4); /* page numuber */
1108
1109 if (id == 1 && pgn >= 1 && pgn <= 10) {
1110 memcpy(raw->subfrm[sat - 1] + (pgn - 1) * 38, buff, 38);
1111 if (pgn != 10) {
1112 return 0;
1113 }
1114 if (!decode_bds_d2(raw->subfrm[sat - 1], &eph, NULL)) {
1115 return 0;
1116 }
1117 } else if (id == 5 && pgn == 102) {
1118 memcpy(raw->subfrm[sat - 1] + 10 * 38, buff, 38);
1119 if (!decode_bds_d2(raw->subfrm[sat - 1], NULL, utc)) {
1120 return 0;
1121 }
1122 matcpy(raw->nav.utc_cmp, utc, 8, 1);
1123 return 9;
1124 } else {
1125 return 0;
1126 }
1127 }
1128 if (!strstr(raw->opt, "-EPHALL")) {
1129 if (timediff(eph.toe, raw->nav.eph[sat - 1].toe) == 0.0) {
1130 return 0;
1131 }
1132 }
1133 eph.sat = sat;
1134 raw->nav.eph[sat - 1] = eph;
1135 raw->ephsat = sat;
1136 raw->ephset = 0;
1137 return 2;
1138}
1139/* decode GLONASS navigation data --------------------------------------------*/
1140static int decode_gnav(raw_t* raw, int sat, int off, int frq) {
1141 geph_t geph = {0};
1142 double utc_glo[8] = {0};
1143 int i, j, k, m, prn;
1144 uint8_t *p = raw->buff + 6 + off, buff[64], *fid;
1145
1146 satsys(sat, &prn);
1147
1148 if (raw->len < 24 + off) {
1149 trace(NULL, 2, "ubx rxmsfrbx gnav length error: len=%d\n", raw->len);
1150 return -1;
1151 }
1152 for (i = k = 0; i < 4; i++, p += 4) {
1153 for (j = 0; j < 4; j++) {
1154 buff[k++] = p[3 - j];
1155 }
1156 }
1157 /* test hamming of GLONASS string */
1158 if (!test_glostr(buff)) {
1159 trace(NULL, 2, "ubx rxmsfrbx gnav hamming error: sat=%2d\n", sat);
1160 return -1;
1161 }
1162 m = getbitu(buff, 1, 4);
1163 if (m < 1 || 15 < m) {
1164 trace(NULL, 2, "ubx rxmsfrbx gnav string no error: sat=%2d\n", sat);
1165 return -1;
1166 }
1167 /* flush frame buffer if frame-ID changed */
1168 fid = raw->subfrm[sat - 1] + 150;
1169 if (fid[0] != buff[12] || fid[1] != buff[13]) {
1170 for (i = 0; i < 4; i++) {
1171 memset(raw->subfrm[sat - 1] + i * 10, 0, 10);
1172 }
1173 memcpy(fid, buff + 12, 2); /* save frame-id */
1174 }
1175 memcpy(raw->subfrm[sat - 1] + (m - 1) * 10, buff, 10);
1176
1177 if (m == 4) {
1178 /* decode GLONASS ephemeris strings */
1179 geph.tof = raw->time;
1180 if (!decode_glostr(raw->subfrm[sat - 1], &geph, NULL) || geph.sat != sat) {
1181 return 0;
1182 }
1183 geph.frq = frq - 7;
1184
1185 if (!strstr(raw->opt, "-EPHALL")) {
1186 if (geph.iode == raw->nav.geph[prn - 1].iode) {
1187 return 0;
1188 }
1189 }
1190 raw->nav.geph[prn - 1] = geph;
1191 raw->ephsat = sat;
1192 raw->ephset = 0;
1193 return 2;
1194 } else if (m == 5) {
1195 if (!decode_glostr(raw->subfrm[sat - 1], NULL, utc_glo)) {
1196 return 0;
1197 }
1198 matcpy(raw->nav.utc_glo, utc_glo, 8, 1);
1199 return 9;
1200 }
1201 return 0;
1202}
1203/* decode SBAS navigation data -----------------------------------------------*/
1204static int decode_snav(raw_t* raw, int prn, int off) {
1205 int i, tow, week;
1206 uint8_t *p = raw->buff + 6 + off, buff[32];
1207
1208 if (raw->len < 40 + off) {
1209 trace(NULL, 2, "ubx rxmsfrbx snav length error: len=%d\n", raw->len);
1210 return -1;
1211 }
1212 tow = (int)time2gpst(timeadd(raw->time, -1.0), &week);
1213 raw->sbsmsg.prn = prn;
1214 raw->sbsmsg.tow = tow;
1215 raw->sbsmsg.week = week;
1216 for (i = 0; i < 8; i++, p += 4) {
1217 setbitu(buff, 32 * i, 32, U4(p));
1218 }
1219 memcpy(raw->sbsmsg.msg, buff, 29);
1220 raw->sbsmsg.msg[28] &= 0xC0;
1221 return 3;
1222}
1223/* decode UBX-RXM-SFRBX: raw subframe data (ref [3][4][5]) -------------------*/
1224static int decode_rxmsfrbx(raw_t* raw) {
1225 uint8_t* p = raw->buff + 6;
1226 int prn, sat, sys;
1227
1228 if (raw->outtype) {
1229 sprintf(raw->msgtype, "UBX RXM-SFRBX (%4d): sys=%d prn=%3d", raw->len, U1(p), U1(p + 1));
1230 }
1231 if (!(sys = ubx_sys(U1(p)))) {
1232 trace(NULL, 2, "ubx rxmsfrbx sys id error: sys=%d\n", U1(p));
1233 return -1;
1234 }
1235 prn = U1(p + 1) + ((sys == SYS_QZS) ? 192 : 0);
1236 if (!(sat = satno(sys, prn))) {
1237 if (sys == SYS_GLO && prn == 255) {
1238 return 0; /* suppress error for unknown GLONASS satellite */
1239 }
1240 trace(NULL, 2, "ubx rxmsfrbx sat number error: sys=%d prn=%d\n", sys, prn);
1241 return -1;
1242 }
1243 if (sys == SYS_QZS && raw->len == 52) { /* QZSS L1S */
1244 sys = SYS_SBS;
1245 prn -= 10;
1246 }
1247 switch (sys) {
1248 case SYS_GPS:
1249 return decode_nav(raw, sat, 8);
1250 case SYS_QZS:
1251 return decode_nav(raw, sat, 8);
1252 case SYS_GAL:
1253 return decode_enav(raw, sat, 8);
1254 case SYS_CMP:
1255 return decode_cnav(raw, sat, 8);
1256 case SYS_GLO:
1257 return decode_gnav(raw, sat, 8, U1(p + 3));
1258 case SYS_SBS:
1259 return decode_snav(raw, prn, 8);
1260 }
1261 return 0;
1262}
1263/* decode UBX-TRK-SFRBX: subframe buffer extension (unoffitial) --------------*/
1264static int decode_trksfrbx(raw_t* raw) {
1265 uint8_t* p = raw->buff + 6;
1266 int prn, sat, sys;
1267
1268 if (raw->outtype) {
1269 sprintf(raw->msgtype, "UBX TRK-SFRBX (%4d): sys=%d prn=%3d", raw->len, U1(p + 1), U1(p + 2));
1270 }
1271 if (!(sys = ubx_sys(U1(p + 1)))) {
1272 trace(NULL, 2, "ubx trksfrbx sys id error: sys=%d\n", U1(p + 1));
1273 return -1;
1274 }
1275 prn = U1(p + 2) + (sys == SYS_QZS ? 192 : 0);
1276 if (!(sat = satno(sys, prn))) {
1277 trace(NULL, 2, "ubx trksfrbx sat number error: sys=%d prn=%d\n", sys, prn);
1278 return -1;
1279 }
1280 switch (sys) {
1281 case SYS_GPS:
1282 return decode_nav(raw, sat, 13);
1283 case SYS_QZS:
1284 return decode_nav(raw, sat, 13);
1285 case SYS_GAL:
1286 return decode_enav(raw, sat, 13);
1287 case SYS_CMP:
1288 return decode_cnav(raw, sat, 13);
1289 case SYS_GLO:
1290 return decode_gnav(raw, sat, 13, U1(p + 4));
1291 case SYS_SBS:
1292 return decode_snav(raw, sat, 13);
1293 }
1294 return 0;
1295}
1296/* decode UBX-RXM-SFRB: subframe buffer (GPS/SBAS) ---------------------------*/
1297static int decode_rxmsfrb(raw_t* raw) {
1298 uint32_t words[10];
1299 uint8_t *p = raw->buff + 6, buff[30];
1300 int i, sys, prn, sat, id;
1301
1302 if (raw->outtype) {
1303 sprintf(raw->msgtype, "UBX RXM-SFRB (%4d): prn=%2d", raw->len, U1(p + 1));
1304 }
1305 if (raw->len < 42) {
1306 trace(NULL, 2, "ubx rxmsfrb length error: len=%d\n", raw->len);
1307 return -1;
1308 }
1309 prn = U1(p + 1);
1310 sys = (prn >= MINPRNSBS) ? SYS_SBS : SYS_GPS;
1311
1312 if (!(sat = satno(sys, prn))) {
1313 trace(NULL, 2, "ubx rxmsfrb satellite error: prn=%d\n", prn);
1314 return -1;
1315 }
1316 if (sys == SYS_GPS) {
1317 for (i = 0, p += 2; i < 10; i++, p += 4) {
1318 setbitu(buff, 24 * i, 24, U4(p));
1319 }
1320 id = getbitu(buff, 43, 3);
1321 if (id >= 1 && id <= 5) {
1322 memcpy(raw->subfrm[sat - 1] + (id - 1) * 30, buff, 30);
1323 if (id == 3) {
1324 return decode_eph(raw, sat);
1325 } else if (id == 4) {
1326 return decode_ionutc(raw, sat);
1327 }
1328 }
1329 } else {
1330 for (i = 0, p += 2; i < 10; i++, p += 4) {
1331 words[i] = U4(p);
1332 }
1333 if (!sbsdecodemsg(raw->time, prn, words, &raw->sbsmsg)) {
1334 return 0;
1335 }
1336 return 3;
1337 }
1338 return 0;
1339}
1340/* decode UBX-RXM-QZSSL6: QZSS L6 message ------------------------------------*/
1341static int decode_rxmqzssl6(raw_t* raw, rtcm_t* rtcm) {
1342 static int count[16][2] = {{0}}; /* -OUT_QZSSL6 debug counts per svId */
1343 uint8_t* p = raw->buff + 6;
1344 double cn0, time;
1345 char buff[1024] = "", *q = buff;
1346 int i, ver, prn, msg, nerr, stat, ret;
1347
1348 if (raw->len < 272) {
1349 trace(NULL, 2, "ubx rxmqzssl6 length error: len=%d\n", raw->len);
1350 return -1;
1351 }
1352 ver = U1(p);
1353 prn = U1(p + 1) + 192;
1354 msg = (U2(p + 10) >> 10) & 1; /* message name 0:L6D,1:L6E */
1355 cn0 = U2(p + 2) / 256.0; /* C/N0 (dBHz) */
1356 time = U4(p + 4) * 1e-3; /* time tag (s) */
1357 nerr = U2(p + 9); /* number of errors corrected */
1358 stat = (U2(p + 10) >> 12) & 3; /* error status 0:unknown,1:err-free,2:erroneous */
1359
1360 if (raw->outtype) {
1361 sprintf(raw->msgtype, "UBX RXM-QZSSL6(%4d): ver=%d prn=%2d msg=%s cn0=%.1f nerr=%2d stat=%d", raw->len, ver,
1362 prn, msg ? "L6E" : "L6D", cn0, nerr, stat);
1363 }
1364 if (strstr(raw->opt, "-OUT_QZSSL6") && prn - 192 < 16) {
1365 if (stat >= 1) {
1366 count[prn - 192][stat == 1 ? 0 : 1]++;
1367 }
1368 if (stat == 1) {
1369 trace(NULL, 2, "$CH,%.3f,%s,%d,%d,%.1f,%.9f,%.3f,%.3f,%d,%d\n", time, msg ? "L6E" : "L6D", prn, 0, cn0, 0.0,
1370 0.0, 0.0, count[prn - 192][0], count[prn - 192][1]);
1371 for (i = 0; i < 250; i++) {
1372 q += sprintf(q, "%02X", U1(p + 14 + i));
1373 }
1374 trace(NULL, 2, "$L6FRM,%.3f,%s,%d,%d,%s\n", time, msg ? "L6E" : "L6D", prn, nerr, buff);
1375 }
1376 }
1377 ret = 0;
1378 if (stat == 1) {
1379 memcpy(rtcm->buff, p + 14, 250);
1380 raw->l6tag = time;
1381 /* route by the L6 header service, not by the L6D/L6E message bit: an
1382 * L6D channel may carry MADOCA-PPP iono (PRN 200/201) -> 16, which must
1383 * not enter the CLAS demux; L6E carries MADOCA-PPP (15) and QZNMA (17) */
1384 ret = decode_qzss_l6frame(rtcm, msg == 0);
1385 }
1386 return ret;
1387}
1388/* decode ublox raw message --------------------------------------------------*/
1389static int decode_ubx(raw_t* raw, rtcm_t* rtcm) {
1390 int type = (U1(raw->buff + 2) << 8) + U1(raw->buff + 3);
1391
1392 trace(NULL, 3, "decode_ubx: type=%04x len=%d\n", type, raw->len);
1393
1394 /* checksum */
1395 if (!checksum(raw->buff, raw->len)) {
1396 trace(NULL, 2, "ubx checksum error: type=%04x len=%d\n", type, raw->len);
1397 return -1;
1398 }
1399 switch (type) {
1400 case ID_RXMRAW:
1401 return decode_rxmraw(raw);
1402 case ID_RXMRAWX:
1403 return decode_rxmrawx(raw);
1404 case ID_RXMSFRB:
1405 return decode_rxmsfrb(raw);
1406 case ID_RXMSFRBX:
1407 return decode_rxmsfrbx(raw);
1408 case ID_RXMQZSSL6:
1409 return decode_rxmqzssl6(raw, rtcm);
1410 case ID_NAVSOL:
1411 return decode_navsol(raw);
1412 case ID_NAVTIME:
1413 return decode_navtime(raw);
1414 case ID_TRKMEAS:
1415 return decode_trkmeas(raw);
1416 case ID_TRKD5:
1417 return decode_trkd5(raw);
1418 case ID_TRKSFRBX:
1419 return decode_trksfrbx(raw);
1420 }
1421 if (raw->outtype) {
1422 sprintf(raw->msgtype, "UBX 0x%02X 0x%02X (%4d)", type >> 8, type & 0xFF, raw->len);
1423 }
1424 return 0;
1425}
1426/* sync code -----------------------------------------------------------------*/
1427static int sync_ubx(uint8_t* buff, uint8_t data) {
1428 buff[0] = buff[1];
1429 buff[1] = data;
1430 return buff[0] == UBXSYNC1 && buff[1] == UBXSYNC2;
1431}
1432/* input ublox raw message from stream -----------------------------------------
1433 * fetch next ublox raw data and input a mesasge from stream
1434 * args : raw_t *raw IO receiver raw data control struct
1435 * rtcm_t *rtcm IO rtcm control struct
1436 * uint8_t data I stream data (1 byte)
1437 * return : status (-1: error message, 0: no message, 1: input observation data,
1438 * 2: input ephemeris, 3: input sbas message,
1439 * 9: input ion/utc parameter)
1440 *
1441 * notes : to specify input options, set raw->opt to the following option
1442 * strings separated by spaces.
1443 *
1444 * -EPHALL : input all ephemerides
1445 * -INVCP : invert polarity of carrier-phase
1446 * -TADJ=tint : adjust time tags to multiples of tint (sec)
1447 * -STD_SLIP=std: slip by std-dev of carrier phase under std
1448 * -OUT_QZSSL6: output QZSS L6 message to tracefile
1449 *
1450 * The supported messages are as follows.
1451 *
1452 * UBX-RXM-RAW : raw measurement data
1453 * UBX-RXM-RAWX : multi-gnss measurement data
1454 * UBX-RXM-SFRB : subframe buffer
1455 * UBX-RXM-SFRBX: subframe buffer extension
1456 * UBX-RXM-QZSSL6: QZSS L6 message by D9C
1457 * UBX-NAV-TIMEGPS: time info by D9C
1458 *
1459 * UBX-TRK-MEAS and UBX-TRK-SFRBX are based on NEO-M8N (F/W 2.01).
1460 * UBX-TRK-D5 is based on NEO-7N (F/W 1.00). They are not formally
1461 * documented and not supported by u-blox.
1462 * Users can use these messages by their own risk.
1463 *-----------------------------------------------------------------------------*/
1464extern int input_ubx(raw_t* raw, rtcm_t* rtcm, uint8_t data) {
1465 trace(NULL, 5, "input_ubx: data=%02x\n", data);
1466
1467 /* synchronize frame */
1468 if (raw->nbyte == 0) {
1469 if (!sync_ubx(raw->buff, data)) {
1470 return 0;
1471 }
1472 raw->nbyte = 2;
1473 return 0;
1474 }
1475 raw->buff[raw->nbyte++] = data;
1476
1477 if (raw->nbyte == 6) {
1478 if ((raw->len = U2(raw->buff + 4) + 8) > MAXRAWLEN) {
1479 trace(NULL, 2, "ubx length error: len=%d\n", raw->len);
1480 raw->nbyte = 0;
1481 return -1;
1482 }
1483 }
1484 if (raw->nbyte < 6 || raw->nbyte < raw->len) {
1485 return 0;
1486 }
1487 raw->nbyte = 0;
1488
1489 /* decode ublox raw message */
1490 return decode_ubx(raw, rtcm);
1491}
1492/* input ublox raw message from file -------------------------------------------
1493 * fetch next ublox raw data and input a message from file
1494 * args : raw_t *raw IO receiver raw data control struct
1495 * rtcm_t *rtcm IO rtcm control struct
1496 * FILE *fp I file pointer
1497 * return : status(-2: end of file, -1...9: same as above)
1498 *-----------------------------------------------------------------------------*/
1499extern int input_ubxf(raw_t* raw, rtcm_t* rtcm, FILE* fp) {
1500 int i, data;
1501
1502 trace(NULL, 4, "input_ubxf:\n");
1503
1504 /* synchronize frame */
1505 if (raw->nbyte == 0) {
1506 for (i = 0;; i++) {
1507 if ((data = fgetc(fp)) == EOF) {
1508 return -2;
1509 }
1510 if (sync_ubx(raw->buff, (uint8_t)data)) {
1511 break;
1512 }
1513 if (i >= 4096) {
1514 return 0;
1515 }
1516 }
1517 }
1518 if (fread(raw->buff + 2, 1, 4, fp) < 4) {
1519 return -2;
1520 }
1521 raw->nbyte = 6;
1522
1523 if ((raw->len = U2(raw->buff + 4) + 8) > MAXRAWLEN) {
1524 trace(NULL, 2, "ubx length error: len=%d\n", raw->len);
1525 raw->nbyte = 0;
1526 return -1;
1527 }
1528 if (fread(raw->buff + 6, 1, raw->len - 6, fp) < (size_t)(raw->len - 6)) {
1529 return -2;
1530 }
1531 raw->nbyte = 0;
1532
1533 /* decode ubx raw message */
1534 return decode_ubx(raw, rtcm);
1535}
1536/* convert string to integer -------------------------------------------------*/
1537static int stoi(const char* s) {
1538 uint32_t n;
1539 if (sscanf(s, "0x%X", &n) == 1) {
1540 return (int)n; /* hex (0xXXXX) */
1541 }
1542 return atoi(s);
1543}
1544/* generate ublox binary message -----------------------------------------------
1545 * generate ublox binary message from message string
1546 * args : char *msg IO message string
1547 * "CFG-PRT portid res0 res1 mode baudrate inmask outmask flags"
1548 * "CFG-USB vendid prodid res1 res2 power flags vstr pstr serino"
1549 * "CFG-MSG msgid rate0 rate1 rate2 rate3 rate4 rate5 rate6"
1550 * "CFG-NMEA filter version numsv flags"
1551 * "CFG-RATE meas nav time"
1552 * "CFG-CFG clear_mask save_mask load_mask [dev_mask]"
1553 * "CFG-TP interval length status time_ref res adelay rdelay udelay"
1554 * "CFG-NAV2 ..."
1555 * "CFG-DAT maja flat dx dy dz rotx roty rotz scale"
1556 * "CFG-INF protocolid res0 res1 res2 mask0 mask1 mask2 ... mask5"
1557 * "CFG-RST navbbr reset res"
1558 * "CFG-RXM gpsmode lpmode"
1559 * "CFG-ANT flags pins"
1560 * "CFG-FXN flags treacq tacq treacqoff tacqoff ton toff res basetow"
1561 * "CFG-SBAS mode usage maxsbas res scanmode"
1562 * "CFG-LIC key0 key1 key2 key3 key4 key5"
1563 * "CFG-TM intid rate flags"
1564 * "CFG-TM2 ch res0 res1 rate flags"
1565 * "CFG-TMODE tmode posx posy posz posvar svinmindur svinvarlimit"
1566 * "CFG-EKF ..."
1567 * "CFG-GNSS ..."
1568 * "CFG-ITFM conf conf2"
1569 * "CFG-LOGFILTER ver flag min_int time_thr speed_thr pos_thr"
1570 * "CFG-NAV5 ..."
1571 * "CFG-NAVX5 ..."
1572 * "CFG-ODO ..."
1573 * "CFG-PM2 ..."
1574 * "CFG-PWR ver rsv1 rsv2 rsv3 state"
1575 * "CFG-RINV flag data ..."
1576 * "CFG-SMGR ..."
1577 * "CFG-TMODE2 ..."
1578 * "CFG-TMODE3 ..."
1579 * "CFG-TPS ..."
1580 * "CFG-TXSLOT ..."
1581 * "CFG-VALDEL ver layer res0 res1 key [key ...]"
1582 * "CFG-VALGET ver layer pos key [key ...]"
1583 * "CFG-VALSET ver layer res0 res1 key value [key value ...]"
1584 * uint8_t *buff O binary message
1585 * return : length of binary message (0: error)
1586 * note : see reference [1][3][5] for details.
1587 * the following messages are not supported:
1588 * CFG-DOSC,CFG-ESRC
1589 *-----------------------------------------------------------------------------*/
1590extern int gen_ubx(const char* msg, uint8_t* buff) {
1591 const char* cmd[] = {"PRT", "USB", "MSG", "NMEA", "RATE", "CFG", "TP", "NAV2",
1592 "DAT", "INF", "RST", "RXM", "ANT", "FXN", "SBAS", "LIC",
1593 "TM", "TM2", "TMODE", "EKF", "GNSS", "ITFM", "LOGFILTER", "NAV5",
1594 "NAVX5", "ODO", "PM2", "PWR", "RINV", "SMGR", "TMODE2", "TMODE3",
1595 "TPS", "TXSLOT", "VALDEL", "VALGET", "VALSET", ""};
1596 const uint8_t id[] = {0x00, 0x1B, 0x01, 0x17, 0x08, 0x09, 0x07, 0x1A, 0x06, 0x02, 0x04, 0x11, 0x13,
1597 0x0E, 0x16, 0x80, 0x10, 0x19, 0x1D, 0x12, 0x3E, 0x39, 0x47, 0x24, 0x23, 0x1E,
1598 0x3B, 0x57, 0x34, 0x62, 0x3D, 0x71, 0x31, 0x53, 0x8c, 0x8b, 0x8a};
1599 const int prm[][32] = {
1600 {FU1, FU1, FU2, FU4, FU4, FU2, FU2, FU2, FU2}, /* PRT */
1601 {FU2, FU2, FU2, FU2, FU2, FU2, FS32, FS32, FS32}, /* USB */
1602 {FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1}, /* MSG */
1603 {FU1, FU1, FU1, FU1}, /* NMEA */
1604 {FU2, FU2, FU2}, /* RATE */
1605 {FU4, FU4, FU4, FU1}, /* CFG */
1606 {FU4, FU4, FI1, FU1, FU2, FI2, FI2, FI4}, /* TP */
1607 {FU1, FU1, FU2, FU1, FU1, FU1, FU1, FI4, FU1, FU1, FU1, FU1,
1608 FU1, FU1, FU2, FU2, FU2, FU2, FU2, FU1, FU1, FU2, FU4, FU4}, /* NAV2 */
1609 {FR8, FR8, FR4, FR4, FR4, FR4, FR4, FR4, FR4}, /* DAT */
1610 {FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1}, /* INF */
1611 {FU2, FU1, FU1}, /* RST */
1612 {FU1, FU1}, /* RXM */
1613 {FU2, FU2}, /* ANT */
1614 {FU4, FU4, FU4, FU4, FU4, FU4, FU4, FU4}, /* FXN */
1615 {FU1, FU1, FU1, FU1, FU4}, /* SBAS */
1616 {FU2, FU2, FU2, FU2, FU2, FU2}, /* LIC */
1617 {FU4, FU4, FU4}, /* TM */
1618 {FU1, FU1, FU2, FU4, FU4}, /* TM2 */
1619 {FU4, FI4, FI4, FI4, FU4, FU4, FU4}, /* TMODE */
1620 {FU1, FU1, FU1, FU1, FU4, FU2, FU2, FU1, FU1, FU2}, /* EKF */
1621 {FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU4}, /* GNSS */
1622 {FU4, FU4}, /* ITFM */
1623 {FU1, FU1, FU2, FU2, FU2, FU4}, /* LOGFILTER */
1624 {FU2, FU1, FU1, FI4, FU4, FI1, FU1, FU2, FU2, FU2, FU2, FU1,
1625 FU1, FU1, FU1, FU1, FU1, FU2, FU1, FU1, FU1, FU1, FU1, FU1}, /* NAV5 */
1626 {FU2, FU2, FU4, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1,
1627 FU2, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU2}, /* NAVX5 */
1628 {FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1}, /* ODO */
1629 {FU1, FU1, FU1, FU1, FU4, FU4, FU4, FU4, FU2, FU2}, /* PM2 */
1630 {FU1, FU1, FU1, FU1, FU4}, /* PWR */
1631 {FU1, FU1}, /* RINV */
1632 {FU1, FU1, FU2, FU2, FU1, FU1, FU2, FU2, FU2, FU2, FU4}, /* SMGR */
1633 {FU1, FU1, FU2, FI4, FI4, FI4, FU4, FU4, FU4}, /* TMODE2 */
1634 {FU1, FU1, FU2, FI4, FI4, FI4, FI1, FI1, FI1, FU1, FU4,
1635 FU4, FU4, FU1, FU1, FU1, FU1, FU1, FU1, FU1, FU1}, /* TMODE3 */
1636 {FU1, FU1, FU1, FU1, FI2, FI2, FU4, FU4, FU4, FU4, FI4, FU4}, /* TPS */
1637 {FU1, FU1, FU1, FU1, FU4, FU4, FU4, FU4, FU4}, /* TXSLOT */
1638 {FU1, FU1, FU1, FU1}, /* VALDEL */
1639 {FU1, FU1, FU2}, /* VALGET */
1640 {FU1, FU1, FU1, FU1} /* VALSET */
1641 };
1642 uint8_t* q = buff;
1643 char mbuff[1024], *args[32], *p;
1644 int i, j, n, narg = 0;
1645
1646 trace(NULL, 4, "gen_ubxf: msg=%s\n", msg);
1647
1648 strcpy(mbuff, msg);
1649 for (p = strtok(mbuff, " "); p && narg < 32; p = strtok(NULL, " ")) {
1650 args[narg++] = p;
1651 }
1652 if (narg < 1 || strncmp(args[0], "CFG-", 4)) {
1653 return 0;
1654 }
1655
1656 for (i = 0; *cmd[i]; i++) {
1657 if (!strcmp(args[0] + 4, cmd[i])) {
1658 break;
1659 }
1660 }
1661 if (!*cmd[i]) {
1662 return 0;
1663 }
1664
1665 *q++ = UBXSYNC1;
1666 *q++ = UBXSYNC2;
1667 *q++ = UBXCFG;
1668 *q++ = id[i];
1669 q += 2;
1670 for (j = 1; prm[i][j - 1] || j < narg; j++) {
1671 switch (prm[i][j - 1]) {
1672 case FU1:
1673 setU1(q, j < narg ? (uint8_t)stoi(args[j]) : 0);
1674 q += 1;
1675 break;
1676 case FU2:
1677 setU2(q, j < narg ? (uint16_t)stoi(args[j]) : 0);
1678 q += 2;
1679 break;
1680 case FU4:
1681 setU4(q, j < narg ? (uint32_t)stoi(args[j]) : 0);
1682 q += 4;
1683 break;
1684 case FI1:
1685 setI1(q, j < narg ? (int8_t)stoi(args[j]) : 0);
1686 q += 1;
1687 break;
1688 case FI2:
1689 setI2(q, j < narg ? (int16_t)stoi(args[j]) : 0);
1690 q += 2;
1691 break;
1692 case FI4:
1693 setI4(q, j < narg ? (int32_t)stoi(args[j]) : 0);
1694 q += 4;
1695 break;
1696 case FR4:
1697 setR4(q, j < narg ? (float)atof(args[j]) : 0);
1698 q += 4;
1699 break;
1700 case FR8:
1701 setR8(q, j < narg ? (double)atof(args[j]) : 0);
1702 q += 8;
1703 break;
1704 case FS32:
1705 sprintf((char*)q, "%-32.32s", j < narg ? args[j] : "");
1706 q += 32;
1707 break;
1708 default:
1709 setU1(q, j < narg ? (uint8_t)stoi(args[j]) : 0);
1710 q += 1;
1711 break;
1712 }
1713 }
1714 n = (int)(q - buff) + 2;
1715 setU2(buff + 4, (uint16_t)(n - 8)); /* length */
1716 setcs(buff, n);
1717
1718 trace(NULL, 5, "gen_ubx: buff=\n");
1719 traceb(NULL, 5, buff, n);
1720 return n;
1721}
uint32_t rtk_crc24q(const uint8_t *buff, int len)
Compute CRC-24Q parity for SBAS and RTCM3.
Definition mrtk_bits.c:181
void setbitu(uint8_t *buff, int pos, int len, uint32_t data)
Set unsigned bits in byte data.
Definition mrtk_bits.c:122
uint32_t getbitu(const uint8_t *buff, int pos, int len)
Extract unsigned bits from byte data.
Definition mrtk_bits.c:99
MRTKLIB Bits Module — Binary bit operations and CRC functions.
#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_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...
double code2freq(int sys, uint8_t code, int fcn)
Definition mrtk_obs.c:236
#define SNR_UNIT
#define CODE_L5Q
#define MAXOBS
#define CODE_L2I
#define CODE_L1C
#define CODE_L6I
#define CODE_L2C
#define CODE_L7I
#define CODE_NONE
#define CODE_L5P
#define CODE_L1B
#define CODE_L2S
#define MAXRAWLEN
#define CODE_L7Q
#define CODE_L6B
#define CODE_L2L
#define CODE_L1Z
#define CODE_L1P
#define CODE_L1X
MRTKLIB MADOCA-PPP Module — QZSS L6E CSSR message decode functions.
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.
#define FREQ1
Definition mrtk_obs.c:67
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.
static rtcm_t * rtcm
#define U1(p)
#define MINPRNSBS
#define PREAMB_CNAV
#define R8(p)
#define U4(p)
#define I4(p)
#define R4(p)
#define U2(p)
static int decode_rxmraw(raw_t *raw)
static void setI2(uint8_t *p, int16_t i)
#define U1(p)
static int decode_gnav(raw_t *raw, int sat, int off, int frq)
#define ID_RXMRAW
#define FI4
static int decode_nav(raw_t *raw, int sat, int off)
static int stoi(const char *s)
static int decode_trksfrbx(raw_t *raw)
static int sync_ubx(uint8_t *buff, uint8_t data)
#define ID_NAVTIME
#define FU1
int gen_ubx(const char *msg, uint8_t *buff)
int input_ubxf(raw_t *raw, rtcm_t *rtcm, FILE *fp)
#define UBXCFG
static void setI4(uint8_t *p, int32_t i)
static int decode_snav(raw_t *raw, int prn, int off)
static int decode_enav(raw_t *raw, int sat, int off)
#define FI2
static int decode_rxmsfrb(raw_t *raw)
#define UBXSYNC2
static void adj_utcweek(gtime_t time, double *utc)
#define ID_TRKSFRBX
static void setU1(uint8_t *p, uint8_t u)
static int decode_rxmqzssl6(raw_t *raw, rtcm_t *rtcm)
#define FR8
#define ID_RXMSFRB
static int decode_rxmrawx(raw_t *raw)
static int decode_navtime(raw_t *raw)
#define ID_RXMRAWX
static double I8(uint8_t *p)
static void setI1(uint8_t *p, int8_t i)
#define ID_TRKD5
static int decode_ubx(raw_t *raw, rtcm_t *rtcm)
#define FU4
static int decode_trkmeas(raw_t *raw)
#define FU2
static int sig_idx(int sys, uint8_t code)
static int decode_cnav(raw_t *raw, int sat, int off)
#define UBXSYNC1
#define ID_RXMQZSSL6
static int decode_ionutc(raw_t *raw, int sat)
static int ubx_sig(int sys, int sigid)
static void setcs(uint8_t *buff, int len)
#define ID_TRKMEAS
static int ubx_sys(int gnssid)
#define ID_NAVSOL
static void setR4(uint8_t *p, float r)
static int checksum(uint8_t *buff, int len)
#define FI1
#define ROUND(x)
#define ID_RXMSFRBX
#define CPSTD_VALID
#define P2_10
static void setR8(uint8_t *p, double r)
#define I1(p)
static int decode_rxmsfrbx(raw_t *raw)
#define FS32
static void setU4(uint8_t *p, uint32_t u)
#define FR4
static void setU2(uint8_t *p, uint16_t u)
static int decode_eph(raw_t *raw, int sat)
static int decode_trkd5(raw_t *raw)
static int decode_navsol(raw_t *raw)
int input_ubx(raw_t *raw, rtcm_t *rtcm, uint8_t data)
int decode_qzss_l6frame(rtcm_t *rtcm, int is_l6d)
Route one QZSS L6 frame received in a UBX/SBF container.
int decode_frame(const uint8_t *buff, eph_t *eph, alm_t *alm, double *ion, double *utc)
int test_glostr(const uint8_t *buff)
int decode_glostr(const uint8_t *buff, geph_t *geph, double *utc)
int decode_bds_d2(const uint8_t *buff, eph_t *eph, double *utc)
int decode_gal_inav(const uint8_t *buff, eph_t *eph, double *ion, double *utc)
int decode_bds_d1(const uint8_t *buff, eph_t *eph, double *ion, double *utc)
#define P2_32
Definition mrtk_rcvraw.c:57
MRTKLIB Receiver Raw Data Module — Receiver raw data types and decoder functions for various GNSS rec...
#define LLI_HALFS
Definition mrtk_rinex.c:60
#define LLI_HALFC
Definition mrtk_rinex.c:57
#define LLI_SLIP
Definition mrtk_rinex.c:56
MRTKLIB RTCM Module — RTCM message types and functions.
int sbsdecodemsg(gtime_t time, int prn, const uint32_t *words, sbsmsg_t *sbsmsg)
Decode SBAS message frame words.
Definition mrtk_sbas.c:1080
MRTKLIB SBAS Module — SBAS message decoding and corrections.
MRTKLIB System Module — OS/filesystem utility functions.
gtime_t gpst2time(int week, double sec)
Convert GPS week/tow to gtime_t.
Definition mrtk_time.c:165
void time2epoch(gtime_t t, double *ep)
Convert gtime_t struct to calendar day/time.
Definition mrtk_time.c:136
void time2str(gtime_t t, char *s, int n)
Convert gtime_t struct to string.
Definition mrtk_time.c:507
gtime_t gpst2utc(gtime_t t)
Convert GPS time to UTC considering leap seconds.
Definition mrtk_time.c:422
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
gtime_t timeadd(gtime_t t, double sec)
Add seconds to gtime_t.
Definition mrtk_time.c:265
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
Definition mrtk_time.c:530
MRTKLIB Time Module — GNSS time types and conversion functions.
void traceb(mrtk_ctx_t *ctx, int level, const uint8_t *p, int n)
Output trace binary data.
Definition mrtk_trace.c:243
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 toe
Definition mrtk_eph.h:88
gtime_t toc
Definition mrtk_eph.h:88
int code
Definition mrtk_eph.h:83
int iode
Definition mrtk_eph.h:79
int iodc
Definition mrtk_eph.h:79
GLONASS broadcast ephemeris type.
Definition mrtk_eph.h:111
int iode
Definition mrtk_eph.h:113
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_glo[8]
Definition mrtk_nav.h:415
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 utc_cmp[8]
Definition mrtk_nav.h:418
double ion_cmp[8]
Definition mrtk_nav.h:424
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
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
uint8_t rcv
Definition mrtk_obs.h:46
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
double l6tag
uint8_t halfc[MAXSAT][5+5]
Definition mrtk_rcvraw.h:93
char opt[256]
int ephsat
Definition mrtk_rcvraw.h:85
gtime_t time
Definition mrtk_rcvraw.h:79
RTCM control struct type.
Definition mrtk_rtcm.h:50
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