From 0bf275a61322262bace7f6b65ee34e54cc6d114d Mon Sep 17 00:00:00 2001 From: Pekka Pessi Date: Thu, 4 Nov 2010 22:35:39 +0200 Subject: modem/modem: derive Modem from ModemOface New functions: - modem_list_interfaces () - modem_has_imsi () - modem_has_imei () New signals: - "interface-added" - "interface-removed" - "imsi-added" --- modem/modem.c | 500 +++++++++++++++++++++++++++++++++++++++++++++------------- modem/modem.h | 16 +- 2 files changed, 403 insertions(+), 113 deletions(-) diff --git a/modem/modem.c b/modem/modem.c index fb813c4..ae15490 100644 --- a/modem/modem.c +++ b/modem/modem.c @@ -2,7 +2,9 @@ * modem/modem.c - oFono modem * * Copyright (C) 2009, 2010 Nokia Corporation - * @author Pekka Pessi + * + * @author Pekka Pessi + * @author Kai Vehmanen * * This work is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,8 +29,13 @@ #include "modem/modem.h" #include "modem/request-private.h" +#include "modem/oface.h" #include "modem/ofono.h" +#include "modem/call.h" +#include "modem/sim.h" +#include "modem/sms.h" #include "modem/errors.h" +#include "modem/oface.h" #include @@ -48,49 +55,59 @@ /* ------------------------------------------------------------------------ */ -G_DEFINE_TYPE (Modem, modem, G_TYPE_OBJECT); +G_DEFINE_TYPE (Modem, modem, MODEM_TYPE_OFACE); enum { - PROP_OBJECT_PATH = 1, + PROP_NONE, PROP_POWERED, PROP_ONLINE, PROP_NAME, PROP_MANUFACTURER, PROP_MODEL, PROP_REVISION, - PROP_SERIAL, + PROP_IMEI, PROP_FEATURES, PROP_INTERFACES, N_PROPS }; +enum +{ + SIGNAL_INTERFACE_ADDED, + SIGNAL_INTERFACE_REMOVED, + SIGNAL_IMSI_ADDED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + /* private data */ struct _ModemPrivate { - DBusGProxy *proxy; - /* Properties */ - gchar *object_path; gboolean powered; gboolean online; gchar *name; gchar *manufacturer; gchar *model; gchar *revision; - gchar *serial; + gchar *imei; gchar **features; gchar **interfaces; - unsigned dispose_has_run:1; - unsigned :0; + GHashTable *ifhash; + GHashTable *connecting; + GHashTable *ofaces; }; /* ------------------------------------------------------------------------ */ /* Local functions */ -static void on_modem_property_changed (DBusGProxy *, char const *, - GValue const *, gpointer); +static void on_notify_interfaces (Modem *, GParamSpec *, Modem *); +static void modem_update_interfaces (Modem *); +static void on_sim_notify_imsi (ModemSIMService *, GParamSpec *, Modem *); +static void on_oface_connected (ModemOface *, gboolean, Modem *); /* ------------------------------------------------------------------------ */ @@ -101,41 +118,24 @@ modem_init (Modem *self) self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MODEM_TYPE_MODEM, ModemPrivate); + + self->priv->ifhash = g_hash_table_new (g_str_hash, g_str_equal); + self->priv->connecting = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); + self->priv->ofaces = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); } static void modem_constructed (GObject *object) { - Modem *self = MODEM_MODEM (object); - ModemPrivate *priv = self->priv; - - priv->proxy = modem_ofono_proxy (priv->object_path, OFONO_IFACE_MODEM); - - if (priv->proxy) - { - modem_ofono_proxy_connect_to_property_changed (priv->proxy, - on_modem_property_changed, self); - } - else - g_error ("Unable to proxy oFono modem %s", priv->object_path); + if (G_OBJECT_CLASS (modem_parent_class)->constructed) + G_OBJECT_CLASS (modem_parent_class)->constructed (object); } static void modem_dispose (GObject *object) { - Modem *self = MODEM_MODEM (object); - ModemPrivate *priv = self->priv; - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - modem_ofono_proxy_disconnect_from_property_changed (priv->proxy, - on_modem_property_changed, self); - - g_object_run_dispose (G_OBJECT (priv->proxy)); - if (G_OBJECT_CLASS (modem_parent_class)->dispose) G_OBJECT_CLASS (modem_parent_class)->dispose (object); } @@ -150,17 +150,18 @@ modem_finalize (GObject *object) /* Free any data held directly by the object here */ - g_object_unref (priv->proxy); - - g_free (priv->object_path); g_free (priv->name); g_free (priv->manufacturer); g_free (priv->model); g_free (priv->revision); - g_free (priv->serial); + g_free (priv->imei); g_strfreev (priv->features); g_strfreev (priv->interfaces); + g_hash_table_destroy (priv->ifhash); + g_hash_table_destroy (priv->ofaces); + g_hash_table_destroy (priv->connecting); + G_OBJECT_CLASS (modem_parent_class)->finalize (object); } @@ -175,11 +176,6 @@ modem_set_property (GObject *obj, switch (property_id) { - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_boxed (value); - break; - case PROP_POWERED: priv->powered = g_value_get_boolean (value); break; @@ -208,9 +204,9 @@ modem_set_property (GObject *obj, priv->revision = g_value_dup_string (value); break; - case PROP_SERIAL: - g_free (priv->serial); - priv->serial = g_value_dup_string (value); + case PROP_IMEI: + g_free (priv->imei); + priv->imei = g_value_dup_string (value); break; case PROP_FEATURES: @@ -240,10 +236,6 @@ modem_get_property (GObject *obj, switch (property_id) { - case PROP_OBJECT_PATH: - g_value_set_boxed (value, priv->object_path); - break; - case PROP_POWERED: g_value_set_boolean (value, priv->powered); break; @@ -268,8 +260,8 @@ modem_get_property (GObject *obj, g_value_set_string (value, priv->revision); break; - case PROP_SERIAL: - g_value_set_string (value, priv->serial); + case PROP_IMEI: + g_value_set_string (value, priv->imei); break; case PROP_FEATURES: @@ -286,10 +278,84 @@ modem_get_property (GObject *obj, } } +/* ------------------------------------------------------------------------- */ + +/** Maps properties of org.ofono.Modem to matching Modem properties */ +char const * +modem_property_mapper (char const *name) +{ + if (!strcmp (name, "Powered")) + return "powered"; + if (!strcmp (name, "Online")) + return "online"; + if (!strcmp (name, "Name")) + return "name"; + if (!strcmp (name, "Manufacturer")) + return "manufacturer"; + if (!strcmp (name, "Model")) + return "model"; + if (!strcmp (name, "Revision")) + return "revision"; + if (!strcmp (name, "Serial")) + return "imei"; + if (!strcmp (name, "Features")) + return "features"; + if (!strcmp (name, "Interfaces")) + return "interfaces"; + return NULL; +} + +static void +modem_connect (ModemOface *_self) +{ + DEBUG ("(%p): enter", _self); + + modem_oface_connect_properties (_self, FALSE); + + g_signal_connect (_self, "notify::interfaces", + G_CALLBACK(on_notify_interfaces), _self); + + modem_update_interfaces ( MODEM_MODEM(_self) ); +} + +static void +modem_disconnect (ModemOface *_self) +{ + DEBUG ("(%p): enter", _self); + + Modem *self = MODEM_MODEM (_self); + ModemPrivate *priv = self->priv; + GHashTableIter iter[1]; + char *interface; + ModemOface *oface; + + g_signal_handlers_disconnect_by_func (_self, + G_CALLBACK(on_notify_interfaces), _self); + + for (g_hash_table_iter_init (iter, priv->connecting); + g_hash_table_iter_next (iter, (gpointer)&interface, (gpointer)&oface);) + { + g_signal_handlers_disconnect_by_func (oface, + on_oface_connected, self); + } + + for (g_hash_table_iter_init (iter, priv->ofaces); + g_hash_table_iter_next (iter, (gpointer)&interface, (gpointer)&oface);) + { + g_signal_handlers_disconnect_by_func (oface, + on_oface_connected, self); + + if (MODEM_IS_SIM_SERVICE (oface)) + g_signal_handlers_disconnect_by_func (oface, + on_sim_notify_imsi, self); + } +} + static void modem_class_init (ModemClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + ModemOfaceClass *oface_class = MODEM_OFACE_CLASS (klass); DEBUG ("enter"); @@ -299,14 +365,35 @@ modem_class_init (ModemClass *klass) object_class->get_property = modem_get_property; object_class->set_property = modem_set_property; + oface_class->property_mapper = modem_property_mapper; + oface_class->connect = modem_connect; + oface_class->disconnect = modem_disconnect; + g_type_class_add_private (klass, sizeof (ModemPrivate)); - g_object_class_install_property (object_class, PROP_OBJECT_PATH, - g_param_spec_boxed ("object-path", - "Object Path", - "Object path of the modem on oFono", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + signals[SIGNAL_INTERFACE_ADDED] = g_signal_new ("interface-added", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[SIGNAL_INTERFACE_REMOVED] = g_signal_new ("interface-removed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[SIGNAL_IMSI_ADDED] = g_signal_new ("imsi-added", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); g_object_class_install_property (object_class, PROP_POWERED, g_param_spec_boolean ("powered", @@ -350,10 +437,10 @@ modem_class_init (ModemClass *klass) "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, PROP_SERIAL, - g_param_spec_string ("serial", + g_object_class_install_property (object_class, PROP_IMEI, + g_param_spec_string ("imei", "Serial", - "The serial number (IMEI) of the modem device.", + "The IMEI (serial number) of the modem device.", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -365,6 +452,7 @@ modem_class_init (ModemClass *klass) G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /* XXX/KV: should this be removed as this is oFono-specific */ g_object_class_install_property (object_class, PROP_INTERFACES, g_param_spec_boxed ("interfaces", "Interfaces", @@ -376,53 +464,190 @@ modem_class_init (ModemClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } - /* -------------------------------------------------------------------------- */ -/* modem interface */ -char const * -modem_property_name_by_ofono_name (char const *name) +static void +on_sim_notify_imsi (ModemSIMService *sim, + GParamSpec *dummy, + Modem *self) { - if (!strcmp (name, "Powered")) - return "powered"; - if (!strcmp (name, "Online")) - return "online"; - if (!strcmp (name, "Name")) - return "name"; - if (!strcmp (name, "Manufacturer")) - return "manufacturer"; - if (!strcmp (name, "Model")) - return "model"; - if (!strcmp (name, "Revision")) - return "revision"; - if (!strcmp (name, "Serial")) - return "serial"; - if (!strcmp (name, "Features")) - return "features"; - if (!strcmp (name, "Interfaces")) - return "interfaces"; - return NULL; + gchar *imsi = NULL; + + DEBUG ("enter"); + + g_object_get (sim, "imsi", &imsi, NULL); + if (imsi == NULL) + return; + + if (strlen (imsi)) + { + DEBUG ("emitting imsi-added \"%s\" for %s", imsi, + modem_oface_object_path (MODEM_OFACE (sim))); + g_signal_emit (self, signals[SIGNAL_IMSI_ADDED], 0, imsi); + } + + g_free (imsi); } static void -on_modem_property_changed (DBusGProxy *proxy, - char const *property, - GValue const *value, - gpointer _self) +on_oface_connected (ModemOface *oface, + gboolean connected, + Modem *self) { - property = modem_property_name_by_ofono_name (property); + ModemPrivate *priv = self->priv; + char *interface; + + DEBUG ("enter"); + + g_object_get (oface, "interface", &interface, NULL); + + DEBUG ("%s %s interface = %s, oface = %p", + connected ? "connected" : "disconnected", + modem_oface_object_path (oface), + interface, oface); - if (property) - g_object_set_property (G_OBJECT (_self), property, value); + if (!connected) + { + g_signal_handlers_disconnect_by_func (oface, + on_oface_connected, self); + + if (MODEM_IS_SIM_SERVICE (oface)) + g_signal_handlers_disconnect_by_func (oface, + on_sim_notify_imsi, self); + + if (g_hash_table_lookup (priv->connecting, interface)) + { + g_hash_table_remove (priv->connecting, interface); + } + else if (g_hash_table_lookup (priv->ofaces, interface)) + { + DEBUG("emitting interface-removed for %s", interface); + g_signal_emit (self, signals[SIGNAL_INTERFACE_REMOVED], 0, oface); + g_hash_table_remove (priv->ofaces, interface); + } + + g_free (interface); + + return; + } + + g_hash_table_insert (priv->ofaces, interface, g_object_ref (oface)); + g_hash_table_remove (priv->connecting, interface); + + DEBUG ("emitting interface-added for %s", interface); + + g_signal_emit (self, signals[SIGNAL_INTERFACE_ADDED], 0, oface); + + if (MODEM_IS_SIM_SERVICE (oface)) + { + g_signal_connect (oface, "notify::imsi", + G_CALLBACK(on_sim_notify_imsi), self); + on_sim_notify_imsi (MODEM_SIM_SERVICE (oface), NULL, self); + } } +static void +modem_update_interfaces (Modem *self) +{ + ModemPrivate *priv = self->priv; + ModemOface *oface; + ModemOface *already; + GHashTableIter iter[1]; + char const *object_path; + GHashTable *prev_ifhash; + char *interface; + guint i; + + DEBUG ("enter"); + + prev_ifhash = priv->ifhash; + priv->ifhash = g_hash_table_new (g_str_hash, g_str_equal); + + for (i = 0; priv->interfaces[i]; i++) + { + interface = g_strdup (priv->interfaces[i]); + g_hash_table_insert (priv->ifhash, interface, GUINT_TO_POINTER(1)); + } + + object_path = modem_oface_object_path (MODEM_OFACE (self)); + + for (i = 0; priv->interfaces[i]; i++) + { + interface = priv->interfaces[i]; + + if (g_hash_table_lookup (priv->ofaces, interface)) + continue; + if (g_hash_table_lookup (prev_ifhash, interface)) + continue; + + oface = modem_oface_new (interface, object_path); + if (oface == NULL) { + DEBUG("Modem %s ignoring interface %s", object_path, interface); + continue; + } + + DEBUG("Modem %s adding interface %s", object_path, interface); + + already = g_hash_table_lookup (priv->connecting, interface); + if (already) + { + /* interface was added, removed and added before it got connected */ + g_signal_handlers_disconnect_by_func (already, + on_oface_connected, self); + } + + g_hash_table_insert (priv->connecting, g_strdup (interface), oface); + + g_signal_connect (oface, "connected", + G_CALLBACK (on_oface_connected), self); + + modem_oface_connect (oface); + } + + g_hash_table_unref (prev_ifhash); + + DEBUG("All modem %s interfaces added", object_path); + + redo_connecting: + + for (g_hash_table_iter_init (iter, priv->connecting); + g_hash_table_iter_next (iter, (gpointer)&interface, (gpointer)&oface);) + { + if (g_hash_table_lookup (priv->ifhash, interface) == NULL) + { + modem_oface_disconnect (oface); + goto redo_connecting; + } + } + + redo_ofaces: + + for (g_hash_table_iter_init (iter, priv->ofaces); + g_hash_table_iter_next (iter, (gpointer)&interface, (gpointer)&oface);) + { + if (g_hash_table_lookup (priv->ifhash, interface) == NULL) + { + modem_oface_disconnect (oface); + goto redo_ofaces; + } + } +} + +static void +on_notify_interfaces (Modem *self, + GParamSpec *dummy1, + Modem *dummy2) +{ + modem_update_interfaces (self); +} + +/* -------------------------------------------------------------------------- */ +/* modem interface */ + char const * modem_get_modem_path (Modem const *self) { - if (!MODEM_IS_MODEM (self)) - return NULL; - - return dbus_g_proxy_get_path (self->priv->proxy); + return modem_oface_object_path (MODEM_OFACE (self)); } gboolean @@ -441,37 +666,96 @@ modem_is_online (Modem const *self) return self->priv->online; } +ModemOface * +modem_get_interface (Modem const *self, char const *interface) +{ + g_return_val_if_fail (MODEM_IS_MODEM (self), FALSE); + + return g_hash_table_lookup (self->priv->ofaces, interface); +} + gboolean modem_has_interface (Modem const *self, char const *interface) { - guint i; - g_return_val_if_fail (MODEM_IS_MODEM (self), FALSE); - if (!self->priv->interfaces) + if (!self->priv->ifhash) return FALSE; - for (i = 0; self->priv->interfaces[i]; i++) - if (!strcmp (self->priv->interfaces[i], interface)) - return TRUE; + return g_hash_table_lookup (self->priv->ifhash, interface) != NULL; +} + +ModemOface ** +modem_list_interfaces (Modem const *self) +{ + ModemPrivate *priv; + GPtrArray *array; + char *key; + ModemOface *oface; + GHashTableIter iter[1]; + + g_return_val_if_fail (MODEM_IS_MODEM (self), g_new (ModemOface *, 1)); - return FALSE; + priv = self->priv; + array = g_ptr_array_sized_new (g_hash_table_size (priv->ofaces) + 1); + + for (g_hash_table_iter_init (iter, priv->ofaces); + g_hash_table_iter_next (iter, (gpointer)&key, (gpointer)&oface);) + { + g_ptr_array_add(array, oface); + } + + g_ptr_array_add (array, NULL); + + return (ModemOface **)g_ptr_array_free (array, FALSE); } gboolean modem_supports_sim (Modem const *self) { - return modem_has_interface (self, OFONO_IFACE_SIM); + return modem_get_interface (self, OFONO_IFACE_SIM) != NULL; } gboolean modem_supports_call (Modem const *self) { - return modem_has_interface (self, OFONO_IFACE_CALL_MANAGER); + return modem_get_interface (self, OFONO_IFACE_CALL_MANAGER) != NULL; } gboolean modem_supports_sms (Modem const *self) { - return modem_has_interface (self, OFONO_IFACE_SMS); + return modem_get_interface (self, OFONO_IFACE_SMS) != NULL; +} + +gboolean +modem_has_imsi (Modem const *self, gchar const *imsi) +{ + ModemSIMService *sim; + gchar *sim_imsi; + gboolean match; + + g_return_val_if_fail (MODEM_IS_MODEM (self), FALSE); + g_return_val_if_fail (imsi != NULL, FALSE); + + sim = (ModemSIMService *)modem_get_interface (self, OFONO_IFACE_SIM); + if (sim == NULL) + return FALSE; + + g_object_get(sim, "imsi", &sim_imsi, NULL); + + match = strcmp(sim_imsi, imsi) == 0; + + g_free(sim_imsi); + + return match; +} + +gboolean +modem_has_imei (Modem const *self, gchar const *imei) +{ + g_return_val_if_fail (MODEM_IS_MODEM (self), FALSE); + g_return_val_if_fail (imei != NULL, FALSE); + + return g_strcmp0(self->priv->imei, imei) == 0; } diff --git a/modem/modem.h b/modem/modem.h index e907b18..4cad466 100644 --- a/modem/modem.h +++ b/modem/modem.h @@ -1,7 +1,7 @@ /* * modem/modem.h - Interface towards oFono modem instance * - * Copyright (C) 2009 Nokia Corporation + * Copyright (C) 2009,2010 Nokia Corporation * @author Pekka Pessi * * This work is free software; you can redistribute it and/or @@ -24,6 +24,7 @@ #include #include +#include G_BEGIN_DECLS @@ -32,11 +33,11 @@ typedef struct _ModemClass ModemClass; typedef struct _ModemPrivate ModemPrivate; struct _ModemClass { - GObjectClass parent_class; + ModemOfaceClass parent_class; }; struct _Modem { - GObject parent; + ModemOface parent; ModemPrivate *priv; }; @@ -57,17 +58,22 @@ GType modem_get_type (void); /* ---------------------------------------------------------------------- */ -char const *modem_property_name_by_ofono_name (char const *name); - char const *modem_get_modem_path (Modem const *self); gboolean modem_is_powered (Modem const *self); gboolean modem_is_online (Modem const *self); gboolean modem_has_interface (Modem const *self, char const *interface); + +ModemOface **modem_list_interfaces (Modem const *self); + gboolean modem_supports_sim (Modem const *self); gboolean modem_supports_call (Modem const *self); gboolean modem_supports_sms (Modem const *self); +gboolean modem_has_imsi (Modem const *self, gchar const *imsi); + +gboolean modem_has_imei (Modem const *self, gchar const *imei); + G_END_DECLS #endif /* #ifndef _MODEM_MODEM_H_*/ -- cgit v1.2.3