MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_convrnx.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_convrnx.c : RINEX translator for RTCM and receiver raw data log
3 *
4 * Copyright (C) 2026 H.SHIONO (MRTKLIB Project)
5 * Copyright (C) 2009-2020 T.TAKASU
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 *----------------------------------------------------------------------------*/
9/**
10 * @file mrtk_convrnx.c
11 * @brief RINEX translator for RTCM and receiver raw data log.
12 *
13 * version : $Revision: 1.2 $ $Date: 2008/07/17 21:48:06 $
14 * history : 2009/04/10 1.0 new
15 * 2009/06/02 1.1 support glonass
16 * 2009/12/18 1.2 add check return of init_rtcm()/init_raw()
17 * 2010/07/15 1.3 support wildcard expansion of input file
18 * support rinex 3.00
19 * support rinex as input format
20 * support output of geo navigation message
21 * support rtcm antenna and receiver info
22 * changed api:
23 * convrnx()
24 * 2011/05/27 1.4 support GW10, Javad, LEX receiver
25 * support lex message conversion
26 * change api convrnx()
27 * 2012/10/18 1.5 support multiple codes in a frequency
28 * 2012/10/29 1.6 fix bug on scanning obs types
29 * support output of compass navigation data
30 * add supported obs types for rinex input
31 * 2013/03/11 1.7 support binex and rinex 3.02
32 * add approx position in rinex obs header if blank
33 * 2014/05/24 1.8 support beidou B1
34 * 2014/08/26 1.9 support input format rt17
35 * 2015/05/24 1.10 fix bug on setting antenna delta in rtcm2opt()
36 * 2016/07/04 1.11 support IRNSS
37 * 2016/10/10 1.12 support event output by staid change in rtcm
38 * support separated navigation files for ver.3
39 * 2017/06/06 1.13 fix bug on array overflow in set_obstype() and
40 * scan_obstype()
41 * 2018/10/10 1.14 add trace of half-cycle ambiguity status
42 * fix bug on missing navigation data
43 * 2020/11/30 1.15 force scanning receiver log for obs-types (2-pass)
44 * delete scanobs in RINEX options (rnxopt_t)
45 * add phase shift option (phshift) in rnxopt_t
46 * sort obs-types by freq-index and code priority
47 * add test obs-types supportted by RINEX versions
48 * support receiver/antenna info in raw data
49 * fix bug on writing BDS/IRN nav header in closefile()
50 * fix bug on screening time in screent_ttol()
51 * fix bug on screening QZS L1S messages as SBAS
52 * use integer types in stdint.h
53 */
54#include "mrtklib/rtklib.h"
55
56#define NOUTFILE 9 /* number of output files */
57#define NSATSYS 7 /* number of satellite systems */
58#define TSTARTMARGIN 60.0 /* time margin for file name replacement */
59
60#define EVENT_STARTMOVE 2 /* rinex event start moving antenna */
61#define EVENT_NEWSITE 3 /* rinex event new site occupation */
62#define EVENT_HEADER 4 /* rinex event header info follows */
63#define EVENT_EXTERNAL 5 /* rinex event external event */
64
65/* type definitions ----------------------------------------------------------*/
66
67typedef struct stas_tag { /* station list type */
68 int staid; /* station IS */
69 gtime_t ts, te; /* first and last observation time */
70 sta_t sta; /* station parameters */
71 struct stas_tag* next; /* next list */
73
74typedef struct halfc_tag { /* half-cycle ambiguity list type */
75 gtime_t ts, te; /* first and last observation time */
76 uint8_t stat; /* half-cycle ambiguity status */
77 struct halfc_tag* next; /* next list */
79
80typedef struct { /* stream file type */
81 int format; /* stream format (STRFMT_???) */
82 int staid; /* station ID */
83 int ephsat, ephset; /* satelite and set of input ephemeris */
84 gtime_t time; /* current time */
85 gtime_t tstart; /* start time */
86 obs_t* obs; /* pointer to input observation data */
87 nav_t* nav; /* pointer to input navigation data */
88 sta_t* sta; /* pointer to input station parameters */
89 rtcm_t rtcm; /* input RTCM data */
90 raw_t raw; /* input receiver raw data */
91 rnxctr_t rnx; /* input RINEX control data */
92 stas_t* stas; /* station list */
93 uint8_t slips[MAXSAT][NFREQ + NEXOBS]; /* cycle slip flag cache */
94 halfc_t* halfc[MAXSAT][NFREQ + NEXOBS]; /* half-cycle ambiguity list */
95 FILE* fp; /* output file pointer */
96} strfile_t;
97
98/* global variables ----------------------------------------------------------*/
99static const int navsys[] = {/* system codes */
101static const char vercode[][MAXCODE] = {
102 /* supported obs-type by RINEX version */
103 /* 0........1.........2.........3.........4.........5.........6........ */
104 /* 11111111111112222222222555777666666688822663331155599991555677788444 CODE */
105 /* CPWYMNSLEABXZCDSLXPWYMNIQXIQXABCXZSLIQXIQIQIQXIQABCABCXDDPZEDPZDPABX */
106 "00000000...0.0000000000000..........................................", /* GPS */
107 "00...........0....0..........44.4..........222...................444", /* GLO */
108 "0........0000..........0000000000...000.............................", /* GAL */
109 "2.....22...22..222.....222......2422....................4444........", /* QZS */
110 "0......................000..........................................", /* SBS */
111 ".4...4...4.4.....1.......41114..1.....41111............444..44444...", /* BDS */
112 ".........................3......................3333333............." /* IRN */
113};
114/* convert RINEX obs-type ver.3 -> ver.2 -------------------------------------*/
115static void convcode(int rnxver, int sys, char* type) {
116 if (rnxver >= 212 && (sys == SYS_GPS || sys == SYS_QZS || sys == SYS_SBS) && !strcmp(type + 1, "1C")) { /* L1C/A */
117 strcpy(type + 1, "A");
118 } else if (rnxver >= 212 && (sys == SYS_GPS || sys == SYS_QZS) &&
119 (!strcmp(type + 1, "1S") || !strcmp(type + 1, "1L") || !strcmp(type + 1, "1X"))) { /* L1C */
120 strcpy(type + 1, "B");
121 } else if (rnxver >= 212 && (sys == SYS_GPS || sys == SYS_QZS) &&
122 (!strcmp(type + 1, "2S") || !strcmp(type + 1, "2L") || !strcmp(type + 1, "2X"))) { /* L2C */
123 strcpy(type + 1, "C");
124 } else if (rnxver >= 212 && sys == SYS_GLO && !strcmp(type + 1, "1C")) { /* L1C/A */
125 strcpy(type + 1, "A");
126 } else if (rnxver >= 212 && sys == SYS_GLO && !strcmp(type + 1, "2C")) { /* L2C/A */
127 strcpy(type + 1, "D");
128 } else if (sys == SYS_CMP &&
129 (!strcmp(type + 1, "2I") || !strcmp(type + 1, "2Q") || !strcmp(type + 1, "2X"))) { /* B1_2 */
130 strcpy(type + 1, "2");
131 } else if (!strcmp(type, "C1P") || !strcmp(type, "C1W") || !strcmp(type, "C1Y") ||
132 !strcmp(type, "C1N")) { /* L1P,P(Y) */
133 strcpy(type, "P1");
134 } else if (!strcmp(type, "C2P") || !strcmp(type, "C2W") || !strcmp(type, "C2Y") || !strcmp(type, "C2N") ||
135 !strcmp(type, "C2D")) { /* L2P,P(Y) */
136 strcpy(type, "P2");
137 } else {
138 type[2] = '\0';
139 }
140}
141/* generate stream file ------------------------------------------------------*/
142static strfile_t* gen_strfile(int format, const char* opt) {
143 strfile_t* str;
144 gtime_t time0 = {0};
145 int i, j;
146
147 trace(NULL, 3, "init_strfile:\n");
148
149 if (!(str = (strfile_t*)calloc(sizeof(strfile_t), 1))) return NULL;
150
151 str->format = format;
152 str->staid = -1;
153 str->ephsat = str->ephset = 0;
154 str->time = str->tstart = time0;
155
156 if (format == STRFMT_RTCM2 || format == STRFMT_RTCM3) {
157 if (!init_rtcm(&str->rtcm)) {
158 showmsg("init rtcm error");
159 free(str);
160 return NULL;
161 }
162 str->rtcm.time = time0;
163 str->obs = &str->rtcm.obs;
164 str->nav = &str->rtcm.nav;
165 str->sta = &str->rtcm.sta;
166 strcpy(str->rtcm.opt, opt);
167 } else if (format <= MAXRCVFMT) {
168 if (!init_raw(&str->raw, format)) {
169 showmsg("init raw error");
170 free(str);
171 return NULL;
172 }
173 str->raw.time = time0;
174 str->obs = &str->raw.obs;
175 str->nav = &str->raw.nav;
176 str->sta = &str->raw.sta;
177 strcpy(str->raw.opt, opt);
178 } else if (format == STRFMT_RINEX) {
179 if (!init_rnxctr(&str->rnx)) {
180 showmsg("init rnx error");
181 free(str);
182 return NULL;
183 }
184 str->rnx.time = time0;
185 str->obs = &str->rnx.obs;
186 str->nav = &str->rnx.nav;
187 str->sta = &str->rnx.sta;
188 strcpy(str->rnx.opt, opt);
189 } else {
190 free(str);
191 return NULL;
192 }
193
194 str->stas = NULL;
195 for (i = 0; i < MAXSAT; i++)
196 for (j = 0; j < NFREQ + NEXOBS; j++) {
197 str->slips[i][j] = 0;
198 str->halfc[i][j] = NULL;
199 }
200 str->fp = NULL;
201 return str;
202}
203/* free stream file ----------------------------------------------------------*/
204static void free_strfile(strfile_t* str) {
205 stas_t *sp, *sp_next;
206 halfc_t *hp, *hp_next;
207 int i, j;
208
209 trace(NULL, 3, "free_strfile:\n");
210
211 if (str->format == STRFMT_RTCM2 || str->format == STRFMT_RTCM3) {
212 free_rtcm(&str->rtcm);
213 } else if (str->format <= MAXRCVFMT) {
214 free_raw(&str->raw);
215 } else if (str->format == STRFMT_RINEX) {
216 free_rnxctr(&str->rnx);
217 }
218 for (sp = str->stas; sp; sp = sp_next) {
219 sp_next = sp->next;
220 free(sp);
221 }
222 for (i = 0; i < MAXSAT; i++)
223 for (j = 0; j < NFREQ + NEXOBS; j++) {
224 for (hp = str->halfc[i][j]; hp; hp = hp_next) {
225 hp_next = hp->next;
226 free(hp);
227 }
228 }
229 free(str);
230}
231/* input stream file ---------------------------------------------------------*/
232static int input_strfile(strfile_t* str) {
233 int type = 0;
234
235 trace(NULL, 4, "input_strfile:\n");
236
237 if (str->format == STRFMT_RTCM2) {
238 if ((type = input_rtcm2f(&str->rtcm, str->fp)) >= 1) {
239 str->time = str->rtcm.time;
240 str->ephsat = str->rtcm.ephsat;
241 str->ephset = str->rtcm.ephset;
242 str->staid = str->rtcm.staid;
243 }
244 } else if (str->format == STRFMT_RTCM3) {
245 if ((type = input_rtcm3f(&str->rtcm, str->fp)) >= 1) {
246 str->time = str->rtcm.time;
247 str->ephsat = str->rtcm.ephsat;
248 str->ephset = str->rtcm.ephset;
249 str->staid = str->rtcm.staid;
250 }
251 } else if (str->format <= MAXRCVFMT) {
252 if ((type = input_rawf(&str->raw, &str->rtcm, str->format, str->fp)) >= 1) {
253 str->time = str->raw.time;
254 str->ephsat = str->raw.ephsat;
255 str->ephset = str->raw.ephset;
256 str->staid = 0;
257 }
258 } else if (str->format == STRFMT_RINEX) {
259 if ((type = input_rnxctr(&str->rnx, str->fp)) >= 1) {
260 str->time = str->rnx.time;
261 str->ephsat = str->rnx.ephsat;
262 str->ephset = str->rnx.ephset;
263 str->staid = 0;
264 }
265 }
266 if (!str->tstart.time && str->time.time) {
267 str->tstart = str->time;
268 }
269 trace(NULL, 4, "input_strfile: time=%s type=%d\n", time_str(str->time, 3), type);
270 return type;
271}
272/* open stream file ----------------------------------------------------------*/
273static int open_strfile(strfile_t* str, const char* file) {
274 trace(NULL, 3, "open_strfile: file=%s\n", file);
275
276 if (str->format == STRFMT_RTCM2 || str->format == STRFMT_RTCM3) {
277 if (!(str->fp = fopen(file, "rb"))) {
278 showmsg("rtcm open error: %s", file);
279 return 0;
280 }
281 str->rtcm.time = str->time;
282 } else if (str->format <= MAXRCVFMT) {
283 if (!(str->fp = fopen(file, "rb"))) {
284 showmsg("log open error: %s", file);
285 return 0;
286 }
287 str->raw.time = str->time;
288 } else if (str->format == STRFMT_RINEX) {
289 if (!(str->fp = fopen(file, "r"))) {
290 showmsg("rinex open error: %s", file);
291 return 0;
292 }
293 /* open rinex control */
294 if (!open_rnxctr(&str->rnx, str->fp)) {
295 showmsg("no rinex file: %s", file);
296 fclose(str->fp);
297 return 0;
298 }
299 str->rnx.time = str->time;
300 }
301 return 1;
302}
303/* close stream file ---------------------------------------------------------*/
304static void close_strfile(strfile_t* str) {
305 trace(NULL, 3, "close_strfile:\n");
306
307 if (str->format == STRFMT_RTCM2 || str->format == STRFMT_RTCM3) {
308 if (str->fp) fclose(str->fp);
309 } else if (str->format <= MAXRCVFMT) {
310 if (str->fp) fclose(str->fp);
311 } else if (str->format == STRFMT_RINEX) {
312 if (str->fp) fclose(str->fp);
313 }
314}
315/* set format and files in RINEX options comments ----------------------------*/
316static void setopt_file(int format, char** paths, int n, const int* mask, rnxopt_t* opt) {
317 int i, j;
318
319 for (i = 0; i < MAXCOMMENT; i++) {
320 if (!*opt->comment[i]) break;
321 }
322 if (i < MAXCOMMENT) {
323 sprintf(opt->comment[i++], "format: %.55s", formatstrs[format]);
324 }
325 for (j = 0; j < n && i < MAXCOMMENT; j++) {
326 if (!mask[j]) continue;
327 sprintf(opt->comment[i++], "log: %.58s", paths[j]);
328 }
329}
330/* unset RINEX options comments ----------------------------------------------*/
331static void unsetopt_file(rnxopt_t* opt) {
332 int i, brk = 0;
333
334 for (i = MAXCOMMENT - 1; i >= 0 && !brk; i--) {
335 if (!*opt->comment[i]) continue;
336 if (!strncmp(opt->comment[i], "format: ", 8)) brk = 1;
337 *opt->comment[i] = '\0';
338 }
339}
340/* sort obs-types ------------------------------------------------------------*/
341static void sort_obstype(uint8_t* codes, uint8_t* types, int n, int sys) {
342 uint8_t tmp;
343 int i, j, idx1, idx2, pri1, pri2;
344
345 for (i = 0; i < n - 1; i++)
346 for (j = i + 1; j < n; j++) {
347 idx1 = code2freq_idx(navsys[sys], codes[i]);
348 idx2 = code2freq_idx(navsys[sys], codes[j]);
349 pri1 = getcodepri(navsys[sys], codes[i], "");
350 pri2 = getcodepri(navsys[sys], codes[j], "");
351 if (idx1 < idx2 || (idx1 == idx2 && pri1 >= pri2)) continue;
352 tmp = codes[i];
353 codes[i] = codes[j];
354 codes[j] = tmp;
355 tmp = types[i];
356 types[i] = types[j];
357 types[j] = tmp;
358 }
359}
360/* set obs-types in RINEX options --------------------------------------------*/
361static void setopt_obstype(const uint8_t* codes, const uint8_t* types, int sys, rnxopt_t* opt) {
362 const char type_str[] = "CLDS";
363 char type[16], *id, ver;
364 int i, j, k, idx;
365
366 trace(NULL, 3, "setopt_obstype: sys=%d\n", sys);
367
368 opt->nobs[sys] = 0;
369
370 if (!(navsys[sys] & opt->navsys)) return;
371
372 for (i = 0; codes[i]; i++) {
373 if (!(id = code2obs(codes[i])) || (idx = code2freq_idx(navsys[sys], codes[i])) < 0) {
374 continue;
375 }
376 if (!(opt->freqtype & (1 << idx)) || opt->mask[sys][codes[i] - 1] == '0') {
377 continue;
378 }
379 if (opt->rnxver >= 300) {
380 ver = vercode[sys][codes[i] - 1];
381 if (ver < '0' || ver > '0' + opt->rnxver - 300) {
382 trace(NULL, 2, "unsupported obs type: rnxver=%.2f sys=%d code=%s\n", opt->rnxver / 100.0, sys,
383 code2obs(codes[i]));
384 continue;
385 }
386 }
387 for (j = 0; j < 4; j++) {
388 if (!(opt->obstype & (1 << j))) continue;
389 if (types && !(types[i] & (1 << j))) continue;
390
391 /* obs-types in ver.3 */
392 sprintf(type, "%c%s", type_str[j], id);
393 if (type[0] == 'C' && type[2] == 'N') continue; /* codeless */
394
395 if (opt->rnxver <= 299) { /* ver.2 */
396
397 /* ver.3 -> ver.2 */
398 convcode(opt->rnxver, navsys[sys], type);
399
400 /* check duplicated obs-type */
401 for (k = 0; k < opt->nobs[0]; k++) {
402 if (!strcmp(opt->tobs[0][k], type)) break;
403 }
404 if (k >= opt->nobs[0] && opt->nobs[0] < MAXOBSTYPE) {
405 strcpy(opt->tobs[0][opt->nobs[0]++], type);
406 }
407 } else if (opt->nobs[sys] < MAXOBSTYPE) { /* ver.3 */
408 strcpy(opt->tobs[sys][opt->nobs[sys]++], type);
409 }
410 }
411 }
412}
413/* set phase shift in RINEX options (RINEX 3.04 A23) -------------------------*/
414static void setopt_phshift(rnxopt_t* opt) {
415 uint8_t code;
416 int i, j;
417
418 for (i = 0; i < NSATSYS; i++)
419 for (j = 0; j < opt->nobs[i]; j++) {
420 if (opt->tobs[i][j][0] != 'L') continue;
421 code = obs2code(opt->tobs[i][j] + 1);
422
423 if (navsys[i] == SYS_GPS) {
424 if (code == CODE_L1S || code == CODE_L1L || code == CODE_L1X || code == CODE_L1P || code == CODE_L1W ||
425 code == CODE_L1N) {
426 opt->shift[i][j] = 0.25; /* +1/4 cyc */
427 } else if (code == CODE_L2C || code == CODE_L2S || code == CODE_L2L || code == CODE_L2X ||
428 code == CODE_L5Q) {
429 opt->shift[i][j] = -0.25; /* -1/4 cyc */
430 }
431 } else if (navsys[i] == SYS_GLO) {
432 if (code == CODE_L1P || code == CODE_L2P || code == CODE_L3Q) {
433 opt->shift[i][j] = 0.25; /* +1/4 cyc */
434 }
435 } else if (navsys[i] == SYS_GAL) {
436 if (code == CODE_L1C) {
437 opt->shift[i][j] = 0.5; /* +1/2 cyc */
438 } else if (code == CODE_L5Q || code == CODE_L7Q || code == CODE_L8Q) {
439 opt->shift[i][j] = -0.25; /* -1/4 cyc */
440 } else if (code == CODE_L6C) {
441 opt->shift[i][j] = -0.5; /* -1/2 cyc */
442 }
443 } else if (navsys[i] == SYS_QZS) {
444 if (code == CODE_L1S || code == CODE_L1L || code == CODE_L1X) {
445 opt->shift[i][j] = 0.25; /* +1/4 cyc */
446 } else if (code == CODE_L5Q || code == CODE_L5P) {
447 opt->shift[i][j] = -0.25; /* -1/4 cyc */
448 }
449 } else if (navsys[i] == SYS_CMP) {
450 if (code == CODE_L2P || code == CODE_L7Q || code == CODE_L6Q) {
451 opt->shift[i][j] = -0.25; /* -1/4 cyc */
452 } else if (code == CODE_L1P || code == CODE_L5P || code == CODE_L7P) {
453 opt->shift[i][j] = 0.25; /* +1/4 cyc */
454 }
455 }
456 }
457}
458/* set station ID list to RINEX options comments -----------------------------*/
459static void setopt_sta_list(const strfile_t* str, rnxopt_t* opt) {
460 const stas_t* p;
461 char s1[32], s2[32];
462 int i, n = 0;
463
464 for (p = str->stas; p; p = p->next) {
465 n++;
466 }
467 if (n <= 1) return;
468
469 for (i = 0; i < MAXCOMMENT; i++) {
470 if (!*opt->comment[i]) break;
471 }
472 sprintf(opt->comment[i++], "%5s %22s %22s", "STAID", "TIME OF FIRST OBS", "TIME OF LAST OBS");
473
474 for (p = str->stas, n--; p && n >= 0; p = p->next, n--) {
475 if (i + n >= MAXCOMMENT) continue;
476 time2str(p->ts, s1, 2);
477 time2str(p->te, s2, 2);
478 sprintf(opt->comment[i + n], " %04d %s %s", p->staid, s1, s2);
479 }
480}
481/* set station info in RINEX options -----------------------------------------*/
482static void setopt_sta(const strfile_t* str, rnxopt_t* opt) {
483 const stas_t* p;
484 const sta_t* sta;
485 double pos[3], enu[3];
486
487 trace(NULL, 3, "setopt_sta:\n");
488
489 /* search first station in station list */
490 for (p = str->stas; p; p = p->next) {
491 if (!p->next) break;
492 if (opt->ts.time && timediff(p->next->te, opt->ts) < 0.0) break;
493 }
494 if (p) {
495 sta = &p->sta;
496 setopt_sta_list(str, opt);
497 } else {
498 sta = str->sta;
499 }
500 /* marker name and number */
501 if (!*opt->marker && !*opt->markerno) {
502 strcpy(opt->marker, sta->name);
503 strcpy(opt->markerno, sta->marker);
504 }
505 /* receiver and antenna info */
506 if (!*opt->rec[0] && !*opt->rec[1] && !*opt->rec[2]) {
507 strcpy(opt->rec[0], sta->recsno);
508 strcpy(opt->rec[1], sta->rectype);
509 strcpy(opt->rec[2], sta->recver);
510 }
511 if (!*opt->ant[0] && !*opt->ant[1] && !*opt->ant[2]) {
512 strcpy(opt->ant[0], sta->antsno);
513 strcpy(opt->ant[1], sta->antdes);
514 if (sta->antsetup) {
515 sprintf(opt->ant[2], "%d", sta->antsetup);
516 } else
517 *opt->ant[2] = '\0';
518 }
519 /* antenna approx position */
520 if (!opt->autopos && norm(sta->pos, 3) > 0.0) {
521 matcpy(opt->apppos, sta->pos, 3, 1);
522 }
523 /* antenna delta */
524 if (norm(opt->antdel, 3) > 0.0) {
525 ;
526 } else if (norm(sta->del, 3) > 0.0) {
527 if (!sta->deltype && norm(sta->del, 3) > 0.0) { /* enu */
528 opt->antdel[0] = sta->del[2]; /* h */
529 opt->antdel[1] = sta->del[0]; /* e */
530 opt->antdel[2] = sta->del[1]; /* n */
531 } else if (norm(sta->pos, 3) > 0.0) { /* xyz */
532 ecef2pos(sta->pos, pos);
533 ecef2enu(pos, sta->del, enu);
534 opt->antdel[0] = enu[2]; /* h */
535 opt->antdel[1] = enu[0]; /* e */
536 opt->antdel[2] = enu[1]; /* n */
537 }
538 } else {
539 opt->antdel[0] = sta->hgt;
540 opt->antdel[1] = 0.0;
541 opt->antdel[2] = 0.0;
542 }
543}
544/* update station list -------------------------------------------------------*/
545static void update_stas(strfile_t* str) {
546 stas_t* p;
547
548 if (!str->stas || str->stas->staid != str->staid) { /* station ID changed */
549 if (!(p = (stas_t*)calloc(sizeof(stas_t), 1))) return;
550 p->staid = str->staid;
551 p->ts = p->te = str->time;
552 p->next = str->stas;
553 str->stas = p;
554 } else {
555 str->stas->te = str->time;
556 }
557}
558/* update station info in station list ---------------------------------------*/
559static void update_stainf(strfile_t* str) {
560 if (str->stas && str->stas->staid == str->staid) {
561 str->stas->sta = *str->sta;
562 }
563}
564/* dump station list ---------------------------------------------------------*/
565static void dump_stas(const strfile_t* str) {
566#if 1 /* for debug */
567 stas_t* p;
568 double pos[3];
569 char s1[32], s2[32];
570
571 trace(NULL, 2, "# STATION LIST\n");
572 trace(NULL, 2, "# %17s %19s %5s %6s %16s %16s %12s %13s %9s %2s %6s %6s %6s\n", "TIME", "STAID", "MARKER",
573 "ANTENNA", "RECEIVER", "LATITUDE", "LONGITUDE", "HIGHT", "DT", "DEL1", "DEL2", "DEL3");
574
575 for (p = str->stas; p; p = p->next) {
576 time2str(p->ts, s1, 0);
577 time2str(p->te, s2, 0);
578 ecef2pos(p->sta.pos, pos);
579 trace(NULL, 2,
580 "%s %s %04d %-6.6s %-16.16s %-16.16s %12.8f %13.8f %9.3f %2d "
581 "%6.3f %6.3f %6.3f\n",
582 s1, s2, p->staid, p->sta.name, p->sta.antdes, p->sta.rectype, pos[0] * R2D, pos[1] * R2D, pos[2],
583 p->sta.deltype, p->sta.del[0], p->sta.del[1], p->sta.del[2]);
584 }
585#endif
586}
587/* add half-cycle ambiguity list ---------------------------------------------*/
588static int add_halfc(strfile_t* str, int sat, int idx, gtime_t time) {
589 halfc_t* p;
590
591 if (!(p = (halfc_t*)calloc(sizeof(halfc_t), 1))) return 0;
592 p->ts = p->te = time;
593 p->stat = 0;
594 p->next = str->halfc[sat - 1][idx];
595 str->halfc[sat - 1][idx] = p;
596 return 1;
597}
598/* update half-cycle ambiguity -----------------------------------------------*/
599static void update_halfc(strfile_t* str, obsd_t* obs) {
600 int i, sat = obs->sat;
601
602 for (i = 0; i < NFREQ + NEXOBS; i++) {
603 if (obs->L[i] == 0.0) continue;
604
605 if (!str->halfc[sat - 1][i]) {
606 if (!add_halfc(str, sat, i, obs->time)) continue;
607 }
608 if (obs->LLI[i] & LLI_SLIP) {
609 str->halfc[sat - 1][i]->stat = 0;
610 }
611 if (obs->LLI[i] & LLI_HALFC) { /* halfcyc unknown */
612 if (str->halfc[sat - 1][i]->stat == 0) {
613 str->halfc[sat - 1][i]->ts = obs->time;
614 }
615 str->halfc[sat - 1][i]->te = obs->time;
616 str->halfc[sat - 1][i]->stat = 1; /* unresolved */
617 } else if (str->halfc[sat - 1][i]->stat == 1) { /* halfcyc unknown -> known */
618 if (obs->LLI[i] & LLI_HALFA) {
619 str->halfc[sat - 1][i]->stat = 2; /* resolved with added */
620 } else if (obs->LLI[i] & LLI_HALFS) {
621 str->halfc[sat - 1][i]->stat = 3; /* resolved with subtracted */
622 } else {
623 str->halfc[sat - 1][i]->stat = 4; /* resolved with none */
624 }
625 if (!add_halfc(str, sat, i, obs->time)) continue;
626 }
627 }
628}
629/* dump half-cycle ambiguity list --------------------------------------------*/
630static void dump_halfc(const strfile_t* str) {
631#if 0 /* for debug */
632 halfc_t *p;
633 char s0[32],s1[32],s2[32],*stats[]={"ADD","SUB","NON"};
634 int i,j;
635
636 trace(NULL,2,"# HALF-CYCLE AMBIGUITY CORRECTIONS\n");
637 trace(NULL,2,"# %20s %22s %4s %3s %3s\n","START","END","SAT","FRQ","COR");
638
639 for (i=0;i<MAXSAT;i++) for (j=0;j<NFREQ+NEXOBS;j++) {
640 for (p=str->halfc[i][j];p;p=p->next) {
641 if (p->stat<=1) continue;
642 satno2id(i+1,s0);
643 time2str(p->ts,s1,2);
644 time2str(p->te,s2,2);
645 trace(NULL,2,"%s %s %4s %3d %3s\n",s1,s2,s0,j+1,stats[p->stat-2]);
646 }
647 }
648#endif
649}
650/* resolve half-cycle ambiguity ----------------------------------------------*/
651static void resolve_halfc(const strfile_t* str, obsd_t* data, int n) {
652 halfc_t* p;
653 int i, j, sat;
654
655 for (i = 0; i < n; i++)
656 for (j = 0; j < NFREQ + NEXOBS; j++) {
657 sat = data[i].sat;
658
659 for (p = str->halfc[sat - 1][j]; p; p = p->next) {
660 if (p->stat <= 1) continue;
661 if (timediff(data[i].time, p->ts) < -DTTOL || timediff(data[i].time, p->te) > DTTOL) continue;
662
663 if (p->stat == 3) {
664 data[i].L[j] += 0.5;
665 } else if (p->stat == 4) {
666 data[i].L[j] -= 0.5;
667 }
668 data[i].LLI[j] &= ~LLI_HALFC;
669 }
670 data[i].LLI[j] &= ~(LLI_HALFA | LLI_HALFS);
671 }
672}
673/* scan input files ----------------------------------------------------------*/
674static int scan_file(char** files, int nf, rnxopt_t* opt, strfile_t* str, int* mask) {
675 eph_t eph0 = {0, -1, -1};
676 geph_t geph0 = {0, -1};
677 seph_t seph0 = {0};
678 uint8_t codes[NSATSYS][33] = {{0}};
679 uint8_t types[NSATSYS][33] = {{0}};
680 char msg[128];
681 int i, j, k, l, m, c = 0, type, sys, prn, abort = 0, n[NSATSYS] = {0};
682
683 trace(NULL, 3, "scan_file: nf=%d\n", nf);
684
685 for (m = 0; m < nf && !abort; m++) {
686 if (!open_strfile(str, files[m])) {
687 continue;
688 }
689 while ((type = input_strfile(str)) >= -1) {
690 if (opt->ts.time && timediff(str->time, opt->ts) < -opt->ttol) continue;
691 if (opt->te.time && timediff(str->time, opt->te) > -opt->ttol) break;
692 mask[m] = 1; /* update file mask */
693
694 if (type == 1) { /* observation data */
695 for (i = 0; i < str->obs->n; i++) {
696 sys = satsys(str->obs->data[i].sat, NULL);
697 if (!(sys & opt->navsys)) continue;
698 for (l = 0; navsys[l]; l++)
699 if (navsys[l] == sys) break;
700 if (!navsys[l]) continue;
701
702 /* update obs-types */
703 for (j = 0; j < NFREQ + NEXOBS; j++) {
704 if (!str->obs->data[i].code[j]) continue;
705
706 for (k = 0; k < n[l]; k++) {
707 if (codes[l][k] == str->obs->data[i].code[j]) break;
708 }
709 if (k >= n[l] && n[l] < 32) {
710 codes[l][n[l]++] = str->obs->data[i].code[j];
711 }
712 if (k < n[l]) {
713 if (str->obs->data[i].P[j] != 0.0) types[l][k] |= 1;
714 if (str->obs->data[i].L[j] != 0.0) types[l][k] |= 2;
715 if (str->obs->data[i].D[j] != 0.0) types[l][k] |= 4;
716 if (str->obs->data[i].SNR[j] != 0) types[l][k] |= 8;
717 }
718 }
719 /* update half-cycle ambiguity list */
720 if (opt->halfcyc) {
721 update_halfc(str, str->obs->data + i);
722 }
723 }
724 /* update station list */
725 update_stas(str);
726 } else if (type == 5) { /* station info */
727 /* update station info */
728 update_stainf(str);
729 }
730 if (++c % 11) continue;
731
732 sprintf(msg, "scanning: %s %s%s%s%s%s%s%s", time_str(str->time, 0), n[0] ? "G" : "", n[1] ? "R" : "",
733 n[2] ? "E" : "", n[3] ? "J" : "", n[4] ? "S" : "", n[5] ? "C" : "", n[6] ? "I" : "");
734 if ((abort = showmsg(msg))) break;
735 }
736 close_strfile(str);
737 }
738 showmsg("");
739
740 if (abort) {
741 trace(NULL, 2, "aborted in scan\n");
742 return 0;
743 }
744 for (i = 0; i < NSATSYS; i++)
745 for (j = 0; j < n[i]; j++) {
746 trace(NULL, 2, "scan_file: sys=%d code=%s type=%d\n", i, code2obs(codes[i][j]), types[i][j]);
747 }
748 /* sort and set obs-types in RINEX options */
749 for (i = 0; i < NSATSYS; i++) {
750 sort_obstype(codes[i], types[i], n[i], i);
751 setopt_obstype(codes[i], types[i], i, opt);
752
753 for (j = 0; j < n[i]; j++) {
754 trace(NULL, 3, "scan_file: sys=%d code=%s\n", i, code2obs(codes[i][j]));
755 }
756 }
757 /* set station info in RINEX options */
758 setopt_sta(str, opt);
759
760 /* set phase shifts in RINEX options */
761 if (opt->phshift) {
762 setopt_phshift(opt);
763 }
764 /* set GLONASS FCN and clear ephemeris */
765 for (i = 0; i < str->nav->n; i++) {
766 str->nav->eph[i] = eph0;
767 }
768 for (i = 0; i < str->nav->ng; i++) {
769 if (satsys(str->nav->geph[i].sat, &prn) != SYS_GLO) continue;
770 str->nav->glo_fcn[prn - 1] = str->nav->geph[i].frq + 8;
771 str->nav->geph[i] = geph0;
772 }
773 for (i = 0; i < str->nav->ns; i++) {
774 str->nav->seph[i] = seph0;
775 }
776 dump_stas(str);
777 dump_halfc(str);
778 return 1;
779}
780/* write RINEX header --------------------------------------------------------*/
781static void write_header(FILE** ofp, int idx, const rnxopt_t* opt, const nav_t* nav) {
782 switch (idx) {
783 case 0:
784 outrnxobsh(ofp[0], opt, nav);
785 break;
786 case 1:
787 outrnxnavh(ofp[1], opt, nav);
788 break;
789 case 2:
790 outrnxgnavh(ofp[2], opt, nav);
791 break;
792 case 3:
793 outrnxhnavh(ofp[3], opt, nav);
794 break;
795 case 4:
796 outrnxqnavh(ofp[4], opt, nav);
797 break;
798 case 5:
799 outrnxlnavh(ofp[5], opt, nav);
800 break;
801 case 6:
802 outrnxcnavh(ofp[6], opt, nav);
803 break;
804 case 7:
805 outrnxinavh(ofp[7], opt, nav);
806 break;
807 }
808}
809/* open output files ---------------------------------------------------------*/
810static int openfile(FILE** ofp, char* files[], const char* file, const rnxopt_t* opt, const nav_t* nav) {
811 char path[1024];
812 int i;
813
814 trace(NULL, 3, "openfile:\n");
815
816 for (i = 0; i < NOUTFILE; i++) {
817 if (!*files[i]) continue;
818
819 strcpy(path, files[i]);
820
821 /* check overwrite input file and modify output file */
822 if (!strcmp(path, file)) strcat(path, "_");
823
824 /* create directory if not exist */
825 createdir(path);
826
827 if (!(ofp[i] = fopen(path, "w"))) {
828 showmsg("file open error: %s", path);
829 for (i--; i >= 0; i--)
830 if (ofp[i]) fclose(ofp[i]);
831 return 0;
832 }
833 /* write RINEX header */
834 write_header(ofp, i, opt, nav);
835 }
836 return 1;
837}
838/* close output files --------------------------------------------------------*/
839static void closefile(FILE** ofp, const rnxopt_t* opt, nav_t* nav) {
840 int i;
841
842 trace(NULL, 3, "closefile:\n");
843
844 for (i = 0; i < NOUTFILE; i++) {
845 if (!ofp[i]) continue;
846
847 /* rewrite RINEX header */
848 rewind(ofp[i]);
849 write_header(ofp, i, opt, nav);
850
851 fclose(ofp[i]);
852 }
853}
854/* output RINEX event --------------------------------------------------------*/
855static void outrnxevent(FILE* fp, const rnxopt_t* opt, gtime_t time, int event, const stas_t* stas, int staid) {
856 const stas_t *p = NULL, *q;
857 double ep[6], pos[3], enu[3], del[3];
858
859 trace(NULL, 3, "outrnxevent: event=%d\n", event);
860
861 if (event == EVENT_STARTMOVE) {
862 fprintf(fp, "%*s%d%3d\n", (opt->rnxver >= 300) ? 31 : 28, "", event, 2);
863 fprintf(fp, "%-60s%-20s\n", "EVENT: START MOVING ANTENNA", "COMMENT");
864 fprintf(fp, "%-60s%-20s\n", opt->marker, "MARKER NAME");
865 } else if (event == EVENT_NEWSITE) {
866 for (q = stas; q; q = q->next) {
867 if (q->staid == staid && timediff(time, q->te) <= 0.0) p = q;
868 }
869 fprintf(fp, "%*s%d%3d\n", (opt->rnxver >= 300) ? 31 : 28, "", event, 6);
870 fprintf(fp, "%-60s%-20s\n", "EVENT: NEW SITE OCCUPATION", "COMMENT");
871 if (!p) {
872 fprintf(fp, "%04d%56s%-20s\n", staid, "", "MARKER NAME");
873 return;
874 }
875 fprintf(fp, "%-60s%-20s\n", p->sta.name, "MARKER NAME");
876 fprintf(fp, "%-20.20s%-20.20s%-20.20s%-20s\n", p->sta.recsno, p->sta.rectype, p->sta.recver,
877 "REC # / TYPE / VERS");
878 fprintf(fp, "%-20.20s%-20.20s%-20.20s%-20s\n", p->sta.antsno, p->sta.antdes, "", "ANT # / TYPE");
879 fprintf(fp, "%14.4f%14.4f%14.4f%-18s%-20s\n", p->sta.pos[0], p->sta.pos[1], p->sta.pos[2], "",
880 "APPROX POSITION XYZ");
881
882 /* antenna delta */
883 if (norm(p->sta.del, 3) > 0.0) {
884 if (!p->sta.deltype && norm(p->sta.del, 3) > 0.0) { /* enu */
885 del[0] = p->sta.del[2]; /* h */
886 del[1] = p->sta.del[0]; /* e */
887 del[2] = p->sta.del[1]; /* n */
888 } else if (norm(p->sta.pos, 3) > 0.0) { /* xyz */
889 ecef2pos(p->sta.pos, pos);
890 ecef2enu(pos, p->sta.del, enu);
891 del[0] = enu[2]; /* h */
892 del[1] = enu[0]; /* e */
893 del[2] = enu[1]; /* n */
894 }
895 } else {
896 del[0] = p->sta.hgt;
897 del[1] = del[2] = 0.0;
898 }
899 fprintf(fp, "%14.4f%14.4f%14.4f%-18s%-20s\n", del[0], del[1], del[2], "", "ANTENNA: DELTA H/E/N");
900 } else if (event == EVENT_EXTERNAL) {
901 time2epoch(time, ep);
902 fprintf(fp, "%s %02d %02.0f %02.0f %02.0f %02.0f %010.7f %d%3d\n", (opt->rnxver >= 300) ? ">" : "",
903 (opt->rnxver >= 300) ? (int)ep[0] : (int)ep[0] % 100, ep[1], ep[2], ep[3], ep[4], ep[5], event, 1);
904 fprintf(fp, "%-60s%-20s\n", "EXTERNAL EVENT", "COMMENT");
905 }
906}
907/* save cycle slips ----------------------------------------------------------*/
908static void save_slips(strfile_t* str, obsd_t* data, int n) {
909 int i, j;
910
911 for (i = 0; i < n; i++)
912 for (j = 0; j < NFREQ + NEXOBS; j++) {
913 if (data[i].LLI[j] & LLI_SLIP) str->slips[data[i].sat - 1][j] = 1;
914 }
915}
916/* restore cycle slips -------------------------------------------------------*/
917static void rest_slips(strfile_t* str, obsd_t* data, int n) {
918 int i, j;
919
920 for (i = 0; i < n; i++)
921 for (j = 0; j < NFREQ + NEXOBS; j++) {
922 if (data[i].L[j] != 0.0 && str->slips[data[i].sat - 1][j]) {
923 data[i].LLI[j] |= LLI_SLIP;
924 str->slips[data[i].sat - 1][j] = 0;
925 }
926 }
927}
928/* screen time with time tolerance -------------------------------------------*/
929static int screent_ttol(gtime_t time, gtime_t ts, gtime_t te, double tint, double ttol) {
930 if (ttol <= 0.0) ttol = DTTOL;
931
932 return (tint <= 0.0 || fmod(time2gpst(time, NULL) + ttol, tint) <= ttol * 2.0) &&
933 (ts.time == 0 || timediff(time, ts) >= -ttol) && (te.time == 0 || timediff(time, te) < ttol);
934}
935/* convert observation data --------------------------------------------------*/
936static void convobs(FILE** ofp, rnxopt_t* opt, strfile_t* str, int* n, gtime_t* tend, int* staid) {
937 gtime_t time;
938 int i, j;
939
940 trace(NULL, 3, "convobs :\n");
941
942 if (!ofp[0] || str->obs->n <= 0) return;
943
944 time = str->obs->data[0].time;
945
946 /* avoid duplicated data by multiple files handover */
947 if (tend->time && timediff(time, *tend) < opt->ttol) return;
948 *tend = time;
949
950 /* save cycle slips */
951 save_slips(str, str->obs->data, str->obs->n);
952
953 if (!screent_ttol(time, opt->ts, opt->te, opt->tint, opt->ttol)) return;
954
955 /* restore cycle slips */
956 rest_slips(str, str->obs->data, str->obs->n);
957
958 if (str->staid != *staid) { /* station ID changed */
959
960 if (*staid >= 0) { /* output RINEX event */
961 outrnxevent(ofp[0], opt, str->time, EVENT_NEWSITE, str->stas, str->staid);
962 }
963 *staid = str->staid;
964
965 /* set cycle slips */
966 for (i = 0; i < str->obs->n; i++)
967 for (j = 0; j < NFREQ + NEXOBS; j++) {
968 if (str->obs->data[i].L[j] != 0.0) {
969 str->obs->data[i].LLI[j] |= LLI_SLIP;
970 }
971 }
972 }
973 /* resolve half-cycle ambiguity */
974 if (opt->halfcyc) {
975 resolve_halfc(str, str->obs->data, str->obs->n);
976 }
977 /* output RINEX observation data */
978 outrnxobsb(ofp[0], opt, str->obs->data, str->obs->n, 0);
979
980 if (opt->tstart.time == 0) opt->tstart = time;
981 opt->tend = time;
982
983 n[0]++;
984}
985/* convert navigattion data --------------------------------------------------*/
986static void convnav(FILE** ofp, rnxopt_t* opt, strfile_t* str, int* n) {
987 gtime_t ts;
988 double dtoe;
989 int sat, set, sys, prn, sep_nav = (opt->rnxver <= 299 || opt->sep_nav);
990
991 trace(NULL, 3, "convnav :\n");
992
993 sat = str->ephsat;
994 set = str->ephset;
995 sys = satsys(sat, &prn);
996 if (!(sys & opt->navsys) || opt->exsats[sat - 1]) return;
997
998 switch (sys) {
999 case SYS_GLO:
1000 dtoe = MAXDTOE_GLO;
1001 break;
1002 case SYS_GAL:
1003 dtoe = MAXDTOE_GAL;
1004 break;
1005 case SYS_QZS:
1006 dtoe = MAXDTOE_QZS;
1007 break;
1008 case SYS_CMP:
1009 dtoe = MAXDTOE_CMP;
1010 break;
1011 case SYS_IRN:
1012 dtoe = MAXDTOE_IRN;
1013 break;
1014 case SYS_SBS:
1015 dtoe = MAXDTOE_SBS;
1016 break;
1017 default:
1018 dtoe = MAXDTOE;
1019 break;
1020 }
1021 ts = opt->ts;
1022 if (ts.time != 0) ts = timeadd(ts, -dtoe);
1023 if (!screent(str->time, ts, opt->te, 0.0)) return;
1024
1025 if (sys == SYS_GPS) {
1026 if (ofp[1]) {
1027 outrnxnavb(ofp[1], opt, str->nav->eph + sat - 1 + MAXSAT * set);
1028 n[1]++;
1029 }
1030 } else if (sys == SYS_GLO) {
1031 if (ofp[1] && !sep_nav) {
1032 outrnxgnavb(ofp[1], opt, str->nav->geph + prn - 1);
1033 n[1]++;
1034 } else if (ofp[2] && sep_nav) {
1035 outrnxgnavb(ofp[2], opt, str->nav->geph + prn - 1);
1036 n[2]++;
1037 }
1038 } else if (sys == SYS_SBS) {
1039 if (ofp[1] && !sep_nav) {
1040 outrnxhnavb(ofp[1], opt, str->nav->seph + prn - MINPRNSBS);
1041 n[1]++;
1042 } else if (ofp[3] && sep_nav) {
1043 outrnxhnavb(ofp[3], opt, str->nav->seph + prn - MINPRNSBS);
1044 n[3]++;
1045 }
1046 } else if (sys == SYS_QZS) {
1047 if (ofp[1] && !sep_nav) {
1048 outrnxnavb(ofp[1], opt, str->nav->eph + sat - 1 + MAXSAT * set);
1049 n[1]++;
1050 } else if (ofp[4] && sep_nav) {
1051 outrnxnavb(ofp[4], opt, str->nav->eph + sat - 1 + MAXSAT * set);
1052 n[4]++;
1053 }
1054 } else if (sys == SYS_GAL) {
1055 if (ofp[1] && !sep_nav) {
1056 outrnxnavb(ofp[1], opt, str->nav->eph + sat - 1 + MAXSAT * set);
1057 n[1]++;
1058 } else if (ofp[5] && sep_nav) {
1059 outrnxnavb(ofp[5], opt, str->nav->eph + sat - 1 + MAXSAT * set);
1060 n[5]++;
1061 }
1062 } else if (sys == SYS_CMP) {
1063 if (ofp[1] && !sep_nav) {
1064 outrnxnavb(ofp[1], opt, str->nav->eph + sat - 1 + MAXSAT * set);
1065 n[1]++;
1066 } else if (ofp[6] && sep_nav) {
1067 outrnxnavb(ofp[6], opt, str->nav->eph + sat - 1 + MAXSAT * set);
1068 n[6]++;
1069 }
1070 } else if (sys == SYS_IRN) {
1071 if (ofp[1] && !sep_nav) {
1072 outrnxnavb(ofp[1], opt, str->nav->eph + sat - 1 + MAXSAT * set);
1073 n[1]++;
1074 } else if (ofp[7] && sep_nav) {
1075 outrnxnavb(ofp[7], opt, str->nav->eph + sat - 1 + MAXSAT * set);
1076 n[7]++;
1077 }
1078 }
1079}
1080/* convert SBAS message ------------------------------------------------------*/
1081static void convsbs(FILE** ofp, rnxopt_t* opt, strfile_t* str, int* n, gtime_t* tend) {
1082 gtime_t time;
1083 int prn, sat, sys, sep_nav = opt->rnxver <= 299 || opt->sep_nav;
1084
1085 trace(NULL, 3, "convsbs :\n");
1086
1087 time = gpst2time(str->raw.sbsmsg.week, str->raw.sbsmsg.tow);
1088
1089 if (!screent(time, opt->ts, opt->te, 0.0)) return;
1090
1091 /* avoid duplicated data by multiple files handover */
1092 if (tend->time && timediff(time, *tend) < opt->ttol) return;
1093 *tend = time;
1094
1095 prn = str->raw.sbsmsg.prn;
1096 if (MINPRNSBS <= prn && prn <= MAXPRNSBS) {
1097 sys = SYS_SBS;
1098 } else if (MINPRNQZS_S <= prn && prn <= MAXPRNQZS_S) {
1099 sys = SYS_QZS;
1100 prn += 10;
1101 } else {
1102 trace(NULL, 2, "sbas message satellite error: prn=%d\n", prn);
1103 return;
1104 }
1105 if (!(sat = satno(sys, prn)) || opt->exsats[sat - 1] == 1) return;
1106
1107 /* output SBAS message log */
1108 if (ofp[NOUTFILE - 1]) {
1109 sbsoutmsg(ofp[NOUTFILE - 1], &str->raw.sbsmsg);
1110 n[NOUTFILE - 1]++;
1111 }
1112 /* output SBAS ephemeris */
1113 if ((opt->navsys & SYS_SBS) && sbsupdatecorr(&str->raw.sbsmsg, str->nav) == 9) {
1114 if (ofp[1] && !sep_nav) {
1115 outrnxhnavb(ofp[1], opt, str->nav->seph + prn - MINPRNSBS);
1116 n[1]++;
1117 } else if (ofp[3] && sep_nav) {
1118 outrnxhnavb(ofp[3], opt, str->nav->seph + prn - MINPRNSBS);
1119 n[3]++;
1120 }
1121 }
1122}
1123/* set approx position in RINEX options --------------------------------------*/
1124static void setopt_apppos(strfile_t* str, rnxopt_t* opt) {
1125 prcopt_t prcopt = prcopt_default;
1126 sol_t sol = {{0}};
1127 char msg[128];
1128
1129 prcopt.navsys = opt->navsys;
1130
1131 /* point positioning with last obs data */
1132 if (!pntpos(NULL, str->obs->data, str->obs->n, str->nav, &prcopt, &sol, NULL, NULL, msg)) {
1133 trace(NULL, 2, "point position error (%s)\n", msg);
1134 return;
1135 }
1136 matcpy(opt->apppos, sol.rr, 3, 1);
1137}
1138/* show conversion status ----------------------------------------------------*/
1139static int showstat(int sess, gtime_t ts, gtime_t te, int* n) {
1140 const char type[] = "ONGHQLCISE";
1141 char msg[1024] = "", *p = msg, s[64];
1142 int i;
1143
1144 if (sess > 0) {
1145 p += sprintf(p, "(%d) ", sess);
1146 }
1147 if (ts.time != 0) {
1148 time2str(ts, s, 0);
1149 p += sprintf(p, "%s", s);
1150 }
1151 if (te.time != 0 && timediff(te, ts) > 0.9) {
1152 time2str(te, s, 0);
1153 p += sprintf(p, "-%s", s + 5);
1154 }
1155 p += sprintf(p, ": ");
1156
1157 for (i = 0; i < NOUTFILE + 1; i++) {
1158 if (n[i] == 0) continue;
1159 p += sprintf(p, "%c=%d%s", type[i], n[i], i < NOUTFILE ? " " : "");
1160 }
1161 return showmsg(msg);
1162}
1163/* RINEX converter for single-session ----------------------------------------*/
1164static int convrnx_s(int sess, int format, rnxopt_t* opt, const char* file, char** ofile) {
1165 FILE* ofp[NOUTFILE] = {NULL};
1166 strfile_t* str;
1167 gtime_t tend[3] = {{0}};
1168 int i, j, nf, type, n[NOUTFILE + 1] = {0}, mask[MAXEXFILE] = {0}, staid = -1, abort = 0;
1169 char path[1024], *paths[NOUTFILE], s[NOUTFILE][1024];
1170 char *epath[MAXEXFILE] = {0}, *staname = *opt->staid ? opt->staid : "0000";
1171
1172 trace(NULL, 3,
1173 "convrnx_s: sess=%d format=%d file=%s ofile=%s %s %s %s %s %s %s "
1174 "%s %s\n",
1175 sess, format, file, ofile[0], ofile[1], ofile[2], ofile[3], ofile[4], ofile[5], ofile[6], ofile[7], ofile[8]);
1176
1177 /* replace keywords in input file */
1178 if (reppath(file, path, opt->ts, staname, "") < 0) {
1179 showmsg("no time for input file: %s", file);
1180 return 0;
1181 }
1182 /* expand wild-cards in input file */
1183 for (i = 0; i < MAXEXFILE; i++) {
1184 if (!(epath[i] = (char*)malloc(1024))) {
1185 for (i = 0; i < MAXEXFILE; i++) free(epath[i]);
1186 return 0;
1187 }
1188 }
1189 if ((nf = expath(path, epath, MAXEXFILE)) <= 0) {
1190 showmsg("no input file: %s", path);
1191 for (i = 0; i < MAXEXFILE; i++) free(epath[i]);
1192 return 0;
1193 }
1194 if (!(str = gen_strfile(format, opt->rcvopt))) {
1195 for (i = 0; i < MAXEXFILE; i++) free(epath[i]);
1196 return 0;
1197 }
1198 if (format == STRFMT_RTCM2 || format == STRFMT_RTCM3 || format == STRFMT_RT17) {
1199 str->time = opt->trtcm;
1200 } else if (opt->ts.time) {
1201 str->time = timeadd(opt->ts, -1.0);
1202 }
1203 /* set GLONASS FCN in RINEX options */
1204 for (i = 0; i < MAXPRNGLO; i++) {
1205 str->nav->glo_fcn[i] = opt->glofcn[i]; /* FCN+8 */
1206 }
1207 /* scan input files */
1208 if (!scan_file(epath, nf, opt, str, mask)) {
1209 for (i = 0; i < MAXEXFILE; i++) free(epath[i]);
1210 free_strfile(str);
1211 return 0;
1212 }
1213 /* set format and file in RINEX options comments */
1214 setopt_file(format, epath, nf, mask, opt);
1215
1216 /* replace keywords in output file */
1217 for (i = 0; i < NOUTFILE; i++) {
1218 paths[i] = s[i];
1219 if (reppath(ofile[i], paths[i], opt->ts.time ? opt->ts : str->tstart, staname, "") < 0) {
1220 showmsg("no time for output path: %s", ofile[i]);
1221 for (i = 0; i < MAXEXFILE; i++) free(epath[i]);
1222 free_strfile(str);
1223 return 0;
1224 }
1225 }
1226 /* open output files */
1227 if (!openfile(ofp, paths, path, opt, str->nav)) {
1228 for (i = 0; i < MAXEXFILE; i++) free(epath[i]);
1229 free_strfile(str);
1230 return 0;
1231 }
1232 str->time = str->tstart;
1233
1234 for (i = 0; i < nf && !abort; i++) {
1235 if (!mask[i]) continue;
1236
1237 /* open stream file */
1238 if (!open_strfile(str, epath[i])) continue;
1239
1240 /* input message */
1241 for (j = 0; (type = input_strfile(str)) >= -1; j++) {
1242 if (!(j % 11) && (abort = showstat(sess, str->time, str->time, n))) break;
1243
1244 if (opt->ts.time && timediff(str->time, opt->ts) < -opt->ttol) continue;
1245 if (opt->te.time && timediff(str->time, opt->te) > -opt->ttol) break;
1246
1247 /* convert message */
1248 switch (type) {
1249 case 1:
1250 convobs(ofp, opt, str, n, tend, &staid);
1251 break;
1252 case 2:
1253 convnav(ofp, opt, str, n);
1254 break;
1255 case 3:
1256 convsbs(ofp, opt, str, n, tend + 1);
1257 break;
1258 case -1:
1259 n[NOUTFILE]++;
1260 break; /* error */
1261 }
1262 /* set approx position in rinex option */
1263 if (type == 1 && !opt->autopos && norm(opt->apppos, 3) <= 0.0) {
1264 setopt_apppos(str, opt);
1265 }
1266 }
1267 /* close stream file */
1268 close_strfile(str);
1269 }
1270 /* close output files */
1271 closefile(ofp, opt, str->nav);
1272
1273 /* remove empty output files */
1274 for (i = 0; i < NOUTFILE; i++) {
1275 if (ofp[i] && n[i] <= 0) remove(paths[i]);
1276 }
1277 showstat(sess, opt->tstart, opt->tend, n);
1278
1279 /* unset RINEX options comments */
1280 unsetopt_file(opt);
1281
1282 free_strfile(str);
1283 for (i = 0; i < MAXEXFILE; i++) free(epath[i]);
1284
1285 return abort ? -1 : 1;
1286}
1287/* RINEX converter -------------------------------------------------------------
1288 * convert receiver log file to RINEX obs/nav, SBAS log files
1289 * args : int format I receiver raw format (STRFMT_???)
1290 * rnxopt_t *opt IO RINEX options (see below)
1291 * char *file I RTCM, receiver raw or RINEX file
1292 * (wild-cards (*) are expanded)
1293 * char **ofile IO output files
1294 * ofile[0] RINEX OBS file ("": no output)
1295 * ofile[1] RINEX NAV file ("": no output)
1296 * ofile[2] RINEX GNAV file ("": no output)
1297 * ofile[3] RINEX HNAV file ("": no output)
1298 * ofile[4] RINEX QNAV file ("": no output)
1299 * ofile[5] RINEX LNAV file ("": no output)
1300 * ofile[6] RINEX CNAV file ("": no output)
1301 * ofile[7] RINEX INAV file ("": no output)
1302 * ofile[8] SBAS log file ("": no output)
1303 * return : status (1:ok,0:error,-1:abort)
1304 * notes : the following members of opt are replaced by information in last
1305 * converted RINEX: opt->tstart, opt->tend, opt->obstype, opt->nobs
1306 * keywords in ofile[] are replaced by first observation date/time and
1307 * station ID (%r)
1308 * the order of wild-card expanded files must be in-order by time
1309 *-----------------------------------------------------------------------------*/
1310extern int convrnx(int format, rnxopt_t* opt, const char* file, char** ofile) {
1311 gtime_t t0 = {0};
1312 rnxopt_t opt_ = *opt;
1313 double tu, ts;
1314 int i, week, stat = 1, sys_GRS = SYS_GPS | SYS_GLO | SYS_SBS;
1315
1316 trace(NULL, 3, "convrnx: format=%d file=%s ofile=%s %s %s %s %s %s %s %s %s\n", format, file, ofile[0], ofile[1],
1317 ofile[2], ofile[3], ofile[4], ofile[5], ofile[6], ofile[7], ofile[8]);
1318
1319 showmsg("");
1320
1321 /* disable systems according to RINEX version */
1322 if (opt->rnxver <= 210)
1323 opt_.navsys &= sys_GRS;
1324 else if (opt->rnxver <= 211)
1325 opt_.navsys &= sys_GRS | SYS_GAL;
1326 else if (opt->rnxver <= 212)
1327 opt_.navsys &= sys_GRS | SYS_GAL | SYS_CMP;
1328 else if (opt->rnxver <= 300)
1329 opt_.navsys &= sys_GRS | SYS_GAL;
1330 else if (opt->rnxver <= 301)
1331 opt_.navsys &= sys_GRS | SYS_GAL | SYS_CMP;
1332 else if (opt->rnxver <= 302)
1333 opt_.navsys &= sys_GRS | SYS_GAL | SYS_CMP | SYS_QZS;
1334
1335 /* disable frequency according to RINEX version */
1336 if (opt->rnxver <= 210) opt_.freqtype &= 0x3;
1337
1338 if (opt->ts.time == 0 || opt->te.time == 0 || opt->tunit <= 0.0) {
1339 /* single session */
1340 opt_.tstart = opt_.tend = t0;
1341 stat = convrnx_s(0, format, &opt_, file, ofile);
1342 } else if (timediff(opt->ts, opt->te) < 0.0) {
1343 /* multiple session */
1344 tu = opt->tunit < 86400.0 ? opt->tunit : 86400.0;
1345 ts = tu * (int)floor(time2gpst(opt->ts, &week) / tu);
1346
1347 for (i = 0;; i++) { /* for each session */
1348 opt_.ts = gpst2time(week, ts + i * tu);
1349 opt_.te = timeadd(opt_.ts, tu);
1350 if (opt->trtcm.time) {
1351 opt_.trtcm = timeadd(opt->trtcm, timediff(opt_.ts, opt->ts));
1352 }
1353 if (timediff(opt_.ts, opt->te) > -opt->ttol) break;
1354
1355 if (timediff(opt_.ts, opt->ts) < 0.0) opt_.ts = opt->ts;
1356 if (timediff(opt_.te, opt->te) > 0.0) opt_.te = opt->te;
1357 opt_.tstart = opt_.tend = t0;
1358 if ((stat = convrnx_s(i + 1, format, &opt_, file, ofile)) < 0) break;
1359 }
1360 } else {
1361 showmsg("no period");
1362 return 0;
1363 }
1364 /* output start and end time */
1365 opt->tstart = opt_.tstart;
1366 opt->tend = opt_.tend;
1367
1368 return stat;
1369}
void satno2id(int sat, char *id)
Definition mrtk_nav.c:817
uint8_t obs2code(const char *obs)
Definition mrtk_obs.c:173
char * code2obs(uint8_t code)
Definition mrtk_obs.c:190
static int openfile(FILE **ofp, char *files[], const char *file, const rnxopt_t *opt, const nav_t *nav)
static int scan_file(char **files, int nf, rnxopt_t *opt, strfile_t *str, int *mask)
static int open_strfile(strfile_t *str, const char *file)
static void unsetopt_file(rnxopt_t *opt)
static void setopt_file(int format, char **paths, int n, const int *mask, rnxopt_t *opt)
static strfile_t * gen_strfile(int format, const char *opt)
static void convsbs(FILE **ofp, rnxopt_t *opt, strfile_t *str, int *n, gtime_t *tend)
static const char vercode[][MAXCODE]
struct stas_tag stas_t
static void write_header(FILE **ofp, int idx, const rnxopt_t *opt, const nav_t *nav)
static void save_slips(strfile_t *str, obsd_t *data, int n)
static void closefile(FILE **ofp, const rnxopt_t *opt, nav_t *nav)
struct halfc_tag halfc_t
int convrnx(int format, rnxopt_t *opt, const char *file, char **ofile)
#define NSATSYS
static void convcode(int rnxver, int sys, char *type)
static void setopt_apppos(strfile_t *str, rnxopt_t *opt)
static void dump_stas(const strfile_t *str)
static void convobs(FILE **ofp, rnxopt_t *opt, strfile_t *str, int *n, gtime_t *tend, int *staid)
static const int navsys[]
#define EVENT_NEWSITE
static void setopt_phshift(rnxopt_t *opt)
static int convrnx_s(int sess, int format, rnxopt_t *opt, const char *file, char **ofile)
static int input_strfile(strfile_t *str)
static void setopt_sta(const strfile_t *str, rnxopt_t *opt)
static void close_strfile(strfile_t *str)
#define EVENT_EXTERNAL
static void sort_obstype(uint8_t *codes, uint8_t *types, int n, int sys)
#define EVENT_STARTMOVE
static int add_halfc(strfile_t *str, int sat, int idx, gtime_t time)
static int screent_ttol(gtime_t time, gtime_t ts, gtime_t te, double tint, double ttol)
static void outrnxevent(FILE *fp, const rnxopt_t *opt, gtime_t time, int event, const stas_t *stas, int staid)
static void resolve_halfc(const strfile_t *str, obsd_t *data, int n)
static void free_strfile(strfile_t *str)
static void update_halfc(strfile_t *str, obsd_t *obs)
static void setopt_sta_list(const strfile_t *str, rnxopt_t *opt)
static int showstat(int sess, gtime_t ts, gtime_t te, int *n)
#define NOUTFILE
static void dump_halfc(const strfile_t *str)
static void setopt_obstype(const uint8_t *codes, const uint8_t *types, int sys, rnxopt_t *opt)
static void convnav(FILE **ofp, rnxopt_t *opt, strfile_t *str, int *n)
static void update_stas(strfile_t *str)
static void rest_slips(strfile_t *str, obsd_t *data, int n)
static void update_stainf(strfile_t *str)
#define MAXSAT
Definition mrtk_coords.c:45
void ecef2pos(const double *r, double *pos)
Transform ECEF position to geodetic position.
void ecef2enu(const double *pos, const double *r, double *e)
Transform ECEF vector to local tangential coordinate.
int satsys(int sat, int *prn)
Definition mrtk_nav.c:117
#define SYS_GPS
Definition mrtk_eph.c:65
#define MAXDTOE
Definition mrtk_eph.c:74
#define SYS_SBS
Definition mrtk_eph.c:66
#define SYS_QZS
Definition mrtk_eph.c:69
#define MAXDTOE_IRN
Definition mrtk_eph.c:79
#define MAXDTOE_SBS
Definition mrtk_eph.c:80
#define MAXDTOE_QZS
Definition mrtk_eph.c:75
#define SYS_IRN
Definition mrtk_eph.c:71
#define MAXDTOE_CMP
Definition mrtk_eph.c:77
#define SYS_CMP
Definition mrtk_eph.c:70
#define SYS_GAL
Definition mrtk_eph.c:68
#define SYS_GLO
Definition mrtk_eph.c:67
#define MAXDTOE_GLO
Definition mrtk_eph.c:78
#define MAXDTOE_GAL
Definition mrtk_eph.c:76
struct nav_s nav_t
Definition mrtk_eph.h:40
#define CODE_L5Q
#define CODE_L6C
#define CODE_L1S
#define MAXPRNQZS_S
#define CODE_L7P
#define CODE_L2X
#define CODE_L1L
#define CODE_L2P
#define MINPRNQZS_S
#define MAXCODE
#define CODE_L1C
#define CODE_L2C
#define DTTOL
#define CODE_L8Q
#define CODE_L5P
#define CODE_L3Q
#define CODE_L2S
#define CODE_L7Q
#define CODE_L1W
#define CODE_L1N
#define CODE_L2L
#define CODE_L1P
#define MAXCOMMENT
#define MAXEXFILE
#define MAXPRNGLO
#define CODE_L6Q
#define MAXOBSTYPE
#define CODE_L1X
void matcpy(double *A, const double *B, int n, int m)
Copy matrix.
Definition mrtk_mat.c:205
double norm(const double *a, int n)
Euclidean norm of vector.
Definition mrtk_mat.c:165
int satno(int sys, int prn)
Convert satellite system+prn/slot number to satellite number.
Definition mrtk_nav.c:58
int getcodepri(int sys, uint8_t code, const char *opt)
Get code priority for multiple codes in a frequency.
Definition mrtk_obs.c:276
#define R2D
Definition mrtk_obs.c:51
int code2freq_idx(int sys, uint8_t code)
Convert system and obs code to frequency index (obsdef-based).
Definition mrtk_obs.c:225
int screent(gtime_t time, gtime_t ts, gtime_t te, double tint)
Screen data by time range and interval.
Definition mrtk_obs.c:424
const prcopt_t prcopt_default
Definition mrtk_opt.c:31
static sta_t stas[MAXRCV]
int showmsg(const char *format,...)
#define MAXPRNSBS
#define MINPRNSBS
void free_raw(raw_t *raw)
Free receiver raw data control struct.
int input_rawf(raw_t *raw, rtcm_t *rtcm, int format, FILE *fp)
Input receiver raw data from file.
int init_raw(raw_t *raw, int format)
Initialize receiver raw data control struct.
#define STRFMT_RTCM3
Definition mrtk_rcvraw.h:50
#define STRFMT_RINEX
Definition mrtk_rcvraw.h:62
#define STRFMT_RT17
Definition mrtk_rcvraw.h:60
#define STRFMT_RTCM2
Definition mrtk_rcvraw.h:49
#define LLI_HALFS
Definition mrtk_rinex.c:60
int outrnxobsh(FILE *fp, const rnxopt_t *opt, const nav_t *nav)
Output RINEX observation data file header.
int init_rnxctr(rnxctr_t *rnx)
Initialize RINEX control struct.
#define LLI_HALFC
Definition mrtk_rinex.c:57
int outrnxlnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav)
Output RINEX Galileo navigation data file header.
int outrnxgnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav)
Output RINEX GLONASS navigation data file header.
int outrnxnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav)
Output RINEX navigation data file header.
int open_rnxctr(rnxctr_t *rnx, FILE *fp)
Open RINEX data (read header).
int outrnxqnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav)
Output RINEX QZSS navigation data file header.
#define LLI_SLIP
Definition mrtk_rinex.c:56
#define LLI_HALFA
Definition mrtk_rinex.c:59
int outrnxhnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav)
Output RINEX GEO navigation data file header.
int outrnxnavb(FILE *fp, const rnxopt_t *opt, const eph_t *eph)
Output RINEX navigation data file body.
int outrnxobsb(FILE *fp, const rnxopt_t *opt, const obsd_t *obs, int n, int flag)
Output RINEX observation data body.
int outrnxgnavb(FILE *fp, const rnxopt_t *opt, const geph_t *geph)
Output RINEX GLONASS navigation data file body.
int input_rnxctr(rnxctr_t *rnx, FILE *fp)
Input RINEX control (read next message).
int outrnxinavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav)
Output RINEX NavIC/IRNSS navigation data file header.
int outrnxcnavh(FILE *fp, const rnxopt_t *opt, const nav_t *nav)
Output RINEX BDS navigation data file header.
void free_rnxctr(rnxctr_t *rnx)
Free RINEX control struct buffers.
int outrnxhnavb(FILE *fp, const rnxopt_t *opt, const seph_t *seph)
Output RINEX GEO navigation data file body.
void free_rtcm(rtcm_t *rtcm)
Free RTCM control struct.
Definition mrtk_rtcm.c:118
int input_rtcm3f(rtcm_t *rtcm, FILE *fp)
Input RTCM 3 message from file.
Definition mrtk_rtcm.c:347
int init_rtcm(rtcm_t *rtcm)
Initialize RTCM control struct.
Definition mrtk_rtcm.c:37
int input_rtcm2f(rtcm_t *rtcm, FILE *fp)
Input RTCM 2 message from file.
Definition mrtk_rtcm.c:325
void sbsoutmsg(FILE *fp, sbsmsg_t *sbsmsg)
Output SBAS message record.
Definition mrtk_sbas.c:732
int sbsupdatecorr(const sbsmsg_t *msg, nav_t *nav)
Update SBAS corrections in navigation data.
Definition mrtk_sbas.c:517
int pntpos(mrtk_ctx_t *ctx, const obsd_t *obs, int n, const nav_t *nav, const prcopt_t *opt, sol_t *sol, double *azel, ssat_t *ssat, char *msg)
Compute receiver position, velocity, clock bias by single-point positioning with pseudorange and dopp...
Definition mrtk_spp.c:865
const char * formatstrs[32]
Definition mrtk_stream.c:80
#define MAXRCVFMT
Definition mrtk_stream.h:57
int expath(const char *path, char *paths[], int nmax)
Expand file path with wild-card (*) in file.
Definition mrtk_sys.c:96
void createdir(const char *path)
Create directory if not exists (recursively).
Definition mrtk_sys.c:187
int reppath(const char *path, char *rpath, gtime_t time, const char *rov, const char *base)
Replace keywords in file path with date, time, rover and base station id.
Definition mrtk_sys.c:248
gtime_t gpst2time(int week, double sec)
Convert GPS week/tow to gtime_t.
Definition mrtk_time.c:165
void time2epoch(gtime_t t, double *ep)
Convert gtime_t struct to calendar day/time.
Definition mrtk_time.c:136
void time2str(gtime_t t, char *s, int n)
Convert gtime_t struct to string.
Definition mrtk_time.c:507
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
Definition mrtk_time.c:279
double time2gpst(gtime_t t, int *week)
Convert gtime_t to GPS week/tow.
Definition mrtk_time.c:181
gtime_t timeadd(gtime_t t, double sec)
Add seconds to gtime_t.
Definition mrtk_time.c:265
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
Definition mrtk_time.c:530
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
Definition mrtk_trace.c:78
GPS/GAL/QZS/BDS/IRN broadcast ephemeris type.
Definition mrtk_eph.h:77
GLONASS broadcast ephemeris type.
Definition mrtk_eph.h:111
int sat
Definition mrtk_eph.h:112
int frq
Definition mrtk_eph.h:114
GNSS time representation.
Definition mrtk_time.h:49
time_t time
Definition mrtk_time.h:50
uint8_t stat
gtime_t ts
gtime_t te
struct halfc_tag * next
int ng
Definition mrtk_nav.h:394
int glo_fcn[32]
Definition mrtk_nav.h:426
seph_t * seph
Definition mrtk_nav.h:408
geph_t * geph
Definition mrtk_nav.h:407
eph_t * eph
Definition mrtk_nav.h:400
int ns
Definition mrtk_nav.h:395
int n
Definition mrtk_nav.h:393
Observation data collection.
Definition mrtk_obs.h:59
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
int navsys
Definition mrtk_opt.h:175
Receiver raw data control type.
Definition mrtk_rcvraw.h:78
sbsmsg_t sbsmsg
Definition mrtk_rcvraw.h:87
nav_t nav
Definition mrtk_rcvraw.h:83
int ephset
Definition mrtk_rcvraw.h:86
obs_t obs
Definition mrtk_rcvraw.h:81
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
RINEX control struct type.
Definition mrtk_rinex.h:93
nav_t nav
Definition mrtk_rinex.h:101
char opt[256]
Definition mrtk_rinex.h:105
gtime_t time
Definition mrtk_rinex.h:94
obs_t obs
Definition mrtk_rinex.h:100
sta_t sta
Definition mrtk_rinex.h:102
RINEX options type.
Definition mrtk_rinex.h:49
double tint
Definition mrtk_rinex.h:51
uint8_t exsats[MAXSAT]
Definition mrtk_rinex.h:73
char rcvopt[256]
Definition mrtk_rinex.h:72
char marker[64]
Definition mrtk_rinex.h:62
char staid[32]
Definition mrtk_rinex.h:59
double antdel[3]
Definition mrtk_rinex.h:69
char markerno[32]
Definition mrtk_rinex.h:63
int rnxver
Definition mrtk_rinex.h:54
int freqtype
Definition mrtk_rinex.h:57
char mask[7][MAXCODE]
Definition mrtk_rinex.h:58
int obstype
Definition mrtk_rinex.h:56
int autopos
Definition mrtk_rinex.h:78
int nobs[7]
Definition mrtk_rinex.h:87
int sep_nav
Definition mrtk_rinex.h:81
double shift[7][MAXOBSTYPE]
Definition mrtk_rinex.h:86
double tunit
Definition mrtk_rinex.h:53
int navsys
Definition mrtk_rinex.h:55
gtime_t te
Definition mrtk_rinex.h:50
double apppos[3]
Definition mrtk_rinex.h:68
char rec[3][32]
Definition mrtk_rinex.h:66
int phshift
Definition mrtk_rinex.h:79
int glofcn[32]
Definition mrtk_rinex.h:74
double ttol
Definition mrtk_rinex.h:52
char ant[3][32]
Definition mrtk_rinex.h:67
gtime_t ts
Definition mrtk_rinex.h:50
gtime_t trtcm
Definition mrtk_rinex.h:84
gtime_t tend
Definition mrtk_rinex.h:83
char comment[MAXCOMMENT][64]
Definition mrtk_rinex.h:71
int halfcyc
Definition mrtk_rinex.h:80
gtime_t tstart
Definition mrtk_rinex.h:82
char tobs[7][MAXOBSTYPE][4]
Definition mrtk_rinex.h:85
RTCM control struct type.
Definition mrtk_rtcm.h:50
obs_t obs
Definition mrtk_rtcm.h:57
gtime_t time
Definition mrtk_rtcm.h:55
nav_t nav
Definition mrtk_rtcm.h:58
int staid
Definition mrtk_rtcm.h:51
int ephset
Definition mrtk_rtcm.h:67
char opt[256]
Definition mrtk_rtcm.h:79
int ephsat
Definition mrtk_rtcm.h:66
sta_t sta
Definition mrtk_rtcm.h:59
int tow
Definition mrtk_nav.h:102
uint8_t prn
Definition mrtk_nav.h:103
int week
Definition mrtk_nav.h:102
SBAS ephemeris type.
Definition mrtk_eph.h:130
double rr[6]
Definition mrtk_sol.h:46
double pos[3]
Definition mrtk_nav.h:380
char antsno[MAXANT]
Definition mrtk_nav.h:373
char recsno[MAXANT]
Definition mrtk_nav.h:376
int deltype
Definition mrtk_nav.h:379
char recver[MAXANT]
Definition mrtk_nav.h:375
double hgt
Definition mrtk_nav.h:382
double del[3]
Definition mrtk_nav.h:381
char rectype[MAXANT]
Definition mrtk_nav.h:374
char name[MAXANT]
Definition mrtk_nav.h:370
int antsetup
Definition mrtk_nav.h:377
char marker[MAXANT]
Definition mrtk_nav.h:371
char antdes[MAXANT]
Definition mrtk_nav.h:372
sta_t sta
gtime_t ts
gtime_t te
struct stas_tag * next
rtcm_t rtcm
gtime_t time
halfc_t * halfc[MAXSAT][5+5]
uint8_t slips[MAXSAT][5+5]
stas_t * stas
nav_t * nav
gtime_t tstart
obs_t * obs
FILE * fp
sta_t * sta
rnxctr_t rnx
#define malloc(x)
Definition toml.c:52
#define calloc(x, y)
Definition toml.c:54
#define free(x)
Definition toml.c:53