diff options
Diffstat (limited to 'src/mm-generic-gsm.c')
-rw-r--r-- | src/mm-generic-gsm.c | 737 |
1 files changed, 279 insertions, 458 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index f7b7a178..88589ef7 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -6,8 +6,9 @@ #include "mm-generic-gsm.h" #include "mm-modem-gsm-card.h" #include "mm-modem-gsm-network.h" -#include "mm-modem-error.h" +#include "mm-errors.h" #include "mm-callback-info.h" +#include "mm-serial-parsers.h" static gpointer mm_generic_gsm_parent_class = NULL; @@ -22,7 +23,8 @@ typedef struct { guint32 pending_id; } MMGenericGsmPrivate; -static void register_auto (MMModemGsmNetwork *modem, MMCallbackInfo *info); +static void get_registration_status (MMSerial *serial, MMCallbackInfo *info); +static void real_register (MMSerial *serial, const char *network_id, MMCallbackInfo *info); MMModem * mm_generic_gsm_new (const char *serial_device, const char *driver) @@ -74,89 +76,23 @@ mm_generic_gsm_set_operator (MMGenericGsm *modem, /*****************************************************************************/ static void -check_pin_done (MMSerial *serial, - int reply_index, - gpointer user_data) -{ - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - - switch (reply_index) { - case 0: - /* success */ - break; - case 1: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_PIN_NEEDED, "%s", "PIN needed"); - break; - case 2: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_PUK_NEEDED, "%s", "PUK needed"); - break; - case -1: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "PIN checking timed out."); - break; - default: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "PIN checking failed."); - break; - } - - mm_callback_info_schedule (info); -} - -static void -check_pin (MMSerial *serial, gpointer user_data) -{ - char *responses[] = { "READY", "SIM PIN", "SIM PUK", "ERROR", "ERR", NULL }; - char *terminators[] = { "OK", "ERROR", "ERR", NULL }; - guint id = 0; - - if (mm_serial_send_command_string (serial, "AT+CPIN?")) - id = mm_serial_wait_for_reply (serial, 3, responses, terminators, check_pin_done, user_data); - - if (!id) { - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "PIN checking failed."); - mm_callback_info_schedule (info); - } -} - -static void init_done (MMSerial *serial, - int reply_index, + GString *response, + GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - switch (reply_index) { - case 0: - /* success */ - check_pin (serial, user_data); - break; - case -1: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Modem initialization timed out."); - break; - default: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Modem initialization failed"); - } + if (error) + info->error = g_error_copy (error); - if (info->error) - mm_callback_info_schedule (info); + mm_callback_info_schedule (info); } static void flash_done (MMSerial *serial, gpointer user_data) { - char *responses[] = { "OK", "ERROR", "ERR", NULL }; - guint id = 0; - - if (mm_serial_send_command_string (serial, "ATZ E0")) - id = mm_serial_wait_for_reply (serial, 10, responses, responses, init_done, user_data); - - if (!id) { - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Turning modem echo off failed."); - mm_callback_info_schedule (info); - } + mm_serial_queue_command (serial, "Z E0 V1 X4 &C1 +CMEE=1", 3, init_done, user_data); } static void @@ -175,29 +111,25 @@ enable (MMModem *modem, return; } - if (mm_serial_open (MM_SERIAL (modem))) { - guint id; - - id = mm_serial_flash (MM_SERIAL (modem), 100, flash_done, info); - if (!id) - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, - "%s", "Could not communicate with serial device."); - } else - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Could not open serial device."); + if (mm_serial_open (MM_SERIAL (modem), &info->error)) + mm_serial_flash (MM_SERIAL (modem), 100, flash_done, info); if (info->error) mm_callback_info_schedule (info); } static void -get_string_done (MMSerial *serial, const char *reply, gpointer user_data) +get_string_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (reply) - mm_callback_info_set_result (info, g_strdup (reply), g_free); + if (error) + info->error = g_error_copy (error); else - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading information failed."); + mm_callback_info_set_result (info, g_strdup (response->str), g_free); mm_callback_info_schedule (info); } @@ -208,18 +140,9 @@ get_imei (MMModemGsmCard *modem, gpointer user_data) { MMCallbackInfo *info; - const char *terminators = "\r\n"; - guint id = 0; info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data); - - if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+CGSN")) - id = mm_serial_get_reply (MM_SERIAL (modem), 3, terminators, get_string_done, info); - - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading IMEI failed."); - mm_callback_info_schedule (info); - } + mm_serial_queue_command (MM_SERIAL (modem), "+CGSN", 3, get_string_done, info); } static void @@ -228,21 +151,11 @@ get_imsi (MMModemGsmCard *modem, gpointer user_data) { MMCallbackInfo *info; - const char *terminators = "\r\n"; - guint id = 0; info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data); - - if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+CIMI")) - id = mm_serial_get_reply (MM_SERIAL (modem), 3, terminators, get_string_done, info); - - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading IMSI failed."); - mm_callback_info_schedule (info); - } + mm_serial_queue_command (MM_SERIAL (modem), "+CIMI", 3, get_string_done, info); } - static void card_info_wrapper (MMModem *modem, GError *error, @@ -263,52 +176,47 @@ card_info_wrapper (MMModem *modem, } static void -get_version_done (MMSerial *serial, const char *reply, gpointer user_data) +get_version_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (reply) - mm_callback_info_set_data (info, "card-info-version", g_strdup (reply), g_free); - else - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading version failed."); - + if (!error) + mm_callback_info_set_data (info, "card-info-version", g_strdup (response->str), g_free); + else if (!info->error) + info->error = g_error_copy (error); + mm_callback_info_schedule (info); } static void -get_model_done (MMSerial *serial, const char *reply, gpointer user_data) +get_model_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - char *terminators = "\r\n"; - guint id = 0; - - if (reply && mm_serial_send_command_string (serial, "AT+CGMR")) - id = mm_serial_get_reply (serial, 5, terminators, get_version_done, info); - if (id) - mm_callback_info_set_data (info, "card-info-model", g_strdup (reply), g_free); - else { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading model failed."); - mm_callback_info_schedule (info); - } + if (!error) + mm_callback_info_set_data (info, "card-info-model", g_strdup (response->str), g_free); + else if (!info->error) + info->error = g_error_copy (error); } static void -get_manufacturer_done (MMSerial *serial, const char *reply, gpointer user_data) +get_manufacturer_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - char *terminators = "\r\n"; - guint id = 0; - if (reply && mm_serial_send_command_string (serial, "AT+CGMM")) - id = mm_serial_get_reply (serial, 5, terminators, get_model_done, info); - - if (id) - mm_callback_info_set_data (info, "card-info-manufacturer", g_strdup (reply), g_free); - else { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading manufacturer failed."); - mm_callback_info_schedule (info); - } + if (!error) + mm_callback_info_set_data (info, "card-info-manufacturer", g_strdup (response->str), g_free); + else + info->error = g_error_copy (error); } static void @@ -317,43 +225,27 @@ get_card_info (MMModemGsmCard *modem, gpointer user_data) { MMCallbackInfo *info; - char *terminators = "\r\n"; - guint id = 0; info = mm_callback_info_new (MM_MODEM (modem), card_info_wrapper, NULL); info->user_data = info; mm_callback_info_set_data (info, "card-info-callback", callback, NULL); mm_callback_info_set_data (info, "card-info-data", user_data, NULL); - if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+CGMI")) - id = mm_serial_get_reply (MM_SERIAL (modem), 5, terminators, get_manufacturer_done, info); - - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading card information failed."); - mm_callback_info_schedule (info); - } + mm_serial_queue_command (MM_SERIAL (modem), "+CGMI", 3, get_manufacturer_done, info); + mm_serial_queue_command (MM_SERIAL (modem), "+CGMM", 3, get_model_done, info); + mm_serial_queue_command (MM_SERIAL (modem), "+CGMR", 3, get_version_done, info); } static void send_pin_done (MMSerial *serial, - int reply_index, + GString *response, + GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - switch (reply_index) { - case 0: - /* success */ - break; - case -1: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, - "%s", "Did not receive response for secret"); - break; - default: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_INVALID_SECRET, "%s", "Invalid secret"); - break; - } - + if (error) + info->error = g_error_copy (error); mm_callback_info_schedule (info); } @@ -365,21 +257,11 @@ send_pin (MMModemGsmCard *modem, { MMCallbackInfo *info; char *command; - char *responses[] = { "OK", "ERROR", "ERR", NULL }; - guint id = 0; info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); - - command = g_strdup_printf ("AT+CPIN=\"%s\"", pin); - if (mm_serial_send_command_string (MM_SERIAL (modem), command)) - id = mm_serial_wait_for_reply (MM_SERIAL (modem), 3, responses, responses, send_pin_done, info); - + command = g_strdup_printf ("+CPIN=\"%s\"", pin); + mm_serial_queue_command (MM_SERIAL (modem), command, 3, send_pin_done, info); g_free (command); - - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "PIN checking failed."); - mm_callback_info_schedule (info); - } } static char * @@ -409,244 +291,206 @@ parse_operator (const char *reply) } static void -get_reg_name_done (MMSerial *serial, const char *reply, gpointer user_data) +get_reg_code_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - char *oper; + const char *reply = response->str; - oper = parse_operator (reply); - if (!oper) - g_warning ("Could not parse operator"); + if (!error) { + char *oper; - mm_generic_gsm_set_operator (MM_GENERIC_GSM (serial), - (char *) mm_callback_info_get_data (info, "reg-info-oper-code"), - oper); - g_free (oper); + oper = parse_operator (reply); + if (oper) { + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (serial); - mm_callback_info_schedule (info); + g_free (priv->oper_code); + priv->oper_name = oper; + } + } } static void -get_reg_code_done (MMSerial *serial, const char *reply, gpointer user_data) +get_reg_name_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - char *oper; - guint id = 0; + const char *reply = response->str; - oper = parse_operator (reply); - if (oper) { - char *terminators = "\r\n"; + if (!error) { + char *oper; - mm_callback_info_set_data (info, "reg-info-oper-code", oper, g_free); + oper = parse_operator (reply); + if (oper) { + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (serial); - if (mm_serial_send_command_string (serial, "AT+COPS=3,0;+COPS?")) - id = mm_serial_get_reply (MM_SERIAL (serial), 5, terminators, get_reg_name_done, info); + g_free (priv->oper_name); + priv->oper_name = oper; + } } +} - if (!id) { - g_warning ("Could not read operator"); +static gboolean +reg_status_again (gpointer data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) data; + guint32 counter; + + counter = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "reg-status-counter")); + if (counter > 60) { + /* That's 60 seconds */ + info->error = g_error_new_literal (MM_MOBILE_ERROR, + MM_MOBILE_ERROR_NETWORK_TIMEOUT, + "Registration timed out"); mm_callback_info_schedule (info); + } else { + mm_callback_info_set_data (info, "reg-status-counter", + GUINT_TO_POINTER (++counter), NULL); + get_registration_status (MM_SERIAL (info->modem), info); } + + return TRUE; } static void -read_operator (MMGenericGsm *modem, - MMCallbackInfo *info) +reg_status_remove (gpointer data) { - char *terminators = "\r\n"; - guint id = 0; - - if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+COPS=3,2;+COPS?")) - id = mm_serial_get_reply (MM_SERIAL (modem), 5, terminators, get_reg_code_done, info); - - if (!id) { - g_warning ("Reading operator code failed."); - mm_callback_info_schedule (info); - } + g_source_remove (GPOINTER_TO_UINT (data)); } static void get_reg_status_done (MMSerial *serial, - int reply_index, + GString *response, + GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - MMModemGsmNetworkRegStatus status; + const char *reply = response->str; + guint32 id; + gboolean done = FALSE; - switch (reply_index) { - 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_ROAMING; - break; - case -1: - status = MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN; - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", - "Reading registration status timed out"); - break; - default: - status = MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN; - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", - "Reading registration status failed"); - break; + if (error) { + info->error = g_error_copy (error); + goto out; } - mm_generic_gsm_set_reg_status (MM_GENERIC_GSM (serial), status); - mm_callback_info_set_result (info, GUINT_TO_POINTER (status), NULL); - - mm_callback_info_schedule (info); -} - -static void -get_registration_status (MMModemGsmNetwork *modem, MMModemUIntFn callback, gpointer user_data) -{ - MMCallbackInfo *info; - char *responses[] = { "+CREG: 0,0", "+CREG: 0,1", "+CREG: 0,2", "+CREG: 0,3", "+CREG: 0,5", NULL }; - char *terminators[] = { "OK", "ERROR", "ERR", NULL }; - guint id = 0; - - info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); - - if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+CREG?")) - id = mm_serial_wait_for_reply (MM_SERIAL (modem), 60, responses, terminators, - get_reg_status_done, info); + if (g_str_has_prefix (reply, "+CREG: ")) { + /* Got valid reply */ + int n, stat; + + if (sscanf (reply + 7, "%d,%d", &n, &stat)) { + MMModemGsmNetworkRegStatus status; + + switch (stat) { + 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; + } + + mm_generic_gsm_set_reg_status (MM_GENERIC_GSM (serial), status); + + switch (status) { + 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); + done = TRUE; + break; + case MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE: + /* Huh? Stupid card, we already told it to register, tell again */ + real_register (serial, + (char *) mm_callback_info_get_data (info, "reg-network-id"), + info); + break; + case MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING: + /* Wait more until the timeout expires. */ + id = GPOINTER_TO_INT (mm_callback_info_get_data (info, "reg-status-timeout")); + if (!id) { + id = g_timeout_add (1000, reg_status_again, info); + mm_callback_info_set_data (info, "reg-status-timeout", GUINT_TO_POINTER (id), + reg_status_remove); + } + break; + case MM_MODEM_GSM_NETWORK_REG_STATUS_DENIED: + info->error = g_error_new_literal (MM_MOBILE_ERROR, + MM_MOBILE_ERROR_NETWORK_NOT_ALLOWED, + "Network no allowed"); + break; + case MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN: + default: + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Unknown network status"); + break; + } + } + } else + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Could not parse the response"); - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading registration status failed."); + out: + if (done || info->error) mm_callback_info_schedule (info); - } } static void -register_manual_get_status_done (MMModem *modem, - guint32 result, - GError *error, - gpointer user_data) +get_registration_status (MMSerial *serial, MMCallbackInfo *info) { - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - - if (result == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME || result == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) - read_operator (MM_GENERIC_GSM (modem), info); - else - mm_callback_info_schedule (info); + g_debug ("Queueing +CREG"); + mm_serial_queue_command (serial, "+CREG?", 3, get_reg_status_done, info); } static void -register_manual_done (MMSerial *serial, - int reply_index, - gpointer user_data) +register_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - switch (reply_index) { - case 0: - /* success */ - get_registration_status (MM_MODEM_GSM_NETWORK (serial), register_manual_get_status_done, info); - break; - case -1: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Manual registration timed out"); - break; - default: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Manual registration failed"); - break; - } - - if (info->error) + if (error) { + info->error = g_error_copy (error); mm_callback_info_schedule (info); + } else + get_registration_status (serial, info); } static void -register_manual (MMModemGsmNetwork *modem, const char *network_id, MMCallbackInfo *info) +real_register (MMSerial *serial, + const char *network_id, + MMCallbackInfo *info) { char *command; - char *responses[] = { "OK", "ERROR", "ERR", NULL }; - guint id = 0; - - command = g_strdup_printf ("AT+COPS=1,2,\"%s\"", network_id); - if (mm_serial_send_command_string (MM_SERIAL (modem), command)) - id = mm_serial_wait_for_reply (MM_SERIAL (modem), 30, responses, responses, - register_manual_done, info); - - g_free (command); - - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Manual registration failed."); - mm_callback_info_schedule (info); - } -} - -static gboolean -automatic_registration_again (gpointer data) -{ - MMCallbackInfo *info = (MMCallbackInfo *) data; - - register_auto (MM_MODEM_GSM_NETWORK (info->modem), info); - - return FALSE; -} -static void -register_auto_done (MMModem *modem, - guint result, - GError *error, - gpointer user_data) -{ - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - - if (error) { - info->error = g_error_copy (error); - goto out; - } - - switch (result) { - case MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, - "%s", "Automatic registration failed: not registered and not searching."); - break; - case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME: - g_message ("Registered on Home network"); - break; - case MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING: - MM_GENERIC_GSM_GET_PRIVATE (modem)->pending_id = g_timeout_add (1000, automatic_registration_again, info); - return; - break; - case MM_MODEM_GSM_NETWORK_REG_STATUS_DENIED: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", - "Automatic registration failed: registration denied"); - break; - case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING: - g_message ("Registered on Roaming network"); - break; - case -1: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Automatic registration timed out"); - break; - default: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Automatic registration failed"); - break; - } - - out: - - if (info->error) - mm_callback_info_schedule (info); + if (network_id) + command = g_strdup_printf ("+COPS=1,2,\"%s\"", network_id); else - read_operator (MM_GENERIC_GSM (modem), info); -} + command = g_strdup ("+COPS=0,,"); -static void -register_auto (MMModemGsmNetwork *modem, MMCallbackInfo *info) -{ - get_registration_status (modem, register_auto_done, info); + mm_serial_queue_command (serial, command, 60, register_done, info); + g_free (command); } static void @@ -658,14 +502,11 @@ do_register (MMModemGsmNetwork *modem, MMCallbackInfo *info; info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); + mm_callback_info_set_data (info, "reg-network-id", g_strdup (network_id), g_free); - if (network_id) - register_manual (modem, network_id, info); - else - register_auto (modem, info); + real_register (MM_SERIAL (modem), network_id, info); } - static void get_registration_info_done (MMModem *modem, GError *error, gpointer user_data) { @@ -698,37 +539,39 @@ get_registration_info (MMModemGsmNetwork *self, } static void -connect_done (MMSerial *serial, - int reply_index, - gpointer user_data) +connect_report_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - switch (reply_index) { - case 0: - /* success */ - break; - case 1: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dial failed: Busy"); - break; - case 2: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dial failed: No dial tone"); - break; - case 3: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dial failed: No carrier"); - break; - case -1: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dialing timed out"); - break; - default: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dialing failed"); - break; + if (!error && g_str_has_prefix (response->str, "+CEER: ")) { + g_free (info->error->message); + info->error->message = g_strdup (response->str + 7); /* skip the "+CEER: " */ } - + mm_callback_info_schedule (info); } static void +connect_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) { + info->error = g_error_copy (error); + /* Try to get more information why it failed */ + mm_serial_queue_command (serial, "+CEER", 3, connect_report_done, info); + } else + /* Done */ + mm_callback_info_schedule (info); +} + +static void connect (MMModem *modem, const char *number, MMModemFn callback, @@ -736,8 +579,6 @@ connect (MMModem *modem, { MMCallbackInfo *info; char *command; - char *responses[] = { "CONNECT", "BUSY", "NO DIAL TONE", "NO CARRIER", NULL }; - guint id = 0; guint32 cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (modem)); info = mm_callback_info_new (modem, callback, user_data); @@ -745,7 +586,7 @@ connect (MMModem *modem, if (cid > 0) { GString *str; - str = g_string_new ("ATD"); + str = g_string_new ("D"); if (g_str_has_suffix (number, "#")) str = g_string_append_len (str, number, strlen (number) - 1); else @@ -754,17 +595,16 @@ connect (MMModem *modem, g_string_append_printf (str, "***%d#", cid); command = g_string_free (str, FALSE); } else - command = g_strconcat ("ATDT", number, NULL); - - if (mm_serial_send_command_string (MM_SERIAL (modem), command)) - id = mm_serial_wait_for_reply (MM_SERIAL (modem), 60, responses, responses, connect_done, info); + command = g_strconcat ("DT", number, NULL); + mm_serial_queue_command (MM_SERIAL (modem), command, 60, connect_done, info); g_free (command); +} - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dialing failed."); - mm_callback_info_schedule (info); - } +static void +disconnect_flash_done (MMSerial *serial, gpointer user_data) +{ + mm_callback_info_schedule ((MMCallbackInfo *) user_data); } static void @@ -775,8 +615,7 @@ disconnect (MMModem *modem, MMCallbackInfo *info; info = mm_callback_info_new (modem, callback, user_data); - mm_serial_close (MM_SERIAL (modem)); - mm_callback_info_schedule (info); + mm_serial_flash (MM_SERIAL (modem), 1000, disconnect_flash_done, info); } static void @@ -806,15 +645,19 @@ destroy_scan_data (gpointer data) } static void -scan_done (MMSerial *serial, const char *reply, gpointer user_data) +scan_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - GPtrArray *results; + char *reply = response->str; - results = g_ptr_array_new (); - - if (reply && !strncmp (reply, "+COPS: ", 7)) { + if (error) + info->error = g_error_copy (error); + else if (!strncmp (reply, "+COPS: ", 7)) { /* Got valid reply */ + GPtrArray *results; GRegex *r; GMatchInfo *match_info; GError *err = NULL; @@ -830,6 +673,8 @@ scan_done (MMSerial *serial, const char *reply, gpointer user_data) goto out; } + results = g_ptr_array_new (); + g_regex_match (r, reply, 0, &match_info); while (g_match_info_matches (match_info)) { GHashTable *hash; @@ -844,12 +689,10 @@ scan_done (MMSerial *serial, const char *reply, gpointer user_data) g_match_info_next (match_info, NULL); } + mm_callback_info_set_data (info, "scan-results", results, destroy_scan_data); g_match_info_free (match_info); g_regex_unref (r); - } else - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Could not parse scan results"); - - mm_callback_info_set_data (info, "scan-results", results, destroy_scan_data); + } out: mm_callback_info_schedule (info); @@ -861,39 +704,27 @@ scan (MMModemGsmNetwork *modem, gpointer user_data) { MMCallbackInfo *info; - char *terminators = "\r\n"; - guint id = 0; info = mm_callback_info_new (MM_MODEM (modem), scan_callback_wrapper, NULL); info->user_data = info; mm_callback_info_set_data (info, "scan-callback", callback, NULL); mm_callback_info_set_data (info, "scan-data", user_data, NULL); - if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+COPS=?")) - id = mm_serial_get_reply (MM_SERIAL (modem), 60, terminators, scan_done, info); - - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Scanning failed."); - mm_callback_info_schedule (info); - } + mm_serial_queue_command (MM_SERIAL (modem), "+COPS=?", 60, scan_done, info); } static void set_apn_done (MMSerial *serial, - int reply_index, + GString *response, + GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - switch (reply_index) { - case 0: - /* success */ + if (error) + info->error = g_error_copy (error); + else MM_GENERIC_GSM_GET_PRIVATE (serial)->cid = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "CID")); - break; - default: - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Setting APN failed"); - break; - } mm_callback_info_schedule (info); } @@ -906,32 +737,28 @@ set_apn (MMModemGsmNetwork *modem, { MMCallbackInfo *info; char *command; - char *responses[] = { "OK", "ERROR", NULL }; guint cid = 1; - guint id = 0; info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); mm_callback_info_set_data (info, "CID", GUINT_TO_POINTER (cid), NULL); - command = g_strdup_printf ("AT+CGDCONT=%d, \"IP\", \"%s\"", cid, apn); - if (mm_serial_send_command_string (MM_SERIAL (modem), command)) - id = mm_serial_wait_for_reply (MM_SERIAL (modem), 3, responses, responses, set_apn_done, info); - + command = g_strdup_printf ("+CGDCONT=%d, \"IP\", \"%s\"", cid, apn); + mm_serial_queue_command (MM_SERIAL (modem), command, 3, set_apn_done, info); g_free (command); - - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Setting APN failed."); - mm_callback_info_schedule (info); - } } static void -get_signal_quality_done (MMSerial *serial, const char *reply, gpointer user_data) +get_signal_quality_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - guint32 result = 0; + char *reply = response->str; - if (reply && !strncmp (reply, "+CSQ: ", 6)) { + if (error) + info->error = g_error_copy (error); + else if (!strncmp (reply, "+CSQ: ", 6)) { /* Got valid reply */ int quality; int ber; @@ -942,15 +769,14 @@ get_signal_quality_done (MMSerial *serial, const char *reply, gpointer user_data /* 99 means unknown */ if (quality != 99) /* Normalize the quality */ - result = quality * 100 / 31; + quality = quality * 100 / 31; + + mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL); } else info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Could not parse signal quality results"); - } else - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, - "%s", "Could not parse signal quality results"); + } - mm_callback_info_set_result (info, GUINT_TO_POINTER (result), NULL); mm_callback_info_schedule (info); } @@ -960,18 +786,9 @@ get_signal_quality (MMModemGsmNetwork *modem, gpointer user_data) { MMCallbackInfo *info; - char *terminators = "\r\n"; - guint id = 0; info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); - - if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+CSQ")) - id = mm_serial_get_reply (MM_SERIAL (modem), 10, terminators, get_signal_quality_done, info); - - if (!id) { - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Getting signal quality failed."); - mm_callback_info_schedule (info); - } + mm_serial_queue_command (MM_SERIAL (modem), "+CSQ", 3, get_signal_quality_done, info); } /*****************************************************************************/ @@ -1006,6 +823,10 @@ modem_gsm_network_init (MMModemGsmNetwork *class) static void mm_generic_gsm_init (MMGenericGsm *self) { + mm_serial_set_response_parser (MM_SERIAL (self), + mm_serial_parser_v1_parse, + mm_serial_parser_v1_new (), + mm_serial_parser_v1_destroy); } static void |