diff options
-rw-r--r-- | plugins/mm-modem-huawei.c | 204 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 81 | ||||
-rw-r--r-- | src/mm-generic-gsm.h | 4 |
3 files changed, 204 insertions, 85 deletions
diff --git a/plugins/mm-modem-huawei.c b/plugins/mm-modem-huawei.c index e4f30281..4f0ae36b 100644 --- a/plugins/mm-modem-huawei.c +++ b/plugins/mm-modem-huawei.c @@ -12,6 +12,8 @@ static gpointer mm_modem_huawei_parent_class = NULL; +static void pending_registration_stop (MMModemHuawei *self); + #define MM_MODEM_HUAWEI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_HUAWEI, MMModemHuaweiPrivate)) typedef struct { @@ -24,7 +26,11 @@ typedef struct { GRegex *status_regex; GRegex *reg_state_regex; + /* Pending operations */ + guint pending_registration; + /* Cached state */ + MMModemGsmNetworkRegStatus reg_status; guint signal_quality; MMModemGsmNetworkMode mode; MMModemGsmNetworkBand band; @@ -47,15 +53,74 @@ mm_modem_huawei_new (const char *data_device, } static void +reg_status_updated (MMModemHuawei *self, int new_status) +{ + MMModemHuaweiPrivate *priv = MM_MODEM_HUAWEI_GET_PRIVATE (self); + + switch (new_status) { + case 0: + priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE; + break; + case 1: + priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_HOME; + break; + case 2: + priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING; + break; + case 3: + priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_DENIED; + break; + case 4: + priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN; + break; + case 5: + priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING; + break; + default: + priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN; + break; + } + + /* Stop the pending registration in case of success or certain failure */ + if (priv->reg_status == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME || + priv->reg_status == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING || + priv->reg_status == MM_MODEM_GSM_NETWORK_REG_STATUS_DENIED) + + pending_registration_stop (self); + + g_debug ("Registration state changed: %d\n", priv->reg_status); + mm_generic_gsm_set_reg_status (MM_GENERIC_GSM (self), priv->reg_status); +} + +static void +got_reg_status (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) +{ + if (error) + g_warning ("Error getting registration status: %s", error->message); + else if (g_str_has_prefix (response->str, "+CREG: ")) { + /* Got valid reply */ + int n, stat; + + if (sscanf (response->str + 7, "%d,%d", &n, &stat)) + reg_status_updated (MM_MODEM_HUAWEI (serial), stat); + } +} + +static void parent_enable_done (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; if (error) info->error = g_error_copy (error); - else - /* Enable unsolicited registration state changes */ + else { + /* Enable unsolicited registration state changes and get the current state */ mm_serial_queue_command (MM_SERIAL (modem), "+CREG=1", 5, NULL, NULL); + mm_serial_queue_command (MM_SERIAL (modem), "+CREG?", 5, got_reg_status, NULL); + } mm_callback_info_schedule (info); } @@ -75,8 +140,105 @@ enable (MMModem *modem, info = mm_callback_info_new (modem, callback, user_data); parent_modem_iface->enable (modem, enable, parent_enable_done, info); - } else + } else { + pending_registration_stop (MM_MODEM_HUAWEI (modem)); parent_modem_iface->enable (modem, enable, callback, user_data); + } +} + +static void +pending_registration_set (MMModemHuawei *self, guint tag) +{ + MM_MODEM_HUAWEI_GET_PRIVATE (self)->pending_registration = tag; +} + +static void +pending_registration_stop (MMModemHuawei *self) +{ + guint tag; + + tag = MM_MODEM_HUAWEI_GET_PRIVATE (self)->pending_registration; + if (tag) + g_source_remove (tag); +} + +static void +pending_registration_cleanup (gpointer data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) data; + + if (!info->error) { + switch (MM_MODEM_HUAWEI_GET_PRIVATE (info->modem)->reg_status) { + case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME: + case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING: + /* Successfully registered */ + break; + case MM_MODEM_GSM_NETWORK_REG_STATUS_DENIED: + info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_NETWORK_NOT_ALLOWED); + break; + case MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING: + info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_NETWORK_TIMEOUT); + break; + case MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE: + info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_NO_NETWORK); + break; + default: + info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_UNKNOWN); + break; + } + } + + pending_registration_set (MM_MODEM_HUAWEI (info->modem), 0); + mm_callback_info_schedule (info); +} + +static gboolean +pending_registration_timed_out (gpointer data) +{ + return FALSE; +} + +static void +register_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) { + info->error = g_error_copy (error); + mm_callback_info_schedule (info); + } else { + /* Add a timeout to wait for the unsolicited "connected" message */ + pending_registration_set (MM_MODEM_HUAWEI (serial), + g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, 60, + pending_registration_timed_out, + info, + pending_registration_cleanup)); + + mm_serial_queue_command (serial, "+CREG?", 5, got_reg_status, NULL); + } +} + +static void +do_register (MMModemGsmNetwork *modem, + const char *network_id, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + char *command; + + info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); + + if (network_id) + command = g_strdup_printf ("+COPS=1,2,\"%s\"", network_id); + else + command = g_strdup ("+COPS=0,,"); + + mm_serial_queue_command (MM_SERIAL (modem), command, 5, register_done, info); + g_free (command); } static gboolean @@ -465,36 +627,7 @@ handle_status_change (const char *str, gpointer data) static void reg_state_changed (const char *str, gpointer data) { - int i; - MMModemGsmNetworkRegStatus status; - - i = atoi (str); - switch (i) { - case 0: - status = MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE; - break; - case 1: - status = MM_MODEM_GSM_NETWORK_REG_STATUS_HOME; - break; - case 2: - status = MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING; - break; - case 3: - status = MM_MODEM_GSM_NETWORK_REG_STATUS_DENIED; - break; - case 4: - status = MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN; - break; - case 5: - status = MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING; - break; - default: - status = MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN; - break; - } - - g_debug ("Registration state changed: %d\n", status); - mm_generic_gsm_set_reg_status (MM_GENERIC_GSM (data), status); + reg_status_updated (MM_MODEM_HUAWEI (data), atoi (str)); } static gboolean @@ -521,6 +654,7 @@ modem_init (MMModem *modem_class) static void modem_gsm_network_init (MMModemGsmNetwork *class) { + class->do_register = do_register; class->set_network_mode = set_network_mode; class->get_network_mode = get_network_mode; class->set_band = set_band; @@ -533,6 +667,8 @@ mm_modem_huawei_init (MMModemHuawei *self) { MMModemHuaweiPrivate *priv = MM_MODEM_HUAWEI_GET_PRIVATE (self); + priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN; + priv->signal_quality_regex = g_regex_new ("\\r\\n\\^RSSI:(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); priv->mode_regex = g_regex_new ("\\r\\n\\^MODE:(.+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); priv->status_regex = g_regex_new ("\\r\\n\\^DSFLOWRPT:(.+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); @@ -547,6 +683,8 @@ finalize (GObject *object) { MMModemHuaweiPrivate *priv = MM_MODEM_HUAWEI_GET_PRIVATE (object); + pending_registration_stop (MM_MODEM_HUAWEI (object)); + mm_serial_parser_v1_destroy (priv->std_parser); g_regex_unref (priv->signal_quality_regex); g_regex_unref (priv->mode_regex); diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 7210bbe1..7323be09 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -25,8 +25,9 @@ typedef struct { } MMGenericGsmPrivate; static void get_registration_status (MMSerial *serial, MMCallbackInfo *info); -static void get_signal_quality (MMModemGsmNetwork *modem, - MMModemUIntFn callback, +static void read_operator_done (MMSerial *serial, + GString *response, + GError *error, gpointer user_data); MMModem * @@ -61,27 +62,29 @@ void mm_generic_gsm_set_reg_status (MMGenericGsm *modem, MMModemGsmNetworkRegStatus status) { - g_return_if_fail (MM_IS_GENERIC_GSM (modem)); - - MM_GENERIC_GSM_GET_PRIVATE (modem)->reg_status = status; -} - -void -mm_generic_gsm_set_operator (MMGenericGsm *modem, - const char *code, - const char *name) -{ MMGenericGsmPrivate *priv; g_return_if_fail (MM_IS_GENERIC_GSM (modem)); priv = MM_GENERIC_GSM_GET_PRIVATE (modem); - g_free (priv->oper_code); - g_free (priv->oper_name); + if (priv->reg_status != status) { + priv->reg_status = status; - priv->oper_code = g_strdup (code); - priv->oper_name = g_strdup (name); + if (status == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME || + status == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) { + mm_serial_queue_command (MM_SERIAL (modem), "+COPS=3,2;+COPS?", 3, read_operator_done, GINT_TO_POINTER (0)); + mm_serial_queue_command (MM_SERIAL (modem), "+COPS=3,0;+COPS?", 3, read_operator_done, GINT_TO_POINTER (1)); + mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (modem), NULL, NULL); + } else { + g_free (priv->oper_code); + g_free (priv->oper_name); + priv->oper_code = priv->oper_name = NULL; + + mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (modem), priv->reg_status, + priv->oper_code, priv->oper_name); + } + } } static void @@ -460,43 +463,28 @@ parse_operator (const char *reply) } static void -get_reg_code_done (MMSerial *serial, - GString *response, - GError *error, - gpointer user_data) +read_operator_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { - const char *reply = response->str; - if (!error) { char *oper; - oper = parse_operator (reply); + oper = parse_operator (response->str); if (oper) { MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (serial); - g_free (priv->oper_code); - priv->oper_code = oper; - } - } -} - -static void -get_reg_name_done (MMSerial *serial, - GString *response, - GError *error, - gpointer user_data) -{ - const char *reply = response->str; + if (GPOINTER_TO_INT (user_data) == 0) { + g_free (priv->oper_code); + priv->oper_code = oper; + } else { + g_free (priv->oper_name); + priv->oper_name = oper; - if (!error) { - char *oper; - - oper = parse_operator (reply); - if (oper) { - MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (serial); - - g_free (priv->oper_name); - priv->oper_name = oper; + mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (serial), priv->reg_status, + priv->oper_code, priv->oper_name); + } } } } @@ -582,9 +570,6 @@ get_reg_status_done (MMSerial *serial, case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME: case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING: /* Done */ - mm_serial_queue_command (serial, "+COPS=3,2;+COPS?", 3, get_reg_code_done, NULL); - mm_serial_queue_command (serial, "+COPS=3,0;+COPS?", 3, get_reg_name_done, NULL); - get_signal_quality (MM_MODEM_GSM_NETWORK (serial), NULL, NULL); done = TRUE; break; case MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE: diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index ec8428f5..ab8bee07 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -33,10 +33,6 @@ guint32 mm_generic_gsm_get_cid (MMGenericGsm *modem); void mm_generic_gsm_set_reg_status (MMGenericGsm *modem, MMModemGsmNetworkRegStatus status); -void mm_generic_gsm_set_operator (MMGenericGsm *modem, - const char *code, - const char *name); - void mm_generic_gsm_check_pin (MMGenericGsm *modem, MMModemFn callback, gpointer user_data); |