diff options
-rw-r--r-- | src/gypsy-discovery.c | 400 | ||||
-rw-r--r-- | src/gypsy-discovery.h | 50 |
2 files changed, 450 insertions, 0 deletions
diff --git a/src/gypsy-discovery.c b/src/gypsy-discovery.c new file mode 100644 index 0000000..1a12722 --- /dev/null +++ b/src/gypsy-discovery.c @@ -0,0 +1,400 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Gypsy + * + * A simple to use and understand GPSD replacement + * that uses D-Bus, GLib and memory allocations + * + * Author: Iain Holmes <iain@gnome.org> + * Copyright (C) 2007 Iain Holmes + * Copyright (C) 2007 Openedhand, Ltd + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* + * GypsyDiscovery - GPS device discovery service + */ +#include "config.h" + +#include <string.h> +#include <stdlib.h> + +#include <glib.h> + +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-bindings.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include <gudev/gudev.h> + +#include "gypsy-discovery.h" + +enum { + PROP_0, +}; + +enum { + DEVICE_ADDED, + DEVICE_REMOVED, + LAST_SIGNAL, +}; + +struct _GypsyDiscoveryPrivate { + GUdevClient *client; + GPtrArray *known_devices; + +#ifdef HAVE_BLUEZ + DBusGConnection *connection; + DBusGProxy *adapter_proxy; + DBusGProxy *manager_proxy; +#endif +}; + +#define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_MANAGER_PATH "/" +#define BLUEZ_MANAGER_IFACE "org.bluez.Manager" +#define BLUEZ_ADAPTER_IFACE "org.bluez.Adapter" +#define BLUEZ_DEVICE_IFACE "org.bluez.Device" + +#ifndef DBUS_TYPE_G_OBJECT_PATH_ARRAY +#define DBUS_TYPE_G_OBJECT_PATH_ARRAY \ + (dbus_g_type_get_collection("GPtrArray", DBUS_TYPE_G_OBJECT_PATH)) +#endif + +#ifndef DBUS_TYPE_G_DICTIONARY +#define DBUS_TYPE_G_DICTIONARY \ + (dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) +#endif + +#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GYPSY_TYPE_DISCOVERY, GypsyDiscoveryPrivate)) +G_DEFINE_TYPE (GypsyDiscovery, gypsy_discovery, G_TYPE_OBJECT); +static guint32 signals[LAST_SIGNAL] = {0,}; + +static gboolean gypsy_discovery_list_devices (GypsyDiscovery *discovery, + char ***devices, + GError **error); +static gboolean gypsy_discovery_start_scanning (GypsyDiscovery *discovery, + GError **error); +static gboolean gypsy_discovery_stop_scanning (GypsyDiscovery *discovery, + GError **error); + +#include "gypsy-discovery-glue.h" + +static void +gypsy_discovery_finalize (GObject *object) +{ + GypsyDiscovery *self = (GypsyDiscovery *) object; + GypsyDiscoveryPrivate *priv = self->priv; + + if (priv->known_devices) { + g_ptr_array_free (priv->known_devices, TRUE); + priv->known_devices = NULL; + } + + G_OBJECT_CLASS (gypsy_discovery_parent_class)->finalize (object); +} + +static void +gypsy_discovery_dispose (GObject *object) +{ + GypsyDiscovery *self = (GypsyDiscovery *) object; + GypsyDiscoveryPrivate *priv = self->priv; + + if (priv->client) { + g_object_unref (priv->client); + priv->client = NULL; + } + +#ifdef HAVE_BLUEZ + if (priv->manager_proxy) { + g_object_unref (priv->manager_proxy); + priv->manager_proxy = NULL; + } + + if (priv->adapter_proxy) { + g_object_unref (priv->adapter_proxy); + priv->adapter_proxy = NULL; + } +#endif + + G_OBJECT_CLASS (gypsy_discovery_parent_class)->dispose (object); +} + +#if 0 +static void +gypsy_discovery_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GypsyDiscovery *self = (GypsyDiscovery *) object; + + switch (prop_id) { + + default: + break; + } +} + +static void +gypsy_discovery_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GypsyDiscovery *self = (GypsyDiscovery *) object; + + switch (prop_id) { + + default: + break; + } +} +#endif + +static void +gypsy_discovery_class_init (GypsyDiscoveryClass *klass) +{ + GObjectClass *o_class = (GObjectClass *) klass; + + o_class->dispose = gypsy_discovery_dispose; + o_class->finalize = gypsy_discovery_finalize; +/* + o_class->set_property = gypsy_discovery_set_property; + o_class->get_property = gypsy_discovery_get_property; +*/ + g_type_class_add_private (klass, sizeof (GypsyDiscoveryPrivate)); + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), + &dbus_glib_gypsy_discovery_object_info); + + signals[DEVICE_ADDED] = g_signal_new ("device-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | + G_SIGNAL_NO_RECURSE, + 0, NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRV); + signals[DEVICE_REMOVED] = g_signal_new ("device-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | + G_SIGNAL_NO_RECURSE, + 0, NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRV); +} + +static void +uevent_occurred_cb (GUdevClient *client, + const char *action, + GUdevDevice *device, + GypsyDiscovery *discovery) +{ + if (strcmp (action, "add") == 0) { + } else if (strcmp (action, "remove") == 0) { + } +} + +#ifdef HAVE_BLUEZ +static gboolean +class_is_positioning_device (GValue *value) +{ + int class_id = g_value_get_uint (value); + + return ((class_id >> 16) & 0x1); +} + +static gboolean +get_positioning_devices (GypsyDiscovery *discovery, + GPtrArray *devices, + GError **error) +{ + GypsyDiscoveryPrivate *priv = discovery->priv; + int i; + + if (devices == NULL) { + /* It didn't fail, there just weren't any devices */ + return TRUE; + } + + for (i = 0; i < devices->len; i++) { + DBusGProxy *proxy; + GHashTable *properties; + GValue *path, *class; + gboolean ret; + + proxy = dbus_g_proxy_new_for_name (priv->connection, + BLUEZ_SERVICE, + devices->pdata[i], + BLUEZ_DEVICE_IFACE); + ret = dbus_g_proxy_call (proxy, "GetProperties", error, + G_TYPE_INVALID, + DBUS_TYPE_G_DICTIONARY, &properties, + G_TYPE_INVALID); + if (ret == FALSE) { + g_object_unref (proxy); + return FALSE; + } + + class = g_hash_table_lookup (properties, "Class"); + if (class == NULL) { + g_object_unref (proxy); + g_hash_table_destroy (properties); + continue; + } + + if (class_is_positioning_device (class) == FALSE) { + g_object_unref (proxy); + g_hash_table_destroy (properties); + continue; + } + + path = g_hash_table_lookup (properties, "Address"); + if (path == NULL) { + g_object_unref (proxy); + g_hash_table_destroy (properties); + continue; + } + + g_ptr_array_add (priv->known_devices, + g_value_dup_string (path)); + + g_object_unref (proxy); + g_hash_table_destroy (properties); + } + + return TRUE; +} +#endif + +static void +setup_bluetooth_discovery (GypsyDiscovery *discovery) +{ +#ifdef HAVE_BLUEZ + GypsyDiscoveryPrivate *priv = self->priv; + GError *error = NULL; + char *default_adapter; + GPtrArray *devices; + gboolean ret; + + priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (!priv->connection) { + g_warning ("Error getting D-Bus connection: %s\n" + "Continuing without Bluetooth discovery", + error->message); + g_error_free (error); + return; + } + + priv->manager_proxy = dbus_g_proxy_new_for_name (priv->connection, + BLUEZ_SERVICE, + BLUEZ_MANAGER_PATH, + BLUEZ_MANAGER_IFACE); + + ret = dbus_g_proxy_call (priv->manager_proxy, "DefaultAdapter", + &error, G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, &default_adapter, + G_TYPE_INVALID); + if (ret == FALSE) { + g_warning ("Error getting default adapter path: %s\n" + "Continuing without Bluetooth discovery", + error->message); + g_error_free (error); + + /* Shut down BT discovery */ + g_object_unref (priv->manager_proxy); + priv->manager_proxy = NULL; + + priv->connection = NULL; + return; + } + + priv->adapter_proxy = dbus_g_proxy_new_for_name (priv->connection, + BLUEZ_SERVICE, + default_adapter, + BLUEZ_ADAPTER_IFACE); + ret = dbus_g_proxy_call (priv->adapter_proxy, "ListDevices", &error, + G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH_ARRAY, &devices, + G_TYPE_INVALID); + if (ret == FALSE) { + g_warning ("Error getting devices on %s: %s\n", default_adapter, + error->message); + g_error_free (error); + return; + } + + if (!get_positioning_devices (self, devices, &error)) { + g_warning ("Error getting positioning devices: %s", + error->message); + g_error_free (error); + return; + } +#endif +} + +static void +gypsy_discovery_init (GypsyDiscovery *self) +{ + GypsyDiscoveryPrivate *priv = GET_PRIVATE (self); + const char * const subsystems[] = { "" }; + + self->priv = priv; + + priv->known_devices = g_ptr_array_new (); + + priv->client = g_udev_client_new (subsystems); + g_signal_connect (priv->client, "uevent", + G_CALLBACK (uevent_occurred_cb), self); + + /* FIXME: Get devices UDev knows about */ + + setup_bluetooth_discovery (self); +} + +static gboolean +gypsy_discovery_list_devices (GypsyDiscovery *discovery, + char ***devices, + GError **error) +{ + GypsyDiscoveryPrivate *priv = discovery->priv; + int i; + + *devices = g_new (char *, priv->known_devices->len); + for (i = 0; i < priv->known_devices->len; i++) { + (*devices)[i] = g_strdup (priv->known_devices->pdata[i]); + } + + return TRUE; +} + +static gboolean +gypsy_discovery_start_scanning (GypsyDiscovery *discovery, + GError **error) +{ + g_warning ("Scanning not implemented"); + return TRUE; +} + +static gboolean +gypsy_discovery_stop_scanning (GypsyDiscovery *discovery, + GError **error) +{ + g_warning ("Scanning not implemented"); + return TRUE; +} diff --git a/src/gypsy-discovery.h b/src/gypsy-discovery.h new file mode 100644 index 0000000..201ee6d --- /dev/null +++ b/src/gypsy-discovery.h @@ -0,0 +1,50 @@ +#ifndef __GYPSY_DISCOVERY_H__ +#define __GYPSY_DISCOVERY_H__ + +#include <glib-object.h> + + +G_BEGIN_DECLS + +#define GYPSY_TYPE_DISCOVERY \ + (gypsy_discovery_get_type()) +#define GYPSY_DISCOVERY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GYPSY_TYPE_DISCOVERY, \ + GypsyDiscovery)) +#define GYPSY_DISCOVERY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GYPSY_TYPE_DISCOVERY, \ + GypsyDiscoveryClass)) +#define GYPSY_IS_DISCOVERY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + GYPSY_TYPE_DISCOVERY)) +#define GYPSY_IS_DISCOVERY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + GYPSY_TYPE_DISCOVERY)) +#define GYPSY_DISCOVERY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GYPSY_TYPE_DISCOVERY, \ + GypsyDiscoveryClass)) + +typedef struct _GypsyDiscoveryPrivate GypsyDiscoveryPrivate; +typedef struct _GypsyDiscovery GypsyDiscovery; +typedef struct _GypsyDiscoveryClass GypsyDiscoveryClass; + +struct _GypsyDiscovery +{ + GObject parent; + + GypsyDiscoveryPrivate *priv; +}; + +struct _GypsyDiscoveryClass +{ + GObjectClass parent_class; +}; + +GType gypsy_discovery_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __GYPSY_DISCOVERY_H__ */ |