You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rtcm2_json.c 11KB

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