/src/gpsd/gpsd-3.26.2~dev/libgps/libgps_json.c
Line | Count | Source |
1 | | /**************************************************************************** |
2 | | |
3 | | NAME |
4 | | libgps_json.c - deserialize gpsd data coming from the server |
5 | | |
6 | | DESCRIPTION |
7 | | This module uses the generic JSON parser to get data from JSON |
8 | | representations to libgps structures. |
9 | | |
10 | | PERMISSIONS |
11 | | Written by Eric S. Raymond, 2009 |
12 | | This file is Copyright 2009 by the GPSD project |
13 | | SPDX-License-Identifier: BSD-2-clause |
14 | | |
15 | | ***************************************************************************/ |
16 | | |
17 | | /* isfinite() needs _POSIX_C_SOURCE >= 200112L |
18 | | * isnan(+Inf) is false, isfinite(+Inf) is false |
19 | | * use isfinite() to make sure a float or double is valid |
20 | | */ |
21 | | |
22 | | #include "../include/gpsd_config.h" // must be before all includes |
23 | | |
24 | | #include <math.h> |
25 | | #include <stdbool.h> |
26 | | #include <stddef.h> |
27 | | #include <string.h> |
28 | | |
29 | | #include "../include/gpsd.h" |
30 | | #include "../include/strfuncs.h" |
31 | | #include "../include/gps_json.h" |
32 | | #include "../include/timespec.h" |
33 | | |
34 | | static int json_tpv_read(const char *buf, struct gps_data_t *gpsdata, |
35 | | const char **endptr) |
36 | 378 | { |
37 | 378 | int ret; |
38 | | |
39 | 378 | const struct json_attr_t json_attrs_1[] = { |
40 | | // *INDENT-OFF* |
41 | 378 | {"class", t_check, .dflt.check = "TPV"}, |
42 | 378 | {"alt", t_real, .addr.real = &gpsdata->fix.altitude, |
43 | 378 | .dflt.real = NAN}, // DEPRECATED, undefined |
44 | 378 | {"altHAE", t_real, .addr.real = &gpsdata->fix.altHAE, |
45 | 378 | .dflt.real = NAN}, |
46 | 378 | {"altMSL", t_real, .addr.real = &gpsdata->fix.altMSL, |
47 | 378 | .dflt.real = NAN}, |
48 | 378 | {"ant", t_integer, .addr.integer = &gpsdata->fix.ant_stat, |
49 | 378 | .dflt.integer = 0}, |
50 | 378 | {"antPwr", t_integer, .addr.integer = &gpsdata->fix.ant_power, |
51 | 378 | .dflt.integer = 0}, |
52 | 378 | {"baseS", t_integer, .addr.integer = &gpsdata->fix.base.status, |
53 | 378 | .dflt.integer = STATUS_UNK}, // aka zero |
54 | 378 | {"baseE", t_real, .addr.real = &gpsdata->fix.base.east, |
55 | 378 | .dflt.real = NAN}, |
56 | 378 | {"baseN", t_real, .addr.real = &gpsdata->fix.base.north, |
57 | 378 | .dflt.real = NAN}, |
58 | 378 | {"baseU", t_real, .addr.real = &gpsdata->fix.base.up, |
59 | 378 | .dflt.real = NAN}, |
60 | 378 | {"baseL", t_real, .addr.real = &gpsdata->fix.base.length, |
61 | 378 | .dflt.real = NAN}, |
62 | 378 | {"baseC", t_real, .addr.real = &gpsdata->fix.base.course, |
63 | 378 | .dflt.real = NAN}, |
64 | 378 | {"climb", t_real, .addr.real = &gpsdata->fix.climb, |
65 | 378 | .dflt.real = NAN}, |
66 | 378 | {"datum", t_string, .addr.string = gpsdata->fix.datum, |
67 | 378 | .len = sizeof(gpsdata->fix.datum)}, |
68 | 378 | {"device", t_string, .addr.string = gpsdata->dev.path, |
69 | 378 | .len = sizeof(gpsdata->dev.path)}, |
70 | 378 | {"depth", t_real, .addr.real = &gpsdata->fix.depth, |
71 | 378 | .dflt.real = NAN}, |
72 | 378 | {"dgpsAge", t_real, .addr.real = &gpsdata->fix.dgps_age, |
73 | 378 | .dflt.real = NAN}, |
74 | 378 | {"dgpsRatio", t_real, .addr.real = &gpsdata->fix.base.ratio, |
75 | 378 | .dflt.real = NAN}, |
76 | 378 | {"dgpsSta", t_integer, .addr.integer = &gpsdata->fix.dgps_station, |
77 | 378 | .dflt.integer = -1}, |
78 | 378 | {"ecefx", t_real, .addr.real = &gpsdata->fix.ecef.x, |
79 | 378 | .dflt.real = NAN}, |
80 | 378 | {"ecefy", t_real, .addr.real = &gpsdata->fix.ecef.y, |
81 | 378 | .dflt.real = NAN}, |
82 | 378 | {"ecefz", t_real, .addr.real = &gpsdata->fix.ecef.z, |
83 | 378 | .dflt.real = NAN}, |
84 | 378 | {"ecefvx", t_real, .addr.real = &gpsdata->fix.ecef.vx, |
85 | 378 | .dflt.real = NAN}, |
86 | 378 | {"ecefvy", t_real, .addr.real = &gpsdata->fix.ecef.vy, |
87 | 378 | .dflt.real = NAN}, |
88 | 378 | {"ecefvz", t_real, .addr.real = &gpsdata->fix.ecef.vz, |
89 | 378 | .dflt.real = NAN}, |
90 | 378 | {"ecefpAcc", t_real, .addr.real = &gpsdata->fix.ecef.pAcc, |
91 | 378 | .dflt.real = NAN}, |
92 | 378 | {"ecefvAcc", t_real, .addr.real = &gpsdata->fix.ecef.vAcc, |
93 | 378 | .dflt.real = NAN}, |
94 | 378 | {"epc", t_real, .addr.real = &gpsdata->fix.epc, |
95 | 378 | .dflt.real = NAN}, |
96 | 378 | {"epd", t_real, .addr.real = &gpsdata->fix.epd, |
97 | 378 | .dflt.real = NAN}, |
98 | 378 | {"eph", t_real, .addr.real = &gpsdata->fix.eph, |
99 | 378 | .dflt.real = NAN}, |
100 | 378 | {"eps", t_real, .addr.real = &gpsdata->fix.eps, |
101 | 378 | .dflt.real = NAN}, |
102 | 378 | {"ept", t_real, .addr.real = &gpsdata->fix.ept, |
103 | 378 | .dflt.real = NAN}, |
104 | 378 | {"epx", t_real, .addr.real = &gpsdata->fix.epx, |
105 | 378 | .dflt.real = NAN}, |
106 | 378 | {"epy", t_real, .addr.real = &gpsdata->fix.epy, |
107 | 378 | .dflt.real = NAN}, |
108 | 378 | {"epv", t_real, .addr.real = &gpsdata->fix.epv, |
109 | 378 | .dflt.real = NAN}, |
110 | 378 | {"geoidSep", t_real, .addr.real = &gpsdata->fix.geoid_sep, |
111 | 378 | .dflt.real = NAN}, |
112 | 378 | {"lat", t_real, .addr.real = &gpsdata->fix.latitude, |
113 | 378 | .dflt.real = NAN}, |
114 | 378 | {"jam", t_integer, .addr.integer = &gpsdata->fix.jam, |
115 | 378 | .dflt.integer = -1}, |
116 | 378 | {"leapseconds", t_integer, .addr.integer = &gpsdata->leap_seconds, |
117 | 378 | .dflt.integer = 0}, |
118 | 378 | {"lon", t_real, .addr.real = &gpsdata->fix.longitude, |
119 | 378 | .dflt.real = NAN}, |
120 | 378 | {"magtrack", t_real, .addr.real = &gpsdata->fix.magnetic_track, |
121 | 378 | .dflt.real = NAN}, |
122 | 378 | {"magvar", t_real, .addr.real = &gpsdata->fix.magnetic_var, |
123 | 378 | .dflt.real = NAN}, |
124 | 378 | {"mode", t_integer, .addr.integer = &gpsdata->fix.mode, |
125 | 378 | .dflt.integer = MODE_NOT_SEEN}, |
126 | 378 | {"relD", t_real, .addr.real = &gpsdata->fix.NED.relPosD, |
127 | 378 | .dflt.real = NAN}, |
128 | 378 | {"relE", t_real, .addr.real = &gpsdata->fix.NED.relPosE, |
129 | 378 | .dflt.real = NAN}, |
130 | 378 | {"relN", t_real, .addr.real = &gpsdata->fix.NED.relPosN, |
131 | 378 | .dflt.real = NAN}, |
132 | 378 | {"relH", t_real, .addr.real = &gpsdata->fix.NED.relPosH, |
133 | 378 | .dflt.real = NAN}, |
134 | 378 | {"relL", t_real, .addr.real = &gpsdata->fix.NED.relPosL, |
135 | 378 | .dflt.real = NAN}, |
136 | 378 | {"temp", t_real, .addr.real = &gpsdata->fix.temp, |
137 | 378 | .dflt.real = NAN}, |
138 | 378 | {"time", t_time, .addr.ts = &gpsdata->fix.time, |
139 | 378 | .dflt.ts = {0, 0}}, |
140 | 378 | {"track", t_real, .addr.real = &gpsdata->fix.track, |
141 | 378 | .dflt.real = NAN}, |
142 | 378 | {"sep", t_real, .addr.real = &gpsdata->fix.sep, |
143 | 378 | .dflt.real = NAN}, |
144 | 378 | {"speed", t_real, .addr.real = &gpsdata->fix.speed, |
145 | 378 | .dflt.real = NAN}, |
146 | 378 | {"status", t_integer, .addr.integer = &gpsdata->fix.status, |
147 | 378 | .dflt.integer = STATUS_UNK}, |
148 | 378 | {"velD", t_real, .addr.real = &gpsdata->fix.NED.velD, |
149 | 378 | .dflt.real = NAN}, |
150 | 378 | {"velE", t_real, .addr.real = &gpsdata->fix.NED.velE, |
151 | 378 | .dflt.real = NAN}, |
152 | 378 | {"velN", t_real, .addr.real = &gpsdata->fix.NED.velN, |
153 | 378 | .dflt.real = NAN}, |
154 | 378 | {"wanglem", t_real, .addr.real = &gpsdata->fix.wanglem, |
155 | 378 | .dflt.real = NAN}, |
156 | 378 | {"wangler", t_real, .addr.real = &gpsdata->fix.wangler, |
157 | 378 | .dflt.real = NAN}, |
158 | 378 | {"wanglet", t_real, .addr.real = &gpsdata->fix.wanglet, |
159 | 378 | .dflt.real = NAN}, |
160 | 378 | {"wspeedr", t_real, .addr.real = &gpsdata->fix.wspeedr, |
161 | 378 | .dflt.real = NAN}, |
162 | 378 | {"wspeedt", t_real, .addr.real = &gpsdata->fix.wspeedt, |
163 | 378 | .dflt.real = NAN}, |
164 | 378 | {"wtemp", t_real, .addr.real = &gpsdata->fix.wtemp, |
165 | 378 | .dflt.real = NAN}, |
166 | | // ignore unknown keys, for cross-version compatibility |
167 | 378 | {"", t_ignore}, |
168 | | |
169 | 378 | {NULL}, |
170 | | // *INDENT-ON* |
171 | 378 | }; |
172 | | |
173 | 378 | ret = json_read_object(buf, json_attrs_1, endptr); |
174 | 378 | return ret; |
175 | 378 | } |
176 | | |
177 | | static int json_noise_read(const char *buf, struct gps_data_t *gpsdata, |
178 | | const char **endptr) |
179 | 313 | { |
180 | 313 | int ret; |
181 | | |
182 | 313 | const struct json_attr_t json_attrs_1[] = { |
183 | | // *INDENT-OFF* |
184 | 313 | {"class", t_check, .dflt.check = "GST"}, |
185 | 313 | {"device", t_string, .addr.string = gpsdata->dev.path, |
186 | 313 | .len = sizeof(gpsdata->dev.path)}, |
187 | 313 | {"time", t_time, .addr.ts = &gpsdata->gst.utctime, |
188 | 313 | .dflt.ts = {0, 0}}, |
189 | 313 | {"alt", t_real, .addr.real = &gpsdata->gst.alt_err_deviation, |
190 | 313 | .dflt.real = NAN}, |
191 | 313 | {"lat", t_real, .addr.real = &gpsdata->gst.lat_err_deviation, |
192 | 313 | .dflt.real = NAN}, |
193 | 313 | {"lon", t_real, .addr.real = &gpsdata->gst.lon_err_deviation, |
194 | 313 | .dflt.real = NAN}, |
195 | 313 | {"major", t_real, .addr.real = &gpsdata->gst.smajor_deviation, |
196 | 313 | .dflt.real = NAN}, |
197 | 313 | {"minor", t_real, .addr.real = &gpsdata->gst.sminor_deviation, |
198 | 313 | .dflt.real = NAN}, |
199 | 313 | {"orient", t_real, .addr.real = &gpsdata->gst.smajor_orientation, |
200 | 313 | .dflt.real = NAN}, |
201 | 313 | {"rms", t_real, .addr.real = &gpsdata->gst.rms_deviation, |
202 | 313 | .dflt.real = NAN}, |
203 | 313 | {"ve", t_real, .addr.real = &gpsdata->gst.ve_err_deviation, |
204 | 313 | .dflt.real = NAN}, |
205 | 313 | {"vn", t_real, .addr.real = &gpsdata->gst.vn_err_deviation, |
206 | 313 | .dflt.real = NAN}, |
207 | 313 | {"vu", t_real, .addr.real = &gpsdata->gst.vu_err_deviation, |
208 | 313 | .dflt.real = NAN}, |
209 | | // ignore unknown keys, for cross-version compatibility |
210 | 313 | {"", t_ignore}, |
211 | 313 | {NULL}, |
212 | | // *INDENT-ON* |
213 | 313 | }; |
214 | | |
215 | 313 | ret = json_read_object(buf, json_attrs_1, endptr); |
216 | | |
217 | 313 | return ret; |
218 | 313 | } |
219 | | |
220 | | // decode a RAW messages into gpsdata.raw |
221 | | static int json_raw_read(const char *buf, struct gps_data_t *gpsdata, |
222 | | const char **endptr) |
223 | 86 | { |
224 | 86 | int measurements; |
225 | | // initialized to shut up clang |
226 | 86 | double mtime_s = 0.0, mtime_ns = 0.0; |
227 | | |
228 | 86 | const struct json_attr_t json_attrs_meas[] = { |
229 | | // *INDENT-OFF* |
230 | 86 | {"gnssid", t_ubyte, STRUCTOBJECT(struct meas_t, gnssid)}, |
231 | 86 | {"svid", t_ubyte, STRUCTOBJECT(struct meas_t, svid)}, |
232 | 86 | {"sigid", t_ubyte, STRUCTOBJECT(struct meas_t, sigid), |
233 | 86 | .dflt.ubyte = 0}, |
234 | 86 | {"snr", t_ubyte, STRUCTOBJECT(struct meas_t, snr)}, |
235 | 86 | {"freqid", t_ubyte, STRUCTOBJECT(struct meas_t, freqid), |
236 | 86 | .dflt.ubyte = 0}, |
237 | 86 | {"obs", t_string, STRUCTOBJECT(struct meas_t, obs_code), |
238 | 86 | .len = sizeof(gpsdata->raw.meas[0].obs_code)}, |
239 | 86 | {"lli", t_ubyte, STRUCTOBJECT(struct meas_t, lli), |
240 | 86 | .dflt.ubyte = 0}, |
241 | 86 | {"locktime", t_uinteger, STRUCTOBJECT(struct meas_t, locktime), |
242 | 86 | .dflt.uinteger = 0}, |
243 | 86 | {"carrierphase", t_real, STRUCTOBJECT(struct meas_t, carrierphase), |
244 | 86 | .dflt.real = NAN}, |
245 | 86 | {"pseudorange", t_real, STRUCTOBJECT(struct meas_t, pseudorange), |
246 | 86 | .dflt.real = NAN}, |
247 | 86 | {"doppler", t_real, STRUCTOBJECT(struct meas_t, doppler), |
248 | 86 | .dflt.real = NAN}, |
249 | 86 | {"c2c", t_real, STRUCTOBJECT(struct meas_t, c2c), |
250 | 86 | .dflt.real = NAN}, |
251 | 86 | {"l2c", t_real, STRUCTOBJECT(struct meas_t, l2c), |
252 | 86 | .dflt.real = NAN}, |
253 | | // ignore unknown keys, for cross-version compatibility |
254 | 86 | {"", t_ignore}, |
255 | | // *INDENT-ON* |
256 | 86 | {NULL}, |
257 | 86 | }; |
258 | 86 | const struct json_attr_t json_attrs_raw[] = { |
259 | | // *INDENT-OFF* |
260 | 86 | {"class", t_check, .dflt.check = "RAW"}, |
261 | 86 | {"device", t_string, .addr.string = gpsdata->dev.path, |
262 | 86 | .len = sizeof(gpsdata->dev.path)}, |
263 | 86 | {"time", t_real, .addr.real = &mtime_s, |
264 | 86 | .dflt.real = NAN}, |
265 | 86 | {"nsec", t_real, .addr.real = &mtime_ns, |
266 | 86 | .dflt.real = NAN}, |
267 | 86 | {"rawdata", t_array, STRUCTARRAY(gpsdata->raw.meas, |
268 | 86 | json_attrs_meas, &measurements)}, |
269 | | // ignore unknown keys, for cross-version compatibility |
270 | 86 | {"", t_ignore}, |
271 | 86 | {NULL}, |
272 | | // *INDENT-ON* |
273 | 86 | }; |
274 | 86 | int status; |
275 | | |
276 | 86 | memset(&gpsdata->raw, 0, sizeof(gpsdata->raw)); |
277 | | |
278 | 86 | status = json_read_object(buf, json_attrs_raw, endptr); |
279 | 86 | if (0 != status) { |
280 | 70 | return status; |
281 | 70 | } |
282 | 16 | gpsdata->set |= RAW_SET; |
283 | 16 | if (0 == isfinite(mtime_s) || |
284 | 15 | 0 == isfinite(mtime_ns)) { |
285 | 15 | return status; |
286 | 15 | } |
287 | 1 | gpsdata->raw.mtime.tv_sec = (time_t)mtime_s; |
288 | 1 | gpsdata->raw.mtime.tv_nsec = (long)mtime_ns; |
289 | | |
290 | 1 | return 0; |
291 | 16 | } |
292 | | |
293 | | static int json_sky_read(const char *buf, struct gps_data_t *gpsdata, |
294 | | const char **endptr) |
295 | 175 | { |
296 | | |
297 | 175 | const struct json_attr_t json_attrs_satellites[] = { |
298 | | // *INDENT-OFF* |
299 | 175 | {"PRN", t_short, STRUCTOBJECT(struct satellite_t, PRN)}, |
300 | 175 | {"az", t_real, STRUCTOBJECT(struct satellite_t, azimuth), |
301 | 175 | .dflt.real = NAN}, |
302 | 175 | {"el", t_real, STRUCTOBJECT(struct satellite_t, elevation), |
303 | 175 | .dflt.real = NAN}, |
304 | 175 | {"freqid", t_byte, STRUCTOBJECT(struct satellite_t, freqid), |
305 | 175 | .dflt.byte = -1}, |
306 | 175 | {"gnssid", t_ubyte, STRUCTOBJECT(struct satellite_t, gnssid)}, |
307 | 175 | {"health", t_ubyte, STRUCTOBJECT(struct satellite_t, health), |
308 | 175 | .dflt.ubyte = SAT_HEALTH_UNK}, |
309 | 175 | {"pr", t_real, STRUCTOBJECT(struct satellite_t, pr), |
310 | 175 | .dflt.real = NAN}, |
311 | 175 | {"prRate", t_real, STRUCTOBJECT(struct satellite_t, prRate), |
312 | 175 | .dflt.real = NAN}, |
313 | 175 | {"prRes", t_real, STRUCTOBJECT(struct satellite_t, prRes), |
314 | 175 | .dflt.real = NAN}, |
315 | 175 | {"ss", t_real, STRUCTOBJECT(struct satellite_t, ss), |
316 | 175 | .dflt.real = NAN}, |
317 | 175 | {"sigid", t_ubyte, STRUCTOBJECT(struct satellite_t, sigid)}, |
318 | 175 | {"svid", t_ubyte, STRUCTOBJECT(struct satellite_t, svid)}, |
319 | 175 | {"used", t_boolean, STRUCTOBJECT(struct satellite_t, used)}, |
320 | | // ignore unknown keys, for cross-version compatibility |
321 | 175 | {"", t_ignore}, |
322 | | // *INDENT-ON* |
323 | 175 | {NULL}, |
324 | 175 | }; |
325 | | |
326 | 175 | int nSat = -1; // Use nSat only to know if sats are in SKY |
327 | | |
328 | 175 | const struct json_attr_t json_attrs_2[] = { |
329 | | // *INDENT-OFF* |
330 | 175 | {"class", t_check, .dflt.check = "SKY"}, |
331 | 175 | {"device", t_string, .addr.string = gpsdata->dev.path, |
332 | 175 | .len = sizeof(gpsdata->dev.path)}, |
333 | 175 | {"gdop", t_real, .addr.real = &gpsdata->dop.gdop, |
334 | 175 | .dflt.real = NAN}, |
335 | 175 | {"hdop", t_real, .addr.real = &gpsdata->dop.hdop, |
336 | 175 | .dflt.real = NAN}, |
337 | 175 | {"nSat", t_integer, .addr.integer = &nSat, |
338 | 175 | .dflt.integer = -1}, |
339 | 175 | {"pdop", t_real, .addr.real = &gpsdata->dop.pdop, |
340 | 175 | .dflt.real = NAN}, |
341 | 175 | {"tdop", t_real, .addr.real = &gpsdata->dop.tdop, |
342 | 175 | .dflt.real = NAN}, |
343 | 175 | {"vdop", t_real, .addr.real = &gpsdata->dop.vdop, |
344 | 175 | .dflt.real = NAN}, |
345 | 175 | {"xdop", t_real, .addr.real = &gpsdata->dop.xdop, |
346 | 175 | .dflt.real = NAN}, |
347 | 175 | {"ydop", t_real, .addr.real = &gpsdata->dop.ydop, |
348 | 175 | .dflt.real = NAN}, |
349 | 175 | {"satellites", t_array, |
350 | 175 | STRUCTARRAY(gpsdata->skyview, |
351 | 175 | json_attrs_satellites, |
352 | 175 | &gpsdata->satellites_visible)}, |
353 | 175 | {"time", t_time, .addr.ts = &gpsdata->skyview_time, |
354 | 175 | .dflt.ts = {0, 0}}, |
355 | 175 | {"uSat", t_integer, .addr.integer = &gpsdata->satellites_used, |
356 | 175 | .dflt.integer = 0}, |
357 | | // ignore unknown keys, for cross-version compatibility |
358 | 175 | {"", t_ignore}, |
359 | 175 | {NULL}, |
360 | | // *INDENT-ON* |
361 | 175 | }; |
362 | 175 | int status, i; |
363 | | |
364 | 175 | memset(&gpsdata->skyview, 0, sizeof(gpsdata->skyview)); |
365 | | |
366 | 175 | status = json_read_object(buf, json_attrs_2, endptr); |
367 | 175 | if (0 != status) { |
368 | 49 | return status; |
369 | 49 | } |
370 | | |
371 | 126 | if (1 == isfinite(gpsdata->dop.hdop) || |
372 | 125 | 1 == isfinite(gpsdata->dop.xdop) || |
373 | 124 | 1 == isfinite(gpsdata->dop.ydop) || |
374 | 123 | 1 == isfinite(gpsdata->dop.vdop) || |
375 | 122 | 1 == isfinite(gpsdata->dop.tdop) || |
376 | 121 | 1 == isfinite(gpsdata->dop.pdop) || |
377 | 120 | 1 == isfinite(gpsdata->dop.gdop)) { |
378 | | // got at least one DOP |
379 | 7 | gpsdata->set |= DOP_SET; |
380 | 7 | } |
381 | | |
382 | 126 | gpsdata->satellites_visible = 0; |
383 | | |
384 | 126 | if (-1 == nSat) { |
385 | | // no sats in the SKY, likely just dops. Maybe uSat |
386 | 17 | gpsdata->set &= ~SATELLITE_SET; |
387 | 17 | return 0; |
388 | 17 | } |
389 | 109 | gpsdata->satellites_used = 0; |
390 | | |
391 | 109 | gpsdata->set |= SATELLITE_SET; |
392 | | // recalculate used and visible, do not use nSat, uSat |
393 | 20.1k | for (i = 0; i < MAXCHANNELS; i++) { |
394 | 20.0k | if (0 < gpsdata->skyview[i].PRN) { |
395 | 1.69k | gpsdata->satellites_visible++; |
396 | 1.69k | } |
397 | 20.0k | if (gpsdata->skyview[i].used) { |
398 | 1.29k | gpsdata->satellites_used++; |
399 | 1.29k | } |
400 | 20.0k | } |
401 | | |
402 | 109 | return 0; |
403 | 126 | } |
404 | | |
405 | | // decode class ATT, almost the same as IMU |
406 | | static int json_att_read(const char *buf, struct gps_data_t *gpsdata, |
407 | | const char **endptr) |
408 | 61 | { |
409 | 61 | struct attitude_t *datap = &gpsdata->attitude; |
410 | | |
411 | 61 | const struct json_attr_t json_attrs_1[] = { |
412 | | // *INDENT-OFF* |
413 | 61 | {"class", t_check, .dflt.check = "ATT"}, |
414 | 61 | {"device", t_string, .addr.string = gpsdata->dev.path, |
415 | 61 | .len = sizeof(gpsdata->dev.path)}, |
416 | 61 | {"acc_len", t_real, .addr.real = &datap->acc_len, |
417 | 61 | .dflt.real = NAN}, |
418 | 61 | {"acc_x", t_real, .addr.real = &datap->acc_x, |
419 | 61 | .dflt.real = NAN}, |
420 | 61 | {"acc_y", t_real, .addr.real = &datap->acc_y, |
421 | 61 | .dflt.real = NAN}, |
422 | 61 | {"acc_z", t_real, .addr.real = &datap->acc_z, |
423 | 61 | .dflt.real = NAN}, |
424 | 61 | {"baseS", t_integer, .addr.integer = &datap->base.status, |
425 | 61 | .dflt.integer = STATUS_UNK}, // aka zero |
426 | 61 | {"baseE", t_real, .addr.real = &datap->base.east, |
427 | 61 | .dflt.real = NAN}, |
428 | 61 | {"baseN", t_real, .addr.real = &datap->base.north, |
429 | 61 | .dflt.real = NAN}, |
430 | 61 | {"baseU", t_real, .addr.real = &datap->base.up, |
431 | 61 | .dflt.real = NAN}, |
432 | 61 | {"baseL", t_real, .addr.real = &datap->base.length, |
433 | 61 | .dflt.real = NAN}, |
434 | 61 | {"baseC", t_real, .addr.real = &datap->base.course, |
435 | 61 | .dflt.real = NAN}, |
436 | 61 | {"dgpsRatio", t_real, .addr.real = &datap->base.ratio, |
437 | 61 | .dflt.real = NAN}, |
438 | 61 | {"depth", t_real, .addr.real = &datap->depth, |
439 | 61 | .dflt.real = NAN}, |
440 | 61 | {"dip", t_real, .addr.real = &datap->dip, |
441 | 61 | .dflt.real = NAN}, |
442 | 61 | {"gyro_temp", t_real, .addr.real = &datap->gyro_x, |
443 | 61 | .dflt.real = NAN}, |
444 | 61 | {"gyro_x", t_real, .addr.real = &datap->gyro_x, |
445 | 61 | .dflt.real = NAN}, |
446 | 61 | {"gyro_y", t_real, .addr.real = &datap->gyro_y, |
447 | 61 | .dflt.real = NAN}, |
448 | 61 | {"gyro_z", t_real, .addr.real = &datap->gyro_z, |
449 | 61 | .dflt.real = NAN}, |
450 | 61 | {"heading", t_real, .addr.real = &datap->heading, |
451 | 61 | .dflt.real = NAN}, |
452 | 61 | {"mag_len", t_real, .addr.real = &datap->mag_len, |
453 | 61 | .dflt.real = NAN}, |
454 | 61 | {"mag_st", t_character, .addr.character = &datap->mag_st}, |
455 | 61 | {"mag_x", t_real, .addr.real = &datap->mag_x, |
456 | 61 | .dflt.real = NAN}, |
457 | 61 | {"mag_y", t_real, .addr.real = &datap->mag_y, |
458 | 61 | .dflt.real = NAN}, |
459 | 61 | {"mag_z", t_real, .addr.real = &datap->mag_z, |
460 | 61 | .dflt.real = NAN}, |
461 | 61 | {"mheading", t_real, .addr.real = &datap->mheading, |
462 | 61 | .dflt.real = NAN}, |
463 | 61 | {"msg", t_string, .addr.string = datap->msg, |
464 | 61 | .len = sizeof(datap->msg)}, |
465 | 61 | {"pitch_st", t_character, .addr.character = &datap->pitch_st}, |
466 | 61 | {"pitch", t_real, .addr.real = &datap->pitch, |
467 | 61 | .dflt.real = NAN}, |
468 | 61 | {"roll_st", t_character, .addr.character = &datap->roll_st}, |
469 | 61 | {"roll", t_real, .addr.real = &datap->roll, |
470 | 61 | .dflt.real = NAN}, |
471 | 61 | {"temp", t_real, .addr.real = &datap->temp, |
472 | 61 | .dflt.real = NAN}, |
473 | 61 | {"time", t_time, .addr.ts = &datap->mtime, .dflt.ts = {0, 0}}, |
474 | 61 | {"timeTag", t_ulongint, .addr.ulongint = &datap->timeTag, |
475 | 61 | .dflt.ulongint = 0}, |
476 | 61 | {"yaw_st", t_character, .addr.character = &datap->yaw_st}, |
477 | 61 | {"yaw", t_real, .addr.real = &datap->yaw, .dflt.real = NAN}, |
478 | | |
479 | | // ignore unknown keys, for cross-version compatibility |
480 | 61 | {"", t_ignore}, |
481 | 61 | {NULL}, |
482 | | // *INDENT-ON* |
483 | 61 | }; |
484 | | |
485 | 61 | return json_read_object(buf, json_attrs_1, endptr); |
486 | 61 | } |
487 | | |
488 | | // decode class IMU, almost the ame as ATT |
489 | | static int json_imu_read(const char *buf, struct gps_data_t *gpsdata, |
490 | | const char **endptr) |
491 | 59 | { |
492 | | // the client only uses the first slot. |
493 | 59 | struct attitude_t *datap = &gpsdata->imu[0]; |
494 | | |
495 | 59 | const struct json_attr_t json_attrs_1[] = { |
496 | | // *INDENT-OFF* |
497 | 59 | {"class", t_check, .dflt.check = "IMU"}, |
498 | 59 | {"device", t_string, .addr.string = gpsdata->dev.path, |
499 | 59 | .len = sizeof(gpsdata->dev.path)}, |
500 | 59 | {"acc_len", t_real, .addr.real = &datap->acc_len, |
501 | 59 | .dflt.real = NAN}, |
502 | 59 | {"acc_x", t_real, .addr.real = &datap->acc_x, |
503 | 59 | .dflt.real = NAN}, |
504 | 59 | {"acc_y", t_real, .addr.real = &datap->acc_y, |
505 | 59 | .dflt.real = NAN}, |
506 | 59 | {"acc_z", t_real, .addr.real = &datap->acc_z, |
507 | 59 | .dflt.real = NAN}, |
508 | 59 | {"depth", t_real, .addr.real = &datap->depth, |
509 | 59 | .dflt.real = NAN}, |
510 | 59 | {"dip", t_real, .addr.real = &datap->dip, |
511 | 59 | .dflt.real = NAN}, |
512 | 59 | {"gyro_temp", t_real, .addr.real = &datap->gyro_temp, |
513 | 59 | .dflt.real = NAN}, |
514 | 59 | {"gyro_x", t_real, .addr.real = &datap->gyro_x, |
515 | 59 | .dflt.real = NAN}, |
516 | 59 | {"gyro_y", t_real, .addr.real = &datap->gyro_y, |
517 | 59 | .dflt.real = NAN}, |
518 | 59 | {"gyro_z", t_real, .addr.real = &datap->gyro_z, |
519 | 59 | .dflt.real = NAN}, |
520 | 59 | {"heading", t_real, .addr.real = &datap->heading, |
521 | 59 | .dflt.real = NAN}, |
522 | 59 | {"mag_len", t_real, .addr.real = &datap->mag_len, |
523 | 59 | .dflt.real = NAN}, |
524 | 59 | {"mag_st", t_character, .addr.character = &datap->mag_st}, |
525 | 59 | {"mag_x", t_real, .addr.real = &datap->mag_x, |
526 | 59 | .dflt.real = NAN}, |
527 | 59 | {"mag_y", t_real, .addr.real = &datap->mag_y, |
528 | 59 | .dflt.real = NAN}, |
529 | 59 | {"mag_z", t_real, .addr.real = &datap->mag_z, |
530 | 59 | .dflt.real = NAN}, |
531 | 59 | {"msg", t_string, .addr.string = datap->msg, |
532 | 59 | .len = sizeof(datap->msg)}, |
533 | 59 | {"pitch_st", t_character, .addr.character = &datap->pitch_st}, |
534 | 59 | {"pitch", t_real, .addr.real = &datap->pitch, |
535 | 59 | .dflt.real = NAN}, |
536 | 59 | {"roll_st", t_character, .addr.character = &datap->roll_st}, |
537 | 59 | {"roll", t_real, .addr.real = &datap->roll, |
538 | 59 | .dflt.real = NAN}, |
539 | 59 | {"temp", t_real, .addr.real = &datap->temp, |
540 | 59 | .dflt.real = NAN}, |
541 | 59 | {"time", t_time, .addr.ts = &datap->mtime, .dflt.ts = {0, 0}}, |
542 | 59 | {"timeTag", t_ulongint, .addr.ulongint = &datap->timeTag, |
543 | 59 | .dflt.ulongint = 0}, |
544 | 59 | {"yaw_st", t_character, .addr.character = &datap->yaw_st}, |
545 | 59 | {"yaw", t_real, .addr.real = &datap->yaw, .dflt.real = NAN}, |
546 | | |
547 | | // ignore unknown keys, for cross-version compatibility |
548 | 59 | {"", t_ignore}, |
549 | 59 | {NULL}, |
550 | | // *INDENT-ON* |
551 | 59 | }; |
552 | | |
553 | 59 | return json_read_object(buf, json_attrs_1, endptr); |
554 | 59 | } |
555 | | |
556 | | static int json_devicelist_read(const char *buf, struct gps_data_t *gpsdata, |
557 | | const char **endptr) |
558 | 53 | { |
559 | 53 | const struct json_attr_t json_attrs_subdevices[] = { |
560 | | // *INDENT-OFF* |
561 | 53 | {"class", t_check, .dflt.check = "DEVICE"}, |
562 | 53 | {"path", t_string, STRUCTOBJECT(struct devconfig_t, path), |
563 | 53 | .len = sizeof(gpsdata->devices.list[0].path)}, |
564 | 53 | {"activated", t_time, |
565 | 53 | STRUCTOBJECT(struct devconfig_t, activated)}, |
566 | 53 | {"activated", t_real, |
567 | 53 | STRUCTOBJECT(struct devconfig_t, activated)}, |
568 | 53 | {"flags", t_integer, STRUCTOBJECT(struct devconfig_t, flags)}, |
569 | 53 | {"driver", t_string, STRUCTOBJECT(struct devconfig_t, driver), |
570 | 53 | .len = sizeof(gpsdata->devices.list[0].driver)}, |
571 | 53 | {"hexdata", t_string, STRUCTOBJECT(struct devconfig_t, hexdata), |
572 | 53 | .len = sizeof(gpsdata->devices.list[0].hexdata)}, |
573 | 53 | {"sernum", t_string, STRUCTOBJECT(struct devconfig_t, sernum), |
574 | 53 | .len = sizeof(gpsdata->devices.list[0].sernum)}, |
575 | 53 | {"subtype", t_string, STRUCTOBJECT(struct devconfig_t, subtype), |
576 | 53 | .len = sizeof(gpsdata->devices.list[0].subtype)}, |
577 | 53 | {"subtype1", t_string, STRUCTOBJECT(struct devconfig_t, subtype1), |
578 | 53 | .len = sizeof(gpsdata->devices.list[0].subtype1)}, |
579 | 53 | {"native", t_integer, STRUCTOBJECT(struct devconfig_t, driver_mode), |
580 | 53 | .dflt.integer = -1}, |
581 | 53 | {"bps", t_uinteger, STRUCTOBJECT(struct devconfig_t, baudrate), |
582 | 53 | .dflt.uinteger = DEVDEFAULT_BPS}, |
583 | 53 | {"parity", t_character, STRUCTOBJECT(struct devconfig_t, parity), |
584 | 53 | .dflt.character = DEVDEFAULT_PARITY}, |
585 | 53 | {"stopbits", t_uinteger, STRUCTOBJECT(struct devconfig_t, stopbits), |
586 | 53 | .dflt.integer = DEVDEFAULT_STOPBITS}, |
587 | 53 | {"cycle", t_timespec, STRUCTOBJECT(struct devconfig_t, cycle), |
588 | 53 | .dflt.ts = {0,0}}, |
589 | 53 | {"mincycle", t_timespec, STRUCTOBJECT(struct devconfig_t, mincycle), |
590 | 53 | .dflt.ts = {0,0}}, |
591 | | // ignore unknown keys, for cross-version compatibility |
592 | 53 | {"", t_ignore}, |
593 | 53 | {NULL}, |
594 | | // *INDENT-ON* |
595 | 53 | }; |
596 | 53 | const struct json_attr_t json_attrs_devices[] = { |
597 | 53 | {"class", t_check,.dflt.check = "DEVICES"}, |
598 | 53 | {"devices", t_array, STRUCTARRAY(gpsdata->devices.list, |
599 | 53 | json_attrs_subdevices, |
600 | 53 | &gpsdata->devices.ndevices)}, |
601 | | // ignore unknown keys, for cross-version compatibility |
602 | 53 | {"", t_ignore}, |
603 | 53 | {NULL}, |
604 | 53 | }; |
605 | 53 | int status; |
606 | | |
607 | 53 | memset(&gpsdata->devices, 0, sizeof(gpsdata->devices)); |
608 | 53 | status = json_read_object(buf, json_attrs_devices, endptr); |
609 | 53 | if (status != 0) { |
610 | 52 | return status; |
611 | 52 | } |
612 | | |
613 | 1 | (void)clock_gettime(CLOCK_REALTIME, &gpsdata->devices.time); |
614 | 1 | return 0; |
615 | 53 | } |
616 | | |
617 | | static int json_version_read(const char *buf, struct gps_data_t *gpsdata, |
618 | | const char **endptr) |
619 | 13 | { |
620 | 13 | const struct json_attr_t json_attrs_version[] = { |
621 | | // *INDENT-OFF* |
622 | 13 | {"class", t_check, .dflt.check = "VERSION"}, |
623 | 13 | {"release", t_string, .addr.string = gpsdata->version.release, |
624 | 13 | .len = sizeof(gpsdata->version.release)}, |
625 | 13 | {"rev", t_string, .addr.string = gpsdata->version.rev, |
626 | 13 | .len = sizeof(gpsdata->version.rev)}, |
627 | 13 | {"proto_major", t_integer, |
628 | 13 | .addr.integer = &gpsdata->version.proto_major}, |
629 | 13 | {"proto_minor", t_integer, |
630 | 13 | .addr.integer = &gpsdata->version.proto_minor}, |
631 | 13 | {"remote", t_string, .addr.string = gpsdata->version.remote, |
632 | 13 | .len = sizeof(gpsdata->version.remote)}, |
633 | | // ignore unknown keys, for cross-version compatibility |
634 | 13 | {"", t_ignore}, |
635 | 13 | {NULL}, |
636 | | // *INDENT-ON* |
637 | 13 | }; |
638 | 13 | int status; |
639 | | |
640 | 13 | memset(&gpsdata->version, 0, sizeof(gpsdata->version)); |
641 | 13 | status = json_read_object(buf, json_attrs_version, endptr); |
642 | | |
643 | 13 | return status; |
644 | 13 | } |
645 | | |
646 | | static int json_error_read(const char *buf, struct gps_data_t *gpsdata, |
647 | | const char **endptr) |
648 | 7 | { |
649 | 7 | const struct json_attr_t json_attrs_error[] = { |
650 | | // *INDENT-OFF* |
651 | 7 | {"class", t_check, .dflt.check = "ERROR"}, |
652 | 7 | {"message", t_string, .addr.string = gpsdata->error, |
653 | 7 | .len = sizeof(gpsdata->error)}, |
654 | | // ignore unknown keys, for cross-version compatibility |
655 | 7 | {"", t_ignore}, |
656 | 7 | {NULL}, |
657 | | // *INDENT-ON* |
658 | 7 | }; |
659 | 7 | int status; |
660 | | |
661 | 7 | memset(&gpsdata->error, 0, sizeof(gpsdata->error)); |
662 | 7 | status = json_read_object(buf, json_attrs_error, endptr); |
663 | 7 | if (status != 0) |
664 | 5 | return status; |
665 | | |
666 | 2 | return status; |
667 | 7 | } |
668 | | |
669 | | int json_toff_read(const char *buf, struct gps_data_t *gpsdata, |
670 | | const char **endptr) |
671 | 2.61k | { |
672 | 2.61k | int real_sec = 0, real_nsec = 0, clock_sec = 0, clock_nsec = 0; |
673 | 2.61k | const struct json_attr_t json_attrs_toff[] = { |
674 | | // *INDENT-OFF* |
675 | 2.61k | {"class", t_check, .dflt.check = "TOFF"}, |
676 | 2.61k | {"device", t_string, .addr.string = gpsdata->dev.path, |
677 | 2.61k | .len = sizeof(gpsdata->dev.path)}, |
678 | 2.61k | {"real_sec", t_integer, .addr.integer = &real_sec, |
679 | 2.61k | .dflt.integer = 0}, |
680 | 2.61k | {"real_nsec", t_integer, .addr.integer = &real_nsec, |
681 | 2.61k | .dflt.integer = 0}, |
682 | 2.61k | {"clock_sec", t_integer, .addr.integer = &clock_sec, |
683 | 2.61k | .dflt.integer = 0}, |
684 | 2.61k | {"clock_nsec",t_integer, .addr.integer = &clock_nsec, |
685 | 2.61k | .dflt.integer = 0}, |
686 | | // ignore unknown keys, for cross-version compatibility |
687 | 2.61k | {"", t_ignore}, |
688 | 2.61k | {NULL}, |
689 | | // *INDENT-ON* |
690 | 2.61k | }; |
691 | 2.61k | int status; |
692 | | |
693 | 2.61k | memset(&gpsdata->toff, 0, sizeof(gpsdata->toff)); |
694 | 2.61k | status = json_read_object(buf, json_attrs_toff, endptr); |
695 | 2.61k | gpsdata->toff.real.tv_sec = (time_t)real_sec; |
696 | 2.61k | gpsdata->toff.real.tv_nsec = (long)real_nsec; |
697 | 2.61k | gpsdata->toff.clock.tv_sec = (time_t)clock_sec; |
698 | 2.61k | gpsdata->toff.clock.tv_nsec = (long)clock_nsec; |
699 | 2.61k | if (status != 0) |
700 | 885 | return status; |
701 | | |
702 | 1.72k | return status; |
703 | 2.61k | } |
704 | | |
705 | | int json_pps_read(const char *buf, struct gps_data_t *gpsdata, |
706 | | const char **endptr) |
707 | 31 | { |
708 | 31 | int real_sec = 0, real_nsec = 0, clock_sec = 0, clock_nsec = 0, precision=0; |
709 | 31 | int qErr = 0; |
710 | | |
711 | 31 | const struct json_attr_t json_attrs_pps[] = { |
712 | | // *INDENT-OFF* |
713 | 31 | {"class", t_check, .dflt.check = "PPS"}, |
714 | 31 | {"device", t_string, .addr.string = gpsdata->dev.path, |
715 | 31 | .len = sizeof(gpsdata->dev.path)}, |
716 | 31 | {"real_sec", t_integer, .addr.integer = &real_sec, |
717 | 31 | .dflt.integer = 0}, |
718 | 31 | {"real_nsec", t_integer, .addr.integer = &real_nsec, |
719 | 31 | .dflt.integer = 0}, |
720 | 31 | {"clock_sec", t_integer, .addr.integer = &clock_sec, |
721 | 31 | .dflt.integer = 0}, |
722 | 31 | {"clock_nsec",t_integer, .addr.integer = &clock_nsec, |
723 | 31 | .dflt.integer = 0}, |
724 | 31 | {"precision", t_integer, .addr.integer = &precision, |
725 | 31 | .dflt.integer = 0}, |
726 | 31 | {"qErr", t_integer, .addr.integer = &qErr, |
727 | 31 | .dflt.integer = 0}, |
728 | | // ignore unknown keys, for cross-version compatibility |
729 | 31 | {"", t_ignore}, |
730 | 31 | {NULL}, |
731 | | // *INDENT-ON* |
732 | 31 | }; |
733 | 31 | int status; |
734 | | |
735 | 31 | memset(&gpsdata->pps, 0, sizeof(gpsdata->pps)); |
736 | 31 | status = json_read_object(buf, json_attrs_pps, endptr); |
737 | | |
738 | | // This is good until GPS are more than nanosec accurate |
739 | 31 | gpsdata->pps.real.tv_sec = (time_t)real_sec; |
740 | 31 | gpsdata->pps.real.tv_nsec = (long)real_nsec; |
741 | 31 | gpsdata->pps.clock.tv_sec = (time_t)clock_sec; |
742 | 31 | gpsdata->pps.clock.tv_nsec = (long)clock_nsec; |
743 | | // hope qErr fits in int |
744 | 31 | gpsdata->qErr = (long)qErr; |
745 | | |
746 | | // FIXME: precision is currently parsed but discarded |
747 | 31 | return status; |
748 | 31 | } |
749 | | |
750 | | int json_oscillator_read(const char *buf, struct gps_data_t *gpsdata, |
751 | | const char **endptr) |
752 | 15 | { |
753 | 15 | bool running = false, reference = false, disciplined = false; |
754 | 15 | int delta = 0; |
755 | 15 | const struct json_attr_t json_attrs_osc[] = { |
756 | | // *INDENT-OFF* |
757 | 15 | {"class", t_check, .dflt.check = "OSC"}, |
758 | 15 | {"device", t_string, .addr.string = gpsdata->dev.path, |
759 | 15 | .len = sizeof(gpsdata->dev.path)}, |
760 | 15 | {"running", t_boolean, .addr.boolean = &running, |
761 | 15 | .dflt.boolean = false}, |
762 | 15 | {"reference", t_boolean, .addr.boolean = &reference, |
763 | 15 | .dflt.boolean = false}, |
764 | 15 | {"disciplined", t_boolean, .addr.boolean = &disciplined, |
765 | 15 | .dflt.boolean = false}, |
766 | 15 | {"delta", t_integer, .addr.integer = &delta, |
767 | 15 | .dflt.integer = 0}, |
768 | | // ignore unknown keys, for cross-version compatibility |
769 | 15 | {"", t_ignore}, |
770 | 15 | {NULL}, |
771 | | // *INDENT-ON* |
772 | 15 | }; |
773 | 15 | int status; |
774 | | |
775 | 15 | memset(&gpsdata->osc, 0, sizeof(gpsdata->osc)); |
776 | 15 | status = json_read_object(buf, json_attrs_osc, endptr); |
777 | | |
778 | 15 | gpsdata->osc.running = running; |
779 | 15 | gpsdata->osc.reference = reference; |
780 | 15 | gpsdata->osc.disciplined = disciplined; |
781 | 15 | gpsdata->osc.delta = delta; |
782 | | |
783 | 15 | return status; |
784 | 15 | } |
785 | | |
786 | | // Test for JSON read status values that should be treated as a go-ahead |
787 | | // for further processing. JSON_BADATTR - to allow JSON attributes unknown |
788 | | // to this version of the library, for forward compatibility, is an obvious |
789 | | // thing to go here. |
790 | 1.41k | #define PASS(n) (((n) == 0) || ((n) == JSON_ERR_BADATTR)) |
791 | 1.98k | #define FILTER(n) ((n) == JSON_ERR_BADATTR ? 0 : n) |
792 | | |
793 | | // the only entry point - unpack a JSON object into gpsdata_t substructures |
794 | | int libgps_json_unpack(const char *buf, |
795 | | struct gps_data_t *gpsdata, const char **end) |
796 | 2.58k | { |
797 | 2.58k | int status; |
798 | 2.58k | char *classtag = strstr(buf, "\"class\":"); |
799 | | |
800 | 2.58k | if (NULL == classtag) { |
801 | 377 | return -1; |
802 | 377 | } |
803 | | |
804 | 2.20k | if (str_starts_with(classtag, "\"class\":\"TPV\"")) { |
805 | 378 | status = json_tpv_read(buf, gpsdata, end); |
806 | 378 | gpsdata->set = STATUS_SET; |
807 | 378 | if (0 != gpsdata->fix.time.tv_sec) { |
808 | 234 | gpsdata->set |= TIME_SET; |
809 | 234 | } |
810 | 378 | if (0 != isfinite(gpsdata->fix.ept)) { |
811 | 1 | gpsdata->set |= TIMERR_SET; |
812 | 1 | } |
813 | 378 | if (0 != isfinite(gpsdata->fix.longitude)) { |
814 | 1 | gpsdata->set |= LATLON_SET; |
815 | 1 | } |
816 | 378 | if (0 != isfinite(gpsdata->fix.altitude) || |
817 | 377 | 0 != isfinite(gpsdata->fix.altHAE) || |
818 | 376 | 0 != isfinite(gpsdata->fix.depth) || |
819 | 375 | 0 != isfinite(gpsdata->fix.altMSL)) { |
820 | 4 | gpsdata->set |= ALTITUDE_SET; |
821 | 4 | } |
822 | 378 | if (0 != isfinite(gpsdata->fix.epx) && |
823 | 2 | 0 != isfinite(gpsdata->fix.epy)) { |
824 | 1 | gpsdata->set |= HERR_SET; |
825 | 1 | } |
826 | 378 | if (0 != isfinite(gpsdata->fix.epv)) { |
827 | 1 | gpsdata->set |= VERR_SET; |
828 | 1 | } |
829 | 378 | if (0 != isfinite(gpsdata->fix.track)) { |
830 | 1 | gpsdata->set |= TRACK_SET; |
831 | 1 | } |
832 | 378 | if (0 != isfinite(gpsdata->fix.magnetic_track) || |
833 | 377 | 0 != isfinite(gpsdata->fix.magnetic_var)) { |
834 | 2 | gpsdata->set |= MAGNETIC_TRACK_SET; |
835 | 2 | } |
836 | 378 | if (0 != isfinite(gpsdata->fix.speed)) { |
837 | 1 | gpsdata->set |= SPEED_SET; |
838 | 1 | } |
839 | 378 | if (0 != isfinite(gpsdata->fix.climb)) { |
840 | 1 | gpsdata->set |= CLIMB_SET; |
841 | 1 | } |
842 | 378 | if (0 != isfinite(gpsdata->fix.epd)) { |
843 | 1 | gpsdata->set |= TRACKERR_SET; |
844 | 1 | } |
845 | 378 | if (0 != isfinite(gpsdata->fix.eps)) { |
846 | 1 | gpsdata->set |= SPEEDERR_SET; |
847 | 1 | } |
848 | 378 | if (0 != isfinite(gpsdata->fix.epc)) { |
849 | 1 | gpsdata->set |= CLIMBERR_SET; |
850 | 1 | } |
851 | 378 | if (MODE_NOT_SEEN != gpsdata->fix.mode) { |
852 | 57 | gpsdata->set |= MODE_SET; |
853 | 57 | } |
854 | 378 | if (0 != isfinite(gpsdata->fix.wanglem) || |
855 | 377 | 0 != isfinite(gpsdata->fix.wangler) || |
856 | 376 | 0 != isfinite(gpsdata->fix.wanglet) || |
857 | 375 | 0 != isfinite(gpsdata->fix.wspeedr) || |
858 | 374 | 0 != isfinite(gpsdata->fix.wspeedt)) { |
859 | 5 | gpsdata->set |= NAVDATA_SET; |
860 | 5 | } |
861 | 378 | if (0 != isfinite(gpsdata->fix.NED.relPosN) || |
862 | 377 | 0 != isfinite(gpsdata->fix.NED.relPosE) || |
863 | 376 | 0 != isfinite(gpsdata->fix.NED.relPosD) || |
864 | 374 | 0 != isfinite(gpsdata->fix.NED.relPosH) || |
865 | 373 | 0 != isfinite(gpsdata->fix.NED.relPosL) || |
866 | 372 | 0 != isfinite(gpsdata->fix.NED.velN) || |
867 | 371 | 0 != isfinite(gpsdata->fix.NED.velE) || |
868 | 370 | 0 != isfinite(gpsdata->fix.NED.velD)) { |
869 | 9 | gpsdata->set |= NED_SET; |
870 | 9 | } |
871 | 378 | if ((0 != isfinite(gpsdata->fix.ecef.x)) && |
872 | 3 | (0 != isfinite(gpsdata->fix.ecef.y)) && |
873 | 2 | (0 != isfinite(gpsdata->fix.ecef.z))) { |
874 | | // All, or none. Clients can just do their own isfinite()s |
875 | 1 | gpsdata->set |= ECEF_SET; |
876 | 1 | } |
877 | 378 | if ((0 != isfinite(gpsdata->fix.ecef.vx)) && |
878 | 3 | (0 != isfinite(gpsdata->fix.ecef.vy)) && |
879 | 2 | (0 != isfinite(gpsdata->fix.ecef.vz))) { |
880 | | // All, or none. Clients can just do their own isfinite()s |
881 | 1 | gpsdata->set |= VECEF_SET; |
882 | 1 | } |
883 | 378 | return FILTER(status); |
884 | 378 | } |
885 | 1.82k | if (str_starts_with(classtag, "\"class\":\"GST\"")) { |
886 | 313 | status = json_noise_read(buf, gpsdata, end); |
887 | 313 | if (PASS(status)) { |
888 | 294 | gpsdata->set &= ~UNION_SET; |
889 | 294 | gpsdata->set |= GST_SET; |
890 | 294 | } |
891 | 313 | return FILTER(status); |
892 | 313 | } |
893 | 1.51k | if (str_starts_with(classtag, "\"class\":\"SKY\"")) { |
894 | 175 | status = json_sky_read(buf, gpsdata, end); |
895 | 175 | return FILTER(status); |
896 | 175 | } |
897 | 1.33k | if (str_starts_with(classtag, "\"class\":\"ATT\"")) { |
898 | 61 | status = json_att_read(buf, gpsdata, end); |
899 | 61 | if (PASS(status)) { |
900 | 31 | gpsdata->set |= ATTITUDE_SET; |
901 | 31 | } |
902 | 61 | return FILTER(status); |
903 | 61 | } |
904 | 1.27k | if (str_starts_with(classtag, "\"class\":\"IMU\"")) { |
905 | 59 | status = json_imu_read(buf, gpsdata, end); |
906 | 59 | if (PASS(status)) { |
907 | 25 | gpsdata->set |= IMU_SET; |
908 | 25 | } |
909 | 59 | return FILTER(status); |
910 | 59 | } |
911 | 1.21k | if (str_starts_with(classtag, "\"class\":\"DEVICES\"")) { |
912 | 53 | status = json_devicelist_read(buf, gpsdata, end); |
913 | 53 | if (PASS(status)) { |
914 | 1 | gpsdata->set &= ~UNION_SET; |
915 | 1 | gpsdata->set |= DEVICELIST_SET; |
916 | 1 | } |
917 | 53 | return FILTER(status); |
918 | 53 | } |
919 | 1.16k | if (str_starts_with(classtag, "\"class\":\"DEVICE\"")) { |
920 | 14 | status = json_device_read(buf, &gpsdata->dev, end); |
921 | 14 | if (PASS(status)) |
922 | 3 | gpsdata->set |= DEVICE_SET; |
923 | 14 | return FILTER(status); |
924 | 14 | } |
925 | 1.15k | if (str_starts_with(classtag, "\"class\":\"WATCH\"")) { |
926 | 60 | status = json_watch_read(buf, &gpsdata->policy, end); |
927 | 60 | if (PASS(status)) { |
928 | 54 | gpsdata->set &= ~UNION_SET; |
929 | 54 | gpsdata->set |= POLICY_SET; |
930 | 54 | } |
931 | 60 | return FILTER(status); |
932 | 60 | } |
933 | 1.09k | if (str_starts_with(classtag, "\"class\":\"VERSION\"")) { |
934 | 13 | status = json_version_read(buf, gpsdata, end); |
935 | 13 | if (status == 0) { |
936 | 3 | gpsdata->set &= ~UNION_SET; |
937 | 3 | gpsdata->set |= VERSION_SET; |
938 | 3 | } |
939 | 13 | return FILTER(status); |
940 | 13 | } |
941 | 1.07k | if (str_starts_with(classtag, "\"class\":\"RTCM2\"")) { |
942 | 264 | status = json_rtcm2_read(buf, |
943 | 264 | gpsdata->dev.path, sizeof(gpsdata->dev.path), |
944 | 264 | &gpsdata->rtcm2, end); |
945 | 264 | if (PASS(status)) { |
946 | 101 | gpsdata->set &= ~UNION_SET; |
947 | 101 | gpsdata->set |= RTCM2_SET; |
948 | 101 | } |
949 | 264 | return FILTER(status); |
950 | 264 | } |
951 | 815 | if (str_starts_with(classtag, "\"class\":\"RTCM3\"")) { |
952 | 105 | status = json_rtcm3_read(buf, |
953 | 105 | gpsdata->dev.path, sizeof(gpsdata->dev.path), |
954 | 105 | &gpsdata->rtcm3, end); |
955 | 105 | if (PASS(status)) { |
956 | 29 | gpsdata->set &= ~UNION_SET; |
957 | 29 | gpsdata->set |= RTCM3_SET; |
958 | 29 | } |
959 | 105 | return FILTER(status); |
960 | 105 | } |
961 | 710 | #ifdef AIVDM_ENABLE |
962 | 710 | if (str_starts_with(classtag, "\"class\":\"AIS\"")) { |
963 | 317 | status = json_ais_read(buf, |
964 | 317 | gpsdata->dev.path, sizeof(gpsdata->dev.path), |
965 | 317 | &gpsdata->ais, end); |
966 | 317 | if (PASS(status)) { |
967 | 192 | gpsdata->set &= ~UNION_SET; |
968 | 192 | gpsdata->set |= AIS_SET; |
969 | 192 | } |
970 | 317 | return FILTER(status); |
971 | 317 | } |
972 | 393 | #endif // AIVDM_ENABLE |
973 | 393 | if (str_starts_with(classtag, "\"class\":\"ERROR\"")) { |
974 | 7 | status = json_error_read(buf, gpsdata, end); |
975 | 7 | if (PASS(status)) { |
976 | 2 | gpsdata->set &= ~UNION_SET; |
977 | 2 | gpsdata->set |= ERROR_SET; |
978 | 2 | } |
979 | 7 | return FILTER(status); |
980 | 7 | } |
981 | 386 | if (str_starts_with(classtag, "\"class\":\"TOFF\"")) { |
982 | 31 | status = json_toff_read(buf, gpsdata, end); |
983 | 31 | if (PASS(status)) { |
984 | 16 | gpsdata->set &= ~UNION_SET; |
985 | 16 | gpsdata->set |= TOFF_SET; |
986 | 16 | } |
987 | 31 | return FILTER(status); |
988 | 31 | } |
989 | 355 | if (str_starts_with(classtag, "\"class\":\"PPS\"")) { |
990 | 31 | status = json_pps_read(buf, gpsdata, end); |
991 | 31 | if (PASS(status)) { |
992 | 20 | gpsdata->set &= ~UNION_SET; |
993 | 20 | gpsdata->set |= PPS_SET; |
994 | 20 | } |
995 | 31 | return FILTER(status); |
996 | 31 | } |
997 | 324 | if (str_starts_with(classtag, "\"class\":\"OSC\"")) { |
998 | 15 | status = json_oscillator_read(buf, gpsdata, end); |
999 | 15 | if (PASS(status)) { |
1000 | 10 | gpsdata->set &= ~UNION_SET; |
1001 | 10 | gpsdata->set |= OSCILLATOR_SET; |
1002 | 10 | } |
1003 | 15 | return FILTER(status); |
1004 | 15 | } |
1005 | 309 | if (str_starts_with(classtag, "\"class\":\"RAW\"")) { |
1006 | 86 | status = json_raw_read(buf, gpsdata, end); |
1007 | 86 | if (PASS(status)) { |
1008 | 16 | gpsdata->set &= ~UNION_SET; |
1009 | 16 | gpsdata->set |= RAW_SET; |
1010 | 16 | } |
1011 | 86 | return FILTER(status); |
1012 | 86 | } |
1013 | | // else, unknown class type |
1014 | 223 | return -1; |
1015 | 309 | } |
1016 | | |
1017 | | |
1018 | | |
1019 | | // vim: set expandtab shiftwidth=4 |