summaryrefslogtreecommitdiff
path: root/libgps_dbus.c
blob: 8f84e720985f54b3c9bed05f4a2cd1ad3bbb5436 (plain)
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
#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"

#if defined(DBUS_EXPORT_ENABLE) && !defined(S_SPLINT_S)

struct privdata_t
{
    void (*handler)(struct gps_data_t *);
};
#define PRIVATE(gpsdata) ((struct privdata_t *)(gpsdata)->privdata)

#include <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <dbus/dbus-glib.h>

#include <glib/gprintf.h>

DBusConnection *connection;

static char gpsd_devname[BUFSIZ];

static DBusHandlerResult handle_gps_fix(DBusMessage * message)
{
    DBusError error;
    /* this packet format was designed before we split eph */
    double eph;
    struct gps_data_t gpsdata;

    dbus_error_init(&error);

    (void)memset(&gpsdata, '\0', sizeof(gpsdata));
    dbus_message_get_args(message,
			  &error,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.time,
			  DBUS_TYPE_INT32, &gpsdata.fix.mode,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.ept,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.latitude,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.longitude,
			  DBUS_TYPE_DOUBLE, &eph,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.altitude,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.epv,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.track,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.epd,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.speed,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.eps,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.climb,
			  DBUS_TYPE_DOUBLE, &gpsdata.fix.epc,
			  DBUS_TYPE_STRING, &gpsd_devname, DBUS_TYPE_INVALID);

    if (gpsdata.fix.mode > MODE_NO_FIX )
	gpsdata.status = STATUS_FIX;
    else
	gpsdata.status = STATUS_NO_FIX;

    PRIVATE(&gpsdata)->handler(&gpsdata);
    return DBUS_HANDLER_RESULT_HANDLED;
}

/*
 * Message dispatching function
 *
 */
static DBusHandlerResult signal_handler(DBusConnection * connection,
					DBusMessage * message)
{
    /* dummy, need to use the variable for some reason */
    connection = NULL;

    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(void (*handler)(struct gps_data_t *), struct gps_data_t *gpsdata)
{
    GMainLoop *mainloop;
    DBusError error;

    gpsdata->privdata = (void *)malloc(sizeof(struct privdata_t));
    if (gpsdata->privdata == NULL)
	return -1;
    PRIVATE(gpsdata)->handler = handler;

    mainloop = g_main_loop_new(NULL, FALSE);

    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;
    }

    dbus_connection_setup_with_g_main(connection, NULL);

    g_main_loop_run(mainloop);
    return 0;
}

#endif /* defined(DBUS_EXPORT_ENABLE) && !defined(S_SPLINT_S) */