cleanup specfile for packaging
[profile/ivi/gpsd.git] / libgps_json.c
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 (c) 2010 by the GPSD project
13    BSD terms apply: see the file COPYING in the distribution root for details.
14
15 ***************************************************************************/
16
17 #include <math.h>
18 #include <assert.h>
19 #include <string.h>
20 #include <stddef.h>
21 #include <stdio.h>
22
23 #include "gpsd.h"
24 #include "gps_json.h"
25
26 /*
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.
31  */
32 /*@-compdef@*/
33
34 static int json_tpv_read(const char *buf, struct gps_data_t *gpsdata,
35                          /*@null@*/ const char **endptr)
36 {
37     int status;
38     /*@ -fullinitblock @*/
39     const struct json_attr_t json_attrs_1[] = {
40         /* *INDENT-OFF* */
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,
47                                  .dflt.real = NAN},
48         {"ept",    t_real,    .addr.real = &gpsdata->fix.ept,
49                                  .dflt.real = NAN},
50         {"lon",    t_real,    .addr.real = &gpsdata->fix.longitude,
51                                  .dflt.real = NAN},
52         {"lat",    t_real,    .addr.real = &gpsdata->fix.latitude,
53                                  .dflt.real = NAN},
54         {"alt",    t_real,    .addr.real = &gpsdata->fix.altitude,
55                                  .dflt.real = NAN},
56         {"epx",    t_real,    .addr.real = &gpsdata->fix.epx,
57                                  .dflt.real = NAN},
58         {"epy",    t_real,    .addr.real = &gpsdata->fix.epy,
59                                  .dflt.real = NAN},
60         {"epv",    t_real,    .addr.real = &gpsdata->fix.epv,
61                                  .dflt.real = NAN},
62         {"track",   t_real,   .addr.real = &gpsdata->fix.track,
63                                  .dflt.real = NAN},
64         {"speed",   t_real,   .addr.real = &gpsdata->fix.speed,
65                                  .dflt.real = NAN},
66         {"climb",   t_real,   .addr.real = &gpsdata->fix.climb,
67                                  .dflt.real = NAN},
68         {"epd",    t_real,    .addr.real = &gpsdata->fix.epd,
69                                  .dflt.real = NAN},
70         {"eps",    t_real,    .addr.real = &gpsdata->fix.eps,
71                                  .dflt.real = NAN},
72         {"epc",    t_real,    .addr.real = &gpsdata->fix.epc,
73                                  .dflt.real = NAN},
74         {"mode",   t_integer, .addr.integer = &gpsdata->fix.mode,
75                                  .dflt.integer = MODE_NOT_SEEN},
76         {NULL},
77         /* *INDENT-ON* */
78     };
79     /*@ +fullinitblock @*/
80
81     status = json_read_object(buf, json_attrs_1, endptr);
82
83     if (status == 0) {
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;
114     }
115     return status;
116 }
117
118 static int json_sky_read(const char *buf, struct gps_data_t *gpsdata,
119                          /*@null@*/ const char **endptr)
120 {
121     bool usedflags[MAXCHANNELS];
122     /*@ -fullinitblock @*/
123     const struct json_attr_t json_attrs_2_1[] = {
124         /* *INDENT-OFF* */
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},
130         /* *INDENT-ON* */
131         {NULL},
132     };
133     const struct json_attr_t json_attrs_2[] = {
134         /* *INDENT-OFF* */
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,
141                                      .nodefault = true},
142         {"hdop",       t_real,    .addr.real    = &gpsdata->dop.hdop,
143                                      .dflt.real = NAN},
144         {"xdop",       t_real,    .addr.real    = &gpsdata->dop.xdop,
145                                      .dflt.real = NAN},
146         {"ydop",       t_real,    .addr.real    = &gpsdata->dop.ydop,
147                                      .dflt.real = NAN},
148         {"vdop",       t_real,    .addr.real    = &gpsdata->dop.vdop,
149                                      .dflt.real = NAN},
150         {"tdop",       t_real,    .addr.real    = &gpsdata->dop.tdop,
151                                      .dflt.real = NAN},
152         {"pdop",       t_real,    .addr.real    = &gpsdata->dop.pdop,
153                                      .dflt.real = NAN},
154         {"gdop",       t_real,    .addr.real    = &gpsdata->dop.gdop,
155                                      .dflt.real = NAN},
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},
160         {NULL},
161         /* *INDENT-ON* */
162     };
163     /*@ +fullinitblock @*/
164     int status, i, j;
165
166     for (i = 0; i < MAXCHANNELS; i++)
167         usedflags[i] = false;
168
169     status = json_read_object(buf, json_attrs_2, endptr);
170     if (status != 0)
171         return status;
172
173     gpsdata->satellites_used = 0;
174     for (i = j = 0; i < MAXCHANNELS; i++) {
175         if (usedflags[i]) {
176             gpsdata->used[j++] = gpsdata->PRN[i];
177             gpsdata->satellites_used++;
178         }
179     }
180
181     gpsdata->set |= SATELLITE_SET;
182     return 0;
183 }
184
185 static int json_att_read(const char *buf, struct gps_data_t *gpsdata,
186                          /*@null@*/ const char **endptr)
187 {
188     /*@ -fullinitblock @*/
189     const struct json_attr_t json_attrs_1[] = {
190         /* *INDENT-OFF* */
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,
197                                      .dflt.real = NAN},
198         {"mag_st",   t_character, .addr.character = &gpsdata->attitude.mag_st},
199         {"pitch",    t_real,      .addr.real = &gpsdata->attitude.pitch,
200                                      .dflt.real = NAN},
201         {"pitch_st", t_character, .addr.character = &gpsdata->attitude.pitch_st},
202         {"roll",     t_real,      .addr.real = &gpsdata->attitude.roll,
203                                      .dflt.real = NAN},
204         {"roll_st",  t_character, .addr.character = &gpsdata->attitude.roll_st},
205         {"yaw",      t_real,      .addr.real = &gpsdata->attitude.yaw,
206                                      .dflt.real = NAN},
207         {"yaw_st",   t_character, .addr.character = &gpsdata->attitude.yaw_st},
208
209         {"mag_len",  t_real,      .addr.real = &gpsdata->attitude.mag_len,
210                                      .dflt.real = NAN},
211         {"mag_x",    t_real,      .addr.real = &gpsdata->attitude.mag_x,
212                                       .dflt.real = NAN},
213         {"mag_y",    t_real,      .addr.real = &gpsdata->attitude.mag_y,
214                                       .dflt.real = NAN},
215         {"mag_z",    t_real,      .addr.real = &gpsdata->attitude.mag_z,
216                                       .dflt.real = NAN},
217         {"acc_len",  t_real,      .addr.real = &gpsdata->attitude.acc_len,
218                                      .dflt.real = NAN},
219         {"acc_x",    t_real,      .addr.real = &gpsdata->attitude.acc_x,
220                                       .dflt.real = NAN},
221         {"acc_y",    t_real,      .addr.real = &gpsdata->attitude.acc_y,
222                                       .dflt.real = NAN},
223         {"acc_z",    t_real,      .addr.real = &gpsdata->attitude.acc_z,
224                                       .dflt.real = NAN},
225         {"gyro_x",    t_real,      .addr.real = &gpsdata->attitude.gyro_x,
226                                       .dflt.real = NAN},
227         {"gyro_y",    t_real,      .addr.real = &gpsdata->attitude.gyro_y,
228                                       .dflt.real = NAN},
229
230         {"temp", t_real, .addr.real = &gpsdata->attitude.temp,
231                                  .dflt.real = NAN},
232         {"depth",    t_real,    .addr.real = &gpsdata->attitude.depth,
233                                  .dflt.real = NAN},
234         {NULL},
235         /* *INDENT-ON* */
236     };
237     /*@ +fullinitblock @*/
238
239     return json_read_object(buf, json_attrs_1, endptr);
240 }
241
242 static int json_devicelist_read(const char *buf, struct gps_data_t *gpsdata,
243                                 /*@null@*/ const char **endptr)
244 {
245     /*@ -fullinitblock @*/
246     const struct json_attr_t json_attrs_subdevices[] = {
247         /* *INDENT-OFF* */
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),
258                                         .dflt.integer = -1},
259         {"bps",        t_integer,    STRUCTOBJECT(struct devconfig_t, baudrate),
260                                         .dflt.integer = -1},
261         {"parity",     t_character,  STRUCTOBJECT(struct devconfig_t, parity),
262                                         .dflt.character = 'N'},
263         {"stopbits",   t_integer,    STRUCTOBJECT(struct devconfig_t, stopbits),
264                                         .dflt.integer = -1},
265         {"cycle",      t_real,       STRUCTOBJECT(struct devconfig_t, cycle),
266                                         .dflt.real = NAN},
267         {"mincycle",   t_real,       STRUCTOBJECT(struct devconfig_t, mincycle),
268                                         .dflt.real = NAN},
269         {NULL},
270         /* *INDENT-ON* */
271     };
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)},
278         {NULL},
279     };
280     /*@+type@*/
281     /*@ +fullinitblock @*/
282     int status;
283
284     memset(&gpsdata->devices, '\0', sizeof(gpsdata->devices));
285     status = json_read_object(buf, json_attrs_devices, endptr);
286     if (status != 0) {
287         return status;
288     }
289
290     gpsdata->devices.time = timestamp();
291     gpsdata->set &= ~UNION_SET;
292     gpsdata->set |= DEVICELIST_SET;
293     return 0;
294 }
295
296 static int json_version_read(const char *buf, struct gps_data_t *gpsdata,
297                              /*@null@*/ const char **endptr)
298 {
299     /*@ -fullinitblock @*/
300     const struct json_attr_t json_attrs_version[] = {
301         /* *INDENT-OFF* */
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},
309         {NULL},
310         /* *INDENT-ON* */
311     };
312     /*@ +fullinitblock @*/
313     int status;
314
315     memset(&gpsdata->version, '\0', sizeof(gpsdata->version));
316     status = json_read_object(buf, json_attrs_version, endptr);
317     if (status != 0)
318         return status;
319
320     gpsdata->set &= ~UNION_SET;
321     gpsdata->set |= VERSION_SET;
322     return 0;
323 }
324
325 static int json_error_read(const char *buf, struct gps_data_t *gpsdata,
326                            /*@null@*/ const char **endptr)
327 {
328     /*@ -fullinitblock @*/
329     const struct json_attr_t json_attrs_error[] = {
330         /* *INDENT-OFF* */
331         {"class",     t_check,   .dflt.check = "ERROR"},
332         {"message",   t_string,  .addr.string  = gpsdata->error,
333                                     .len = sizeof(gpsdata->error)},
334         {NULL},
335         /* *INDENT-ON* */
336     };
337     /*@ +fullinitblock @*/
338     int status;
339
340     memset(&gpsdata->error, '\0', sizeof(gpsdata->error));
341     status = json_read_object(buf, json_attrs_error, endptr);
342     if (status != 0)
343         return status;
344
345     gpsdata->set &= ~UNION_SET;
346     gpsdata->set |= ERROR_SET;
347     return 0;
348 }
349
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 */
353 {
354     int status;
355     char *classtag = strstr(buf, "\"class\":");
356
357     if (classtag == NULL)
358         return -1;
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);
370         if (status == 0)
371             gpsdata->set |= DEVICE_SET;
372         return status;
373     } else if (STARTSWITH(classtag, "\"class\":\"WATCH\"")) {
374         status = json_watch_read(buf, &gpsdata->policy, end);
375         if (status == 0)
376             gpsdata->set |= POLICY_SET;
377         return status;
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);
385         if (status == 0) {
386             gpsdata->set &= ~UNION_SET;
387             gpsdata->set |= RTCM2_SET;
388         }
389         return status;
390 #endif /* RTCM104V2_ENABLE */
391 #ifdef AIVDM_ENABLE
392     } else if (STARTSWITH(classtag, "\"class\":\"AIS\"")) {
393         status = json_ais_read(buf,
394                                gpsdata->dev.path, sizeof(gpsdata->dev.path),
395                                &gpsdata->ais, end);
396         if (status == 0) {
397             gpsdata->set &= ~UNION_SET;
398             gpsdata->set |= AIS_SET;
399         }
400         return status;
401 #endif /* AIVDM_ENABLE */
402     } else if (STARTSWITH(classtag, "\"class\":\"ERROR\"")) {
403         return json_error_read(buf, gpsdata, end);
404     } else
405         return -1;
406 #undef STARTSWITH
407 }
408
409 /*@+compdef@*/
410
411 /* libgps_json.c ends here */