Coverage Report

Created: 2026-10-12 06:10

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