Coverage Report

Created: 2025-07-18 06:25

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