MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_options.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_options.c : option string processing functions
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/* mrtklib modular headers */
18
19#include <ctype.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "mrtklib/mrtk_coords.h"
25#include "mrtklib/mrtk_nav.h"
26#include "mrtklib/mrtk_obs.h"
27#include "mrtklib/mrtk_toml.h"
28#include "mrtklib/mrtk_trace.h"
29
30/* local constants (duplicated from rtklib.h to avoid rtklib.h dependency) ----*/
31#define D2R (3.1415926535897932384626433832795 / 180.0)
32#define R2D (180.0 / 3.1415926535897932384626433832795)
33
34/* forward declarations for functions still in legacy rtkcmn.c ----------------*/
35
36/* system options buffer -----------------------------------------------------*/
40static int antpostype_[2];
42static double antpos_[2][3];
43static char exsats_[1024];
44static char snrmask_[NFREQ][1024];
45static char signals_[1024];
46static int bds2prn_given_; /* pos2-bds2prn was read from a configuration */
47
48/* system options table ------------------------------------------------------*/
49#define SWTOPT "0:off,1:on"
50#define ISBOPT "0:off,1:table,1:on"
51#define SEEDOPT "0:off,1:cn0+tdcp,2:cn0+tdcp+robust"
52#define MODOPT \
53 "0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed,9:ppp-rtk,10:" \
54 "ssr2osr,11:ssr2osr-fixed,12:vrs-rtk"
55#define FRQOPT "1:l1,2:l1+2,2:l1+l2,3:l1+2+3,3:l1+l2+l5,4:l1+2+3+4,4:l1+l2+l5+l6,5:l1+2+3+4+5,5:l1+l2+l5+l6+l7"
56#define FRQOPT2 "1:l1,2:l1+l2,3:l1+l5,4:l1+l2+l5,5:l1+l5(l2)"
57#define TYPOPT "0:forward,1:backward,2:combined"
58#define IONOPT "0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc,9:est-adaptive"
59#define TRPOPT "0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad"
60#define EPHOPT "0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom"
61#define ROBOPT "0:off,1:igg3"
62#define NAVOPT "1:gps+2:sbas+4:glo+8:gal+16:qzs+32:bds+64:navic"
63#define GAROPT "0:off,1:on"
64#define SOLOPT "0:llh,1:xyz,2:enu,3:nmea"
65#define TSYOPT "0:gpst,1:utc,2:jst"
66#define TFTOPT "0:tow,1:hms"
67#define DFTOPT "0:deg,1:dms"
68#define HGTOPT "0:ellipsoidal,1:geodetic"
69#define GEOOPT "0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000"
70#define STAOPT "0:all,1:single"
71#define STSOPT "0:off,1:state,2:residual"
72#define ARMOPT "0:off,1:continuous,2:instantaneous,3:fix-and-hold"
73#define POSOPT "0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw"
74#define TIDEOPT "0:off,1:on,2:otl,3:solid+otl-clasgrid+pole"
75#define PHWOPT "0:off,1:on,2:precise"
76#define SIGOPT1 "0:L1/L2,1:L1/L5,2:L1/L2/L5"
77#define SIGOPT2 "0:L1/L5,1:L1/L2,2:L1/L5/L2"
78#define SIGOPT3 "0:E1/E5a,1:E1/E5b,2:E1/E6,3:E1/E5a/E5b/E6,4:E1/E5a/E6/E5b"
79#define SIGOPT4 "0:B1I/B3I,1:B1I/B2I,2:B1I/B3I/B2I"
80#define SIGOPT5 "0:B1I/B3I,1:B1I/B2a,2:B1I/B3I/B2a"
81#define COMOPT "0:off,1:ssr,2:meas"
82#define ARALPHAOPT "0:0.1%,1:0.5%,2:1%,3:5%,4:10%,5:20%"
83#define PSHFTOPT "0:off,1:table"
84#define DOPOPT "0:zd,1:sd"
85#define SATCB "0:auto,1:ssr,2:bia,3:dcb"
86#define SATPB "0:auto,1:ssr,2:bia,3:fcb"
87#define CORROPT "-1:auto,0:none,1:igs,2:igs-rts,3:qzs-madoca,4:gal-has,5:bds-b2b,6:qzs-clas"
88#define BDS2OPT "satid(C01-C18),.. BDS-2 in PRN 1-18 (\"\":no BDS-2)"
89#define IGSOOPT "satid,.. BDS-3 IGSO (\"\":C06-C08)"
91 {"pos1-posmode", 3, (void*)&prcopt_.mode, MODOPT},
92 {"pos1-correction", 3, (void*)&prcopt_.correction, CORROPT},
93 {"pos1-frequency", 3, (void*)&prcopt_.nf, FRQOPT},
94 {"pos1-soltype", 3, (void*)&prcopt_.soltype, TYPOPT},
95 {"pos1-elmask", 1, (void*)&elmask_, "deg"},
96 {"pos1-snrmask_r", 3, (void*)&prcopt_.snrmask.ena[0], SWTOPT},
97 {"pos1-snrmask_b", 3, (void*)&prcopt_.snrmask.ena[1], SWTOPT},
98 {"pos1-snrmask_L1", 2, (void*)snrmask_[0], ""},
99 {"pos1-snrmask_L2", 2, (void*)snrmask_[1], ""},
100 {"pos1-snrmask_L5", 2, (void*)snrmask_[2], ""},
101 {"pos1-dynamics", 3, (void*)&prcopt_.dynamics, SWTOPT},
102 {"pos1-tidecorr", 3, (void*)&prcopt_.tidecorr, TIDEOPT},
103 {"pos1-ionoopt", 3, (void*)&prcopt_.ionoopt, IONOPT},
104 {"pos1-tropopt", 3, (void*)&prcopt_.tropopt, TRPOPT},
105 {"pos1-robust", 3, (void*)&prcopt_.robust, ROBOPT},
106 {"pos1-robustk0", 1, (void*)&prcopt_.robustk[0], ""},
107 {"pos1-robustk1", 1, (void*)&prcopt_.robustk[1], ""},
108 {"pos1-tdcp", 3, (void*)&prcopt_.tdcp, SWTOPT},
109 {"pos1-tdcpjump", 1, (void*)&prcopt_.tdcpjump, "m"},
110 {"pos1-seedenh", 3, (void*)&prcopt_.enhanced_spp_seed, SEEDOPT},
111 {"pos1-sateph", 3, (void*)&prcopt_.sateph, EPHOPT},
112 {"pos1-posopt1", 3, (void*)&prcopt_.posopt[0], SWTOPT},
113 {"pos1-posopt2", 3, (void*)&prcopt_.posopt[1], SWTOPT},
114 {"pos1-posopt3", 3, (void*)&prcopt_.posopt[2], PHWOPT},
115 {"pos1-posopt4", 3, (void*)&prcopt_.posopt[3], SWTOPT},
116 {"pos1-posopt5", 3, (void*)&prcopt_.posopt[4], SWTOPT},
117 {"pos1-posopt6", 3, (void*)&prcopt_.posopt[5], COMOPT},
118 {"pos1-exclsats", 2, (void*)exsats_, "prn ..."},
119 {"pos1-navsys", 0, (void*)&prcopt_.navsys, NAVOPT},
120 {"pos1-posopt7", 3, (void*)&prcopt_.posopt[6], SWTOPT}, /* partial AR */
121 {"pos1-posopt8", 3, (void*)&prcopt_.posopt[7], SWTOPT}, /* shapiro time delay */
122 {"pos1-posopt9", 3, (void*)&prcopt_.posopt[8], SWTOPT}, /* exclude QZS as refsat */
123 {"pos1-posopt10", 3, (void*)&prcopt_.posopt[9], SWTOPT}, /* don't adjust phase bias */
124 {"pos1-posopt11", 3, (void*)&prcopt_.posopt[10], FRQOPT2}, /* gps freq (l1+l2/l1+l5) */
125 {"pos1-posopt12", 0, (void*)&prcopt_.posopt[11], "dB-Hz"}, /* snr_fixed (dB-Hz, 0=elev model) */
126 {"pos1-posopt13", 3, (void*)&prcopt_.posopt[12], FRQOPT2}, /* qzs freq (l1+l2/l1+l5) */
127 {"pos1-gridsel", 0, (void*)&prcopt_.gridsel, "m"},
128 {"pos1-rectype", 2, (void*)prcopt_.rectype[0], ""},
129 {"pos1-signals", 2, (void*)signals_, ""},
130
131 {"pos2-armode", 3, (void*)&prcopt_.modear, ARMOPT},
132 {"pos2-gloarmode", 3, (void*)&prcopt_.glomodear, GAROPT},
133 {"pos2-bdsarmode", 3, (void*)&prcopt_.bdsmodear, SWTOPT},
134 {"pos2-arsys", 0, (void*)&prcopt_.arsys, NAVOPT},
135 {"pos2-arthres", 1, (void*)&prcopt_.thresar[0], ""},
136 {"pos2-arthres1", 1, (void*)&prcopt_.thresar[1], ""},
137 {"pos2-arthres2", 1, (void*)&prcopt_.thresar[2], ""},
138 {"pos2-arthres3", 1, (void*)&prcopt_.thresar[3], ""},
139 {"pos2-arthres4", 1, (void*)&prcopt_.thresar[4], ""},
140 {"pos2-arlockcnt", 0, (void*)&prcopt_.minlock, ""},
141 {"pos2-arelmask", 1, (void*)&elmaskar_, "deg"},
142 {"pos2-arminfix", 0, (void*)&prcopt_.minfix, ""},
143 {"pos2-armaxiter", 0, (void*)&prcopt_.armaxiter, ""},
144 {"pos2-elmaskhold", 1, (void*)&elmaskhold_, "deg"},
145 {"pos2-aroutcnt", 0, (void*)&prcopt_.maxout, ""},
146 {"pos2-maxage", 1, (void*)&prcopt_.maxtdiff, "s"},
147 {"pos2-syncsol", 3, (void*)&prcopt_.syncsol, SWTOPT},
148 {"pos2-slipthres", 1, (void*)&prcopt_.thresslip, "m"},
149 {"pos2-thresdop", 1, (void*)&prcopt_.thresdop, "cyc/s"},
150 {"pos2-rejethres", 1, (void*)&prcopt_.rejethres, "m"},
151 {"pos2-rejeminsat", 0, (void*)&prcopt_.rejeminsat, ""},
152 {"pos2-rejionno", 1, (void*)&prcopt_.maxinno, "m"},
153 {"pos2-rejgdop", 1, (void*)&prcopt_.maxgdop, ""},
154 {"pos2-niter", 0, (void*)&prcopt_.niter, ""},
155 {"pos2-baselen", 1, (void*)&prcopt_.baseline[0], "m"},
156 {"pos2-basesig", 1, (void*)&prcopt_.baseline[1], "m"},
157 {"pos2-siggps", 3, (void*)&prcopt_.pppsig[0], SIGOPT1},
158 {"pos2-sigqzs", 3, (void*)&prcopt_.pppsig[1], SIGOPT2},
159 {"pos2-siggal", 3, (void*)&prcopt_.pppsig[2], SIGOPT3},
160 {"pos2-sigbds2", 3, (void*)&prcopt_.pppsig[3], SIGOPT4},
161 {"pos2-sigbds3", 3, (void*)&prcopt_.pppsig[4], SIGOPT5},
162 {"pos2-ionocorr", 3, (void*)&prcopt_.ionocorr, SWTOPT},
163 {"pos2-ign_chierr", 3, (void*)&prcopt_.ign_chierr, SWTOPT},
164 {"pos2-bds2bias", 3, (void*)&prcopt_.bds2bias, SWTOPT},
165 {"pos2-bds2prn", 2, (void*)prcopt_.bds2prn, BDS2OPT},
166 {"pos2-bds3igso", 2, (void*)prcopt_.bds3igso, IGSOOPT},
167 {"pos2-pppsatcb", 0, (void*)&prcopt_.pppsatcb, SATCB},
168 {"pos2-pppsatpb", 0, (void*)&prcopt_.pppsatpb, SATPB},
169 {"pos2-uncorrbias", 3, (void*)&prcopt_.unbias, SWTOPT},
170 {"pos2-clkjump", 3, (void*)&prcopt_.clockjump, SWTOPT},
171 {"pos2-maxbiasdt", 0, (void*)&prcopt_.maxbiasdt, "s"},
172 {"pos2-sattmode", 0, (void*)&prcopt_.sattmode, ""},
173 {"pos2-qzsarmode", 3, (void*)&prcopt_.qzsmodear, SWTOPT},
174 {"pos2-aralpha", 3, (void*)&prcopt_.alphaar, ARALPHAOPT},
175 {"pos2-arminamb", 0, (void*)&prcopt_.minamb, ""},
176 {"pos2-maxpdopar", 1, (void*)&prcopt_.maxpdopar, ""},
177 {"pos2-maxpdophold", 1, (void*)&prcopt_.maxpdophold, ""},
178 {"pos2-refdop", 3, (void*)&prcopt_.refdop, DOPOPT},
179 {"pos2-armaxdelsat", 0, (void*)&prcopt_.armaxdelsat, ""},
180 {"pos2-varholdamb", 1, (void*)&prcopt_.varholdamb, "cyc^2"},
181 {"pos2-arthres5", 1, (void*)&prcopt_.thresar[5], ""},
182 {"pos2-arthres6", 1, (void*)&prcopt_.thresar[6], ""},
183 {"pos2-arminfixsats", 0, (void*)&prcopt_.minfixsats, ""},
184 {"pos2-armindropsats", 0, (void*)&prcopt_.mindropsats, ""},
185 {"pos2-arminholdsats", 0, (void*)&prcopt_.minholdsats, ""},
186 {"pos2-arfilter", 3, (void*)&prcopt_.arfilter, SWTOPT},
187 {"pos2-gpsarmode", 3, (void*)&prcopt_.gpsmodear, SWTOPT},
188 {"pos2-rejionno1", 1, (void*)&prcopt_.maxinno_ext[0], "sigma"},
189 {"pos2-rejionno2", 1, (void*)&prcopt_.maxinno_ext[1], "sigma"},
190 {"pos2-rejionno3", 1, (void*)&prcopt_.maxinno_ext[2], "sigma"},
191 {"pos2-rejionno4", 1, (void*)&prcopt_.maxinno_ext[3], ""},
192 {"pos2-rejionno5", 1, (void*)&prcopt_.maxinno_ext[4], ""},
193 {"pos2-rejdiffpse", 1, (void*)&prcopt_.maxdiffp, "m"},
194 {"pos2-poserrcnt", 0, (void*)&prcopt_.poserrcnt, "cnt"},
195 {"pos2-forgetion", 1, (void*)&prcopt_.forgetion, ""},
196 {"pos2-afgainion", 1, (void*)&prcopt_.afgainion, ""},
197 {"pos2-prnadpt", 3, (void*)&prcopt_.prnadpt, SWTOPT},
198 {"pos2-forgetpva", 1, (void*)&prcopt_.forgetpva, ""},
199 {"pos2-afgainpva", 1, (void*)&prcopt_.afgainpva, ""},
200 {"pos2-phasshft", 3, (void*)&prcopt_.phasshft, PSHFTOPT},
201 {"pos2-rectype", 2, (void*)prcopt_.rectype[1], ""},
202 {"pos2-isb", 3, (void*)&prcopt_.isb, ISBOPT},
203
204 {"out-solformat", 3, (void*)&solopt_.posf, SOLOPT},
205 {"out-outhead", 3, (void*)&solopt_.outhead, SWTOPT},
206 {"out-outopt", 3, (void*)&solopt_.outopt, SWTOPT},
207 {"out-outvel", 3, (void*)&solopt_.outvel, SWTOPT},
208 {"out-timesys", 3, (void*)&solopt_.times, TSYOPT},
209 {"out-timeform", 3, (void*)&solopt_.timef, TFTOPT},
210 {"out-timendec", 0, (void*)&solopt_.timeu, ""},
211 {"out-degform", 3, (void*)&solopt_.degf, DFTOPT},
212 {"out-fieldsep", 2, (void*)solopt_.sep, ""},
213 {"out-outsingle", 3, (void*)&prcopt_.outsingle, SWTOPT},
214 {"out-maxsolstd", 1, (void*)&solopt_.maxsolstd, "m"},
215 {"out-height", 3, (void*)&solopt_.height, HGTOPT},
216 {"out-geoid", 3, (void*)&solopt_.geoid, GEOOPT},
217 {"out-solstatic", 3, (void*)&solopt_.solstatic, STAOPT},
218 {"out-nmeaintv1", 1, (void*)&solopt_.nmeaintv[0], "s"},
219 {"out-nmeaintv2", 1, (void*)&solopt_.nmeaintv[1], "s"},
220 {"out-outstat", 3, (void*)&solopt_.sstat, STSOPT},
221
222 {"stats-eratio1", 1, (void*)&prcopt_.eratio[0], ""},
223 {"stats-eratio2", 1, (void*)&prcopt_.eratio[1], ""},
224 {"stats-eratio3", 1, (void*)&prcopt_.eratio[2], ""},
225 {"stats-errphase", 1, (void*)&prcopt_.err[1], "m"},
226 {"stats-errphaseel", 1, (void*)&prcopt_.err[2], "m"},
227 {"stats-errphasebl", 1, (void*)&prcopt_.err[3], "m/10km"},
228 {"stats-errdoppler", 1, (void*)&prcopt_.err[4], "Hz"},
229 {"stats-snrmax", 1, (void*)&prcopt_.err[5], "dBHz"},
230 {"stats-errsnr", 1, (void*)&prcopt_.err[6], "m"},
231 {"stats-erriono", 1, (void*)&prcopt_.stats_erriono, "m"},
232 {"stats-errtrop", 1, (void*)&prcopt_.stats_errtrop, "m"},
233 {"stats-stdbias", 1, (void*)&prcopt_.std[0], "m"},
234 {"stats-stdiono", 1, (void*)&prcopt_.std[1], "m"},
235 {"stats-stdtrop", 1, (void*)&prcopt_.std[2], "m"},
236 {"stats-prnaccelh", 1, (void*)&prcopt_.prn[3], "m/s^2"},
237 {"stats-prnaccelv", 1, (void*)&prcopt_.prn[4], "m/s^2"},
238 {"stats-prnbias", 1, (void*)&prcopt_.prn[0], "m"},
239 {"stats-prniono", 1, (void*)&prcopt_.prn[1], "m"},
240 {"stats-prntrop", 1, (void*)&prcopt_.prn[2], "m"},
241 {"stats-prnpos", 1, (void*)&prcopt_.prn[5], "m"},
242 {"stats-prnifb", 1, (void*)&prcopt_.prn[6], "m"},
243 {"stats-prndcb", 1, (void*)&prcopt_.prn[6], "m"}, /* alias for prnifb (legacy name) */
244 {"stats-uraratio", 1, (void*)&prcopt_.uraratio, ""},
245 {"stats-clkstab", 1, (void*)&prcopt_.sclkstab, "s/s"},
246 {"stats-prnionomax", 1, (void*)&prcopt_.prnionomax, "m"},
247 {"stats-prnposith", 1, (void*)&prcopt_.stats_prnposith, "m"},
248 {"stats-prnpositv", 1, (void*)&prcopt_.stats_prnpositv, "m"},
249 {"stats-tconstiono", 1, (void*)&prcopt_.stats_tconstiono, "s"},
250
251 {"ant1-postype", 3, (void*)&antpostype_[0], POSOPT},
252 {"ant1-pos1", 1, (void*)&antpos_[0][0], "deg|m"},
253 {"ant1-pos2", 1, (void*)&antpos_[0][1], "deg|m"},
254 {"ant1-pos3", 1, (void*)&antpos_[0][2], "m|m"},
255 {"ant1-anttype", 2, (void*)prcopt_.anttype[0], ""},
256 {"ant1-antdele", 1, (void*)&prcopt_.antdel[0][0], "m"},
257 {"ant1-antdeln", 1, (void*)&prcopt_.antdel[0][1], "m"},
258 {"ant1-antdelu", 1, (void*)&prcopt_.antdel[0][2], "m"},
259
260 {"ant2-postype", 3, (void*)&antpostype_[1], POSOPT},
261 {"ant2-pos1", 1, (void*)&antpos_[1][0], "deg|m"},
262 {"ant2-pos2", 1, (void*)&antpos_[1][1], "deg|m"},
263 {"ant2-pos3", 1, (void*)&antpos_[1][2], "m|m"},
264 {"ant2-anttype", 2, (void*)prcopt_.anttype[1], ""},
265 {"ant2-antdele", 1, (void*)&prcopt_.antdel[1][0], "m"},
266 {"ant2-antdeln", 1, (void*)&prcopt_.antdel[1][1], "m"},
267 {"ant2-antdelu", 1, (void*)&prcopt_.antdel[1][2], "m"},
268 {"ant2-maxaveep", 0, (void*)&prcopt_.maxaveep, ""},
269 {"ant2-initrst", 3, (void*)&prcopt_.initrst, SWTOPT},
270
271 {"misc-timeinterp", 3, (void*)&prcopt_.intpref, SWTOPT},
272 {"misc-sbasatsel", 0, (void*)&prcopt_.sbassatsel, "0:all"},
273 {"misc-rnxopt1", 2, (void*)prcopt_.rnxopt[0], ""},
274 {"misc-rnxopt2", 2, (void*)prcopt_.rnxopt[1], ""},
275 {"misc-pppopt", 2, (void*)prcopt_.pppopt, ""},
276 {"misc-maxobsloss", 1, (void*)&prcopt_.maxobsloss_s, "s"},
277 {"misc-floatcnt", 0, (void*)&prcopt_.floatcnt, "epoch"},
278 {"misc-rtcmopt", 2, (void*)&prcopt_.rtcmopt, ""},
279 {"misc-l6mrg", 0, (void*)&prcopt_.l6mrg, ""},
280 {"misc-regularly", 0, (void*)&prcopt_.regularly, ""},
281
282 {"file-satantfile", 2, (void*)&filopt_.satantp, ""},
283 {"file-rcvantfile", 2, (void*)&filopt_.rcvantp, ""},
284 {"file-staposfile", 2, (void*)&filopt_.stapos, ""},
285 {"file-geoidfile", 2, (void*)&filopt_.geoid, ""},
286 {"file-ionofile", 2, (void*)&filopt_.iono, ""},
287 {"file-dcbfile", 2, (void*)&filopt_.dcb, ""},
288 {"file-eopfile", 2, (void*)&filopt_.eop, ""},
289 {"file-blqfile", 2, (void*)&filopt_.blq, ""},
290 {"file-elmaskfile", 2, (void*)&filopt_.elmask, ""},
291 {"file-tempdir", 2, (void*)&filopt_.tempdir, ""},
292 {"file-geexefile", 2, (void*)&filopt_.geexe, ""},
293 {"file-solstatfile", 2, (void*)&filopt_.solstat, ""},
294 {"file-tracefile", 2, (void*)&filopt_.trace, ""},
295 {"file-fcbfile", 2, (void*)&filopt_.fcb, ""},
296 {"file-biafile", 2, (void*)&filopt_.bia, ""},
297 {"file-cssrgridfile", 2, (void*)&filopt_.grid, ""},
298 {"file-isbfile", 2, (void*)&filopt_.isb, ""},
299 {"file-phacycfile", 2, (void*)&filopt_.phacyc, ""},
300
301 {"", 0, NULL, ""} /* terminator */
302};
303/* discard space characters at tail ------------------------------------------*/
304static void chop(char* str) {
305 char* p;
306 if ((p = strchr(str, '#'))) {
307 *p = '\0'; /* comment */
308 }
309 for (p = str + strlen(str) - 1; p >= str && !isgraph((int)*p); p--) {
310 *p = '\0';
311 }
312}
313/* enum to string ------------------------------------------------------------*/
314static int enum2str(char* s, const char* comment, int val) {
315 char str[32], *p, *q;
316 int n;
317
318 n = sprintf(str, "%d:", val);
319 if (!(p = strstr(comment, str))) {
320 return sprintf(s, "%d", val);
321 }
322 if (!(q = strchr(p + n, ',')) && !(q = strchr(p + n, ')'))) {
323 strcpy(s, p + n);
324 return (int)strlen(p + n);
325 }
326 strncpy(s, p + n, q - p - n);
327 s[q - p - n] = '\0';
328 return (int)(q - p - n);
329}
330/* string to enum ------------------------------------------------------------*/
331static int str2enum(const char* str, const char* comment, int* val) {
332 const char* p;
333 char s[32];
334
335 for (p = comment;; p++) {
336 if (!(p = strstr(p, str))) {
337 break;
338 }
339 if (p <= comment || *(p - 1) != ':') {
340 continue;
341 }
342 for (p -= 2; p >= comment && '0' <= *p && *p <= '9'; p--) {
343 /* find start of numeric id */
344 }
345 /* include a leading '-' so signed ids (e.g. "-1:auto") parse correctly */
346 if (p >= comment && *p == '-') {
347 return sscanf(p, "%d", val) == 1;
348 }
349 return sscanf(p + 1, "%d", val) == 1;
350 }
351 sprintf(s, "%.30s:", str);
352 if ((p = strstr(comment, s))) { /* number */
353 return sscanf(p, "%d", val) == 1;
354 }
355 return 0;
356}
357/* search option ---------------------------------------------------------------
358 * search option record
359 * args : char *name I option name
360 * opt_t *opts I options table
361 * (terminated with table[i].name="")
362 * return : option record (NULL: not found)
363 *-----------------------------------------------------------------------------*/
364extern opt_t* searchopt(const char* name, const opt_t* opts) {
365 int i;
366
367 trace(NULL, 3, "searchopt: name=%s\n", name);
368
369 for (i = 0; *opts[i].name; i++) {
370 if (strstr(opts[i].name, name)) {
371 return (opt_t*)(opts + i);
372 }
373 }
374 return NULL;
375}
376/* string to option value ------------------------------------------------------
377 * convert string to option value
378 * args : opt_t *opt O option
379 * char *str I option value string
380 * return : status (1:ok,0:error)
381 *-----------------------------------------------------------------------------*/
382extern int str2opt(opt_t* opt, const char* str) {
383 /* the TOML loader passes values up to 2047 bytes; these lists are 256 */
384 if ((opt->var == (void*)prcopt_.bds2prn && strlen(str) >= sizeof(prcopt_.bds2prn)) ||
385 (opt->var == (void*)prcopt_.bds3igso && strlen(str) >= sizeof(prcopt_.bds3igso))) {
386 return 0;
387 }
388 if (opt->var == (void*)prcopt_.bds2prn) {
389 bds2prn_given_ = 1; /* an explicit "" (no BDS-2) is still a setting */
390 }
391 switch (opt->format) {
392 case 0:
393 *(int*)opt->var = atoi(str);
394 break;
395 case 1:
396 *(double*)opt->var = atof(str);
397 break;
398 case 2:
399 strcpy((char*)opt->var, str);
400 break;
401 case 3:
402 return str2enum(str, opt->comment, (int*)opt->var);
403 default:
404 return 0;
405 }
406 return 1;
407}
408/* option value to string ------------------------------------------------------
409 * convert option value to string
410 * args : opt_t *opt I option
411 * char *str O option value string
412 * return : length of output string
413 *-----------------------------------------------------------------------------*/
414extern int opt2str(const opt_t* opt, char* str) {
415 char* p = str;
416
417 trace(NULL, 3, "opt2str : name=%s\n", opt->name);
418
419 switch (opt->format) {
420 case 0:
421 p += sprintf(p, "%d", *(int*)opt->var);
422 break;
423 case 1:
424 p += sprintf(p, "%.15g", *(double*)opt->var);
425 break;
426 case 2:
427 p += sprintf(p, "%s", (char*)opt->var);
428 break;
429 case 3:
430 p += enum2str(p, opt->comment, *(int*)opt->var);
431 break;
432 }
433 return (int)(p - str);
434}
435/* option to string -------------------------------------------------------------
436 * convert option to string (keyword=value # comment)
437 * args : opt_t *opt I option
438 * char *buff O option string
439 * return : length of output string
440 *-----------------------------------------------------------------------------*/
441extern int opt2buf(const opt_t* opt, char* buff) {
442 char* p = buff;
443 int n;
444
445 trace(NULL, 3, "opt2buf : name=%s\n", opt->name);
446
447 p += sprintf(p, "%-18s =", opt->name);
448 p += opt2str(opt, p);
449 if (*opt->comment) {
450 if ((n = (int)(buff + 30 - p)) > 0) {
451 p += sprintf(p, "%*s", n, "");
452 }
453 p += sprintf(p, " # (%s)", opt->comment);
454 }
455 return (int)(p - buff);
456}
457/* load options ----------------------------------------------------------------
458 * load options from file
459 * args : char *file I options file
460 * opt_t *opts IO options table
461 * (terminated with table[i].name="")
462 * return : status (1:ok,0:error)
463 *-----------------------------------------------------------------------------*/
464extern int loadopts(const char* file, opt_t* opts) {
465 FILE* fp;
466 opt_t* opt;
467 char buff[2048], *p;
468 int n = 0;
469 const char* ext;
470
471 trace(NULL, 3, "loadopts: file=%s\n", file);
472
473 /* detect .toml extension → use TOML loader */
474 ext = strrchr(file, '.');
475 if (ext && strcmp(ext, ".toml") == 0) {
476 return loadopts_toml(file, opts);
477 }
478
479 /* legacy .conf key=value parser */
480 if (!(fp = fopen(file, "r"))) {
481 trace(NULL, 1, "loadopts: options file open error (%s)\n", file);
482 return 0;
483 }
484 while (fgets(buff, sizeof(buff), fp)) {
485 n++;
486 chop(buff);
487
488 if (buff[0] == '\0') {
489 continue;
490 }
491
492 if (!(p = strstr(buff, "="))) {
493 fprintf(stderr, "invalid option %s (%s:%d)\n", buff, file, n);
494 continue;
495 }
496 *p++ = '\0';
497 while (*p == ' ' || *p == '\t') {
498 p++; /* skip leading whitespace in value */
499 }
500 chop(buff);
501 if (!(opt = searchopt(buff, opts))) {
502 continue;
503 }
504
505 if (!str2opt(opt, p)) {
506 fprintf(stderr, "invalid option value %s (%s:%d)\n", buff, file, n);
507 continue;
508 }
509 }
510 fclose(fp);
511
512 return 1;
513}
514/* save options to file --------------------------------------------------------
515 * save options to file
516 * args : char *file I options file
517 * char *mode I write mode ("w":overwrite,"a":append);
518 * char *comment I header comment (NULL: no comment)
519 * opt_t *opts I options table
520 * (terminated with table[i].name="")
521 * return : status (1:ok,0:error)
522 *-----------------------------------------------------------------------------*/
523extern int saveopts(const char* file, const char* mode, const char* comment, const opt_t* opts) {
524 FILE* fp;
525 char buff[2048];
526 const char* ext;
527 int i;
528
529 trace(NULL, 3, "saveopts: file=%s mode=%s\n", file, mode);
530
531 /* detect .toml extension — TOML save does not support append mode. Report
532 * it as an error: a skipped append left the file without these options
533 * while the caller reported success (#342) */
534 ext = strrchr(file, '.');
535 if (ext && strcmp(ext, ".toml") == 0) {
536 if (mode && strcmp(mode, "a") == 0) {
537 trace(NULL, 1, "saveopts: TOML append not supported (%s)\n", file);
538 return 0;
539 }
540 return saveopts_toml(file, comment, opts);
541 }
542
543 if (!(fp = fopen(file, mode))) {
544 trace(NULL, 1, "saveopts: options file open error (%s)\n", file);
545 return 0;
546 }
547 if (comment) {
548 fprintf(fp, "# %s\n\n", comment);
549 }
550
551 for (i = 0; *opts[i].name; i++) {
552 opt2buf(opts + i, buff);
553 fprintf(fp, "%s\n", buff);
554 }
555 fclose(fp);
556 return 1;
557}
558/* system options buffer to options ------------------------------------------*/
559static void buff2sysopts(void) {
560 double pos[3], *rr;
561 char buff[1024], *p, *id;
562 int i, j, sat, *ps;
563
564 prcopt_.elmin = elmask_ * D2R;
565 prcopt_.elmaskar = elmaskar_ * D2R;
566 prcopt_.elmaskhold = elmaskhold_ * D2R;
567
568 for (i = 0; i < 2; i++) {
569 ps = i == 0 ? &prcopt_.rovpos : &prcopt_.refpos;
570 rr = i == 0 ? prcopt_.ru : prcopt_.rb;
571
572 if (antpostype_[i] == 0) { /* lat/lon/hgt */
573 *ps = 0;
574 pos[0] = antpos_[i][0] * D2R;
575 pos[1] = antpos_[i][1] * D2R;
576 pos[2] = antpos_[i][2];
577 pos2ecef(pos, rr);
578 } else if (antpostype_[i] == 1) { /* xyz-ecef */
579 *ps = 0;
580 rr[0] = antpos_[i][0];
581 rr[1] = antpos_[i][1];
582 rr[2] = antpos_[i][2];
583 } else {
584 *ps = antpostype_[i] - 1;
585 }
586 }
587 prcopt_.bds2prn_set = bds2prn_given_;
588
589 /* excluded satellites */
590 for (i = 0; i < MAXSAT; i++) {
591 prcopt_.exsats[i] = 0;
592 }
593 if (exsats_[0] != '\0') {
594 strcpy(buff, exsats_);
595 for (p = strtok(buff, " "); p; p = strtok(NULL, " ")) {
596 if (*p == '+') {
597 id = p + 1;
598 } else {
599 id = p;
600 }
601 if (!(sat = satid2no(id))) {
602 continue;
603 }
604 prcopt_.exsats[sat - 1] = *p == '+' ? 2 : 1;
605 }
606 }
607 /* snrmask */
608 for (i = 0; i < NFREQ; i++) {
609 for (j = 0; j < 9; j++) {
610 prcopt_.snrmask.mask[i][j] = 0.0;
611 }
612 strcpy(buff, snrmask_[i]);
613 for (p = strtok(buff, ","), j = 0; p && j < 9; p = strtok(NULL, ",")) {
614 prcopt_.snrmask.mask[i][j++] = atof(p);
615 }
616 }
617 /* explicit signal configuration */
618 if (signals_[0] != '\0') {
619 const char* sigs[64];
620 int nsig = 0, nf = 0;
621
622 strcpy(buff, signals_);
623 for (p = strtok(buff, ","); p && nsig < 64; p = strtok(NULL, ",")) {
624 char* end;
625 /* trim leading whitespace */
626 while (*p == ' ' || *p == '\t') {
627 p++;
628 }
629 /* trim trailing whitespace */
630 end = p + strlen(p) - 1;
631 while (end > p && (*end == ' ' || *end == '\t')) {
632 *end-- = '\0';
633 }
634 if (*p) {
635 sigs[nsig++] = p;
636 }
637 }
638 if (nsig > 0 && mrtk_sigcfg_from_signals(sigs, nsig, prcopt_.sigcfg, &nf) == 0) {
639 if (nf > 0 && nf <= NFREQ) {
640 prcopt_.sigcfg_set = 1;
641 prcopt_.nf = nf;
643 trace(NULL, 3, "buff2sysopts: signals configured (%d signals, nf=%d)\n", nsig, nf);
644 } else {
645 trace(NULL, 1, "buff2sysopts: nf=%d exceeds NFREQ=%d for signals '%s'\n", nf, NFREQ, signals_);
646 }
647 } else {
648 trace(NULL, 1, "buff2sysopts: invalid signals string '%s'\n", signals_);
649 }
650 }
651}
652/* options to system options buffer ------------------------------------------*/
653static void sysopts2buff(void) {
654 double pos[3], *rr;
655 char id[32], *p;
656 int i, j, sat, *ps;
657
658 elmask_ = prcopt_.elmin * R2D;
659 elmaskar_ = prcopt_.elmaskar * R2D;
660 elmaskhold_ = prcopt_.elmaskhold * R2D;
661
662 for (i = 0; i < 2; i++) {
663 ps = i == 0 ? &prcopt_.rovpos : &prcopt_.refpos;
664 rr = i == 0 ? prcopt_.ru : prcopt_.rb;
665
666 if (*ps == 0) {
667 antpostype_[i] = 0;
668 ecef2pos(rr, pos);
669 antpos_[i][0] = pos[0] * R2D;
670 antpos_[i][1] = pos[1] * R2D;
671 antpos_[i][2] = pos[2];
672 } else {
673 antpostype_[i] = *ps + 1;
674 }
675 }
676 bds2prn_given_ = prcopt_.bds2prn_set;
677
678 /* excluded satellites */
679 exsats_[0] = '\0';
680 for (sat = 1, p = exsats_; sat <= MAXSAT && p - exsats_ < (int)sizeof(exsats_) - 32; sat++) {
681 if (prcopt_.exsats[sat - 1]) {
682 satno2id(sat, id);
683 p += sprintf(p, "%s%s%s", p == exsats_ ? "" : " ", prcopt_.exsats[sat - 1] == 2 ? "+" : "", id);
684 }
685 }
686 /* snrmask */
687 for (i = 0; i < NFREQ; i++) {
688 snrmask_[i][0] = '\0';
689 p = snrmask_[i];
690 for (j = 0; j < 9; j++) {
691 p += sprintf(p, "%s%.0f", j > 0 ? "," : "", prcopt_.snrmask.mask[i][j]);
692 }
693 }
694}
695/* reset system options to default ---------------------------------------------
696 * reset system options to default
697 * args : none
698 * return : none
699 *-----------------------------------------------------------------------------*/
700extern void resetsysopts(void) {
701 int i, j;
702
703 trace(NULL, 3, "resetsysopts:\n");
704
707 filopt_.satantp[0] = '\0';
708 filopt_.rcvantp[0] = '\0';
709 filopt_.stapos[0] = '\0';
710 filopt_.geoid[0] = '\0';
711 filopt_.dcb[0] = '\0';
712 filopt_.blq[0] = '\0';
713 filopt_.solstat[0] = '\0';
714 filopt_.trace[0] = '\0';
715 for (i = 0; i < 2; i++) {
716 antpostype_[i] = 0;
717 }
718 elmask_ = 15.0;
719 elmaskar_ = 0.0;
720 elmaskhold_ = 0.0;
721 for (i = 0; i < 2; i++) {
722 for (j = 0; j < 3; j++) {
723 antpos_[i][j] = 0.0;
724 }
725 }
726 exsats_[0] = '\0';
727 signals_[0] = '\0';
728 bds2prn_given_ = 0;
729}
730/* get system options ----------------------------------------------------------
731 * get system options
732 * args : prcopt_t *popt IO processing options (NULL: no output)
733 * solopt_t *sopt IO solution options (NULL: no output)
734 * folopt_t *fopt IO file options (NULL: no output)
735 * return : none
736 * notes : to load system options, use loadopts() before calling the function
737 *-----------------------------------------------------------------------------*/
738extern void getsysopts(prcopt_t* popt, solopt_t* sopt, filopt_t* fopt) {
739 trace(NULL, 3, "getsysopts:\n");
740
741 buff2sysopts();
742 if (popt) {
743 *popt = prcopt_;
744 }
745 if (sopt) {
746 *sopt = solopt_;
747 }
748 if (fopt) {
749 *fopt = filopt_;
750 }
751}
752/* set system options ----------------------------------------------------------
753 * set system options
754 * args : prcopt_t *prcopt I processing options (NULL: default)
755 * solopt_t *solopt I solution options (NULL: default)
756 * filopt_t *filopt I file options (NULL: default)
757 * return : none
758 * notes : to save system options, use saveopts() after calling the function
759 *-----------------------------------------------------------------------------*/
760extern void setsysopts(const prcopt_t* prcopt, const solopt_t* solopt, const filopt_t* filopt) {
761 trace(NULL, 3, "setsysopts:\n");
762
763 resetsysopts();
764 if (prcopt) {
765 prcopt_ = *prcopt;
766 }
767 if (solopt) {
768 solopt_ = *solopt;
769 }
770 if (filopt) {
771 filopt_ = *filopt;
772 }
773 sysopts2buff();
774}
void satno2id(int sat, char *id)
Definition mrtk_nav.c:817
int satid2no(const char *id)
Definition mrtk_nav.c:753
#define D2R
Definition mrtk_coords.c:36
void pos2ecef(const double *pos, double *r)
Transform geodetic position to ECEF position.
#define MAXSAT
Definition mrtk_coords.c:45
void ecef2pos(const double *r, double *pos)
Transform ECEF position to geodetic position.
MRTKLIB Coordinates Module — Coordinate transformations and geometry.
MRTKLIB Navigation Module — Navigation data types and satellite/nav utility functions.
#define R2D
Definition mrtk_obs.c:51
int mrtk_sigcfg_from_signals(const char **sigs, int nsig, mrtk_sigcfg_t *cfg, int *nf)
Build per-constellation signal config from a signal string array.
Definition mrtk_obs.c:1128
int mrtk_sigcfg_to_obsdef(const mrtk_sigcfg_t *cfg)
Apply signal config to obsdef tables (bridge to existing system).
Definition mrtk_obs.c:1187
MRTKLIB Observation Module — Observation data types and utility functions.
const prcopt_t prcopt_default
Definition mrtk_opt.c:31
const solopt_t solopt_default
Definition mrtk_opt.c:92
int loadopts(const char *file, opt_t *opts)
Load options from file.
#define ARALPHAOPT
static double elmaskhold_
#define TSYOPT
#define PSHFTOPT
void getsysopts(prcopt_t *popt, solopt_t *sopt, filopt_t *fopt)
Get system options.
static filopt_t filopt_
#define SEEDOPT
#define COMOPT
#define NAVOPT
#define EPHOPT
int saveopts(const char *file, const char *mode, const char *comment, const opt_t *opts)
Save options to file.
static double antpos_[2][3]
#define TIDEOPT
#define SIGOPT2
static solopt_t solopt_
#define CORROPT
static int antpostype_[2]
int opt2str(const opt_t *opt, char *str)
Convert option value to string.
#define GEOOPT
#define POSOPT
static double elmaskar_
#define PHWOPT
#define MODOPT
#define TRPOPT
opt_t * searchopt(const char *name, const opt_t *opts)
Search option record.
#define SIGOPT5
#define SIGOPT4
static void chop(char *str)
#define STSOPT
int opt2buf(const opt_t *opt, char *buff)
Convert option to string (keyword=value # comment).
static int enum2str(char *s, const char *comment, int val)
opt_t sysopts[]
System options table.
#define STAOPT
#define SIGOPT1
static double elmask_
#define IONOPT
static char exsats_[1024]
#define ISBOPT
#define HGTOPT
#define SWTOPT
#define SATCB
static char snrmask_[5][1024]
#define TFTOPT
static void buff2sysopts(void)
#define TYPOPT
#define ARMOPT
static void sysopts2buff(void)
#define SATPB
static int str2enum(const char *str, const char *comment, int *val)
#define DOPOPT
#define ROBOPT
#define SOLOPT
int str2opt(opt_t *opt, const char *str)
Convert string to option value.
void setsysopts(const prcopt_t *prcopt, const solopt_t *solopt, const filopt_t *filopt)
Set system options.
void resetsysopts(void)
Reset system options to default.
#define SIGOPT3
#define FRQOPT
#define FRQOPT2
static prcopt_t prcopt_
#define IGSOOPT
#define GAROPT
static char signals_[1024]
#define DFTOPT
static int bds2prn_given_
#define BDS2OPT
MRTKLIB Options Module — Configuration option parsing and system option management.
int loadopts_toml(const char *file, opt_t *opts)
Load options from a TOML configuration file.
Definition mrtk_toml.c:608
int saveopts_toml(const char *file, const char *comment, const opt_t *opts)
Save options to a TOML configuration file.
Definition mrtk_toml.c:785
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.
Option type for configuration file parsing.
int format
void * var
const char * name
const char * comment