/* diversity-gypsy.c - DiversityGypsy * * Copyright 2008 OpenMoko, Inc. * Authored by Chia-I Wu * * 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. */ #include /* strcmp */ #include #include #include #include #include #include #include #define DIVERSITY_GYPSY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), DIVERSITY_TYPE_GYPSY, DiversityGypsyPrivate)) typedef struct _DiversityGypsyPrivate DiversityGypsyPrivate; struct _DiversityGypsyPrivate { DiversityObject *obj; gchar *device_path; GypsyControl *ctrl; GypsyDevice *dev; GypsyPosition *pos; }; G_DEFINE_TYPE(DiversityGypsy, diversity_gypsy, DIVERSITY_TYPE_EQUIPMENT); static gboolean diversity_gypsy_create(DiversityGypsy *gypsy, const gchar *path); static void diversity_gypsy_shutdown(DiversityGypsy *gypsy); static void diversity_gypsy_dispose(GObject *obj) { DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(obj); diversity_gypsy_shutdown(DIVERSITY_GYPSY(obj)); if (priv->obj) { g_object_unref(priv->obj); priv->obj = NULL; } ((GObjectClass *) diversity_gypsy_parent_class)->dispose(obj); } static void diversity_gypsy_finalize(GObject *obj) { DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(obj); g_free(priv->device_path); ((GObjectClass *) diversity_gypsy_parent_class)->finalize(obj); } static gboolean diversity_gypsy_equip(DiversityEquipment *eqp) { DiversityGypsy *gypsy = DIVERSITY_GYPSY(eqp); DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(gypsy); return diversity_gypsy_create(gypsy, priv->device_path); } static void diversity_gypsy_unequip(DiversityEquipment *eqp) { DiversityGypsy *gypsy = DIVERSITY_GYPSY(eqp); diversity_gypsy_shutdown(gypsy); } static gboolean diversity_gypsy_set_config(DiversityEquipment *eqp, const gchar *key, const GValue *val) { gboolean success = FALSE; if (strcmp(key, "device-path") == 0 && G_VALUE_TYPE(val) == G_TYPE_STRING) success = diversity_gypsy_create(DIVERSITY_GYPSY(eqp), g_value_get_string(val)); return success; } static gboolean diversity_gypsy_get_config(DiversityEquipment *eqp, const gchar *key, GValue *val) { DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(eqp); gboolean success = FALSE; // XXX should I? //g_value_init(val, G_TYPE_STRING); if (strcmp(key, "device-path") == 0 && G_VALUE_TYPE(val) == G_TYPE_STRING) g_value_set_string(val, priv->device_path); return success; } static void diversity_gypsy_class_init(DiversityGypsyClass *klass) { GObjectClass *o_class = (GObjectClass *) klass; DiversityEquipmentClass *eqp_class = (DiversityEquipmentClass *) klass; o_class->dispose = diversity_gypsy_dispose; o_class->finalize = diversity_gypsy_finalize; eqp_class->equip = diversity_gypsy_equip; eqp_class->unequip = diversity_gypsy_unequip; eqp_class->set_config = diversity_gypsy_set_config; eqp_class->get_config = diversity_gypsy_get_config; g_type_class_add_private(klass, sizeof(DiversityGypsyPrivate)); } static void diversity_gypsy_init(DiversityGypsy *gypsy) { DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(gypsy); priv->obj = NULL; priv->device_path = NULL; priv->ctrl = NULL; priv->dev = NULL; priv->pos = NULL; } inline static void diversity_gypsy_update_accuracy(DiversityGypsy *gypsy, DiversityObjectAccuracy acc) { DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(gypsy); diversity_object_touch(priv->obj); diversity_object_set_accuracy(priv->obj, acc); } inline static void diversity_gypsy_update_position(DiversityGypsy *gypsy, gdouble lon, gdouble lat) { DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(gypsy); diversity_object_touch(priv->obj); diversity_object_geometry_set(priv->obj, lon, lat, 0.0, 0.0); } static void on_connection_changed(GypsyDevice *dev, gboolean connected, gpointer user_data) { DiversityGypsy *gypsy = DIVERSITY_GYPSY(user_data); DiversityObjectAccuracy acc; g_print("connection changed: %d\n", connected); if (connected) acc = DIVERSITY_OBJECT_ACCURACY_DIRECT; else acc = DIVERSITY_OBJECT_ACCURACY_NONE; diversity_gypsy_update_accuracy(gypsy, acc); } static void on_fix_status_changed(GypsyDevice *dev, GypsyDeviceFixStatus fix, gpointer user_data) { DiversityGypsy *gypsy = DIVERSITY_GYPSY(user_data); DiversityObjectAccuracy acc; g_print("fix changed: %d\n", fix); switch (fix) { case GYPSY_DEVICE_FIX_STATUS_INVALID: case GYPSY_DEVICE_FIX_STATUS_NONE: acc = DIVERSITY_OBJECT_ACCURACY_NONE; break; case GYPSY_DEVICE_FIX_STATUS_2D: case GYPSY_DEVICE_FIX_STATUS_3D: acc = DIVERSITY_OBJECT_ACCURACY_DIRECT; break; default: g_assert_not_reached(); break; } diversity_gypsy_update_accuracy(gypsy, acc); } static void on_position_changed(GypsyPosition *pos, GypsyPositionFields fields, gint timestamp, gdouble lat, gdouble lon, gdouble alt, gpointer user_data) { DiversityGypsy *gypsy = DIVERSITY_GYPSY(user_data); g_print("pos changed: %f, %f\n", lon, lat); if ((fields & GYPSY_POSITION_FIELDS_LATITUDE) && (fields & GYPSY_POSITION_FIELDS_LONGITUDE)) diversity_gypsy_update_position(gypsy, lon, lat); } static void diversity_gypsy_shutdown(DiversityGypsy *gypsy) { DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(gypsy); GError *error = NULL; if (priv->dev) { if (!gypsy_device_stop(priv->dev, &error)) { g_printerr("failed to stop Gypsy device: %s\n", error->message); g_error_free(error); } g_object_unref(G_OBJECT(priv->dev)); priv->dev = NULL; } if (priv->pos) { g_object_unref(G_OBJECT(priv->pos)); priv->pos = NULL; } if (priv->ctrl) { g_object_unref(G_OBJECT(priv->ctrl)); priv->ctrl = NULL; } if (priv->obj) diversity_gypsy_update_accuracy(gypsy, DIVERSITY_OBJECT_ACCURACY_NONE); } static void gypsy_control_create_cb(GypsyControl *ctrl, const gchar *path, gpointer user_data) { DiversityGypsy *gypsy = DIVERSITY_GYPSY(user_data); DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(gypsy); GError *error = NULL; if (!path) return; priv->pos = gypsy_position_new(path); g_signal_connect(priv->pos, "position-changed", G_CALLBACK(on_position_changed), user_data); priv->dev = gypsy_device_new(path); g_signal_connect(priv->dev, "connection-changed", G_CALLBACK(on_connection_changed), user_data); g_signal_connect(priv->dev, "fix-status-changed", G_CALLBACK(on_fix_status_changed), user_data); if (!gypsy_device_start(priv->dev, &error)) { g_printerr("failed to start Gypsy device (%s): %s\n", path, error->message); g_error_free(error); } } static gboolean diversity_gypsy_create(DiversityGypsy *gypsy, const gchar *path) { DiversityGypsyPrivate *priv = DIVERSITY_GYPSY_GET_PRIVATE(gypsy); gchar *obj_path; GError *error = NULL; if (priv->ctrl) diversity_gypsy_shutdown(gypsy); if (!path) return TRUE; priv->ctrl = gypsy_control_get_default(); obj_path = gypsy_control_create(priv->ctrl, path, &error); if (!obj_path) { g_printerr("failed to create Gypsy device for %s: %s\n", path, error->message); g_error_free(error); return FALSE; } gypsy_control_create_cb(priv->ctrl, obj_path, gypsy); if (obj_path) g_free(obj_path); return TRUE; } DiversityGypsy *diversity_gypsy_new(DiversityObject *obj) { DiversityGypsy *gypsy; DiversityGypsyPrivate *priv; gypsy = g_object_new(DIVERSITY_TYPE_GYPSY, "name", "gypsy", NULL); priv = DIVERSITY_GYPSY_GET_PRIVATE(gypsy); priv->obj = obj; g_object_ref(obj); return gypsy; }