Coverage Report

Created: 2026-03-03 06:57

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