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