broadband-modem: implement Operator Code and Name loading
This commit is contained in:
@@ -65,6 +65,9 @@ struct _MMBroadbandModemPrivate {
|
|||||||
MMModemCapability modem_current_capabilities;
|
MMModemCapability modem_current_capabilities;
|
||||||
MMModem3gppRegistrationState modem_3gpp_registration_state;
|
MMModem3gppRegistrationState modem_3gpp_registration_state;
|
||||||
|
|
||||||
|
/* Modem helpers */
|
||||||
|
MMModemCharset current_charset;
|
||||||
|
|
||||||
/* 3GPP registration helpers */
|
/* 3GPP registration helpers */
|
||||||
GPtrArray *reg_regex;
|
GPtrArray *reg_regex;
|
||||||
MMModem3gppRegistrationState reg_cs;
|
MMModem3gppRegistrationState reg_cs;
|
||||||
@@ -827,9 +830,12 @@ current_charset_ready (MMBroadbandModem *self,
|
|||||||
MM_CORE_ERROR_FAILED,
|
MM_CORE_ERROR_FAILED,
|
||||||
"Modem failed to change character set to %s",
|
"Modem failed to change character set to %s",
|
||||||
mm_modem_charset_to_string (ctx->charset));
|
mm_modem_charset_to_string (ctx->charset));
|
||||||
else
|
else {
|
||||||
|
/* We'll keep track ourselves of the current charset */
|
||||||
|
self->priv->current_charset = current;
|
||||||
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_simple_async_result_complete (ctx->result);
|
g_simple_async_result_complete (ctx->result);
|
||||||
modem_charset_context_free (ctx);
|
modem_charset_context_free (ctx);
|
||||||
@@ -1162,6 +1168,98 @@ load_imei (MMIfaceModem3gpp *self,
|
|||||||
user_data);
|
user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Operator Code */
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
load_operator_code_finish (MMIfaceModem3gpp *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GVariant *result;
|
||||||
|
gchar *operator_code;
|
||||||
|
|
||||||
|
result = mm_at_sequence_finish (G_OBJECT (self), res, error);
|
||||||
|
if (!result)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
operator_code = mm_3gpp_parse_operator (g_variant_get_string (result, NULL),
|
||||||
|
MM_MODEM_CHARSET_UNKNOWN);
|
||||||
|
if (operator_code)
|
||||||
|
mm_dbg ("loaded Operator Code: %s", operator_code);
|
||||||
|
|
||||||
|
g_variant_unref (result);
|
||||||
|
return operator_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MMAtCommand operator_code_commands[] = {
|
||||||
|
{ "+COPS=3,2;+COPS?", 3, (MMAtResponseProcessor)common_parse_string_reply },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_operator_code (MMIfaceModem3gpp *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
mm_dbg ("loading Operator Code...");
|
||||||
|
mm_at_sequence (G_OBJECT (self),
|
||||||
|
mm_base_modem_get_port_primary (MM_BASE_MODEM (self)),
|
||||||
|
(MMAtCommand *)operator_code_commands,
|
||||||
|
NULL, /* response_processor_context */
|
||||||
|
FALSE,
|
||||||
|
"s",
|
||||||
|
NULL, /* TODO: cancellable */
|
||||||
|
callback,
|
||||||
|
user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Operator Name */
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
load_operator_name_finish (MMIfaceModem3gpp *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GVariant *result;
|
||||||
|
gchar *operator_name;
|
||||||
|
|
||||||
|
result = mm_at_sequence_finish (G_OBJECT (self), res, error);
|
||||||
|
if (!result)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
operator_name = mm_3gpp_parse_operator (g_variant_get_string (result, NULL),
|
||||||
|
MM_MODEM_CHARSET_UNKNOWN);
|
||||||
|
if (operator_name)
|
||||||
|
mm_dbg ("loaded Operator Name: %s", operator_name);
|
||||||
|
|
||||||
|
g_variant_unref (result);
|
||||||
|
return operator_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MMAtCommand operator_name_commands[] = {
|
||||||
|
{ "+COPS=3,0;+COPS?", 3, (MMAtResponseProcessor)common_parse_string_reply },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_operator_name (MMIfaceModem3gpp *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
mm_dbg ("loading Operator Name...");
|
||||||
|
mm_at_sequence (G_OBJECT (self),
|
||||||
|
mm_base_modem_get_port_primary (MM_BASE_MODEM (self)),
|
||||||
|
(MMAtCommand *)operator_name_commands,
|
||||||
|
NULL, /* response_processor_context */
|
||||||
|
FALSE,
|
||||||
|
"s",
|
||||||
|
NULL, /* TODO: cancellable */
|
||||||
|
callback,
|
||||||
|
user_data);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Unsolicited registration messages handling (3GPP) */
|
/* Unsolicited registration messages handling (3GPP) */
|
||||||
|
|
||||||
@@ -2302,6 +2400,7 @@ mm_broadband_modem_init (MMBroadbandModem *self)
|
|||||||
self->priv->reg_regex = mm_gsm_creg_regex_get (TRUE);
|
self->priv->reg_regex = mm_gsm_creg_regex_get (TRUE);
|
||||||
self->priv->reg_cs = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
|
self->priv->reg_cs = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
|
||||||
self->priv->reg_ps = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
|
self->priv->reg_ps = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
|
||||||
|
self->priv->current_charset = MM_MODEM_CHARSET_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2367,6 +2466,10 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
|
|||||||
{
|
{
|
||||||
iface->load_imei = load_imei;
|
iface->load_imei = load_imei;
|
||||||
iface->load_imei_finish = load_imei_finish;
|
iface->load_imei_finish = load_imei_finish;
|
||||||
|
iface->load_operator_code = load_operator_code;
|
||||||
|
iface->load_operator_code_finish = load_operator_code_finish;
|
||||||
|
iface->load_operator_name = load_operator_name;
|
||||||
|
iface->load_operator_name_finish = load_operator_name_finish;
|
||||||
|
|
||||||
iface->setup_unsolicited_registration = setup_unsolicited_registration;
|
iface->setup_unsolicited_registration = setup_unsolicited_registration;
|
||||||
iface->setup_unsolicited_registration_finish = setup_unsolicited_registration_finish;
|
iface->setup_unsolicited_registration_finish = setup_unsolicited_registration_finish;
|
||||||
|
@@ -855,6 +855,81 @@ mm_gsm_parse_cscs_support_response (const char *reply,
|
|||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
convert_operator_from_ucs2 (gchar **operator)
|
||||||
|
{
|
||||||
|
const gchar *p;
|
||||||
|
gchar *converted;
|
||||||
|
gsize len;
|
||||||
|
|
||||||
|
g_return_if_fail (operator != NULL);
|
||||||
|
g_return_if_fail (*operator != NULL);
|
||||||
|
|
||||||
|
p = *operator;
|
||||||
|
len = strlen (p);
|
||||||
|
|
||||||
|
/* Len needs to be a multiple of 4 for UCS2 */
|
||||||
|
if ((len < 4) || ((len % 4) != 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (*p) {
|
||||||
|
if (!isxdigit (*p++))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
converted = mm_modem_charset_hex_to_utf8 (*operator, MM_MODEM_CHARSET_UCS2);
|
||||||
|
if (converted) {
|
||||||
|
g_free (*operator);
|
||||||
|
*operator = converted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar *
|
||||||
|
mm_3gpp_parse_operator (const gchar *reply,
|
||||||
|
MMModemCharset cur_charset)
|
||||||
|
{
|
||||||
|
gchar *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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operator) {
|
||||||
|
/* Some modems (Option & HSO) return the operator name as a hexadecimal
|
||||||
|
* string of the bytes of the operator name as encoded by the current
|
||||||
|
* character set.
|
||||||
|
*/
|
||||||
|
if (cur_charset == MM_MODEM_CHARSET_UCS2)
|
||||||
|
convert_operator_from_ucs2 (&operator);
|
||||||
|
|
||||||
|
/* Ensure the operator name is valid UTF-8 so that we can send it
|
||||||
|
* through D-Bus and such.
|
||||||
|
*/
|
||||||
|
if (!g_utf8_validate (operator, -1, NULL)) {
|
||||||
|
g_free (operator);
|
||||||
|
operator = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
/* Map two letter facility codes into flag values. There are
|
/* Map two letter facility codes into flag values. There are
|
||||||
* many more facilities defined (for various flavors of call
|
* many more facilities defined (for various flavors of call
|
||||||
* barring); we only map the ones we care about. */
|
* barring); we only map the ones we care about. */
|
||||||
|
@@ -63,6 +63,9 @@ gboolean mm_gsm_parse_clck_test_response (const char *reply,
|
|||||||
gboolean mm_gsm_parse_clck_response (const char *reply,
|
gboolean mm_gsm_parse_clck_response (const char *reply,
|
||||||
gboolean *enabled);
|
gboolean *enabled);
|
||||||
|
|
||||||
|
gchar *mm_3gpp_parse_operator (const gchar *reply,
|
||||||
|
MMModemCharset cur_charset);
|
||||||
|
|
||||||
char *mm_gsm_get_facility_name (MMModemGsmFacility facility);
|
char *mm_gsm_get_facility_name (MMModemGsmFacility facility);
|
||||||
|
|
||||||
MMModemGsmAccessTech mm_gsm_string_to_access_tech (const char *string);
|
MMModemGsmAccessTech mm_gsm_string_to_access_tech (const char *string);
|
||||||
|
Reference in New Issue
Block a user