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) 2009-2018 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 is valid
20  */
21 
22 #include "gpsd_config.h"  /* must be before all includes */
23 
24 #include <math.h>
25 #include <stdbool.h>
26 #include <stddef.h>
27 #include <string.h>
28 
29 #include "gpsd.h"
30 #include "strfuncs.h"
31 #ifdef SOCKET_EXPORT_ENABLE
32 #include "gps_json.h"
33 #include "timespec.h"
34 
json_tpv_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)35 static int json_tpv_read(const char *buf, struct gps_data_t *gpsdata,
36                          const char **endptr)
37 {
38     int leapseconds; /* FIXME, unused... */
39     int ret;
40 
41     const struct json_attr_t json_attrs_1[] = {
42         /* *INDENT-OFF* */
43         {"class",  t_check,   .dflt.check = "TPV"},
44         {"device", t_string,  .addr.string = gpsdata->dev.path,
45                                  .len = sizeof(gpsdata->dev.path)},
46         {"time",   t_time,    .addr.ts = &gpsdata->fix.time,
47                                  .dflt.ts = {0, 0}},
48         {"leapseconds",   t_integer, .addr.integer = &leapseconds,
49                                  .dflt.integer = 0},
50         {"ept",    t_real,    .addr.real = &gpsdata->fix.ept,
51                                  .dflt.real = NAN},
52         {"lon",    t_real,    .addr.real = &gpsdata->fix.longitude,
53                                  .dflt.real = NAN},
54         {"lat",    t_real,    .addr.real = &gpsdata->fix.latitude,
55                                  .dflt.real = NAN},
56         {"alt",    t_real,    .addr.real = &gpsdata->fix.altitude,
57                                  .dflt.real = NAN}, // DEPRECATED, undefined
58         {"altHAE",    t_real,  .addr.real = &gpsdata->fix.altHAE,
59                                  .dflt.real = NAN},
60         {"altMSL", t_real,    .addr.real = &gpsdata->fix.altMSL,
61                                  .dflt.real = NAN},
62         {"datum",  t_string,  .addr.string = gpsdata->fix.datum,
63                                  .len = sizeof(gpsdata->fix.datum)},
64         {"epc",    t_real,    .addr.real = &gpsdata->fix.epc,
65                                  .dflt.real = NAN},
66         {"epd",    t_real,    .addr.real = &gpsdata->fix.epd,
67                                  .dflt.real = NAN},
68         {"eph",    t_real,    .addr.real = &gpsdata->fix.eph,
69                                  .dflt.real = NAN},
70         {"eps",    t_real,    .addr.real = &gpsdata->fix.eps,
71                                  .dflt.real = NAN},
72         {"epx",    t_real,    .addr.real = &gpsdata->fix.epx,
73                                  .dflt.real = NAN},
74         {"epy",    t_real,    .addr.real = &gpsdata->fix.epy,
75                                  .dflt.real = NAN},
76         {"epv",    t_real,    .addr.real = &gpsdata->fix.epv,
77                                  .dflt.real = NAN},
78         {"track",  t_real,    .addr.real = &gpsdata->fix.track,
79                                  .dflt.real = NAN},
80         {"magtrack",  t_real,    .addr.real = &gpsdata->fix.magnetic_track,
81                                  .dflt.real = NAN},
82         {"magvar",  t_real,   .addr.real = &gpsdata->fix.magnetic_var,
83                                  .dflt.real = NAN},
84         {"speed",  t_real,    .addr.real = &gpsdata->fix.speed,
85                                  .dflt.real = NAN},
86         {"climb",  t_real,    .addr.real = &gpsdata->fix.climb,
87                                  .dflt.real = NAN},
88         {"ecefx",  t_real,    .addr.real = &gpsdata->fix.ecef.x,
89                                  .dflt.real = NAN},
90         {"ecefy",  t_real,    .addr.real = &gpsdata->fix.ecef.y,
91                                  .dflt.real = NAN},
92         {"ecefz",  t_real,    .addr.real = &gpsdata->fix.ecef.z,
93                                  .dflt.real = NAN},
94         {"ecefvx", t_real,    .addr.real = &gpsdata->fix.ecef.vx,
95                                  .dflt.real = NAN},
96         {"ecefvy", t_real,    .addr.real = &gpsdata->fix.ecef.vy,
97                                  .dflt.real = NAN},
98         {"ecefvz", t_real,    .addr.real = &gpsdata->fix.ecef.vz,
99                                  .dflt.real = NAN},
100         {"ecefpAcc", t_real,  .addr.real = &gpsdata->fix.ecef.vAcc,
101                                  .dflt.real = NAN},
102         {"ecefvAcc", t_real,  .addr.real = &gpsdata->fix.ecef.pAcc,
103                                  .dflt.real = NAN},
104         {"mode",   t_integer, .addr.integer = &gpsdata->fix.mode,
105                                  .dflt.integer = MODE_NOT_SEEN},
106         {"sep",    t_real,    .addr.real = &gpsdata->fix.sep,
107                                  .dflt.real = NAN},
108         {"status", t_integer, .addr.integer = &gpsdata->status,
109                                  .dflt.integer = STATUS_FIX},
110         {"relN", t_real,  .addr.real = &gpsdata->fix.NED.relPosN,
111                                  .dflt.real = NAN},
112         {"relE", t_real,  .addr.real = &gpsdata->fix.NED.relPosE,
113                                  .dflt.real = NAN},
114         {"relD", t_real,  .addr.real = &gpsdata->fix.NED.relPosD,
115                                  .dflt.real = NAN},
116         {"velN", t_real,  .addr.real = &gpsdata->fix.NED.relPosN,
117                                  .dflt.real = NAN},
118         {"velE", t_real,  .addr.real = &gpsdata->fix.NED.relPosE,
119                                  .dflt.real = NAN},
120         {"velD", t_real,  .addr.real = &gpsdata->fix.NED.relPosD,
121                                  .dflt.real = NAN},
122         {"geoidSep", t_real,  .addr.real = &gpsdata->fix.geoid_sep,
123                                  .dflt.real = NAN},
124         {"depth", t_real,  .addr.real = &gpsdata->fix.depth,
125                                  .dflt.real = NAN},
126         {"dgpsAge", t_real, .addr.real = &gpsdata->fix.dgps_age,
127                                  .dflt.real = NAN},
128         {"dgpsSta", t_integer, .addr.integer = &gpsdata->fix.dgps_station,
129                                  .dflt.integer = -1},
130         // ignore unkown keys, for cross-version compatibility
131         {"", t_ignore},
132 
133         {NULL},
134         /* *INDENT-ON* */
135     };
136 
137     ret = json_read_object(buf, json_attrs_1, endptr);
138     return ret;
139 }
140 
json_noise_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)141 static int json_noise_read(const char *buf, struct gps_data_t *gpsdata,
142                            const char **endptr)
143 {
144     int ret;
145 
146     const struct json_attr_t json_attrs_1[] = {
147         /* *INDENT-OFF* */
148         {"class",  t_check,   .dflt.check = "GST"},
149         {"device", t_string,  .addr.string = gpsdata->dev.path,
150                                  .len = sizeof(gpsdata->dev.path)},
151         {"time",   t_time,    .addr.ts = &gpsdata->gst.utctime,
152                                  .dflt.ts = {0, 0}},
153         {"rms",    t_real,    .addr.real = &gpsdata->gst.rms_deviation,
154                                  .dflt.real = NAN},
155         {"major",  t_real,    .addr.real = &gpsdata->gst.smajor_deviation,
156                                  .dflt.real = NAN},
157         {"minor",  t_real,    .addr.real = &gpsdata->gst.sminor_deviation,
158                                  .dflt.real = NAN},
159         {"orient", t_real,    .addr.real = &gpsdata->gst.smajor_orientation,
160                                  .dflt.real = NAN},
161         {"lat",    t_real,    .addr.real = &gpsdata->gst.lat_err_deviation,
162                                  .dflt.real = NAN},
163         {"lon",    t_real,    .addr.real = &gpsdata->gst.lon_err_deviation,
164                                  .dflt.real = NAN},
165         {"alt",    t_real,    .addr.real = &gpsdata->gst.alt_err_deviation,
166                                  .dflt.real = NAN},
167         {NULL},
168         /* *INDENT-ON* */
169     };
170 
171     ret = json_read_object(buf, json_attrs_1, endptr);
172 
173     return ret;
174 }
175 
176 /* decode a RAW messages into gpsdata.raw */
json_raw_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)177 static int json_raw_read(const char *buf, struct gps_data_t *gpsdata,
178                          const char **endptr)
179 {
180     int measurements;
181     double mtime_s, mtime_ns;
182 
183     const struct json_attr_t json_attrs_meas[] = {
184         /* *INDENT-OFF* */
185         {"gnssid",       t_ubyte,    STRUCTOBJECT(struct meas_t, gnssid)},
186         {"svid",         t_ubyte,    STRUCTOBJECT(struct meas_t, svid)},
187         {"sigid",        t_ubyte,    STRUCTOBJECT(struct meas_t, sigid),
188                                      .dflt.ubyte = 0},
189         {"snr",          t_ubyte,    STRUCTOBJECT(struct meas_t, snr)},
190         {"freqid",       t_ubyte,    STRUCTOBJECT(struct meas_t, freqid),
191                                      .dflt.ubyte = 0},
192         {"obs",          t_string,   STRUCTOBJECT(struct meas_t, obs_code),
193                                 .len = sizeof(gpsdata->raw.meas[0].obs_code)},
194         {"lli",          t_ubyte,    STRUCTOBJECT(struct meas_t, lli),
195                                      .dflt.ubyte = 0},
196         {"locktime",     t_uinteger, STRUCTOBJECT(struct meas_t, locktime),
197                                      .dflt.uinteger = 0},
198         {"carrierphase", t_real,     STRUCTOBJECT(struct meas_t, carrierphase),
199                                      .dflt.real = NAN},
200         {"pseudorange",  t_real,     STRUCTOBJECT(struct meas_t, pseudorange),
201                                      .dflt.real = NAN},
202         {"doppler",      t_real,     STRUCTOBJECT(struct meas_t, doppler),
203                                      .dflt.real = NAN},
204         {"c2c",          t_real,     STRUCTOBJECT(struct meas_t, c2c),
205                                     .dflt.real = NAN},
206         {"l2c",          t_real,     STRUCTOBJECT(struct meas_t, l2c),
207                                     .dflt.real = NAN},
208         /* *INDENT-ON* */
209         {NULL},
210     };
211     const struct json_attr_t json_attrs_raw[] = {
212         /* *INDENT-OFF* */
213         {"class",      t_check,   .dflt.check = "RAW"},
214         {"device",     t_string,  .addr.string  = gpsdata->dev.path,
215                                     .len = sizeof(gpsdata->dev.path)},
216         {"time",       t_real,    .addr.real = &mtime_s,
217                                  .dflt.real = NAN},
218         {"nsec",       t_real,    .addr.real = &mtime_ns,
219                                  .dflt.real = NAN},
220         {"rawdata",    t_array,   STRUCTARRAY(gpsdata->raw.meas,
221                                      json_attrs_meas, &measurements)},
222         {NULL},
223         /* *INDENT-ON* */
224     };
225     int status;
226 
227     memset(&gpsdata->raw, 0, sizeof(gpsdata->raw));
228 
229     status = json_read_object(buf, json_attrs_raw, endptr);
230     if (status != 0)
231         return status;
232     if (0 == isfinite(mtime_s) || 0 == isfinite(mtime_ns))
233         return status;
234     gpsdata->raw.mtime.tv_sec = (time_t)mtime_s;
235     gpsdata->raw.mtime.tv_nsec = (long)mtime_ns;
236 
237     return 0;
238 }
239 
json_sky_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)240 static int json_sky_read(const char *buf, struct gps_data_t *gpsdata,
241                          const char **endptr)
242 {
243 
244     const struct json_attr_t json_attrs_satellites[] = {
245         /* *INDENT-OFF* */
246         {"PRN",    t_short,   STRUCTOBJECT(struct satellite_t, PRN)},
247         {"el",     t_real,    STRUCTOBJECT(struct satellite_t, elevation),
248                               .dflt.real = NAN},
249         {"az",     t_real,    STRUCTOBJECT(struct satellite_t, azimuth),
250                               .dflt.real = NAN},
251         {"ss",     t_real,    STRUCTOBJECT(struct satellite_t, ss),
252                               .dflt.real = NAN},
253         {"used",   t_boolean, STRUCTOBJECT(struct satellite_t, used)},
254         {"gnssid", t_ubyte,   STRUCTOBJECT(struct satellite_t, gnssid)},
255         {"svid",   t_ubyte,   STRUCTOBJECT(struct satellite_t, svid)},
256         {"sigid",  t_ubyte,   STRUCTOBJECT(struct satellite_t, sigid)},
257         {"freqid", t_byte,    STRUCTOBJECT(struct satellite_t, freqid),
258                               .dflt.byte = -1},
259         {"health", t_ubyte,   STRUCTOBJECT(struct satellite_t, health),
260                               .dflt.ubyte = SAT_HEALTH_UNK},
261         /* *INDENT-ON* */
262         {NULL},
263     };
264     const struct json_attr_t json_attrs_2[] = {
265         /* *INDENT-OFF* */
266         {"class",      t_check,   .dflt.check = "SKY"},
267         {"device",     t_string,  .addr.string  = gpsdata->dev.path,
268                                      .len = sizeof(gpsdata->dev.path)},
269         {"time",       t_time,    .addr.ts = &gpsdata->skyview_time,
270                                      .dflt.ts = {0, 0}},
271         {"hdop",       t_real,    .addr.real    = &gpsdata->dop.hdop,
272                                      .dflt.real = NAN},
273         {"xdop",       t_real,    .addr.real    = &gpsdata->dop.xdop,
274                                      .dflt.real = NAN},
275         {"ydop",       t_real,    .addr.real    = &gpsdata->dop.ydop,
276                                      .dflt.real = NAN},
277         {"vdop",       t_real,    .addr.real    = &gpsdata->dop.vdop,
278                                      .dflt.real = NAN},
279         {"tdop",       t_real,    .addr.real    = &gpsdata->dop.tdop,
280                                      .dflt.real = NAN},
281         {"pdop",       t_real,    .addr.real    = &gpsdata->dop.pdop,
282                                      .dflt.real = NAN},
283         {"gdop",       t_real,    .addr.real    = &gpsdata->dop.gdop,
284                                      .dflt.real = NAN},
285         {"satellites", t_array,
286                                    STRUCTARRAY(gpsdata->skyview,
287                                          json_attrs_satellites,
288                                          &gpsdata->satellites_visible)},
289         {NULL},
290         /* *INDENT-ON* */
291     };
292     int status, i;
293 
294     memset(&gpsdata->skyview, 0, sizeof(gpsdata->skyview));
295 
296     status = json_read_object(buf, json_attrs_2, endptr);
297     if (status != 0)
298         return status;
299 
300     gpsdata->satellites_used = 0;
301     gpsdata->satellites_visible = 0;
302     for (i = 0; i < MAXCHANNELS; i++) {
303         if(gpsdata->skyview[i].PRN > 0)
304             gpsdata->satellites_visible++;
305         if (gpsdata->skyview[i].used) {
306             gpsdata->satellites_used++;
307         }
308     }
309 
310     return 0;
311 }
312 
json_att_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)313 static int json_att_read(const char *buf, struct gps_data_t *gpsdata,
314                          const char **endptr)
315 {
316     const struct json_attr_t json_attrs_1[] = {
317         /* *INDENT-OFF* */
318         {"class",    t_check,     .dflt.check = "ATT"},
319         {"device",   t_string,    .addr.string = gpsdata->dev.path,
320                                      .len = sizeof(gpsdata->dev.path)},
321         {"heading",  t_real,      .addr.real = &gpsdata->attitude.heading,
322                                      .dflt.real = NAN},
323         {"mag_st",   t_character, .addr.character = &gpsdata->attitude.mag_st},
324         {"pitch",    t_real,      .addr.real = &gpsdata->attitude.pitch,
325                                      .dflt.real = NAN},
326         {"pitch_st", t_character, .addr.character = &gpsdata->attitude.pitch_st},
327         {"roll",     t_real,      .addr.real = &gpsdata->attitude.roll,
328                                      .dflt.real = NAN},
329         {"roll_st",  t_character, .addr.character = &gpsdata->attitude.roll_st},
330         {"yaw",      t_real,      .addr.real = &gpsdata->attitude.yaw,
331                                      .dflt.real = NAN},
332         {"yaw_st",   t_character, .addr.character = &gpsdata->attitude.yaw_st},
333 
334         {"dip",      t_real,      .addr.real = &gpsdata->attitude.dip,
335                                      .dflt.real = NAN},
336         {"mag_len",  t_real,      .addr.real = &gpsdata->attitude.mag_len,
337                                      .dflt.real = NAN},
338         {"mag_x",    t_real,      .addr.real = &gpsdata->attitude.mag_x,
339                                       .dflt.real = NAN},
340         {"mag_y",    t_real,      .addr.real = &gpsdata->attitude.mag_y,
341                                       .dflt.real = NAN},
342         {"mag_z",    t_real,      .addr.real = &gpsdata->attitude.mag_z,
343                                       .dflt.real = NAN},
344         {"acc_len",  t_real,      .addr.real = &gpsdata->attitude.acc_len,
345                                      .dflt.real = NAN},
346         {"acc_x",    t_real,      .addr.real = &gpsdata->attitude.acc_x,
347                                       .dflt.real = NAN},
348         {"acc_y",    t_real,      .addr.real = &gpsdata->attitude.acc_y,
349                                       .dflt.real = NAN},
350         {"acc_z",    t_real,      .addr.real = &gpsdata->attitude.acc_z,
351                                       .dflt.real = NAN},
352         {"gyro_x",    t_real,      .addr.real = &gpsdata->attitude.gyro_x,
353                                       .dflt.real = NAN},
354         {"gyro_y",    t_real,      .addr.real = &gpsdata->attitude.gyro_y,
355                                       .dflt.real = NAN},
356 
357         {"temp", t_real, .addr.real = &gpsdata->attitude.temp,
358                                  .dflt.real = NAN},
359         {"depth",    t_real,    .addr.real = &gpsdata->attitude.depth,
360                                  .dflt.real = NAN},
361         {NULL},
362         /* *INDENT-ON* */
363     };
364 
365     return json_read_object(buf, json_attrs_1, endptr);
366 }
367 
json_devicelist_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)368 static int json_devicelist_read(const char *buf, struct gps_data_t *gpsdata,
369                                 const char **endptr)
370 {
371     const struct json_attr_t json_attrs_subdevices[] = {
372         /* *INDENT-OFF* */
373         {"class",      t_check,      .dflt.check = "DEVICE"},
374         {"path",       t_string,     STRUCTOBJECT(struct devconfig_t, path),
375                                         .len = sizeof(gpsdata->devices.list[0].path)},
376         {"activated",  t_time,       STRUCTOBJECT(struct devconfig_t, activated)},
377         {"activated",  t_real,       STRUCTOBJECT(struct devconfig_t, activated)},
378         {"flags",      t_integer,    STRUCTOBJECT(struct devconfig_t, flags)},
379         {"driver",     t_string,     STRUCTOBJECT(struct devconfig_t, driver),
380                                         .len = sizeof(gpsdata->devices.list[0].driver)},
381         {"hexdata",    t_string,     STRUCTOBJECT(struct devconfig_t, hexdata),
382                                         .len = sizeof(gpsdata->devices.list[0].hexdata)},
383         {"subtype",    t_string,     STRUCTOBJECT(struct devconfig_t, subtype),
384                             .len = sizeof(gpsdata->devices.list[0].subtype)},
385         {"subtype1",   t_string,     STRUCTOBJECT(struct devconfig_t, subtype1),
386                             .len = sizeof(gpsdata->devices.list[0].subtype1)},
387         {"native",     t_integer,    STRUCTOBJECT(struct devconfig_t, driver_mode),
388                                         .dflt.integer = -1},
389         {"bps",        t_uinteger,   STRUCTOBJECT(struct devconfig_t, baudrate),
390                                         .dflt.uinteger = DEVDEFAULT_BPS},
391         {"parity",     t_character,  STRUCTOBJECT(struct devconfig_t, parity),
392                                         .dflt.character = DEVDEFAULT_PARITY},
393         {"stopbits",   t_uinteger,   STRUCTOBJECT(struct devconfig_t, stopbits),
394                                         .dflt.integer = DEVDEFAULT_STOPBITS},
395         {"cycle",      t_real,       STRUCTOBJECT(struct devconfig_t, cycle),
396                                         .dflt.real = NAN},
397         {"mincycle",   t_real,       STRUCTOBJECT(struct devconfig_t, mincycle),
398                                         .dflt.real = NAN},
399         // ignore unkown keys, for cross-version compatibility
400         {"", t_ignore},
401         {NULL},
402         /* *INDENT-ON* */
403     };
404     const struct json_attr_t json_attrs_devices[] = {
405         {"class", t_check,.dflt.check = "DEVICES"},
406         {"devices", t_array, STRUCTARRAY(gpsdata->devices.list,
407                                          json_attrs_subdevices,
408                                          &gpsdata->devices.ndevices)},
409         {NULL},
410     };
411     int status;
412 
413     memset(&gpsdata->devices, 0, sizeof(gpsdata->devices));
414     status = json_read_object(buf, json_attrs_devices, endptr);
415     if (status != 0) {
416         return status;
417     }
418 
419     (void)clock_gettime(CLOCK_REALTIME, &gpsdata->devices.time);
420     return 0;
421 }
422 
json_version_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)423 static int json_version_read(const char *buf, struct gps_data_t *gpsdata,
424                              const char **endptr)
425 {
426     const struct json_attr_t json_attrs_version[] = {
427         /* *INDENT-OFF* */
428         {"class",     t_check,   .dflt.check = "VERSION"},
429         {"release",   t_string,  .addr.string  = gpsdata->version.release,
430                                     .len = sizeof(gpsdata->version.release)},
431         {"rev",       t_string,  .addr.string  = gpsdata->version.rev,
432                                     .len = sizeof(gpsdata->version.rev)},
433         {"proto_major", t_integer, .addr.integer = &gpsdata->version.proto_major},
434         {"proto_minor", t_integer, .addr.integer = &gpsdata->version.proto_minor},
435         {"remote",    t_string,  .addr.string  = gpsdata->version.remote,
436                                     .len = sizeof(gpsdata->version.remote)},
437         {NULL},
438         /* *INDENT-ON* */
439     };
440     int status;
441 
442     memset(&gpsdata->version, 0, sizeof(gpsdata->version));
443     status = json_read_object(buf, json_attrs_version, endptr);
444 
445     return status;
446 }
447 
json_error_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)448 static int json_error_read(const char *buf, struct gps_data_t *gpsdata,
449                            const char **endptr)
450 {
451     const struct json_attr_t json_attrs_error[] = {
452         /* *INDENT-OFF* */
453         {"class",     t_check,   .dflt.check = "ERROR"},
454         {"message",   t_string,  .addr.string  = gpsdata->error,
455                                     .len = sizeof(gpsdata->error)},
456         {NULL},
457         /* *INDENT-ON* */
458     };
459     int status;
460 
461     memset(&gpsdata->error, 0, sizeof(gpsdata->error));
462     status = json_read_object(buf, json_attrs_error, endptr);
463     if (status != 0)
464         return status;
465 
466     return status;
467 }
468 
json_toff_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)469 int json_toff_read(const char *buf, struct gps_data_t *gpsdata,
470                            const char **endptr)
471 {
472     int real_sec = 0, real_nsec = 0, clock_sec = 0, clock_nsec = 0;
473     const struct json_attr_t json_attrs_toff[] = {
474         /* *INDENT-OFF* */
475         {"class",     t_check,   .dflt.check = "TOFF"},
476         {"device",    t_string,  .addr.string = gpsdata->dev.path,
477                                  .len = sizeof(gpsdata->dev.path)},
478         {"real_sec",  t_integer, .addr.integer = &real_sec,
479                                  .dflt.integer = 0},
480         {"real_nsec", t_integer, .addr.integer = &real_nsec,
481                                  .dflt.integer = 0},
482         {"clock_sec", t_integer, .addr.integer = &clock_sec,
483                                  .dflt.integer = 0},
484         {"clock_nsec",t_integer, .addr.integer = &clock_nsec,
485                                  .dflt.integer = 0},
486         {NULL},
487         /* *INDENT-ON* */
488     };
489     int status;
490 
491     memset(&gpsdata->toff, 0, sizeof(gpsdata->toff));
492     status = json_read_object(buf, json_attrs_toff, endptr);
493     gpsdata->toff.real.tv_sec = (time_t)real_sec;
494     gpsdata->toff.real.tv_nsec = (long)real_nsec;
495     gpsdata->toff.clock.tv_sec = (time_t)clock_sec;
496     gpsdata->toff.clock.tv_nsec = (long)clock_nsec;
497     if (status != 0)
498         return status;
499 
500     return status;
501 }
502 
json_pps_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)503 int json_pps_read(const char *buf, struct gps_data_t *gpsdata,
504                   const char **endptr)
505 {
506     int real_sec = 0, real_nsec = 0, clock_sec = 0, clock_nsec = 0, precision=0;
507     int qErr = 0;
508 
509     const struct json_attr_t json_attrs_pps[] = {
510         /* *INDENT-OFF* */
511         {"class",     t_check,   .dflt.check = "PPS"},
512         {"device",    t_string,  .addr.string = gpsdata->dev.path,
513                                  .len = sizeof(gpsdata->dev.path)},
514         {"real_sec",  t_integer, .addr.integer = &real_sec,
515                                  .dflt.integer = 0},
516         {"real_nsec", t_integer, .addr.integer = &real_nsec,
517                                  .dflt.integer = 0},
518         {"clock_sec", t_integer, .addr.integer = &clock_sec,
519                                  .dflt.integer = 0},
520         {"clock_nsec",t_integer, .addr.integer = &clock_nsec,
521                                  .dflt.integer = 0},
522         {"precision", t_integer, .addr.integer = &precision,
523                                  .dflt.integer = 0},
524         {"qErr", t_integer, .addr.integer = &qErr,
525                                  .dflt.integer = 0},
526         {NULL},
527         /* *INDENT-ON* */
528     };
529     int status;
530 
531     memset(&gpsdata->pps, 0, sizeof(gpsdata->pps));
532     status = json_read_object(buf, json_attrs_pps, endptr);
533 
534     /* This is good until GPS are more than nanosec accurate */
535     gpsdata->pps.real.tv_sec = (time_t)real_sec;
536     gpsdata->pps.real.tv_nsec = (long)real_nsec;
537     gpsdata->pps.clock.tv_sec = (time_t)clock_sec;
538     gpsdata->pps.clock.tv_nsec = (long)clock_nsec;
539     // hope qErr fits in int
540     gpsdata->qErr = (long)qErr;
541 
542     /* FIXME: precision is currently parsed but discarded */
543     return status;
544 }
545 
json_oscillator_read(const char * buf,struct gps_data_t * gpsdata,const char ** endptr)546 int json_oscillator_read(const char *buf, struct gps_data_t *gpsdata,
547                          const char **endptr)
548 {
549     bool running = false, reference = false, disciplined = false;
550     int delta = 0;
551     const struct json_attr_t json_attrs_osc[] = {
552         /* *INDENT-OFF* */
553         {"class",       t_check,   .dflt.check = "OSC"},
554         {"device",      t_string,  .addr.string = gpsdata->dev.path,
555                                    .len = sizeof(gpsdata->dev.path)},
556         {"running",     t_boolean, .addr.boolean = &running,
557                                    .dflt.boolean = false},
558         {"reference",   t_boolean, .addr.boolean = &reference,
559                                    .dflt.boolean = false},
560         {"disciplined", t_boolean, .addr.boolean = &disciplined,
561                                    .dflt.boolean = false},
562         {"delta",       t_integer, .addr.integer = &delta,
563                                    .dflt.integer = 0},
564         {NULL},
565         /* *INDENT-ON* */
566     };
567     int status;
568 
569     memset(&gpsdata->osc, 0, sizeof(gpsdata->osc));
570     status = json_read_object(buf, json_attrs_osc, endptr);
571 
572     gpsdata->osc.running = running;
573     gpsdata->osc.reference = reference;
574     gpsdata->osc.disciplined = disciplined;
575     gpsdata->osc.delta = delta;
576 
577     return status;
578 }
579 
580 // Test for JSON read status values that should be treated as a go-ahead
581 // for further processing.  JSON_BADATTR - to allow JSON attributes uknown
582 // to this version of the library, for forward compatibility, is an obvious
583 // thing to go here.
584 #define PASS(n) (((n) == 0) || ((n) == JSON_ERR_BADATTR))
585 #define FILTER(n) ((n) == JSON_ERR_BADATTR ? 0 : n)
586 
libgps_json_unpack(const char * buf,struct gps_data_t * gpsdata,const char ** end)587 int libgps_json_unpack(const char *buf,
588                        struct gps_data_t *gpsdata, const char **end)
589 /* the only entry point - unpack a JSON object into gpsdata_t substructures */
590 {
591     int status;
592     char *classtag = strstr(buf, "\"class\":");
593 
594     if (classtag == NULL)
595         return -1;
596     if (str_starts_with(classtag, "\"class\":\"TPV\"")) {
597         status = json_tpv_read(buf, gpsdata, end);
598         gpsdata->set = STATUS_SET;
599         if (0 != gpsdata->fix.time.tv_sec)
600             gpsdata->set |= TIME_SET;
601         if (isfinite(gpsdata->fix.ept) != 0)
602             gpsdata->set |= TIMERR_SET;
603         if (isfinite(gpsdata->fix.longitude) != 0)
604             gpsdata->set |= LATLON_SET;
605         if (0 != isfinite(gpsdata->fix.altitude) ||
606             0 != isfinite(gpsdata->fix.altHAE) ||
607             0 != isfinite(gpsdata->fix.depth) ||
608             0 != isfinite(gpsdata->fix.altMSL)) {
609             gpsdata->set |= ALTITUDE_SET;
610         }
611         if (isfinite(gpsdata->fix.epx) != 0 && isfinite(gpsdata->fix.epy) != 0)
612             gpsdata->set |= HERR_SET;
613         if (isfinite(gpsdata->fix.epv) != 0)
614             gpsdata->set |= VERR_SET;
615         if (isfinite(gpsdata->fix.track) != 0)
616             gpsdata->set |= TRACK_SET;
617         if (0 != isfinite(gpsdata->fix.magnetic_track) ||
618             0 != isfinite(gpsdata->fix.magnetic_var))
619             gpsdata->set |= MAGNETIC_TRACK_SET;
620         if (isfinite(gpsdata->fix.speed) != 0)
621             gpsdata->set |= SPEED_SET;
622         if (isfinite(gpsdata->fix.climb) != 0)
623             gpsdata->set |= CLIMB_SET;
624         if (isfinite(gpsdata->fix.epd) != 0)
625             gpsdata->set |= TRACKERR_SET;
626         if (isfinite(gpsdata->fix.eps) != 0)
627             gpsdata->set |= SPEEDERR_SET;
628         if (isfinite(gpsdata->fix.epc) != 0)
629             gpsdata->set |= CLIMBERR_SET;
630         if (gpsdata->fix.mode != MODE_NOT_SEEN)
631             gpsdata->set |= MODE_SET;
632         return FILTER(status);
633     } else if (str_starts_with(classtag, "\"class\":\"GST\"")) {
634         status = json_noise_read(buf, gpsdata, end);
635         if (PASS(status)) {
636             gpsdata->set &= ~UNION_SET;
637             gpsdata->set |= GST_SET;
638         }
639         return FILTER(status);
640     } else if (str_starts_with(classtag, "\"class\":\"SKY\"")) {
641         status = json_sky_read(buf, gpsdata, end);
642         if (PASS(status))
643             gpsdata->set |= SATELLITE_SET;
644         return FILTER(status);
645     } else if (str_starts_with(classtag, "\"class\":\"ATT\"")) {
646         status = json_att_read(buf, gpsdata, end);
647         if (PASS(status)) {
648             gpsdata->set &= ~UNION_SET;
649             gpsdata->set |= ATTITUDE_SET;
650         }
651         return FILTER(status);
652     } else if (str_starts_with(classtag, "\"class\":\"DEVICES\"")) {
653         status = json_devicelist_read(buf, gpsdata, end);
654         if (PASS(status)) {
655             gpsdata->set &= ~UNION_SET;
656             gpsdata->set |= DEVICELIST_SET;
657         }
658         return FILTER(status);
659     } else if (str_starts_with(classtag, "\"class\":\"DEVICE\"")) {
660         status = json_device_read(buf, &gpsdata->dev, end);
661         if (PASS(status))
662             gpsdata->set |= DEVICE_SET;
663         return FILTER(status);
664     } else if (str_starts_with(classtag, "\"class\":\"WATCH\"")) {
665         status = json_watch_read(buf, &gpsdata->policy, end);
666         if (PASS(status)) {
667             gpsdata->set &= ~UNION_SET;
668             gpsdata->set |= POLICY_SET;
669         }
670         return FILTER(status);
671     } else if (str_starts_with(classtag, "\"class\":\"VERSION\"")) {
672         status = json_version_read(buf, gpsdata, end);
673         if (status ==  0) {
674             gpsdata->set &= ~UNION_SET;
675             gpsdata->set |= VERSION_SET;
676         }
677         return FILTER(status);
678 #ifdef RTCM104V2_ENABLE
679     } else if (str_starts_with(classtag, "\"class\":\"RTCM2\"")) {
680         status = json_rtcm2_read(buf,
681                                  gpsdata->dev.path, sizeof(gpsdata->dev.path),
682                                  &gpsdata->rtcm2, end);
683         if (PASS(status)) {
684             gpsdata->set &= ~UNION_SET;
685             gpsdata->set |= RTCM2_SET;
686         }
687         return FILTER(status);
688 #endif /* RTCM104V2_ENABLE */
689 #ifdef RTCM104V3_ENABLE
690     } else if (str_starts_with(classtag, "\"class\":\"RTCM3\"")) {
691         status = json_rtcm3_read(buf,
692                                  gpsdata->dev.path, sizeof(gpsdata->dev.path),
693                                  &gpsdata->rtcm3, end);
694         if (PASS(status)) {
695             gpsdata->set &= ~UNION_SET;
696             gpsdata->set |= RTCM3_SET;
697         }
698         return FILTER(status);
699 #endif /* RTCM104V3_ENABLE */
700 #ifdef AIVDM_ENABLE
701     } else if (str_starts_with(classtag, "\"class\":\"AIS\"")) {
702         status = json_ais_read(buf,
703                                gpsdata->dev.path, sizeof(gpsdata->dev.path),
704                                &gpsdata->ais, end);
705         if (PASS(status)) {
706             gpsdata->set &= ~UNION_SET;
707             gpsdata->set |= AIS_SET;
708         }
709         return FILTER(status);
710 #endif /* AIVDM_ENABLE */
711     } else if (str_starts_with(classtag, "\"class\":\"ERROR\"")) {
712         status = json_error_read(buf, gpsdata, end);
713         if (PASS(status)) {
714             gpsdata->set &= ~UNION_SET;
715             gpsdata->set |= ERROR_SET;
716         }
717         return FILTER(status);
718     } else if (str_starts_with(classtag, "\"class\":\"TOFF\"")) {
719         status = json_pps_read(buf, gpsdata, end);
720         if (PASS(status)) {
721             gpsdata->set &= ~UNION_SET;
722             gpsdata->set |= TOFF_SET;
723         }
724         return FILTER(status);
725     } else if (str_starts_with(classtag, "\"class\":\"PPS\"")) {
726         status = json_pps_read(buf, gpsdata, end);
727         if (PASS(status)) {
728             gpsdata->set &= ~UNION_SET;
729             gpsdata->set |= PPS_SET;
730         }
731         return FILTER(status);
732     } else if (str_starts_with(classtag, "\"class\":\"OSC\"")) {
733         status = json_oscillator_read(buf, gpsdata, end);
734         if (PASS(status)) {
735             gpsdata->set &= ~UNION_SET;
736             gpsdata->set |= OSCILLATOR_SET;
737         }
738         return FILTER(status);
739     } else if (str_starts_with(classtag, "\"class\":\"RAW\"")) {
740         status = json_raw_read(buf, gpsdata, end);
741         if (PASS(status)) {
742             gpsdata->set &= ~UNION_SET;
743             gpsdata->set |= RAW_SET;
744         }
745         return FILTER(status);
746     } else
747         return -1;
748 }
749 
750 
751 #endif /* SOCKET_EXPORT_ENABLE */
752 
753 /* libgps_json.c ends here */
754