diff options
author | Dan Williams <dcbw@redhat.com> | 2009-10-09 16:17:13 -0700 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2009-10-09 16:17:13 -0700 |
commit | 91171cdae295352011252d28d3d777960d0d876a (patch) | |
tree | 647a38f9c6e61cea264f1fdaa3ba109e030b7206 | |
parent | a088f12956763eb99a8f8b37934cf038a0b14cc0 (diff) |
cdma: implement generic registration state handling
-rw-r--r-- | introspection/mm-modem-cdma.xml | 34 | ||||
-rw-r--r-- | src/mm-generic-cdma.c | 194 | ||||
-rw-r--r-- | src/mm-generic-cdma.h | 11 | ||||
-rw-r--r-- | src/mm-modem-cdma.c | 46 | ||||
-rw-r--r-- | src/mm-modem-cdma.h | 34 | ||||
-rwxr-xr-x | test/mm-test.py | 18 |
6 files changed, 308 insertions, 29 deletions
diff --git a/introspection/mm-modem-cdma.xml b/introspection/mm-modem-cdma.xml index 0c7e9e34..4f18d371 100644 --- a/introspection/mm-modem-cdma.xml +++ b/introspection/mm-modem-cdma.xml @@ -53,5 +53,39 @@ </arg> </signal> + <method name="GetRegistrationState"> + <tp:docstring>Get device registration state.</tp:docstring> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_get_registration_state"/> + <arg name="state" type="u" direction="out" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE"> + <tp:docstring>Registration state.</tp:docstring> + </arg> + </method> + + <signal name="RegistrationStateChanged"> + <tp:docstring> + The device registration state changed. + </tp:docstring> + <arg name="state" type="u" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE"> + <tp:docstring>Registration state.</tp:docstring> + </arg> + </signal> + + <tp:enum name="MM_MODEM_CDMA_REGISTRATION_STATE" type="u"> + <tp:enumvalue suffix="UNKNOWN" value="0"> + <tp:docstring>Registration status is unknown or the device is not registered.</tp:docstring> + </tp:enumvalue> + <tp:enumvalue suffix="REGISTERED" value="1"> + <tp:docstring>Registered, but roaming status is unknown or cannot be provided by the device. The device may or may not be roaming.</tp:docstring> + </tp:enumvalue> + <tp:enumvalue suffix="HOME" value="2"> + <tp:docstring>Currently registered on the home network.</tp:docstring> + </tp:enumvalue> + <tp:enumvalue suffix="ROAMING" value="3"> + <tp:docstring>Currently registered on a roaming network.</tp:docstring> + </tp:enumvalue> + </tp:enum> + </interface> </node> + diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index 0292aa32..00b8d027 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -40,6 +40,7 @@ typedef struct { guint32 signal_quality; guint32 ip_method; gboolean valid; + MMModemCdmaRegistrationState reg_state; MMSerialPort *primary; MMSerialPort *secondary; @@ -62,20 +63,6 @@ mm_generic_cdma_new (const char *device, NULL)); } -static const char * -strip_response (const char *resp, const char *cmd) -{ - const char *p = resp; - - if (p) { - if (!strncmp (p, cmd, strlen (cmd))) - p += strlen (cmd); - while (*p == ' ') - p++; - } - return p; -} - /*****************************************************************************/ static void @@ -184,6 +171,30 @@ release_port (MMModem *modem, const char *subsys, const char *name) check_valid (MM_GENERIC_CDMA (modem)); } +/*****************************************************************************/ + +void +mm_generic_cdma_set_registration_state (MMGenericCdma *self, + MMModemCdmaRegistrationState new_state) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_GENERIC_CDMA (self)); + + MM_GENERIC_CDMA_GET_PRIVATE (self)->reg_state = new_state; + mm_modem_cdma_emit_registration_state_changed (MM_MODEM_CDMA (self), new_state); +} + +MMModemCdmaRegistrationState +mm_generic_cdma_get_registration_state_sync (MMGenericCdma *self) +{ + g_return_val_if_fail (self != NULL, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN); + g_return_val_if_fail (MM_IS_GENERIC_CDMA (self), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN); + + return MM_GENERIC_CDMA_GET_PRIVATE (self)->reg_state; +} + +/*****************************************************************************/ + static void enable_error_reporting_done (MMSerialPort *port, GString *response, @@ -364,6 +375,20 @@ card_info_invoke (MMCallbackInfo *info) info->error, info->user_data); } +static const char * +strip_response (const char *resp, const char *cmd) +{ + const char *p = resp; + + if (p) { + if (!strncmp (p, cmd, strlen (cmd))) + p += strlen (cmd); + while (*p == ' ') + p++; + } + return p; +} + static void get_version_done (MMSerialPort *port, GString *response, @@ -465,6 +490,7 @@ get_signal_quality_done (MMSerialPort *port, priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); priv->signal_quality = quality; mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL); + mm_modem_cdma_emit_signal_quality_changed (MM_MODEM_CDMA (info->modem), quality); } } else info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, @@ -678,6 +704,7 @@ serving_system_done (MMSerialPort *port, sid = 99999; if (sid == 0 || sid == 99999) { + /* NOTE: update reg_state_css_response() if this error changes */ info->error = g_error_new_literal (MM_MOBILE_ERROR, MM_MOBILE_ERROR_NO_NETWORK, "No service"); @@ -722,6 +749,134 @@ get_serving_system (MMModemCdma *modem, mm_serial_port_queue_command (priv->primary, "+CSS?", 3, serving_system_done, info); } +static void +reg_state_query_done (MMModem *modem, guint32 reg_state, GError *error, gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) + info->error = g_error_copy (error); + else { + mm_callback_info_set_result (info, GUINT_TO_POINTER (reg_state), NULL); + mm_generic_cdma_set_registration_state (MM_GENERIC_CDMA (info->modem), reg_state); + } + + mm_callback_info_schedule (info); +} + +static void +reg_state_css_response (MMModemCdma *cdma, + guint32 class, + unsigned char band, + guint32 sid, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMModem *modem = info->modem; + + /* We'll get an error if the SID isn't valid, so detect that and + * report unknown registration status. + */ + if (error) { + if ( (error->domain == MM_MOBILE_ERROR) + && (error->code == MM_MOBILE_ERROR_NO_NETWORK)) { + mm_callback_info_set_result (info, + GUINT_TO_POINTER (MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN), + NULL); + mm_generic_cdma_set_registration_state (MM_GENERIC_CDMA (modem), + MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN); + } else { + /* Some other error parsing CSS results */ + info->error = g_error_copy (error); + } + mm_callback_info_schedule (info); + return; + } + + /* SID is valid; let subclasses figure out roaming and detailed registration */ + if (MM_GENERIC_CDMA_GET_CLASS (modem)->query_registration_status) { + MM_GENERIC_CDMA_GET_CLASS (modem)->query_registration_status (MM_GENERIC_CDMA (modem), + reg_state_query_done, + info); + } else { + reg_state_query_done (modem, + MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED, + NULL, + info); + } +} + +static void +get_analog_digital_done (MMSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + const char *reply; + long int int_cad; + + if (error) { + info->error = g_error_copy (error); + goto error; + } + + /* Strip any leading command tag and spaces */ + reply = strip_response (response->str, "+CAD:"); + + errno = 0; + int_cad = strtol (reply, NULL, 10); + if ((errno == EINVAL) || (errno == ERANGE)) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Failed to parse +CAD response"); + goto error; + } + + if (int_cad == 1) { /* 1 == CDMA service */ + /* Now that we have some sort of service, check if the the device is + * registered on some network. + */ + get_serving_system (MM_MODEM_CDMA (info->modem), + reg_state_css_response, + info); + return; + } else { + /* No service */ + info->error = g_error_new_literal (MM_MOBILE_ERROR, + MM_MOBILE_ERROR_NO_NETWORK, + "No service"); + } + +error: + mm_callback_info_schedule (info); +} + +static void +get_registration_state (MMModemCdma *modem, + MMModemUIntFn callback, + gpointer user_data) +{ + MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem); + MMCallbackInfo *info; + gboolean connected; + + connected = mm_port_get_connected (MM_PORT (priv->primary)); + if (connected && !priv->secondary) { + g_message ("Returning saved registration state %d", priv->reg_state); + callback (MM_MODEM (modem), priv->reg_state, NULL, user_data); + return; + } + + info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); + /* Prefer secondary port for registration status */ + mm_serial_port_queue_command (priv->secondary ? priv->secondary : priv->primary, + "+CAD?", + 3, + get_analog_digital_done, info); +} + /*****************************************************************************/ /* MMModemSimple interface */ @@ -886,11 +1041,12 @@ modem_init (MMModem *modem_class) } static void -modem_cdma_init (MMModemCdma *cdma_modem_class) +modem_cdma_init (MMModemCdma *cdma_class) { - cdma_modem_class->get_signal_quality = get_signal_quality; - cdma_modem_class->get_esn = get_esn; - cdma_modem_class->get_serving_system = get_serving_system; + cdma_class->get_signal_quality = get_signal_quality; + cdma_class->get_esn = get_esn; + cdma_class->get_serving_system = get_serving_system; + cdma_class->get_registration_state = get_registration_state; } static void @@ -921,7 +1077,7 @@ set_property (GObject *object, guint prop_id, priv->plugin = g_value_dup_string (value); break; case MM_MODEM_PROP_MASTER_DEVICE: - /* Constrcut only */ + /* Construct only */ priv->device = g_value_dup_string (value); break; case MM_MODEM_PROP_IP_METHOD: diff --git a/src/mm-generic-cdma.h b/src/mm-generic-cdma.h index 670f5cbd..1f3d5989 100644 --- a/src/mm-generic-cdma.h +++ b/src/mm-generic-cdma.h @@ -19,6 +19,7 @@ #include "mm-modem.h" #include "mm-modem-base.h" +#include "mm-modem-cdma.h" #define MM_TYPE_GENERIC_CDMA (mm_generic_cdma_get_type ()) #define MM_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdma)) @@ -33,6 +34,10 @@ typedef struct { typedef struct { MMModemBaseClass parent; + + void (*query_registration_status) (MMGenericCdma *self, + MMModemUIntFn callback, + gpointer user_data); } MMGenericCdmaClass; GType mm_generic_cdma_get_type (void); @@ -41,4 +46,10 @@ MMModem *mm_generic_cdma_new (const char *device, const char *driver, const char *plugin); +/* Private, for subclasses */ +void mm_generic_cdma_set_registration_state (MMGenericCdma *self, + MMModemCdmaRegistrationState new_state); + +MMModemCdmaRegistrationState mm_generic_cdma_get_registration_state_sync (MMGenericCdma *self); + #endif /* MM_GENERIC_CDMA_H */ diff --git a/src/mm-modem-cdma.c b/src/mm-modem-cdma.c index 02ef788c..0f5bc3d9 100644 --- a/src/mm-modem-cdma.c +++ b/src/mm-modem-cdma.c @@ -23,11 +23,13 @@ static void impl_modem_cdma_get_signal_quality (MMModemCdma *modem, DBusGMethodInvocation *context); static void impl_modem_cdma_get_esn (MMModemCdma *modem, DBusGMethodInvocation *context); static void impl_modem_cdma_get_serving_system (MMModemCdma *modem, DBusGMethodInvocation *context); +static void impl_modem_cdma_get_registration_state (MMModemCdma *modem, DBusGMethodInvocation *context); #include "mm-modem-cdma-glue.h" enum { SIGNAL_QUALITY, + REGISTRATION_STATE_CHANGED, LAST_SIGNAL }; @@ -212,14 +214,42 @@ impl_modem_cdma_get_signal_quality (MMModemCdma *modem, DBusGMethodInvocation *c } void -mm_modem_cdma_signal_quality (MMModemCdma *self, - guint32 quality) +mm_modem_cdma_emit_signal_quality_changed (MMModemCdma *self, guint32 quality) { g_return_if_fail (MM_IS_MODEM_CDMA (self)); g_signal_emit (self, signals[SIGNAL_QUALITY], 0, quality); } +void +mm_modem_cdma_get_registration_state (MMModemCdma *self, + MMModemUIntFn callback, + gpointer user_data) +{ + g_return_if_fail (MM_IS_MODEM_CDMA (self)); + g_return_if_fail (callback != NULL); + + if (MM_MODEM_CDMA_GET_INTERFACE (self)->get_registration_state) + MM_MODEM_CDMA_GET_INTERFACE (self)->get_registration_state (self, callback, user_data); + else + uint_op_not_supported (MM_MODEM (self), callback, user_data); +} + +static void +impl_modem_cdma_get_registration_state (MMModemCdma *modem, DBusGMethodInvocation *context) +{ + mm_modem_cdma_get_registration_state (modem, uint_call_done, context); +} + +void +mm_modem_cdma_emit_registration_state_changed (MMModemCdma *self, + MMModemCdmaRegistrationState new_state) +{ + g_return_if_fail (MM_IS_MODEM_CDMA (self)); + + g_signal_emit (self, signals[REGISTRATION_STATE_CHANGED], 0, new_state); +} + /*****************************************************************************/ static void @@ -239,8 +269,16 @@ mm_modem_cdma_init (gpointer g_iface) G_STRUCT_OFFSET (MMModemCdma, signal_quality), NULL, NULL, g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, - G_TYPE_UINT); + G_TYPE_NONE, 1, G_TYPE_UINT); + + signals[REGISTRATION_STATE_CHANGED] = + g_signal_new ("registration-state-changed", + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MMModemCdma, registration_state_changed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); initialized = TRUE; } diff --git a/src/mm-modem-cdma.h b/src/mm-modem-cdma.h index 5a5de3d5..bd8dfa3f 100644 --- a/src/mm-modem-cdma.h +++ b/src/mm-modem-cdma.h @@ -19,11 +19,22 @@ #include <mm-modem.h> -#define MM_TYPE_MODEM_CDMA (mm_modem_cdma_get_type ()) -#define MM_MODEM_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_CDMA, MMModemCdma)) -#define MM_IS_MODEM_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_CDMA)) +typedef enum { + MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN = 0, + MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED = 1, + MM_MODEM_CDMA_REGISTRATION_STATE_HOME = 2, + MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING = 3, + + MM_MODEM_CDMA_REGISTRATION_STATE_LAST = MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING +} MMModemCdmaRegistrationState; + +#define MM_TYPE_MODEM_CDMA (mm_modem_cdma_get_type ()) +#define MM_MODEM_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_CDMA, MMModemCdma)) +#define MM_IS_MODEM_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_CDMA)) #define MM_MODEM_CDMA_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM_CDMA, MMModemCdma)) +#define MM_MODEM_CDMA_REGISTRATION_STATE_CHANGED "registration-state-changed" + typedef struct _MMModemCdma MMModemCdma; typedef void (*MMModemCdmaServingSystemFn) (MMModemCdma *modem, @@ -49,9 +60,16 @@ struct _MMModemCdma { MMModemCdmaServingSystemFn callback, gpointer user_data); + void (*get_registration_state) (MMModemCdma *self, + MMModemUIntFn callback, + gpointer user_data); + /* Signals */ void (*signal_quality) (MMModemCdma *self, guint32 quality); + + void (*registration_state_changed) (MMModemCdma *self, + MMModemCdmaRegistrationState new_state); }; GType mm_modem_cdma_get_type (void); @@ -68,9 +86,15 @@ void mm_modem_cdma_get_serving_system (MMModemCdma *self, MMModemCdmaServingSystemFn callback, gpointer user_data); +void mm_modem_cdma_get_registration_state (MMModemCdma *self, + MMModemUIntFn callback, + gpointer user_data); + /* Protected */ -void mm_modem_cdma_signal_quality (MMModemCdma *self, - guint32 quality); +void mm_modem_cdma_emit_signal_quality_changed (MMModemCdma *self, guint32 new_quality); + +void mm_modem_cdma_emit_registration_state_changed (MMModemCdma *self, + MMModemCdmaRegistrationState new_state); #endif /* MM_MODEM_CDMA_H */ diff --git a/test/mm-test.py b/test/mm-test.py index 67769c57..9a7be763 100755 --- a/test/mm-test.py +++ b/test/mm-test.py @@ -35,6 +35,16 @@ def get_cdma_band_class(band_class): else: return "Unknown" +def get_reg_state(state): + if state == 1: + return "registered (roaming unknown)" + elif state == 2: + return "registered on home network" + elif state == 4: + return "registered on roaming network" + else: + return "unknown" + def inspect_cdma(proxy, dump_private): cdma = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_CDMA) @@ -45,8 +55,14 @@ def inspect_cdma(proxy, dump_private): except dbus.exceptions.DBusException: esn = "<unavailable>" + print "" print "ESN: %s" % esn - print "-------------------" + + try: + state = cdma.GetRegistrationState() + print "Registration: %s" % get_reg_state (state) + except dbus.exceptions.DBusException, e: + print "Error reading registration state: %s" % e try: info = cdma.GetServingSystem() |