From 9bbc6ab53b14097c510548dde4818a596e551617 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 27 Oct 2009 15:01:00 -0700 Subject: core: initial implementation of modem states Needs more work for GSM, but should be reasonably complete for CDMA. --- src/mm-modem.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'src/mm-modem.c') diff --git a/src/mm-modem.c b/src/mm-modem.c index ca2afbd7..11934a20 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -19,6 +19,7 @@ #include "mm-modem.h" #include "mm-errors.h" #include "mm-callback-info.h" +#include "mm-marshal.h" static void impl_modem_enable (MMModem *modem, gboolean enable, DBusGMethodInvocation *context); static void impl_modem_connect (MMModem *modem, const char *number, DBusGMethodInvocation *context); @@ -57,9 +58,18 @@ mm_modem_enable (MMModem *self, MMModemFn callback, gpointer user_data) { + MMModemState state; + g_return_if_fail (MM_IS_MODEM (self)); g_return_if_fail (callback != NULL); + state = mm_modem_get_state (self); + if (state >= MM_MODEM_STATE_ENABLED) { + /* Already enabled */ + callback (self, NULL, user_data); + return; + } + if (MM_MODEM_GET_INTERFACE (self)->enable) MM_MODEM_GET_INTERFACE (self)->enable (self, callback, user_data); else @@ -71,9 +81,18 @@ mm_modem_disable (MMModem *self, MMModemFn callback, gpointer user_data) { + MMModemState state; + g_return_if_fail (MM_IS_MODEM (self)); g_return_if_fail (callback != NULL); + state = mm_modem_get_state (self); + if (state <= MM_MODEM_STATE_DISABLED) { + /* Already disabled */ + callback (self, NULL, user_data); + return; + } + if (MM_MODEM_GET_INTERFACE (self)->disable) MM_MODEM_GET_INTERFACE (self)->disable (self, callback, user_data); else @@ -381,11 +400,37 @@ mm_modem_get_device (MMModem *self) return device; } +MMModemState +mm_modem_get_state (MMModem *self) +{ + MMModemState state = MM_MODEM_STATE_UNKNOWN; + + g_object_get (G_OBJECT (self), MM_MODEM_STATE, &state, NULL); + return state; +} + +void +mm_modem_set_state (MMModem *self, + MMModemState new_state, + MMModemStateReason reason) +{ + MMModemState old_state = MM_MODEM_STATE_UNKNOWN; + + g_object_get (G_OBJECT (self), MM_MODEM_STATE, &old_state, NULL); + + if (new_state != old_state) { + g_object_set (G_OBJECT (self), MM_MODEM_STATE, new_state, NULL); + g_signal_emit_by_name (G_OBJECT (self), "state-changed", new_state, old_state, reason); +g_message ("%s: state %d -> %d", __func__, old_state, new_state); + } +} + /*****************************************************************************/ static void mm_modem_init (gpointer g_iface) { + GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); static gboolean initialized = FALSE; if (initialized) @@ -450,6 +495,26 @@ mm_modem_init (gpointer g_iface) FALSE, G_PARAM_READABLE)); + g_object_interface_install_property + (g_iface, + g_param_spec_uint (MM_MODEM_STATE, + "State", + "State", + MM_MODEM_STATE_UNKNOWN, + MM_MODEM_STATE_LAST, + MM_MODEM_STATE_UNKNOWN, + G_PARAM_READWRITE)); + + /* Signals */ + g_signal_new ("state-changed", + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MMModem, state_changed), + NULL, NULL, + mm_marshal_VOID__UINT_UINT_UINT, + G_TYPE_NONE, 3, + G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); + initialized = TRUE; } -- cgit v1.2.3-70-g09d2 From 231d2ca90b6d197d4594407fc3e6b6ee2c7fb850 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 12:57:39 -0800 Subject: core: schedule enabled/disabled callbacks to avoid infinite recursion --- src/mm-modem.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/mm-modem.c') diff --git a/src/mm-modem.c b/src/mm-modem.c index 11934a20..72efe0b9 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -65,8 +65,11 @@ mm_modem_enable (MMModem *self, state = mm_modem_get_state (self); if (state >= MM_MODEM_STATE_ENABLED) { + MMCallbackInfo *info; + /* Already enabled */ - callback (self, NULL, user_data); + info = mm_callback_info_new (self, callback, user_data); + mm_callback_info_schedule (info); return; } @@ -88,8 +91,11 @@ mm_modem_disable (MMModem *self, state = mm_modem_get_state (self); if (state <= MM_MODEM_STATE_DISABLED) { + MMCallbackInfo *info; + /* Already disabled */ - callback (self, NULL, user_data); + info = mm_callback_info_new (self, callback, user_data); + mm_callback_info_schedule (info); return; } -- cgit v1.2.3-70-g09d2 From e9964231e931f283ecf232f23f45282a22e3471a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 15:38:11 -0800 Subject: core: use modem states to protect against double operations --- src/mm-modem.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 6 deletions(-) (limited to 'src/mm-modem.c') diff --git a/src/mm-modem.c b/src/mm-modem.c index 72efe0b9..10052fa4 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -67,8 +67,16 @@ mm_modem_enable (MMModem *self, if (state >= MM_MODEM_STATE_ENABLED) { MMCallbackInfo *info; - /* Already enabled */ info = mm_callback_info_new (self, callback, user_data); + + if (state == MM_MODEM_STATE_ENABLING) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_OPERATION_IN_PROGRESS, + "The device is already being enabled."); + } else { + /* Already enabled */ + } + mm_callback_info_schedule (info); return; } @@ -79,6 +87,42 @@ mm_modem_enable (MMModem *self, async_op_not_supported (self, callback, user_data); } +static void +finish_disable (MMModem *self, + MMModemFn callback, + gpointer user_data) +{ + + if (MM_MODEM_GET_INTERFACE (self)->disable) + MM_MODEM_GET_INTERFACE (self)->disable (self, callback, user_data); + else + async_op_not_supported (self, callback, user_data); +} + +typedef struct { + MMModemFn callback; + gpointer user_data; +} DisableDisconnectInfo; + +static void +disable_disconnect_done (MMModem *self, + GError *error, + gpointer user_data) +{ + DisableDisconnectInfo *cb_data = user_data; + + /* ignore errors */ + if (error) { + g_warning ("%s: (%s): error disconnecting the modem while disabling: (%d) %s", + __func__, + mm_modem_get_device (self), + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + } + finish_disable (self, cb_data->callback, cb_data->user_data); + g_free (cb_data); +} + void mm_modem_disable (MMModem *self, MMModemFn callback, @@ -93,16 +137,30 @@ mm_modem_disable (MMModem *self, if (state <= MM_MODEM_STATE_DISABLED) { MMCallbackInfo *info; - /* Already disabled */ info = mm_callback_info_new (self, callback, user_data); + + if (state == MM_MODEM_STATE_DISABLING) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_OPERATION_IN_PROGRESS, + "The device is already being disabled."); + } else { + /* Already disabled */ + } + mm_callback_info_schedule (info); return; } - if (MM_MODEM_GET_INTERFACE (self)->disable) - MM_MODEM_GET_INTERFACE (self)->disable (self, callback, user_data); - else - async_op_not_supported (self, callback, user_data); + /* If the modem is connected, disconnect it */ + if (state >= MM_MODEM_STATE_CONNECTING) { + DisableDisconnectInfo *cb_data; + + cb_data = g_malloc0 (sizeof (DisableDisconnectInfo)); + cb_data->callback = callback; + cb_data->user_data = user_data; + mm_modem_disconnect (self, disable_disconnect_done, cb_data); + } else + finish_disable (self, callback, user_data); } static void @@ -122,10 +180,30 @@ mm_modem_connect (MMModem *self, MMModemFn callback, gpointer user_data) { + MMModemState state; + g_return_if_fail (MM_IS_MODEM (self)); g_return_if_fail (callback != NULL); g_return_if_fail (number != NULL); + state = mm_modem_get_state (self); + if (state >= MM_MODEM_STATE_CONNECTING) { + MMCallbackInfo *info; + + /* Already connecting */ + info = mm_callback_info_new (self, callback, user_data); + if (state == MM_MODEM_STATE_CONNECTING) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_OPERATION_IN_PROGRESS, + "The device is already being connected."); + } else { + /* already connected */ + } + + mm_callback_info_schedule (info); + return; + } + if (MM_MODEM_GET_INTERFACE (self)->connect) MM_MODEM_GET_INTERFACE (self)->connect (self, number, callback, user_data); else @@ -236,9 +314,30 @@ mm_modem_disconnect (MMModem *self, MMModemFn callback, gpointer user_data) { + MMModemState state; + g_return_if_fail (MM_IS_MODEM (self)); g_return_if_fail (callback != NULL); + state = mm_modem_get_state (self); + if (state <= MM_MODEM_STATE_DISCONNECTING) { + MMCallbackInfo *info; + + /* Already connecting */ + info = mm_callback_info_new (self, callback, user_data); + if (state == MM_MODEM_STATE_DISCONNECTING) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_OPERATION_IN_PROGRESS, + "The device is already being disconnected."); + } else { + /* already disconnected */ + } + + mm_callback_info_schedule (info); + return; + } + + if (MM_MODEM_GET_INTERFACE (self)->disconnect) MM_MODEM_GET_INTERFACE (self)->disconnect (self, callback, user_data); else -- cgit v1.2.3-70-g09d2 From 7f1951fec867de5553b130c21df4eb5f447889a1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 16:44:07 -0800 Subject: core: fix ordering of DISABLING and DISABLED states --- src/mm-modem.c | 2 +- src/mm-modem.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/mm-modem.c') diff --git a/src/mm-modem.c b/src/mm-modem.c index 10052fa4..b49c7070 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -134,7 +134,7 @@ mm_modem_disable (MMModem *self, g_return_if_fail (callback != NULL); state = mm_modem_get_state (self); - if (state <= MM_MODEM_STATE_DISABLED) { + if (state <= MM_MODEM_STATE_DISABLING) { MMCallbackInfo *info; info = mm_callback_info_new (self, callback, user_data); diff --git a/src/mm-modem.h b/src/mm-modem.h index 0af1e534..cf16f190 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -23,8 +23,8 @@ typedef enum { MM_MODEM_STATE_UNKNOWN = 0, - MM_MODEM_STATE_DISABLING = 10, - MM_MODEM_STATE_DISABLED = 20, + MM_MODEM_STATE_DISABLED = 10, + MM_MODEM_STATE_DISABLING = 20, MM_MODEM_STATE_ENABLING = 30, MM_MODEM_STATE_ENABLED = 40, MM_MODEM_STATE_SEARCHING = 50, -- cgit v1.2.3-70-g09d2 From 1157b59a18ee4e5da109977947181f8596f100ff Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 2 Dec 2009 14:59:26 -0800 Subject: core: pretty-print state changes --- src/mm-manager.c | 2 -- src/mm-modem.c | 43 ++++++++++++++++++++++++++++++++++++++++++- src/mm-modem.h | 2 ++ 3 files changed, 44 insertions(+), 3 deletions(-) (limited to 'src/mm-modem.c') diff --git a/src/mm-manager.c b/src/mm-manager.c index 73189146..1a93170b 100644 --- a/src/mm-manager.c +++ b/src/mm-manager.c @@ -43,8 +43,6 @@ static guint signals[LAST_SIGNAL] = { 0 }; #define MM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MANAGER, MMManagerPrivate)) -#define DBUS_PATH_TAG "dbus-path" - typedef struct { DBusGConnection *connection; GUdevClient *udev; diff --git a/src/mm-modem.c b/src/mm-modem.c index b49c7070..af67864d 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -514,19 +514,60 @@ mm_modem_get_state (MMModem *self) return state; } +static const char * +state_to_string (MMModemState state) +{ + switch (state) { + case MM_MODEM_STATE_UNKNOWN: + return "unknown"; + case MM_MODEM_STATE_DISABLED: + return "disabled"; + case MM_MODEM_STATE_DISABLING: + return "disabling"; + case MM_MODEM_STATE_ENABLING: + return "enabling"; + case MM_MODEM_STATE_ENABLED: + return "enabled"; + case MM_MODEM_STATE_SEARCHING: + return "searching"; + case MM_MODEM_STATE_REGISTERED: + return "registered"; + case MM_MODEM_STATE_DISCONNECTING: + return "disconnecting"; + case MM_MODEM_STATE_CONNECTING: + return "connecting"; + case MM_MODEM_STATE_CONNECTED: + return "connected"; + default: + g_assert_not_reached (); + break; + } + + g_assert_not_reached (); + return "(invalid)"; +} + void mm_modem_set_state (MMModem *self, MMModemState new_state, MMModemStateReason reason) { MMModemState old_state = MM_MODEM_STATE_UNKNOWN; + const char *dbus_path; g_object_get (G_OBJECT (self), MM_MODEM_STATE, &old_state, NULL); if (new_state != old_state) { g_object_set (G_OBJECT (self), MM_MODEM_STATE, new_state, NULL); g_signal_emit_by_name (G_OBJECT (self), "state-changed", new_state, old_state, reason); -g_message ("%s: state %d -> %d", __func__, old_state, new_state); + + dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG); + if (dbus_path) { + g_message ("Modem %s: state changed (%s -> %s)", + dbus_path, + state_to_string (old_state), + state_to_string (new_state)); + } } } diff --git a/src/mm-modem.h b/src/mm-modem.h index cf16f190..1a379411 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -40,6 +40,8 @@ typedef enum { MM_MODEM_STATE_REASON_NONE = 0 } MMModemStateReason; +#define DBUS_PATH_TAG "dbus-path" + #define MM_TYPE_MODEM (mm_modem_get_type ()) #define MM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM, MMModem)) #define MM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM)) -- cgit v1.2.3-70-g09d2