libgps_core.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /* libgps_core.c -- client interface library for the gpsd daemon
  2. *
  3. * Core portion of client library. Cals helpers to handle different eports.
  4. *
  5. * This file is Copyright 2010 by the GPSD project
  6. * SPDX-License-Identifier: BSD-2-clause
  7. */
  8. #include "../include/gpsd_config.h" /* must be before all includes */
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include <stdarg.h>
  12. #include <stdarg.h>
  13. #include <stdbool.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "../include/gpsd.h"
  18. #include "../include/libgps.h"
  19. #include "../include/gps_json.h"
  20. #include "../include/strfuncs.h"
  21. int libgps_debuglevel = 0;
  22. static FILE *debugfp;
  23. void gps_enable_debug(int level, FILE * fp)
  24. /* control the level and destination of debug trace messages */
  25. {
  26. libgps_debuglevel = level;
  27. debugfp = fp;
  28. json_enable_debug(level - DEBUG_JSON, fp);
  29. }
  30. /* assemble command in printf(3) style */
  31. void libgps_trace(int errlevel, const char *fmt, ...)
  32. {
  33. if (errlevel <= libgps_debuglevel) {
  34. char buf[BUFSIZ];
  35. va_list ap;
  36. (void)strlcpy(buf, "libgps: ", sizeof(buf));
  37. va_start(ap, fmt);
  38. str_vappendf(buf, sizeof(buf), fmt, ap);
  39. va_end(ap);
  40. (void)fputs(buf, debugfp);
  41. }
  42. }
  43. #if defined(SHM_EXPORT_ENABLE) || defined(SOCKET_EXPORT_ENABLE)
  44. #define CONDITIONALLY_UNUSED UNUSED
  45. #else
  46. #define CONDITIONALLY_UNUSED UNUSED
  47. #endif /* SOCKET_EXPORT_ENABLE */
  48. int gps_open(const char *host,
  49. const char *port CONDITIONALLY_UNUSED,
  50. struct gps_data_t *gpsdata)
  51. {
  52. int status = -1;
  53. if (!gpsdata)
  54. return -1;
  55. #ifdef SHM_EXPORT_ENABLE
  56. if (host != NULL && strcmp(host, GPSD_SHARED_MEMORY) == 0) {
  57. status = gps_shm_open(gpsdata);
  58. if (status == -1)
  59. status = SHM_NOSHARED;
  60. else if (status == -2)
  61. status = SHM_NOATTACH;
  62. }
  63. #define USES_HOST
  64. #endif /* SHM_EXPORT_ENABLE */
  65. #ifdef DBUS_EXPORT_ENABLE
  66. if (host != NULL && strcmp(host, GPSD_DBUS_EXPORT) == 0) {
  67. status = gps_dbus_open(gpsdata);
  68. if (status != 0)
  69. status = DBUS_FAILURE;
  70. }
  71. #define USES_HOST
  72. #endif /* DBUS_EXPORT_ENABLE */
  73. #ifdef SOCKET_EXPORT_ENABLE
  74. if (status == -1) {
  75. status = gps_sock_open(host, port, gpsdata);
  76. }
  77. #define USES_HOST
  78. #endif /* SOCKET_EXPORT_ENABLE */
  79. #ifndef USES_HOST
  80. (void)fprintf(stderr,
  81. "No methods available for connecting to %s!\n",
  82. host);
  83. #endif /* USES_HOST */
  84. #undef USES_HOST
  85. gpsdata->set = 0;
  86. gpsdata->satellites_used = 0;
  87. gps_clear_att(&(gpsdata->attitude));
  88. gps_clear_dop(&(gpsdata->dop));
  89. gps_clear_fix(&(gpsdata->fix));
  90. gps_clear_log(&(gpsdata->log));
  91. return status;
  92. }
  93. /* close a gpsd connection */
  94. int gps_close(struct gps_data_t *gpsdata CONDITIONALLY_UNUSED)
  95. {
  96. int status = -1;
  97. libgps_debug_trace((DEBUG_CALLS, "gps_close()\n"));
  98. #ifdef SHM_EXPORT_ENABLE
  99. if (BAD_SOCKET((intptr_t)(gpsdata->gps_fd))) {
  100. gps_shm_close(gpsdata);
  101. status = 0;
  102. }
  103. #endif /* SHM_EXPORT_ENABLE */
  104. #ifdef SOCKET_EXPORT_ENABLE
  105. if (status == -1) {
  106. status = gps_sock_close(gpsdata);
  107. }
  108. #endif /* SOCKET_EXPORT_ENABLE */
  109. return status;
  110. }
  111. /* read from a gpsd connection
  112. *
  113. * parameters:
  114. * gps_data_t *gpsdata -- structure for GPS data
  115. * char *message -- NULL, or optional buffer for received JSON
  116. * int message_len -- zero, or sizeof(message)
  117. */
  118. int gps_read(struct gps_data_t *gpsdata CONDITIONALLY_UNUSED,
  119. char *message, int message_len)
  120. {
  121. int status = -1;
  122. libgps_debug_trace((DEBUG_CALLS, "gps_read() begins\n"));
  123. if ((NULL != message) && (0 < message_len)) {
  124. /* be sure message is zero length */
  125. /* we do not memset() as this is time critical input path */
  126. *message = '\0';
  127. }
  128. #ifdef SHM_EXPORT_ENABLE
  129. if (BAD_SOCKET((intptr_t)(gpsdata->gps_fd))) {
  130. status = gps_shm_read(gpsdata);
  131. }
  132. #endif /* SHM_EXPORT_ENABLE */
  133. #ifdef SOCKET_EXPORT_ENABLE
  134. if (status == -1 && !BAD_SOCKET((intptr_t)(gpsdata->gps_fd))) {
  135. status = gps_sock_read(gpsdata, message, message_len);
  136. }
  137. #endif /* SOCKET_EXPORT_ENABLE */
  138. libgps_debug_trace((DEBUG_CALLS, "gps_read() -> %d (%s)\n",
  139. status, gps_maskdump(gpsdata->set)));
  140. return status;
  141. }
  142. /* send a command to the gpsd instance */
  143. int gps_send(struct gps_data_t *gpsdata CONDITIONALLY_UNUSED,
  144. const char *fmt CONDITIONALLY_UNUSED, ...)
  145. {
  146. int status = -1;
  147. char buf[BUFSIZ];
  148. va_list ap;
  149. va_start(ap, fmt);
  150. (void)vsnprintf(buf, sizeof(buf) - 2, fmt, ap);
  151. va_end(ap);
  152. if (buf[strlen(buf) - 1] != '\n')
  153. (void)strlcat(buf, "\n", sizeof(buf));
  154. #ifdef SOCKET_EXPORT_ENABLE
  155. status = gps_sock_send(gpsdata, buf);
  156. #endif /* SOCKET_EXPORT_ENABLE */
  157. return status;
  158. }
  159. int gps_stream(struct gps_data_t *gpsdata CONDITIONALLY_UNUSED,
  160. unsigned int flags CONDITIONALLY_UNUSED,
  161. void *d CONDITIONALLY_UNUSED)
  162. {
  163. int status = -1;
  164. #ifdef SOCKET_EXPORT_ENABLE
  165. /* cppcheck-suppress redundantAssignment */
  166. status = gps_sock_stream(gpsdata, flags, d);
  167. #endif /* SOCKET_EXPORT_ENABLE */
  168. return status;
  169. }
  170. /* return the contents of the client data buffer */
  171. const char *gps_data(const struct gps_data_t *gpsdata CONDITIONALLY_UNUSED)
  172. {
  173. const char *bufp = NULL;
  174. #ifdef SOCKET_EXPORT_ENABLE
  175. bufp = gps_sock_data(gpsdata);
  176. #endif /* SOCKET_EXPORT_ENABLE */
  177. return bufp;
  178. }
  179. /* is there input waiting from the GPS? */
  180. /* timeout is in uSec */
  181. bool gps_waiting(const struct gps_data_t *gpsdata CONDITIONALLY_UNUSED,
  182. int timeout CONDITIONALLY_UNUSED)
  183. {
  184. /* this is bogus, but I can't think of a better solution yet */
  185. bool waiting = true;
  186. #ifdef SHM_EXPORT_ENABLE
  187. if ((intptr_t)(gpsdata->gps_fd) == SHM_PSEUDO_FD)
  188. waiting = gps_shm_waiting(gpsdata, timeout);
  189. #endif /* SHM_EXPORT_ENABLE */
  190. #ifdef SOCKET_EXPORT_ENABLE
  191. // cppcheck-suppress pointerPositive
  192. if ((intptr_t)(gpsdata->gps_fd) >= 0)
  193. waiting = gps_sock_waiting(gpsdata, timeout);
  194. #endif /* SOCKET_EXPORT_ENABLE */
  195. return waiting;
  196. }
  197. int gps_mainloop(struct gps_data_t *gpsdata CONDITIONALLY_UNUSED,
  198. int timeout CONDITIONALLY_UNUSED,
  199. void (*hook)(struct gps_data_t *gpsdata) CONDITIONALLY_UNUSED)
  200. {
  201. int status = -1;
  202. libgps_debug_trace((DEBUG_CALLS, "gps_mainloop() begins\n"));
  203. #ifdef SHM_EXPORT_ENABLE
  204. if ((intptr_t)(gpsdata->gps_fd) == SHM_PSEUDO_FD)
  205. status = gps_shm_mainloop(gpsdata, timeout, hook);
  206. #endif /* SHM_EXPORT_ENABLE */
  207. #ifdef DBUS_EXPORT_ENABLE
  208. if ((intptr_t)(gpsdata->gps_fd) == DBUS_PSEUDO_FD)
  209. status = gps_dbus_mainloop(gpsdata, timeout, hook);
  210. #endif /* DBUS_EXPORT_ENABLE */
  211. #ifdef SOCKET_EXPORT_ENABLE
  212. if ((intptr_t)(gpsdata->gps_fd) >= 0)
  213. status = gps_sock_mainloop(gpsdata, timeout, hook);
  214. #endif /* SOCKET_EXPORT_ENABLE */
  215. libgps_debug_trace((DEBUG_CALLS, "gps_mainloop() -> %d (%s)\n",
  216. status, gps_maskdump(gpsdata->set)));
  217. return status;
  218. }
  219. extern const char *gps_errstr(const int err)
  220. {
  221. /*
  222. * We might add our own error codes in the future, e.g for
  223. * protocol compatibility checks
  224. */
  225. #ifndef USE_QT
  226. #ifdef SHM_EXPORT_ENABLE
  227. if (err == SHM_NOSHARED)
  228. return "no shared-memory segment or daemon not running";
  229. else if (err == SHM_NOATTACH)
  230. return "attach failed for unknown reason";
  231. #endif /* SHM_EXPORT_ENABLE */
  232. #ifdef DBUS_EXPORT_ENABLE
  233. if (err == DBUS_FAILURE)
  234. return "DBUS initialization failure";
  235. #endif /* DBUS_EXPORT_ENABLE */
  236. return netlib_errstr(err);
  237. #else
  238. static char buf[32];
  239. (void)snprintf(buf, sizeof(buf), "Qt error %d", err);
  240. return buf;
  241. #endif
  242. }
  243. void libgps_dump_state(struct gps_data_t *collect)
  244. {
  245. char ts_buf[TIMESPEC_LEN];
  246. /* no need to dump the entire state, this is a sanity check */
  247. #ifndef USE_QT
  248. (void)fprintf(debugfp, "flags: (0x%04x) %s\n",
  249. (unsigned int)collect->set, gps_maskdump(collect->set));
  250. #endif
  251. if (collect->set & ONLINE_SET)
  252. (void)fprintf(debugfp, "ONLINE: %s\n",
  253. timespec_str(&collect->online, ts_buf, sizeof(ts_buf)));
  254. if (collect->set & TIME_SET)
  255. (void)fprintf(debugfp, "TIME: %s\n",
  256. timespec_str(&collect->fix.time, ts_buf, sizeof(ts_buf)));
  257. /* NOTE: %.7f needed for cm level accurate GPS */
  258. if (collect->set & LATLON_SET)
  259. (void)fprintf(debugfp, "LATLON: lat/lon: %.7lf %.7lf\n",
  260. collect->fix.latitude, collect->fix.longitude);
  261. if (collect->set & ALTITUDE_SET)
  262. (void)fprintf(debugfp, "ALTITUDE: altHAE: %lf U: climb: %lf\n",
  263. collect->fix.altHAE, collect->fix.climb);
  264. if (collect->set & SPEED_SET)
  265. (void)fprintf(debugfp, "SPEED: %lf\n", collect->fix.speed);
  266. if (collect->set & TRACK_SET)
  267. (void)fprintf(debugfp, "TRACK: track: %lf\n", collect->fix.track);
  268. if (collect->set & MAGNETIC_TRACK_SET)
  269. (void)fprintf(debugfp, "MAGNETIC_TRACK: magtrack: %lf\n",
  270. collect->fix.magnetic_track);
  271. if (collect->set & CLIMB_SET)
  272. (void)fprintf(debugfp, "CLIMB: climb: %lf\n", collect->fix.climb);
  273. if (collect->set & STATUS_SET) {
  274. // FIXME! add missing status values. range check status!
  275. const char *status_values[] = { "NO_FIX", "FIX", "DGPS_FIX" };
  276. (void)fprintf(debugfp, "STATUS: status: %d (%s)\n",
  277. collect->fix.status, status_values[collect->fix.status]);
  278. }
  279. if (collect->set & MODE_SET) {
  280. const char *mode_values[] = { "", "NO_FIX", "MODE_2D", "MODE_3D" };
  281. (void)fprintf(debugfp, "MODE: mode: %d (%s)\n",
  282. collect->fix.mode, mode_values[collect->fix.mode]);
  283. }
  284. if (collect->set & SATELLITE_SET)
  285. (void)fprintf(debugfp,
  286. "DOP: satellites %d, pdop=%lf, hdop=%lf, vdop=%lf\n",
  287. collect->satellites_used, collect->dop.pdop,
  288. collect->dop.hdop, collect->dop.vdop);
  289. if (collect->set & VERSION_SET)
  290. (void)fprintf(debugfp, "VERSION: release=%s rev=%s proto=%d.%d\n",
  291. collect->version.release,
  292. collect->version.rev,
  293. collect->version.proto_major,
  294. collect->version.proto_minor);
  295. if (collect->set & POLICY_SET)
  296. (void)fprintf(debugfp,
  297. "POLICY: watcher=%s nmea=%s raw=%d scaled=%s timing=%s, "
  298. "split24=%s pps=%s, devpath=%s\n",
  299. collect->policy.watcher ? "true" : "false",
  300. collect->policy.nmea ? "true" : "false",
  301. collect->policy.raw,
  302. collect->policy.scaled ? "true" : "false",
  303. collect->policy.timing ? "true" : "false",
  304. collect->policy.split24 ? "true" : "false",
  305. collect->policy.pps ? "true" : "false",
  306. collect->policy.devpath);
  307. if (collect->set & SATELLITE_SET) {
  308. struct satellite_t *sp;
  309. (void)fprintf(debugfp, "SKY: satellites in view: %d\n",
  310. collect->satellites_visible);
  311. for (sp = collect->skyview;
  312. sp < collect->skyview + collect->satellites_visible;
  313. sp++) {
  314. (void)fprintf(debugfp, " %2.2d: %4.1f %5.1f %3.0f %c\n",
  315. sp->PRN, sp->elevation,
  316. sp->azimuth, sp->ss,
  317. sp->used ? 'Y' : 'N');
  318. }
  319. }
  320. if (collect->set & RAW_SET)
  321. (void)fprintf(debugfp, "RAW: got raw data\n");
  322. if (collect->set & DEVICE_SET)
  323. (void)fprintf(debugfp, "DEVICE: Device is '%s', driver is '%s'\n",
  324. collect->dev.path, collect->dev.driver);
  325. if (collect->set & DEVICELIST_SET) {
  326. int i;
  327. (void)fprintf(debugfp, "DEVICELIST:%d devices:\n",
  328. collect->devices.ndevices);
  329. for (i = 0; i < collect->devices.ndevices; i++) {
  330. (void)fprintf(debugfp, "%d: path='%s' driver='%s'\n",
  331. collect->devices.ndevices,
  332. collect->devices.list[i].path,
  333. collect->devices.list[i].driver);
  334. }
  335. }
  336. }
  337. // end
  338. // vim: set expandtab shiftwidth=4