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