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