aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2010-03-09 21:31:57 -0800
committerDan Williams <dcbw@redhat.com>2010-03-09 21:31:57 -0800
commit38514db896ea8706375c222e1262fa10b830c4c6 (patch)
tree5b87f1073bbe3f019744dc10c3316e0e374b4ff6 /src
parent07fc116d5a16b1f168c120c298b747b9d9bbe8d8 (diff)
gsm: let generic class handle signal quality caching and updates
Diffstat (limited to 'src')
-rw-r--r--src/mm-generic-gsm.c123
-rw-r--r--src/mm-generic-gsm.h5
2 files changed, 107 insertions, 21 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 8d013a52..5d209366 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -78,6 +78,8 @@ typedef struct {
guint pending_reg_id;
MMCallbackInfo *pending_reg_info;
+ guint signal_quality_id;
+ time_t signal_quality_timestamp;
guint32 signal_quality;
guint32 cid;
@@ -144,14 +146,6 @@ mm_generic_gsm_get_cid (MMGenericGsm *modem)
return MM_GENERIC_GSM_GET_PRIVATE (modem)->cid;
}
-static void
-got_signal_quality (MMModem *modem,
- guint32 result,
- GError *error,
- gpointer user_data)
-{
-}
-
typedef struct {
const char *result;
const char *normalized;
@@ -905,6 +899,11 @@ disable (MMModem *modem,
priv->poll_id = 0;
}
+ if (priv->signal_quality_id) {
+ g_source_remove (priv->signal_quality_id);
+ priv->signal_quality_id = 0;
+ }
+
priv->lac[0] = 0;
priv->lac[1] = 0;
priv->cell_id[0] = 0;
@@ -1361,6 +1360,15 @@ mm_generic_gsm_pending_registration_stop (MMGenericGsm *modem)
}
}
+static void
+got_signal_quality (MMModem *modem,
+ guint32 quality,
+ GError *error,
+ gpointer user_data)
+{
+ mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (modem), quality);
+}
+
void
mm_generic_gsm_set_reg_status (MMGenericGsm *modem,
MMModemGsmNetworkRegStatus status)
@@ -2138,26 +2146,91 @@ set_apn (MMModemGsmNetwork *modem,
/* GetSignalQuality */
+static gboolean
+emit_signal_quality_change (gpointer user_data)
+{
+ MMGenericGsm *self = MM_GENERIC_GSM (user_data);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+ priv->signal_quality_id = 0;
+ priv->signal_quality_timestamp = time (NULL);
+ mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (self), priv->signal_quality);
+ return FALSE;
+}
+
+void
+mm_generic_gsm_update_signal_quality (MMGenericGsm *self, guint32 quality)
+{
+ MMGenericGsmPrivate *priv;
+ guint delay = 0;
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (MM_IS_GENERIC_GSM (self));
+ g_return_if_fail (quality <= 100);
+
+ priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+ if (priv->signal_quality == quality)
+ return;
+
+ priv->signal_quality = quality;
+
+ /* Some modems will send unsolcited signal quality changes quite often,
+ * so rate-limit them to every few seconds. Track the last time we
+ * emitted signal quality so that we send the signal immediately if there
+ * haven't been any updates in a while.
+ */
+ if (!priv->signal_quality_id) {
+ if (priv->signal_quality_timestamp > 0) {
+ time_t curtime;
+ long int diff;
+
+ curtime = time (NULL);
+ diff = curtime - priv->signal_quality_timestamp;
+ if (diff == 0) {
+ /* If the device is sending more than one update per second,
+ * make sure we don't spam clients with signals.
+ */
+ delay = 3;
+ } else if ((diff > 0) && (diff <= 3)) {
+ /* Emitted an update less than 3 seconds ago; schedule an update
+ * 3 seconds after the previous one.
+ */
+ delay = (guint) diff;
+ } else {
+ /* Otherwise, we haven't emitted an update in the last 3 seconds,
+ * or the user turned their clock back, or something like that.
+ */
+ delay = 0;
+ }
+ }
+
+ priv->signal_quality_id = g_timeout_add_seconds (delay,
+ emit_signal_quality_change,
+ self);
+ }
+}
+
static void
get_signal_quality_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
- MMGenericGsmPrivate *priv;
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
char *reply = response->str;
+ gboolean parsed = FALSE;
- if (error)
- info->error = g_error_copy (error);
- else if (!strncmp (reply, "+CSQ: ", 6)) {
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error)
+ goto done;
+
+ if (!strncmp (reply, "+CSQ: ", 6)) {
/* Got valid reply */
int quality;
int ber;
- reply += 6;
-
- if (sscanf (reply, "%d, %d", &quality, &ber)) {
+ if (sscanf (reply + 6, "%d, %d", &quality, &ber)) {
/* 99 means unknown */
if (quality == 99) {
info->error = g_error_new_literal (MM_MOBILE_ERROR,
@@ -2167,15 +2240,19 @@ get_signal_quality_done (MMSerialPort *port,
/* Normalize the quality */
quality = CLAMP (quality, 0, 31) * 100 / 31;
- priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
- priv->signal_quality = quality;
+ mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (info->modem), quality);
mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL);
}
- } else
- info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Could not parse signal quality results");
+ parsed = TRUE;
+ }
}
+ if (!parsed && !info->error) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse signal quality results");
+ }
+
+done:
mm_callback_info_schedule (info);
}
@@ -2190,7 +2267,6 @@ get_signal_quality (MMModemGsmNetwork *modem,
connected = mm_port_get_connected (MM_PORT (priv->primary));
if (connected && !priv->secondary) {
- g_message ("Returning saved signal quality %d", priv->signal_quality);
callback (MM_MODEM (modem), priv->signal_quality, NULL, user_data);
return;
}
@@ -2824,6 +2900,11 @@ finalize (GObject *object)
priv->poll_id = 0;
}
+ if (priv->signal_quality_id) {
+ g_source_remove (priv->signal_quality_id);
+ priv->signal_quality_id = 0;
+ }
+
mm_gsm_creg_regex_destroy (priv->reg_regex);
g_free (priv->oper_code);
diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h
index 13c996be..348ff4f8 100644
--- a/src/mm-generic-gsm.h
+++ b/src/mm-generic-gsm.h
@@ -133,6 +133,11 @@ void mm_generic_gsm_update_allowed_mode (MMGenericGsm *modem,
void mm_generic_gsm_update_access_technology (MMGenericGsm *modem,
MMModemGsmAccessTech act);
+/* Called to asynchronously update the current signal quality of the device;
+ * 'quality' is a 0 - 100% quality.
+ */
+void mm_generic_gsm_update_signal_quality (MMGenericGsm *modem, guint32 quality);
+
void mm_generic_gsm_check_pin (MMGenericGsm *modem,
MMModemFn callback,
gpointer user_data);