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