modem-helpers,mm-base-sim: Sim.SetPreferredNetworks AT implementation
Implement Sim.SetPreferredNetworks method by using the AT+CPOL command.
This commit is contained in:
committed by
Aleksander Morgado
parent
0919abaa2f
commit
8b1ae5afab
@@ -209,3 +209,12 @@ mm_sim_preferred_network_list_new_from_variant (GVariant *variant)
|
||||
|
||||
return network_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* mm_sim_preferred_network_list_copy: (skip)
|
||||
*/
|
||||
GList *
|
||||
mm_sim_preferred_network_list_copy (GList *preferred_network_list)
|
||||
{
|
||||
return g_list_copy_deep (preferred_network_list, (GCopyFunc) mm_sim_preferred_network_copy, NULL);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ MMSimPreferredNetwork * mm_sim_preferred_network_new_from_variant (
|
||||
GVariant *mm_sim_preferred_network_get_tuple (const MMSimPreferredNetwork *self);
|
||||
GVariant *mm_sim_preferred_network_list_get_variant (const GList *preferred_network_list);
|
||||
GList *mm_sim_preferred_network_list_new_from_variant (GVariant *variant);
|
||||
|
||||
GList *mm_sim_preferred_network_list_copy (GList *preferred_network_list);
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -964,6 +964,443 @@ handle_send_puk (MMBaseSim *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SET PREFERRED NETWORKS (Generic implementation) */
|
||||
|
||||
/* Setting preferred network list with AT+CPOL is a complicated procedure with
|
||||
* the following steps:
|
||||
* 1. Using AT+CPOL=? to get SIM capacity; the capacity is checked to ensure
|
||||
* that the list is not too large for the SIM card.
|
||||
* 2. Reading existing preferred networks from SIM with AT+CPOL?.
|
||||
* 3. Clearing existing networks with a series of AT+CPOL=<index> commands.
|
||||
* 4. Setting the new list by invoking AT+CPOL for each network.
|
||||
*
|
||||
* There are some complications with AT+CPOL handling which makes the work more
|
||||
* difficult for us. It seems that modems can only handle a certain exact number
|
||||
* of access technology identifiers - and this cannot be certainly known in
|
||||
* advance.
|
||||
*
|
||||
* If AT+CPOL? in step 2 returns anything, we can deduce the number of supported
|
||||
* identifiers there. But if there were no networks configured earlier, we must
|
||||
* start with a default based on modem capacity and work our way down from there
|
||||
* if the AT+CPOL command fails.
|
||||
*/
|
||||
|
||||
static void set_preferred_networks_set_next (MMBaseSim *self,
|
||||
GTask *task);
|
||||
static void set_preferred_networks_clear_next (MMBaseSim *self,
|
||||
GTask *task);
|
||||
|
||||
typedef struct {
|
||||
GList *set_list;
|
||||
/* AT+CPOL indices that must be cleared before setting the networks. */
|
||||
GArray *clear_index;
|
||||
/* Number of access technology identifiers we will set. */
|
||||
guint act_count;
|
||||
/* If TRUE, we know that act_count is something the modem can handle */
|
||||
gboolean act_count_verified;
|
||||
/* Index of preferred network currently being set (0 = first) */
|
||||
guint current_write_index;
|
||||
/* Operation error code */
|
||||
GError *error;
|
||||
} SetPreferredNetworksContext;
|
||||
|
||||
static void
|
||||
set_preferred_network_context_free (SetPreferredNetworksContext *ctx)
|
||||
{
|
||||
g_list_free_full (ctx->set_list, (GDestroyNotify) mm_sim_preferred_network_free);
|
||||
g_clear_error (&ctx->error);
|
||||
g_array_free (ctx->clear_index, TRUE);
|
||||
g_slice_free (SetPreferredNetworksContext, ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_preferred_networks_finish (MMBaseSim *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_old_preferred_networks (const gchar *response,
|
||||
SetPreferredNetworksContext *ctx)
|
||||
{
|
||||
gchar **entries;
|
||||
gchar **iter;
|
||||
|
||||
entries = g_strsplit_set (response, "\r\n", -1);
|
||||
for (iter = entries; iter && *iter; iter++) {
|
||||
guint index;
|
||||
guint act_count = 0;
|
||||
|
||||
g_strstrip (*iter);
|
||||
if (strlen (*iter) == 0)
|
||||
continue;
|
||||
|
||||
if (mm_sim_parse_cpol_query_response (*iter,
|
||||
&index,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
&act_count,
|
||||
NULL) && index > 0) {
|
||||
/* Remember how many access technologies the modem/SIM can take */
|
||||
if (!ctx->act_count_verified || act_count > ctx->act_count) {
|
||||
ctx->act_count = act_count;
|
||||
ctx->act_count_verified = TRUE;
|
||||
}
|
||||
|
||||
/* Store the index to be cleared */
|
||||
g_array_append_val (ctx->clear_index, index);
|
||||
}
|
||||
}
|
||||
g_strfreev (entries);
|
||||
}
|
||||
|
||||
/* This function is called only in error case, after reloading the network list from SIM. */
|
||||
static void
|
||||
set_preferred_networks_reload_ready (MMBaseSim *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GList *preferred_nets_list;
|
||||
SetPreferredNetworksContext *ctx;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
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);
|
||||
|
||||
/* Return the original error stored in our context */
|
||||
g_task_return_error (task, g_steal_pointer (&ctx->error));
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
set_preferred_networks_retry_command (MMBaseSim *self,
|
||||
SetPreferredNetworksContext *ctx)
|
||||
{
|
||||
/* If we haven't yet determined the number of access technology parameters supported by
|
||||
* the modem, try reducing the count if possible and retry with the reduced count.
|
||||
*/
|
||||
if (!ctx->act_count_verified && ctx->act_count > 0) {
|
||||
ctx->act_count--;
|
||||
mm_obj_dbg (self, "retrying operation with %u access technologies", ctx->act_count);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_preferred_network_reload_and_return_error (MMBaseSim *self,
|
||||
GTask *task,
|
||||
GError *error)
|
||||
{
|
||||
SetPreferredNetworksContext *ctx;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Reload the complete list from SIM card to ensure that the PreferredNetworks
|
||||
* property matches with whatever is actually on the SIM.
|
||||
*/
|
||||
if (MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks &&
|
||||
MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks_finish) {
|
||||
ctx->error = error;
|
||||
MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks (
|
||||
self,
|
||||
(GAsyncReadyCallback)set_preferred_networks_reload_ready,
|
||||
task);
|
||||
} else {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_preferred_networks_set_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseSim *self;
|
||||
SetPreferredNetworksContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
/* The command may fail; check if we can retry */
|
||||
if (error) {
|
||||
if (!set_preferred_networks_retry_command (self, ctx)) {
|
||||
/* Retrying not possible, failing... */
|
||||
mm_obj_warn (self, "failed to set preferred networks: '%s'", error->message);
|
||||
set_preferred_network_reload_and_return_error (self, task, error);
|
||||
return;
|
||||
}
|
||||
/* Retrying possible */
|
||||
g_clear_error (&error);
|
||||
} else {
|
||||
/* Last set operation was successful, so we know for sure how many access technologies
|
||||
* the modem can take.
|
||||
*/
|
||||
ctx->act_count_verified = TRUE;
|
||||
ctx->current_write_index++;
|
||||
}
|
||||
|
||||
set_preferred_networks_set_next (self, task);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_preferred_networks_check_support (MMBaseSim *self,
|
||||
SetPreferredNetworksContext *ctx,
|
||||
MMSimPreferredNetwork *network,
|
||||
GError **error)
|
||||
{
|
||||
MMModemAccessTechnology requested_act;
|
||||
MMModemAccessTechnology supported_act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
|
||||
|
||||
requested_act = mm_sim_preferred_network_get_access_technology (network);
|
||||
if (ctx->act_count >= 1)
|
||||
supported_act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM;
|
||||
if (ctx->act_count >= 2)
|
||||
supported_act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT;
|
||||
if (ctx->act_count >= 3)
|
||||
supported_act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
|
||||
if (ctx->act_count >= 4)
|
||||
supported_act |= MM_MODEM_ACCESS_TECHNOLOGY_LTE;
|
||||
if (ctx->act_count >= 5)
|
||||
supported_act |= MM_MODEM_ACCESS_TECHNOLOGY_5GNR;
|
||||
|
||||
if (requested_act & ~supported_act) {
|
||||
g_autofree gchar *act_string = NULL;
|
||||
|
||||
act_string = mm_modem_access_technology_build_string_from_mask (requested_act & ~supported_act);
|
||||
mm_obj_warn (self, "cannot set preferred net '%s'; access technology '%s' not supported by modem/SIM",
|
||||
mm_sim_preferred_network_get_operator_code (network), act_string);
|
||||
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
|
||||
"Access technology unsupported by modem or SIM");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Set next preferred network in queue */
|
||||
static void
|
||||
set_preferred_networks_set_next (MMBaseSim *self,
|
||||
GTask *task)
|
||||
{
|
||||
SetPreferredNetworksContext *ctx;
|
||||
g_autofree gchar *command = NULL;
|
||||
MMSimPreferredNetwork *current_network;
|
||||
const gchar *operator_code;
|
||||
MMModemAccessTechnology act;
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
current_network = (MMSimPreferredNetwork *) g_list_nth_data (ctx->set_list, ctx->current_write_index);
|
||||
if (current_network == NULL) {
|
||||
/* No more networks to set; we are done. */
|
||||
mm_obj_dbg (self, "setting preferred networks completed.");
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!set_preferred_networks_check_support (self, ctx, current_network, &error)) {
|
||||
set_preferred_network_reload_and_return_error (self, task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
operator_code = mm_sim_preferred_network_get_operator_code (current_network);
|
||||
act = mm_sim_preferred_network_get_access_technology (current_network);
|
||||
|
||||
/* Assemble the command to set the network */
|
||||
command = g_strdup_printf ("+CPOL=%u,2,\"%s\"%s%s%s%s%s", ctx->current_write_index + 1, operator_code,
|
||||
ctx->act_count == 0 ? "" : ((act & MM_MODEM_ACCESS_TECHNOLOGY_GSM) ? ",1" : ",0"),
|
||||
ctx->act_count <= 1 ? "" : ((act & MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT) ? ",1" : ",0"),
|
||||
ctx->act_count <= 2 ? "" : ((act & MM_MODEM_ACCESS_TECHNOLOGY_UMTS) ? ",1" : ",0"),
|
||||
ctx->act_count <= 3 ? "" : ((act & MM_MODEM_ACCESS_TECHNOLOGY_LTE) ? ",1" : ",0"),
|
||||
ctx->act_count <= 4 ? "" : ((act & MM_MODEM_ACCESS_TECHNOLOGY_5GNR) ? ",1" : ",0"));
|
||||
mm_base_modem_at_command (
|
||||
self->priv->modem,
|
||||
command,
|
||||
20,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)set_preferred_networks_set_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
set_preferred_networks_clear_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseSim *self;
|
||||
GError *error = NULL;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error) {
|
||||
mm_obj_warn (self, "couldn't clear preferred network entry: '%s'", error->message);
|
||||
set_preferred_network_reload_and_return_error (self, task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
set_preferred_networks_clear_next (self, task);
|
||||
}
|
||||
|
||||
/* Clear one of the networks in the clear list */
|
||||
static void
|
||||
set_preferred_networks_clear_next (MMBaseSim *self,
|
||||
GTask *task)
|
||||
{
|
||||
SetPreferredNetworksContext *ctx;
|
||||
g_autofree gchar *command = NULL;
|
||||
guint current_clear_index;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Clear from last index to first, since some modems (e.g. u-blox) may shift up items
|
||||
* following the cleared ones.
|
||||
*/
|
||||
if (ctx->clear_index->len > 0) {
|
||||
current_clear_index = g_array_index (ctx->clear_index, guint, ctx->clear_index->len - 1);
|
||||
g_array_remove_index (ctx->clear_index, ctx->clear_index->len - 1);
|
||||
command = g_strdup_printf ("+CPOL=%u", current_clear_index);
|
||||
mm_base_modem_at_command (
|
||||
self->priv->modem,
|
||||
command,
|
||||
20,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)set_preferred_networks_clear_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
/* All clear operations done; start setting new networks */
|
||||
set_preferred_networks_set_next (self, task);
|
||||
}
|
||||
|
||||
static void
|
||||
set_preferred_networks_load_existing_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseSim *self;
|
||||
GError *error = NULL;
|
||||
SetPreferredNetworksContext *ctx;
|
||||
const gchar *response;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error) {
|
||||
mm_obj_warn (self, "couldn't load existing preferred network list: '%s'", error->message);
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_old_preferred_networks (response, ctx);
|
||||
set_preferred_networks_clear_next (self, task);
|
||||
}
|
||||
|
||||
static void
|
||||
set_preferred_networks_query_sim_capacity_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseSim *self;
|
||||
GError *error = NULL;
|
||||
SetPreferredNetworksContext *ctx;
|
||||
const gchar *response;
|
||||
guint max_index;
|
||||
guint networks_count;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error) {
|
||||
mm_obj_warn (self, "couldn't query preferred network list capacity: '%s'", error->message);
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mm_sim_parse_cpol_test_response (response, NULL, &max_index, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Compare the number of networks to maximum index returned by AT+CPOL=? */
|
||||
networks_count = g_list_length (ctx->set_list);
|
||||
if (networks_count > max_index) {
|
||||
mm_obj_warn (self, "can't set %u preferred networks; SIM capacity: %u", networks_count, max_index);
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_TOO_MANY,
|
||||
"Too many networks; SIM capacity %u", max_index);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "setting %u preferred networks, SIM capacity: %u", networks_count, max_index);
|
||||
mm_base_modem_at_command (
|
||||
self->priv->modem,
|
||||
"+CPOL?",
|
||||
20,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)set_preferred_networks_load_existing_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
set_preferred_networks (MMBaseSim *self,
|
||||
GList *preferred_network_list,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
SetPreferredNetworksContext *ctx;
|
||||
|
||||
mm_obj_dbg (self, "set preferred networks: loading existing networks...");
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
ctx = g_slice_new0 (SetPreferredNetworksContext);
|
||||
ctx->set_list = mm_sim_preferred_network_list_copy (preferred_network_list);
|
||||
ctx->clear_index = g_array_new (FALSE, TRUE, sizeof (guint));
|
||||
if (mm_iface_modem_is_5g (MM_IFACE_MODEM (self->priv->modem)))
|
||||
ctx->act_count = 5;
|
||||
else if (mm_iface_modem_is_4g (MM_IFACE_MODEM (self->priv->modem)))
|
||||
ctx->act_count = 4;
|
||||
else if (mm_iface_modem_is_3g (MM_IFACE_MODEM (self->priv->modem)))
|
||||
ctx->act_count = 3;
|
||||
else if (mm_iface_modem_is_2g (MM_IFACE_MODEM (self->priv->modem)))
|
||||
ctx->act_count = 2;
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify) set_preferred_network_context_free);
|
||||
|
||||
/* Query SIM capacity first to find out how many preferred networks it can take */
|
||||
mm_base_modem_at_command (
|
||||
self->priv->modem,
|
||||
"+CPOL=?",
|
||||
20,
|
||||
FALSE, /* Do not cache, the response depends on SIM card properties */
|
||||
(GAsyncReadyCallback)set_preferred_networks_query_sim_capacity_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SET PREFERRED NETWORKS (DBus call handling) */
|
||||
|
||||
@@ -1269,12 +1706,14 @@ parse_preferred_networks (const gchar *response,
|
||||
continue;
|
||||
|
||||
if (mm_sim_parse_cpol_query_response (*iter,
|
||||
NULL,
|
||||
&operator_code,
|
||||
&gsm_act,
|
||||
&gsm_compact_act,
|
||||
&utran_act,
|
||||
&eutran_act,
|
||||
&ngran_act,
|
||||
NULL,
|
||||
error)) {
|
||||
preferred_network = mm_sim_preferred_network_new ();
|
||||
mm_sim_preferred_network_set_operator_code (preferred_network, operator_code);
|
||||
@@ -2317,6 +2756,8 @@ mm_base_sim_class_init (MMBaseSimClass *klass)
|
||||
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->set_preferred_networks = set_preferred_networks;
|
||||
klass->set_preferred_networks_finish = set_preferred_networks_finish;
|
||||
klass->send_pin = send_pin;
|
||||
klass->send_pin_finish = common_send_pin_puk_finish;
|
||||
klass->send_puk = send_puk;
|
||||
|
||||
+1
-1
@@ -161,7 +161,7 @@ struct _MMBaseSimClass {
|
||||
|
||||
/* Set preferred networks (async) */
|
||||
void (* set_preferred_networks) (MMBaseSim *self,
|
||||
const GList *preferred_network_list,
|
||||
GList *preferred_network_list,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean (* set_preferred_networks_finish) (MMBaseSim *self,
|
||||
|
||||
+73
-16
@@ -5131,12 +5131,14 @@ out:
|
||||
|
||||
gboolean
|
||||
mm_sim_parse_cpol_query_response (const gchar *response,
|
||||
guint *out_index,
|
||||
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,
|
||||
guint *out_act_count,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
@@ -5146,7 +5148,7 @@ mm_sim_parse_cpol_query_response (const gchar *response,
|
||||
guint act = 0;
|
||||
guint match_count;
|
||||
|
||||
r = g_regex_new ("\\+CPOL:\\s*\\d+,\\s*(\\d+),\\s*\"(\\d+)\""
|
||||
r = g_regex_new ("\\+CPOL:\\s*(\\d+),\\s*(\\d+),\\s*\"(\\d+)\""
|
||||
"(?:,\\s*(\\d+))?" /* GSM_AcTn */
|
||||
"(?:,\\s*(\\d+))?" /* GSM_Compact_AcTn */
|
||||
"(?:,\\s*(\\d+))?" /* UTRAN_AcTn */
|
||||
@@ -5165,10 +5167,10 @@ mm_sim_parse_cpol_query_response (const gchar *response,
|
||||
|
||||
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);
|
||||
g_assert (match_count >= 4);
|
||||
|
||||
if (!mm_get_uint_from_match_info (match_info, 1, &format) ||
|
||||
!(operator_code = mm_get_string_unquoted_from_match_info (match_info, 2))) {
|
||||
if (!mm_get_uint_from_match_info (match_info, 2, &format) ||
|
||||
!(operator_code = mm_get_string_unquoted_from_match_info (match_info, 3))) {
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
@@ -5184,29 +5186,84 @@ mm_sim_parse_cpol_query_response (const gchar *response,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (out_operator_code) {
|
||||
if (out_index)
|
||||
if (!mm_get_uint_from_match_info (match_info, 1, out_index)) {
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse +CPOL index: %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) &&
|
||||
*out_gsm_act = match_count >= 5 &&
|
||||
mm_get_uint_from_match_info (match_info, 4, &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) &&
|
||||
*out_gsm_compact_act = match_count >= 6 &&
|
||||
mm_get_uint_from_match_info (match_info, 5, &act) &&
|
||||
act != 0;
|
||||
if (out_utran_act)
|
||||
*out_utran_act = match_count >= 6 &&
|
||||
mm_get_uint_from_match_info (match_info, 5, &act) &&
|
||||
*out_utran_act = match_count >= 7 &&
|
||||
mm_get_uint_from_match_info (match_info, 6, &act) &&
|
||||
act != 0;
|
||||
if (out_eutran_act)
|
||||
*out_eutran_act = match_count >= 7 &&
|
||||
mm_get_uint_from_match_info (match_info, 6, &act) &&
|
||||
*out_eutran_act = match_count >= 8 &&
|
||||
mm_get_uint_from_match_info (match_info, 7, &act) &&
|
||||
act != 0;
|
||||
if (out_ngran_act)
|
||||
*out_ngran_act = match_count >= 8 &&
|
||||
mm_get_uint_from_match_info (match_info, 7, &act) &&
|
||||
*out_ngran_act = match_count >= 9 &&
|
||||
mm_get_uint_from_match_info (match_info, 8, &act) &&
|
||||
act != 0;
|
||||
/* number of access technologies (0...5) in modem response */
|
||||
if (out_act_count)
|
||||
*out_act_count = match_count - 4;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_sim_parse_cpol_test_response (const gchar *response,
|
||||
guint *out_min_index,
|
||||
guint *out_max_index,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
g_autoptr(GRegex) r = NULL;
|
||||
guint match_count;
|
||||
guint min_index;
|
||||
guint max_index;
|
||||
|
||||
r = g_regex_new ("\\+CPOL:\\s*\\((\\d+)\\s*-\\s*(\\d+)\\)",
|
||||
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, &min_index) ||
|
||||
!mm_get_uint_from_match_info (match_info, 2, &max_index)) {
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse indices in +CPOL=? reply: %s", response);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (out_min_index)
|
||||
*out_min_index = min_index;
|
||||
if (out_max_index)
|
||||
*out_max_index = max_index;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -526,14 +526,22 @@ gboolean mm_parse_supl_address (const gchar *supl,
|
||||
|
||||
/* +CPOL? response parser (for a single entry) - accepts only numeric operator format*/
|
||||
gboolean mm_sim_parse_cpol_query_response (const gchar *response,
|
||||
guint *out_index,
|
||||
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,
|
||||
guint *out_act_count,
|
||||
GError **error);
|
||||
|
||||
/* +CPOL=? response parser for getting supported min and max index */
|
||||
gboolean mm_sim_parse_cpol_test_response (const gchar *response,
|
||||
guint *out_min_index,
|
||||
guint *out_max_index,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Useful when clamp-ing an unsigned integer with implicit low limit set to 0,
|
||||
|
||||
Reference in New Issue
Block a user