aboutsummaryrefslogtreecommitdiff
path: root/src/mm-generic-gsm.c
diff options
context:
space:
mode:
authorTambet Ingo <tambet@gmail.com>2008-09-11 08:35:32 +0300
committerTambet Ingo <tambet@gmail.com>2008-09-11 08:35:32 +0300
commitac4409e7cea29e03d311e6b805a084837d8bb70f (patch)
tree6b534ff91a3976a0268a89c858543bc973b17f8c /src/mm-generic-gsm.c
parentbb874acea0c8552f86932084e222b45a94119f29 (diff)
Rewrite serial device communications.
Instead of vague "send something, wait something" the responses are now analyzed by (overridable) parsers. Makes all the modem implementations much easier since each caller knows without any code whether the call succeeded or failed. Another thing that makes modem code simpler (and the whole thing more robust), is the queueing of sent commands. Each queued command has a command and a callback which is quaranteed to get called, even if sending failed. Define and implement error reporting.
Diffstat (limited to 'src/mm-generic-gsm.c')
-rw-r--r--src/mm-generic-gsm.c737
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