MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_rcv_septentrio.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_rcv_septentrio.c : Septentrio 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_coords.h"
24#include "mrtklib/mrtk_eph.h"
25#include "mrtklib/mrtk_madoca.h"
26#include "mrtklib/mrtk_mat.h"
27#include "mrtklib/mrtk_nav.h"
28#include "mrtklib/mrtk_obs.h"
29#include "mrtklib/mrtk_rcvraw.h"
30#include "mrtklib/mrtk_rtcm.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/* Power-of-2 constants */
81#define P2_5 0.03125
82#define P2_6 0.015625
83#define P2_11 4.882812500000000E-04
84#define P2_15 3.051757812500000E-05
85#define P2_17 7.629394531250000E-06
86#define P2_19 1.907348632812500E-06
87#define P2_20 9.536743164062500E-07
88#define P2_21 4.768371582031250E-07
89#define P2_23 1.192092895507810E-07
90#define P2_24 5.960464477539063E-08
91#define P2_27 7.450580596923828E-09
92#define P2_29 1.862645149230957E-09
93#define P2_30 9.313225746154785E-10
94#define P2_31 4.656612873077393E-10
95#define P2_32 2.328306436538696E-10
96#define P2_33 1.164153218269348E-10
97#define P2_34 5.820766091346740E-11
98#define P2_35 2.910383045673370E-11
99#define P2_38 3.637978807091710E-12
100#define P2_40 9.094947017729280E-13
101#define P2_43 1.136868377216160E-13
102#define P2_46 1.421085471520200E-14
103#define P2_50 8.881784197001252E-16
104#define P2_55 2.775557561562891E-17
105#define P2_59 1.734723475976810E-18
106
107/* Forward declarations for functions in rtklib (resolved at link time) */
108
109#define SBF_SYNC1 0x24 /* SBF block header 1 */
110#define SBF_SYNC2 0x40 /* SBF block header 2 */
111#define SBF_MAXSIG 40 /* SBF max signal number */
112
113#define SBF_MEASEPOCH 4027 /* SBF GNSS measurements */
114#define SBF_MEASEXTRA 4000 /* SBF GNSS measurements extra info */
115#define SBF_GPSRAWCA 4017 /* SBF GPS C/A subframe */
116#define SBF_GLORAWCA 4026 /* SBF GLONASS L1CA or L2CA navigation string */
117#define SBF_GALRAWFNAV 4022 /* SBF Galileo F/NAV navigation page */
118#define SBF_GALRAWINAV 4023 /* SBF Galileo I/NAV navigation page */
119#define SBF_GALRAWCNAV 4024 /* SBF Galileo E6-B C/NAV page (HAS) */
120#define SBF_GEORAWL1 4020 /* SBF SBAS L1 navigation frame */
121#define SBF_BDSRAW 4047 /* SBF BDS navigation page */
122#define SBF_QZSRAWL1CA 4066 /* SBF QZSS C/A subframe */
123#define SBF_QZSRAWL6 4069 /* SBF QZSS L6 message (generic; Source: 1=L6D, 2=L6E) */
124#define SBF_QZSRAWL6D 4270 /* SBF QZSS L6D message (mosaic-G5; Source always 1) */
125#define SBF_QZSRAWL6E 4271 /* SBF QZSS L6E message (mosaic-G5; Source always 2) */
126#define SBF_NAVICRAW 4093 /* SBF NavIC/IRNSS subframe */
127
128/* Decoded navigation blocks */
129#define SBF_GPSNAV 5891 /* SBF GPS decoded ephemeris */
130#define SBF_GLONAV 4004 /* SBF GLONASS decoded ephemeris */
131#define SBF_GALNAV 4002 /* SBF Galileo decoded ephemeris */
132#define SBF_BDSNAV 4081 /* SBF BDS decoded ephemeris */
133#define SBF_QZSSNAV 4095 /* SBF QZSS decoded ephemeris */
134
135/* Position blocks */
136#define SBF_PVTGEOD 4007 /* SBF PVTGeodetic */
137
138/* get fields (little-endian) ------------------------------------------------*/
139#define U1(p) (*((uint8_t*)(p)))
140#define I1(p) (*((int8_t*)(p)))
141static uint16_t U2(uint8_t* p) {
142 uint16_t a;
143 memcpy(&a, p, 2);
144 return a;
145}
146static uint32_t U4(uint8_t* p) {
147 uint32_t a;
148 memcpy(&a, p, 4);
149 return a;
150}
151static int32_t I4(uint8_t* p) {
152 int32_t a;
153 memcpy(&a, p, 4);
154 return a;
155}
156static int16_t I2(uint8_t* p) {
157 int16_t a;
158 memcpy(&a, p, 2);
159 return a;
160}
161static float R4(const uint8_t* p) {
162 float r;
163 memcpy(&r, p, 4);
164 return r;
165}
166static double R8(const uint8_t* p) {
167 double r;
168 memcpy(&r, p, 8);
169 return r;
170}
171
172/* convert N-bit week number to full week ------------------------------------*/
173static uint16_t adjust_WN10(uint16_t ref_WN, uint16_t WN) {
174 int16_t offset = (ref_WN % 1024) - WN;
175 if (offset > 512) offset -= 1024;
176 if (offset < -511) offset += 1024;
177 return ref_WN + offset;
178}
179static uint16_t adjust_WN12(uint16_t ref_WN, uint16_t WN) {
180 int16_t offset = (ref_WN % 4096) - WN;
181 if (offset > 2048) offset -= 4096;
182 if (offset < -2047) offset += 4096;
183 return ref_WN + offset;
184}
185static uint16_t adjust_WN14(uint16_t ref_WN, uint16_t WN) {
186 int16_t offset = (ref_WN % 8192) - WN;
187 if (offset > 4096) offset -= 8192;
188 if (offset < -4095) offset += 8192;
189 return ref_WN + offset;
190}
191
192/* svid to satellite number ([1] 4.1.9) --------------------------------------*/
193static int svid2sat(int svid) {
194 if (svid <= 37) {
195 return satno(SYS_GPS, svid);
196 }
197 if (svid <= 61) {
198 return satno(SYS_GLO, svid - 37);
199 }
200 if (svid <= 62) {
201 return 0; /* glonass unknown slot */
202 }
203 if (svid <= 68) {
204 return satno(SYS_GLO, svid - 38);
205 }
206 if (svid <= 70) {
207 return 0;
208 }
209 if (svid <= 106) {
210 return satno(SYS_GAL, svid - 70);
211 }
212 if (svid <= 119) {
213 return 0;
214 }
215 if (svid <= 140) {
216 return satno(SYS_SBS, svid);
217 }
218 if (svid <= 180) {
219 return satno(SYS_CMP, svid - 140);
220 }
221 if (svid <= 187) {
222 return satno(SYS_QZS, svid - 180 + 192);
223 }
224 if (svid <= 190) {
225 return 0;
226 }
227 if (svid <= 197) {
228 return satno(SYS_IRN, svid - 190);
229 }
230 if (svid <= 215) {
231 return satno(SYS_SBS, svid - 57);
232 }
233 if (svid <= 222) {
234 return satno(SYS_IRN, svid - 208);
235 }
236 if (svid <= 245) {
237 return satno(SYS_CMP, svid - 182);
238 }
239 return 0; /* error */
240}
241/* signal number table ([1] 4.1.10) ------------------------------------------*/
242static uint8_t sig_tbl[SBF_MAXSIG + 1][2] = {
243 /* system, obs-code */
244 {SYS_GPS, CODE_L1C}, /* 0: GPS L1C/A */
245 {SYS_GPS, CODE_L1W}, /* 1: GPS L1P */
246 {SYS_GPS, CODE_L2W}, /* 2: GPS L2P */
247 {SYS_GPS, CODE_L2L}, /* 3: GPS L2C */
248 {SYS_GPS, CODE_L5Q}, /* 4: GPS L5 */
249 {SYS_GPS, CODE_L1L}, /* 5: GPS L1C */
250 {SYS_QZS, CODE_L1C}, /* 6: QZS L1C/A */
251 {SYS_QZS, CODE_L2L}, /* 7: QZS L2C */
252 {SYS_GLO, CODE_L1C}, /* 8: GLO L1C/A */
253 {SYS_GLO, CODE_L1P}, /* 9: GLO L1P */
254 {SYS_GLO, CODE_L2P}, /* 10: GLO L2P */
255 {SYS_GLO, CODE_L2C}, /* 11: GLO L2C/A */
256 {SYS_GLO, CODE_L3Q}, /* 12: GLO L3 */
257 {SYS_CMP, CODE_L1P}, /* 13: BDS B1C */
258 {SYS_CMP, CODE_L5P}, /* 14: BDS B2a */
259 {SYS_IRN, CODE_L5A}, /* 15: IRN L5 */
260 {0, 0}, /* 16: reserved */
261 {SYS_GAL, CODE_L1C}, /* 17: GAL E1(L1BC) */
262 {0, 0}, /* 18: reserved */
263 {SYS_GAL, CODE_L6C}, /* 19: GAL E6(E6BC) */
264 {SYS_GAL, CODE_L5Q}, /* 20: GAL E5a */
265 {SYS_GAL, CODE_L7Q}, /* 21: GAL E5b */
266 {SYS_GAL, CODE_L8Q}, /* 22: GAL E5 AltBoc */
267 {0, 0}, /* 23: LBand */
268 {SYS_SBS, CODE_L1C}, /* 24: SBS L1C/A */
269 {SYS_SBS, CODE_L5I}, /* 25: SBS L5 */
270 {SYS_QZS, CODE_L5Q}, /* 26: QZS L5 */
271 {SYS_QZS, CODE_L6L}, /* 27: QZS L6 */
272 {SYS_CMP, CODE_L2I}, /* 28: BDS B1I */
273 {SYS_CMP, CODE_L7I}, /* 29: BDS B2I */
274 {SYS_CMP, CODE_L6I}, /* 30: BDS B3I */
275 {0, 0}, /* 31: reserved */
276 {SYS_QZS, CODE_L1L}, /* 32: QZS L1C */
277 {SYS_QZS, CODE_L1Z}, /* 33: QZS L1S */
278 {SYS_CMP, CODE_L7D}, /* 34: BDS B2b */
279 {0, 0}, /* 35: reserved */
280 {SYS_IRN, CODE_L9A}, /* 36: IRN S */
281 {0, 0}, /* 37: reserved */
282 {SYS_QZS, CODE_L1E}, /* 38: QZS L1E(L1CB) */
283 {SYS_QZS, CODE_L5Z} /* 39: QZS L5S */
284};
285/* signal number to freq-index and code --------------------------------------*/
286static int sig2idx(int sat, int sig, const raw_t* raw, uint8_t* code) {
287 const char* opt = raw->opt;
288 int idx, sys = satsys(sat, NULL), nex = NEXOBS;
289
290 if (sig < 0 || sig > SBF_MAXSIG || sig_tbl[sig][0] != sys) {
291 return -1;
292 }
293 *code = sig_tbl[sig][1];
294
295 /* #189: when [positioning].signals (sigcfg) is configured, it is authoritative
296 * for per-band code selection (e.g. GLONASS L2C/A as the 2nd frequency). Fall
297 * through to the legacy -R/-G option logic only when this system has no sigcfg
298 * entry (NOOPINION). */
299 if (raw->sigcfg_set) {
300 int r = mrtk_sigcfg_freq_idx(sys, *code, raw->sigcfg, nex);
301 if (r != MRTK_SIGCFG_NOOPINION) {
302 return r;
303 }
304 }
305
306 idx = code2freq_idx(sys, *code);
307
308 /* resolve code priority in a freq-index */
309 if (sys == SYS_GPS) {
310 if (strstr(opt, "-GL1W") && idx == 0) {
311 return (*code == CODE_L1W) ? 0 : -1;
312 }
313 if (strstr(opt, "-GL1L") && idx == 0) {
314 return (*code == CODE_L1L) ? 0 : -1;
315 }
316 if (strstr(opt, "-GL2L") && idx == 1) {
317 return (*code == CODE_L2L) ? 1 : -1;
318 }
319 if (*code == CODE_L1W) {
320 return (nex < 1) ? -1 : NFREQ;
321 }
322 if (*code == CODE_L2L) {
323 return (nex < 2) ? -1 : NFREQ + 1;
324 }
325 if (*code == CODE_L1L) {
326 return (nex < 3) ? -1 : NFREQ + 2;
327 }
328 } else if (sys == SYS_GLO) {
329 if (strstr(opt, "-RL1P") && idx == 0) {
330 return (*code == CODE_L1P) ? 0 : -1;
331 }
332 if (strstr(opt, "-RL2C") && idx == 1) {
333 return (*code == CODE_L2C) ? 1 : -1;
334 }
335 if (*code == CODE_L1P) {
336 return (nex < 1) ? -1 : NFREQ;
337 }
338 if (*code == CODE_L2C) {
339 return (nex < 2) ? -1 : NFREQ + 1;
340 }
341 } else if (sys == SYS_QZS) {
342 if (strstr(opt, "-JL1L") && idx == 0) {
343 return (*code == CODE_L1L) ? 0 : -1;
344 }
345 if (strstr(opt, "-JL1Z") && idx == 0) {
346 return (*code == CODE_L1Z) ? 0 : -1;
347 }
348 if (*code == CODE_L1L) {
349 return (nex < 1) ? -1 : NFREQ;
350 }
351 if (*code == CODE_L1Z) {
352 return (nex < 2) ? -1 : NFREQ + 1;
353 }
354 } else if (sys == SYS_CMP) {
355 if (strstr(opt, "-CL1P") && idx == 0) {
356 return (*code == CODE_L1P) ? 0 : -1;
357 }
358 if (*code == CODE_L1P) {
359 return (nex < 1) ? -1 : NFREQ;
360 }
361 }
362 return (idx < NFREQ) ? idx : -1;
363}
364/* initialize obs data fields ------------------------------------------------*/
365static void init_obsd(gtime_t time, int sat, obsd_t* data) {
366 int i;
367
368 data->time = time;
369 data->sat = (uint8_t)sat;
370
371 for (i = 0; i < NFREQ + NEXOBS; i++) {
372 data->L[i] = data->P[i] = 0.0;
373 data->D[i] = 0.0f;
374 data->SNR[i] = (uint16_t)0;
375 data->LLI[i] = (uint8_t)0;
376 data->code[i] = CODE_NONE;
377 }
378}
379/* decode SBF GNSS measurements ----------------------------------------------*/
380static int decode_measepoch(raw_t* raw) {
381 uint8_t *p = raw->buff + 14, code;
382 double P1, P2, L1, L2, D1, D2, S1, S2, freq1, freq2;
383 int i, j, idx, n, n1, n2, len1, len2, sig, ant, svid, info, sat, sys, lock, fcn, LLI;
384 int ant_sel = 0; /* antenna selection (0:main) */
385
386 if (strstr(raw->opt, "-AUX1")) {
387 ant_sel = 1;
388 } else if (strstr(raw->opt, "-AUX2")) {
389 ant_sel = 2;
390 }
391
392 if (raw->len < 20) {
393 trace(NULL, 2, "sbf measepoch length error: len=%d\n", raw->len);
394 return -1;
395 }
396 n1 = U1(p);
397 len1 = U1(p + 1);
398 len2 = U1(p + 2);
399
400 if (U1(p + 3) & 0x80) {
401 trace(NULL, 2, "sbf measepoch scrambled\n");
402 return -1;
403 }
404 if (raw->outtype) {
405 sprintf(raw->msgtype + strlen(raw->msgtype), " nsat=%d", n1);
406 }
407 for (i = n = 0, p += 6; i < n1 && n < MAXOBS && p + 20 <= raw->buff + raw->len; i++) {
408 svid = U1(p + 2);
409 ant = U1(p + 1) >> 5;
410 sig = U1(p + 1) & 0x1f;
411 info = U1(p + 18);
412 n2 = U1(p + 19);
413 fcn = 0;
414 if (sig == 31) {
415 sig = (info >> 3) + 32;
416 } else if (sig >= 8 && sig <= 11) {
417 fcn = (info >> 3) - 8;
418 }
419
420 if (ant != ant_sel) {
421 trace(NULL, 3, "sbf measepoch ant error: svid=%d ant=%d\n", svid, ant);
422 p += len1 + len2 * n2;
423 continue;
424 }
425 if (!(sat = svid2sat(svid))) {
426 trace(NULL, 3, "sbf measepoch svid error: svid=%d\n", svid);
427 p += len1 + len2 * n2;
428 continue;
429 }
430 init_obsd(raw->time, sat, raw->obs.data + n);
431 P1 = D1 = 0.0;
432 sys = satsys(sat, NULL);
433
434 /* Always extract Type-1 pseudorange, Doppler, and frequency —
435 * these are the base values for Type-2 delta computation
436 * regardless of whether the Type-1 signal is in obsdef. */
437 freq1 = 0.0;
438 if (sig >= 0 && sig <= SBF_MAXSIG && sig_tbl[sig][0] == sys) {
439 freq1 = code2freq(sys, sig_tbl[sig][1], fcn);
440 }
441 if ((U1(p + 3) & 0x1f) != 0 || U4(p + 4) != 0) {
442 P1 = (U1(p + 3) & 0x0f) * 4294967.296 + U4(p + 4) * 0.001;
443 }
444 if (I4(p + 8) != (-2147483647 - 1)) {
445 D1 = I4(p + 8) * 0.0001;
446 }
447
448 /* Store Type-1 observation only if the signal is in obsdef */
449 if ((idx = sig2idx(sat, sig, raw, &code)) >= 0) {
450 if (P1 != 0.0) {
451 raw->obs.data[n].P[idx] = P1;
452 }
453 if (D1 != 0.0) {
454 raw->obs.data[n].D[idx] = (float)D1;
455 }
456 lock = U2(p + 16);
457 if (P1 != 0.0 && freq1 > 0.0 && lock != 65535 && (I1(p + 14) != -128 || U2(p + 12) != 0)) {
458 L1 = I1(p + 14) * 65.536 + U2(p + 12) * 0.001;
459 raw->obs.data[n].L[idx] = P1 * freq1 / CLIGHT + L1;
460 LLI = 0;
461 if (lock < raw->lockt[sat - 1][idx]) {
462 LLI += 1;
463 }
464 if (info & (1 << 2)) {
465 LLI += 2;
466 }
467 raw->obs.data[n].LLI[idx] = (uint8_t)LLI;
468 raw->lockt[sat - 1][idx] = lock;
469 }
470 if (U1(p + 15) != 255) {
471 S1 = U1(p + 15) * 0.25 + ((sig == 1 || sig == 2) ? 0.0 : 10.0);
472 raw->obs.data[n].SNR[idx] = (uint16_t)(S1 / SNR_UNIT + 0.5);
473 }
474 raw->obs.data[n].code[idx] = code;
475 }
476
477 for (j = 0, p += len1; j < n2 && p + 12 <= raw->buff + raw->len; j++, p += len2) {
478 sig = U1(p) & 0x1f;
479 ant = U1(p) >> 5;
480 info = U1(p + 5);
481 if (sig == 31) {
482 sig = (info >> 3) + 32;
483 }
484
485 if (ant != ant_sel) {
486 trace(NULL, 3, "sbf measepoch ant error: sat=%d ant=%d\n", sat, ant);
487 continue;
488 }
489 if ((idx = sig2idx(sat, sig, raw, &code)) < 0) {
490 trace(NULL, 3, "sbf measepoch sig error: sat=%d sig=%d\n", sat, sig);
491 continue;
492 }
493 P2 = 0.0;
494 freq2 = code2freq(sys, code, fcn);
495
496 if (P1 != 0.0 && (getbits(p + 3, 5, 3) != -4 || U2(p + 6) != 0)) {
497 P2 = P1 + getbits(p + 3, 5, 3) * 65.536 + U2(p + 6) * 0.001;
498 raw->obs.data[n].P[idx] = P2;
499 }
500 if (P2 != 0.0 && freq2 > 0.0 && (I1(p + 4) != -128 || U2(p + 8) != 0)) {
501 L2 = I1(p + 4) * 65.536 + U2(p + 8) * 0.001;
502 raw->obs.data[n].L[idx] = P2 * freq2 / CLIGHT + L2;
503 }
504 if (D1 != 0.0 && freq1 > 0.0 && freq2 > 0.0 && (getbits(p + 3, 0, 5) != -16 || U2(p + 10) != 0)) {
505 D2 = getbits(p + 3, 0, 5) * 6.5536 + U2(p + 10) * 0.0001;
506 raw->obs.data[n].D[idx] = (float)(D1 * freq2 / freq1) + D2;
507 }
508 lock = U1(p + 1);
509 if (lock != 255) {
510 LLI = 0;
511 if (lock < raw->lockt[sat - 1][idx]) {
512 LLI += 1;
513 }
514 if (info & (1 << 2)) {
515 LLI += 2;
516 }
517 raw->obs.data[n].LLI[idx] = (uint8_t)LLI;
518 raw->lockt[sat - 1][idx] = lock;
519 }
520 if (U1(p + 2) != 255) {
521 S2 = U1(p + 2) * 0.25 + ((sig == 1 || sig == 2) ? 0.0 : 10.0);
522 raw->obs.data[n].SNR[idx] = (uint16_t)(S2 / SNR_UNIT + 0.5);
523 }
524 raw->obs.data[n].code[idx] = code;
525 }
526 /* advance obs counter only if at least one signal was accepted */
527 {
528 int has_obs = 0, ki;
529 for (ki = 0; ki < NFREQ + NEXOBS; ki++) {
530 if (raw->obs.data[n].code[ki] != 0) {
531 has_obs = 1;
532 break;
533 }
534 }
535 if (has_obs) {
536 n++;
537 }
538 }
539 }
540 raw->obs.n = n;
541 return 1;
542}
543/* decode SBF GNSS measurements extra info -----------------------------------*/
544static int decode_measextra(raw_t* raw) {
545 /* not yet supported */
546 return 0;
547}
548/* decode ephemeris ----------------------------------------------------------*/
549static int decode_eph(raw_t* raw, int sat) {
550 eph_t eph = {0};
551
552 if (!decode_frame(raw->subfrm[sat - 1], &eph, NULL, NULL, NULL)) {
553 return 0;
554 }
555
556 if (!strstr(raw->opt, "-EPHALL")) {
557 if (eph.iode == raw->nav.eph[sat - 1].iode && eph.iodc == raw->nav.eph[sat - 1].iodc &&
558 timediff(eph.toe, raw->nav.eph[sat - 1].toe) == 0.0 &&
559 timediff(eph.toc, raw->nav.eph[sat - 1].toc) == 0.0) {
560 return 0;
561 }
562 }
563 eph.sat = sat;
564 raw->nav.eph[sat - 1] = eph;
565 raw->ephsat = sat;
566 raw->ephset = 0;
567 return 2;
568}
569/* UTC 8-bit week -> full week -----------------------------------------------*/
570static void adj_utcweek(gtime_t time, double* utc) {
571 int week;
572
573 time2gpst(time, &week);
574 utc[3] += week / 256 * 256;
575 if (utc[3] < week - 127) {
576 utc[3] += 256.0;
577 } else if (utc[3] > week + 127) {
578 utc[3] -= 256.0;
579 }
580 utc[5] += utc[3] / 256 * 256;
581 if (utc[5] < utc[3] - 127) {
582 utc[5] += 256.0;
583 } else if (utc[5] > utc[3] + 127) {
584 utc[5] -= 256.0;
585 }
586}
587/* decode ION/UTC parameters -------------------------------------------------*/
588static int decode_ionutc(raw_t* raw, int sat) {
589 double ion[8], utc[8];
590 int sys = satsys(sat, NULL);
591
592 if (!decode_frame(raw->subfrm[sat - 1], NULL, NULL, ion, utc)) {
593 return 0;
594 }
595
596 adj_utcweek(raw->time, utc);
597 if (sys == SYS_QZS) {
598 matcpy(raw->nav.ion_qzs, ion, 8, 1);
599 matcpy(raw->nav.utc_qzs, utc, 8, 1);
600 } else {
601 matcpy(raw->nav.ion_gps, ion, 8, 1);
602 matcpy(raw->nav.utc_gps, utc, 8, 1);
603 }
604 return 9;
605}
606/* decode SBF raw C/A subframe -----------------------------------------------*/
607static int decode_rawca(raw_t* raw, int sys) {
608 uint8_t *p = raw->buff + 14, buff[30];
609 int i, svid, sat, prn, id, ret;
610
611 if (raw->len < 60) {
612 trace(NULL, 2, "sbf rawca length error: sys=%d len=%d\n", sys, raw->len);
613 return -1;
614 }
615 svid = U1(p);
616 if (!(sat = svid2sat(svid)) || satsys(sat, &prn) != sys) {
617 trace(NULL, 2, "sbf rawca svid error: sys=%d svid=%d\n", sys, svid);
618 return -1;
619 }
620 if (!U1(p + 1)) {
621 trace(NULL, 3, "sbf rawca parity/crc error: sys=%d prn=%d\n", sys, prn);
622 return 0;
623 }
624 if (raw->outtype) {
625 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
626 }
627 for (i = 0, p += 6; i < 10; i++, p += 4) { /* 24 x 10 bits w/o parity */
628 setbitu(buff, 24 * i, 24, U4(p) >> 6);
629 }
630 id = getbitu(buff, 43, 3);
631
632 if (id < 1 || id > 5) {
633 trace(NULL, 2, "sbf rawca subframe id error: sys=%d prn=%d id=%d\n", sys, prn, id);
634 return -1;
635 }
636 memcpy(raw->subfrm[sat - 1] + (id - 1) * 30, buff, 30);
637
638 if (id == 3) {
639 return decode_eph(raw, sat);
640 }
641 if (id == 4 || id == 5) {
642 ret = decode_ionutc(raw, sat);
643 memset(raw->subfrm[sat - 1] + id * 30, 0, 30);
644 return ret;
645 }
646 return 0;
647}
648/* decode SBF GPS C/A subframe -----------------------------------------------*/
649static int decode_gpsrawca(raw_t* raw) { return decode_rawca(raw, SYS_GPS); }
650/* decode SBF GLONASS L1CA or L2CA navigation string -------------------------*/
651static int decode_glorawca(raw_t* raw) {
652 geph_t geph = {0};
653 gtime_t* time;
654 double utc[8] = {0};
655 uint8_t *p = raw->buff + 14, buff[12];
656 int i, svid, sat, prn, m;
657
658 if (raw->len < 32) {
659 trace(NULL, 2, "sbf glorawca length error: len=%d\n", raw->len);
660 return -1;
661 }
662 svid = U1(p);
663 if (!(sat = svid2sat(svid)) || satsys(sat, &prn) != SYS_GLO) {
664 trace(NULL, 3, "sbf glorawca svid error: svid=%d\n", svid);
665 return (svid == 62) ? 0 : -1; /* svid=62: slot unknown */
666 }
667 if (!U1(p + 1)) {
668 trace(NULL, 3, "sbf glorawca parity/crc error: prn=%d\n", prn);
669 return 0;
670 }
671 if (raw->outtype) {
672 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
673 }
674 for (i = 0; i < 3; i++) {
675 setbitu(buff, 32 * i, 32, U4(p + 6 + 4 * i)); /* 85 bits */
676 }
677 m = getbitu(buff, 1, 4);
678 if (m < 1 || m > 15) {
679 trace(NULL, 2, "sbf glorawca string number error: prn=%d m=%d\n", prn, m);
680 return -1;
681 }
682 time = (gtime_t*)(raw->subfrm[sat - 1] + 150);
683 if (fabs(timediff(raw->time, *time)) > 30.0) {
684 memset(raw->subfrm[sat - 1], 0, 40);
685 memcpy(time, &raw->time, sizeof(gtime_t));
686 }
687 memcpy(raw->subfrm[sat - 1] + (m - 1) * 10, buff, 10);
688 if (m != 4) {
689 return 0;
690 }
691
692 geph.tof = raw->time;
693 if (!decode_glostr(raw->subfrm[sat - 1], &geph, utc)) {
694 return 0;
695 }
696
697 matcpy(raw->nav.utc_glo, utc, 8, 1);
698
699 if (geph.sat != sat) {
700 trace(NULL, 2, "sbf glorawca satellite error: sat=%d %d\n", sat, geph.sat);
701 return -1;
702 }
703 geph.frq = (int)U1(p + 4) - 8;
704
705 if (!strstr(raw->opt, "-EPHALL")) {
706 if (geph.iode == raw->nav.geph[prn - 1].iode && geph.svh == raw->nav.geph[prn - 1].svh &&
707 timediff(geph.toe, raw->nav.geph[prn - 1].toe) == 0.0) {
708 return 0;
709 }
710 }
711 raw->nav.geph[prn - 1] = geph;
712 raw->ephsat = sat;
713 raw->ephset = 0;
714 return 2;
715}
716/* decode SBF Galileo F/NAV navigation page ----------------------------------*/
717static int decode_galrawfnav(raw_t* raw) {
718 eph_t eph = {0};
719 double ion[4] = {0}, utc[8] = {0};
720 uint8_t *p = raw->buff + 14, buff[32], crc_buff[27];
721 int i, svid, src, sat, prn, type;
722
723 if (strstr(raw->opt, "-GALINAV")) {
724 return 0;
725 }
726
727 if (raw->len < 52) {
728 trace(NULL, 2, "sbf galrawfnav length error: len=%d\n", raw->len);
729 return -1;
730 }
731 svid = U1(p);
732 src = U1(p + 3) & 0x1f;
733
734 if (!(sat = svid2sat(svid)) || satsys(sat, &prn) != SYS_GAL) {
735 trace(NULL, 2, "sbf galrawfnav svid error: svid=%d src=%d\n", svid, src);
736 return -1;
737 }
738 if (raw->outtype) {
739 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d src=%d", prn, src);
740 }
741 if (src != 20 && src != 22) { /* E5a or E5 AltBOC */
742 trace(NULL, 2, "sbf galrawfnav source error: prn=%d src=%d\n", prn, src);
743 return -1;
744 }
745 for (i = 0; i < 8; i++) {
746 setbitu(buff, 32 * i, 32, U4(p + 6 + 4 * i)); /* 244 bits page */
747 }
748 for (i = 0; i < 27; i++) { /* data(214) + CRC(24) */
749 if (i == 0) {
750 crc_buff[i] = getbitu(buff, 0, 6);
751 } else {
752 crc_buff[i] = getbitu(buff, 8 * i - 2, 8);
753 }
754 }
755 trace(NULL, 4, "sbf galrawfnav: prn=%d src=%d crc=%06x %06x\n", prn, src, rtk_crc24q(crc_buff, 27),
756 getbitu(buff, 214, 24));
757
758 if (!U1(p + 1)) {
759 trace(NULL, 3, "sbf galrawfnav parity/crc error: prn=%d src=%d\n", prn, src);
760 return 0;
761 }
762 type = getbitu(buff, 0, 6); /* page type */
763
764 if (type == 63) {
765 return 0; /* dummy page */
766 }
767 if (type < 1 || type > 6) {
768 trace(NULL, 2, "sbf galrawfnav page type error: prn=%d type=%d\n", prn, type);
769 return -1;
770 }
771 /* save 244 bits page (31 bytes * 6 page) */
772 memcpy(raw->subfrm[sat - 1] + 128 + (type - 1) * 31, buff, 31);
773
774 if (type != 4) {
775 return 0;
776 }
777 if (!decode_gal_fnav(raw->subfrm[sat - 1] + 128, &eph, ion, utc)) {
778 return 0;
779 }
780
781 if (eph.sat != sat) {
782 trace(NULL, 2, "sbf galrawfnav satellite error: sat=%d %d\n", sat, eph.sat);
783 return -1;
784 }
785 eph.code |= (1 << 1); /* data source: E5a */
786
787 adj_utcweek(raw->time, utc);
788 matcpy(raw->nav.ion_gal, ion, 4, 1);
789 matcpy(raw->nav.utc_gal, utc, 8, 1);
790
791 if (!strstr(raw->opt, "-EPHALL")) {
792 if (eph.iode == raw->nav.eph[sat - 1 + MAXSAT].iode &&
793 timediff(eph.toe, raw->nav.eph[sat - 1 + MAXSAT].toe) == 0.0 &&
794 timediff(eph.toc, raw->nav.eph[sat - 1 + MAXSAT].toc) == 0.0) {
795 return 0;
796 }
797 }
798 raw->nav.eph[sat - 1 + MAXSAT] = eph;
799 raw->ephsat = sat;
800 raw->ephset = 1; /* 1:F/NAV */
801 return 2;
802}
803/* decode SBF Galileo I/NAV navigation page ----------------------------------*/
804static int decode_galrawinav(raw_t* raw) {
805 eph_t eph = {0};
806 double ion[4] = {0}, utc[8] = {0};
807 uint8_t *p = raw->buff + 14, buff[32], crc_buff[25], type, part1, part2, page1, page2;
808 int i, j, svid, src, sat, prn;
809
810 if (strstr(raw->opt, "-GALFNAV")) {
811 return 0;
812 }
813
814 if (raw->len < 52) {
815 trace(NULL, 2, "sbf galrawinav length error: len=%d\n", raw->len);
816 return -1;
817 }
818 svid = U1(p);
819 src = U1(p + 3) & 0x1f;
820
821 if (!(sat = svid2sat(svid)) || satsys(sat, &prn) != SYS_GAL) {
822 trace(NULL, 2, "sbf galrawinav svid error: svid=%d src=%d\n", svid, src);
823 return -1;
824 }
825 if (raw->outtype) {
826 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d src=%d", prn, src);
827 }
828 if (src != 17 && src != 21 && src != 22) { /* E1, E5b or E5 AltBOC */
829 trace(NULL, 2, "sbf galrawinav source error: prn=%d src=%d\n", prn, src);
830 return -1;
831 }
832 for (i = 0; i < 8; i++) {
833 setbitu(buff, 32 * i, 32, U4(p + 6 + i * 4)); /* 114(even) + 120(odd) bits */
834 }
835 for (i = 0; i < 25; i++) { /* data(196) + CRC(24) */
836 if (i == 0) {
837 crc_buff[i] = getbitu(buff, 0, 4);
838 } else {
839 crc_buff[i] = getbitu(buff, 8 * i - 4, 8);
840 }
841 }
842 trace(NULL, 4, "sbf galrawinav: prn=%d src=%d crc=%06x %06x\n", prn, src, rtk_crc24q(crc_buff, 25),
843 getbitu(buff, 196, 24));
844
845 if (!U1(p + 1)) {
846 trace(NULL, 3, "sbf galrawinav parity/crc error: prn=%d src=%d\n", prn, src);
847 return 0;
848 }
849 part1 = getbitu(buff, 0, 1);
850 page1 = getbitu(buff, 1, 1);
851 part2 = getbitu(buff, 114, 1);
852 page2 = getbitu(buff, 115, 1);
853
854 if (part1 != 0 || part2 != 1) {
855 trace(NULL, 3, "sbf galrawinav part error: prn=%d even/odd=%d %d\n", prn, part1, part2);
856 return -1;
857 }
858 if (page1 == 1 || page2 == 1) {
859 return 0; /* alert page */
860 }
861
862 type = getbitu(buff, 2, 6); /* word type */
863
864 if (type > 6) {
865 return 0;
866 }
867
868 /* save 128 (112:even+16:odd) bits word (16 bytes * 7 word) */
869 for (i = 0, j = 2; i < 14; i++, j += 8) {
870 raw->subfrm[sat - 1][type * 16 + i] = getbitu(buff, j, 8);
871 }
872 for (i = 14, j = 116; i < 16; i++, j += 8) {
873 raw->subfrm[sat - 1][type * 16 + i] = getbitu(buff, j, 8);
874 }
875 if (type != 5) {
876 return 0;
877 }
878 if (!decode_gal_inav(raw->subfrm[sat - 1], &eph, ion, utc)) {
879 return 0;
880 }
881
882 if (eph.sat != sat) {
883 trace(NULL, 2, "sbf galrawinav satellite error: sat=%d %d\n", sat, eph.sat);
884 return -1;
885 }
886 eph.code |= (src == 17) ? (1 << 0) : (1 << 2); /* data source: E1 or E5b */
887
888 adj_utcweek(raw->time, utc);
889 matcpy(raw->nav.ion_gal, ion, 4, 1);
890 matcpy(raw->nav.utc_gal, utc, 8, 1);
891
892 if (!strstr(raw->opt, "-EPHALL")) {
893 if (eph.iode == raw->nav.eph[sat - 1].iode && timediff(eph.toe, raw->nav.eph[sat - 1].toe) == 0.0 &&
894 timediff(eph.toc, raw->nav.eph[sat - 1].toc) == 0.0) {
895 return 0;
896 }
897 }
898 raw->nav.eph[sat - 1] = eph;
899 raw->ephsat = sat;
900 raw->ephset = 0; /* 0:I/NAV */
901 return 2;
902}
903/* decode SBF Galileo E6-B C/NAV page (HAS) ----------------------------------*/
904/**
905 * @brief Decode an SBF GALRawCNAV block (4024) into a staged Galileo HAS page.
906 *
907 * The block payload (after the 8-byte SBF header) is: TOW u4, WNc u2, SVID u1,
908 * CRCPassed u1, ViterbiCnt u1, Source u1, FreqNr u1, RxChannel u1,
909 * NAVBits u4[16]. The 16 little-endian words are concatenated MSB-first into
910 * 512 bits; the 448-bit HAS page is bits 14..461 (56 bytes). The staged page is
911 * routed to svr->has by decoderaw(). Dummy pages (24-bit header 0xAF3BC3),
912 * CRC failures and out-of-range PRNs are skipped here (return 0); TOW sentinels
913 * are filtered upstream in decode_sbf before this handler runs.
914 *
915 * @param[in,out] raw Receiver raw data control struct (buff holds the block;
916 * raw->time already set by input_sbf from this block's
917 * TOW/WNc)
918 * @return 13 when a valid HAS page is staged in raw->has_page/has_prn/has_time,
919 * 0 when the page is skipped, -1 on length error.
920 */
921static int decode_galrawcnav(raw_t* raw) {
922 uint8_t* p = raw->buff + 14;
923 uint8_t bits[64]; /* 512 bits, MSB-first */
924 uint32_t hdr24;
925 int i, svid, crc_ok, prn, srcbit, b;
926
927 /* need SVID(1) CRCPassed(1) ...(4) + NAVBits u4[16]: 14 hdr + 6 + 64 = 84 */
928 if (raw->len < 84) {
929 trace(NULL, 2, "sbf galrawcnav length error: len=%d\n", raw->len);
930 return -1;
931 }
932 svid = U1(p);
933 crc_ok = U1(p + 1);
934
935 prn = svid - 70; /* GAL PRN = SVID - 70 */
936 if (prn < 1 || prn > 40) {
937 trace(NULL, 2, "sbf galrawcnav svid error: svid=%d\n", svid);
938 return 0;
939 }
940 if (raw->outtype) {
941 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d crc=%d", prn, crc_ok);
942 }
943 if (!crc_ok) {
944 trace(NULL, 3, "sbf galrawcnav crc fail: prn=%d\n", prn);
945 return 0;
946 }
947
948 /* concatenate 16 NAVBits words MSB-first into a 512-bit buffer */
949 for (i = 0; i < 16; i++) {
950 uint32_t w = U4(raw->buff + 20 + i * 4);
951 bits[i * 4] = (w >> 24) & 0xFF;
952 bits[i * 4 + 1] = (w >> 16) & 0xFF;
953 bits[i * 4 + 2] = (w >> 8) & 0xFF;
954 bits[i * 4 + 3] = w & 0xFF;
955 }
956
957 /* HAS page = bits 14..461 (448 bits = 56 bytes), MSB-first */
958 for (i = 0; i < 56 * 8; i++) {
959 srcbit = 14 + i;
960 b = (bits[srcbit >> 3] >> (7 - (srcbit & 7))) & 1;
961 if (b) {
962 raw->has_page[i >> 3] |= (uint8_t)(1 << (7 - (i & 7)));
963 } else {
964 raw->has_page[i >> 3] &= (uint8_t)~(1 << (7 - (i & 7)));
965 }
966 }
967
968 /* skip dummy pages (24-bit HAS header == 0xAF3BC3) */
969 hdr24 = ((uint32_t)raw->has_page[0] << 16) | ((uint32_t)raw->has_page[1] << 8) | raw->has_page[2];
970 if (hdr24 == 0xAF3BC3) {
971 return 0;
972 }
973
974 raw->has_prn = prn;
975 raw->has_time = raw->time; /* set by input_sbf from this block's TOW/WNc */
976 return 13;
977}
978/* decode SBF SBAS L1 navigation frame ---------------------------------------*/
979static int decode_georawl1(raw_t* raw) {
980 uint8_t *p = raw->buff + 14, buff[32];
981 int i, svid, sat, prn;
982
983 if (raw->len < 52) {
984 trace(NULL, 2, "sbf georawl1 length error: len=%d\n", raw->len);
985 return -1;
986 }
987 svid = U1(p);
988 if (!(sat = svid2sat(svid)) || satsys(sat, &prn) != SYS_SBS) {
989 trace(NULL, 2, "sbf georawl1 svid error: svid=%d\n", svid);
990 return -1;
991 }
992 if (!U1(p + 1)) {
993 trace(NULL, 3, "sbf georawl1 parity/crc error: prn=%d err=%d\n", prn, U1(p + 2));
994 return 0;
995 }
996 if (raw->outtype) {
997 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
998 }
999 raw->sbsmsg.tow = (int)time2gpst(raw->time, &raw->sbsmsg.week);
1000 raw->sbsmsg.prn = prn;
1001
1002 for (i = 0; i < 8; i++) {
1003 setbitu(buff, 32 * i, 32, U4(p + 6 + 4 * i));
1004 }
1005 memcpy(raw->sbsmsg.msg, buff, 29); /* 226 bits w/o CRC */
1006 raw->sbsmsg.msg[28] &= 0xC0;
1007 return 3;
1008}
1009/* decode SBF BDS navigation frame -------------------------------------------*/
1010static int decode_bdsraw(raw_t* raw) {
1011 eph_t eph = {0};
1012 double ion[8], utc[8];
1013 uint8_t *p = raw->buff + 14, buff[40];
1014 int i, id, svid, sat, prn, pgn;
1015
1016 if (raw->len < 52) {
1017 trace(NULL, 2, "sbf bdsraw length error: len=%d\n", raw->len);
1018 return -1;
1019 }
1020 svid = U1(p);
1021 if (!(sat = svid2sat(svid)) || satsys(sat, &prn) != SYS_CMP) {
1022 trace(NULL, 2, "sbf bdsraw svid error: svid=%d\n", svid);
1023 return -1;
1024 }
1025 if (!U1(p + 1)) {
1026 trace(NULL, 3, "sbf bdsraw parity/crc error: prn=%d\n", prn);
1027 return 0;
1028 }
1029 if (raw->outtype) {
1030 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
1031 }
1032 for (i = 0, p += 6; i < 10; i++, p += 4) {
1033 setbitu(buff, 32 * i, 32, U4(p));
1034 }
1035 id = getbitu(buff, 15, 3); /* subframe ID */
1036 if (id < 1 || id > 5) {
1037 trace(NULL, 2, "sbf bdsraw id error: prn=%d id=%d\n", prn, id);
1038 return -1;
1039 }
1040 if (prn >= 6 && prn <= 58) { /* IGSO/MEO */
1041 memcpy(raw->subfrm[sat - 1] + (id - 1) * 38, buff, 38);
1042
1043 if (id == 3) {
1044 if (!decode_bds_d1(raw->subfrm[sat - 1], &eph, NULL, NULL)) {
1045 return 0;
1046 }
1047 } else if (id == 5) {
1048 if (!decode_bds_d1(raw->subfrm[sat - 1], NULL, ion, utc)) {
1049 return 0;
1050 }
1051 matcpy(raw->nav.ion_cmp, ion, 8, 1);
1052 matcpy(raw->nav.utc_cmp, utc, 8, 1);
1053 return 9;
1054 } else {
1055 return 0;
1056 }
1057 } else { /* GEO */
1058 pgn = getbitu(buff, 42, 4); /* page number */
1059
1060 if (id == 1 && pgn >= 1 && pgn <= 10) {
1061 memcpy(raw->subfrm[sat - 1] + (pgn - 1) * 38, buff, 38);
1062 if (pgn != 10) {
1063 return 0;
1064 }
1065 if (!decode_bds_d2(raw->subfrm[sat - 1], &eph, NULL)) {
1066 return 0;
1067 }
1068 } else if (id == 1 && pgn == 102) {
1069 memcpy(raw->subfrm[sat - 1] + 10 * 38, buff, 38);
1070 if (!decode_bds_d2(raw->subfrm[sat - 1], NULL, utc)) {
1071 return 0;
1072 }
1073 matcpy(raw->nav.utc_cmp, utc, 8, 1);
1074 return 9;
1075 } else {
1076 return 0;
1077 }
1078 }
1079 if (!strstr(raw->opt, "-EPHALL")) {
1080 if (timediff(eph.toe, raw->nav.eph[sat - 1].toe) == 0.0) {
1081 return 0;
1082 }
1083 }
1084 eph.sat = sat;
1085 raw->nav.eph[sat - 1] = eph;
1086 raw->ephsat = sat;
1087 raw->ephset = 0;
1088 return 2;
1089}
1090/* decode SBF QZS C/A subframe -----------------------------------------------*/
1091static int decode_qzsrawl1ca(raw_t* raw) { return decode_rawca(raw, SYS_QZS); }
1092/* decode SBF QZS L6 message (QZSRawL6 / QZSRawL6D / QZSRawL6E) ---------------
1093 * Parses the shared QZSRawL6x header + 250-byte L6 frame and routes it by the
1094 * L6 header service (decode_qzss_l6frame): 10 CLAS frame for the caller's
1095 * redirect, 15 MADOCA-PPP SSR decoded, 16 MADOCA-PPP iono frame, 17 QZNMA
1096 * frame. Handles both the legacy generic block (4069, mosaic-CLAS) and the
1097 * signal-split blocks (4270/4271, mosaic-G5).
1098 *---------------------------------------------------------------------------*/
1099static int decode_qzsrawl6(raw_t* raw, rtcm_t* rtcm) {
1100 gtime_t time;
1101 double tow;
1102 int prn, sat, week, i, j, ret;
1103 unsigned char svid, parity, rscnt, source, rxchannel;
1104 uint8_t* p = (raw->buff) + 8; /* jump to TOW location */
1105 unsigned char buff[256];
1106
1107 if (raw->len < 272) {
1108 trace(NULL, 2, "SBF decode_qzsrawl6 frame length error: len=%d\n", raw->len);
1109 return -1;
1110 }
1111
1112 /* Get time information */
1113 tow = U4(p); /* TOW in ms */
1114 week = U2(p + 4); /* number of weeks */
1115 time = gpst2time(week, tow * 0.001);
1116
1117 svid = U1(p + 6);
1118 parity = U1(p + 7);
1119 rscnt = U1(p + 8);
1120 source = U1(p + 9);
1121 rxchannel = U1(p + 11);
1122
1123 prn = svid - 180 + MINPRNQZS - 1;
1124 sat = satno(SYS_QZS, prn);
1125
1126 if (sat == 0) {
1127 trace(NULL, 2, "SBF decode_qzssl6 SVID error: SVID=%d,prn=%d\n", svid, prn);
1128 return -1;
1129 }
1130 trace(NULL, 3, "SBF QZSRawL6 : %s, prn=%d,SVID=%d, Parity=%d, RSCnt=%d, Source=%d, rxchannel=%d\n",
1131 time_str(time, 0), prn, svid, parity, rscnt, source, rxchannel);
1132
1133 if (parity == 0) {
1134 trace(NULL, 2, "SBF decode_qzsrawl6 RS decode error\n");
1135 return -1;
1136 }
1137
1138 j = 0;
1139 for (i = 0; i < 63; i++) {
1140 buff[j] = ((U4(p + 12 + i * 4) >> 24) & 0x000000FF); /* take first byte */
1141 buff[1 + j] = ((U4(p + 12 + i * 4) >> 16) & 0x000000FF); /* take second byte */
1142 buff[2 + j] = ((U4(p + 12 + i * 4) >> 8) & 0x000000FF); /* take third byte */
1143 buff[3 + j] = ((U4(p + 12 + i * 4)) & 0x000000FF); /* take fourth byte */
1144 j = j + 4;
1145 }
1146
1147 memcpy(rtcm->buff, buff, 250);
1148 raw->l6tag = week * 604800.0 + tow * 0.001;
1149
1150 /* Route by the L6 header (vendor ID + CSID), not by the SBF Source field
1151 * or the satellite PRN: L6E PRNs time-multiplex MADOCA-PPP and QZNMA, and
1152 * PRN 197 carries CLAS (IS-QZSS-MDC rev 002), not MADOCA iono. Source
1153 * (1=L6D, 2=L6E) only decides the legacy handling of null messages. */
1154 ret = decode_qzss_l6frame(rtcm, source == 1);
1155 if (ret == 10 || ret == 16) {
1156 raw->ephsat = sat; /* L6D satellite for redirect / cssr2rtcm3 filtering */
1157 }
1158 return ret;
1159}
1160/* decode SBF NavIC/IRNSS subframe -------------------------------------------*/
1161static int decode_navicraw(raw_t* raw) {
1162 eph_t eph = {0};
1163 double ion[8], utc[9];
1164 uint8_t *p = raw->buff + 14, buff[40];
1165 int i, id, svid, sat, prn, ret = 0;
1166
1167 if (raw->len < 52) {
1168 trace(NULL, 2, "sbf navicraw length error: len=%d\n", raw->len);
1169 return -1;
1170 }
1171 svid = U1(p);
1172 if (!(sat = svid2sat(svid)) || satsys(sat, &prn) != SYS_IRN) {
1173 trace(NULL, 2, "sbf navicraw svid error: svid=%d\n", svid);
1174 return -1;
1175 }
1176 if (!U1(p + 1)) {
1177 trace(NULL, 3, "sbf navicraw parity/crc error: prn=%d err=%d\n", prn, U1(p + 2));
1178 return 0;
1179 }
1180 if (raw->outtype) {
1181 sprintf(raw->msgtype + strlen(raw->msgtype), " prn=%d", prn);
1182 }
1183 for (i = 0, p += 6; i < 10; i++, p += 4) {
1184 setbitu(buff, 32 * i, 32, U4(p));
1185 }
1186 id = getbitu(buff, 27, 2); /* subframe ID (0-3) */
1187
1188 memcpy(raw->subfrm[sat - 1] + id * 37, buff, 37);
1189
1190 if (id == 1) { /* subframe 2 */
1191 if (!decode_irn_nav(raw->subfrm[sat - 1], &eph, NULL, NULL)) {
1192 return 0;
1193 }
1194
1195 if (!strstr(raw->opt, "-EPHALL")) {
1196 if (eph.iode == raw->nav.eph[sat - 1].iode && timediff(eph.toe, raw->nav.eph[sat - 1].toe) == 0.0) {
1197 return 0;
1198 }
1199 }
1200 eph.sat = sat;
1201 raw->nav.eph[sat - 1] = eph;
1202 raw->ephsat = sat;
1203 raw->ephset = 0;
1204 return 2;
1205 } else if (id == 2 || id == 3) { /* subframe 3 or 4 */
1206 if (decode_irn_nav(raw->subfrm[sat - 1], NULL, ion, NULL)) {
1207 matcpy(raw->nav.ion_irn, ion, 8, 1);
1208 ret = 9;
1209 }
1210 if (decode_irn_nav(raw->subfrm[sat - 1], NULL, NULL, utc)) {
1211 adj_utcweek(raw->time, utc);
1212 matcpy(raw->nav.utc_irn, utc, 9, 1);
1213 ret = 9;
1214 }
1215 memset(raw->subfrm[sat - 1] + id * 37, 0, 37);
1216 return ret;
1217 }
1218 return 0;
1219}
1220/* decode SBF GPS decoded navigation (GPSNav 5891) ---------------------------*/
1221static int decode_gpsnav(raw_t* raw) {
1222 eph_t eph = {0};
1223 uint8_t prn, sat;
1224 uint16_t week;
1225 uint32_t tocs;
1226
1227 trace(NULL, 4, "SBF decode_gpsnav: len=%d\n", raw->len);
1228
1229 if (raw->len < 140) {
1230 trace(NULL, 2, "SBF decode_gpsnav frame length error: len=%d\n", raw->len);
1231 return -1;
1232 }
1233 prn = U1(raw->buff + 14);
1234 sat = satno(SYS_GPS, prn);
1235 if (sat == 0 || !(prn >= 1 && prn <= 37)) {
1236 trace(NULL, 2, "SBF decode_gpsnav prn error: prn=%d\n", prn);
1237 return -1;
1238 }
1239 week = U2(raw->buff + 12);
1240 eph.code = U1(raw->buff + 18);
1241 eph.sva = U1(raw->buff + 19);
1242 eph.svh = U1(raw->buff + 20);
1243 eph.flag = U1(raw->buff + 21);
1244 eph.iodc = U2(raw->buff + 22);
1245 eph.iode = U1(raw->buff + 24);
1246 eph.fit = U1(raw->buff + 26) ? 6 : 4;
1247 eph.tgd[0] = R4(raw->buff + 28);
1248 tocs = U4(raw->buff + 32);
1249 eph.f2 = R4(raw->buff + 36);
1250 eph.f1 = R4(raw->buff + 40);
1251 eph.f0 = R4(raw->buff + 44);
1252 eph.crs = R4(raw->buff + 48);
1253 eph.deln = R4(raw->buff + 52) * PI;
1254 eph.M0 = R8(raw->buff + 56) * PI;
1255 eph.cuc = R4(raw->buff + 64);
1256 eph.e = R8(raw->buff + 68);
1257 eph.cus = R4(raw->buff + 76);
1258 eph.A = pow(R8(raw->buff + 80), 2);
1259 eph.toes = U4(raw->buff + 88);
1260 eph.cic = R4(raw->buff + 92);
1261 eph.OMG0 = R8(raw->buff + 96) * PI;
1262 eph.cis = R4(raw->buff + 104);
1263 eph.i0 = R8(raw->buff + 108) * PI;
1264 eph.crc = R4(raw->buff + 116);
1265 eph.omg = R8(raw->buff + 120) * PI;
1266 eph.OMGd = R4(raw->buff + 128) * PI;
1267 eph.idot = R4(raw->buff + 132) * PI;
1268 eph.week = adjgpsweek(week);
1269 eph.toe = gpst2time(adjgpsweek(adjust_WN10(week, U2(raw->buff + 138))), eph.toes);
1270 eph.toc = gpst2time(adjgpsweek(adjust_WN10(week, U2(raw->buff + 136))), tocs);
1271 eph.ttr = raw->time;
1272
1273 if (!strstr(raw->opt, "-EPHALL")) {
1274 if (eph.iode == raw->nav.eph[sat - 1].iode && eph.iodc == raw->nav.eph[sat - 1].iodc) return 0;
1275 }
1276 eph.sat = sat;
1277 raw->nav.eph[sat - 1] = eph;
1278 raw->ephsat = sat;
1279 raw->ephset = 0;
1280 return 2;
1281}
1282/* decode SBF GLONASS decoded navigation (GLONav 4004) -----------------------*/
1283static int decode_glonav(raw_t* raw) {
1284 geph_t eph = {0};
1285 uint8_t* p = raw->buff + 8;
1286 int prn, sat;
1287 uint16_t week, week_toes;
1288 uint32_t toes;
1289
1290 trace(NULL, 4, "SBF decode_glonav: len=%d\n", raw->len);
1291
1292 if (raw->len < 96) {
1293 trace(NULL, 2, "SBF decode_glonav frame length error: len=%d\n", raw->len);
1294 return -1;
1295 }
1296 prn = U1(p + 6) - 37;
1297 sat = satno(SYS_GLO, prn);
1298 if (sat == 0 || !(prn >= 1 && prn <= 24)) {
1299 trace(NULL, 2, "SBF decode_glonav prn error: prn=%d\n", prn);
1300 return -1;
1301 }
1302 week = U2(p + 4);
1303 eph.frq = U1(p + 7) - 8;
1304 eph.pos[0] = R8(p + 8) * 1000.0;
1305 eph.pos[1] = R8(p + 16) * 1000.0;
1306 eph.pos[2] = R8(p + 24) * 1000.0;
1307 eph.vel[0] = R4(p + 32) * 1000.0;
1308 eph.vel[1] = R4(p + 36) * 1000.0;
1309 eph.vel[2] = R4(p + 40) * 1000.0;
1310 eph.acc[0] = R4(p + 44) * 1000.0;
1311 eph.acc[1] = R4(p + 48) * 1000.0;
1312 eph.acc[2] = R4(p + 52) * 1000.0;
1313 eph.gamn = R4(p + 56);
1314 eph.taun = R4(p + 60);
1315 eph.dtaun = R4(p + 64);
1316 toes = U4(p + 68);
1317 week_toes = adjust_WN10(week, U2(p + 72));
1318 eph.age = U1(p + 76);
1319 eph.svh = U1(p + 77) >> 2;
1320 eph.iode = U2(p + 78);
1321 eph.sva = U2(p + 86);
1322 eph.tof = gpst2time(week, U4(p) * 0.001);
1323 eph.toe = gpst2time(week_toes, toes);
1324
1325 if (!strstr(raw->opt, "-EPHALL")) {
1326 if (eph.iode == raw->nav.geph[prn - 1].iode) return 0;
1327 }
1328 eph.sat = sat;
1329 raw->nav.geph[prn - 1] = eph;
1330 raw->ephsat = sat;
1331 raw->ephset = 0;
1332 raw->nav.glo_fcn[prn - 1] = eph.frq + 8;
1333 return 2;
1334}
1335/* decode SBF Galileo decoded navigation (GALNav 4002) -----------------------*/
1336static int decode_galnav(raw_t* raw) {
1337 eph_t eph = {0};
1338 uint8_t* p = raw->buff + 8;
1339 int prn, sat, code;
1340 uint16_t week_toe, week_toc, health;
1341 uint32_t tocs;
1342 uint8_t sva;
1343
1344 trace(NULL, 4, "SBF decode_galnav: len=%d\n", raw->len);
1345
1346 if (raw->len < 149) {
1347 trace(NULL, 2, "SBF decode_galnav frame length error: len=%d\n", raw->len);
1348 return -1;
1349 }
1350 prn = U1(p + 6) - 70;
1351 sat = satno(SYS_GAL, prn);
1352 if (sat == 0 || !(prn >= 1 && prn <= 36)) {
1353 trace(NULL, 2, "SBF decode_galnav prn error: prn=%d\n", prn);
1354 return -1;
1355 }
1356 eph.week = U2(p + 4);
1357 code = U1(p + 7);
1358 if (code != 2 && code != 16) {
1359 trace(NULL, 2, "SBF decode_galnav code error: prn=%d code=%d\n", prn, code);
1360 return -1;
1361 }
1362 eph.code = code == 2 ? (1 << 0) | (1 << 2) | (1 << 9) : (1 << 1) | (1 << 8);
1363 eph.A = pow(R8(p + 8), 2);
1364 eph.M0 = R8(p + 16) * PI;
1365 eph.e = R8(p + 24);
1366 eph.i0 = R8(p + 32) * PI;
1367 eph.omg = R8(p + 40) * PI;
1368 eph.OMG0 = R8(p + 48) * PI;
1369 eph.OMGd = R4(p + 56) * PI;
1370 eph.idot = R4(p + 60) * PI;
1371 eph.deln = R4(p + 64) * PI;
1372 eph.cuc = R4(p + 68);
1373 eph.cus = R4(p + 72);
1374 eph.crc = R4(p + 76);
1375 eph.crs = R4(p + 80);
1376 eph.cic = R4(p + 84);
1377 eph.cis = R4(p + 88);
1378 eph.toes = U4(p + 92);
1379 tocs = U4(p + 96);
1380 eph.f2 = R4(p + 100);
1381 eph.f1 = R4(p + 104);
1382 eph.f0 = R8(p + 108);
1383 week_toe = adjust_WN12(eph.week, U2(p + 116));
1384 week_toc = adjust_WN12(eph.week, U2(p + 118));
1385 eph.iode = U2(p + 120);
1386 eph.iodc = 0;
1387 health = U2(p + 122);
1388 {
1389 int svh = 0;
1390 if (health & 0x001) svh |= (health >> 1) & 7;
1391 if (health & 0x010) svh |= ((health >> 5) & 7) << 6;
1392 if (health & 0x100) svh |= ((health >> 9) & 7) << 3;
1393 eph.svh = svh;
1394 }
1395 sva = U1(p + (code == 2 ? 126 : 125));
1396 eph.sva = sva == 255 ? 0 : sva;
1397 if (R4(p + 128) != -2.e10f) eph.tgd[0] = R4(p + 128);
1398 if (R4(p + 132) != -2.e10f) eph.tgd[1] = R4(p + 132);
1399 eph.fit = 0;
1400 eph.toe = gpst2time(week_toe, eph.toes);
1401 eph.toc = gpst2time(week_toc, tocs);
1402 eph.ttr = gpst2time(eph.week, U4(p) * 0.001);
1403
1404 if (!strstr(raw->opt, "-EPHALL")) {
1405 if (eph.iode == raw->nav.eph[sat - 1].iode) return 0;
1406 }
1407 eph.sat = sat;
1408 raw->nav.eph[sat - 1] = eph;
1409 raw->ephsat = sat;
1410 raw->ephset = 0;
1411 return 2;
1412}
1413/* decode SBF BDS decoded navigation (BDSNav 4081) ---------------------------*/
1414static int decode_bdsnav(raw_t* raw) {
1415 eph_t eph = {0};
1416 int prn, sat;
1417 uint16_t week, week_toc, week_toe;
1418 uint32_t tocs;
1419
1420 trace(NULL, 4, "SBF decode_bdsnav: len=%d\n", raw->len);
1421
1422 if (raw->len < 140) {
1423 trace(NULL, 2, "SBF decode_bdsnav frame length error: len=%d\n", raw->len);
1424 return -1;
1425 }
1426 prn = U1(raw->buff + 14) - 140;
1427 sat = satno(SYS_CMP, prn);
1428 if (sat == 0 || !(prn >= 1 && prn <= 63)) {
1429 trace(NULL, 2, "SBF decode_bdsnav prn error: prn=%d\n", prn);
1430 return -1;
1431 }
1432 eph.code = 0;
1433 eph.sva = U1(raw->buff + 18);
1434 eph.svh = U1(raw->buff + 19);
1435 eph.iodc = U1(raw->buff + 20);
1436 eph.iode = U1(raw->buff + 21);
1437 eph.tgd[0] = R4(raw->buff + 24);
1438 if (R4(raw->buff + 28) != -2.e10f) eph.tgd[1] = R4(raw->buff + 28);
1439 tocs = U4(raw->buff + 32);
1440 eph.f2 = R4(raw->buff + 36);
1441 eph.f1 = R4(raw->buff + 40);
1442 eph.f0 = R4(raw->buff + 44);
1443 eph.crs = R4(raw->buff + 48);
1444 eph.deln = R4(raw->buff + 52) * PI;
1445 eph.M0 = R8(raw->buff + 56) * PI;
1446 eph.cuc = R4(raw->buff + 64);
1447 eph.e = R8(raw->buff + 68);
1448 eph.cus = R4(raw->buff + 76);
1449 eph.A = pow(R8(raw->buff + 80), 2);
1450 eph.toes = U4(raw->buff + 88);
1451 eph.cic = R4(raw->buff + 92);
1452 eph.OMG0 = R8(raw->buff + 96) * PI;
1453 eph.cis = R4(raw->buff + 104);
1454 eph.i0 = R8(raw->buff + 108) * PI;
1455 eph.crc = R4(raw->buff + 116);
1456 eph.omg = R8(raw->buff + 120) * PI;
1457 eph.OMGd = R4(raw->buff + 128) * PI;
1458 eph.idot = R4(raw->buff + 132) * PI;
1459 week = U2(raw->buff + 12) - 1356; /* GPS week -> approx BDS week */
1460 week_toc = adjust_WN14(week, U2(raw->buff + 136));
1461 week_toe = adjust_WN14(week, U2(raw->buff + 138));
1462 eph.week = week_toe;
1463 eph.fit = 0;
1464 eph.toe = bdt2gpst(bdt2time(week_toe, eph.toes));
1465 eph.toc = bdt2gpst(bdt2time(week_toc, tocs));
1466 eph.ttr = raw->time;
1467
1468 if (!strstr(raw->opt, "-EPHALL")) {
1469 if (eph.iode == raw->nav.eph[sat - 1].iode) return 0;
1470 }
1471 eph.sat = sat;
1472 raw->nav.eph[sat - 1] = eph;
1473 raw->ephsat = sat;
1474 raw->ephset = 0;
1475 return 2;
1476}
1477/* decode SBF QZSS decoded navigation (QZSNav 4095) -------------------------*/
1478static int decode_qzssnav(raw_t* raw) {
1479 eph_t eph = {0};
1480 int svid, sat;
1481 uint16_t week;
1482 double toc;
1483
1484 trace(NULL, 4, "SBF decode_qzssnav: len=%d\n", raw->len);
1485
1486 if (raw->len < 140) {
1487 trace(NULL, 2, "SBF decode_qzssnav frame length error: len=%d\n", raw->len);
1488 return -1;
1489 }
1490 svid = U1(raw->buff + 14);
1491 sat = svid2sat(svid);
1492 if (sat == 0) {
1493 trace(NULL, 2, "SBF decode_qzssnav svid error: svid=%d\n", svid);
1494 return -1;
1495 }
1496 week = U2(raw->buff + 12);
1497 eph.code = U1(raw->buff + 18);
1498 eph.sva = U1(raw->buff + 19);
1499 eph.svh = U1(raw->buff + 20);
1500 eph.iodc = U2(raw->buff + 22);
1501 eph.iode = U1(raw->buff + 24);
1502 eph.fit = U1(raw->buff + 26) ? 4 : 2;
1503 if (R4(raw->buff + 28) != -2.e10f) eph.tgd[0] = R4(raw->buff + 28);
1504 toc = U4(raw->buff + 32);
1505 eph.f2 = R4(raw->buff + 36);
1506 eph.f1 = R4(raw->buff + 40);
1507 eph.f0 = R4(raw->buff + 44);
1508 eph.crs = R4(raw->buff + 48);
1509 eph.deln = R4(raw->buff + 52) * PI;
1510 eph.M0 = R8(raw->buff + 56) * PI;
1511 eph.cuc = R4(raw->buff + 64);
1512 eph.e = R8(raw->buff + 68);
1513 eph.cus = R4(raw->buff + 76);
1514 eph.A = pow(R8(raw->buff + 80), 2);
1515 eph.toes = U4(raw->buff + 88);
1516 eph.cic = R4(raw->buff + 92);
1517 eph.OMG0 = R8(raw->buff + 96) * PI;
1518 eph.cis = R4(raw->buff + 104);
1519 eph.i0 = R8(raw->buff + 108) * PI;
1520 eph.crc = R4(raw->buff + 116);
1521 eph.omg = R8(raw->buff + 120) * PI;
1522 eph.OMGd = R4(raw->buff + 128) * PI;
1523 eph.idot = R4(raw->buff + 132) * PI;
1524 eph.week = adjust_WN10(week, U2(raw->buff + 136));
1525 eph.toe = gpst2time(adjust_WN10(week, U2(raw->buff + 138)), eph.toes);
1526 eph.toc = gpst2time(eph.week, toc);
1527 eph.ttr = raw->time;
1528
1529 if (!strstr(raw->opt, "-EPHALL")) {
1530 if (eph.iode == raw->nav.eph[sat - 1].iode) return 0;
1531 }
1532 eph.sat = sat;
1533 raw->nav.eph[sat - 1] = eph;
1534 raw->ephsat = sat;
1535 raw->ephset = 0;
1536 return 2;
1537}
1538/* decode SBF PVTGeodetic (4007) ---------------------------------------------*/
1539static int decode_pvtgeodetic(raw_t* raw) {
1540 uint8_t* p = raw->buff + 8;
1541 uint8_t mode, error;
1542 double lat, lon, hgt, pos[3];
1543
1544 if (raw->len < 44) return 0;
1545
1546 mode = U1(p + 6);
1547 error = U1(p + 7);
1548
1549 /* bits 0-3: PVT type; 0 = no fix */
1550 if ((mode & 0x0F) == 0 || error != 0) return 0;
1551
1552 lat = R8(p + 8); /* rad */
1553 lon = R8(p + 16); /* rad */
1554 hgt = R8(p + 24); /* m, ellipsoidal */
1555
1556 /* Do-Not-Use check (-2e10) */
1557 if (lat < -2.0e10 || lon < -2.0e10 || hgt < -2.0e10) return 0;
1558
1559 pos[0] = lat;
1560 pos[1] = lon;
1561 pos[2] = hgt;
1562 pos2ecef(pos, raw->sta.pos);
1563
1564 trace(NULL, 3, "SBF PVTGeodetic: lat=%.8f lon=%.8f hgt=%.3f mode=%d\n", lat / D2R, lon / D2R, hgt, mode & 0x0F);
1565
1566 return 5; /* receiver position */
1567}
1568/* decode SBF block ----------------------------------------------------------*/
1569static int decode_sbf(raw_t* raw, rtcm_t* rtcm) {
1570 uint8_t* p = raw->buff;
1571 uint32_t week, tow;
1572 char tstr[32];
1573 int type = U2(p + 4) & 0x1fff;
1574
1575 if (rtk_crc16(p + 4, raw->len - 4) != U2(p + 2)) {
1576 trace(NULL, 2, "sbf crc error: type=%d len=%d\n", type, raw->len);
1577 return -1;
1578 }
1579 if (raw->len < 14) {
1580 trace(NULL, 2, "sbf length error: type=%d len=%d\n", type, raw->len);
1581 return -1;
1582 }
1583 tow = U4(p + 8);
1584 week = U2(p + 12);
1585 if (tow == 4294967295u || week == 65535u) {
1586 trace(NULL, 2, "sbf tow/week error: type=%d len=%d\n", type, raw->len);
1587 return -1;
1588 }
1589 raw->time = gpst2time(week, tow * 0.001);
1590
1591 if (raw->outtype) {
1592 time2str(raw->time, tstr, 2);
1593 sprintf(raw->msgtype, "SBF %4d (%4d): %s", type, raw->len, tstr);
1594 }
1595 switch (type) {
1596 case SBF_MEASEPOCH:
1597 return decode_measepoch(raw);
1598 case SBF_MEASEXTRA:
1599 return decode_measextra(raw);
1600 case SBF_GPSRAWCA:
1601 return decode_gpsrawca(raw);
1602 case SBF_GLORAWCA:
1603 return decode_glorawca(raw);
1604 case SBF_GALRAWFNAV:
1605 return decode_galrawfnav(raw);
1606 case SBF_GALRAWINAV:
1607 return decode_galrawinav(raw);
1608 case SBF_GALRAWCNAV:
1609 return decode_galrawcnav(raw);
1610 case SBF_GEORAWL1:
1611 return decode_georawl1(raw);
1612 case SBF_BDSRAW:
1613 return decode_bdsraw(raw);
1614 case SBF_QZSRAWL1CA:
1615 return decode_qzsrawl1ca(raw);
1616 case SBF_QZSRAWL6: /* generic (mosaic-CLAS): Source field selects L6D/L6E */
1617 case SBF_QZSRAWL6D: /* mosaic-G5 CLAS L6D (Source always 1) */
1618 case SBF_QZSRAWL6E: /* mosaic-G5 MADOCA L6E (Source always 2) */
1619 return decode_qzsrawl6(raw, rtcm);
1620 case SBF_NAVICRAW:
1621 return decode_navicraw(raw);
1622 /* decoded navigation blocks */
1623 case SBF_GPSNAV:
1624 return decode_gpsnav(raw);
1625 case SBF_GLONAV:
1626 return decode_glonav(raw);
1627 case SBF_GALNAV:
1628 return decode_galnav(raw);
1629 case SBF_BDSNAV:
1630 return decode_bdsnav(raw);
1631 case SBF_QZSSNAV:
1632 return decode_qzssnav(raw);
1633 /* receiver position */
1634 case SBF_PVTGEOD:
1635 return decode_pvtgeodetic(raw);
1636 }
1637 trace(NULL, 3, "sbf unsupported message: type=%d\n", type);
1638 return 0;
1639}
1640/* synchronize SBF block header ----------------------------------------------*/
1641static int sync_sbf(uint8_t* buff, uint8_t data) {
1642 buff[0] = buff[1];
1643 buff[1] = data;
1644 return buff[0] == SBF_SYNC1 && buff[1] == SBF_SYNC2;
1645}
1646/* input SBF raw data from stream ----------------------------------------------
1647 * fetch next SBF raw data and input a mesasge from stream
1648 * args : raw_t *raw IO receiver raw data control struct
1649 * rtcm_t *rtcm IO rtcm control struct
1650 * uint_t data I stream data (1 byte)
1651 * return : status (-1: error message, 0: no message, 1: input observation data,
1652 * 2: input ephemeris, 3: input sbas message,
1653 * 9: input ion/utc parameter)
1654 *
1655 * notes : supported SBF block (block ID):
1656 *
1657 * MEASEPOCH(4027), GPSRAWCA(4017), GLORAWCA(4026), GALRAWFNAV(4022),
1658 * GALRAWINAV(4023), GALRAWCNAV(4024), GEORAWL1(4020), BDSRAW(4047),
1659 * QZSRAWL1CA(4066), NAVICRAW(4093)
1660 *
1661 * to specify input options for sbf, set raw->opt to the following
1662 * option strings separated by spaces.
1663 *
1664 * -EPHALL : input all ephemerides
1665 * -AUX1 : select antenna Aux1 (default: main)
1666 * -AUX2 : select antenna Aux2 (default: main)
1667 * -GL1W : select 1W for GPS L1 (default: 1C)
1668 * -GL1L : select 1L for GPS L1 (default: 1C)
1669 * -GL2L : select 2L for GPS L2 (default: 2W)
1670 * -RL1P : select 1P for GLO G1 (default: 1C)
1671 * -RL2C : select 2C for GLO G2 (default: 2P)
1672 * -JL1L : select 1L for QZS L1 (default: 1C)
1673 * -JL1Z : select 1Z for QZS L1 (default: 1C)
1674 * -CL1P : select 1P for BDS B1 (default: 2I)
1675 * -GALINAV: select I/NAV for Galileo ephemeris (default: all)
1676 * -GALFNAV: select F/NAV for Galileo ephemeris (default: all)
1677 *-----------------------------------------------------------------------------*/
1678extern int input_sbf(raw_t* raw, rtcm_t* rtcm, uint8_t data) {
1679 trace(NULL, 5, "input_sbf: data=%02x\n", data);
1680
1681 if (raw->nbyte == 0) {
1682 if (sync_sbf(raw->buff, data)) {
1683 raw->nbyte = 2;
1684 }
1685 return 0;
1686 }
1687 raw->buff[raw->nbyte++] = data;
1688 if (raw->nbyte < 8) {
1689 return 0;
1690 }
1691 raw->len = U2(raw->buff + 6);
1692
1693 if (raw->len <= 8 || raw->len > MAXRAWLEN) {
1694 trace(NULL, 2, "sbf length error: len=%d\n", raw->len);
1695 raw->nbyte = 0;
1696 return -1;
1697 }
1698 if (raw->nbyte < raw->len) {
1699 return 0;
1700 }
1701 raw->nbyte = 0;
1702
1703 /* decode SBF block */
1704 return decode_sbf(raw, rtcm);
1705}
1706/* input SBF raw data from file ------------------------------------------------
1707 * fetch next SBF raw data and input a message from file
1708 * args : raw_t *raw IO receiver raw data control struct
1709 * rtcm_t *rtcm IO rtcm control struct
1710 * FILE *fp I file pointer
1711 * return : status(-2: end of file, -1...9: same as above)
1712 *-----------------------------------------------------------------------------*/
1713extern int input_sbff(raw_t* raw, rtcm_t* rtcm, FILE* fp) {
1714 int i, data;
1715
1716 trace(NULL, 4, "input_sbff:\n");
1717
1718 if (raw->nbyte == 0) {
1719 for (i = 0;; i++) {
1720 if ((data = fgetc(fp)) == EOF) {
1721 return -2;
1722 }
1723 if (sync_sbf(raw->buff, (uint8_t)data)) {
1724 break;
1725 }
1726 if (i >= 4096) {
1727 return 0;
1728 }
1729 }
1730 }
1731 if (fread(raw->buff + 2, 1, 6, fp) < 6) {
1732 return -2;
1733 }
1734 raw->nbyte = 8;
1735 raw->len = U2(raw->buff + 6);
1736
1737 if (raw->len <= 8 || raw->len > MAXRAWLEN) {
1738 trace(NULL, 2, "sbf length error: len=%d\n", raw->len);
1739 raw->nbyte = 0;
1740 return -1;
1741 }
1742 if (fread(raw->buff + 8, raw->len - 8, 1, fp) < 1) {
1743 return -2;
1744 }
1745 raw->nbyte = 0;
1746
1747 /* decode SBF block */
1748 return decode_sbf(raw, rtcm);
1749}
uint32_t rtk_crc24q(const uint8_t *buff, int len)
Compute CRC-24Q parity for SBAS and RTCM3.
Definition mrtk_bits.c:181
uint16_t rtk_crc16(const uint8_t *buff, int len)
Compute CRC-16 parity for BINEX and NVS.
Definition mrtk_bits.c:199
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
int32_t getbits(const uint8_t *buff, int pos, int len)
Extract signed bits from byte data.
Definition mrtk_bits.c:107
MRTKLIB Bits Module — Binary bit operations and CRC functions.
#define D2R
Definition mrtk_coords.c:36
void pos2ecef(const double *pos, double *r)
Transform geodetic position to ECEF position.
#define CLIGHT
Definition mrtk_coords.c:41
#define PI
Definition mrtk_coords.c:35
#define MAXSAT
Definition mrtk_coords.c:45
MRTKLIB Coordinates Module — Coordinate transformations and geometry.
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...
double code2freq(int sys, uint8_t code, int fcn)
Definition mrtk_obs.c:236
#define SNR_UNIT
#define CODE_L5Q
#define CODE_L6C
#define CODE_L5I
#define CODE_L1L
#define MAXOBS
#define MINPRNQZS
#define CODE_L2P
#define CODE_L2I
#define CODE_L1C
#define CODE_L6I
#define CODE_L2C
#define CODE_L7I
#define CODE_NONE
#define CODE_L9A
#define CODE_L8Q
#define CODE_L5P
#define CODE_L3Q
#define CODE_L1E
#define CODE_L7D
#define MAXRAWLEN
#define CODE_L6L
#define CODE_L7Q
#define CODE_L1W
#define CODE_L5Z
#define CODE_L2W
#define CODE_L2L
#define CODE_L1Z
#define CODE_L5A
#define CODE_L1P
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.
int mrtk_sigcfg_freq_idx(int sys, uint8_t code, const mrtk_sigcfg_t *cfg, int nex)
Resolve the observation slot for a decoded (sys, code) from sigcfg.
Definition mrtk_obs.c:1224
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 MRTK_SIGCFG_NOOPINION
mrtk_sigcfg_freq_idx() sentinel: this constellation has no sigcfg entry, so the caller should fall ba...
Definition mrtk_obs.h:291
static rtcm_t * rtcm
#define R8(p)
#define U4(p)
#define I4(p)
#define R4(p)
#define U2(p)
#define I2(p)
#define SBF_QZSRAWL6E
static int decode_galrawinav(raw_t *raw)
static int decode_bdsraw(raw_t *raw)
#define SBF_PVTGEOD
#define SBF_GPSNAV
#define U1(p)
static uint16_t adjust_WN14(uint16_t ref_WN, uint16_t WN)
static int decode_glonav(raw_t *raw)
static int decode_galrawcnav(raw_t *raw)
Decode an SBF GALRawCNAV block (4024) into a staged Galileo HAS page.
static int decode_sbf(raw_t *raw, rtcm_t *rtcm)
static int decode_georawl1(raw_t *raw)
static int sig2idx(int sat, int sig, const raw_t *raw, uint8_t *code)
#define SBF_GLORAWCA
#define SBF_BDSNAV
static uint16_t adjust_WN10(uint16_t ref_WN, uint16_t WN)
static int decode_measepoch(raw_t *raw)
#define SBF_MAXSIG
#define SBF_BDSRAW
static int decode_qzsrawl1ca(raw_t *raw)
static int decode_glorawca(raw_t *raw)
static void adj_utcweek(gtime_t time, double *utc)
static int svid2sat(int svid)
static uint8_t sig_tbl[40+1][2]
#define SBF_QZSRAWL6
#define SBF_GALRAWFNAV
#define SBF_QZSRAWL1CA
static int decode_navicraw(raw_t *raw)
#define SBF_GALNAV
int input_sbff(raw_t *raw, rtcm_t *rtcm, FILE *fp)
int input_sbf(raw_t *raw, rtcm_t *rtcm, uint8_t data)
static int decode_galnav(raw_t *raw)
#define SBF_GALRAWINAV
#define SBF_GLONAV
#define SBF_GEORAWL1
#define SBF_NAVICRAW
#define SBF_QZSSNAV
static int decode_measextra(raw_t *raw)
#define SBF_MEASEXTRA
#define SBF_QZSRAWL6D
#define SBF_GALRAWCNAV
static int decode_qzssnav(raw_t *raw)
static uint16_t adjust_WN12(uint16_t ref_WN, uint16_t WN)
static int decode_rawca(raw_t *raw, int sys)
static int decode_ionutc(raw_t *raw, int sat)
static int sync_sbf(uint8_t *buff, uint8_t data)
static int decode_galrawfnav(raw_t *raw)
#define SBF_MEASEPOCH
#define SBF_SYNC2
static void init_obsd(gtime_t time, int sat, obsd_t *data)
static int decode_qzsrawl6(raw_t *raw, rtcm_t *rtcm)
static int decode_gpsnav(raw_t *raw)
static int decode_bdsnav(raw_t *raw)
#define I1(p)
static int decode_gpsrawca(raw_t *raw)
static int decode_eph(raw_t *raw, int sat)
#define SBF_GPSRAWCA
static int decode_pvtgeodetic(raw_t *raw)
#define SBF_SYNC1
int decode_qzss_l6frame(rtcm_t *rtcm, int is_l6d)
Route one QZSS L6 frame received in a UBX/SBF container.
int decode_gal_fnav(const uint8_t *buff, eph_t *eph, double *ion, double *utc)
int decode_frame(const uint8_t *buff, eph_t *eph, alm_t *alm, double *ion, double *utc)
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)
int decode_irn_nav(const uint8_t *buff, eph_t *eph, double *ion, double *utc)
MRTKLIB Receiver Raw Data Module — Receiver raw data types and decoder functions for various GNSS rec...
MRTKLIB RTCM Module — RTCM message types and functions.
MRTKLIB System Module — OS/filesystem utility functions.
gtime_t 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
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 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
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 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
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 ion_irn[8]
Definition mrtk_nav.h:425
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
double utc_irn[9]
Definition mrtk_nav.h:419
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
Observation data record.
Definition mrtk_obs.h:44
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
mrtk_sigcfg_t sigcfg[MRTK_NSYS]
int ephset
Definition mrtk_rcvraw.h:86
int has_prn
int outtype
int sigcfg_set
obs_t obs
Definition mrtk_rcvraw.h:81
int len
Definition mrtk_rcvraw.h:96
gtime_t has_time
uint8_t has_page[56]
uint8_t buff[MAXRAWLEN]
char msgtype[256]
Definition mrtk_rcvraw.h:88
int nbyte
Definition mrtk_rcvraw.h:95
double l6tag
char opt[256]
sta_t sta
Definition mrtk_rcvraw.h:84
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
double pos[3]
Definition mrtk_nav.h:380