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