MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_rcv_skytraq.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_rcv_skytraq.c : SkyTraq receiver raw data decoder
3 *
4 * Copyright (C) 2026 H.SHIONO (MRTKLIB Project)
5 * Copyright (C) 2023-2025 Cabinet Office, Japan
6 * Copyright (C) 2024-2025 Lighthouse Technology & Consulting Co. Ltd.
7 * Copyright (C) 2023-2025 Japan Aerospace Exploration Agency
8 * Copyright (C) 2023-2025 TOSHIBA ELECTRONIC TECHNOLOGIES CORPORATION
9 * Copyright (C) 2015- Mitsubishi Electric Corp.
10 * Copyright (C) 2014 Geospatial Information Authority of Japan
11 * Copyright (C) 2014 T.SUZUKI
12 * Copyright (C) 2007-2023 T.TAKASU
13 *
14 * SPDX-License-Identifier: BSD-2-Clause
15 *----------------------------------------------------------------------------*/
16#include <ctype.h>
17#include <math.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include "mrtklib/mrtk_bits.h"
23#include "mrtklib/mrtk_eph.h"
24#include "mrtklib/mrtk_mat.h"
25#include "mrtklib/mrtk_nav.h"
26#include "mrtklib/mrtk_obs.h"
27#include "mrtklib/mrtk_rcvraw.h"
28#include "mrtklib/mrtk_rtcm.h"
29#include "mrtklib/mrtk_sys.h"
30#include "mrtklib/mrtk_time.h"
31#include "mrtklib/mrtk_trace.h"
32
33/* Local constants (duplicated from rtklib.h to avoid dependency) */
34#define PI 3.1415926535897932 /* pi */
35#define D2R (PI / 180.0) /* deg to rad */
36#define R2D (180.0 / PI) /* rad to deg */
37#define CLIGHT 299792458.0 /* speed of light (m/s) */
38#define SC2RAD 3.1415926535898 /* semi-circle to radian (IS-GPS) */
39
40#define SYS_NONE 0x00
41#define SYS_GPS 0x01
42#define SYS_SBS 0x02
43#define SYS_GLO 0x04
44#define SYS_GAL 0x08
45#define SYS_QZS 0x10
46#define SYS_CMP 0x20
47#define SYS_IRN 0x40
48
49#define TSYS_GPS 0
50#define TSYS_UTC 1
51#define TSYS_GLO 2
52#define TSYS_GAL 3
53#define TSYS_QZS 4
54#define TSYS_CMP 5
55#define TSYS_IRN 6
56
57#define FREQ1 1.57542E9 /* L1/E1/B1C frequency (Hz) */
58#define FREQ2 1.22760E9 /* L2 frequency (Hz) */
59#define FREQ5 1.17645E9 /* L5/E5a/B2a frequency (Hz) */
60#define FREQ6 1.27875E9 /* E6/L6 frequency (Hz) */
61#define FREQ7 1.20714E9 /* E5b/B2I frequency (Hz) */
62#define FREQ8 1.191795E9 /* E5ab/B2ab frequency (Hz) */
63#define FREQ9 2.492028E9 /* S frequency (Hz) */
64#define FREQ1_GLO 1.60200E9 /* GLONASS G1 base frequency (Hz) */
65#define DFRQ1_GLO 0.56250E6 /* GLONASS G1 bias frequency (Hz/n) */
66#define FREQ2_GLO 1.24600E9 /* GLONASS G2 base frequency (Hz) */
67#define DFRQ2_GLO 0.43750E6 /* GLONASS G2 bias frequency (Hz/n) */
68#define FREQ3_GLO 1.202025E9 /* GLONASS G3 frequency (Hz) */
69#define FREQ1a_GLO 1.600995E9 /* GLONASS G1a frequency (Hz) */
70#define FREQ2a_GLO 1.248060E9 /* GLONASS G2a frequency (Hz) */
71#define FREQ1_CMP 1.561098E9 /* BDS B1I frequency (Hz) */
72
73#define MINPRNGPS 1
74#define MAXPRNGPS 32
75#define MINPRNSBS 120
76#define MAXPRNSBS 158
77
78/* Power-of-2 constants */
79#define P2_5 0.03125
80#define P2_6 0.015625
81#define P2_11 4.882812500000000E-04
82#define P2_15 3.051757812500000E-05
83#define P2_17 7.629394531250000E-06
84#define P2_19 1.907348632812500E-06
85#define P2_20 9.536743164062500E-07
86#define P2_21 4.768371582031250E-07
87#define P2_23 1.192092895507810E-07
88#define P2_24 5.960464477539063E-08
89#define P2_27 7.450580596923828E-09
90#define P2_29 1.862645149230957E-09
91#define P2_30 9.313225746154785E-10
92#define P2_31 4.656612873077393E-10
93#define P2_32 2.328306436538696E-10
94#define P2_33 1.164153218269348E-10
95#define P2_34 5.820766091346740E-11
96#define P2_35 2.910383045673370E-11
97#define P2_38 3.637978807091710E-12
98#define P2_40 9.094947017729280E-13
99#define P2_43 1.136868377216160E-13
100#define P2_46 1.421085471520200E-14
101#define P2_50 8.881784197001252E-16
102#define P2_55 2.775557561562891E-17
103#define P2_59 1.734723475976810E-18
104
105/* Forward declarations for functions in rtklib (resolved at link time) */
106
107#define STQSYNC1 0xA0 /* skytraq binary sync code 1 */
108#define STQSYNC2 0xA1 /* skytraq binary sync code 2 */
109
110#define ID_STQTIME 0xDC /* skytraq message id: measurement epoch */
111#define ID_STQRAW 0xDD /* skytraq message id: raw measurement */
112#define ID_STQSVCH 0xDE /* skytraq message id: SV and channel status */
113#define ID_STQSTAT 0xDF /* skytraq message id: navigation status */
114#define ID_STQGPS 0xE0 /* skytraq message id: gps/qzs subframe */
115#define ID_STQGLO 0xE1 /* skytraq message id: glonass string */
116#define ID_STQBDSD1 0xE2 /* skytraq message id: beidou d1 subframe */
117#define ID_STQBDSD2 0xE3 /* skytraq message id: beidou d2 subframe */
118#define ID_STQRAWX 0xE5 /* skytraq message id: extended raw meas v.1 */
119#define ID_STQGLOE 0x5C /* skytraq message id: glonass ephemeris */
120#define ID_STQACK 0x83 /* skytraq message id: ack to request msg */
121#define ID_STQNACK 0x84 /* skytraq message id: nack to request msg */
122
123#define ID_RESTART 0x01 /* skytraq message id: system restart */
124#define ID_CFGSERI 0x05 /* skytraq message id: configure serial port */
125#define ID_CFGFMT 0x09 /* skytraq message id: configure message format */
126#define ID_CFGRATE 0x12 /* skytraq message id: configure message rate */
127#define ID_CFGBIN 0x1E /* skytraq message id: configure binary message */
128#define ID_GETGLOEPH 0x5B /* skytraq message id: get glonass ephemeris */
129
130/* extract field (big-endian) ------------------------------------------------*/
131#define U1(p) (*((uint8_t*)(p)))
132#define I1(p) (*((int8_t*)(p)))
133
134static uint16_t U2(uint8_t* p) {
135 uint16_t value;
136 uint8_t* q = (uint8_t*)&value + 1;
137 int i;
138 for (i = 0; i < 2; i++) {
139 *q-- = *p++;
140 }
141 return value;
142}
143static uint32_t U4(uint8_t* p) {
144 uint32_t value;
145 uint8_t* q = (uint8_t*)&value + 3;
146 int i;
147 for (i = 0; i < 4; i++) {
148 *q-- = *p++;
149 }
150 return value;
151}
152static float R4(uint8_t* p) {
153 float value;
154 uint8_t* q = (uint8_t*)&value + 3;
155 int i;
156 for (i = 0; i < 4; i++) {
157 *q-- = *p++;
158 }
159 return value;
160}
161static double R8(uint8_t* p) {
162 double value;
163 uint8_t* q = (uint8_t*)&value + 7;
164 int i;
165 for (i = 0; i < 8; i++) {
166 *q-- = *p++;
167 }
168 return value;
169}
170/* checksum ------------------------------------------------------------------*/
171static uint8_t checksum(uint8_t* buff, int len) {
172 uint8_t cs = 0;
173 int i;
174
175 for (i = 4; i < len - 3; i++) {
176 cs ^= buff[i];
177 }
178 return cs;
179}
180/* 8-bit week -> full week ---------------------------------------------------*/
181static void adj_utcweek(gtime_t time, double* utc) {
182 int week;
183
184 if (utc[3] >= 256.0) {
185 return;
186 }
187 time2gpst(time, &week);
188 utc[3] += week / 256 * 256;
189 if (utc[3] < week - 128) {
190 utc[3] += 256.0;
191 } else if (utc[3] > week + 128) {
192 utc[3] -= 256.0;
193 }
194}
195/* decode skytraq measurement epoch (0xDC) -----------------------------------*/
196static int decode_stqtime(raw_t* raw) {
197 uint8_t* p = raw->buff + 4;
198 double tow;
199 int week;
200
201 trace(NULL, 4, "decode_stqtime: len=%d\n", raw->len);
202
203 raw->iod = U1(p + 1);
204 week = U2(p + 2);
205 week = adjgpsweek(week);
206 tow = U4(p + 4) * 0.001;
207 raw->time = gpst2time(week, tow);
208
209 if (raw->outtype) {
210 sprintf(raw->msgtype, "SKYTRAQ EPOCH (%4d): iod=%d week=%d tow=%.3f", raw->len, raw->iod, week, tow);
211 }
212 return 0;
213}
214/* decode skytraq raw measurement (0xDD) -------------------------------------*/
215static int decode_stqraw(raw_t* raw) {
216 uint8_t *p = raw->buff + 4, ind;
217 double pr1, cp1;
218 int i, j, iod, prn, sys, sat, n = 0, nsat;
219
220 trace(NULL, 4, "decode_stqraw: len=%d\n", raw->len);
221
222 if (raw->outtype) {
223 sprintf(raw->msgtype, "SKYTRAQ RAW (%4d): nsat=%d", raw->len, U1(p + 2));
224 }
225 iod = U1(p + 1);
226 if (iod != raw->iod) { /* need preceding measurement epoch (0xDC) */
227 trace(NULL, 2, "stq raw iod error: iod=%d %d\n", iod, raw->iod);
228 return -1;
229 }
230 nsat = U1(p + 2);
231 if (raw->len < 8 + 23 * nsat) {
232 trace(NULL, 2, "stq raw length error: len=%d nsat=%d\n", raw->len, nsat);
233 return -1;
234 }
235 for (i = 0, p += 3; i < nsat && i < MAXOBS; i++, p += 23) {
236 prn = U1(p);
237
238 if (MINPRNGPS <= prn && prn <= MAXPRNGPS) {
239 sys = SYS_GPS;
240 } else if (MINPRNGLO <= prn - 64 && prn - 64 <= MAXPRNGLO) {
241 sys = SYS_GLO;
242 prn -= 64;
243 } else if (MINPRNQZS <= prn && prn <= MAXPRNQZS) {
244 sys = SYS_QZS;
245 } else if (MINPRNCMP <= prn - 200 && prn - 200 <= MAXPRNCMP) {
246 sys = SYS_CMP;
247 prn -= 200;
248 } else {
249 trace(NULL, 2, "stq raw satellite number error: prn=%d\n", prn);
250 continue;
251 }
252 if (!(sat = satno(sys, prn))) {
253 trace(NULL, 2, "stq raw satellite number error: sys=%d prn=%d\n", sys, prn);
254 continue;
255 }
256 ind = U1(p + 22);
257 pr1 = !(ind & 1) ? 0.0 : R8(p + 2);
258 cp1 = !(ind & 4) ? 0.0 : R8(p + 10);
259 cp1 -= floor((cp1 + 1E9) / 2E9) * 2E9; /* -10^9 < cp1 < 10^9 */
260
261 raw->obs.data[n].P[0] = pr1;
262 raw->obs.data[n].L[0] = cp1;
263 raw->obs.data[n].D[0] = !(ind & 2) ? 0.0 : R4(p + 18);
264 raw->obs.data[n].SNR[0] = (uint16_t)(U1(p + 1) / SNR_UNIT + 0.5);
265 raw->obs.data[n].LLI[0] = 0;
266 raw->obs.data[n].code[0] = sys == SYS_CMP ? CODE_L2I : CODE_L1C;
267
268 raw->lockt[sat - 1][0] = ind & 8 ? 1 : 0; /* cycle slip */
269
270 if (raw->obs.data[n].L[0] != 0.0) {
271 raw->obs.data[n].LLI[0] = (uint8_t)raw->lockt[sat - 1][0];
272 raw->lockt[sat - 1][0] = 0;
273 }
274 /* receiver dependent options */
275 if (strstr(raw->opt, "-INVCP")) {
276 raw->obs.data[n].L[0] *= -1.0;
277 }
278 raw->obs.data[n].time = raw->time;
279 raw->obs.data[n].sat = sat;
280
281 for (j = 1; j < NFREQ + NEXOBS; j++) {
282 raw->obs.data[n].L[j] = raw->obs.data[n].P[j] = 0.0;
283 raw->obs.data[n].D[j] = 0.0;
284 raw->obs.data[n].SNR[j] = raw->obs.data[n].LLI[j] = 0;
285 raw->obs.data[n].code[j] = CODE_NONE;
286 }
287 n++;
288 }
289 raw->obs.n = n;
290 return n > 0 ? 1 : 0;
291}
292/* decode skytraq extended raw measurement data v.1 (0xE5) -------------------*/
293static int decode_stqrawx(raw_t* raw) {
294 uint8_t *p = raw->buff + 4, ind;
295 double tow, peri, pr1, cp1;
296 int i, j, ver, week, nsat, sys, sig, prn, sat, n = 0;
297 int gnss_type, signal_type;
298
299 trace(NULL, 4, "decode_stqraw: len=%d\n", raw->len);
300
301 if (raw->outtype) {
302 sprintf(raw->msgtype, "SKYTRAQ RAWX (%4d): nsat=%2d", raw->len, U1(p + 13));
303 }
304 ver = U1(p + 1);
305 raw->iod = U1(p + 2);
306 week = U2(p + 3);
307 week = adjgpsweek(week);
308 tow = U4(p + 5) * 0.001;
309 raw->time = gpst2time(week, tow);
310 peri = U2(p + 9) * 0.001;
311 nsat = U1(p + 13);
312 if (raw->len < 19 + 31 * nsat) {
313 trace(NULL, 2, "stq raw length error: len=%d nsat=%d\n", raw->len, nsat);
314 return -1;
315 }
316 for (i = 0, p += 14; i < nsat && i < MAXOBS; i++, p += 31) {
317 gnss_type = U1(p) & 0xF;
318 signal_type = (U1(p) >> 4) & 0xF;
319 if (gnss_type == 0) { /* GPS */
320 sys = SYS_GPS;
321 switch (signal_type) {
322 case 1:
323 sig = CODE_L1X;
324 break;
325 case 2:
326 sig = CODE_L2X;
327 break;
328 case 4:
329 sig = CODE_L5X;
330 break;
331 default:
332 sig = CODE_L1C;
333 break;
334 }
335 prn = U1(p + 1);
336 } else if (gnss_type == 1) { /* SBAS */
337 sys = SYS_SBS;
338 sig = CODE_L1C;
339 prn = U1(p + 1);
340 } else if (gnss_type == 2) { /* GLONASS */
341 sys = SYS_GLO;
342 switch (signal_type) {
343 case 2:
344 sig = CODE_L2C;
345 break;
346 case 4:
347 sig = CODE_L3X;
348 break;
349 default:
350 sig = CODE_L1C;
351 break;
352 }
353 prn = U1(p + 1);
354 } else if (gnss_type == 3) { /* Galileo */
355 sys = SYS_GAL;
356 switch (signal_type) {
357 case 4:
358 sig = CODE_L5X;
359 break;
360 case 5:
361 sig = CODE_L7X;
362 break;
363 case 6:
364 sig = CODE_L6X;
365 break;
366 default:
367 sig = CODE_L1C;
368 break;
369 }
370 prn = U1(p + 1);
371 } else if (gnss_type == 4) { /* QZSS */
372 sys = SYS_QZS;
373 switch (signal_type) {
374 case 1:
375 sig = CODE_L1X;
376 break;
377 case 2:
378 sig = CODE_L2X;
379 break;
380 case 4:
381 sig = CODE_L5X;
382 break;
383 case 6:
384 sig = CODE_L6X;
385 break;
386 default:
387 sig = CODE_L1C;
388 break;
389 }
390 prn = U1(p + 1);
391 } else if (gnss_type == 5) { /* BeiDou */
392 sys = SYS_CMP;
393 switch (signal_type) {
394 case 4:
395 sig = CODE_L7I;
396 break;
397 case 6:
398 sig = CODE_L6I;
399 break;
400 default:
401 sig = CODE_L2I;
402 break;
403 }
404 prn = U1(p + 1);
405 } else {
406 trace(NULL, 2, "stq rawx gnss type error: type=%d\n", U1(p));
407 continue;
408 }
409 if (!(sat = satno(sys, prn))) {
410 trace(NULL, 2, "stq raw satellite number error: sys=%d prn=%d\n", sys, prn);
411 continue;
412 }
413 /* set glonass freq channel number */
414 if (gnss_type == 2) {
415 raw->nav.geph[prn - 1].frq = (int)(U1(p + 2) & 0xF) - 7;
416 }
417 ind = U2(p + 27);
418 pr1 = !(ind & 1) ? 0.0 : R8(p + 4);
419 cp1 = !(ind & 4) ? 0.0 : R8(p + 12);
420 cp1 -= floor((cp1 + 1E9) / 2E9) * 2E9; /* -10^9 < cp1 < 10^9 */
421
422 raw->obs.data[n].P[0] = pr1;
423 raw->obs.data[n].L[0] = cp1;
424 raw->obs.data[n].D[0] = !(ind & 2) ? 0.0 : R4(p + 20);
425 raw->obs.data[n].SNR[0] = (uint16_t)(U1(p + 3) / SNR_UNIT + 0.5);
426 raw->obs.data[n].LLI[0] = 0;
427 raw->obs.data[n].code[0] = sys == SYS_CMP ? CODE_L2I : CODE_L1C;
428
429 raw->lockt[sat - 1][0] = ind & 8 ? 1 : 0; /* cycle slip */
430
431 if (raw->obs.data[n].L[0] != 0.0) {
432 raw->obs.data[n].LLI[0] = (uint8_t)raw->lockt[sat - 1][0];
433 raw->lockt[sat - 1][0] = 0;
434 }
435 /* receiver dependent options */
436 if (strstr(raw->opt, "-INVCP")) {
437 raw->obs.data[n].L[0] *= -1.0;
438 }
439 raw->obs.data[n].time = raw->time;
440 raw->obs.data[n].sat = sat;
441
442 for (j = 1; j < NFREQ + NEXOBS; j++) {
443 raw->obs.data[n].L[j] = raw->obs.data[n].P[j] = 0.0;
444 raw->obs.data[n].D[j] = 0.0;
445 raw->obs.data[n].SNR[j] = raw->obs.data[n].LLI[j] = 0;
446 raw->obs.data[n].code[j] = CODE_NONE;
447 }
448 n++;
449 }
450 raw->obs.n = n;
451 return n > 0 ? 1 : 0;
452}
453/* save subframe -------------------------------------------------------------*/
454static int save_subfrm(int sat, raw_t* raw) {
455 uint8_t *p = raw->buff + 7, *q;
456 int i, id;
457
458 trace(NULL, 4, "save_subfrm: sat=%2d\n", sat);
459
460 /* check navigation subframe preamble */
461 if (p[0] != 0x8B) {
462 trace(NULL, 2, "stq subframe preamble error: 0x%02X\n", p[0]);
463 return 0;
464 }
465 id = (p[5] >> 2) & 0x7;
466
467 /* check subframe id */
468 if (id < 1 || 5 < id) {
469 trace(NULL, 2, "stq subframe id error: id=%d\n", id);
470 return 0;
471 }
472 q = raw->subfrm[sat - 1] + (id - 1) * 30;
473
474 for (i = 0; i < 30; i++) {
475 q[i] = p[i];
476 }
477
478 return id;
479}
480/* decode ephemeris ----------------------------------------------------------*/
481static int decode_ephem(int sat, raw_t* raw) {
482 eph_t eph = {0};
483
484 trace(NULL, 4, "decode_ephem: sat=%2d\n", sat);
485
486 if (!decode_frame(raw->subfrm[sat - 1], &eph, NULL, NULL, NULL)) {
487 return 0;
488 }
489
490 if (!strstr(raw->opt, "-EPHALL")) {
491 if (eph.iode == raw->nav.eph[sat - 1].iode && eph.iodc == raw->nav.eph[sat - 1].iodc) {
492 return 0; /* unchanged */
493 }
494 }
495 eph.sat = sat;
496 raw->nav.eph[sat - 1] = eph;
497 raw->ephsat = sat;
498 raw->ephset = 0;
499 return 2;
500}
501/* decode almanac and ion/utc ------------------------------------------------*/
502static int decode_alm1(int sat, raw_t* raw) {
503 int sys = satsys(sat, NULL);
504
505 trace(NULL, 4, "decode_alm1 : sat=%2d\n", sat);
506
507 if (sys == SYS_GPS) {
508 decode_frame(raw->subfrm[sat - 1], NULL, raw->nav.alm, raw->nav.ion_gps, raw->nav.utc_gps);
509 adj_utcweek(raw->time, raw->nav.utc_gps);
510 } else if (sys == SYS_QZS) {
511 decode_frame(raw->subfrm[sat - 1], NULL, raw->nav.alm, raw->nav.ion_qzs, raw->nav.utc_qzs);
512 adj_utcweek(raw->time, raw->nav.utc_qzs);
513 }
514 return 9;
515}
516/* decode almanac ------------------------------------------------------------*/
517static int decode_alm2(int sat, raw_t* raw) {
518 int sys = satsys(sat, NULL);
519
520 trace(NULL, 4, "decode_alm2 : sat=%2d\n", sat);
521
522 if (sys == SYS_GPS) {
523 decode_frame(raw->subfrm[sat - 1], NULL, raw->nav.alm, NULL, NULL);
524 } else if (sys == SYS_QZS) {
525 decode_frame(raw->subfrm[sat - 1], NULL, raw->nav.alm, raw->nav.ion_qzs, raw->nav.utc_qzs);
526 adj_utcweek(raw->time, raw->nav.utc_qzs);
527 }
528 return 0;
529}
530/* decode gps/qzss subframe (0xE0) -------------------------------------------*/
531static int decode_stqgps(raw_t* raw) {
532 int prn, sat, id;
533 uint8_t* p = raw->buff + 4;
534
535 trace(NULL, 4, "decode_stqgps: len=%d\n", raw->len);
536
537 if (raw->len < 40) {
538 trace(NULL, 2, "stq gps/qzss subframe length error: len=%d\n", raw->len);
539 return -1;
540 }
541 if (raw->outtype) {
542 sprintf(raw->msgtype, "SKYTRAQ GPSSF (%4d): prn=%2d id=%d", raw->len, U1(p + 1), (p[8] >> 2) & 0x7);
543 }
544 prn = U1(p + 1);
545 if (!(sat = satno(MINPRNQZS <= prn && prn <= MAXPRNQZS ? SYS_QZS : SYS_GPS, prn))) {
546 trace(NULL, 2, "stq gps/qzss subframe satellite number error: prn=%d\n", prn);
547 return -1;
548 }
549 id = save_subfrm(sat, raw);
550 if (id == 3) {
551 return decode_ephem(sat, raw);
552 }
553 if (id == 4) {
554 return decode_alm1(sat, raw);
555 }
556 if (id == 5) {
557 return decode_alm2(sat, raw);
558 }
559 return 0;
560}
561/* decode glonass string (0xE1) ----------------------------------------------*/
562static int decode_stqglo(raw_t* raw) {
563 geph_t geph = {0};
564 int i, prn, sat, m;
565 uint8_t* p = raw->buff + 4;
566
567 trace(NULL, 4, "decode_stqglo: len=%d\n", raw->len);
568
569 if (raw->len < 19) {
570 trace(NULL, 2, "stq glo string length error: len=%d\n", raw->len);
571 return -1;
572 }
573 if (raw->outtype) {
574 sprintf(raw->msgtype, "SKYTRAQ GLSTR (%4d): prn=%2d no=%d", raw->len, U1(p + 1) - 64, U1(p + 2));
575 }
576 prn = U1(p + 1) - 64;
577 if (!(sat = satno(SYS_GLO, prn))) {
578 trace(NULL, 2, "stq glo string satellite number error: prn=%d\n", prn);
579 return -1;
580 }
581 m = U1(p + 2); /* string number */
582 if (m < 1 || 4 < m) {
583 return 0; /* non-immediate info and almanac */
584 }
585 setbitu(raw->subfrm[sat - 1] + (m - 1) * 10, 1, 4, m);
586 for (i = 0; i < 9; i++) {
587 setbitu(raw->subfrm[sat - 1] + (m - 1) * 10, 5 + i * 8, 8, p[3 + i]);
588 }
589 if (m != 4) {
590 return 0;
591 }
592
593 /* decode glonass ephemeris strings */
594 geph.tof = raw->time;
595 if (!decode_glostr(raw->subfrm[sat - 1], &geph, NULL) || geph.sat != sat) {
596 return 0;
597 }
598
599 if (!strstr(raw->opt, "-EPHALL")) {
600 if (geph.iode == raw->nav.geph[prn - 1].iode) {
601 return 0; /* unchanged */
602 }
603 }
604 /* keep freq channel number */
605 geph.frq = raw->nav.geph[prn - 1].frq;
606 raw->nav.geph[prn - 1] = geph;
607 raw->ephsat = sat;
608 raw->ephset = 0;
609 return 2;
610}
611/* decode glonass string (requested) (0x5C) ----------------------------------*/
612static int decode_stqgloe(raw_t* raw) {
613 int prn, sat;
614 uint8_t* p = raw->buff + 4;
615
616 trace(NULL, 4, "decode_stqgloe: len=%d\n", raw->len);
617
618 if (raw->len < 50) {
619 trace(NULL, 2, "stq glo string length error: len=%d\n", raw->len);
620 return -1;
621 }
622 prn = U1(p + 1);
623 if (!(sat = satno(SYS_GLO, prn))) {
624 trace(NULL, 2, "stq gloe string satellite number error: prn=%d\n", prn);
625 return -1;
626 }
627 /* set frequency channel number */
628 raw->nav.geph[prn - 1].frq = I1(p + 2);
629
630 return 0;
631}
632/* decode beidou subframe (0xE2,0xE3) ----------------------------------------*/
633static int decode_stqbds(raw_t* raw) {
634 eph_t eph = {0};
635 uint32_t word;
636 int i, j = 0, id, pgn, prn, sat;
637 uint8_t* p = raw->buff + 4;
638
639 trace(NULL, 4, "decode_stqbds: len=%d\n", raw->len);
640
641 if (raw->len < 38) {
642 trace(NULL, 2, "stq bds subframe length error: len=%d\n", raw->len);
643 return -1;
644 }
645 if (raw->outtype) {
646 sprintf(raw->msgtype, "SKYTRAQ BDSSF (%4d): prn=%2d id=%d", raw->len, U1(p + 1) - 200, U1(p + 2));
647 }
648 prn = U1(p + 1) - 200;
649 if (!(sat = satno(SYS_CMP, prn))) {
650 trace(NULL, 2, "stq bds subframe satellite number error: prn=%d\n", prn);
651 return -1;
652 }
653 id = U1(p + 2); /* subframe id */
654 if (id < 1 || 5 < id) {
655 trace(NULL, 2, "stq bds subframe id error: prn=%2d\n", prn);
656 return -1;
657 }
658 if (prn > 5) { /* IGSO/MEO */
659 word = getbitu(p + 3, j, 26) << 4;
660 j += 26;
661 setbitu(raw->subfrm[sat - 1] + (id - 1) * 38, 0, 30, word);
662
663 for (i = 1; i < 10; i++) {
664 word = getbitu(p + 3, j, 22) << 8;
665 j += 22;
666 setbitu(raw->subfrm[sat - 1] + (id - 1) * 38, i * 30, 30, word);
667 }
668 if (id != 3) {
669 return 0;
670 }
671 if (!decode_bds_d1(raw->subfrm[sat - 1], &eph, NULL, NULL)) {
672 return 0;
673 }
674 } else { /* GEO */
675 if (id != 1) {
676 return 0;
677 }
678
679 pgn = getbitu(p + 3, 26 + 12, 4); /* page number */
680 if (pgn < 1 || 10 < pgn) {
681 trace(NULL, 2, "stq bds subframe page number error: prn=%2d pgn=%d\n", prn, pgn);
682 return -1;
683 }
684 word = getbitu(p + 3, j, 26) << 4;
685 j += 26;
686 setbitu(raw->subfrm[sat - 1] + (pgn - 1) * 38, 0, 30, word);
687
688 for (i = 1; i < 10; i++) {
689 word = getbitu(p + 3, j, 22) << 8;
690 j += 22;
691 setbitu(raw->subfrm[sat - 1] + (pgn - 1) * 38, i * 30, 30, word);
692 }
693 if (pgn != 10) {
694 return 0;
695 }
696 if (!decode_bds_d2(raw->subfrm[sat - 1], &eph, NULL)) {
697 return 0;
698 }
699 }
700 if (!strstr(raw->opt, "-EPHALL")) {
701 if (timediff(eph.toe, raw->nav.eph[sat - 1].toe) == 0.0) {
702 return 0; /* unchanged */
703 }
704 }
705 eph.sat = sat;
706 raw->nav.eph[sat - 1] = eph;
707 raw->ephsat = sat;
708 raw->ephset = 0;
709 return 2;
710}
711/* decode ack to request msg (0x83) ------------------------------------------*/
712static int decode_stqack(raw_t* raw) {
713 uint8_t* p = raw->buff + 4;
714
715 trace(NULL, 4, "decode_stqack: len=%d\n", raw->len);
716
717 if (raw->len < 9) {
718 trace(NULL, 2, "stq ack length error: len=%d\n", raw->len);
719 return -1;
720 }
721 if (raw->outtype) {
722 sprintf(raw->msgtype, "SKYTRAQ ACK (%4d): msg=0x%02X", raw->len, U1(p + 1));
723 }
724 return 0;
725}
726/* decode nack to request msg (0x84) -----------------------------------------*/
727static int decode_stqnack(raw_t* raw) {
728 uint8_t* p = raw->buff + 4;
729
730 trace(NULL, 4, "decode_stqnack: len=%d\n", raw->len);
731
732 if (raw->len < 9) {
733 trace(NULL, 2, "stq nack length error: len=%d\n", raw->len);
734 return -1;
735 }
736 if (raw->outtype) {
737 sprintf(raw->msgtype, "SKYTRAQ NACK (%4d): msg=0x%02X", raw->len, U1(p + 1));
738 }
739 return 0;
740}
741/* decode skytraq message ----------------------------------------------------*/
742static int decode_stq(raw_t* raw) {
743 int type = U1(raw->buff + 4);
744 uint8_t cs, *p = raw->buff + raw->len - 3;
745
746 trace(NULL, 3, "decode_stq: type=%02x len=%d\n", type, raw->len);
747
748 /* checksum */
749 cs = checksum(raw->buff, raw->len);
750
751 if (cs != *p || *(p + 1) != 0x0D || *(p + 2) != 0x0A) {
752 trace(NULL, 2, "stq checksum error: type=%02X cs=%02X tail=%02X%02X%02X\n", type, cs, *p, *(p + 1), *(p + 2));
753 return -1;
754 }
755 if (raw->outtype) {
756 sprintf(raw->msgtype, "SKYTRAQ 0x%02X (%4d):", type, raw->len);
757 }
758 switch (type) {
759 case ID_STQTIME:
760 return decode_stqtime(raw);
761 case ID_STQRAW:
762 return decode_stqraw(raw);
763 case ID_STQRAWX:
764 return decode_stqrawx(raw);
765 case ID_STQGPS:
766 return decode_stqgps(raw);
767 case ID_STQGLO:
768 return decode_stqglo(raw);
769 case ID_STQGLOE:
770 return decode_stqgloe(raw);
771 case ID_STQBDSD1:
772 return decode_stqbds(raw);
773 case ID_STQBDSD2:
774 return decode_stqbds(raw);
775 case ID_STQACK:
776 return decode_stqack(raw);
777 case ID_STQNACK:
778 return decode_stqnack(raw);
779 }
780 return 0;
781}
782/* sync code -----------------------------------------------------------------*/
783static int sync_stq(uint8_t* buff, uint8_t data) {
784 buff[0] = buff[1];
785 buff[1] = data;
786 return buff[0] == STQSYNC1 && buff[1] == STQSYNC2;
787}
788/* input skytraq raw message from stream ---------------------------------------
789 * fetch next skytraq raw data and input a mesasge from stream
790 * args : raw_t *raw IO receiver raw data control struct
791 * uint8_t data I stream data (1 byte)
792 * return : status (-1: error message, 0: no message, 1: input observation data,
793 * 2: input ephemeris, 3: input sbas message,
794 * 9: input ion/utc parameter)
795 *
796 * notes : to specify input options, set raw->opt to the following option
797 * strings separated by spaces.
798 *
799 * -INVCP : inverse polarity of carrier-phase
800 *
801 *-----------------------------------------------------------------------------*/
802extern int input_stq(raw_t* raw, uint8_t data) {
803 trace(NULL, 5, "input_stq: data=%02x\n", data);
804
805 /* synchronize frame */
806 if (raw->nbyte == 0) {
807 if (!sync_stq(raw->buff, data)) {
808 return 0;
809 }
810 raw->nbyte = 2;
811 return 0;
812 }
813 raw->buff[raw->nbyte++] = data;
814
815 if (raw->nbyte == 4) {
816 if ((raw->len = U2(raw->buff + 2) + 7) > MAXRAWLEN) {
817 trace(NULL, 2, "stq message length error: len=%d\n", raw->len);
818 raw->nbyte = 0;
819 return -1;
820 }
821 }
822 if (raw->nbyte < 4 || raw->nbyte < raw->len) {
823 return 0;
824 }
825 raw->nbyte = 0;
826
827 /* decode skytraq raw message */
828 return decode_stq(raw);
829}
830/* input skytraq raw message from file -----------------------------------------
831 * fetch next skytraq raw data and input a message from file
832 * args : raw_t *raw IO receiver raw data control struct
833 * FILE *fp I file pointer
834 * return : status(-2: end of file, -1...9: same as above)
835 *-----------------------------------------------------------------------------*/
836extern int input_stqf(raw_t* raw, FILE* fp) {
837 int i, data;
838
839 trace(NULL, 4, "input_stqf:\n");
840
841 /* synchronize frame */
842 if (raw->nbyte == 0) {
843 for (i = 0;; i++) {
844 if ((data = fgetc(fp)) == EOF) {
845 return -2;
846 }
847 if (sync_stq(raw->buff, (uint8_t)data)) {
848 break;
849 }
850 if (i >= 4096) {
851 return 0;
852 }
853 }
854 }
855 if (fread(raw->buff + 2, 1, 2, fp) < 2) {
856 return -2;
857 }
858 raw->nbyte = 4;
859
860 if ((raw->len = U2(raw->buff + 2) + 7) > MAXRAWLEN) {
861 trace(NULL, 2, "stq message length error: len=%d\n", raw->len);
862 raw->nbyte = 0;
863 return -1;
864 }
865 if (fread(raw->buff + 4, 1, raw->len - 4, fp) < (size_t)(raw->len - 4)) {
866 return -2;
867 }
868 raw->nbyte = 0;
869
870 /* decode skytraq raw message */
871 return decode_stq(raw);
872}
873/* generate skytraq binary message ---------------------------------------------
874 * generate skytraq binary message from message string
875 * args : char *msg I message string
876 * "RESTART [arg...]" system restart
877 * "CFG-SERI [arg...]" configure serial port propperty
878 * "CFG-FMT [arg...]" configure output message format
879 * "CFG-RATE [arg...]" configure binary measurement output rates
880 * "CFG-BIN [arg...]" configure general binary
881 * "GET-GLOEPH [slot]" get glonass ephemeris for freq channel number
882 * uint8_t *buff O binary message
883 * return : length of binary message (0: error)
884 * note : see reference [1][2][3][4] for details.
885 *-----------------------------------------------------------------------------*/
886extern int gen_stq(const char* msg, uint8_t* buff) {
887 const char* hz[] = {"1Hz", "2Hz", "4Hz", "5Hz", "10Hz", "20Hz", ""};
888 uint8_t* q = buff;
889 char mbuff[1024], *args[32], *p;
890 int i, n, narg = 0;
891
892 trace(NULL, 4, "gen_stq: msg=%s\n", msg);
893
894 strcpy(mbuff, msg);
895 for (p = strtok(mbuff, " "); p && narg < 32; p = strtok(NULL, " ")) {
896 args[narg++] = p;
897 }
898 if (narg < 1) {
899 return 0;
900 }
901 *q++ = STQSYNC1;
902 *q++ = STQSYNC2;
903 if (!strcmp(args[0], "RESTART")) {
904 *q++ = 0;
905 *q++ = 15;
906 *q++ = ID_RESTART;
907 *q++ = narg > 2 ? (uint8_t)atoi(args[1]) : 0;
908 for (i = 1; i < 15; i++) {
909 *q++ = 0; /* set all 0 */
910 }
911 } else if (!strcmp(args[0], "CFG-SERI")) {
912 *q++ = 0;
913 *q++ = 4;
914 *q++ = ID_CFGSERI;
915 for (i = 1; i < 4; i++) {
916 *q++ = narg > i + 1 ? (uint8_t)atoi(args[i]) : 0;
917 }
918 } else if (!strcmp(args[0], "CFG-FMT")) {
919 *q++ = 0;
920 *q++ = 3;
921 *q++ = ID_CFGFMT;
922 for (i = 1; i < 3; i++) {
923 *q++ = narg > i + 1 ? (uint8_t)atoi(args[i]) : 0;
924 }
925 } else if (!strcmp(args[0], "CFG-RATE")) {
926 *q++ = 0;
927 *q++ = 8;
928 *q++ = ID_CFGRATE;
929 if (narg > 2) {
930 for (i = 0; *hz[i]; i++) {
931 if (!strcmp(args[1], hz[i])) {
932 break;
933 }
934 }
935 if (*hz[i]) {
936 *q++ = i;
937 } else {
938 *q++ = (uint8_t)atoi(args[1]);
939 }
940 } else {
941 *q++ = 0;
942 }
943 for (i = 2; i < 8; i++) {
944 *q++ = narg > i + 1 ? (uint8_t)atoi(args[i]) : 0;
945 }
946 } else if (!strcmp(args[0], "CFG-BIN")) {
947 *q++ = 0;
948 *q++ = 9; /* F/W 1.4.32 */
949 *q++ = ID_CFGBIN;
950 if (narg > 2) {
951 for (i = 0; *hz[i]; i++) {
952 if (!strcmp(args[1], hz[i])) {
953 break;
954 }
955 }
956 if (*hz[i]) {
957 *q++ = i;
958 } else {
959 *q++ = (uint8_t)atoi(args[1]);
960 }
961 } else {
962 *q++ = 0;
963 }
964 for (i = 2; i < 9; i++) {
965 *q++ = narg > i + 1 ? (uint8_t)atoi(args[i]) : 0;
966 }
967 } else if (!strcmp(args[0], "GET-GLOEPH")) {
968 *q++ = 0;
969 *q++ = 2;
970 *q++ = ID_GETGLOEPH;
971 *q++ = narg >= 2 ? (uint8_t)atoi(args[1]) : 0;
972 } else {
973 return 0;
974 }
975
976 n = (int)(q - buff);
977 *q++ = checksum(buff, n + 3);
978 *q++ = 0x0D;
979 *q = 0x0A;
980
981 trace(NULL, 4, "gen_stq: buff=\n");
982 traceb(NULL, 4, buff, n + 3);
983 return n + 3;
984}
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.
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...
#define SNR_UNIT
#define MINPRNCMP
#define CODE_L2X
#define CODE_L3X
#define MAXOBS
#define MINPRNQZS
#define CODE_L5X
#define CODE_L7X
#define CODE_L2I
#define MAXPRNQZS
#define CODE_L1C
#define CODE_L6I
#define CODE_L2C
#define CODE_L7I
#define CODE_L6X
#define CODE_NONE
#define MAXRAWLEN
#define MINPRNGLO
#define MAXPRNCMP
#define MAXPRNGLO
#define CODE_L1X
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.
MRTKLIB Observation Module — Observation data types and utility functions.
#define U1(p)
#define MINPRNGPS
#define MAXPRNGPS
#define R8(p)
#define U4(p)
#define R4(p)
#define U2(p)
#define ID_GETGLOEPH
#define U1(p)
#define ID_STQRAW
static int decode_stqnack(raw_t *raw)
int input_stqf(raw_t *raw, FILE *fp)
#define ID_STQNACK
static int decode_ephem(int sat, raw_t *raw)
#define ID_STQGLO
static int sync_stq(uint8_t *buff, uint8_t data)
static void adj_utcweek(gtime_t time, double *utc)
#define ID_STQGPS
static int decode_stqack(raw_t *raw)
#define ID_STQTIME
#define ID_STQBDSD1
#define ID_CFGBIN
static int decode_stqgloe(raw_t *raw)
#define ID_STQBDSD2
#define ID_CFGFMT
static int decode_alm2(int sat, raw_t *raw)
static int decode_stqraw(raw_t *raw)
static int decode_stqgps(raw_t *raw)
#define ID_STQGLOE
#define ID_STQRAWX
static int save_subfrm(int sat, raw_t *raw)
static int decode_stq(raw_t *raw)
#define ID_CFGRATE
int gen_stq(const char *msg, uint8_t *buff)
int input_stq(raw_t *raw, uint8_t data)
static int decode_stqbds(raw_t *raw)
#define STQSYNC2
static int decode_stqtime(raw_t *raw)
static int decode_stqglo(raw_t *raw)
#define I1(p)
#define ID_RESTART
#define ID_CFGSERI
#define ID_STQACK
static int decode_alm1(int sat, raw_t *raw)
static uint8_t checksum(uint8_t *buff, int len)
#define STQSYNC1
static int decode_stqrawx(raw_t *raw)
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_bds_d1(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 gpst2time(int week, double sec)
Convert GPS week/tow to gtime_t.
Definition mrtk_time.c:165
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
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
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
double utc_qzs[8]
Definition mrtk_nav.h:417
double utc_gps[8]
Definition mrtk_nav.h:414
geph_t * geph
Definition mrtk_nav.h:407
alm_t * alm
Definition mrtk_nav.h:411
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
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
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
char opt[256]
int ephsat
Definition mrtk_rcvraw.h:85
int iod
Definition mrtk_rcvraw.h:97
gtime_t time
Definition mrtk_rcvraw.h:79