/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 | 385 | { |
37 | 385 | int ret; |
38 | | |
39 | 385 | const struct json_attr_t json_attrs_1[] = { |
40 | | // *INDENT-OFF* |
41 | 385 | {"class", t_check, .dflt.check = "TPV"}, |
42 | 385 | {"alt", t_real, .addr.real = &gpsdata->fix.altitude, |
43 | 385 | .dflt.real = NAN}, // DEPRECATED, undefined |
44 | 385 | {"altHAE", t_real, .addr.real = &gpsdata->fix.altHAE, |
45 | 385 | .dflt.real = NAN}, |
46 | 385 | {"altMSL", t_real, .addr.real = &gpsdata->fix.altMSL, |
47 | 385 | .dflt.real = NAN}, |
48 | 385 | {"ant", t_integer, .addr.integer = &gpsdata->fix.ant_stat, |
49 | 385 | .dflt.integer = 0}, |
50 | 385 | {"antPwr", t_integer, .addr.integer = &gpsdata->fix.ant_power, |
51 | 385 | .dflt.integer = 0}, |
52 | 385 | {"baseS", t_integer, .addr.integer = &gpsdata->fix.base.status, |
53 | 385 | .dflt.integer = STATUS_UNK}, // aka zero |
54 | 385 | {"baseE", t_real, .addr.real = &gpsdata->fix.base.east, |
55 | 385 | .dflt.real = NAN}, |
56 | 385 | {"baseN", t_real, .addr.real = &gpsdata->fix.base.north, |
57 | 385 | .dflt.real = NAN}, |
58 | 385 | {"baseU", t_real, .addr.real = &gpsdata->fix.base.up, |
59 | 385 | .dflt.real = NAN}, |
60 | 385 | {"baseL", t_real, .addr.real = &gpsdata->fix.base.length, |
61 | 385 | .dflt.real = NAN}, |
62 | 385 | {"baseC", t_real, .addr.real = &gpsdata->fix.base.course, |
63 | 385 | .dflt.real = NAN}, |
64 | 385 | {"climb", t_real, .addr.real = &gpsdata->fix.climb, |
65 | 385 | .dflt.real = NAN}, |
66 | 385 | {"datum", t_string, .addr.string = gpsdata->fix.datum, |
67 | 385 | .len = sizeof(gpsdata->fix.datum)}, |
68 | 385 | {"device", t_string, .addr.string = gpsdata->dev.path, |
69 | 385 | .len = sizeof(gpsdata->dev.path)}, |
70 | 385 | {"depth", t_real, .addr.real = &gpsdata->fix.depth, |
71 | 385 | .dflt.real = NAN}, |
72 | 385 | {"dgpsAge", t_real, .addr.real = &gpsdata->fix.dgps_age, |
73 | 385 | .dflt.real = NAN}, |
74 | 385 | {"dgpsRatio", t_real, .addr.real = &gpsdata->fix.base.ratio, |
75 | 385 | .dflt.real = NAN}, |
76 | 385 | {"dgpsSta", t_integer, .addr.integer = &gpsdata->fix.dgps_station, |
77 | 385 | .dflt.integer = -1}, |
78 | 385 | {"ecefx", t_real, .addr.real = &gpsdata->fix.ecef.x, |
79 | 385 | .dflt.real = NAN}, |
80 | 385 | {"ecefy", t_real, .addr.real = &gpsdata->fix.ecef.y, |
81 | 385 | .dflt.real = NAN}, |
82 | 385 | {"ecefz", t_real, .addr.real = &gpsdata->fix.ecef.z, |
83 | 385 | .dflt.real = NAN}, |
84 | 385 | {"ecefvx", t_real, .addr.real = &gpsdata->fix.ecef.vx, |
85 | 385 | .dflt.real = NAN}, |
86 | 385 | {"ecefvy", t_real, .addr.real = &gpsdata->fix.ecef.vy, |
87 | 385 | .dflt.real = NAN}, |
88 | 385 | {"ecefvz", t_real, .addr.real = &gpsdata->fix.ecef.vz, |
89 | 385 | .dflt.real = NAN}, |
90 | 385 | {"ecefpAcc", t_real, .addr.real = &gpsdata->fix.ecef.pAcc, |
91 | 385 | .dflt.real = NAN}, |
92 | 385 | {"ecefvAcc", t_real, .addr.real = &gpsdata->fix.ecef.vAcc, |
93 | 385 | .dflt.real = NAN}, |
94 | 385 | {"epc", t_real, .addr.real = &gpsdata->fix.epc, |
95 | 385 | .dflt.real = NAN}, |
96 | 385 | {"epd", t_real, .addr.real = &gpsdata->fix.epd, |
97 | 385 | .dflt.real = NAN}, |
98 | 385 | {"eph", t_real, .addr.real = &gpsdata->fix.eph, |
99 | 385 | .dflt.real = NAN}, |
100 | 385 | {"eps", t_real, .addr.real = &gpsdata->fix.eps, |
101 | 385 | .dflt.real = NAN}, |
102 | 385 | {"ept", t_real, .addr.real = &gpsdata->fix.ept, |
103 | 385 | .dflt.real = NAN}, |
104 | 385 | {"epx", t_real, .addr.real = &gpsdata->fix.epx, |
105 | 385 | .dflt.real = NAN}, |
106 | 385 | {"epy", t_real, .addr.real = &gpsdata->fix.epy, |
107 | 385 | .dflt.real = NAN}, |
108 | 385 | {"epv", t_real, .addr.real = &gpsdata->fix.epv, |
109 | 385 | .dflt.real = NAN}, |
110 | 385 | {"geoidSep", t_real, .addr.real = &gpsdata->fix.geoid_sep, |
111 | 385 | .dflt.real = NAN}, |
112 | 385 | {"lat", t_real, .addr.real = &gpsdata->fix.latitude, |
113 | 385 | .dflt.real = NAN}, |
114 | 385 | {"jam", t_integer, .addr.integer = &gpsdata->fix.jam, |
115 | 385 | .dflt.integer = -1}, |
116 | 385 | {"leapseconds", t_integer, .addr.integer = &gpsdata->leap_seconds, |
117 | 385 | .dflt.integer = 0}, |
118 | 385 | {"lon", t_real, .addr.real = &gpsdata->fix.longitude, |
119 | 385 | .dflt.real = NAN}, |
120 | 385 | {"magtrack", t_real, .addr.real = &gpsdata->fix.magnetic_track, |
121 | 385 | .dflt.real = NAN}, |
122 | 385 | {"magvar", t_real, .addr.real = &gpsdata->fix.magnetic_var, |
123 | 385 | .dflt.real = NAN}, |
124 | 385 | {"mode", t_integer, .addr.integer = &gpsdata->fix.mode, |
125 | 385 | .dflt.integer = MODE_NOT_SEEN}, |
126 | 385 | {"relD", t_real, .addr.real = &gpsdata->fix.NED.relPosD, |
127 | 385 | .dflt.real = NAN}, |
128 | 385 | {"relE", t_real, .addr.real = &gpsdata->fix.NED.relPosE, |
129 | 385 | .dflt.real = NAN}, |
130 | 385 | {"relN", t_real, .addr.real = &gpsdata->fix.NED.relPosN, |
131 | 385 | .dflt.real = NAN}, |
132 | 385 | {"relH", t_real, .addr.real = &gpsdata->fix.NED.relPosH, |
133 | 385 | .dflt.real = NAN}, |
134 | 385 | {"relL", t_real, .addr.real = &gpsdata->fix.NED.relPosL, |
135 | 385 | .dflt.real = NAN}, |
136 | 385 | {"temp", t_real, .addr.real = &gpsdata->fix.temp, |
137 | 385 | .dflt.real = NAN}, |
138 | 385 | {"time", t_time, .addr.ts = &gpsdata->fix.time, |
139 | 385 | .dflt.ts = {0, 0}}, |
140 | 385 | {"track", t_real, .addr.real = &gpsdata->fix.track, |
141 | 385 | .dflt.real = NAN}, |
142 | 385 | {"sep", t_real, .addr.real = &gpsdata->fix.sep, |
143 | 385 | .dflt.real = NAN}, |
144 | 385 | {"speed", t_real, .addr.real = &gpsdata->fix.speed, |
145 | 385 | .dflt.real = NAN}, |
146 | 385 | {"status", t_integer, .addr.integer = &gpsdata->fix.status, |
147 | 385 | .dflt.integer = STATUS_UNK}, |
148 | 385 | {"velD", t_real, .addr.real = &gpsdata->fix.NED.velD, |
149 | 385 | .dflt.real = NAN}, |
150 | 385 | {"velE", t_real, .addr.real = &gpsdata->fix.NED.velE, |
151 | 385 | .dflt.real = NAN}, |
152 | 385 | {"velN", t_real, .addr.real = &gpsdata->fix.NED.velN, |
153 | 385 | .dflt.real = NAN}, |
154 | 385 | {"wanglem", t_real, .addr.real = &gpsdata->fix.wanglem, |
155 | 385 | .dflt.real = NAN}, |
156 | 385 | {"wangler", t_real, .addr.real = &gpsdata->fix.wangler, |
157 | 385 | .dflt.real = NAN}, |
158 | 385 | {"wanglet", t_real, .addr.real = &gpsdata->fix.wanglet, |
159 | 385 | .dflt.real = NAN}, |
160 | 385 | {"wspeedr", t_real, .addr.real = &gpsdata->fix.wspeedr, |
161 | 385 | .dflt.real = NAN}, |
162 | 385 | {"wspeedt", t_real, .addr.real = &gpsdata->fix.wspeedt, |
163 | 385 | .dflt.real = NAN}, |
164 | 385 | {"wtemp", t_real, .addr.real = &gpsdata->fix.wtemp, |
165 | 385 | .dflt.real = NAN}, |
166 | | // ignore unknown keys, for cross-version compatibility |
167 | 385 | {"", t_ignore}, |
168 | | |
169 | 385 | {NULL}, |
170 | | // *INDENT-ON* |
171 | 385 | }; |
172 | | |
173 | 385 | ret = json_read_object(buf, json_attrs_1, endptr); |
174 | 385 | return ret; |
175 | 385 | } |
176 | | |
177 | | static int json_noise_read(const char *buf, struct gps_data_t *gpsdata, |
178 | | const char **endptr) |
179 | 327 | { |
180 | 327 | int ret; |
181 | | |
182 | 327 | const struct json_attr_t json_attrs_1[] = { |
183 | | // *INDENT-OFF* |
184 | 327 | {"class", t_check, .dflt.check = "GST"}, |
185 | 327 | {"device", t_string, .addr.string = gpsdata->dev.path, |
186 | 327 | .len = sizeof(gpsdata->dev.path)}, |
187 | 327 | {"time", t_time, .addr.ts = &gpsdata->gst.utctime, |
188 | 327 | .dflt.ts = {0, 0}}, |
189 | 327 | {"alt", t_real, .addr.real = &gpsdata->gst.alt_err_deviation, |
190 | 327 | .dflt.real = NAN}, |
191 | 327 | {"lat", t_real, .addr.real = &gpsdata->gst.lat_err_deviation, |
192 | 327 | .dflt.real = NAN}, |
193 | 327 | {"lon", t_real, .addr.real = &gpsdata->gst.lon_err_deviation, |
194 | 327 | .dflt.real = NAN}, |
195 | 327 | {"major", t_real, .addr.real = &gpsdata->gst.smajor_deviation, |
196 | 327 | .dflt.real = NAN}, |
197 | 327 | {"minor", t_real, .addr.real = &gpsdata->gst.sminor_deviation, |
198 | 327 | .dflt.real = NAN}, |
199 | 327 | {"orient", t_real, .addr.real = &gpsdata->gst.smajor_orientation, |
200 | 327 | .dflt.real = NAN}, |
201 | 327 | {"rms", t_real, .addr.real = &gpsdata->gst.rms_deviation, |
202 | 327 | .dflt.real = NAN}, |
203 | 327 | {"ve", t_real, .addr.real = &gpsdata->gst.ve_err_deviation, |
204 | 327 | .dflt.real = NAN}, |
205 | 327 | {"vn", t_real, .addr.real = &gpsdata->gst.vn_err_deviation, |
206 | 327 | .dflt.real = NAN}, |
207 | 327 | {"vu", t_real, .addr.real = &gpsdata->gst.vu_err_deviation, |
208 | 327 | .dflt.real = NAN}, |
209 | | // ignore unknown keys, for cross-version compatibility |
210 | 327 | {"", t_ignore}, |
211 | 327 | {NULL}, |
212 | | // *INDENT-ON* |
213 | 327 | }; |
214 | | |
215 | 327 | ret = json_read_object(buf, json_attrs_1, endptr); |
216 | | |
217 | 327 | return ret; |
218 | 327 | } |
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 | 97 | { |
224 | 97 | int measurements; |
225 | | // initialized to shut up clang |
226 | 97 | double mtime_s = 0.0, mtime_ns = 0.0; |
227 | | |
228 | 97 | const struct json_attr_t json_attrs_meas[] = { |
229 | | // *INDENT-OFF* |
230 | 97 | {"gnssid", t_ubyte, STRUCTOBJECT(struct meas_t, gnssid)}, |
231 | 97 | {"svid", t_ubyte, STRUCTOBJECT(struct meas_t, svid)}, |
232 | 97 | {"sigid", t_ubyte, STRUCTOBJECT(struct meas_t, sigid), |
233 | 97 | .dflt.ubyte = 0}, |
234 | 97 | {"snr", t_ubyte, STRUCTOBJECT(struct meas_t, snr)}, |
235 | 97 | {"freqid", t_ubyte, STRUCTOBJECT(struct meas_t, freqid), |
236 | 97 | .dflt.ubyte = 0}, |
237 | 97 | {"obs", t_string, STRUCTOBJECT(struct meas_t, obs_code), |
238 | 97 | .len = sizeof(gpsdata->raw.meas[0].obs_code)}, |
239 | 97 | {"lli", t_ubyte, STRUCTOBJECT(struct meas_t, lli), |
240 | 97 | .dflt.ubyte = 0}, |
241 | 97 | {"locktime", t_uinteger, STRUCTOBJECT(struct meas_t, locktime), |
242 | 97 | .dflt.uinteger = 0}, |
243 | 97 | {"carrierphase", t_real, STRUCTOBJECT(struct meas_t, carrierphase), |
244 | 97 | .dflt.real = NAN}, |
245 | 97 | {"pseudorange", t_real, STRUCTOBJECT(struct meas_t, pseudorange), |
246 | 97 | .dflt.real = NAN}, |
247 | 97 | {"doppler", t_real, STRUCTOBJECT(struct meas_t, doppler), |
248 | 97 | .dflt.real = NAN}, |
249 | 97 | {"c2c", t_real, STRUCTOBJECT(struct meas_t, c2c), |
250 | 97 | .dflt.real = NAN}, |
251 | 97 | {"l2c", t_real, STRUCTOBJECT(struct meas_t, l2c), |
252 | 97 | .dflt.real = NAN}, |
253 | | // ignore unknown keys, for cross-version compatibility |
254 | 97 | {"", t_ignore}, |
255 | | // *INDENT-ON* |
256 | 97 | {NULL}, |
257 | 97 | }; |
258 | 97 | const struct json_attr_t json_attrs_raw[] = { |
259 | | // *INDENT-OFF* |
260 | 97 | {"class", t_check, .dflt.check = "RAW"}, |
261 | 97 | {"device", t_string, .addr.string = gpsdata->dev.path, |
262 | 97 | .len = sizeof(gpsdata->dev.path)}, |
263 | 97 | {"time", t_real, .addr.real = &mtime_s, |
264 | 97 | .dflt.real = NAN}, |
265 | 97 | {"nsec", t_real, .addr.real = &mtime_ns, |
266 | 97 | .dflt.real = NAN}, |
267 | 97 | {"rawdata", t_array, STRUCTARRAY(gpsdata->raw.meas, |
268 | 97 | json_attrs_meas, &measurements)}, |
269 | | // ignore unknown keys, for cross-version compatibility |
270 | 97 | {"", t_ignore}, |
271 | 97 | {NULL}, |
272 | | // *INDENT-ON* |
273 | 97 | }; |
274 | 97 | int status; |
275 | | |
276 | 97 | memset(&gpsdata->raw, 0, sizeof(gpsdata->raw)); |
277 | | |
278 | 97 | status = json_read_object(buf, json_attrs_raw, endptr); |
279 | 97 | if (0 != status) { |
280 | 81 | return status; |
281 | 81 | } |
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 | 55 | return status; |
369 | 55 | } |
370 | | |
371 | 120 | if (1 == isfinite(gpsdata->dop.hdop) || |
372 | 119 | 1 == isfinite(gpsdata->dop.xdop) || |
373 | 118 | 1 == isfinite(gpsdata->dop.ydop) || |
374 | 117 | 1 == isfinite(gpsdata->dop.vdop) || |
375 | 116 | 1 == isfinite(gpsdata->dop.tdop) || |
376 | 115 | 1 == isfinite(gpsdata->dop.pdop) || |
377 | 114 | 1 == isfinite(gpsdata->dop.gdop)) { |
378 | | // got at least one DOP |
379 | 7 | gpsdata->set |= DOP_SET; |
380 | 7 | } |
381 | | |
382 | 120 | gpsdata->satellites_visible = 0; |
383 | | |
384 | 120 | if (-1 == nSat) { |
385 | | // no sats in the SKY, likely just dops. Maybe uSat |
386 | 18 | gpsdata->set &= ~SATELLITE_SET; |
387 | 18 | return 0; |
388 | 18 | } |
389 | 102 | gpsdata->satellites_used = 0; |
390 | | |
391 | 102 | gpsdata->set |= SATELLITE_SET; |
392 | | // recalculate used and visible, do not use nSat, uSat |
393 | 18.8k | for (i = 0; i < MAXCHANNELS; i++) { |
394 | 18.7k | if (0 < gpsdata->skyview[i].PRN) { |
395 | 1.48k | gpsdata->satellites_visible++; |
396 | 1.48k | } |
397 | 18.7k | if (gpsdata->skyview[i].used) { |
398 | 1.29k | gpsdata->satellites_used++; |
399 | 1.29k | } |
400 | 18.7k | } |
401 | | |
402 | 102 | return 0; |
403 | 120 | } |
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 | 53 | { |
492 | | // the client only uses the first slot. |
493 | 53 | struct attitude_t *datap = &gpsdata->imu[0]; |
494 | | |
495 | 53 | const struct json_attr_t json_attrs_1[] = { |
496 | | // *INDENT-OFF* |
497 | 53 | {"class", t_check, .dflt.check = "IMU"}, |
498 | 53 | {"device", t_string, .addr.string = gpsdata->dev.path, |
499 | 53 | .len = sizeof(gpsdata->dev.path)}, |
500 | 53 | {"acc_len", t_real, .addr.real = &datap->acc_len, |
501 | 53 | .dflt.real = NAN}, |
502 | 53 | {"acc_x", t_real, .addr.real = &datap->acc_x, |
503 | 53 | .dflt.real = NAN}, |
504 | 53 | {"acc_y", t_real, .addr.real = &datap->acc_y, |
505 | 53 | .dflt.real = NAN}, |
506 | 53 | {"acc_z", t_real, .addr.real = &datap->acc_z, |
507 | 53 | .dflt.real = NAN}, |
508 | 53 | {"depth", t_real, .addr.real = &datap->depth, |
509 | 53 | .dflt.real = NAN}, |
510 | 53 | {"dip", t_real, .addr.real = &datap->dip, |
511 | 53 | .dflt.real = NAN}, |
512 | 53 | {"gyro_temp", t_real, .addr.real = &datap->gyro_temp, |
513 | 53 | .dflt.real = NAN}, |
514 | 53 | {"gyro_x", t_real, .addr.real = &datap->gyro_x, |
515 | 53 | .dflt.real = NAN}, |
516 | 53 | {"gyro_y", t_real, .addr.real = &datap->gyro_y, |
517 | 53 | .dflt.real = NAN}, |
518 | 53 | {"gyro_z", t_real, .addr.real = &datap->gyro_z, |
519 | 53 | .dflt.real = NAN}, |
520 | 53 | {"heading", t_real, .addr.real = &datap->heading, |
521 | 53 | .dflt.real = NAN}, |
522 | 53 | {"mag_len", t_real, .addr.real = &datap->mag_len, |
523 | 53 | .dflt.real = NAN}, |
524 | 53 | {"mag_st", t_character, .addr.character = &datap->mag_st}, |
525 | 53 | {"mag_x", t_real, .addr.real = &datap->mag_x, |
526 | 53 | .dflt.real = NAN}, |
527 | 53 | {"mag_y", t_real, .addr.real = &datap->mag_y, |
528 | 53 | .dflt.real = NAN}, |
529 | 53 | {"mag_z", t_real, .addr.real = &datap->mag_z, |
530 | 53 | .dflt.real = NAN}, |
531 | 53 | {"msg", t_string, .addr.string = datap->msg, |
532 | 53 | .len = sizeof(datap->msg)}, |
533 | 53 | {"pitch_st", t_character, .addr.character = &datap->pitch_st}, |
534 | 53 | {"pitch", t_real, .addr.real = &datap->pitch, |
535 | 53 | .dflt.real = NAN}, |
536 | 53 | {"roll_st", t_character, .addr.character = &datap->roll_st}, |
537 | 53 | {"roll", t_real, .addr.real = &datap->roll, |
538 | 53 | .dflt.real = NAN}, |
539 | 53 | {"temp", t_real, .addr.real = &datap->temp, |
540 | 53 | .dflt.real = NAN}, |
541 | 53 | {"time", t_time, .addr.ts = &datap->mtime, .dflt.ts = {0, 0}}, |
542 | 53 | {"timeTag", t_ulongint, .addr.ulongint = &datap->timeTag, |
543 | 53 | .dflt.ulongint = 0}, |
544 | 53 | {"yaw_st", t_character, .addr.character = &datap->yaw_st}, |
545 | 53 | {"yaw", t_real, .addr.real = &datap->yaw, .dflt.real = NAN}, |
546 | | |
547 | | // ignore unknown keys, for cross-version compatibility |
548 | 53 | {"", t_ignore}, |
549 | 53 | {NULL}, |
550 | | // *INDENT-ON* |
551 | 53 | }; |
552 | | |
553 | 53 | return json_read_object(buf, json_attrs_1, endptr); |
554 | 53 | } |
555 | | |
556 | | static int json_devicelist_read(const char *buf, struct gps_data_t *gpsdata, |
557 | | const char **endptr) |
558 | 56 | { |
559 | 56 | const struct json_attr_t json_attrs_subdevices[] = { |
560 | | // *INDENT-OFF* |
561 | 56 | {"class", t_check, .dflt.check = "DEVICE"}, |
562 | 56 | {"path", t_string, STRUCTOBJECT(struct devconfig_t, path), |
563 | 56 | .len = sizeof(gpsdata->devices.list[0].path)}, |
564 | 56 | {"activated", t_time, |
565 | 56 | STRUCTOBJECT(struct devconfig_t, activated)}, |
566 | 56 | {"activated", t_real, |
567 | 56 | STRUCTOBJECT(struct devconfig_t, activated)}, |
568 | 56 | {"flags", t_integer, STRUCTOBJECT(struct devconfig_t, flags)}, |
569 | 56 | {"driver", t_string, STRUCTOBJECT(struct devconfig_t, driver), |
570 | 56 | .len = sizeof(gpsdata->devices.list[0].driver)}, |
571 | 56 | {"hexdata", t_string, STRUCTOBJECT(struct devconfig_t, hexdata), |
572 | 56 | .len = sizeof(gpsdata->devices.list[0].hexdata)}, |
573 | 56 | {"sernum", t_string, STRUCTOBJECT(struct devconfig_t, sernum), |
574 | 56 | .len = sizeof(gpsdata->devices.list[0].sernum)}, |
575 | 56 | {"subtype", t_string, STRUCTOBJECT(struct devconfig_t, subtype), |
576 | 56 | .len = sizeof(gpsdata->devices.list[0].subtype)}, |
577 | 56 | {"subtype1", t_string, STRUCTOBJECT(struct devconfig_t, subtype1), |
578 | 56 | .len = sizeof(gpsdata->devices.list[0].subtype1)}, |
579 | 56 | {"native", t_integer, STRUCTOBJECT(struct devconfig_t, driver_mode), |
580 | 56 | .dflt.integer = -1}, |
581 | 56 | {"bps", t_uinteger, STRUCTOBJECT(struct devconfig_t, baudrate), |
582 | 56 | .dflt.uinteger = DEVDEFAULT_BPS}, |
583 | 56 | {"parity", t_character, STRUCTOBJECT(struct devconfig_t, parity), |
584 | 56 | .dflt.character = DEVDEFAULT_PARITY}, |
585 | 56 | {"stopbits", t_uinteger, STRUCTOBJECT(struct devconfig_t, stopbits), |
586 | 56 | .dflt.integer = DEVDEFAULT_STOPBITS}, |
587 | 56 | {"cycle", t_timespec, STRUCTOBJECT(struct devconfig_t, cycle), |
588 | 56 | .dflt.ts = {0,0}}, |
589 | 56 | {"mincycle", t_timespec, STRUCTOBJECT(struct devconfig_t, mincycle), |
590 | 56 | .dflt.ts = {0,0}}, |
591 | | // ignore unknown keys, for cross-version compatibility |
592 | 56 | {"", t_ignore}, |
593 | 56 | {NULL}, |
594 | | // *INDENT-ON* |
595 | 56 | }; |
596 | 56 | const struct json_attr_t json_attrs_devices[] = { |
597 | 56 | {"class", t_check,.dflt.check = "DEVICES"}, |
598 | 56 | {"devices", t_array, STRUCTARRAY(gpsdata->devices.list, |
599 | 56 | json_attrs_subdevices, |
600 | 56 | &gpsdata->devices.ndevices)}, |
601 | | // ignore unknown keys, for cross-version compatibility |
602 | 56 | {"", t_ignore}, |
603 | 56 | {NULL}, |
604 | 56 | }; |
605 | 56 | int status; |
606 | | |
607 | 56 | memset(&gpsdata->devices, 0, sizeof(gpsdata->devices)); |
608 | 56 | status = json_read_object(buf, json_attrs_devices, endptr); |
609 | 56 | if (status != 0) { |
610 | 55 | return status; |
611 | 55 | } |
612 | | |
613 | 1 | (void)clock_gettime(CLOCK_REALTIME, &gpsdata->devices.time); |
614 | 1 | return 0; |
615 | 56 | } |
616 | | |
617 | | static int json_version_read(const char *buf, struct gps_data_t *gpsdata, |
618 | | const char **endptr) |
619 | 11 | { |
620 | 11 | const struct json_attr_t json_attrs_version[] = { |
621 | | // *INDENT-OFF* |
622 | 11 | {"class", t_check, .dflt.check = "VERSION"}, |
623 | 11 | {"release", t_string, .addr.string = gpsdata->version.release, |
624 | 11 | .len = sizeof(gpsdata->version.release)}, |
625 | 11 | {"rev", t_string, .addr.string = gpsdata->version.rev, |
626 | 11 | .len = sizeof(gpsdata->version.rev)}, |
627 | 11 | {"proto_major", t_integer, |
628 | 11 | .addr.integer = &gpsdata->version.proto_major}, |
629 | 11 | {"proto_minor", t_integer, |
630 | 11 | .addr.integer = &gpsdata->version.proto_minor}, |
631 | 11 | {"remote", t_string, .addr.string = gpsdata->version.remote, |
632 | 11 | .len = sizeof(gpsdata->version.remote)}, |
633 | | // ignore unknown keys, for cross-version compatibility |
634 | 11 | {"", t_ignore}, |
635 | 11 | {NULL}, |
636 | | // *INDENT-ON* |
637 | 11 | }; |
638 | 11 | int status; |
639 | | |
640 | 11 | memset(&gpsdata->version, 0, sizeof(gpsdata->version)); |
641 | 11 | status = json_read_object(buf, json_attrs_version, endptr); |
642 | | |
643 | 11 | return status; |
644 | 11 | } |
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.66k | { |
672 | 2.66k | int real_sec = 0, real_nsec = 0, clock_sec = 0, clock_nsec = 0; |
673 | 2.66k | const struct json_attr_t json_attrs_toff[] = { |
674 | | // *INDENT-OFF* |
675 | 2.66k | {"class", t_check, .dflt.check = "TOFF"}, |
676 | 2.66k | {"device", t_string, .addr.string = gpsdata->dev.path, |
677 | 2.66k | .len = sizeof(gpsdata->dev.path)}, |
678 | 2.66k | {"real_sec", t_integer, .addr.integer = &real_sec, |
679 | 2.66k | .dflt.integer = 0}, |
680 | 2.66k | {"real_nsec", t_integer, .addr.integer = &real_nsec, |
681 | 2.66k | .dflt.integer = 0}, |
682 | 2.66k | {"clock_sec", t_integer, .addr.integer = &clock_sec, |
683 | 2.66k | .dflt.integer = 0}, |
684 | 2.66k | {"clock_nsec",t_integer, .addr.integer = &clock_nsec, |
685 | 2.66k | .dflt.integer = 0}, |
686 | | // ignore unknown keys, for cross-version compatibility |
687 | 2.66k | {"", t_ignore}, |
688 | 2.66k | {NULL}, |
689 | | // *INDENT-ON* |
690 | 2.66k | }; |
691 | 2.66k | int status; |
692 | | |
693 | 2.66k | memset(&gpsdata->toff, 0, sizeof(gpsdata->toff)); |
694 | 2.66k | status = json_read_object(buf, json_attrs_toff, endptr); |
695 | 2.66k | gpsdata->toff.real.tv_sec = (time_t)real_sec; |
696 | 2.66k | gpsdata->toff.real.tv_nsec = (long)real_nsec; |
697 | 2.66k | gpsdata->toff.clock.tv_sec = (time_t)clock_sec; |
698 | 2.66k | gpsdata->toff.clock.tv_nsec = (long)clock_nsec; |
699 | 2.66k | if (status != 0) |
700 | 1.00k | return status; |
701 | | |
702 | 1.66k | return status; |
703 | 2.66k | } |
704 | | |
705 | | int json_pps_read(const char *buf, struct gps_data_t *gpsdata, |
706 | | const char **endptr) |
707 | 35 | { |
708 | 35 | int real_sec = 0, real_nsec = 0, clock_sec = 0, clock_nsec = 0, precision=0; |
709 | 35 | int qErr = 0; |
710 | | |
711 | 35 | const struct json_attr_t json_attrs_pps[] = { |
712 | | // *INDENT-OFF* |
713 | 35 | {"class", t_check, .dflt.check = "PPS"}, |
714 | 35 | {"device", t_string, .addr.string = gpsdata->dev.path, |
715 | 35 | .len = sizeof(gpsdata->dev.path)}, |
716 | 35 | {"real_sec", t_integer, .addr.integer = &real_sec, |
717 | 35 | .dflt.integer = 0}, |
718 | 35 | {"real_nsec", t_integer, .addr.integer = &real_nsec, |
719 | 35 | .dflt.integer = 0}, |
720 | 35 | {"clock_sec", t_integer, .addr.integer = &clock_sec, |
721 | 35 | .dflt.integer = 0}, |
722 | 35 | {"clock_nsec",t_integer, .addr.integer = &clock_nsec, |
723 | 35 | .dflt.integer = 0}, |
724 | 35 | {"precision", t_integer, .addr.integer = &precision, |
725 | 35 | .dflt.integer = 0}, |
726 | 35 | {"qErr", t_integer, .addr.integer = &qErr, |
727 | 35 | .dflt.integer = 0}, |
728 | | // ignore unknown keys, for cross-version compatibility |
729 | 35 | {"", t_ignore}, |
730 | 35 | {NULL}, |
731 | | // *INDENT-ON* |
732 | 35 | }; |
733 | 35 | int status; |
734 | | |
735 | 35 | memset(&gpsdata->pps, 0, sizeof(gpsdata->pps)); |
736 | 35 | status = json_read_object(buf, json_attrs_pps, endptr); |
737 | | |
738 | | // This is good until GPS are more than nanosec accurate |
739 | 35 | gpsdata->pps.real.tv_sec = (time_t)real_sec; |
740 | 35 | gpsdata->pps.real.tv_nsec = (long)real_nsec; |
741 | 35 | gpsdata->pps.clock.tv_sec = (time_t)clock_sec; |
742 | 35 | gpsdata->pps.clock.tv_nsec = (long)clock_nsec; |
743 | | // hope qErr fits in int |
744 | 35 | gpsdata->qErr = (long)qErr; |
745 | | |
746 | | // FIXME: precision is currently parsed but discarded |
747 | 35 | return status; |
748 | 35 | } |
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.46k | #define PASS(n) (((n) == 0) || ((n) == JSON_ERR_BADATTR)) |
791 | 2.03k | #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.63k | { |
797 | 2.63k | int status; |
798 | 2.63k | char *classtag = strstr(buf, "\"class\":"); |
799 | | |
800 | 2.63k | if (NULL == classtag) { |
801 | 386 | return -1; |
802 | 386 | } |
803 | | |
804 | 2.25k | if (str_starts_with(classtag, "\"class\":\"TPV\"")) { |
805 | 385 | status = json_tpv_read(buf, gpsdata, end); |
806 | 385 | gpsdata->set = STATUS_SET; |
807 | 385 | if (0 != gpsdata->fix.time.tv_sec) { |
808 | 235 | gpsdata->set |= TIME_SET; |
809 | 235 | } |
810 | 385 | if (0 != isfinite(gpsdata->fix.ept)) { |
811 | 1 | gpsdata->set |= TIMERR_SET; |
812 | 1 | } |
813 | 385 | if (0 != isfinite(gpsdata->fix.longitude)) { |
814 | 1 | gpsdata->set |= LATLON_SET; |
815 | 1 | } |
816 | 385 | if (0 != isfinite(gpsdata->fix.altitude) || |
817 | 384 | 0 != isfinite(gpsdata->fix.altHAE) || |
818 | 383 | 0 != isfinite(gpsdata->fix.depth) || |
819 | 382 | 0 != isfinite(gpsdata->fix.altMSL)) { |
820 | 4 | gpsdata->set |= ALTITUDE_SET; |
821 | 4 | } |
822 | 385 | if (0 != isfinite(gpsdata->fix.epx) && |
823 | 2 | 0 != isfinite(gpsdata->fix.epy)) { |
824 | 1 | gpsdata->set |= HERR_SET; |
825 | 1 | } |
826 | 385 | if (0 != isfinite(gpsdata->fix.epv)) { |
827 | 1 | gpsdata->set |= VERR_SET; |
828 | 1 | } |
829 | 385 | if (0 != isfinite(gpsdata->fix.track)) { |
830 | 1 | gpsdata->set |= TRACK_SET; |
831 | 1 | } |
832 | 385 | if (0 != isfinite(gpsdata->fix.magnetic_track) || |
833 | 384 | 0 != isfinite(gpsdata->fix.magnetic_var)) { |
834 | 2 | gpsdata->set |= MAGNETIC_TRACK_SET; |
835 | 2 | } |
836 | 385 | if (0 != isfinite(gpsdata->fix.speed)) { |
837 | 1 | gpsdata->set |= SPEED_SET; |
838 | 1 | } |
839 | 385 | if (0 != isfinite(gpsdata->fix.climb)) { |
840 | 1 | gpsdata->set |= CLIMB_SET; |
841 | 1 | } |
842 | 385 | if (0 != isfinite(gpsdata->fix.epd)) { |
843 | 1 | gpsdata->set |= TRACKERR_SET; |
844 | 1 | } |
845 | 385 | if (0 != isfinite(gpsdata->fix.eps)) { |
846 | 1 | gpsdata->set |= SPEEDERR_SET; |
847 | 1 | } |
848 | 385 | if (0 != isfinite(gpsdata->fix.epc)) { |
849 | 1 | gpsdata->set |= CLIMBERR_SET; |
850 | 1 | } |
851 | 385 | if (MODE_NOT_SEEN != gpsdata->fix.mode) { |
852 | 56 | gpsdata->set |= MODE_SET; |
853 | 56 | } |
854 | 385 | if (0 != isfinite(gpsdata->fix.wanglem) || |
855 | 384 | 0 != isfinite(gpsdata->fix.wangler) || |
856 | 383 | 0 != isfinite(gpsdata->fix.wanglet) || |
857 | 382 | 0 != isfinite(gpsdata->fix.wspeedr) || |
858 | 381 | 0 != isfinite(gpsdata->fix.wspeedt)) { |
859 | 5 | gpsdata->set |= NAVDATA_SET; |
860 | 5 | } |
861 | 385 | if (0 != isfinite(gpsdata->fix.NED.relPosN) || |
862 | 384 | 0 != isfinite(gpsdata->fix.NED.relPosE) || |
863 | 383 | 0 != isfinite(gpsdata->fix.NED.relPosD) || |
864 | 382 | 0 != isfinite(gpsdata->fix.NED.relPosH) || |
865 | 381 | 0 != isfinite(gpsdata->fix.NED.relPosL) || |
866 | 380 | 0 != isfinite(gpsdata->fix.NED.velN) || |
867 | 379 | 0 != isfinite(gpsdata->fix.NED.velE) || |
868 | 378 | 0 != isfinite(gpsdata->fix.NED.velD)) { |
869 | 8 | gpsdata->set |= NED_SET; |
870 | 8 | } |
871 | 385 | 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 | 385 | 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 | 385 | return FILTER(status); |
884 | 385 | } |
885 | 1.86k | if (str_starts_with(classtag, "\"class\":\"GST\"")) { |
886 | 327 | status = json_noise_read(buf, gpsdata, end); |
887 | 327 | if (PASS(status)) { |
888 | 303 | gpsdata->set &= ~UNION_SET; |
889 | 303 | gpsdata->set |= GST_SET; |
890 | 303 | } |
891 | 327 | return FILTER(status); |
892 | 327 | } |
893 | 1.54k | 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.36k | if (str_starts_with(classtag, "\"class\":\"ATT\"")) { |
898 | 61 | status = json_att_read(buf, gpsdata, end); |
899 | 61 | if (PASS(status)) { |
900 | 27 | gpsdata->set |= ATTITUDE_SET; |
901 | 27 | } |
902 | 61 | return FILTER(status); |
903 | 61 | } |
904 | 1.30k | if (str_starts_with(classtag, "\"class\":\"IMU\"")) { |
905 | 53 | status = json_imu_read(buf, gpsdata, end); |
906 | 53 | if (PASS(status)) { |
907 | 17 | gpsdata->set |= IMU_SET; |
908 | 17 | } |
909 | 53 | return FILTER(status); |
910 | 53 | } |
911 | 1.25k | if (str_starts_with(classtag, "\"class\":\"DEVICES\"")) { |
912 | 56 | status = json_devicelist_read(buf, gpsdata, end); |
913 | 56 | if (PASS(status)) { |
914 | 1 | gpsdata->set &= ~UNION_SET; |
915 | 1 | gpsdata->set |= DEVICELIST_SET; |
916 | 1 | } |
917 | 56 | return FILTER(status); |
918 | 56 | } |
919 | 1.19k | if (str_starts_with(classtag, "\"class\":\"DEVICE\"")) { |
920 | 15 | status = json_device_read(buf, &gpsdata->dev, end); |
921 | 15 | if (PASS(status)) |
922 | 4 | gpsdata->set |= DEVICE_SET; |
923 | 15 | return FILTER(status); |
924 | 15 | } |
925 | 1.18k | if (str_starts_with(classtag, "\"class\":\"WATCH\"")) { |
926 | 53 | status = json_watch_read(buf, &gpsdata->policy, end); |
927 | 53 | if (PASS(status)) { |
928 | 47 | gpsdata->set &= ~UNION_SET; |
929 | 47 | gpsdata->set |= POLICY_SET; |
930 | 47 | } |
931 | 53 | return FILTER(status); |
932 | 53 | } |
933 | 1.12k | if (str_starts_with(classtag, "\"class\":\"VERSION\"")) { |
934 | 11 | status = json_version_read(buf, gpsdata, end); |
935 | 11 | if (status == 0) { |
936 | 3 | gpsdata->set &= ~UNION_SET; |
937 | 3 | gpsdata->set |= VERSION_SET; |
938 | 3 | } |
939 | 11 | return FILTER(status); |
940 | 11 | } |
941 | 1.11k | if (str_starts_with(classtag, "\"class\":\"RTCM2\"")) { |
942 | 286 | status = json_rtcm2_read(buf, |
943 | 286 | gpsdata->dev.path, sizeof(gpsdata->dev.path), |
944 | 286 | &gpsdata->rtcm2, end); |
945 | 286 | if (PASS(status)) { |
946 | 105 | gpsdata->set &= ~UNION_SET; |
947 | 105 | gpsdata->set |= RTCM2_SET; |
948 | 105 | } |
949 | 286 | return FILTER(status); |
950 | 286 | } |
951 | 830 | if (str_starts_with(classtag, "\"class\":\"RTCM3\"")) { |
952 | 120 | status = json_rtcm3_read(buf, |
953 | 120 | gpsdata->dev.path, sizeof(gpsdata->dev.path), |
954 | 120 | &gpsdata->rtcm3, end); |
955 | 120 | if (PASS(status)) { |
956 | 27 | gpsdata->set &= ~UNION_SET; |
957 | 27 | gpsdata->set |= RTCM3_SET; |
958 | 27 | } |
959 | 120 | return FILTER(status); |
960 | 120 | } |
961 | 710 | #ifdef AIVDM_ENABLE |
962 | 710 | if (str_starts_with(classtag, "\"class\":\"AIS\"")) { |
963 | 308 | status = json_ais_read(buf, |
964 | 308 | gpsdata->dev.path, sizeof(gpsdata->dev.path), |
965 | 308 | &gpsdata->ais, end); |
966 | 308 | if (PASS(status)) { |
967 | 178 | gpsdata->set &= ~UNION_SET; |
968 | 178 | gpsdata->set |= AIS_SET; |
969 | 178 | } |
970 | 308 | return FILTER(status); |
971 | 308 | } |
972 | 402 | #endif // AIVDM_ENABLE |
973 | 402 | 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 | 395 | if (str_starts_with(classtag, "\"class\":\"TOFF\"")) { |
982 | 29 | status = json_toff_read(buf, gpsdata, end); |
983 | 29 | if (PASS(status)) { |
984 | 15 | gpsdata->set &= ~UNION_SET; |
985 | 15 | gpsdata->set |= TOFF_SET; |
986 | 15 | } |
987 | 29 | return FILTER(status); |
988 | 29 | } |
989 | 366 | if (str_starts_with(classtag, "\"class\":\"PPS\"")) { |
990 | 35 | status = json_pps_read(buf, gpsdata, end); |
991 | 35 | if (PASS(status)) { |
992 | 23 | gpsdata->set &= ~UNION_SET; |
993 | 23 | gpsdata->set |= PPS_SET; |
994 | 23 | } |
995 | 35 | return FILTER(status); |
996 | 35 | } |
997 | 331 | 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 | 316 | if (str_starts_with(classtag, "\"class\":\"RAW\"")) { |
1006 | 97 | status = json_raw_read(buf, gpsdata, end); |
1007 | 97 | if (PASS(status)) { |
1008 | 16 | gpsdata->set &= ~UNION_SET; |
1009 | 16 | gpsdata->set |= RAW_SET; |
1010 | 16 | } |
1011 | 97 | return FILTER(status); |
1012 | 97 | } |
1013 | | // else, unknown class type |
1014 | 219 | return -1; |
1015 | 316 | } |
1016 | | |
1017 | | |
1018 | | |
1019 | | // vim: set expandtab shiftwidth=4 |