aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mm-iface-modem.c370
-rw-r--r--src/mm-iface-modem.h5
2 files changed, 221 insertions, 154 deletions
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index acda990a..8af6a6cc 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -397,6 +397,210 @@ mm_iface_modem_update_access_tech (MMIfaceModem *self,
/*****************************************************************************/
+#define SIGNAL_QUALITY_RECENT_TIMEOUT_SEC 60
+#define SIGNAL_QUALITY_RECENT_TAG "signal-quality-recent-tag"
+static GQuark signal_quality_recent;
+
+static gboolean
+expire_signal_quality (MMIfaceModem *self)
+{
+ GVariant *old;
+ guint signal_quality = 0;
+ gboolean recent = FALSE;
+ MmGdbusModem *skeleton = NULL;
+
+ g_object_get (self,
+ MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
+ NULL);
+
+ old = mm_gdbus_modem_get_signal_quality (skeleton);
+ g_variant_get (old,
+ "(ub)",
+ &signal_quality,
+ &recent);
+
+ /* If value is already not recent, we're done */
+ if (recent) {
+ mm_dbg ("Signal quality value not updated in %us, "
+ "marking as not being recent",
+ SIGNAL_QUALITY_RECENT_TIMEOUT_SEC);
+ mm_gdbus_modem_set_signal_quality (skeleton,
+ g_variant_new ("(ub)",
+ signal_quality,
+ FALSE));
+ }
+
+ g_object_set_qdata (G_OBJECT (self),
+ signal_quality_recent,
+ GUINT_TO_POINTER (0));
+ return FALSE;
+}
+
+static void
+update_signal_quality (MMIfaceModem *self,
+ guint signal_quality,
+ gboolean expire)
+{
+ guint timeout_source;
+ MmGdbusModem *skeleton = NULL;
+ const gchar *dbus_path;
+
+ if (G_UNLIKELY (!signal_quality_recent))
+ signal_quality_recent = (g_quark_from_static_string (
+ SIGNAL_QUALITY_RECENT_TAG));
+
+ g_object_get (self,
+ MM_IFACE_MODEM_DBUS_SKELETON, &skeleton,
+ NULL);
+
+ /* Note: we always set the new value, even if the signal quality level
+ * is the same, in order to provide an up to date 'recent' flag.
+ * The only exception being if 'expire' is FALSE; in that case we assume
+ * the value won't expire and therefore can be considered obsolete
+ * already. */
+ mm_gdbus_modem_set_signal_quality (skeleton,
+ g_variant_new ("(ub)",
+ signal_quality,
+ expire));
+
+ dbus_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (self));
+ mm_info ("Modem %s: signal quality updated (%u)",
+ dbus_path,
+ signal_quality);
+
+ /* Setup timeout to clear the 'recent' flag */
+ timeout_source = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (self),
+ signal_quality_recent));
+ /* Remove any previous expiration refresh timeout */
+ if (timeout_source)
+ g_source_remove (timeout_source);
+
+ /* If we got a new expirable value, setup new timeout */
+ if (expire) {
+ timeout_source = g_timeout_add_seconds (SIGNAL_QUALITY_RECENT_TIMEOUT_SEC,
+ (GSourceFunc)expire_signal_quality,
+ self);
+ g_object_set_qdata (G_OBJECT (self),
+ signal_quality_recent,
+ GUINT_TO_POINTER (timeout_source));
+ }
+
+ g_object_unref (skeleton);
+}
+
+void
+mm_iface_modem_update_signal_quality (MMIfaceModem *self,
+ guint signal_quality)
+{
+ update_signal_quality (self, signal_quality, TRUE);
+}
+
+/*****************************************************************************/
+
+#define SIGNAL_QUALITY_CHECK_TIMEOUT_SEC 30
+#define PERIODIC_SIGNAL_QUALITY_CHECK_ENABLED_TAG "signal-quality-check-timeout-enabled-tag"
+#define PERIODIC_SIGNAL_QUALITY_CHECK_RUNNING_TAG "signal-quality-check-timeout-running-tag"
+static GQuark signal_quality_check_enabled;
+static GQuark signal_quality_check_running;
+
+static void
+signal_quality_check_ready (MMIfaceModem *self,
+ GAsyncResult *res)
+{
+ GError *error = NULL;
+ guint signal_quality;
+
+ signal_quality = MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish (self,
+ res,
+ &error);
+ if (error) {
+ mm_dbg ("Couldn't refresh signal quality: '%s'", error->message);
+ g_error_free (error);
+ } else
+ update_signal_quality (self, signal_quality, TRUE);
+
+ /* Remove the running tag */
+ g_object_set_qdata (G_OBJECT (self),
+ signal_quality_check_running,
+ GUINT_TO_POINTER (FALSE));
+}
+
+static gboolean
+periodic_signal_quality_check (MMIfaceModem *self)
+{
+ /* Only launch a new one if not one running already */
+ if (!GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (self),
+ signal_quality_check_running))) {
+ g_object_set_qdata (G_OBJECT (self),
+ signal_quality_check_running,
+ GUINT_TO_POINTER (TRUE));
+
+ MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality (
+ self,
+ (GAsyncReadyCallback)signal_quality_check_ready,
+ NULL);
+ }
+
+ return TRUE;
+}
+
+static void
+periodic_signal_quality_check_disable (MMIfaceModem *self)
+{
+ guint timeout_source;
+
+ timeout_source = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (self),
+ signal_quality_check_enabled));
+ if (timeout_source) {
+ g_source_remove (timeout_source);
+ g_object_set_qdata (G_OBJECT (self),
+ signal_quality_check_enabled,
+ GUINT_TO_POINTER (FALSE));
+
+ /* Clear the current value */
+ update_signal_quality (self, 0, FALSE);
+
+ mm_dbg ("Periodic signal quality checks disabled");
+ }
+}
+
+static void
+periodic_signal_quality_check_enable (MMIfaceModem *self)
+{
+ guint timeout_source;
+
+ if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality ||
+ !MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish) {
+ /* If loading signal quality not supported, don't even bother setting up
+ * a timeout */
+ return;
+ }
+
+ if (G_UNLIKELY (!signal_quality_check_enabled))
+ signal_quality_check_enabled = (g_quark_from_static_string (
+ PERIODIC_SIGNAL_QUALITY_CHECK_ENABLED_TAG));
+ if (G_UNLIKELY (!signal_quality_check_running))
+ signal_quality_check_running = (g_quark_from_static_string (
+ PERIODIC_SIGNAL_QUALITY_CHECK_RUNNING_TAG));
+
+ timeout_source = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (self),
+ signal_quality_check_enabled));
+ if (!timeout_source) {
+ mm_dbg ("Periodic signal quality checks enabled");
+ timeout_source = g_timeout_add_seconds (SIGNAL_QUALITY_CHECK_TIMEOUT_SEC,
+ (GSourceFunc)periodic_signal_quality_check,
+ self);
+ g_object_set_qdata (G_OBJECT (self),
+ signal_quality_check_enabled,
+ GUINT_TO_POINTER (timeout_source));
+
+ /* Get first signal quality value */
+ periodic_signal_quality_check (self);
+ }
+}
+
+/*****************************************************************************/
+
static void
bearer_list_count_connected (MMBearer *bearer,
guint *count)
@@ -469,6 +673,19 @@ mm_iface_modem_update_state (MMIfaceModem *self,
old_state,
new_state,
reason);
+
+ /* If we go to registered state (from unregistered), setup signal
+ * quality retrieval */
+ if (new_state == MM_MODEM_STATE_REGISTERED &&
+ old_state < MM_MODEM_STATE_REGISTERED) {
+ periodic_signal_quality_check_enable (self);
+ }
+ /* If we go from a registered/connected state to unregistered,
+ * cleanup signal quality retrieval */
+ else if (old_state >= MM_MODEM_STATE_REGISTERED &&
+ new_state < MM_MODEM_STATE_REGISTERED) {
+ periodic_signal_quality_check_disable (self);
+ }
}
if (skeleton)
@@ -1157,130 +1374,8 @@ mm_iface_modem_unlock_check (MMIfaceModem *self,
/*****************************************************************************/
-typedef struct _SignalQualityCheckContext SignalQualityCheckContext;
-struct _SignalQualityCheckContext {
- MMIfaceModem *self;
- MMAtSerialPort *port;
- GSimpleAsyncResult *result;
- MmGdbusModem *skeleton;
-};
-
-static SignalQualityCheckContext *
-signal_quality_check_context_new (MMIfaceModem *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SignalQualityCheckContext *ctx;
-
- ctx = g_new0 (SignalQualityCheckContext, 1);
- ctx->self = g_object_ref (self);
- ctx->port = g_object_ref (mm_base_modem_get_port_primary (MM_BASE_MODEM (self)));
- ctx->result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- signal_quality_check_context_new);
- g_object_get (ctx->self,
- MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton,
- NULL);
- g_assert (ctx->skeleton != NULL);
- return ctx;
-}
-
-static void
-signal_quality_check_context_free (SignalQualityCheckContext *ctx)
-{
- g_object_unref (ctx->self);
- g_object_unref (ctx->port);
- g_object_unref (ctx->result);
- g_object_unref (ctx->skeleton);
- g_free (ctx);
-}
-
-guint
-mm_iface_modem_signal_quality_check_finish (MMIfaceModem *self,
- GAsyncResult *res,
- gboolean *recent,
- GError **error)
-{
- guint quality = 0;
- gboolean is_recent = FALSE;
-
- if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) {
- GVariant *result;
-
- result = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
- g_variant_get (result, "(ub)", &quality, &is_recent);
- }
-
- if (recent)
- *recent = is_recent;
- return quality;
-}
-
-static void
-signal_quality_check_ready (MMIfaceModem *self,
- GAsyncResult *res,
- SignalQualityCheckContext *ctx)
-{
- GError *error = NULL;
- guint quality;
- gboolean is_recent;
-
- quality = MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish (self,
- res,
- &is_recent,
- &error);
- if (error)
- g_simple_async_result_take_error (ctx->result, error);
- else {
- GVariant *result;
-
- result = g_variant_ref_sink (g_variant_new ("(ub)", quality, is_recent));
- /* Set operation result */
- g_simple_async_result_set_op_res_gpointer (ctx->result,
- g_variant_ref (result),
- (GDestroyNotify)g_variant_unref);
- /* Set the property value in the DBus skeleton */
- mm_gdbus_modem_set_signal_quality (ctx->skeleton, result);
- g_variant_unref (result);
- }
- g_simple_async_result_complete (ctx->result);
- signal_quality_check_context_free (ctx);
-}
-
-void
-mm_iface_modem_signal_quality_check (MMIfaceModem *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SignalQualityCheckContext *ctx;
-
- ctx = signal_quality_check_context_new (self,
- callback,
- user_data);
-
- if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_signal_quality &&
- MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_signal_quality_finish) {
- MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_signal_quality (
- ctx->self,
- (GAsyncReadyCallback)signal_quality_check_ready,
- ctx);
- return;
- }
-
- /* Cannot load signal quality... set operation result */
- g_simple_async_result_set_op_res_gpointer (ctx->result,
- g_variant_new ("(ub)", 0, FALSE),
- (GDestroyNotify)g_variant_unref);
- g_simple_async_result_complete_in_idle (ctx->result);
- signal_quality_check_context_free (ctx);
-}
-
-/*****************************************************************************/
-
typedef enum {
DISABLING_STEP_FIRST,
- /* DISABLING_STEP_FLASH_PORT, */
DISABLING_STEP_MODEM_POWER_DOWN,
DISABLING_STEP_CLOSE_PORT,
DISABLING_STEP_LAST
@@ -1377,24 +1472,6 @@ mm_iface_modem_disable_finish (MMIfaceModem *self,
VOID_REPLY_READY_FN (modem_power_down)
-/* static void */
-/* interface_disabling_flash_done (MMSerialPort *port, */
-/* GError *error, */
-/* gpointer user_data) */
-/* { */
-/* DisablingContext *ctx = user_data; */
-
-/* if (error) { */
-/* g_simple_async_result_set_from_error (ctx->result, error); */
-/* disabling_context_complete_and_free (ctx); */
-/* return; */
-/* } */
-
-/* /\* Go on to next step *\/ */
-/* ctx->step++; */
-/* interface_disabling_step (ctx); */
-/* } */
-
static void
interface_disabling_step (DisablingContext *ctx)
{
@@ -1403,19 +1480,6 @@ interface_disabling_step (DisablingContext *ctx)
/* Fall down to next step */
ctx->step++;
- /* case DISABLING_STEP_FLASH_PORT: */
- /* /\* If primary port connected, flash port *\/ */
- /* if (mm_port_get_connected (MM_PORT (ctx->primary))) { */
- /* mm_serial_port_flash (MM_SERIAL_PORT (ctx->primary), */
- /* 100, */
- /* TRUE, */
- /* interface_disabling_flash_done, */
- /* ctx); */
- /* return; */
- /* } */
- /* /\* Fall down to next step *\/ */
- /* ctx->step++; */
-
case DISABLING_STEP_MODEM_POWER_DOWN:
/* CFUN=0 is dangerous and often will shoot devices in the head (that's
* what it's supposed to do). So don't use CFUN=0 by default, but let
diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h
index 45686056..944fba84 100644
--- a/src/mm-iface-modem.h
+++ b/src/mm-iface-modem.h
@@ -133,7 +133,6 @@ struct _MMIfaceModem {
gpointer user_data);
guint (*load_signal_quality_finish) (MMIfaceModem *self,
GAsyncResult *res,
- gboolean *recent,
GError **error);
/* Asynchronous reset operation */
@@ -304,6 +303,10 @@ void mm_iface_modem_update_access_tech (MMIfaceModem *self,
MMModemAccessTechnology access_tech,
guint32 mask);
+/* Allow updating signal quality */
+void mm_iface_modem_update_signal_quality (MMIfaceModem *self,
+ guint signal_quality);
+
/* Allow setting allowed modes */
void mm_iface_modem_set_allowed_modes (MMIfaceModem *self,
MMModemMode allowed,