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