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