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