diff options
author | Dan Williams <dcbw@redhat.com> | 2010-03-09 21:31:57 -0800 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2010-03-09 21:31:57 -0800 |
commit | 38514db896ea8706375c222e1262fa10b830c4c6 (patch) | |
tree | 5b87f1073bbe3f019744dc10c3316e0e374b4ff6 | |
parent | 07fc116d5a16b1f168c120c298b747b9d9bbe8d8 (diff) |
gsm: let generic class handle signal quality caching and updates
-rw-r--r-- | plugins/mm-modem-huawei-gsm.c | 39 | ||||
-rw-r--r-- | plugins/mm-modem-mbm.c | 14 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 123 | ||||
-rw-r--r-- | src/mm-generic-gsm.h | 5 |
4 files changed, 121 insertions, 60 deletions
diff --git a/plugins/mm-modem-huawei-gsm.c b/plugins/mm-modem-huawei-gsm.c index 67d27920..b0d6a16e 100644 --- a/plugins/mm-modem-huawei-gsm.c +++ b/plugins/mm-modem-huawei-gsm.c @@ -40,7 +40,6 @@ G_DEFINE_TYPE_EXTENDED (MMModemHuaweiGsm, mm_modem_huawei_gsm, MM_TYPE_GENERIC_G typedef struct { /* Cached state */ - guint signal_quality; MMModemGsmBand band; } MMModemHuaweiGsmPrivate; @@ -369,29 +368,6 @@ get_band (MMModemGsmNetwork *modem, } } -static void -get_signal_quality (MMModemGsmNetwork *modem, - MMModemUIntFn callback, - gpointer user_data) -{ - MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (modem); - - if (priv->signal_quality) { - /* have cached signal quality (from an unsolicited message). Use that */ - MMCallbackInfo *info; - - info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); - mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->signal_quality), NULL); - mm_callback_info_schedule (info); - } else { - /* Use the generic implementation */ - MMModemGsmNetwork *parent_gsm_network_iface; - - parent_gsm_network_iface = g_type_interface_peek_parent (MM_MODEM_GSM_NETWORK_GET_INTERFACE (modem)); - parent_gsm_network_iface->get_signal_quality (modem, callback, user_data); - } -} - /* Unsolicited message handlers */ static void @@ -400,24 +376,22 @@ handle_signal_quality_change (MMSerialPort *port, gpointer user_data) { MMModemHuaweiGsm *self = MM_MODEM_HUAWEI_GSM (user_data); - MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (self); char *str; - int quality; + int quality = 0; str = g_match_info_fetch (match_info, 1); quality = atoi (str); g_free (str); - if (quality == 99) + if (quality == 99) { /* 99 means unknown */ quality = 0; - else + } else { /* Normalize the quality */ - quality = quality * 100 / 31; + quality = CLAMP (quality, 0, 31) * 100 / 31; + } - g_debug ("Signal quality: %d", quality); - priv->signal_quality = (guint32) quality; - mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (self), (guint32) quality); + mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (self), (guint32) quality); } static void @@ -568,7 +542,6 @@ modem_gsm_network_init (MMModemGsmNetwork *class) { class->set_band = set_band; class->get_band = get_band; - class->get_signal_quality = get_signal_quality; } static void diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c index ccf20d85..ed39cec4 100644 --- a/plugins/mm-modem-mbm.c +++ b/plugins/mm-modem-mbm.c @@ -561,7 +561,7 @@ mbm_ciev_received (MMSerialPort *port, str = g_match_info_fetch (info, 2); if (str) { quality = atoi (str); - mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (user_data), quality * 20); + mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (user_data), quality * 20); } } } @@ -790,17 +790,19 @@ grab_port (MMModem *modem, } port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error); - if (port && MM_IS_SERIAL_PORT (port) && (ptype == MM_PORT_TYPE_PRIMARY)) { + if (port && MM_IS_SERIAL_PORT (port)) { GRegex *regex; + if (ptype == MM_PORT_TYPE_PRIMARY) { + regex = g_regex_new ("\\r\\n\\*E2NAP: (\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_e2nap_received, modem, NULL); + g_regex_unref (regex); + } + regex = g_regex_new ("\\r\\n\\*EMRDY: \\d\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_emrdy_received, modem, NULL); g_regex_unref (regex); - regex = g_regex_new ("\\r\\n\\*E2NAP: (\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_e2nap_received, modem, NULL); - g_regex_unref (regex); - regex = g_regex_new ("\\r\\n\\+PACSP(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_pacsp_received, modem, NULL); g_regex_unref (regex); 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); |