cdma: implement registration in Simple.Connect path

Wait a bit for the modem to register before trying to dial.
This commit is contained in:
Dan Williams
2009-10-12 22:44:03 -07:00
parent f916d939f3
commit f4ada20709

View File

@@ -28,6 +28,14 @@
#include "mm-callback-info.h" #include "mm-callback-info.h"
#include "mm-serial-parsers.h" #include "mm-serial-parsers.h"
static void simple_reg_callback (MMModemCdma *modem,
MMModemCdmaRegistrationState cdma_1x_reg_state,
MMModemCdmaRegistrationState evdo_reg_state,
GError *error,
gpointer user_data);
static void simple_state_machine (MMModem *modem, GError *error, gpointer user_data);
static gpointer mm_generic_cdma_parent_class = NULL; static gpointer mm_generic_cdma_parent_class = NULL;
#define MM_GENERIC_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_GENERIC_CDMA, MMGenericCdmaPrivate)) #define MM_GENERIC_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_GENERIC_CDMA, MMGenericCdmaPrivate))
@@ -46,6 +54,11 @@ typedef struct {
MMModemCdmaRegistrationState cdma_1x_reg_state; MMModemCdmaRegistrationState cdma_1x_reg_state;
MMModemCdmaRegistrationState evdo_reg_state; MMModemCdmaRegistrationState evdo_reg_state;
guint reg_tries;
guint reg_retry_id;
guint reg_state_changed_id;
MMCallbackInfo *simple_connect_info;
MMSerialPort *primary; MMSerialPort *primary;
MMSerialPort *secondary; MMSerialPort *secondary;
MMPort *data; MMPort *data;
@@ -279,6 +292,34 @@ mm_generic_cdma_evdo_get_registration_state_sync (MMGenericCdma *self)
/*****************************************************************************/ /*****************************************************************************/
static void
registration_cleanup (MMGenericCdma *self, GQuark error_class, guint32 error_num)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
GError *error = NULL;
priv->reg_tries = 0;
if (priv->reg_state_changed_id) {
g_signal_handler_disconnect (self, priv->reg_state_changed_id);
priv->reg_state_changed_id = 0;
}
if (priv->reg_retry_id) {
g_source_remove (priv->reg_retry_id);
priv->reg_retry_id = 0;
}
/* Return an error to any explicit callers of simple_connect */
if (priv->simple_connect_info && error_class) {
error = g_error_new_literal (error_class, error_num,
"Connection attempt terminated");
simple_state_machine (MM_MODEM (self), error, priv->simple_connect_info);
g_error_free (error);
}
priv->simple_connect_info = NULL;
}
static void static void
enable_error_reporting_done (MMSerialPort *port, enable_error_reporting_done (MMSerialPort *port,
GString *response, GString *response,
@@ -342,7 +383,8 @@ enable (MMModem *modem,
MMModemFn callback, MMModemFn callback,
gpointer user_data) gpointer user_data)
{ {
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem); MMGenericCdma *self = MM_GENERIC_CDMA (modem);
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
MMCallbackInfo *info; MMCallbackInfo *info;
info = mm_callback_info_new (modem, callback, user_data); info = mm_callback_info_new (modem, callback, user_data);
@@ -376,9 +418,13 @@ disable (MMModem *modem,
MMModemFn callback, MMModemFn callback,
gpointer user_data) gpointer user_data)
{ {
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem); MMGenericCdma *self = MM_GENERIC_CDMA (modem);
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
MMCallbackInfo *info; MMCallbackInfo *info;
/* Tear down any ongoing registration */
registration_cleanup (self, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL);
info = mm_callback_info_new (modem, callback, user_data); info = mm_callback_info_new (modem, callback, user_data);
if (priv->secondary) if (priv->secondary)
@@ -396,13 +442,16 @@ dial_done (MMSerialPort *port,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
{ {
MMGenericCdmaPrivate *priv;
MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMGenericCdma *self = MM_GENERIC_CDMA (info->modem);
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);;
if (error) if (error)
info->error = g_error_copy (error); info->error = g_error_copy (error);
else { else {
priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); /* Clear reg tries; we're obviously registered by this point */
registration_cleanup (self, 0, 0);
mm_port_set_connected (priv->data, TRUE); mm_port_set_connected (priv->data, TRUE);
} }
@@ -1105,6 +1154,7 @@ get_registration_state (MMModemCdma *modem,
typedef enum { typedef enum {
SIMPLE_STATE_BEGIN = 0, SIMPLE_STATE_BEGIN = 0,
SIMPLE_STATE_ENABLE, SIMPLE_STATE_ENABLE,
SIMPLE_STATE_REGISTER,
SIMPLE_STATE_CONNECT, SIMPLE_STATE_CONNECT,
SIMPLE_STATE_DONE SIMPLE_STATE_DONE
} SimpleState; } SimpleState;
@@ -1129,12 +1179,96 @@ simple_get_string_property (MMCallbackInfo *info, const char *name, GError **err
return NULL; return NULL;
} }
static gboolean
simple_reg_retry (gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
mm_modem_cdma_get_registration_state (MM_MODEM_CDMA (info->modem),
simple_reg_callback,
info);
return TRUE;
}
static void
simple_reg_callback (MMModemCdma *modem,
MMModemCdmaRegistrationState cdma_1x_reg_state,
MMModemCdmaRegistrationState evdo_reg_state,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
gboolean no_service_error = FALSE;
if ( error
&& (error->domain == MM_MOBILE_ERROR)
&& (error->code == MM_MOBILE_ERROR_NO_NETWORK))
no_service_error = TRUE;
/* Fail immediately on anything but "no service" */
if (error && !no_service_error) {
simple_state_machine (MM_MODEM (modem), error, info);
return;
}
if ( no_service_error
|| ( (cdma_1x_reg_state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
&& (evdo_reg_state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN))) {
/* Not registered yet, queue up a retry */
priv->reg_tries++;
if (priv->reg_tries > 5) {
error = g_error_new_literal (MM_MOBILE_ERROR,
MM_MOBILE_ERROR_NO_NETWORK,
"No service");
simple_state_machine (MM_MODEM (modem), error, info);
g_error_free (error);
return;
}
/* otherwise, just try again in a bit */
if (!priv->reg_retry_id)
priv->reg_retry_id = g_timeout_add_seconds (4, simple_reg_retry, info);
} else {
/* Yay, at least one of 1x or EVDO is registered, we can proceed to dial */
simple_state_machine (MM_MODEM (modem), NULL, info);
}
}
static void
reg_state_changed (MMModemCdma *self,
MMModemCdmaRegistrationState cdma_1x_new_state,
MMModemCdmaRegistrationState evdo_new_state,
gpointer user_data)
{
/* Disabled for now... changing the registration state from the
* subclass' query_registration_state handler also emits the registration
* state changed signal, which will call this function, and execute
* simple_state_machine() to advance to the next state. Then however
* query_registration_state will call its callback, which ends up in
* simple_reg_callback(), which calls simple_state_machine() too in
* the same mainloop iteration. Not good. So until that's sorted out
* we'll just have to poll registration state (every 4 seconds so its
* not that bad.
*/
#if 0
MMCallbackInfo *info = user_data;
/* If we're registered, we can proceed */
if ( (cdma_1x_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
|| (evdo_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN))
simple_state_machine (MM_MODEM (modem), NULL, info);
#endif
}
static void static void
simple_state_machine (MMModem *modem, GError *error, gpointer user_data) simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
{ {
MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMCallbackInfo *info = (MMCallbackInfo *) user_data;
const char *str; MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem);
SimpleState state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "simple-connect-state")); SimpleState state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "simple-connect-state"));
const char *str;
guint id;
if (error) { if (error) {
info->error = g_error_copy (error); info->error = g_error_copy (error);
@@ -1147,8 +1281,20 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
mm_modem_enable (modem, simple_state_machine, info); mm_modem_enable (modem, simple_state_machine, info);
break; break;
case SIMPLE_STATE_ENABLE: case SIMPLE_STATE_ENABLE:
str = simple_get_string_property (info, "number", &info->error); state = SIMPLE_STATE_REGISTER;
mm_modem_cdma_get_registration_state (MM_MODEM_CDMA (modem),
simple_reg_callback,
info);
id = g_signal_connect (modem,
MM_MODEM_CDMA_REGISTRATION_STATE_CHANGED,
G_CALLBACK (reg_state_changed),
info);
priv->reg_state_changed_id = id;
break;
case SIMPLE_STATE_REGISTER:
registration_cleanup (MM_GENERIC_CDMA (modem), 0, 0);
state = SIMPLE_STATE_CONNECT; state = SIMPLE_STATE_CONNECT;
str = simple_get_string_property (info, "number", &info->error);
mm_modem_connect (modem, str, simple_state_machine, info); mm_modem_connect (modem, str, simple_state_machine, info);
break; break;
case SIMPLE_STATE_CONNECT: case SIMPLE_STATE_CONNECT:
@@ -1159,9 +1305,10 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
} }
out: out:
if (info->error || state == SIMPLE_STATE_DONE) if (info->error || state == SIMPLE_STATE_DONE) {
registration_cleanup (MM_GENERIC_CDMA (modem), 0, 0);
mm_callback_info_schedule (info); mm_callback_info_schedule (info);
else } else
mm_callback_info_set_data (info, "simple-connect-state", GUINT_TO_POINTER (state), NULL); mm_callback_info_set_data (info, "simple-connect-state", GUINT_TO_POINTER (state), NULL);
} }
@@ -1171,10 +1318,22 @@ simple_connect (MMModemSimple *simple,
MMModemFn callback, MMModemFn callback,
gpointer user_data) gpointer user_data)
{ {
MMGenericCdma *self = MM_GENERIC_CDMA (simple);
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
MMCallbackInfo *info; MMCallbackInfo *info;
GError *error = NULL; GError *error = NULL;
if (priv->simple_connect_info) {
error = g_error_new_literal (MM_MODEM_ERROR,
MM_MODEM_ERROR_OPERATION_IN_PROGRESS,
"Connection is already in progress");
callback (MM_MODEM (simple), error, user_data);
g_error_free (error);
return;
}
info = mm_callback_info_new (MM_MODEM (simple), callback, user_data); info = mm_callback_info_new (MM_MODEM (simple), callback, user_data);
priv->simple_connect_info = info;
mm_callback_info_set_data (info, "simple-connect-properties", mm_callback_info_set_data (info, "simple-connect-properties",
g_hash_table_ref (properties), g_hash_table_ref (properties),
(GDestroyNotify) g_hash_table_unref); (GDestroyNotify) g_hash_table_unref);
@@ -1249,6 +1408,16 @@ simple_get_status (MMModemSimple *simple,
/*****************************************************************************/ /*****************************************************************************/
static void
modem_valid_changed (MMGenericCdma *self, GParamSpec *pspec, gpointer user_data)
{
/* Be paranoid about tearing down any pending registration */
if (!mm_modem_get_valid (MM_MODEM (self)))
registration_cleanup (self, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL);
}
/*****************************************************************************/
static void static void
modem_init (MMModem *modem_class) modem_init (MMModem *modem_class)
{ {
@@ -1278,6 +1447,24 @@ modem_simple_init (MMModemSimple *class)
class->get_status = simple_get_status; class->get_status = simple_get_status;
} }
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
{
GObject *object;
object = G_OBJECT_CLASS (mm_generic_cdma_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (object) {
g_signal_connect (object, "notify::" MM_MODEM_VALID,
G_CALLBACK (modem_valid_changed), NULL);
}
return object;
}
static void static void
mm_generic_cdma_init (MMGenericCdma *self) mm_generic_cdma_init (MMGenericCdma *self)
{ {
@@ -1363,12 +1550,22 @@ get_property (GObject *object, guint prop_id,
} }
} }
static void
dispose (GObject *object)
{
registration_cleanup (MM_GENERIC_CDMA (object), MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL);
G_OBJECT_CLASS (mm_generic_cdma_parent_class)->dispose (object);
}
static void static void
finalize (GObject *object) finalize (GObject *object)
{ {
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (object); MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (object);
g_free (priv->driver); g_free (priv->driver);
g_free (priv->plugin);
g_free (priv->device);
G_OBJECT_CLASS (mm_generic_cdma_parent_class)->finalize (object); G_OBJECT_CLASS (mm_generic_cdma_parent_class)->finalize (object);
} }
@@ -1384,7 +1581,9 @@ mm_generic_cdma_class_init (MMGenericCdmaClass *klass)
/* Virtual methods */ /* Virtual methods */
object_class->set_property = set_property; object_class->set_property = set_property;
object_class->get_property = get_property; object_class->get_property = get_property;
object_class->dispose = dispose;
object_class->finalize = finalize; object_class->finalize = finalize;
object_class->constructor = constructor;
/* Properties */ /* Properties */
g_object_class_override_property (object_class, g_object_class_override_property (object_class,