Implement registration information retrieving for GSM modems.

This commit is contained in:
Tambet Ingo
2008-08-21 17:18:38 +03:00
parent 9afafdf46d
commit d6be2af93f
4 changed files with 349 additions and 33 deletions

View File

@@ -116,6 +116,29 @@
</arg>
</method>
<method name="GetRegistrationInfo">
<tp:docstring>
Get the registration status and the current operator (if registered).
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_gsm_modem_get_reg_info"/>
<arg name="status" type="u" direction="out" tp:type="MM_GSM_MODEM_REG_STATUS">
<tp:docstring>
The current network mode.
</tp:docstring>
</arg>
<arg name="operator_code" type="s" direction="out">
<tp:docstring>
The current operator code.
</tp:docstring>
</arg>
<arg name="operator_name" type="s" direction="out">
<tp:docstring>
The current operator name.
</tp:docstring>
</arg>
</method>
<signal name="SignalQuality">
<tp:docstring>
The signal quality changed.
@@ -239,5 +262,38 @@
</tp:enumvalue>
</tp:enum>
<tp:enum name="MM_GSM_MODEM_REG_STATUS" type="u">
<tp:enumvalue suffix="IDLE" value="0">
<tp:docstring>
Not registered, not searching for new operator to register.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="HOME" value="1">
<tp:docstring>
Registered on home network.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="SEARCHING" value="2">
<tp:docstring>
Not registered, searching for new operator to register with.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="DENIED" value="3">
<tp:docstring>
Registration denied.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="UNKNOWN" value="4">
<tp:docstring>
Unknown registration status.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="ROAMING" value="5">
<tp:docstring>
Registered on a roaming network.
</tp:docstring>
</tp:enumvalue>
</tp:enum>
</interface>
</node>

View File

@@ -248,43 +248,102 @@ register_manual (MMGsmModem *modem, const char *network_id, MMCallbackInfo *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);
mm_callback_info_set_data (info, "modem", NULL, NULL);
return FALSE;
}
static void
register_auto_done (MMSerial *serial,
int reply_index,
gpointer user_data)
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 (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_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;

View File

@@ -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,

View File

@@ -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);