libmm-glib,modem-helpers,mm-base-sim: implement Sim.PreferredNetworks
The ModemManager1.Sim.PreferredNetworks property contains the preferred networks (and access technologies, if available) configured to the SIM card. This commit implements preferred networks reading with AT+CPOL.
This commit is contained in:
committed by
Aleksander Morgado
parent
c7d366671f
commit
816beeffcb
@@ -1140,6 +1140,101 @@ load_emergency_numbers (MMBaseSim *self,
|
||||
g_task_new (self, NULL, callback, user_data));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Preferred networks */
|
||||
|
||||
static GList *
|
||||
parse_preferred_networks (const gchar *response,
|
||||
GError **error)
|
||||
{
|
||||
gchar **entries;
|
||||
gchar **iter;
|
||||
GList *result = NULL;
|
||||
|
||||
entries = g_strsplit_set (response, "\r\n", -1);
|
||||
for (iter = entries; iter && *iter; iter++) {
|
||||
gchar *operator_code = NULL;
|
||||
gboolean gsm_act;
|
||||
gboolean gsm_compact_act;
|
||||
gboolean utran_act;
|
||||
gboolean eutran_act;
|
||||
gboolean ngran_act;
|
||||
MMSimPreferredNetwork *preferred_network = NULL;
|
||||
MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
|
||||
|
||||
g_strstrip (*iter);
|
||||
if (strlen (*iter) == 0)
|
||||
continue;
|
||||
|
||||
if (mm_sim_parse_cpol_query_response (*iter,
|
||||
&operator_code,
|
||||
&gsm_act,
|
||||
&gsm_compact_act,
|
||||
&utran_act,
|
||||
&eutran_act,
|
||||
&ngran_act,
|
||||
error)) {
|
||||
preferred_network = mm_sim_preferred_network_new ();
|
||||
mm_sim_preferred_network_set_operator_code (preferred_network, operator_code);
|
||||
if (gsm_act)
|
||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM;
|
||||
if (gsm_compact_act)
|
||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT;
|
||||
if (utran_act)
|
||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
|
||||
if (eutran_act)
|
||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_LTE;
|
||||
if (ngran_act)
|
||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_5GNR;
|
||||
mm_sim_preferred_network_set_access_technology (preferred_network, act);
|
||||
result = g_list_append (result, preferred_network);
|
||||
} else
|
||||
break;
|
||||
g_free (operator_code);
|
||||
}
|
||||
g_strfreev (entries);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GList *
|
||||
load_preferred_networks_finish (MMBaseSim *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
gchar *result;
|
||||
GList *preferred_network_list;
|
||||
|
||||
result = g_task_propagate_pointer (G_TASK (res), error);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
preferred_network_list = parse_preferred_networks (result, error);
|
||||
mm_obj_dbg (self, "loaded %u preferred networks", g_list_length (preferred_network_list));
|
||||
|
||||
g_free (result);
|
||||
|
||||
return preferred_network_list;
|
||||
}
|
||||
|
||||
STR_REPLY_READY_FN (load_preferred_networks)
|
||||
|
||||
static void
|
||||
load_preferred_networks (MMBaseSim *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
mm_obj_dbg (self, "loading preferred networks...");
|
||||
|
||||
mm_base_modem_at_command (
|
||||
self->priv->modem,
|
||||
"+CPOL?",
|
||||
20,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)load_preferred_networks_command_ready,
|
||||
g_task_new (self, NULL, callback, user_data));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ICCID */
|
||||
|
||||
@@ -1525,6 +1620,7 @@ typedef enum {
|
||||
INITIALIZATION_STEP_OPERATOR_ID,
|
||||
INITIALIZATION_STEP_OPERATOR_NAME,
|
||||
INITIALIZATION_STEP_EMERGENCY_NUMBERS,
|
||||
INITIALIZATION_STEP_PREFERRED_NETWORKS,
|
||||
INITIALIZATION_STEP_LAST
|
||||
} InitializationStep;
|
||||
|
||||
@@ -1623,6 +1719,31 @@ init_load_emergency_numbers_ready (MMBaseSim *self,
|
||||
interface_initialization_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
init_load_preferred_networks_ready (MMBaseSim *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
InitAsyncContext *ctx;
|
||||
GError *error = NULL;
|
||||
GList *preferred_nets_list;
|
||||
|
||||
preferred_nets_list = MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks_finish (self, res, &error);
|
||||
if (error) {
|
||||
mm_obj_warn (self, "couldn't load list of preferred networks: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
mm_gdbus_sim_set_preferred_networks (MM_GDBUS_SIM (self),
|
||||
mm_sim_preferred_network_list_get_variant (preferred_nets_list));
|
||||
g_list_free_full (preferred_nets_list, (GDestroyNotify) mm_sim_preferred_network_free);
|
||||
|
||||
/* Go on to next step */
|
||||
ctx = g_task_get_task_data (task);
|
||||
ctx->step++;
|
||||
interface_initialization_step (task);
|
||||
}
|
||||
|
||||
#undef STR_REPLY_READY_FN
|
||||
#define STR_REPLY_READY_FN(NAME,DISPLAY) \
|
||||
static void \
|
||||
@@ -1798,6 +1919,18 @@ interface_initialization_step (GTask *task)
|
||||
ctx->step++;
|
||||
/* Fall through */
|
||||
|
||||
case INITIALIZATION_STEP_PREFERRED_NETWORKS:
|
||||
if (MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks &&
|
||||
MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks_finish) {
|
||||
MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks (
|
||||
self,
|
||||
(GAsyncReadyCallback)init_load_preferred_networks_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
ctx->step++;
|
||||
/* Fall through */
|
||||
|
||||
case INITIALIZATION_STEP_LAST:
|
||||
/* We are done without errors! */
|
||||
g_task_return_boolean (task, TRUE);
|
||||
@@ -2051,6 +2184,8 @@ mm_base_sim_class_init (MMBaseSimClass *klass)
|
||||
klass->load_operator_name_finish = load_operator_name_finish;
|
||||
klass->load_emergency_numbers = load_emergency_numbers;
|
||||
klass->load_emergency_numbers_finish = load_emergency_numbers_finish;
|
||||
klass->load_preferred_networks = load_preferred_networks;
|
||||
klass->load_preferred_networks_finish = load_preferred_networks_finish;
|
||||
klass->send_pin = send_pin;
|
||||
klass->send_pin_finish = common_send_pin_puk_finish;
|
||||
klass->send_puk = send_puk;
|
||||
|
||||
@@ -150,6 +150,14 @@ struct _MMBaseSimClass {
|
||||
/* Signals */
|
||||
void (* pin_lock_enabled) (MMBaseSim *self,
|
||||
gboolean enabled);
|
||||
|
||||
/* Load preferred networks (async) */
|
||||
void (* load_preferred_networks) (MMBaseSim *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GList * (* load_preferred_networks_finish) (MMBaseSim *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
};
|
||||
|
||||
GType mm_base_sim_get_type (void);
|
||||
|
||||
@@ -5126,3 +5126,87 @@ out:
|
||||
g_strfreev (split);
|
||||
return valid;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean
|
||||
mm_sim_parse_cpol_query_response (const gchar *response,
|
||||
gchar **out_operator_code,
|
||||
gboolean *out_gsm_act,
|
||||
gboolean *out_gsm_compact_act,
|
||||
gboolean *out_utran_act,
|
||||
gboolean *out_eutran_act,
|
||||
gboolean *out_ngran_act,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
g_autoptr(GRegex) r = NULL;
|
||||
g_autofree gchar *operator_code = NULL;
|
||||
guint format = 0;
|
||||
guint act = 0;
|
||||
guint match_count;
|
||||
|
||||
r = g_regex_new ("\\+CPOL:\\s*\\d+,\\s*(\\d+),\\s*\"(\\d+)\""
|
||||
"(?:,\\s*(\\d+))?" /* GSM_AcTn */
|
||||
"(?:,\\s*(\\d+))?" /* GSM_Compact_AcTn */
|
||||
"(?:,\\s*(\\d+))?" /* UTRAN_AcTn */
|
||||
"(?:,\\s*(\\d+))?" /* E-UTRAN_AcTn */
|
||||
"(?:,\\s*(\\d+))?", /* NG-RAN_AcTn */
|
||||
G_REGEX_RAW, 0, NULL);
|
||||
g_regex_match (r, response, 0, &match_info);
|
||||
|
||||
if (!g_match_info_matches (match_info)) {
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse +CPOL reply: %s", response);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
match_count = g_match_info_get_match_count (match_info);
|
||||
/* Remember that g_match_info_get_match_count() includes match #0 */
|
||||
g_assert (match_count >= 3);
|
||||
|
||||
if (!mm_get_uint_from_match_info (match_info, 1, &format) ||
|
||||
!(operator_code = mm_get_string_unquoted_from_match_info (match_info, 2))) {
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse +CPOL reply parameters: %s", response);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (format != 2) {
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"+CPOL reply not using numeric operator code: %s", response);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (out_operator_code) {
|
||||
*out_operator_code = g_steal_pointer (&operator_code);
|
||||
}
|
||||
if (out_gsm_act)
|
||||
*out_gsm_act = match_count >= 4 &&
|
||||
mm_get_uint_from_match_info (match_info, 3, &act) &&
|
||||
act != 0;
|
||||
if (out_gsm_compact_act)
|
||||
*out_gsm_compact_act = match_count >= 5 &&
|
||||
mm_get_uint_from_match_info (match_info, 4, &act) &&
|
||||
act != 0;
|
||||
if (out_utran_act)
|
||||
*out_utran_act = match_count >= 6 &&
|
||||
mm_get_uint_from_match_info (match_info, 5, &act) &&
|
||||
act != 0;
|
||||
if (out_eutran_act)
|
||||
*out_eutran_act = match_count >= 7 &&
|
||||
mm_get_uint_from_match_info (match_info, 6, &act) &&
|
||||
act != 0;
|
||||
if (out_ngran_act)
|
||||
*out_ngran_act = match_count >= 8 &&
|
||||
mm_get_uint_from_match_info (match_info, 7, &act) &&
|
||||
act != 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -520,6 +520,20 @@ gboolean mm_parse_supl_address (const gchar *supl,
|
||||
guint16 *out_port,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SIM specific helpers and utilities */
|
||||
/*****************************************************************************/
|
||||
|
||||
/* +CPOL? response parser (for a single entry) - accepts only numeric operator format*/
|
||||
gboolean mm_sim_parse_cpol_query_response (const gchar *response,
|
||||
gchar **out_operator_code,
|
||||
gboolean *out_gsm_act,
|
||||
gboolean *out_gsm_compact_act,
|
||||
gboolean *out_utran_act,
|
||||
gboolean *out_eutran_act,
|
||||
gboolean *out_ngran_act,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Useful when clamp-ing an unsigned integer with implicit low limit set to 0,
|
||||
|
||||
Reference in New Issue
Block a user