Coverage Report

Created: 2026-01-10 06:40

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