1 /****************************************************************************
4 libgps_json.c - deserialize gpsd data coming from the server
7 This module uses the generic JSON parser to get data from JSON
8 representations to libgps structures.
11 Written by Eric S. Raymond, 2009
12 This file is Copyright (c) 2010 by the GPSD project
13 BSD terms apply: see the file COPYING in the distribution root for details.
15 ***************************************************************************/
27 * There's a splint limitation that parameters can be declared
28 * @out@ or @null@ but not, apparently, both. This collides with
29 * the (admittedly tricky) way we use endptr. The workaround is to
30 * declare it @null@ and use -compdef around the JSON reader calls.
34 static int json_tpv_read(const char *buf, struct gps_data_t *gpsdata,
35 /*@null@*/ const char **endptr)
38 /*@ -fullinitblock @*/
39 const struct json_attr_t json_attrs_1[] = {
41 {"class", t_check, .dflt.check = "TPV"},
42 {"device", t_string, .addr.string = gpsdata->dev.path,
43 .len = sizeof(gpsdata->dev.path)},
44 {"tag", t_string, .addr.string = gpsdata->tag,
45 .len = sizeof(gpsdata->tag)},
46 {"time", t_real, .addr.real = &gpsdata->fix.time,
48 {"ept", t_real, .addr.real = &gpsdata->fix.ept,
50 {"lon", t_real, .addr.real = &gpsdata->fix.longitude,
52 {"lat", t_real, .addr.real = &gpsdata->fix.latitude,
54 {"alt", t_real, .addr.real = &gpsdata->fix.altitude,
56 {"epx", t_real, .addr.real = &gpsdata->fix.epx,
58 {"epy", t_real, .addr.real = &gpsdata->fix.epy,
60 {"epv", t_real, .addr.real = &gpsdata->fix.epv,
62 {"track", t_real, .addr.real = &gpsdata->fix.track,
64 {"speed", t_real, .addr.real = &gpsdata->fix.speed,
66 {"climb", t_real, .addr.real = &gpsdata->fix.climb,
68 {"epd", t_real, .addr.real = &gpsdata->fix.epd,
70 {"eps", t_real, .addr.real = &gpsdata->fix.eps,
72 {"epc", t_real, .addr.real = &gpsdata->fix.epc,
74 {"mode", t_integer, .addr.integer = &gpsdata->fix.mode,
75 .dflt.integer = MODE_NOT_SEEN},
79 /*@ +fullinitblock @*/
81 status = json_read_object(buf, json_attrs_1, endptr);
84 gpsdata->status = STATUS_FIX;
85 gpsdata->set = STATUS_SET;
86 if (isnan(gpsdata->fix.time) == 0)
87 gpsdata->set |= TIME_SET;
88 if (isnan(gpsdata->fix.ept) == 0)
89 gpsdata->set |= TIMERR_SET;
90 if (isnan(gpsdata->fix.longitude) == 0)
91 gpsdata->set |= LATLON_SET;
92 if (isnan(gpsdata->fix.altitude) == 0)
93 gpsdata->set |= ALTITUDE_SET;
94 if (isnan(gpsdata->fix.epx) == 0 && isnan(gpsdata->fix.epy) == 0)
95 gpsdata->set |= HERR_SET;
96 if (isnan(gpsdata->fix.epv) == 0)
97 gpsdata->set |= VERR_SET;
98 if (isnan(gpsdata->fix.track) == 0)
99 gpsdata->set |= TRACK_SET;
100 if (isnan(gpsdata->fix.speed) == 0)
101 gpsdata->set |= SPEED_SET;
102 if (isnan(gpsdata->fix.climb) == 0)
103 gpsdata->set |= CLIMB_SET;
104 if (isnan(gpsdata->fix.epd) == 0)
105 gpsdata->set |= TRACKERR_SET;
106 if (isnan(gpsdata->fix.eps) == 0)
107 gpsdata->set |= SPEEDERR_SET;
108 if (isnan(gpsdata->fix.epc) == 0)
109 gpsdata->set |= CLIMBERR_SET;
110 if (isnan(gpsdata->fix.epc) == 0)
111 gpsdata->set |= CLIMBERR_SET;
112 if (gpsdata->fix.mode != MODE_NOT_SEEN)
113 gpsdata->set |= MODE_SET;
118 static int json_sky_read(const char *buf, struct gps_data_t *gpsdata,
119 /*@null@*/ const char **endptr)
121 bool usedflags[MAXCHANNELS];
122 /*@ -fullinitblock @*/
123 const struct json_attr_t json_attrs_2_1[] = {
125 {"PRN", t_integer, .addr.integer = gpsdata->PRN},
126 {"el", t_integer, .addr.integer = gpsdata->elevation},
127 {"az", t_integer, .addr.integer = gpsdata->azimuth},
128 {"ss", t_real, .addr.real = gpsdata->ss},
129 {"used", t_boolean, .addr.boolean = usedflags},
133 const struct json_attr_t json_attrs_2[] = {
135 {"class", t_check, .dflt.check = "SKY"},
136 {"device", t_string, .addr.string = gpsdata->dev.path,
137 .len = sizeof(gpsdata->dev.path)},
138 {"tag", t_string, .addr.string = gpsdata->tag,
139 .len = sizeof(gpsdata->tag)},
140 {"time", t_real, .addr.real = &gpsdata->fix.time,
142 {"hdop", t_real, .addr.real = &gpsdata->dop.hdop,
144 {"xdop", t_real, .addr.real = &gpsdata->dop.xdop,
146 {"ydop", t_real, .addr.real = &gpsdata->dop.ydop,
148 {"vdop", t_real, .addr.real = &gpsdata->dop.vdop,
150 {"tdop", t_real, .addr.real = &gpsdata->dop.tdop,
152 {"pdop", t_real, .addr.real = &gpsdata->dop.pdop,
154 {"gdop", t_real, .addr.real = &gpsdata->dop.gdop,
156 {"satellites", t_array, .addr.array.element_type = t_object,
157 .addr.array.arr.objects.subtype=json_attrs_2_1,
158 .addr.array.maxlen = MAXCHANNELS,
159 .addr.array.count = &gpsdata->satellites_visible},
163 /*@ +fullinitblock @*/
166 for (i = 0; i < MAXCHANNELS; i++)
167 usedflags[i] = false;
169 status = json_read_object(buf, json_attrs_2, endptr);
173 gpsdata->satellites_used = 0;
174 for (i = j = 0; i < MAXCHANNELS; i++) {
176 gpsdata->used[j++] = gpsdata->PRN[i];
177 gpsdata->satellites_used++;
181 gpsdata->set |= SATELLITE_SET;
185 static int json_att_read(const char *buf, struct gps_data_t *gpsdata,
186 /*@null@*/ const char **endptr)
188 /*@ -fullinitblock @*/
189 const struct json_attr_t json_attrs_1[] = {
191 {"class", t_check, .dflt.check = "ATT"},
192 {"device", t_string, .addr.string = gpsdata->dev.path,
193 .len = sizeof(gpsdata->dev.path)},
194 {"tag", t_string, .addr.string = gpsdata->tag,
195 .len = sizeof(gpsdata->tag)},
196 {"heading", t_real, .addr.real = &gpsdata->attitude.heading,
198 {"mag_st", t_character, .addr.character = &gpsdata->attitude.mag_st},
199 {"pitch", t_real, .addr.real = &gpsdata->attitude.pitch,
201 {"pitch_st", t_character, .addr.character = &gpsdata->attitude.pitch_st},
202 {"roll", t_real, .addr.real = &gpsdata->attitude.roll,
204 {"roll_st", t_character, .addr.character = &gpsdata->attitude.roll_st},
205 {"yaw", t_real, .addr.real = &gpsdata->attitude.yaw,
207 {"yaw_st", t_character, .addr.character = &gpsdata->attitude.yaw_st},
209 {"mag_len", t_real, .addr.real = &gpsdata->attitude.mag_len,
211 {"mag_x", t_real, .addr.real = &gpsdata->attitude.mag_x,
213 {"mag_y", t_real, .addr.real = &gpsdata->attitude.mag_y,
215 {"mag_z", t_real, .addr.real = &gpsdata->attitude.mag_z,
217 {"acc_len", t_real, .addr.real = &gpsdata->attitude.acc_len,
219 {"acc_x", t_real, .addr.real = &gpsdata->attitude.acc_x,
221 {"acc_y", t_real, .addr.real = &gpsdata->attitude.acc_y,
223 {"acc_z", t_real, .addr.real = &gpsdata->attitude.acc_z,
225 {"gyro_x", t_real, .addr.real = &gpsdata->attitude.gyro_x,
227 {"gyro_y", t_real, .addr.real = &gpsdata->attitude.gyro_y,
230 {"temp", t_real, .addr.real = &gpsdata->attitude.temp,
232 {"depth", t_real, .addr.real = &gpsdata->attitude.depth,
237 /*@ +fullinitblock @*/
239 return json_read_object(buf, json_attrs_1, endptr);
242 static int json_devicelist_read(const char *buf, struct gps_data_t *gpsdata,
243 /*@null@*/ const char **endptr)
245 /*@ -fullinitblock @*/
246 const struct json_attr_t json_attrs_subdevices[] = {
248 {"class", t_check, .dflt.check = "DEVICE"},
249 {"path", t_string, STRUCTOBJECT(struct devconfig_t, path),
250 .len = sizeof(gpsdata->devices.list[0].path)},
251 {"activated", t_real, STRUCTOBJECT(struct devconfig_t, activated)},
252 {"flags", t_integer, STRUCTOBJECT(struct devconfig_t, flags)},
253 {"driver", t_string, STRUCTOBJECT(struct devconfig_t, driver),
254 .len = sizeof(gpsdata->devices.list[0].driver)},
255 {"subtype", t_string, STRUCTOBJECT(struct devconfig_t, subtype),
256 .len = sizeof(gpsdata->devices.list[0].subtype)},
257 {"native", t_integer, STRUCTOBJECT(struct devconfig_t, driver_mode),
259 {"bps", t_integer, STRUCTOBJECT(struct devconfig_t, baudrate),
261 {"parity", t_character, STRUCTOBJECT(struct devconfig_t, parity),
262 .dflt.character = 'N'},
263 {"stopbits", t_integer, STRUCTOBJECT(struct devconfig_t, stopbits),
265 {"cycle", t_real, STRUCTOBJECT(struct devconfig_t, cycle),
267 {"mincycle", t_real, STRUCTOBJECT(struct devconfig_t, mincycle),
272 /*@-type@*//* STRUCTARRAY confuses splint */
273 const struct json_attr_t json_attrs_devices[] = {
274 {"class", t_check,.dflt.check = "DEVICES"},
275 {"devices", t_array, STRUCTARRAY(gpsdata->devices.list,
276 json_attrs_subdevices,
277 &gpsdata->devices.ndevices)},
281 /*@ +fullinitblock @*/
284 memset(&gpsdata->devices, '\0', sizeof(gpsdata->devices));
285 status = json_read_object(buf, json_attrs_devices, endptr);
290 gpsdata->devices.time = timestamp();
291 gpsdata->set &= ~UNION_SET;
292 gpsdata->set |= DEVICELIST_SET;
296 static int json_version_read(const char *buf, struct gps_data_t *gpsdata,
297 /*@null@*/ const char **endptr)
299 /*@ -fullinitblock @*/
300 const struct json_attr_t json_attrs_version[] = {
302 {"class", t_check, .dflt.check = "VERSION"},
303 {"release", t_string, .addr.string = gpsdata->version.release,
304 .len = sizeof(gpsdata->version.release)},
305 {"rev", t_string, .addr.string = gpsdata->version.rev,
306 .len = sizeof(gpsdata->version.rev)},
307 {"proto_major", t_integer, .addr.integer = &gpsdata->version.proto_major},
308 {"proto_minor", t_integer, .addr.integer = &gpsdata->version.proto_minor},
312 /*@ +fullinitblock @*/
315 memset(&gpsdata->version, '\0', sizeof(gpsdata->version));
316 status = json_read_object(buf, json_attrs_version, endptr);
320 gpsdata->set &= ~UNION_SET;
321 gpsdata->set |= VERSION_SET;
325 static int json_error_read(const char *buf, struct gps_data_t *gpsdata,
326 /*@null@*/ const char **endptr)
328 /*@ -fullinitblock @*/
329 const struct json_attr_t json_attrs_error[] = {
331 {"class", t_check, .dflt.check = "ERROR"},
332 {"message", t_string, .addr.string = gpsdata->error,
333 .len = sizeof(gpsdata->error)},
337 /*@ +fullinitblock @*/
340 memset(&gpsdata->error, '\0', sizeof(gpsdata->error));
341 status = json_read_object(buf, json_attrs_error, endptr);
345 gpsdata->set &= ~UNION_SET;
346 gpsdata->set |= ERROR_SET;
350 int libgps_json_unpack(const char *buf,
351 struct gps_data_t *gpsdata, const char **end)
352 /* the only entry point - unpack a JSON object into gpsdata_t substructures */
355 char *classtag = strstr(buf, "\"class\":");
357 if (classtag == NULL)
359 #define STARTSWITH(str, prefix) strncmp(str, prefix, sizeof(prefix)-1)==0
360 if (STARTSWITH(classtag, "\"class\":\"TPV\"")) {
361 return json_tpv_read(buf, gpsdata, end);
362 } else if (STARTSWITH(classtag, "\"class\":\"SKY\"")) {
363 return json_sky_read(buf, gpsdata, end);
364 } else if (STARTSWITH(classtag, "\"class\":\"ATT\"")) {
365 return json_att_read(buf, gpsdata, end);
366 } else if (STARTSWITH(classtag, "\"class\":\"DEVICES\"")) {
367 return json_devicelist_read(buf, gpsdata, end);
368 } else if (STARTSWITH(classtag, "\"class\":\"DEVICE\"")) {
369 status = json_device_read(buf, &gpsdata->dev, end);
371 gpsdata->set |= DEVICE_SET;
373 } else if (STARTSWITH(classtag, "\"class\":\"WATCH\"")) {
374 status = json_watch_read(buf, &gpsdata->policy, end);
376 gpsdata->set |= POLICY_SET;
378 } else if (STARTSWITH(classtag, "\"class\":\"VERSION\"")) {
379 return json_version_read(buf, gpsdata, end);
380 #ifdef RTCM104V2_ENABLE
381 } else if (STARTSWITH(classtag, "\"class\":\"RTCM2\"")) {
382 status = json_rtcm2_read(buf,
383 gpsdata->dev.path, sizeof(gpsdata->dev.path),
384 &gpsdata->rtcm2, end);
386 gpsdata->set &= ~UNION_SET;
387 gpsdata->set |= RTCM2_SET;
390 #endif /* RTCM104V2_ENABLE */
392 } else if (STARTSWITH(classtag, "\"class\":\"AIS\"")) {
393 status = json_ais_read(buf,
394 gpsdata->dev.path, sizeof(gpsdata->dev.path),
397 gpsdata->set &= ~UNION_SET;
398 gpsdata->set |= AIS_SET;
401 #endif /* AIVDM_ENABLE */
402 } else if (STARTSWITH(classtag, "\"class\":\"ERROR\"")) {
403 return json_error_read(buf, gpsdata, end);
411 /* libgps_json.c ends here */