Coverage Report

Created: 2025-11-09 06:04

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