aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--introspection/mm-modem-cdma.xml34
-rw-r--r--src/mm-generic-cdma.c194
-rw-r--r--src/mm-generic-cdma.h11
-rw-r--r--src/mm-modem-cdma.c46
-rw-r--r--src/mm-modem-cdma.h34
-rwxr-xr-xtest/mm-test.py18
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()