Coverage Report

Created: 2026-10-10 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/libgps/rtcm2_json.c
Line
Count
Source
1
/****************************************************************************
2
3
NAME
4
   rtcm2_json.c - deserialize RTCM2 JSON
5
6
DESCRIPTION
7
   This module uses the generic JSON parser to get data from RTCM2
8
representations to libgps structures.
9
10
PERMISSIONS
11
   This file is Copyright by the GPSD project
12
   SPDX-License-Identifier: BSD-2-clause
13
14
***************************************************************************/
15
16
#include "../include/gpsd_config.h"  // must be before all includes
17
18
#include <math.h>
19
#include <stddef.h>
20
#include <stdio.h>
21
#include <string.h>
22
23
#include "../include/gpsd.h"
24
25
#include "../include/gps_json.h"
26
27
// common fields in every RTCM2 message
28
29
int json_rtcm2_read(const char *buf,
30
                    char *path, size_t pathlen, struct rtcm2_t *rtcm2,
31
                    const char **endptr)
32
309
{
33
34
    // Why are these static???
35
309
    static char *stringptrs[NITEMS(rtcm2->words)];
36
309
    static char stringstore[sizeof(rtcm2->words) * 2];
37
309
    static unsigned stringcount;
38
39
// *INDENT-OFF*
40
309
#define RTCM2_HEADER \
41
3.39k
        {"class",          t_check,    .dflt.check = "RTCM2"}, \
42
3.39k
        {"type",           t_uinteger, .addr.uinteger = &rtcm2->type}, \
43
3.39k
        {"device",         t_string,   .addr.string = path, \
44
3.39k
                                          .len = pathlen}, \
45
3.39k
        {"station_id",     t_uinteger, .addr.uinteger = &rtcm2->refstaid}, \
46
3.39k
        {"zcount",         t_real,     .addr.real = &rtcm2->zcount, \
47
3.39k
                                          .dflt.real = NAN}, \
48
3.39k
        {"seqnum",         t_uinteger, .addr.uinteger = &rtcm2->seqnum}, \
49
3.39k
        {"length",         t_uinteger, .addr.uinteger = &rtcm2->length}, \
50
3.39k
        {"station_health", t_uinteger, .addr.uinteger = &rtcm2->stathlth},
51
52
309
    int status = 0;
53
309
    unsigned satcount = 0;
54
55
309
    const struct json_attr_t rtcm1_satellite[] = {
56
309
        {"ident",     t_uinteger, STRUCTOBJECT(struct gps_rangesat_t, ident)},
57
309
        {"udre",      t_uinteger, STRUCTOBJECT(struct gps_rangesat_t, udre)},
58
309
        {"iod",       t_uinteger, STRUCTOBJECT(struct gps_rangesat_t, iod)},
59
309
        {"prc",       t_real,     STRUCTOBJECT(struct gps_rangesat_t, prc)},
60
309
        {"rrc",       t_real,     STRUCTOBJECT(struct gps_rangesat_t, rrc)},
61
309
        {NULL},
62
309
    };
63
309
    const struct json_attr_t json_rtcm1[] = {
64
309
        RTCM2_HEADER
65
309
        {"satellites", t_array, STRUCTARRAY(rtcm2->gps_ranges.sat,
66
309
                                            rtcm1_satellite, &satcount)},
67
309
        {NULL},
68
309
    };
69
70
309
    const struct json_attr_t json_rtcm3[] = {
71
309
        RTCM2_HEADER
72
309
        {"x",              t_real,    .addr.real = &rtcm2->ref_sta.x,
73
309
                                         .dflt.real = NAN},
74
309
        {"y",              t_real,    .addr.real = &rtcm2->ref_sta.y,
75
309
                                         .dflt.real = NAN},
76
309
        {"z",              t_real,    .addr.real = &rtcm2->ref_sta.z,
77
309
                                         .dflt.real = NAN},
78
309
        {NULL},
79
309
    };
80
81
    /*
82
     * Beware! Needs to stay synchronized with a corresponding
83
     * name array in the RTCM2 JSON dump code. This interpretation of
84
     * NAVSYSTEM_GALILEO is assumed from RTCM3, it's not actually
85
     * documented in RTCM 2.1.
86
     */
87
309
    const struct json_enum_t system_table[] = {
88
309
        {"GPS", 0}, {"GLONASS", 1}, {"GALILEO", 2}, {"UNKNOWN", 3}, {NULL}
89
309
    };
90
309
    const struct json_attr_t json_rtcm4[] = {
91
309
        RTCM2_HEADER
92
309
        {"valid",          t_boolean, .addr.boolean = &rtcm2->reference.valid},
93
309
        {"system",         t_integer, .addr.integer = &rtcm2->reference.system,
94
309
                                         .map=system_table},
95
309
        {"sense",          t_integer, .addr.integer = &rtcm2->reference.sense},
96
309
        {"datum",          t_string,  .addr.string = rtcm2->reference.datum,
97
309
                                         .len = sizeof(rtcm2->reference.datum)},
98
309
        {"dx",             t_real,    .addr.real = &rtcm2->reference.dx,
99
309
                                         .dflt.real = NAN},
100
309
        {"dy",             t_real,    .addr.real = &rtcm2->reference.dy,
101
309
                                         .dflt.real = NAN},
102
309
        {"dz",             t_real,    .addr.real = &rtcm2->reference.dz,
103
309
                                         .dflt.real = NAN},
104
309
        {NULL},
105
309
    };
106
107
309
    const struct json_attr_t rtcm5_satellite[] = {
108
309
        {"ident",       t_uinteger, STRUCTOBJECT(struct consat_t, ident)},
109
309
        {"iodl",        t_boolean,  STRUCTOBJECT(struct consat_t, iodl)},
110
309
        {"health",      t_uinteger, STRUCTOBJECT(struct consat_t, health)},
111
309
        {"snr",         t_integer,  STRUCTOBJECT(struct consat_t, snr)},
112
309
        {"health_en",   t_boolean,  STRUCTOBJECT(struct consat_t, health_en)},
113
309
        {"new_data",    t_boolean,  STRUCTOBJECT(struct consat_t, new_data)},
114
309
        {"los_warning", t_boolean,  STRUCTOBJECT(struct consat_t, los_warning)},
115
309
        {"tou",         t_uinteger, STRUCTOBJECT(struct consat_t, tou)},
116
309
        {NULL},
117
309
    };
118
309
    const struct json_attr_t json_rtcm5[] = {
119
309
        RTCM2_HEADER
120
309
        {"satellites", t_array, STRUCTARRAY(rtcm2->conhealth.sat,
121
309
                                            rtcm5_satellite, &satcount)},
122
309
        {NULL},
123
309
    };
124
125
309
    const struct json_attr_t json_rtcm6[] = {
126
309
        RTCM2_HEADER
127
        // No-op or keepalive message
128
309
        {NULL},
129
309
    };
130
131
309
    const struct json_attr_t rtcm7_satellite[] = {
132
309
        {"lat",         t_real,     STRUCTOBJECT(struct station_t, latitude)},
133
309
        {"lon",         t_real,     STRUCTOBJECT(struct station_t, longitude)},
134
309
        {"range",       t_uinteger, STRUCTOBJECT(struct station_t, range)},
135
309
        {"frequency",   t_real,     STRUCTOBJECT(struct station_t, frequency)},
136
309
        {"health",      t_uinteger, STRUCTOBJECT(struct station_t, health)},
137
309
        {"station_id",  t_uinteger, STRUCTOBJECT(struct station_t, station_id)},
138
309
        {"bitrate",     t_uinteger, STRUCTOBJECT(struct station_t, bitrate)},
139
309
        {NULL},
140
309
    };
141
309
    const struct json_attr_t json_rtcm7[] = {
142
309
        RTCM2_HEADER
143
309
        {"satellites", t_array, STRUCTARRAY(rtcm2->almanac.station,
144
309
                                            rtcm7_satellite, &satcount)},
145
309
        {NULL},
146
309
    };
147
148
309
    const struct json_attr_t json_rtcm13[] = {
149
309
        RTCM2_HEADER
150
309
        {"status",       t_boolean,  .addr.boolean = &rtcm2->xmitter.status},
151
309
        {"rangeflag",    t_boolean,  .addr.boolean = &rtcm2->xmitter.rangeflag},
152
309
        {"lat",          t_real,     .addr.real = &rtcm2->xmitter.lat,
153
309
                                        .dflt.real = NAN},
154
309
        {"lon",          t_real,     .addr.real = &rtcm2->xmitter.lon,
155
309
                                        .dflt.real = NAN},
156
309
        {"range",        t_uinteger, .addr.uinteger = &rtcm2->xmitter.range},
157
309
        {NULL},
158
309
    };
159
160
309
    const struct json_attr_t json_rtcm14[] = {
161
309
        RTCM2_HEADER
162
309
        {"week",              t_uinteger,
163
309
                              .addr.uinteger = &rtcm2->gpstime.week},
164
309
        {"hour",              t_uinteger,
165
309
                              .addr.uinteger = &rtcm2->gpstime.hour},
166
309
        {"leapsecs",          t_uinteger,
167
309
                              .addr.uinteger = &rtcm2->gpstime.leapsecs},
168
309
        {NULL},
169
309
    };
170
171
309
    const struct json_attr_t json_rtcm16[] = {
172
309
        RTCM2_HEADER
173
309
        {"message",        t_string,  .addr.string = rtcm2->message,
174
309
                                         .len = sizeof(rtcm2->message)},
175
309
        {NULL},
176
309
    };
177
178
309
    const struct json_attr_t rtcm31_satellite[] = {
179
309
        {"ident",     t_uinteger,
180
309
                              STRUCTOBJECT(struct glonass_rangesat_t, ident)},
181
309
        {"udre",      t_uinteger,
182
309
                              STRUCTOBJECT(struct glonass_rangesat_t, udre)},
183
309
        {"change",    t_boolean,
184
309
                              STRUCTOBJECT(struct glonass_rangesat_t, change)},
185
309
        {"tod",       t_uinteger, STRUCTOBJECT(struct glonass_rangesat_t, tod)},
186
309
        {"prc",       t_real,     STRUCTOBJECT(struct glonass_rangesat_t, prc)},
187
309
        {"rrc",       t_real,     STRUCTOBJECT(struct glonass_rangesat_t, rrc)},
188
309
        {NULL},
189
309
    };
190
309
    const struct json_attr_t json_rtcm31[] = {
191
309
        RTCM2_HEADER
192
309
        {"satellites", t_array, STRUCTARRAY(rtcm2->glonass_ranges.sat,
193
309
                                            rtcm31_satellite, &satcount)},
194
309
        {NULL},
195
309
    };
196
197
309
    const struct json_attr_t json_rtcm2_fallback[] = {
198
309
        RTCM2_HEADER
199
309
        {"data",         t_array, .addr.array.element_type = t_string,
200
309
                         .addr.array.arr.strings.ptrs = stringptrs,
201
309
                         .addr.array.arr.strings.store = stringstore,
202
309
                         .addr.array.arr.strings.storelen = sizeof(stringstore),
203
309
                         .addr.array.count = &stringcount,
204
309
                         .addr.array.maxlen = NITEMS(stringptrs)},
205
309
        {NULL},
206
309
    };
207
208
309
#undef RTCM2_HEADER
209
/* *INDENT-ON* */
210
211
309
    memset(rtcm2, '\0', sizeof(struct rtcm2_t));
212
213
309
    if (strstr(buf, "\"type\":1,") != NULL
214
304
        || strstr(buf, "\"type\":9,") != NULL) {
215
7
        status = json_read_object(buf, json_rtcm1, endptr);
216
7
        if (status == 0)
217
1
            rtcm2->gps_ranges.nentries = (unsigned)satcount;
218
302
    } else if (strstr(buf, "\"type\":3,") != NULL) {
219
79
        status = json_read_object(buf, json_rtcm3, endptr);
220
79
        if (status == 0) {
221
74
            rtcm2->ref_sta.valid = (isfinite(rtcm2->ref_sta.x) != 0)
222
28
                && (isfinite(rtcm2->ref_sta.y) != 0)
223
16
                && (isfinite(rtcm2->ref_sta.z) != 0);
224
74
        }
225
223
    } else if (strstr(buf, "\"type\":4,") != NULL) {
226
89
        status = json_read_object(buf, json_rtcm4, endptr);
227
89
        if (status == 0)
228
4
            rtcm2->reference.valid = (isfinite(rtcm2->reference.dx) != 0)
229
2
                && (isfinite(rtcm2->reference.dy) != 0)
230
1
                && (isfinite(rtcm2->reference.dz) != 0);
231
134
    } else if (strstr(buf, "\"type\":5,") != NULL) {
232
7
        status = json_read_object(buf, json_rtcm5, endptr);
233
7
        if (status == 0)
234
1
            rtcm2->conhealth.nentries = (unsigned)satcount;
235
127
    } else if (strstr(buf, "\"type\":6,") != NULL) {
236
1
        status = json_read_object(buf, json_rtcm6, endptr);
237
126
    } else if (strstr(buf, "\"type\":7,") != NULL) {
238
5
        status = json_read_object(buf, json_rtcm7, endptr);
239
5
        if (status == 0)
240
1
            rtcm2->almanac.nentries = (unsigned)satcount;
241
121
    } else if (strstr(buf, "\"type\":13,") != NULL) {
242
1
        status = json_read_object(buf, json_rtcm13, endptr);
243
120
    } else if (strstr(buf, "\"type\":14,") != NULL) {
244
1
        status = json_read_object(buf, json_rtcm14, endptr);
245
119
    } else if (strstr(buf, "\"type\":16,") != NULL) {
246
2
        status = json_read_object(buf, json_rtcm16, endptr);
247
117
    } else if (strstr(buf, "\"type\":31,") != NULL) {
248
5
        status = json_read_object(buf, json_rtcm31, endptr);
249
5
        if (status == 0)
250
1
            rtcm2->glonass_ranges.nentries = (unsigned)satcount;
251
112
    } else {
252
112
        unsigned n;
253
112
        status = json_read_object(buf, json_rtcm2_fallback, endptr);
254
2.88k
        for (n = 0; n < NITEMS(rtcm2->words); n++) {
255
2.80k
            if (n >= stringcount) {
256
2.61k
                rtcm2->words[n] = 0;
257
2.61k
            } else {
258
186
                unsigned int u;
259
186
                int fldcount = sscanf(stringptrs[n], "0x%08x\n", &u);
260
186
                if (1 != fldcount) {
261
23
                    return JSON_ERR_MISC;
262
23
                }  // else
263
163
                rtcm2->words[n] = (isgps30bits_t) u;
264
163
            }
265
2.80k
        }
266
112
    }
267
286
    return status;
268
309
}
269
270
// vim: set expandtab shiftwidth=4