libgps_dbus.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * This file is Copyright (c)2010-2018 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include "gpsd_config.h" /* must be before all includes */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <stdbool.h>
  9. #include <string.h>
  10. #include <math.h>
  11. #include <time.h>
  12. #include <errno.h>
  13. #include <libgen.h>
  14. #include <signal.h>
  15. #include <unistd.h>
  16. #include "gps.h"
  17. #include "libgps.h"
  18. #if defined(DBUS_EXPORT_ENABLE)
  19. #include <syslog.h>
  20. struct privdata_t
  21. {
  22. void (*handler)(struct gps_data_t *);
  23. };
  24. #include <dbus/dbus.h>
  25. /*
  26. * Unpleasant that we have to declare a static context pointer here - means
  27. * you can't have multiple DBUS sessions open (not that this matters
  28. * much in practice). The problem is the DBUS API lacks some hook
  29. * arguments that it ought to have.
  30. */
  31. static struct gps_data_t *share_gpsdata;
  32. static DBusConnection *connection;
  33. static DBusHandlerResult handle_gps_fix(DBusMessage * message)
  34. {
  35. DBusError error;
  36. const char *gpsd_devname = NULL;
  37. dbus_error_init(&error);
  38. dbus_message_get_args(message,
  39. &error,
  40. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.time,
  41. DBUS_TYPE_INT32, &share_gpsdata->fix.mode,
  42. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.ept,
  43. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.latitude,
  44. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.longitude,
  45. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.eph,
  46. /* The debus doc does not seem to specify
  47. * altHAE or altMSL */
  48. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.altHAE,
  49. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.epv,
  50. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.track,
  51. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.epd,
  52. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.speed,
  53. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.eps,
  54. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.climb,
  55. DBUS_TYPE_DOUBLE, &share_gpsdata->fix.epc,
  56. DBUS_TYPE_STRING, &gpsd_devname, DBUS_TYPE_INVALID);
  57. if (share_gpsdata->fix.mode > MODE_NO_FIX )
  58. share_gpsdata->status = STATUS_FIX;
  59. else
  60. share_gpsdata->status = STATUS_NO_FIX;
  61. dbus_error_free(&error);
  62. PRIVATE(share_gpsdata)->handler(share_gpsdata);
  63. return DBUS_HANDLER_RESULT_HANDLED;
  64. }
  65. /*
  66. * Message dispatching function
  67. *
  68. */
  69. static DBusHandlerResult signal_handler(DBusConnection * connection UNUSED,
  70. DBusMessage * message,
  71. void *user_data UNUSED)
  72. {
  73. if (dbus_message_is_signal(message, "org.gpsd", "fix"))
  74. return handle_gps_fix(message);
  75. /*
  76. * ignore all other messages
  77. */
  78. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  79. }
  80. int gps_dbus_open(struct gps_data_t *gpsdata)
  81. {
  82. DBusError error;
  83. gpsdata->privdata = (void *)malloc(sizeof(struct privdata_t));
  84. if (gpsdata->privdata == NULL)
  85. return -1;
  86. dbus_error_init(&error);
  87. connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
  88. if (dbus_error_is_set(&error)) {
  89. syslog(LOG_CRIT, "%s: %s", error.name, error.message);
  90. dbus_error_free(&error);
  91. return 3;
  92. }
  93. dbus_bus_add_match(connection, "type='signal'", &error);
  94. if (dbus_error_is_set(&error)) {
  95. syslog(LOG_CRIT, "unable to add match for signals %s: %s", error.name,
  96. error.message);
  97. dbus_error_free(&error);
  98. return 4;
  99. }
  100. if (!dbus_connection_add_filter
  101. (connection, (DBusHandleMessageFunction) signal_handler, NULL,
  102. NULL)) {
  103. syslog(LOG_CRIT, "unable to register filter with the connection");
  104. return 5;
  105. }
  106. #ifndef USE_QT
  107. gpsdata->gps_fd = DBUS_PSEUDO_FD;
  108. #else
  109. gpsdata->gps_fd = (void *)(intptr_t)DBUS_PSEUDO_FD;
  110. #endif /* USE_QT */
  111. share_gpsdata = gpsdata;
  112. return 0;
  113. }
  114. int gps_dbus_mainloop(struct gps_data_t *gpsdata,
  115. int timeout,
  116. void (*hook)(struct gps_data_t *))
  117. /* run a DBUS main loop with a specified handler */
  118. {
  119. share_gpsdata = gpsdata;
  120. PRIVATE(share_gpsdata)->handler = (void (*)(struct gps_data_t *))hook;
  121. for (;;)
  122. if (dbus_connection_read_write_dispatch(connection, (int)(timeout/1000)) != TRUE)
  123. return -1;
  124. return 0;
  125. }
  126. #endif /* defined(DBUS_EXPORT_ENABLE) */