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