aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am10
-rw-r--r--src/main.c23
-rw-r--r--src/mm-callback-info.c16
-rw-r--r--src/mm-callback-info.h2
-rw-r--r--src/mm-errors.c175
-rw-r--r--src/mm-errors.h110
-rw-r--r--src/mm-generic-cdma.c118
-rw-r--r--src/mm-generic-gsm.c737
-rw-r--r--src/mm-manager.c8
-rw-r--r--src/mm-modem-cdma.c2
-rw-r--r--src/mm-modem-error.c37
-rw-r--r--src/mm-modem-error.h22
-rw-r--r--src/mm-modem-gsm-card.c2
-rw-r--r--src/mm-modem-gsm-network.c2
-rw-r--r--src/mm-modem.c2
-rw-r--r--src/mm-options.c36
-rw-r--r--src/mm-options.h9
-rw-r--r--src/mm-serial-parsers.c266
-rw-r--r--src/mm-serial-parsers.h26
-rw-r--r--src/mm-serial.c708
-rw-r--r--src/mm-serial.h91
21 files changed, 1224 insertions, 1178 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 9240d9f4..f0204704 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,22 +15,26 @@ modem_manager_SOURCES = \
mm-generic-cdma.h \
mm-generic-gsm.c \
mm-generic-gsm.h \
+ mm-errors.c \
+ mm-errors.h \
mm-manager.c \
mm-manager.h \
mm-modem.c \
mm-modem.h \
mm-modem-cdma.c \
mm-modem-cdma.h \
- mm-modem-error.c \
- mm-modem-error.h \
mm-modem-gsm-card.c \
mm-modem-gsm-card.h \
mm-modem-gsm-network.c \
mm-modem-gsm-network.h \
+ mm-options.c \
+ mm-options.h \
mm-plugin.c \
mm-plugin.h \
mm-serial.c \
- mm-serial.h
+ mm-serial.h \
+ mm-serial-parsers.c \
+ mm-serial-parsers.h
mm-manager-glue.h: $(top_srcdir)/introspection/mm-manager.xml
dbus-binding-tool --prefix=mm_manager --mode=glib-server --output=$@ $<
diff --git a/src/main.c b/src/main.c
index a18ad3b5..cdd07481 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,6 +3,7 @@
#include <syslog.h>
#include <dbus/dbus-glib.h>
#include "mm-manager.h"
+#include "mm-options.h"
static void
log_handler (const gchar *log_domain,
@@ -123,31 +124,13 @@ dbus_init (GMainLoop *loop)
int
main (int argc, char *argv[])
{
- GOptionContext *opt_ctx;
- GError *error = NULL;
GMainLoop *loop;
MMManager *manager;
- gboolean debug = FALSE;
- GOptionEntry entries[] = {
- { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Output to console rather than syslog", NULL },
- { NULL }
- };
-
- opt_ctx = g_option_context_new (NULL);
- g_option_context_set_summary (opt_ctx, "DBus system service to communicate with modems.");
- g_option_context_add_main_entries (opt_ctx, entries, NULL);
-
- if (!g_option_context_parse (opt_ctx, &argc, &argv, &error)) {
- g_warning ("%s\n", error->message);
- g_error_free (error);
- return 1;
- }
-
- g_option_context_free (opt_ctx);
+ mm_options_parse (argc, argv);
g_type_init ();
- if (!debug)
+ if (!mm_options_debug ())
logging_setup ();
loop = g_main_loop_new (NULL, FALSE);
diff --git a/src/mm-callback-info.c b/src/mm-callback-info.c
index d016aad4..61283b26 100644
--- a/src/mm-callback-info.c
+++ b/src/mm-callback-info.c
@@ -1,7 +1,7 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "mm-callback-info.h"
-#include "mm-modem-error.h"
+#include "mm-errors.h"
static void
callback_info_done (gpointer user_data)
@@ -23,9 +23,10 @@ callback_info_done (gpointer user_data)
if (info->error)
g_error_free (info->error);
- g_object_unref (info->modem);
- g_datalist_clear (&info->qdata);
+ if (info->modem)
+ g_object_unref (info->modem);
+ g_datalist_clear (&info->qdata);
g_slice_free (MMCallbackInfo, info);
}
@@ -43,15 +44,6 @@ mm_callback_info_schedule (MMCallbackInfo *info)
info->pending_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, callback_info_do, info, callback_info_done);
}
-void
-mm_callback_info_cancel (MMCallbackInfo *info)
-{
- if (info->pending_id) {
- info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Call cancelled");
- mm_callback_info_schedule (info);
- }
-}
-
MMCallbackInfo *
mm_callback_info_new (MMModem *modem, MMModemFn callback, gpointer user_data)
{
diff --git a/src/mm-callback-info.h b/src/mm-callback-info.h
index eef2073f..5c461c58 100644
--- a/src/mm-callback-info.h
+++ b/src/mm-callback-info.h
@@ -31,8 +31,6 @@ MMCallbackInfo *mm_callback_info_string_new (MMModem *modem,
gpointer user_data);
void mm_callback_info_schedule (MMCallbackInfo *info);
-void mm_callback_info_cancel (MMCallbackInfo *info);
-
void mm_callback_info_set_result (MMCallbackInfo *info,
gpointer data,
GDestroyNotify destroy);
diff --git a/src/mm-errors.c b/src/mm-errors.c
new file mode 100644
index 00000000..bdbd8a80
--- /dev/null
+++ b/src/mm-errors.c
@@ -0,0 +1,175 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include "mm-errors.h"
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GQuark
+mm_serial_error_quark (void)
+{
+ static GQuark ret = 0;
+
+ if (ret == 0)
+ ret = g_quark_from_static_string ("mm_serial_error");
+
+ return ret;
+}
+
+GType
+mm_serial_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (MM_SERIAL_OPEN_FAILED, "Could not open the serial device"),
+ ENUM_ENTRY (MM_SERIAL_SEND_FAILED, "Writing to serial device failed"),
+ ENUM_ENTRY (MM_SERIAL_RESPONSE_TIMEOUT, "Did not receive response"),
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static ("MMSerialError", values);
+ }
+
+ return etype;
+}
+
+GQuark
+mm_modem_error_quark (void)
+{
+ static GQuark ret = 0;
+
+ if (ret == 0)
+ ret = g_quark_from_static_string ("mm_modem_error");
+
+ return ret;
+}
+
+GType
+mm_modem_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (MM_MODEM_ERROR_GENERAL, "Unknown error"),
+ ENUM_ENTRY (MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED, "Operation not supported"),
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static ("MMModemError", values);
+ }
+
+ return etype;
+}
+
+GQuark
+mm_modem_connect_error_quark (void)
+{
+ static GQuark ret = 0;
+
+ if (ret == 0)
+ ret = g_quark_from_static_string ("mm_modem_connect_error");
+
+ return ret;
+}
+
+GType
+mm_modem_connect_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (MM_MODEM_CONNECT_ERROR_NO_CARRIER, "No carrier"),
+ ENUM_ENTRY (MM_MODEM_CONNECT_ERROR_NO_DIALTONE, "No dialtone"),
+ ENUM_ENTRY (MM_MODEM_CONNECT_ERROR_BUSY, "Busy"),
+ ENUM_ENTRY (MM_MODEM_CONNECT_ERROR_NO_ANSWER, "No answer"),
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static ("MMModemConnectError", values);
+ }
+
+ return etype;
+}
+
+GQuark
+mm_mobile_error_quark (void)
+{
+ static GQuark ret = 0;
+
+ if (ret == 0)
+ ret = g_quark_from_static_string ("mm_mobile_error");
+
+ return ret;
+}
+
+GType
+mm_mobile_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (MM_MOBILE_ERROR_PHONE_FAILURE, "PhoneFailure"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NO_CONNECTION, "No connection to phone"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_LINK_RESERVED, "Phone-adaptor link reserved"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NOT_ALLOWED, "Operation not allowed"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NOT_SUPPORTED, "Operation not supported"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_PH_SIM_PIN, "PH-SIM PIN required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_PH_FSIM_PIN, "PH-FSIM PIN required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_PH_FSIM_PUK, "PH-FSIM PUK required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SIM_NOT_INSERTED, "SIM not inserted"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SIM_PIN, "SIM PIN required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SIM_PUK, "SIM PUK required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SIM_FAILURE, "SIM failure"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SIM_BUSY, "SIM busy"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SIM_WRONG, "SIM wrong"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_WRONG_PASSWORD, "Incorrect password"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SIM_PIN2, "SIM PIN2 required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SIM_PUK2, "SIM PUK2 required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_MEMORY_FULL, "Memory full"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_INVALID_INDEX, "Invalid index"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NOT_FOUND, "Not found"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_MEMORY_FAILURE, "Memory failure"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_TEXT_TOO_LONG, "Text string too long"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_INVALID_CHARS, "Invalid charactes in text string"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_DIAL_STRING_TOO_LONG, "Dial string too long"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_DIAL_STRING_INVALID, "Invalid charactes in dial string"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NO_NETWORK, "No network service"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NETWORK_TIMEOUT, "Network timeout"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NETWORK_NOT_ALLOWED, "Network not allowed - emergency calls only"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NETWORK_PIN, "Network personalization PIN required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NETWORK_PUK, "Network personalization PUK required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NETWORK_SUBSET_PIN, "Network subset personalization PIN required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_NETWORK_SUBSET_PUK, "Network subset personalization PUK required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SERVICE_PIN, "Service provider personalization PIN required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_SERVICE_PUK, "Service provider personalization PUK required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_CORP_PIN, "Corporate personalization PIN required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_CORP_PUK, "Corporate personalization PUK required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_HIDDEN_KEY, "Hidden key required"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_EAP_NOT_SUPPORTED, "EAP method not supported"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_INCORRECT_PARAMS, "Incorrect parameters"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_UNKNOWN, "Unknown"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_ILLEGAL_MS, "Illegal MS"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_ILLEGAL_ME, "Illegal ME"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_SERVICE_NOT_ALLOWED, "GPRS services not allowed"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_PLMN_NOT_ALLOWED, "PLMN not allowed"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_LOCATION_NOT_ALLOWED, "Location area not allowed"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_ROAMING_NOT_ALLOWED, "Roaming not allowed in this location area"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_OPTION_NOT_SUPPORTED, "Service option not supported"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_NOT_SUBSCRIBED, "Requested service option not subscribed"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_OUT_OF_ORDER, "Service option temporarily out of order"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_PDP_AUTH_FAILURE, "PDP authentication failure"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_UNKNOWN, "Unspecified GPRS error"),
+ ENUM_ENTRY (MM_MOBILE_ERROR_GPRS_INVALID_CLASS, "Invalid mobile class"),
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static ("MMMobileError", values);
+ g_print ("Is enum? %d %d\n", etype, G_TYPE_IS_ENUM (etype));
+ }
+
+ return etype;
+}
diff --git a/src/mm-errors.h b/src/mm-errors.h
new file mode 100644
index 00000000..6d3ca93a
--- /dev/null
+++ b/src/mm-errors.h
@@ -0,0 +1,110 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef MM_MODEM_ERROR_H
+#define MM_MODEM_ERROR_H
+
+#include <glib-object.h>
+
+enum {
+ MM_SERIAL_OPEN_FAILED = 0,
+ MM_SERIAL_SEND_FAILED = 1,
+ MM_SERIAL_RESPONSE_TIMEOUT = 2
+};
+
+#define MM_SERIAL_ERROR (mm_serial_error_quark ())
+#define MM_TYPE_SERIAL_ERROR (mm_serial_error_get_type ())
+
+GQuark mm_serial_error_quark (void);
+GType mm_serial_error_get_type (void);
+
+
+enum {
+ MM_MODEM_ERROR_GENERAL = 0,
+ MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED = 1
+};
+
+#define MM_MODEM_ERROR (mm_modem_error_quark ())
+#define MM_TYPE_MODEM_ERROR (mm_modem_error_get_type ())
+
+GQuark mm_modem_error_quark (void);
+GType mm_modem_error_get_type (void);
+
+
+enum {
+ MM_MODEM_CONNECT_ERROR_NO_CARRIER = 3,
+ MM_MODEM_CONNECT_ERROR_NO_DIALTONE = 6,
+ MM_MODEM_CONNECT_ERROR_BUSY = 7,
+ MM_MODEM_CONNECT_ERROR_NO_ANSWER = 8,
+};
+
+#define MM_MODEM_CONNECT_ERROR (mm_modem_connect_error_quark ())
+#define MM_TYPE_MODEM_CONNECT_ERROR (mm_modem_connect_error_get_type ())
+
+GQuark mm_modem_connect_error_quark (void);
+GType mm_modem_connect_error_get_type (void);
+
+
+enum {
+ MM_MOBILE_ERROR_PHONE_FAILURE = 0,
+ MM_MOBILE_ERROR_NO_CONNECTION = 1,
+ MM_MOBILE_ERROR_LINK_RESERVED = 2,
+ MM_MOBILE_ERROR_NOT_ALLOWED = 3,
+ MM_MOBILE_ERROR_NOT_SUPPORTED = 4,
+ MM_MOBILE_ERROR_PH_SIM_PIN = 5,
+ MM_MOBILE_ERROR_PH_FSIM_PIN = 6,
+ MM_MOBILE_ERROR_PH_FSIM_PUK = 7,
+ MM_MOBILE_ERROR_SIM_NOT_INSERTED = 10,
+ MM_MOBILE_ERROR_SIM_PIN = 11,
+ MM_MOBILE_ERROR_SIM_PUK = 12,
+ MM_MOBILE_ERROR_SIM_FAILURE = 13,
+ MM_MOBILE_ERROR_SIM_BUSY = 14,
+ MM_MOBILE_ERROR_SIM_WRONG = 15,
+ MM_MOBILE_ERROR_WRONG_PASSWORD = 16,
+ MM_MOBILE_ERROR_SIM_PIN2 = 17,
+ MM_MOBILE_ERROR_SIM_PUK2 = 18,
+ MM_MOBILE_ERROR_MEMORY_FULL = 20,
+ MM_MOBILE_ERROR_INVALID_INDEX = 21,
+ MM_MOBILE_ERROR_NOT_FOUND = 22,
+ MM_MOBILE_ERROR_MEMORY_FAILURE = 23,
+ MM_MOBILE_ERROR_TEXT_TOO_LONG = 24,
+ MM_MOBILE_ERROR_INVALID_CHARS = 25,
+ MM_MOBILE_ERROR_DIAL_STRING_TOO_LONG = 26,
+ MM_MOBILE_ERROR_DIAL_STRING_INVALID = 27,
+ MM_MOBILE_ERROR_NO_NETWORK = 30,
+ MM_MOBILE_ERROR_NETWORK_TIMEOUT = 31,
+ MM_MOBILE_ERROR_NETWORK_NOT_ALLOWED = 32,
+ MM_MOBILE_ERROR_NETWORK_PIN = 40,
+ MM_MOBILE_ERROR_NETWORK_PUK = 41,
+ MM_MOBILE_ERROR_NETWORK_SUBSET_PIN = 42,
+ MM_MOBILE_ERROR_NETWORK_SUBSET_PUK = 43,
+ MM_MOBILE_ERROR_SERVICE_PIN = 44,
+ MM_MOBILE_ERROR_SERVICE_PUK = 45,
+ MM_MOBILE_ERROR_CORP_PIN = 46,
+ MM_MOBILE_ERROR_CORP_PUK = 47,
+ MM_MOBILE_ERROR_HIDDEN_KEY = 48,
+ MM_MOBILE_ERROR_EAP_NOT_SUPPORTED = 49,
+ MM_MOBILE_ERROR_INCORRECT_PARAMS = 50,
+ MM_MOBILE_ERROR_UNKNOWN = 100,
+
+ MM_MOBILE_ERROR_GPRS_ILLEGAL_MS = 103,
+ MM_MOBILE_ERROR_GPRS_ILLEGAL_ME = 106,
+ MM_MOBILE_ERROR_GPRS_SERVICE_NOT_ALLOWED = 107,
+ MM_MOBILE_ERROR_GPRS_PLMN_NOT_ALLOWED = 111,
+ MM_MOBILE_ERROR_GPRS_LOCATION_NOT_ALLOWED = 112,
+ MM_MOBILE_ERROR_GPRS_ROAMING_NOT_ALLOWED = 113,
+ MM_MOBILE_ERROR_GPRS_OPTION_NOT_SUPPORTED = 132,
+ MM_MOBILE_ERROR_GPRS_NOT_SUBSCRIBED = 133,
+ MM_MOBILE_ERROR_GPRS_OUT_OF_ORDER = 134,
+ MM_MOBILE_ERROR_GPRS_PDP_AUTH_FAILURE = 149,
+ MM_MOBILE_ERROR_GPRS_UNKNOWN = 148,
+ MM_MOBILE_ERROR_GPRS_INVALID_CLASS = 150
+};
+
+
+#define MM_MOBILE_ERROR (mm_mobile_error_quark ())
+#define MM_TYPE_MOBILE_ERROR (mm_mobile_error_get_type ())
+
+GQuark mm_mobile_error_quark (void);
+GType mm_mobile_error_get_type (void);
+
+#endif /* MM_MODEM_ERROR_H */
diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c
index 9167f418..fe49edac 100644
--- a/src/mm-generic-cdma.c
+++ b/src/mm-generic-cdma.c
@@ -5,7 +5,7 @@
#include "mm-generic-cdma.h"
#include "mm-modem-cdma.h"
-#include "mm-modem-error.h"
+#include "mm-errors.h"
#include "mm-callback-info.h"
static gpointer mm_generic_cdma_parent_class = NULL;
@@ -32,21 +32,14 @@ mm_generic_cdma_new (const char *serial_device, const char *driver)
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 */
- 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);
mm_callback_info_schedule (info);
}
@@ -54,18 +47,7 @@ init_done (MMSerial *serial,
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, "AT 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
@@ -84,15 +66,8 @@ 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);
@@ -100,31 +75,14 @@ enable (MMModem *modem,
static void
dial_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", "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)
+ info->error = g_error_copy (error);
mm_callback_info_schedule (info);
}
@@ -137,21 +95,17 @@ connect (MMModem *modem,
{
MMCallbackInfo *info;
char *command;
- char *responses[] = { "CONNECT", "BUSY", "NO DIAL TONE", "NO CARRIER", NULL };
- guint id = 0;
info = mm_callback_info_new (modem, callback, user_data);
-
- 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, dial_done, info);
-
+ command = g_strconcat ("DT", number, NULL);
+ mm_serial_queue_command (MM_SERIAL (modem), command, 60, dial_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
@@ -162,17 +116,21 @@ 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
-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 (!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;
@@ -183,15 +141,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);
}
@@ -201,18 +158,9 @@ get_signal_quality (MMModemCdma *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);
}
/*****************************************************************************/
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
diff --git a/src/mm-manager.c b/src/mm-manager.c
index 4f18633e..c139046e 100644
--- a/src/mm-manager.c
+++ b/src/mm-manager.c
@@ -6,7 +6,7 @@
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "mm-manager.h"
-#include "mm-modem-error.h"
+#include "mm-errors.h"
#include "mm-generic-gsm.h"
#include "mm-generic-cdma.h"
#include "mm-plugin.h"
@@ -454,5 +454,11 @@ mm_manager_class_init (MMManagerClass *manager_class)
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (manager_class),
&dbus_glib_mm_manager_object_info);
+ /* FIXME: Sigh, these don't work either */
+#if 0
+ dbus_g_error_domain_register (MM_SERIAL_ERROR, NULL, MM_TYPE_SERIAL_ERROR);
dbus_g_error_domain_register (MM_MODEM_ERROR, NULL, MM_TYPE_MODEM_ERROR);
+ dbus_g_error_domain_register (MM_MODEM_CONNECT_ERROR, NULL, MM_TYPE_MODEM_CONNECT_ERROR);
+ dbus_g_error_domain_register (MM_MOBILE_ERROR, NULL, MM_TYPE_MOBILE_ERROR);
+#endif
}
diff --git a/src/mm-modem-cdma.c b/src/mm-modem-cdma.c
index 7b0321e5..f58122a8 100644
--- a/src/mm-modem-cdma.c
+++ b/src/mm-modem-cdma.c
@@ -3,7 +3,7 @@
#include <string.h>
#include <dbus/dbus-glib.h>
#include "mm-modem-cdma.h"
-#include "mm-modem-error.h"
+#include "mm-errors.h"
#include "mm-callback-info.h"
static void impl_modem_cdma_get_signal_quality (MMModemCdma *modem, DBusGMethodInvocation *context);
diff --git a/src/mm-modem-error.c b/src/mm-modem-error.c
deleted file mode 100644
index c415fb1f..00000000
--- a/src/mm-modem-error.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-
-#include "mm-modem-error.h"
-
-GQuark
-mm_modem_error_quark (void)
-{
- static GQuark ret = 0;
-
- if (ret == 0)
- ret = g_quark_from_static_string ("mm_modem_error");
-
- return ret;
-}
-
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-GType
-mm_modem_error_get_type (void)
-{
- static GType etype = 0;
-
- if (etype == 0) {
- static const GEnumValue values[] = {
- ENUM_ENTRY (MM_MODEM_ERROR_GENERAL, "GeneralError"),
- ENUM_ENTRY (MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED, "OperationNotSupported"),
- ENUM_ENTRY (MM_MODEM_ERROR_PIN_NEEDED, "PINNeeded"),
- ENUM_ENTRY (MM_MODEM_ERROR_PUK_NEEDED, "PUKNeeded"),
- ENUM_ENTRY (MM_MODEM_ERROR_INVALID_SECRET, "InvalidSecret"),
- { 0, 0, 0 }
- };
-
- etype = g_enum_register_static ("MMModemError", values);
- }
-
- return etype;
-}
diff --git a/src/mm-modem-error.h b/src/mm-modem-error.h
deleted file mode 100644
index f5c3c57e..00000000
--- a/src/mm-modem-error.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-
-#ifndef MM_MODEM_ERROR_H
-#define MM_MODEM_ERROR_H
-
-#include <glib-object.h>
-
-enum {
- MM_MODEM_ERROR_GENERAL = 0,
- MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
- MM_MODEM_ERROR_PIN_NEEDED,
- MM_MODEM_ERROR_PUK_NEEDED,
- MM_MODEM_ERROR_INVALID_SECRET
-};
-
-#define MM_MODEM_ERROR (mm_modem_error_quark ())
-#define MM_TYPE_MODEM_ERROR (mm_modem_error_get_type ())
-
-GQuark mm_modem_error_quark (void);
-GType mm_modem_error_get_type (void);
-
-#endif /* MM_MODEM_ERROR_H */
diff --git a/src/mm-modem-gsm-card.c b/src/mm-modem-gsm-card.c
index 3a5502a6..1095d968 100644
--- a/src/mm-modem-gsm-card.c
+++ b/src/mm-modem-gsm-card.c
@@ -3,7 +3,7 @@
#include <dbus/dbus-glib.h>
#include "mm-modem-gsm-card.h"
-#include "mm-modem-error.h"
+#include "mm-errors.h"
#include "mm-callback-info.h"
static void impl_gsm_modem_get_imei (MMModemGsmCard *modem,
diff --git a/src/mm-modem-gsm-network.c b/src/mm-modem-gsm-network.c
index e83b48c6..7e170803 100644
--- a/src/mm-modem-gsm-network.c
+++ b/src/mm-modem-gsm-network.c
@@ -4,7 +4,7 @@
#include <dbus/dbus-glib.h>
#include "mm-modem-gsm-network.h"
-#include "mm-modem-error.h"
+#include "mm-errors.h"
#include "mm-callback-info.h"
static void impl_gsm_modem_register (MMModemGsmNetwork *modem,
diff --git a/src/mm-modem.c b/src/mm-modem.c
index 64fc6429..a1fbd1c3 100644
--- a/src/mm-modem.c
+++ b/src/mm-modem.c
@@ -3,7 +3,7 @@
#include <string.h>
#include <dbus/dbus-glib.h>
#include "mm-modem.h"
-#include "mm-modem-error.h"
+#include "mm-errors.h"
#include "mm-callback-info.h"
static void impl_modem_enable (MMModem *modem, gboolean enable, DBusGMethodInvocation *context);
diff --git a/src/mm-options.c b/src/mm-options.c
new file mode 100644
index 00000000..190c99ea
--- /dev/null
+++ b/src/mm-options.c
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <stdlib.h>
+#include <glib.h>
+#include "mm-options.h"
+
+static gboolean debug = FALSE;
+
+void
+mm_options_parse (int argc, char *argv[])
+{
+ GOptionContext *opt_ctx;
+ GError *error = NULL;
+ GOptionEntry entries[] = {
+ { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Output to console rather than syslog", NULL },
+ { NULL }
+ };
+
+ opt_ctx = g_option_context_new (NULL);
+ g_option_context_set_summary (opt_ctx, "DBus system service to communicate with modems.");
+ g_option_context_add_main_entries (opt_ctx, entries, NULL);
+
+ if (!g_option_context_parse (opt_ctx, &argc, &argv, &error)) {
+ g_warning ("%s\n", error->message);
+ g_error_free (error);
+ exit (1);
+ }
+
+ g_option_context_free (opt_ctx);
+}
+
+gboolean
+mm_options_debug (void)
+{
+ return debug;
+}
diff --git a/src/mm-options.h b/src/mm-options.h
new file mode 100644
index 00000000..d9190bc3
--- /dev/null
+++ b/src/mm-options.h
@@ -0,0 +1,9 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef MM_OPTIONS_H
+#define MM_OPTIONS_H
+
+void mm_options_parse (int argc, char *argv[]);
+gboolean mm_options_debug (void);
+
+#endif /* MM_OPTIONS_H */
diff --git a/src/mm-serial-parsers.c b/src/mm-serial-parsers.c
new file mode 100644
index 00000000..cc23cae8
--- /dev/null
+++ b/src/mm-serial-parsers.c
@@ -0,0 +1,266 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mm-serial-parsers.h"
+#include "mm-errors.h"
+
+/* Clean up the response by removing control characters like <CR><LF> etc */
+static void
+response_clean (GString *response)
+{
+ char *s;
+
+ /* Ends with '<CR><LF>' */
+ s = response->str + response->len - 1;
+ if (*s == '\n' && *(--s) == '\r')
+ g_string_truncate (response, response->len - 2);
+
+ /* Starts with '<CR><LF>' */
+ s = response->str;
+ if (*s == '\r' && *(++s) == '\n')
+ g_string_erase (response, 0, 2);
+}
+
+
+static gboolean
+remove_eval_cb (const GMatchInfo *match_info,
+ GString *result,
+ gpointer user_data)
+{
+ int *result_len = (int *) user_data;
+ int start;
+ int end;
+
+ if (g_match_info_fetch_pos (match_info, 0, &start, &end))
+ *result_len -= (end - start);
+
+ return TRUE;
+}
+
+static void
+remove_matches (GRegex *r, GString *string)
+{
+ char *str;
+ int result_len = string->len;
+
+ str = g_regex_replace_eval (r, string->str, string->len, 0, 0,
+ remove_eval_cb, &result_len, NULL);
+
+ g_string_truncate (string, 0);
+ g_string_append_len (string, str, result_len);
+ g_free (str);
+}
+
+/* FIXME: V0 parser is not finished */
+#if 0
+typedef struct {
+ GRegex *generic_response;
+ GRegex *detailed_error;
+} MMSerialParserV0;
+
+gpointer
+mm_serial_parser_v0_new (void)
+{
+ MMSerialParserV0 *parser;
+ GRegexCompileFlags flags = G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW | G_REGEX_OPTIMIZE;
+
+ parser = g_slice_new (MMSerialParserV0);
+
+ parser->generic_response = g_regex_new ("(\\d)\\r%", flags, 0, NULL);
+ parser->detailed_error = g_regex_new ("+CME ERROR: (\\d+)\\r\\n$", flags, 0, NULL);
+
+ return parser;
+}
+
+gboolean
+mm_serial_parser_v0_parse (gpointer parser,
+ GString *response,
+ GError **error)
+{
+ MMSerialParserV0 *parser = (MMSerialParserV0 *) data;
+ GMatchInfo *match_info;
+ char *str;
+ int code;
+ gboolean found;
+
+ found = g_regex_match_full (parser->generic_response, response->str, response->len, 0, 0, &match_info, NULL);
+ if (found) {
+ str = g_match_info_fetch (match_info, 1);
+ if (str) {
+ code = atoi (str);
+ g_free (str);
+ }
+
+ g_match_info_free (match_info);
+
+ return TRUE;
+ }
+
+ found = g_regex_match_full (parser->detailed_error, response->str, response->len, 0, 0, &match_info, NULL);
+ if (found) {
+ str = g_match_info_fetch (match_info, 1);
+ if (str) {
+ code = atoi (str);
+ g_free (str);
+ } else
+ code = MM_MOBILE_ERROR_UNKNOWN;
+
+ g_match_info_free (match_info);
+
+ g_debug ("Got error code %d: %s", code, msg);
+ g_set_error (error, MM_MOBILE_ERROR, code, "%s", msg);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+mm_serial_parser_v0_destroy (gpointer parser)
+{
+ MMSerialParserV0 *parser = (MMSerialParserV0 *) data;
+
+ g_regex_unref (parser->generic_response);
+ g_regex_unref (parser->detailed_error);
+
+ g_slice_free (MMSerialParserV0, data);
+}
+#endif
+
+typedef struct {
+ GRegex *regex_ok;
+ GRegex *regex_connect;
+ GRegex *regex_detailed_error;
+ GRegex *regex_unknown_error;
+ GRegex *regex_connect_failed;
+} MMSerialParserV1;
+
+gpointer
+mm_serial_parser_v1_new (void)
+{
+ MMSerialParserV1 *parser;
+ GRegexCompileFlags flags = G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW | G_REGEX_OPTIMIZE;
+
+ parser = g_slice_new (MMSerialParserV1);
+
+ parser->regex_ok = g_regex_new ("\\r\\nOK\\r\\n$", flags, 0, NULL);
+ parser->regex_connect = g_regex_new ("\\r\\nCONNECT\\s*\\d*\\r\\n$", flags, 0, NULL);
+ parser->regex_detailed_error = g_regex_new ("\\r\\n\\+CME ERROR: (\\d+)\\r\\n$", flags, 0, NULL);
+ parser->regex_unknown_error = g_regex_new ("\\r\\n(ERROR)|(COMMAND NOT SUPPORT)\\r\\n$", flags, 0, NULL);
+ parser->regex_connect_failed = g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n$", flags, 0, NULL);
+
+ return parser;
+}
+
+gboolean
+mm_serial_parser_v1_parse (gpointer data,
+ GString *response,
+ GError **error)
+{
+ MMSerialParserV1 *parser = (MMSerialParserV1 *) data;
+ GMatchInfo *match_info;
+ const char *msg;
+ int code;
+ gboolean found = FALSE;
+
+ /* First, check for successfule responses */
+
+ found = g_regex_match_full (parser->regex_ok, response->str, response->len, 0, 0, NULL, NULL);
+ if (found)
+ remove_matches (parser->regex_ok, response);
+ else
+ found = g_regex_match_full (parser->regex_connect, response->str, response->len, 0, 0, NULL, NULL);
+
+ if (found) {
+ response_clean (response);
+ return TRUE;
+ }
+
+ /* Now failures */
+ code = MM_MOBILE_ERROR_UNKNOWN;
+
+ found = g_regex_match_full (parser->regex_detailed_error,
+ response->str, response->len,
+ 0, 0, &match_info, NULL);
+
+ if (found) {
+ char *str;
+
+ str = g_match_info_fetch (match_info, 1);
+ if (str) {
+ code = atoi (str);
+ g_free (str);
+ }
+ g_match_info_free (match_info);
+ } else
+ found = g_regex_match_full (parser->regex_unknown_error, response->str, response->len, 0, 0, NULL, NULL);
+
+ if (found) {
+#if 0
+ /* FIXME: This does not work for some reason. */
+ GEnumValue *enum_value;
+
+ enum_value = g_enum_get_value ((GEnumClass *) g_type_class_peek_static (), code);
+ msg = enum_value->value_nick;
+#endif
+ msg = "FIXME";
+
+ g_debug ("Got error code %d: %s", code, msg);
+ g_set_error (error, MM_MOBILE_ERROR, code, "%s", msg);
+ } else {
+ found = g_regex_match_full (parser->regex_connect_failed,
+ response->str, response->len,
+ 0, 0, &match_info, NULL);
+ if (found) {
+ char *str;
+
+ str = g_match_info_fetch (match_info, 1);
+ if (str) {
+ if (!strcmp (str, "NO CARRIER")) {
+ code = MM_MODEM_CONNECT_ERROR_NO_CARRIER;
+ msg = "No carrier";
+ } else if (!strcmp (str, "BUSY")) {
+ code = MM_MODEM_CONNECT_ERROR_BUSY;
+ msg = "Busy";
+ } else if (!strcmp (str, "NO ANSWER")) {
+ code = MM_MODEM_CONNECT_ERROR_NO_ANSWER;
+ msg = "No answer";
+ } else if (!strcmp (str, "NO DIALTONE")) {
+ code = MM_MODEM_CONNECT_ERROR_NO_DIALTONE;
+ msg = "No dialtone";
+ } else {
+ g_warning ("Got matching connect failure, but can't parse it");
+ /* uhm... make something up (yes, ok, lie!). */
+ code = MM_MODEM_CONNECT_ERROR_NO_CARRIER;
+ msg = "No carrier";
+ }
+
+ g_free (str);
+ }
+ g_match_info_free (match_info);
+
+ g_debug ("Got connect failure code %d: %s", code, msg);
+ g_set_error (error, MM_MODEM_CONNECT_ERROR, code, "%s", msg);
+ }
+ }
+
+ return found;
+
+}
+
+void
+mm_serial_parser_v1_destroy (gpointer data)
+{
+ MMSerialParserV1 *parser = (MMSerialParserV1 *) data;
+
+ g_regex_unref (parser->regex_ok);
+ g_regex_unref (parser->regex_connect);
+ g_regex_unref (parser->regex_detailed_error);
+ g_regex_unref (parser->regex_unknown_error);
+ g_regex_unref (parser->regex_connect_failed);
+
+ g_slice_free (MMSerialParserV1, data);
+}
diff --git a/src/mm-serial-parsers.h b/src/mm-serial-parsers.h
new file mode 100644
index 00000000..8ef6ef03
--- /dev/null
+++ b/src/mm-serial-parsers.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef MM_SERIAL_PARSERS_H
+#define MM_SERIAL_PARSERS_H
+
+#include <glib.h>
+
+/* FIXME: V0 parser is not finished */
+#if 0
+gpointer mm_serial_parser_v0_new (void);
+gboolean mm_serial_parser_v0_parse (gpointer parser,
+ GString *response,
+ GError **error);
+
+void mm_serial_parser_v0_destroy (gpointer parser);
+#endif
+
+
+gpointer mm_serial_parser_v1_new (void);
+gboolean mm_serial_parser_v1_parse (gpointer parser,
+ GString *response,
+ GError **error);
+
+void mm_serial_parser_v1_destroy (gpointer parser);
+
+#endif /* MM_SERIAL_PARSERS_H */
diff --git a/src/mm-serial.c b/src/mm-serial.c
index 284db4d2..f941feff 100644
--- a/src/mm-serial.c
+++ b/src/mm-serial.c
@@ -2,6 +2,8 @@
#define _GNU_SOURCE /* for strcasestr() */
+#include <stdio.h>
+#include <stdlib.h>
#include <termio.h>
#include <unistd.h>
#include <sys/types.h>
@@ -12,6 +14,10 @@
#include <string.h>
#include "mm-serial.h"
+#include "mm-errors.h"
+#include "mm-options.h"
+
+static gboolean mm_serial_queue_process (gpointer data);
G_DEFINE_TYPE (MMSerial, mm_serial, G_TYPE_OBJECT)
@@ -27,7 +33,6 @@ enum {
LAST_PROP
};
-#define MM_DEBUG_SERIAL 1
#define SERIAL_BUF_SIZE 2048
#define MM_SERIAL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_SERIAL, MMSerialPrivate))
@@ -35,6 +40,15 @@ enum {
typedef struct {
int fd;
GIOChannel *channel;
+ GQueue *queue;
+ GString *command;
+ GString *response;
+
+ /* Response parser data */
+ MMSerialResponseParserFn response_parser_fn;
+ gpointer response_parser_user_data;
+ GDestroyNotify response_parser_notify;
+
struct termios old_t;
char *device;
@@ -44,7 +58,8 @@ typedef struct {
guint stopbits;
guint64 send_delay;
- guint pending_id;
+ guint watch_id;
+ guint timeout_id;
} MMSerialPrivate;
const char *
@@ -189,86 +204,6 @@ parse_stopbits (guint i)
return stopbits;
}
-#ifdef MM_DEBUG_SERIAL
-static inline void
-serial_debug (const char *prefix, const char *data, int len)
-{
- GString *str;
- int i;
-
- str = g_string_sized_new (len);
- for (i = 0; i < len; i++) {
- if (data[i] == '\0')
- g_string_append_c (str, ' ');
- else if (data[i] == '\r')
- g_string_append_c (str, '\n');
- else
- g_string_append_c (str, data[i]);
- }
-
- g_debug ("%s '%s'", prefix, str->str);
- g_string_free (str, TRUE);
-}
-#else
-static inline void
-serial_debug (const char *prefix, const char *data, int len)
-{
-}
-#endif /* MM_DEBUG_SERIAL */
-
-/* Pending data reading */
-
-static gboolean
-mm_serial_timed_out (gpointer data)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (data);
-
- /* Cancel data reading */
- if (priv->pending_id)
- g_source_remove (priv->pending_id);
-
- return FALSE;
-}
-
-static guint
-mm_serial_set_pending (MMSerial *self,
- guint timeout,
- GIOFunc callback,
- gpointer user_data,
- GDestroyNotify notify)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- GSource *source;
-
- if (G_UNLIKELY (priv->pending_id)) {
- /* FIXME: Probably should queue up pending calls instead? */
- /* Multiple pending calls on the same GIOChannel doesn't work, so let's cancel the previous one. */
- g_warning ("Adding new pending call while previous one isn't finished.");
- g_warning ("Cancelling the previous pending call.");
- g_source_remove (priv->pending_id);
- }
-
- priv->pending_id = g_io_add_watch_full (priv->channel,
- G_PRIORITY_DEFAULT,
- G_IO_IN | G_IO_ERR | G_IO_HUP,
- callback, user_data, notify);
-
- source = g_timeout_source_new (timeout * 100);
- g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (mm_serial_timed_out), G_OBJECT (self)));
- g_source_attach (source, NULL);
- g_source_unref (source);
-
- return priv->pending_id;
-}
-
-static void
-mm_serial_pending_done (MMSerial *self)
-{
- MM_SERIAL_GET_PRIVATE (self)->pending_id = 0;
-}
-
-/****/
-
static gboolean
config_fd (MMSerial *self)
{
@@ -305,312 +240,203 @@ config_fd (MMSerial *self)
return TRUE;
}
-gboolean
-mm_serial_open (MMSerial *self)
+static void
+serial_debug (const char *prefix, const char *buf, int len)
{
- MMSerialPrivate *priv;
-
- g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
-
- priv = MM_SERIAL_GET_PRIVATE (self);
+ const char *s;
- if (priv->fd)
- /* Already open */
- return TRUE;
+ if (!mm_options_debug ())
+ return;
- g_debug ("(%s) opening serial device...", priv->device);
- priv->fd = open (priv->device, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
+ if (len < 0)
+ len = strlen (buf);
- if (priv->fd < 0) {
- g_warning ("(%s) cannot open device: %s", priv->device, strerror (errno));
- return FALSE;
- }
+ g_print ("%s '", prefix);
- if (ioctl (priv->fd, TCGETA, &priv->old_t) < 0) {
- g_warning ("(%s) cannot control device (errno %d)", priv->device, errno);
- close (priv->fd);
- return FALSE;
- }
+ s = buf;
+ while (len--) {
+ if (g_ascii_isprint (*s))
+ g_print ("%c", *s);
+ else if (*s == '\r')
+ g_print ("<CR>");
+ else if (*s == '\n')
+ g_print ("<LF>");
+ else
+ g_print ("\\%d", *s);
- if (!config_fd (self)) {
- close (priv->fd);
- priv->fd = 0;
- return FALSE;
+ s++;
}
- priv->channel = g_io_channel_unix_new (priv->fd);
-
- return TRUE;
-}
-
-void
-mm_serial_close (MMSerial *self)
-{
- MMSerialPrivate *priv;
-
- g_return_if_fail (MM_IS_SERIAL (self));
-
- priv = MM_SERIAL_GET_PRIVATE (self);
-
- if (priv->pending_id)
- g_source_remove (priv->pending_id);
-
- if (priv->fd) {
- g_message ("Closing device '%s'", priv->device);
-
- if (priv->channel) {
- g_io_channel_unref (priv->channel);
- priv->channel = NULL;
- }
-
- ioctl (priv->fd, TCSETA, &priv->old_t);
- close (priv->fd);
- priv->fd = 0;
- }
+ g_print ("'\n");
}
-gboolean
-mm_serial_send_command (MMSerial *self, GByteArray *command)
+static gboolean
+mm_serial_send_command (MMSerial *self, const char *command)
{
- MMSerialPrivate *priv;
- int fd;
- int i;
- ssize_t status;
-
- g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
- g_return_val_if_fail (command != NULL, FALSE);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ const char *s;
+ int status;
- priv = MM_SERIAL_GET_PRIVATE (self);
+ g_string_truncate (priv->command, g_str_has_prefix (command, "AT") ? 0 : 2);
+ g_string_append (priv->command, command);
- fd = priv->fd;
+ if (command[strlen (command)] != '\r')
+ g_string_append_c (priv->command, '\r');
- serial_debug ("Sending:", (char *) command->data, command->len);
+ serial_debug ("-->", priv->command->str, -1);
- for (i = 0; i < command->len; i++) {
+ s = priv->command->str;
+ while (*s) {
again:
- status = write (fd, command->data + i, 1);
-
+ status = write (priv->fd, s, 1);
if (status < 0) {
if (errno == EAGAIN)
goto again;
-
- g_warning ("Error in writing (errno %d)", errno);
- return FALSE;
+ else {
+ g_warning ("Error writing to serial device: %s", strerror (errno));
+ break;
+ }
}
if (priv->send_delay)
usleep (priv->send_delay);
- }
- return TRUE;
-}
-
-gboolean
-mm_serial_send_command_string (MMSerial *self, const char *str)
-{
- GByteArray *command;
- gboolean ret;
-
- g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
- g_return_val_if_fail (str != NULL, FALSE);
-
- command = g_byte_array_new ();
- g_byte_array_append (command, (guint8 *) str, strlen (str));
- g_byte_array_append (command, (guint8 *) "\r", 1);
-
- ret = mm_serial_send_command (self, command);
- g_byte_array_free (command, TRUE);
+ s++;
+ }
- return ret;
+ return *s == '\0';
}
typedef struct {
- MMSerial *serial;
- char *terminators;
- GString *result;
- MMSerialGetReplyFn callback;
+ char *command;
+ MMSerialResponseFn callback;
gpointer user_data;
-} GetReplyInfo;
+ guint32 timeout;
+} MMQueueData;
static void
-get_reply_done (gpointer data)
+mm_serial_got_response (MMSerial *self, GError *error)
{
- GetReplyInfo *info = (GetReplyInfo *) data;
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMQueueData *info;
- mm_serial_pending_done (info->serial);
+ if (priv->timeout_id)
+ g_source_remove (priv->timeout_id);
- /* Call the callback */
- info->callback (info->serial, info->result->str, info->user_data);
+ info = (MMQueueData *) g_queue_pop_head (priv->queue);
+ if (info) {
+ if (info->callback)
+ info->callback (self, priv->response, error, info->user_data);
- /* Free info */
- g_free (info->terminators);
- g_string_free (info->result, TRUE);
+ g_free (info->command);
+ g_slice_free (MMQueueData, info);
+ }
+
+ if (error)
+ g_error_free (error);
- g_slice_free (GetReplyInfo, info);
+ g_string_truncate (priv->response, 0);
+ if (!g_queue_is_empty (priv->queue))
+ g_idle_add (mm_serial_queue_process, self);
}
static gboolean
-get_reply_got_data (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
+mm_serial_timed_out (gpointer data)
{
- GetReplyInfo *info = (GetReplyInfo *) data;
- gsize bytes_read;
- char buf[SERIAL_BUF_SIZE + 1];
- GIOStatus status;
- gboolean done = FALSE;
- int i;
+ MMSerial *self = MM_SERIAL (data);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ GError *error;
- if (condition & G_IO_HUP || condition & G_IO_ERR) {
- g_string_truncate (info->result, 0);
- return FALSE;
- }
+ priv->timeout_id = 0;
- do {
- GError *err = NULL;
+ error = g_error_new (MM_SERIAL_ERROR,
+ MM_SERIAL_RESPONSE_TIMEOUT,
+ "%s", "Serial command timed out");
+ /* FIXME: This is not completely correct - if the response finally arrives and there's
+ some other command waiting for response right now, the other command will
+ get the output of the timed out command. Maybe flashing would help here? */
+ mm_serial_got_response (self, error);
- status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err);
- if (status == G_IO_STATUS_ERROR) {
- g_warning ("%s", err->message);
- g_error_free (err);
- err = NULL;
- }
+ return FALSE;
+}
- if (bytes_read > 0) {
- char *p;
-
- serial_debug ("Got:", buf, bytes_read);
-
- p = &buf[0];
- for (i = 0; i < bytes_read && !done; i++, p++) {
- int j;
- gboolean is_terminator = FALSE;
-
- for (j = 0; j < strlen (info->terminators); j++) {
- if (*p == info->terminators[j]) {
- is_terminator = TRUE;
- break;
- }
- }
-
- if (is_terminator) {
- /* Ignore terminators in the beginning of the output */
- if (info->result->len > 0)
- done = TRUE;
- } else
- g_string_append_c (info->result, *p);
- }
- }
+static gboolean
+mm_serial_queue_process (gpointer data)
+{
+ MMSerial *self = MM_SERIAL (data);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMQueueData *info;
- /* Limit the size of the buffer */
- if (info->result->len > SERIAL_BUF_SIZE) {
- g_warning ("%s (%s): response buffer filled before repsonse received",
- __func__, MM_SERIAL_GET_PRIVATE (info->serial)->device);
- g_string_truncate (info->result, 0);
- done = TRUE;
- }
- } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
+ info = (MMQueueData *) g_queue_peek_head (priv->queue);
+ if (!info)
+ return FALSE;
- return !done;
-}
+ if (mm_serial_send_command (self, info->command)) {
+ GSource *source;
-guint
-mm_serial_get_reply (MMSerial *self,
- guint timeout,
- const char *terminators,
- MMSerialGetReplyFn callback,
- gpointer user_data)
-{
- GetReplyInfo *info;
+ source = g_timeout_source_new (info->timeout);
+ g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (mm_serial_timed_out), G_OBJECT (self)));
+ g_source_attach (source, NULL);
+ priv->timeout_id = g_source_get_id (source);
+ g_source_unref (source);
+ } else {
+ GError *error;
- g_return_val_if_fail (MM_IS_SERIAL (self), 0);
- g_return_val_if_fail (terminators != NULL, 0);
- g_return_val_if_fail (callback != NULL, 0);
+ error = g_error_new (MM_SERIAL_ERROR,
+ MM_SERIAL_SEND_FAILED,
+ "%s", "Sending command failed");
- info = g_slice_new0 (GetReplyInfo);
- info->serial = self;
- info->terminators = g_strdup (terminators);
- info->result = g_string_new (NULL);
- info->callback = callback;
- info->user_data = user_data;
+ mm_serial_got_response (self, error);
+ }
- return mm_serial_set_pending (self, timeout, get_reply_got_data, info, get_reply_done);
+ return FALSE;
}
-typedef struct {
- MMSerial *serial;
- char **str_needles;
- char **terminators;
- GString *result;
- MMSerialWaitForReplyFn callback;
- gpointer user_data;
- int reply_index;
- guint timeout;
- time_t start;
-} WaitForReplyInfo;
-
-static void
-wait_for_reply_done (gpointer data)
+void
+mm_serial_set_response_parser (MMSerial *self,
+ MMSerialResponseParserFn fn,
+ gpointer user_data,
+ GDestroyNotify notify)
{
- WaitForReplyInfo *info = (WaitForReplyInfo *) data;
-
- mm_serial_pending_done (info->serial);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- /* Call the callback */
- info->callback (info->serial, info->reply_index, info->user_data);
+ g_return_if_fail (MM_IS_SERIAL (self));
- /* Free info */
- if (info->result)
- g_string_free (info->result, TRUE);
+ if (priv->response_parser_notify)
+ priv->response_parser_notify (priv->response_parser_user_data);
- g_strfreev (info->str_needles);
- g_strfreev (info->terminators);
- g_slice_free (WaitForReplyInfo, info);
+ priv->response_parser_fn = fn;
+ priv->response_parser_user_data = user_data;
+ priv->response_parser_notify = notify;
}
static gboolean
-find_terminator (const char *line, char **terminators)
+parse_response (MMSerial *self,
+ GString *response,
+ GError **error)
{
- int i;
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- for (i = 0; terminators[i]; i++) {
- if (!strncasecmp (line, terminators[i], strlen (terminators[i])))
- return TRUE;
- }
- return FALSE;
-}
+ g_return_val_if_fail (priv->response_parser_fn != NULL, FALSE);
-static gboolean
-find_response (const char *line, char **responses, gint *idx)
-{
- int i;
-
- /* Don't look for a result again if we got one previously */
- for (i = 0; responses[i]; i++) {
- if (strcasestr (line, responses[i])) {
- *idx = i;
- return TRUE;
- }
- }
- return FALSE;
+ return priv->response_parser_fn (priv->response_parser_user_data, response, error);
}
-#define RESPONSE_LINE_MAX 128
-
static gboolean
-wait_for_reply_got_data (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
+data_available (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
{
- WaitForReplyInfo *info = (WaitForReplyInfo *) data;
- gchar buf[SERIAL_BUF_SIZE + 1];
+ MMSerial *self = MM_SERIAL (data);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ char buf[SERIAL_BUF_SIZE + 1];
gsize bytes_read;
GIOStatus status;
- gboolean got_response = FALSE;
- gboolean done = FALSE;
- if (condition & G_IO_HUP || condition & G_IO_ERR)
- return FALSE;
+ if (condition & G_IO_HUP || condition & G_IO_ERR) {
+ g_string_truncate (priv->response, 0);
+ return TRUE;
+ }
do {
GError *err = NULL;
@@ -623,185 +449,112 @@ wait_for_reply_got_data (GIOChannel *source,
}
if (bytes_read > 0) {
- buf[bytes_read] = 0;
- g_string_append (info->result, buf);
-
- serial_debug ("Got:", info->result->str, info->result->len);
+ serial_debug ("<--", buf, bytes_read);
+ g_string_append_len (priv->response, buf, bytes_read);
}
- /* Look for needles and terminators */
- if ((bytes_read > 0) && info->result->str) {
- char *p = info->result->str;
-
- /* Break the response up into lines and process each one */
- while ( (p < info->result->str + strlen (info->result->str))
- && !(done && got_response)) {
- char line[RESPONSE_LINE_MAX] = { '\0', };
- char *tmp;
- int i;
- gboolean got_something = FALSE;
-
- for (i = 0; *p && (i < RESPONSE_LINE_MAX - 1); p++) {
- /* Ignore front CR/LF */
- if ((*p == '\n') || (*p == '\r')) {
- if (got_something)
- break;
- } else {
- line[i++] = *p;
- got_something = TRUE;
- }
- }
- line[i] = '\0';
-
- tmp = g_strstrip (line);
- if (tmp && strlen (tmp)) {
- done = find_terminator (tmp, info->terminators);
- if (info->reply_index == -1)
- got_response = find_response (tmp, info->str_needles, &(info->reply_index));
- }
- }
-
- if (done && got_response)
- break;
- }
+ if (parse_response (self, priv->response, &err))
+ mm_serial_got_response (self, err);
- /* Limit the size of the buffer */
- if (info->result->len > SERIAL_BUF_SIZE) {
- g_warning ("%s (%s): response buffer filled before repsonse received",
- __func__, MM_SERIAL_GET_PRIVATE (info->serial)->device);
- done = TRUE;
- break;
- }
+ } while (bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
- /* Make sure we don't go over the timeout, in addition to the timeout
- * handler that's been scheduled. If for some reason this loop doesn't
- * terminate (terminator not found, whatever) then this should make
- * sure that we don't spin the CPU forever.
- */
- if (time (NULL) - info->start > info->timeout + 1) {
- done = TRUE;
- break;
- } else
- g_usleep (50);
- } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
-
- return !done;
+ return TRUE;
}
-guint
-mm_serial_wait_for_reply (MMSerial *self,
- guint timeout,
- char **responses,
- char **terminators,
- MMSerialWaitForReplyFn callback,
- gpointer user_data)
+gboolean
+mm_serial_open (MMSerial *self, GError **error)
{
- WaitForReplyInfo *info;
+ MMSerialPrivate *priv;
- g_return_val_if_fail (MM_IS_SERIAL (self), 0);
- g_return_val_if_fail (responses != NULL, 0);
- g_return_val_if_fail (callback != NULL, 0);
+ g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
- info = g_slice_new0 (WaitForReplyInfo);
- info->serial = self;
- info->str_needles = g_strdupv (responses);
- info->terminators = g_strdupv (terminators);
- info->result = g_string_new (NULL);
- info->callback = callback;
- info->user_data = user_data;
- info->reply_index = -1;
- info->timeout = timeout;
- info->start = time (NULL);
+ priv = MM_SERIAL_GET_PRIVATE (self);
- return mm_serial_set_pending (self, timeout, wait_for_reply_got_data, info, wait_for_reply_done);
-}
+ if (priv->fd)
+ /* Already open */
+ return TRUE;
-#if 0
-typedef struct {
- MMSerial *serial;
- gboolean timed_out;
- MMSerialWaitQuietFn callback;
- gpointer user_data;
-} WaitQuietInfo;
+ g_debug ("(%s) opening serial device...", priv->device);
+ priv->fd = open (priv->device, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
-static void
-wait_quiet_done (gpointer data)
-{
- WaitQuietInfo *info = (WaitQuietInfo *) data;
+ if (priv->fd < 0) {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
+ "Could not open serial device %s: %s", priv->device, strerror (errno));
+ return FALSE;
+ }
- mm_serial_pending_done (info->serial);
+ if (ioctl (priv->fd, TCGETA, &priv->old_t) < 0) {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
+ "Could not open serial device %s: %s", priv->device, strerror (errno));
+ close (priv->fd);
+ return FALSE;
+ }
- /* Call the callback */
- info->callback (info->serial, info->timed_out, info->user_data);
+ if (!config_fd (self)) {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
+ "Could not open serial device %s: %s", priv->device, strerror (errno));
+ close (priv->fd);
+ priv->fd = 0;
+ return FALSE;
+ }
+
+ priv->channel = g_io_channel_unix_new (priv->fd);
+ priv->watch_id = g_io_add_watch (priv->channel,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ data_available, self);
- /* Free info */
- g_slice_free (WaitQuietInfo, info);
+ return TRUE;
}
-static gboolean
-wait_quiet_quiettime (gpointer data)
+void
+mm_serial_close (MMSerial *self)
{
- WaitQuietInfo *info = (WaitQuietInfo *) data;
-
- info->timed_out = FALSE;
- g_source_remove (MM_SERIAL_GET_PRIVATE (info->serial)->pending);
+ MMSerialPrivate *priv;
- return FALSE;
-}
+ g_return_if_fail (MM_IS_SERIAL (self));
-static gboolean
-wait_quiet_got_data (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
-{
- WaitQuietInfo *info = (WaitQuietInfo *) data;
- gsize bytes_read;
- char buf[4096];
- GIOStatus status;
+ priv = MM_SERIAL_GET_PRIVATE (self);
- if (condition & G_IO_HUP || condition & G_IO_ERR)
- return FALSE;
+ if (priv->fd) {
+ g_message ("Closing device '%s'", priv->device);
- if (condition & G_IO_IN) {
- do {
- status = g_io_channel_read_chars (source, buf, 4096, &bytes_read, NULL);
+ if (priv->channel) {
+ g_source_remove (priv->watch_id);
+ g_io_channel_shutdown (priv->channel, TRUE, NULL);
+ g_io_channel_unref (priv->channel);
+ priv->channel = NULL;
+ }
- if (bytes_read) {
- /* Reset the quiet time timeout */
- g_source_remove (info->quiet_id);
- info->quiet_id = g_timeout_add (info->quiet_time, wait_quiet_quiettime, info);
- }
- } while (bytes_read == 4096 || status == G_IO_STATUS_AGAIN);
+ ioctl (priv->fd, TCSETA, &priv->old_t);
+ close (priv->fd);
+ priv->fd = 0;
}
-
- return TRUE;
}
void
-mm_serial_wait_quiet (MMSerial *self,
- guint timeout,
- guint quiet_time,
- MMSerialWaitQuietFn callback,
- gpointer user_data)
+mm_serial_queue_command (MMSerial *self,
+ const char *command,
+ guint32 timeout_seconds,
+ MMSerialResponseFn callback,
+ gpointer user_data)
{
- WaitQuietInfo *info;
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMQueueData *info;
g_return_if_fail (MM_IS_SERIAL (self));
- g_return_if_fail (callback != NULL);
+ g_return_if_fail (command != NULL);
- info = g_slice_new0 (WaitQuietInfo);
- info->serial = self;
- info->timed_out = TRUE;
+ info = g_slice_new0 (MMQueueData);
+ info->command = g_strdup (command);
+ info->timeout = timeout_seconds * 1000;
info->callback = callback;
info->user_data = user_data;
- info->quiet_id = g_timeout_add (quiet_time,
- wait_quiet_timeout,
- info);
- return mm_serial_set_pending (self, timeout, wait_quiet_got_data, info, wait_quiet_done);
-}
+ g_queue_push_tail (priv->queue, info);
-#endif
+ if (g_queue_get_length (priv->queue) == 1)
+ g_idle_add (mm_serial_queue_process, self);
+}
typedef struct {
MMSerial *serial;
@@ -841,8 +594,6 @@ flash_done (gpointer data)
{
FlashInfo *info = (FlashInfo *) data;
- MM_SERIAL_GET_PRIVATE (info->serial)->pending_id = 0;
-
info->callback (info->serial, info->user_data);
g_slice_free (FlashInfo, info);
@@ -884,25 +635,9 @@ mm_serial_flash (MMSerial *self,
info,
flash_done);
- MM_SERIAL_GET_PRIVATE (self)->pending_id = id;
-
return id;
}
-GIOChannel *
-mm_serial_get_io_channel (MMSerial *self)
-{
- MMSerialPrivate *priv;
-
- g_return_val_if_fail (MM_IS_SERIAL (self), NULL);
-
- priv = MM_SERIAL_GET_PRIVATE (self);
- if (priv->channel)
- return g_io_channel_ref (priv->channel);
-
- return NULL;
-}
-
/*****************************************************************************/
static void
@@ -915,6 +650,10 @@ mm_serial_init (MMSerial *self)
priv->parity = 'n';
priv->stopbits = 1;
priv->send_delay = 0;
+
+ priv->queue = g_queue_new ();
+ priv->command = g_string_new_len ("AT", SERIAL_BUF_SIZE);
+ priv->response = g_string_sized_new (SERIAL_BUF_SIZE);
}
static GObject*
@@ -1012,8 +751,15 @@ finalize (GObject *object)
MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
mm_serial_close (self);
+
+ g_queue_free (priv->queue);
+ g_string_free (priv->command, TRUE);
+ g_string_free (priv->response, TRUE);
g_free (priv->device);
+ if (priv->response_parser_notify)
+ priv->response_parser_notify (priv->response_parser_user_data);
+
G_OBJECT_CLASS (mm_serial_parent_class)->finalize (object);
}
diff --git a/src/mm-serial.h b/src/mm-serial.h
index bd138516..37162c6f 100644
--- a/src/mm-serial.h
+++ b/src/mm-serial.h
@@ -6,12 +6,12 @@
#include <glib/gtypes.h>
#include <glib-object.h>
-#define MM_TYPE_SERIAL (mm_serial_get_type ())
-#define MM_SERIAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SERIAL, MMSerial))
-#define MM_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SERIAL, MMSerialClass))
-#define MM_IS_SERIAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SERIAL))
-#define MM_IS_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SERIAL))
-#define MM_SERIAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SERIAL, MMSerialClass))
+#define MM_TYPE_SERIAL (mm_serial_get_type ())
+#define MM_SERIAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SERIAL, MMSerial))
+#define MM_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SERIAL, MMSerialClass))
+#define MM_IS_SERIAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SERIAL))
+#define MM_IS_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SERIAL))
+#define MM_SERIAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SERIAL, MMSerialClass))
#define MM_SERIAL_DEVICE "device"
#define MM_SERIAL_BAUD "baud"
@@ -20,66 +20,51 @@
#define MM_SERIAL_STOPBITS "stopbits"
#define MM_SERIAL_SEND_DELAY "send-delay"
-typedef struct {
- GObject parent;
-} MMSerial;
-
-typedef struct {
- GObjectClass parent;
-} MMSerialClass;
-
-GType mm_serial_get_type (void);
-
-typedef void (*MMSerialGetReplyFn) (MMSerial *serial,
- const char *reply,
- gpointer user_data);
+typedef struct _MMSerial MMSerial;
+typedef struct _MMSerialClass MMSerialClass;
-typedef void (*MMSerialWaitForReplyFn) (MMSerial *serial,
- int reply_index,
- gpointer user_data);
+typedef gboolean (*MMSerialResponseParserFn) (gpointer user_data,
+ GString *response,
+ GError **error);
-typedef void (*MMSerialWaitQuietFn) (MMSerial *serial,
- gboolean timed_out,
+typedef void (*MMSerialResponseFn) (MMSerial *serial,
+ GString *response,
+ GError *error,
gpointer user_data);
typedef void (*MMSerialFlashFn) (MMSerial *serial,
gpointer user_data);
-const char *mm_serial_get_device (MMSerial *serial);
-
-gboolean mm_serial_open (MMSerial *self);
+struct _MMSerial {
+ GObject parent;
+};
-void mm_serial_close (MMSerial *self);
-gboolean mm_serial_send_command (MMSerial *self,
- GByteArray *command);
+struct _MMSerialClass {
+ GObjectClass parent;
+};
-gboolean mm_serial_send_command_string (MMSerial *self,
- const char *str);
+GType mm_serial_get_type (void);
-guint mm_serial_get_reply (MMSerial *self,
- guint timeout,
- const char *terminators,
- MMSerialGetReplyFn callback,
- gpointer user_data);
+void mm_serial_set_response_parser (MMSerial *self,
+ MMSerialResponseParserFn fn,
+ gpointer user_data,
+ GDestroyNotify notify);
-guint mm_serial_wait_for_reply (MMSerial *self,
- guint timeout,
- char **responses,
- char **terminators,
- MMSerialWaitForReplyFn callback,
- gpointer user_data);
+gboolean mm_serial_open (MMSerial *self,
+ GError **error);
-void mm_serial_wait_quiet (MMSerial *self,
- guint timeout,
- guint quiet_time,
- MMSerialWaitQuietFn callback,
- gpointer user_data);
+void mm_serial_close (MMSerial *self);
+void mm_serial_queue_command (MMSerial *self,
+ const char *command,
+ guint32 timeout_seconds,
+ MMSerialResponseFn callback,
+ gpointer user_data);
-guint mm_serial_flash (MMSerial *self,
- guint32 flash_time,
- MMSerialFlashFn callback,
- gpointer user_data);
+guint mm_serial_flash (MMSerial *self,
+ guint32 flash_time,
+ MMSerialFlashFn callback,
+ gpointer user_data);
-GIOChannel *mm_serial_get_io_channel (MMSerial *self);
+const char *mm_serial_get_device (MMSerial *self);
#endif /* MM_SERIAL_H */