aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTambet Ingo <tambet@gmail.com>2008-08-21 17:18:38 +0300
committerTambet Ingo <tambet@gmail.com>2008-08-21 17:18:38 +0300
commitd6be2af93f3b5f7dde9761b8533ce187c30377b3 (patch)
treeb2a00c3458f25477d8ae3c04607c9d84b81ac618 /src
parent9afafdf46dbd9ded0df4f99505ed5107242b4883 (diff)
Implement registration information retrieving for GSM modems.
Diffstat (limited to 'src')
-rw-r--r--src/mm-generic-gsm.c226
-rw-r--r--src/mm-gsm-modem.c60
-rw-r--r--src/mm-gsm-modem.h24
3 files changed, 285 insertions, 25 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 1ca4920c..518b8198 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -248,43 +248,102 @@ register_manual (MMGsmModem *modem, const char *network_id, MMCallbackInfo *info
}
}
+static void
+get_reg_status_done (MMSerial *serial,
+ int reply_index,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ switch (reply_index) {
+ case 0:
+ info->uint_result = (guint32) MM_GSM_MODEM_REG_STATUS_IDLE;
+ break;
+ case 1:
+ info->uint_result = (guint32) MM_GSM_MODEM_REG_STATUS_HOME;
+ break;
+ case 2:
+ info->uint_result = (guint32) MM_GSM_MODEM_REG_STATUS_SEARCHING;
+ break;
+ case 3:
+ info->uint_result = (guint32) MM_GSM_MODEM_REG_STATUS_DENIED;
+ break;
+ case 4:
+ info->uint_result = (guint32) MM_GSM_MODEM_REG_STATUS_ROAMING;
+ break;
+ case -1:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s",
+ "Reading registration status timed out");
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s",
+ "Reading registration status failed");
+ break;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_registration_status (MMGsmModem *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 (!id) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading registration status failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
static gboolean
automatic_registration_again (gpointer data)
{
MMCallbackInfo *info = (MMCallbackInfo *) data;
- register_auto (MM_GSM_MODEM (mm_callback_info_get_data (info, "modem")), info);
+ register_auto (MM_GSM_MODEM (info->modem), info);
- mm_callback_info_set_data (info, "modem", NULL, NULL);
-
return FALSE;
}
static void
-register_auto_done (MMSerial *serial,
- int reply_index,
+register_auto_done (MMModem *modem,
+ guint result,
+ GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- switch (reply_index) {
- case 0:
+ if (error) {
+ info->error = g_error_copy (error);
+ goto out;
+ }
+
+ switch (result) {
+ case MM_GSM_MODEM_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 1:
+ case MM_GSM_MODEM_REG_STATUS_HOME:
g_message ("Registered on Home network");
break;
- case 2:
- mm_callback_info_set_data (info, "modem", g_object_ref (serial), g_object_unref);
- MM_GENERIC_GSM_GET_PRIVATE (serial)->pending_id = g_timeout_add (1000, automatic_registration_again, info);
+ case MM_GSM_MODEM_REG_STATUS_SEARCHING:
+ MM_GENERIC_GSM_GET_PRIVATE (modem)->pending_id = g_timeout_add (1000, automatic_registration_again, info);
return;
break;
- case 3:
+ case MM_GSM_MODEM_REG_STATUS_DENIED:
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s",
"Automatic registration failed: registration denied");
break;
- case 4:
+ case MM_GSM_MODEM_REG_STATUS_ROAMING:
g_message ("Registered on Roaming network");
break;
case -1:
@@ -295,24 +354,14 @@ register_auto_done (MMSerial *serial,
break;
}
+ out:
mm_callback_info_schedule (info);
}
static void
register_auto (MMGsmModem *modem, 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;
-
- if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+CREG?"))
- id = mm_serial_wait_for_reply (MM_SERIAL (modem), 60, responses, terminators,
- register_auto_done, info);
-
- if (!id) {
- info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Automatic registration failed.");
- mm_callback_info_schedule (info);
- }
+ get_registration_status (modem, register_auto_done, info);
}
static void
@@ -331,6 +380,132 @@ do_register (MMGsmModem *modem,
register_auto (modem, info);
}
+
+static char *
+parse_operator (const char *reply)
+{
+ char *operator = NULL;
+
+ if (reply && !strncmp (reply, "+COPS: ", 7)) {
+ /* Got valid reply */
+ GRegex *r;
+ GMatchInfo *match_info;
+
+ reply += 7;
+ r = g_regex_new ("(\\d),(\\d),\"(.+)\"", G_REGEX_UNGREEDY, 0, NULL);
+ if (!r)
+ return NULL;
+
+ g_regex_match (r, reply, 0, &match_info);
+ if (g_match_info_matches (match_info))
+ operator = g_match_info_fetch (match_info, 3);
+
+ g_match_info_free (match_info);
+ g_regex_unref (r);
+ }
+
+ return operator;
+}
+
+static void
+reg_info_callback_wrapper (MMModem *modem,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMGsmModemRegInfoFn reg_info_fn;
+
+ reg_info_fn = (MMGsmModemRegInfoFn) mm_callback_info_get_data (info, "reg-info-callback");
+ reg_info_fn (MM_GSM_MODEM (modem),
+ GPOINTER_TO_UINT (mm_callback_info_get_data (info, "reg-info-status")),
+ (char *) mm_callback_info_get_data (info, "reg-info-oper-code"),
+ (char *) mm_callback_info_get_data (info, "reg-info-oper-name"),
+ error,
+ mm_callback_info_get_data (info, "reg-info-data"));
+}
+
+static void
+get_reg_name_done (MMSerial *serial, const char *reply, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ char *oper;
+
+ oper = parse_operator (reply);
+ if (oper)
+ mm_callback_info_set_data (info, "reg-info-oper-name", oper, g_free);
+ else
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Could not parse operator");
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_reg_code_done (MMSerial *serial, const char *reply, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ char *oper;
+
+ oper = parse_operator (reply);
+ if (oper) {
+ char *terminators = "\r\n";
+ guint id = 0;
+
+ mm_callback_info_set_data (info, "reg-info-oper-code", oper, g_free);
+
+ 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);
+
+ if (!id)
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Reading operator name failed.");
+ } else
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Could not parse operator");
+
+ if (info->error)
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_reg_info_status_done (MMModem *modem,
+ guint32 result,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ char *terminators = "\r\n";
+ guint id = 0;
+
+ if (!error) {
+ mm_callback_info_set_data (info, "reg-info-status", GUINT_TO_POINTER (result), NULL);
+ 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) {
+ if (error)
+ info->error = g_error_copy (error);
+ else
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s",
+ "Reading operator code failed.");
+
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
+get_registration_info (MMGsmModem *self,
+ MMGsmModemRegInfoFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (MM_MODEM (self), reg_info_callback_wrapper, NULL);
+ info->user_data = info;
+ mm_callback_info_set_data (info, "reg-info-callback", callback, NULL);
+ mm_callback_info_set_data (info, "reg-info-data", user_data, NULL);
+
+ get_registration_status (self, get_reg_info_status_done, info);
+}
+
static void
connect_done (MMSerial *serial,
int reply_index,
@@ -623,6 +798,7 @@ gsm_modem_init (MMGsmModem *gsm_modem_class)
{
gsm_modem_class->set_pin = set_pin;
gsm_modem_class->do_register = do_register;
+ gsm_modem_class->get_registration_info = get_registration_info;
gsm_modem_class->set_apn = set_apn;
gsm_modem_class->scan = scan;
gsm_modem_class->get_signal_quality = get_signal_quality;
diff --git a/src/mm-gsm-modem.c b/src/mm-gsm-modem.c
index 2972f7d5..f175354a 100644
--- a/src/mm-gsm-modem.c
+++ b/src/mm-gsm-modem.c
@@ -8,6 +8,7 @@
static void impl_gsm_modem_set_pin (MMGsmModem *modem, const char *pin, DBusGMethodInvocation *context);
static void impl_gsm_modem_register (MMGsmModem *modem, const char *network_id, DBusGMethodInvocation *context);
+static void impl_gsm_modem_get_reg_info (MMGsmModem *modem, DBusGMethodInvocation *context);
static void impl_gsm_modem_scan (MMGsmModem *modem, DBusGMethodInvocation *context);
static void impl_gsm_modem_set_apn (MMGsmModem *modem, const char *apn, DBusGMethodInvocation *context);
static void impl_gsm_modem_get_signal_quality (MMGsmModem *modem, DBusGMethodInvocation *context);
@@ -131,6 +132,65 @@ impl_gsm_modem_register (MMGsmModem *modem,
mm_gsm_modem_register (modem, id, async_call_done, context);
}
+static void
+reg_not_supported (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMGsmModemRegInfoFn callback = (MMGsmModemRegInfoFn) mm_callback_info_get_data (info, "reg-info-callback");
+
+ callback (MM_GSM_MODEM (modem), 0, NULL, NULL, error, mm_callback_info_get_data (info, "reg-info-data"));
+}
+
+void
+mm_gsm_modem_get_reg_info (MMGsmModem *self,
+ MMGsmModemRegInfoFn callback,
+ gpointer user_data)
+{
+ g_return_if_fail (MM_IS_GSM_MODEM (self));
+ g_return_if_fail (callback != NULL);
+
+ if (MM_GSM_MODEM_GET_INTERFACE (self)->get_registration_info)
+ MM_GSM_MODEM_GET_INTERFACE (self)->get_registration_info (self, callback, user_data);
+ else {
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (MM_MODEM (self), reg_not_supported, user_data);
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
+ "%s", "Operation not supported");
+
+ info->user_data = info;
+ mm_callback_info_set_data (info, "reg-info-callback", callback, NULL);
+ mm_callback_info_set_data (info, "reg-info-data", user_data, NULL);
+
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
+get_reg_info_done (MMGsmModem *modem,
+ NMGsmModemRegStatus status,
+ const char *oper_code,
+ const char *oper_name,
+ GError *error,
+ gpointer user_data)
+{
+ DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+
+ if (error)
+ dbus_g_method_return_error (context, error);
+ else {
+ dbus_g_method_return (context, status,
+ oper_code ? oper_code : "",
+ oper_name ? oper_name : "");
+ }
+}
+
+static void
+impl_gsm_modem_get_reg_info (MMGsmModem *modem, DBusGMethodInvocation *context)
+{
+ mm_gsm_modem_get_reg_info (modem, get_reg_info_done, context);
+}
+
void
mm_gsm_modem_scan (MMGsmModem *self,
MMGsmModemScanFn callback,
diff --git a/src/mm-gsm-modem.h b/src/mm-gsm-modem.h
index 45dde07f..1d1ab569 100644
--- a/src/mm-gsm-modem.h
+++ b/src/mm-gsm-modem.h
@@ -39,6 +39,15 @@ typedef enum {
MM_GSM_MODEM_BAND_LAST = MM_GSM_MODEM_BAND_U17IX
} MMGsmModemBand;
+typedef enum {
+ MM_GSM_MODEM_REG_STATUS_IDLE = 0,
+ MM_GSM_MODEM_REG_STATUS_HOME = 1,
+ MM_GSM_MODEM_REG_STATUS_SEARCHING = 2,
+ MM_GSM_MODEM_REG_STATUS_DENIED = 3,
+ MM_GSM_MODEM_REG_STATUS_UNKNOWN = 4,
+ MM_GSM_MODEM_REG_STATUS_ROAMING = 5
+} NMGsmModemRegStatus;
+
typedef struct _MMGsmModem MMGsmModem;
typedef void (*MMGsmModemScanFn) (MMGsmModem *modem,
@@ -46,6 +55,13 @@ typedef void (*MMGsmModemScanFn) (MMGsmModem *modem,
GError *error,
gpointer user_data);
+typedef void (*MMGsmModemRegInfoFn) (MMGsmModem *modem,
+ NMGsmModemRegStatus status,
+ const char *oper_code,
+ const char *oper_name,
+ GError *error,
+ gpointer user_data);
+
struct _MMGsmModem {
GTypeInterface g_iface;
@@ -61,6 +77,10 @@ struct _MMGsmModem {
MMModemFn callback,
gpointer user_data);
+ void (*get_registration_info) (MMGsmModem *self,
+ MMGsmModemRegInfoFn callback,
+ gpointer user_data);
+
void (*scan) (MMGsmModem *self,
MMGsmModemScanFn callback,
gpointer user_data);
@@ -112,6 +132,10 @@ void mm_gsm_modem_register (MMGsmModem *self,
MMModemFn callback,
gpointer user_data);
+void mm_gsm_modem_get_reg_info (MMGsmModem *self,
+ MMGsmModemRegInfoFn callback,
+ gpointer user_data);
+
void mm_gsm_modem_scan (MMGsmModem *self,
MMGsmModemScanFn callback,
gpointer user_data);