huawei: refactor mode and band related methods

Refactor the loading/setting of supported/current modes/bands,
mostly to enable LTE support via ^SYSCFGEX.

This unfortunately requires many changes at once, as these methods
use the same AT commands and their fallbacks.
This commit is contained in:
Oliver Kästner
2024-04-11 19:36:01 +00:00
parent 338b299fe2
commit 469d310397
4 changed files with 852 additions and 342 deletions
+431 -168
View File
@@ -149,6 +149,9 @@ struct _MMBroadbandModemHuaweiPrivate {
GArray *syscfgex_supported_modes;
GArray *prefmode_supported_modes;
guint64 supported_gsm_umts_bands;
guint64 supported_lte_bands;
DetailedSignal detailed_signal;
/* Voice call audio related properties */
@@ -735,32 +738,82 @@ modem_after_sim_unlock (MMIfaceModem *self,
typedef struct {
MMModemBand mm;
guint32 huawei;
guint64 huawei;
} BandTable;
static BandTable bands[] = {
static BandTable gsm_umts_bands[] = {
/* Sort 3G first since it's preferred */
{ MM_MODEM_BAND_UTRAN_1, 0x00400000 },
{ MM_MODEM_BAND_UTRAN_2, 0x00800000 },
{ MM_MODEM_BAND_UTRAN_5, 0x04000000 },
{ MM_MODEM_BAND_UTRAN_8, 0x00020000 },
{ MM_MODEM_BAND_UTRAN_1, 0x0000000000400000UL },
{ MM_MODEM_BAND_UTRAN_2, 0x0000000000800000UL },
{ MM_MODEM_BAND_UTRAN_3, 0x0000000001000000UL },
{ MM_MODEM_BAND_UTRAN_4, 0x0000000002000000UL },
{ MM_MODEM_BAND_UTRAN_5, 0x0000000004000000UL },
{ MM_MODEM_BAND_UTRAN_6, 0x0000000008000000UL },
{ MM_MODEM_BAND_UTRAN_8, 0x0002000000000000UL },
{ MM_MODEM_BAND_UTRAN_9, 0x0004000000000000UL },
{ MM_MODEM_BAND_UTRAN_19, 0x1000000000000000UL },
/* 2G second */
{ MM_MODEM_BAND_G850, 0x00080000 },
{ MM_MODEM_BAND_DCS, 0x00000080 },
{ MM_MODEM_BAND_EGSM, 0x00000100 },
{ MM_MODEM_BAND_PCS, 0x00200000 }
{ MM_MODEM_BAND_G850, 0x00080000UL },
{ MM_MODEM_BAND_DCS, 0x00000080UL },
{ MM_MODEM_BAND_EGSM, 0x00000100UL },
{ MM_MODEM_BAND_PCS, 0x00200000UL }
};
/* LTE band values reported by ^SYSCFGEX overlap with GSM/UMTS band values */
#define LTE_BAND_TO_HUAWEI(band) (G_GUINT64_CONSTANT(1) << ((band) - 1))
static BandTable lte_bands[] = {
{ MM_MODEM_BAND_EUTRAN_1, LTE_BAND_TO_HUAWEI(1) },
{ MM_MODEM_BAND_EUTRAN_2, LTE_BAND_TO_HUAWEI(2) },
{ MM_MODEM_BAND_EUTRAN_3, LTE_BAND_TO_HUAWEI(3) },
{ MM_MODEM_BAND_EUTRAN_4, LTE_BAND_TO_HUAWEI(4) },
{ MM_MODEM_BAND_EUTRAN_5, LTE_BAND_TO_HUAWEI(5) },
{ MM_MODEM_BAND_EUTRAN_6, LTE_BAND_TO_HUAWEI(6) },
{ MM_MODEM_BAND_EUTRAN_7, LTE_BAND_TO_HUAWEI(7) },
{ MM_MODEM_BAND_EUTRAN_8, LTE_BAND_TO_HUAWEI(8) },
{ MM_MODEM_BAND_EUTRAN_9, LTE_BAND_TO_HUAWEI(9) },
{ MM_MODEM_BAND_EUTRAN_10, LTE_BAND_TO_HUAWEI(10) },
{ MM_MODEM_BAND_EUTRAN_11, LTE_BAND_TO_HUAWEI(11) },
{ MM_MODEM_BAND_EUTRAN_12, LTE_BAND_TO_HUAWEI(12) },
{ MM_MODEM_BAND_EUTRAN_13, LTE_BAND_TO_HUAWEI(13) },
{ MM_MODEM_BAND_EUTRAN_14, LTE_BAND_TO_HUAWEI(14) },
{ MM_MODEM_BAND_EUTRAN_17, LTE_BAND_TO_HUAWEI(17) },
{ MM_MODEM_BAND_EUTRAN_18, LTE_BAND_TO_HUAWEI(18) },
{ MM_MODEM_BAND_EUTRAN_19, LTE_BAND_TO_HUAWEI(19) },
{ MM_MODEM_BAND_EUTRAN_20, LTE_BAND_TO_HUAWEI(20) },
{ MM_MODEM_BAND_EUTRAN_21, LTE_BAND_TO_HUAWEI(21) },
{ MM_MODEM_BAND_EUTRAN_25, LTE_BAND_TO_HUAWEI(25) },
{ MM_MODEM_BAND_EUTRAN_26, LTE_BAND_TO_HUAWEI(26) },
{ MM_MODEM_BAND_EUTRAN_28, LTE_BAND_TO_HUAWEI(28) },
{ MM_MODEM_BAND_EUTRAN_33, LTE_BAND_TO_HUAWEI(33) },
{ MM_MODEM_BAND_EUTRAN_34, LTE_BAND_TO_HUAWEI(34) },
{ MM_MODEM_BAND_EUTRAN_35, LTE_BAND_TO_HUAWEI(35) },
{ MM_MODEM_BAND_EUTRAN_36, LTE_BAND_TO_HUAWEI(36) },
{ MM_MODEM_BAND_EUTRAN_37, LTE_BAND_TO_HUAWEI(37) },
{ MM_MODEM_BAND_EUTRAN_38, LTE_BAND_TO_HUAWEI(38) },
{ MM_MODEM_BAND_EUTRAN_39, LTE_BAND_TO_HUAWEI(39) },
{ MM_MODEM_BAND_EUTRAN_40, LTE_BAND_TO_HUAWEI(40) },
{ MM_MODEM_BAND_EUTRAN_41, LTE_BAND_TO_HUAWEI(41) },
{ MM_MODEM_BAND_EUTRAN_42, LTE_BAND_TO_HUAWEI(42) },
{ MM_MODEM_BAND_EUTRAN_43, LTE_BAND_TO_HUAWEI(43) },
};
static gboolean
bands_array_to_huawei (GArray *bands_array,
guint32 *out_huawei)
bands_array_to_huawei (BandTable *band_table,
guint band_table_len,
GArray *bands_array,
guint64 *out_huawei)
{
guint i;
/* Treat ANY as a special case: All huawei flags enabled */
if (bands_array->len == 1 &&
g_array_index (bands_array, MMModemBand, 0) == MM_MODEM_BAND_ANY) {
*out_huawei = 0x3FFFFFFF;
/* This is only correct for 2G/3G bands when using ^SYSCFG(EX).
* For setting LTE bands with ^SYSCFGEX, the
* MM_HUAWEI_SYSCFGEX_BAND_ANY_LTE mask has to be used
*/
*out_huawei = MM_HUAWEI_SYSCFG_BAND_ANY;
return TRUE;
}
@@ -768,9 +821,9 @@ bands_array_to_huawei (GArray *bands_array,
for (i = 0; i < bands_array->len; i++) {
guint j;
for (j = 0; j < G_N_ELEMENTS (bands); j++) {
if (g_array_index (bands_array, MMModemBand, i) == bands[j].mm)
*out_huawei |= bands[j].huawei;
for (j = 0; j < band_table_len; j++) {
if (g_array_index (bands_array, MMModemBand, i) == band_table[j].mm)
*out_huawei |= band_table[j].huawei;
}
}
@@ -778,18 +831,33 @@ bands_array_to_huawei (GArray *bands_array,
}
static gboolean
huawei_to_bands_array (guint32 huawei,
GArray **bands_array,
GError **error)
gsm_umts_bands_array_to_huawei (GArray *bands_array,
guint32 *out_huawei)
{
gboolean success;
guint64 huawei64;
success = bands_array_to_huawei (gsm_umts_bands, G_N_ELEMENTS (gsm_umts_bands), bands_array, &huawei64);
*out_huawei = (guint32) huawei64;
return success;
}
static gboolean
huawei_to_bands_array (BandTable *band_table,
guint band_table_len,
guint64 huawei,
GArray **bands_array,
GError **error)
{
guint i;
*bands_array = NULL;
for (i = 0; i < G_N_ELEMENTS (bands); i++) {
if (huawei & bands[i].huawei) {
for (i = 0; i < band_table_len; i++) {
if (huawei & band_table[i].huawei) {
if (G_UNLIKELY (!*bands_array))
*bands_array = g_array_new (FALSE, FALSE, sizeof (MMModemBand));
g_array_append_val (*bands_array, bands[i].mm);
g_array_append_val (*bands_array, band_table[i].mm);
}
}
@@ -797,7 +865,7 @@ huawei_to_bands_array (guint32 huawei,
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Couldn't build bands array from '%u'",
"Couldn't build bands array from '%lu'",
huawei);
return FALSE;
}
@@ -806,34 +874,19 @@ huawei_to_bands_array (guint32 huawei,
}
static gboolean
parse_syscfg (const gchar *response,
GArray **bands_array,
GError **error)
gsm_umts_huawei_to_bands_array (guint64 huawei,
GArray **bands_array,
GError **error)
{
gint mode;
gint acquisition_order;
guint32 band;
gint roaming;
gint srv_domain;
return huawei_to_bands_array (gsm_umts_bands, G_N_ELEMENTS (gsm_umts_bands), huawei, bands_array, error);
}
if (!response ||
strncmp (response, "^SYSCFG:", 8) != 0 ||
!sscanf (response + 8, "%d,%d,%x,%d,%d", &mode, &acquisition_order, &band, &roaming, &srv_domain)) {
/* Dump error to upper layer */
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Unexpected SYSCFG response: '%s'",
response);
return FALSE;
}
/* Band */
if (bands_array &&
!huawei_to_bands_array (band, bands_array, error))
return FALSE;
return TRUE;
static gboolean
lte_huawei_to_bands_array (guint64 huawei,
GArray **bands_array,
GError **error)
{
return huawei_to_bands_array (lte_bands, G_N_ELEMENTS (lte_bands), huawei, bands_array, error);
}
/*****************************************************************************/
@@ -844,30 +897,115 @@ load_current_bands_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
const gchar *response;
GArray *bands_array = NULL;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
if (!response)
return NULL;
if (!parse_syscfg (response, &bands_array, error))
return NULL;
return bands_array;
return g_task_propagate_pointer (G_TASK (res), error);
}
static void
load_current_bands (MMIfaceModem *self,
syscfg_load_current_bands_ready (MMBroadbandModemHuawei *self,
GAsyncResult *res,
GTask *task)
{
const gchar *response;
GError *error = NULL;
GArray *bands_array = NULL;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (response) {
guint64 huawei_bands;
if (mm_huawei_parse_syscfg_response (response, NULL, &huawei_bands, &error)) {
if (huawei_bands == MM_HUAWEI_SYSCFG_BAND_ANY)
huawei_bands = self->priv->supported_gsm_umts_bands;
gsm_umts_huawei_to_bands_array (huawei_bands, &bands_array, &error);
}
}
if (error)
g_task_return_error (task, error);
else
g_task_return_pointer (task, bands_array, (GDestroyNotify)g_array_unref);
g_object_unref (task);
}
static void
syscfgex_load_current_bands_ready (MMBroadbandModemHuawei *self,
GAsyncResult *res,
GTask *task)
{
const gchar *response;
GError *error = NULL;
g_autoptr(GArray) bands_array = NULL;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (response) {
guint64 huawei_gsm_umts_bands;
guint64 huawei_lte_bands;
GArray *bands_temp;
if (!mm_huawei_parse_syscfgex_response (response, NULL, &huawei_gsm_umts_bands, &huawei_lte_bands, &error)) {
g_task_return_error (task, error);
g_object_unref (task);
return;
}
bands_array = g_array_new (FALSE, FALSE, sizeof (MMModemBand));
/* handle special "all bands" values */
if (huawei_gsm_umts_bands == MM_HUAWEI_SYSCFG_BAND_ANY)
huawei_gsm_umts_bands = self->priv->supported_gsm_umts_bands;
if (huawei_lte_bands == MM_HUAWEI_SYSCFGEX_BAND_ANY_LTE)
huawei_lte_bands = self->priv->supported_lte_bands;
if (gsm_umts_huawei_to_bands_array (huawei_gsm_umts_bands, &bands_temp, &error)) {
g_array_append_vals (bands_array, bands_temp->data, bands_temp->len);
g_array_free (bands_temp, TRUE);
if (lte_huawei_to_bands_array (huawei_lte_bands, &bands_temp, &error)) {
g_array_append_vals (bands_array, bands_temp->data, bands_temp->len);
g_array_free (bands_temp, TRUE);
}
}
}
if (error)
g_task_return_error (task, error);
else
g_task_return_pointer (task, g_steal_pointer (&bands_array), (GDestroyNotify)g_array_unref);
g_object_unref (task);
}
static void
load_current_bands (MMIfaceModem *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
GTask *task;
task = g_task_new (self, NULL, callback, user_data);
if (self->priv->syscfgex_support == FEATURE_SUPPORTED) {
mm_base_modem_at_command (
MM_BASE_MODEM (self),
"^SYSCFGEX?",
3,
FALSE,
(GAsyncReadyCallback)syscfgex_load_current_bands_ready,
task);
return;
}
/* fallback */
mm_base_modem_at_command (MM_BASE_MODEM (self),
"^SYSCFG?",
3,
FALSE,
callback,
user_data);
(GAsyncReadyCallback)syscfg_load_current_bands_ready,
task);
}
/*****************************************************************************/
@@ -913,7 +1051,7 @@ set_current_bands (MMIfaceModem *self,
bands_string = mm_common_build_bands_string ((MMModemBand *)(gpointer)bands_array->data,
bands_array->len);
if (!bands_array_to_huawei (bands_array, &huawei_band)) {
if (!gsm_umts_bands_array_to_huawei (bands_array, &huawei_band)) {
g_task_return_new_error (task,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
@@ -939,50 +1077,60 @@ set_current_bands (MMIfaceModem *self,
/* Load supported modes (Modem interface) */
static GArray *
load_supported_modes_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
load_supported_modes_finish (MMIfaceModem *_self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_pointer (G_TASK (res), error);
}
MMBroadbandModemHuawei *self;
self = MM_BROADBAND_MODEM_HUAWEI (_self);
static void
syscfg_test_ready (MMBroadbandModemHuawei *self,
GAsyncResult *res,
GTask *task)
{
const gchar *response;
GError *error = NULL;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (response) {
/* There are 2G+3G Huawei modems out there which support mode switching with
* AT^SYSCFG, but fail to provide a valid response for AT^SYSCFG=? (they just
* return an empty string). So handle that case by providing a default response
* string to get parsed. Ugly, ugly, blame Huawei.
*/
if (response[0])
self->priv->syscfg_supported_modes = mm_huawei_parse_syscfg_test (response, self, &error);
else {
self->priv->syscfg_supported_modes = mm_huawei_parse_syscfg_test (MM_HUAWEI_DEFAULT_SYSCFG_FMT, self, NULL);
g_assert (self->priv->syscfg_supported_modes != NULL);
}
if (!g_task_propagate_boolean (G_TASK (res), error)) {
return NULL;
}
if (self->priv->syscfg_supported_modes) {
/* check SYSCFGEX first */
if (self->priv->syscfgex_supported_modes) {
MMModemModeCombination mode;
guint i;
GArray *combinations;
GArray *supported_modes;
GArray *combinations;
guint i;
supported_modes = self->priv->syscfgex_supported_modes;
/* Build list of combinations */
combinations = g_array_sized_new (FALSE,
FALSE,
sizeof (MMModemModeCombination),
self->priv->syscfg_supported_modes->len);
for (i = 0; i < self->priv->syscfg_supported_modes->len; i++) {
supported_modes->len);
for (i = 0; i < supported_modes->len; i++) {
MMHuaweiSyscfgexCombination *huawei_mode;
huawei_mode = &g_array_index (supported_modes, MMHuaweiSyscfgexCombination, i);
mode.allowed = huawei_mode->allowed;
mode.preferred = huawei_mode->preferred;
g_array_append_val (combinations, mode);
}
return combinations;
}
if (self->priv->syscfg_supported_modes) {
MMModemModeCombination mode;
GArray *supported_modes;
GArray *combinations;
guint i;
supported_modes = self->priv->syscfg_supported_modes;
/* Build list of combinations */
combinations = g_array_sized_new (FALSE,
FALSE,
sizeof (MMModemModeCombination),
supported_modes->len);
for (i = 0; i < supported_modes->len; i++) {
MMHuaweiSyscfgCombination *huawei_mode;
huawei_mode = &g_array_index (self->priv->syscfg_supported_modes,
huawei_mode = &g_array_index (supported_modes,
MMHuaweiSyscfgCombination,
i);
mode.allowed = huawei_mode->allowed;
@@ -990,11 +1138,29 @@ syscfg_test_ready (MMBroadbandModemHuawei *self,
g_array_append_val (combinations, mode);
}
self->priv->syscfg_support = FEATURE_SUPPORTED;
g_task_return_pointer (task,
combinations,
(GDestroyNotify)g_array_unref);
} else {
return combinations;
}
if (self->priv->prefmode_supported_modes) {
return g_array_ref (self->priv->prefmode_supported_modes);
}
g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "No method found to retrieve supported modes");
return NULL;
}
static void
syscfg_test_ready (MMBroadbandModemHuawei *self,
GAsyncResult *res,
GTask *task)
{
const gchar *response;
GError *error = NULL;
GArray *supported_modes = NULL;
guint64 supported_gsm_umts_bands = 0;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (!response) {
mm_obj_dbg (self, "error while checking ^SYSCFG format: %s", error->message);
/* If SIM-PIN error, don't mark as feature unsupported; we'll retry later */
if (!g_error_matches (error,
@@ -1002,49 +1168,67 @@ syscfg_test_ready (MMBroadbandModemHuawei *self,
MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN))
self->priv->syscfg_support = FEATURE_NOT_SUPPORTED;
g_task_return_error (task, error);
g_object_unref (task);
return;
}
/* There are 2G+3G Huawei modems out there which support mode switching with
* AT^SYSCFG, but fail to provide a valid response for AT^SYSCFG=? (they just
* return an empty string). So handle that case by providing a default response
* string to get parsed. Ugly, ugly, blame Huawei.
*/
if (!response[0])
response = MM_HUAWEI_DEFAULT_SYSCFG_FMT;
if (!mm_huawei_parse_syscfg_test (response, &supported_modes, &supported_gsm_umts_bands, &error)) {
self->priv->syscfg_support = FEATURE_NOT_SUPPORTED;
mm_obj_dbg (self, "failed to parse ^SYSCFG test response: %s", error->message);
g_task_return_error (task, error);
g_object_unref (task);
return;
}
self->priv->syscfg_support = FEATURE_SUPPORTED;
self->priv->syscfg_supported_modes = supported_modes;
self->priv->supported_gsm_umts_bands = supported_gsm_umts_bands;
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
syscfgex_test_ready (MMBroadbandModemHuawei *self,
GAsyncResult *res,
GTask *task)
GAsyncResult *res,
GTask *task)
{
const gchar *response;
GError *error = NULL;
GError *error = NULL;
GArray *supported_modes = NULL;
guint64 supported_gsm_umts_bands;
guint64 supported_lte_bands;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (response)
self->priv->syscfgex_supported_modes = mm_huawei_parse_syscfgex_test (response, &error);
if (response) {
if (!mm_huawei_parse_syscfgex_test (response,
&supported_modes,
&supported_gsm_umts_bands,
&supported_lte_bands,
&error)) {
self->priv->syscfgex_support = FEATURE_NOT_SUPPORTED;
if (self->priv->syscfgex_supported_modes) {
MMModemModeCombination mode;
guint i;
GArray *combinations;
/* Build list of combinations */
combinations = g_array_sized_new (FALSE,
FALSE,
sizeof (MMModemModeCombination),
self->priv->syscfgex_supported_modes->len);
for (i = 0; i < self->priv->syscfgex_supported_modes->len; i++) {
MMHuaweiSyscfgexCombination *huawei_mode;
huawei_mode = &g_array_index (self->priv->syscfgex_supported_modes,
MMHuaweiSyscfgexCombination,
i);
mode.allowed = huawei_mode->allowed;
mode.preferred = huawei_mode->preferred;
g_array_append_val (combinations, mode);
mm_obj_dbg (self, "failed to parse ^SYSCFGEX test response: %s", error->message);
g_task_return_error (task, error);
g_object_unref (task);
return;
}
self->priv->syscfgex_support = FEATURE_SUPPORTED;
self->priv->syscfgex_supported_modes = supported_modes;
self->priv->supported_gsm_umts_bands = supported_gsm_umts_bands;
self->priv->supported_lte_bands = supported_lte_bands;
g_task_return_pointer (task,
combinations,
(GDestroyNotify)g_array_unref);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
@@ -1123,6 +1307,17 @@ prefmode_test_ready (MMBroadbandModemHuawei *self,
g_object_unref (task);
}
static void
syscfgex_load_supported_modes_bands (GTask *task)
{
mm_base_modem_at_command (MM_BASE_MODEM (g_task_get_source_object (task)),
"^SYSCFGEX=?",
3,
TRUE,
(GAsyncReadyCallback)syscfgex_test_ready,
task);
}
static void
load_supported_modes (MMIfaceModem *_self,
GAsyncReadyCallback callback,
@@ -1146,14 +1341,73 @@ load_supported_modes (MMIfaceModem *_self,
return;
}
/* Check SYSCFGEX */
/* Check SYSCFGEX (with fallback to SYSCFG) */
self->priv->prefmode_support = FEATURE_NOT_SUPPORTED;
mm_base_modem_at_command (MM_BASE_MODEM (self),
"^SYSCFGEX=?",
3,
TRUE,
(GAsyncReadyCallback)syscfgex_test_ready,
task);
if (!self->priv->syscfgex_supported_modes) {
syscfgex_load_supported_modes_bands (task);
return;
}
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
/*****************************************************************************/
/* Load supported bands (Modem interface) */
static GArray *
load_supported_bands_finish (MMIfaceModem *_self,
GAsyncResult *res,
GError **error)
{
MMBroadbandModemHuawei *self;
GArray *bands_array = NULL;
GArray *bands_temp = NULL;
if (!g_task_propagate_boolean (G_TASK (res), error)) {
return NULL;
}
self = MM_BROADBAND_MODEM_HUAWEI (_self);
bands_array = g_array_new (FALSE, FALSE, sizeof (MMModemBand));
if (self->priv->supported_gsm_umts_bands &&
gsm_umts_huawei_to_bands_array (self->priv->supported_gsm_umts_bands, &bands_temp, error)) {
g_array_append_vals (bands_array, bands_temp->data, bands_temp->len);
g_array_free (bands_temp, TRUE);
}
if (self->priv->supported_lte_bands &&
lte_huawei_to_bands_array (self->priv->supported_lte_bands, &bands_temp, error)) {
g_array_append_vals (bands_array, bands_temp->data, bands_temp->len);
g_array_free (bands_temp, TRUE);
}
return bands_array;
}
static void
load_supported_bands (MMIfaceModem *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBroadbandModemHuawei *self;
GTask *task;
self = MM_BROADBAND_MODEM_HUAWEI (_self);
task = g_task_new (self, NULL, callback, user_data);
/* likely already fetched by load_supported_modes() */
if (self->priv->supported_gsm_umts_bands == 0 && self->priv->supported_lte_bands == 0) {
syscfgex_load_supported_modes_bands (task);
return;
}
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
/*****************************************************************************/
@@ -1209,55 +1463,59 @@ prefmode_load_current_modes_ready (MMBroadbandModemHuawei *self,
static void
syscfg_load_current_modes_ready (MMBroadbandModemHuawei *self,
GAsyncResult *res,
GTask *task)
GAsyncResult *res,
GTask *task)
{
const gchar *response;
GError *error = NULL;
const MMHuaweiSyscfgCombination *current = NULL;
GError *error = NULL;
g_autofree MMModemModeCombination *mode = NULL;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (response)
current = mm_huawei_parse_syscfg_response (response,
self->priv->syscfg_supported_modes,
&error);
if (response) {
mode = g_new0 (MMModemModeCombination, 1);
mm_huawei_parse_syscfg_response (response, mode, NULL, &error);
}
if (error)
g_task_return_error (task, error);
else {
MMModemModeCombination *out;
else
g_task_return_pointer (task, g_steal_pointer (&mode), g_free);
out = g_new (MMModemModeCombination, 1);
out->allowed = current->allowed;
out->preferred = current->preferred;
g_task_return_pointer (task, out, g_free);
}
g_object_unref (task);
}
static void
syscfgex_load_current_modes_ready (MMBroadbandModemHuawei *self,
GAsyncResult *res,
GTask *task)
GAsyncResult *res,
GTask *task)
{
const gchar *response;
GError *error = NULL;
const MMHuaweiSyscfgexCombination *current = NULL;
GError *error = NULL;
g_autofree MMModemModeCombination *mode = NULL;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (response)
current = mm_huawei_parse_syscfgex_response (response,
self->priv->syscfgex_supported_modes,
&error);
if (response) {
mode = g_new0 (MMModemModeCombination, 1);
if (mm_huawei_parse_syscfgex_response (response, mode, NULL, NULL, &error)) {
if (mode->allowed == MM_MODEM_MODE_ANY) {
guint i;
const GArray *supported_modes = self->priv->syscfgex_supported_modes;
mode->allowed = MM_MODEM_MODE_NONE;
for (i = 0; i < supported_modes->len; i++) {
mode->allowed |= g_array_index (supported_modes, MMHuaweiSyscfgexCombination, i).allowed;
}
}
}
}
if (error)
g_task_return_error (task, error);
else {
MMModemModeCombination *out;
out = g_new (MMModemModeCombination, 1);
out->allowed = current->allowed;
out->preferred = current->preferred;
g_task_return_pointer (task, out, g_free);
g_task_return_pointer (task, g_steal_pointer (&mode), g_free);
}
g_object_unref (task);
}
@@ -1416,9 +1674,10 @@ syscfg_set_current_modes (MMBroadbandModemHuawei *self,
return FALSE;
}
command = g_strdup_printf ("^SYSCFG=%u,%u,40000000,2,4",
command = g_strdup_printf ("^SYSCFG=%u,%u,%x,2,4",
found->mode,
found->acqorder);
found->acqorder,
MM_HUAWEI_SYSCFG_BAND_NO_CHANGE);
mm_base_modem_at_command (
MM_BASE_MODEM (self),
command,
@@ -1461,8 +1720,10 @@ syscfgex_set_current_modes (MMBroadbandModemHuawei *self,
return FALSE;
}
command = g_strdup_printf ("^SYSCFGEX=\"%s\",3fffffff,2,4,7fffffffffffffff,,",
found->mode_str);
command = g_strdup_printf ("^SYSCFGEX=\"%s\",%x,2,4,%lx,,",
found->mode_str,
MM_HUAWEI_SYSCFG_BAND_ANY,
MM_HUAWEI_SYSCFGEX_BAND_ANY_LTE);
mm_base_modem_at_command (
MM_BASE_MODEM (self),
command,
@@ -4603,6 +4864,8 @@ iface_modem_init (MMIfaceModem *iface)
iface->load_unlock_retries_finish = load_unlock_retries_finish;
iface->modem_after_sim_unlock = modem_after_sim_unlock;
iface->modem_after_sim_unlock_finish = modem_after_sim_unlock_finish;
iface->load_supported_bands = load_supported_bands;
iface->load_supported_bands_finish = load_supported_bands_finish;
iface->load_current_bands = load_current_bands;
iface->load_current_bands_finish = load_current_bands_finish;
iface->set_current_bands = set_current_bands;
+251 -119
View File
@@ -801,77 +801,142 @@ parse_syscfg_modes (const gchar *modes_str,
return out;
}
GArray *
mm_huawei_parse_syscfg_test (const gchar *response,
gpointer log_object,
GError **error)
/* code shared for SYSCFG and SYSCFGEX */
static gboolean
parse_syscfg_bands (const gchar *bands_str,
guint64 *bands_out,
GError **error)
{
gchar **split;
g_auto (GStrv) groups = NULL;
guint i;
g_assert (bands_str);
g_assert (bands_out);
/* Input format examples:
*
* Example GSM/UMTS:
* (2000000400380,"GSM900/GSM1800/WCDMA BCVIII/WCDMA BCI"),(280000,"GSM850/GSM1900"),(3fffffff,"All bands")
*
* Example LTE:
* (800c5,"LTE2100/LTE1800/LTE2600/LTE900/LTE800"),(7fffffffffffffff,"All bands")
*
* The bands might be split in multiple groups.
* Also, there's always a special "All bands" mask in one group.
* The number and order of the groups might differ between modems.
*/
*bands_out = 0;
groups = mm_split_string_groups (bands_str);
if (!groups) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Failed to parse ^SYSCFG bands string");
return FALSE;
}
for (i = 0; groups[i] != NULL; i++) {
g_auto (GStrv) split = NULL;
guint64 band_mask;
split = g_strsplit (groups[i], ",", -1);
g_assert (split);
/* special case: empty bands string, e.g. ^SYSCFGEX LTE bands string from 3G modem */
if (split[0] == NULL)
continue;
if (!mm_get_u64_from_hex_str (split[0], &band_mask)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Could not parse band mask from string: '%s'", split[0]);
return FALSE;
}
if (band_mask == MM_HUAWEI_SYSCFG_BAND_ANY || band_mask == MM_HUAWEI_SYSCFGEX_BAND_ANY_LTE)
continue; /* skip "All bands" mask */
*bands_out |= band_mask;
}
return TRUE;
}
gboolean
mm_huawei_parse_syscfg_test (const gchar *response,
GArray **supported_modes_out,
guint64 *supported_gsm_umts_bands_out,
GError **error)
{
g_auto(GStrv) split = NULL;
GError *inner_error = NULL;
GArray *out;
if (!response || !g_str_has_prefix (response, "^SYSCFG:")) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Missing ^SYSCFG prefix");
return NULL;
return FALSE;
}
/* Examples:
*
* ^SYSCFG:(2,13,14,16),
* (0-3),
* ((400000,"WCDMA2100")),
* ((2000000400380,"GSM900/GSM1800/WCDMA900/WCDMA2100"),(280000,"GSM850/GSM1900"),(3fffffff,"All bands")),
* (0-2),
* (0-4)
*
* Note that "all bands" bit mask doesn't include all bands.
*/
split = split_groups (mm_strip_tag (response, "^SYSCFG:"), error);
if (!split)
return NULL;
/* We expect 5 string chunks */
if (g_strv_length (split) < 5) {
if (!split || g_strv_length (split) < 5) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Unexpected ^SYSCFG format");
g_strfreev (split);
return FALSE;
}
/* Parse supported mode combinations */
out = parse_syscfg_modes (split[0], split[1], log_object, &inner_error);
/* Parse supported mode combinations, if requested */
if (supported_modes_out) {
*supported_modes_out = parse_syscfg_modes (split[0], split[1], NULL, &inner_error);
g_strfreev (split);
if (inner_error) {
g_propagate_error (error, inner_error);
return NULL;
if (inner_error) {
g_propagate_error (error, inner_error);
return FALSE;
}
}
return out;
/* Parse supported bands, if requested */
if (supported_gsm_umts_bands_out) {
if (!parse_syscfg_bands (split[2], supported_gsm_umts_bands_out, &inner_error)) {
g_propagate_error (error, inner_error);
return FALSE;
}
}
return TRUE;
}
/*****************************************************************************/
/* ^SYSCFG response parser */
const MMHuaweiSyscfgCombination *
mm_huawei_parse_syscfg_response (const gchar *response,
const GArray *supported_mode_combinations,
GError **error)
gboolean
mm_huawei_parse_syscfg_response (const gchar *response,
MMModemModeCombination *current_mode_out,
guint64 *current_gsm_umts_bands_out,
GError **error)
{
gchar **split;
g_auto(GStrv) split = NULL;
guint mode;
guint acqorder;
guint i;
guint64 bands;
if (!response || !g_str_has_prefix (response, "^SYSCFG:")) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Missing ^SYSCFG prefix");
return NULL;
return FALSE;
}
/* Format:
@@ -885,44 +950,53 @@ mm_huawei_parse_syscfg_response (const gchar *response,
/* We expect 5 string chunks */
if (g_strv_length (split) < 5 ||
!mm_get_uint_from_str (split[0], &mode) ||
!mm_get_uint_from_str (split[1], &acqorder)) {
!mm_get_uint_from_str (split[1], &acqorder) ||
!mm_get_u64_from_hex_str (split[2], &bands)) {
/* Dump error to upper layer */
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Unexpected ^SYSCFG response: '%s'",
response);
g_strfreev (split);
return NULL;
return FALSE;
}
/* Fix invalid modes with non-sensical acquisition orders */
if (mode == 14 && acqorder != 0) /* WCDMA only but acqorder != "Automatic" */
acqorder = 0;
else if (mode == 13 && acqorder != 0) /* GSM only but acqorder != "Automatic" */
acqorder = 0;
if (current_mode_out) {
/* Fix invalid modes with non-sensical acquisition orders */
if (mode == 14 && acqorder != 0) /* WCDMA only but acqorder != "Automatic" */
acqorder = 0;
else if (mode == 13 && acqorder != 0) /* GSM only but acqorder != "Automatic" */
acqorder = 0;
/* Look for current modes among the supported ones */
for (i = 0; i < supported_mode_combinations->len; i++) {
const MMHuaweiSyscfgCombination *combination;
combination = &g_array_index (supported_mode_combinations,
MMHuaweiSyscfgCombination,
i);
if (mode == combination->mode && acqorder == combination->acqorder) {
g_strfreev (split);
return combination;
if (mode == 2) { /* auto */
current_mode_out->allowed = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G;
if (acqorder == 1)
current_mode_out->preferred = MM_MODEM_MODE_2G;
else if (acqorder == 2)
current_mode_out->preferred = MM_MODEM_MODE_3G;
else
current_mode_out->preferred = MM_MODEM_MODE_NONE;
} else if (mode == 13) { /* GSM only */
current_mode_out->allowed = MM_MODEM_MODE_2G;
current_mode_out->preferred = MM_MODEM_MODE_NONE;
} else if (mode == 14) { /* WCDMA only */
current_mode_out->allowed = MM_MODEM_MODE_3G;
current_mode_out->preferred = MM_MODEM_MODE_NONE;
} else {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Unhandled SYSCFG combination (%d,%d)",
mode,
acqorder);
return FALSE;
}
}
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"No SYSCFG combination found matching the current one (%d,%d)",
mode,
acqorder);
g_strfreev (split);
return NULL;
if (current_gsm_umts_bands_out)
*current_gsm_umts_bands_out = bands;
return TRUE;
}
/*****************************************************************************/
@@ -935,6 +1009,32 @@ huawei_syscfgex_combination_free (MMHuaweiSyscfgexCombination *item)
g_free (item->mode_str);
}
static gboolean
syscfgex_mode_to_mm_modem_mode (const gchar *mode_str,
MMModemMode *mm_mode_out)
{
g_assert (mode_str);
g_assert (mm_mode_out);
if (g_str_has_prefix (mode_str, "00"))
/* auto */
*mm_mode_out = MM_MODEM_MODE_ANY;
else if (g_str_has_prefix (mode_str, "01"))
/* GSM */
*mm_mode_out = MM_MODEM_MODE_2G;
else if (g_str_has_prefix (mode_str, "02"))
/* WCDMA */
*mm_mode_out = MM_MODEM_MODE_3G;
else if (g_str_has_prefix (mode_str, "03"))
/* LTE */
*mm_mode_out = MM_MODEM_MODE_4G;
else
/* 04 -> CDMA1x, 06 -> WiMAX, 07 -> EV-DO, 99 -> no change */
return FALSE;
return TRUE;
}
static gboolean
parse_mode_combination_string (const gchar *mode_str,
MMModemMode *allowed,
@@ -954,22 +1054,7 @@ parse_mode_combination_string (const gchar *mode_str,
for (n = 0; n < strlen (mode_str); n+=2) {
MMModemMode mode;
if (g_ascii_strncasecmp (&mode_str[n], "01", 2) == 0)
/* GSM */
mode = MM_MODEM_MODE_2G;
else if (g_ascii_strncasecmp (&mode_str[n], "02", 2) == 0)
/* WCDMA */
mode = MM_MODEM_MODE_3G;
else if (g_ascii_strncasecmp (&mode_str[n], "03", 2) == 0)
/* LTE */
mode = MM_MODEM_MODE_4G;
else if (g_ascii_strncasecmp (&mode_str[n], "04", 2) == 0)
/* CDMA Note: no EV-DO, just return single value, so assume CDMA1x*/
mode = MM_MODEM_MODE_2G;
else
mode = MM_MODEM_MODE_NONE;
if (mode != MM_MODEM_MODE_NONE) {
if (syscfgex_mode_to_mm_modem_mode (&mode_str[n], &mode)) {
/* The first one in the list is the preferred combination */
if (n == 0)
*preferred |= mode;
@@ -1055,20 +1140,23 @@ parse_mode_combination_string_list (const gchar *modes_str,
return supported_mode_combinations;
}
GArray *
gboolean
mm_huawei_parse_syscfgex_test (const gchar *response,
GError **error)
GArray **supported_modes_out,
guint64 *supported_gsm_umts_bands_out,
guint64 *supported_lte_bands_out,
GError **error)
{
gchar **split;
g_auto(GStrv) split = NULL;
GError *inner_error = NULL;
GArray *out;
GArray *modes;
if (!response || !g_str_has_prefix (response, "^SYSCFGEX:")) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Missing ^SYSCFGEX prefix");
return NULL;
return FALSE;
}
/* Examples:
@@ -1082,50 +1170,63 @@ mm_huawei_parse_syscfgex_test (const gchar *response,
* (7fffffffffffffff,"All bands"))
*/
split = split_groups (mm_strip_tag (response, "^SYSCFGEX:"), error);
if (!split)
return NULL;
/* We expect 5 string chunks */
if (g_strv_length (split) < 5) {
if (!split || g_strv_length (split) < 5) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Unexpected ^SYSCFGEX format");
g_strfreev (split);
return NULL;
return FALSE;
}
out = parse_mode_combination_string_list (split[0], &inner_error);
if (supported_modes_out != NULL) {
modes = parse_mode_combination_string_list (split[0], &inner_error);
g_strfreev (split);
if (inner_error) {
g_propagate_error (error, inner_error);
return FALSE;
}
if (inner_error) {
*supported_modes_out = modes;
}
if (supported_gsm_umts_bands_out != NULL &&
!parse_syscfg_bands (split[1], supported_gsm_umts_bands_out, &inner_error)) {
g_propagate_error (error, inner_error);
return NULL;
return FALSE;
}
return out;
if (supported_lte_bands_out != NULL &&
!parse_syscfg_bands (split[4], supported_lte_bands_out, &inner_error)) {
g_propagate_error (error, inner_error);
return FALSE;
}
return TRUE;
}
/*****************************************************************************/
/* ^SYSCFGEX response parser */
const MMHuaweiSyscfgexCombination *
mm_huawei_parse_syscfgex_response (const gchar *response,
const GArray *supported_mode_combinations,
GError **error)
gboolean
mm_huawei_parse_syscfgex_response (const gchar *response,
MMModemModeCombination *current_mode_out,
guint64 *current_gsm_umts_bands_out,
guint64 *current_lte_bands_out,
GError **error)
{
gchar **split;
guint i;
gsize len;
gchar *str;
g_auto(GStrv) split = NULL;
guint i;
gsize len;
gchar *str;
if (!response || !g_str_has_prefix (response, "^SYSCFGEX:")) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Missing ^SYSCFGEX prefix");
return NULL;
return FALSE;
}
/* Format:
@@ -1143,39 +1244,70 @@ mm_huawei_parse_syscfgex_response (const gchar *response,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Unexpected ^SYSCFGEX response format");
g_strfreev (split);
return NULL;
return FALSE;
}
/* Unquote */
str = split[0];
len = strlen (str);
if ((len >= 2) && (str[0] == '"') && (str[len - 1] == '"')) {
str[0] = ' ';
str[len - 1] = ' ';
str = g_strstrip (str);
}
if (current_mode_out != NULL) {
/* current modes is a string without delimiters, but modes have two chars each.
* The preference is given by the order from left to right.
*
* Ex: "00" -> automatic
* "030102" -> LTE > GSM > WCDMA
*/
MMModemMode first_mode;
current_mode_out->allowed = MM_MODEM_MODE_NONE;
current_mode_out->preferred = MM_MODEM_MODE_NONE;
/* Look for current modes among the supported ones */
for (i = 0; i < supported_mode_combinations->len; i++) {
const MMHuaweiSyscfgexCombination *combination;
str = mm_strip_quotes (split[0]);
len = strlen(str);
combination = &g_array_index (supported_mode_combinations,
MMHuaweiSyscfgexCombination,
i);
if (g_str_equal (str, combination->mode_str)) {
g_strfreev (split);
return combination;
if (!len || len % 2 != 0) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Unexpected ^SYSCFGEX mode string length: %" G_GSIZE_FORMAT, len);
return FALSE;
}
for (i = 0; i < len; i += 2) {
MMModemMode mode;
if (syscfgex_mode_to_mm_modem_mode (&str[i], &mode)) {
if (mode == MM_MODEM_MODE_ANY) {
current_mode_out->allowed = MM_MODEM_MODE_ANY;
current_mode_out->preferred = MM_MODEM_MODE_NONE;
break;
}
/* if only one mode, keep NONE as preferred mode */
if (i == 0)
first_mode = mode;
/* ... but if multiple modes are listed, the first is preferred */
else if (i == 2)
current_mode_out->preferred = first_mode;
current_mode_out->allowed |= mode;
}
}
}
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"No SYSCFGEX combination found matching the current one (%s)",
str);
g_strfreev (split);
return NULL;
if (current_gsm_umts_bands_out != NULL) {
*current_gsm_umts_bands_out = 0;
if (*split[1] != '\0' && !mm_get_u64_from_hex_str (split[1], current_gsm_umts_bands_out)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Could not parse band mask from string: '%s'", split[1]);
return FALSE;
}
}
if (current_lte_bands_out != NULL) {
*current_lte_bands_out = 0;
if (*split[4] != '\0' && !mm_get_u64_from_hex_str (split[4], current_lte_bands_out)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Could not parse band mask from string: '%s'", split[1]);
return FALSE;
}
}
return TRUE;
}
/*****************************************************************************/
+22 -11
View File
@@ -89,6 +89,8 @@ const MMHuaweiPrefmodeCombination *mm_huawei_parse_prefmode_response (const gcha
/* This is the default string we use as fallback when the modem gives
* an empty response to AT^SYSCFG=? */
#define MM_HUAWEI_DEFAULT_SYSCFG_FMT "^SYSCFG:(2,13,14,16),(0-3),,,"
#define MM_HUAWEI_SYSCFG_BAND_ANY 0x3FFFFFFF
#define MM_HUAWEI_SYSCFG_BAND_NO_CHANGE 0x40000000
typedef struct {
guint mode;
@@ -97,35 +99,44 @@ typedef struct {
MMModemMode preferred;
} MMHuaweiSyscfgCombination;
GArray *mm_huawei_parse_syscfg_test (const gchar *response,
gpointer log_object,
GError **error);
gboolean mm_huawei_parse_syscfg_test (const gchar *response,
GArray **supported_modes_out,
guint64 *supported_gsm_umts_bands_out,
GError **error);
/*****************************************************************************/
/* ^SYSCFG response parser */
const MMHuaweiSyscfgCombination *mm_huawei_parse_syscfg_response (const gchar *response,
const GArray *supported_mode_combinations,
GError **error);
gboolean mm_huawei_parse_syscfg_response (const gchar *response,
MMModemModeCombination *current_mode_out,
guint64 *current_gsm_umts_bands_out,
GError **error);
/*****************************************************************************/
/* ^SYSCFGEX test parser */
#define MM_HUAWEI_SYSCFGEX_BAND_ANY_LTE G_GUINT64_CONSTANT (0x7FFFFFFFFFFFFFFF)
typedef struct {
gchar *mode_str;
MMModemMode allowed;
MMModemMode preferred;
} MMHuaweiSyscfgexCombination;
GArray *mm_huawei_parse_syscfgex_test (const gchar *response,
GError **error);
gboolean mm_huawei_parse_syscfgex_test (const gchar *response,
GArray **supported_modes_out,
guint64 *supported_gsm_umts_bands_out,
guint64 *supported_lte_bands_out,
GError **error);
/*****************************************************************************/
/* ^SYSCFGEX response parser */
const MMHuaweiSyscfgexCombination *mm_huawei_parse_syscfgex_response (const gchar *response,
const GArray *supported_mode_combinations,
GError **error);
gboolean mm_huawei_parse_syscfgex_response (const gchar *response,
MMModemModeCombination *current_mode_out,
guint64 *current_gsm_umts_bands_out,
guint64 *current_lte_bands_out,
GError **error);
/*****************************************************************************/
/* ^NWTIME response parser */
@@ -490,6 +490,7 @@ test_prefmode_response (void)
typedef struct {
const gchar *str;
MMHuaweiSyscfgCombination expected_modes[MAX_SYSCFG_COMBINATIONS];
guint64 expected_bands;
} SyscfgTest;
static const SyscfgTest syscfg_tests[] = {
@@ -526,7 +527,8 @@ static const SyscfgTest syscfg_tests[] = {
.allowed = MM_MODEM_MODE_3G,
.preferred = MM_MODEM_MODE_NONE
}
}
},
.expected_bands = 0x0,
},
{
"^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
@@ -561,10 +563,13 @@ static const SyscfgTest syscfg_tests[] = {
.allowed = MM_MODEM_MODE_3G,
.preferred = MM_MODEM_MODE_NONE
}
}
},
.expected_bands = 0x400000,
},
{
"^SYSCFG:(2,13,14,16),(0),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.str = "^SYSCFG:(2,13,14,16),(0),"
"((2000000400380,\"GSM900/GSM1800/WCDMA900/WCDMA2100\"),(280000,\"GSM850/GSM1900\"),(3fffffff,\"All bands\")),"
"(0-2),(0-4)\r\n",
{
{
.mode = 2,
@@ -585,10 +590,13 @@ static const SyscfgTest syscfg_tests[] = {
.preferred = MM_MODEM_MODE_NONE
},
{ 0, 0, 0, 0 }
}
},
.expected_bands = 0x2000000680380,
},
{
"^SYSCFG:(13),(0),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.str = "^SYSCFG:(13),(0),"
"((2000000400380,\"GSM900/GSM1800/WCDMA900/WCDMA2100\"),(280000,\"GSM850/GSM1900\"),(3fffffff,\"All bands\")),"
"(0-2),(0-4)\r\n",
{
{
.mode = 13,
@@ -597,7 +605,8 @@ static const SyscfgTest syscfg_tests[] = {
.preferred = MM_MODEM_MODE_NONE
},
{ 0, 0, 0, 0 }
}
},
.expected_bands = 0x2000000680380,
}
};
@@ -608,7 +617,9 @@ test_syscfg (void)
for (i = 0; i < G_N_ELEMENTS (syscfg_tests); i++) {
GError *error = NULL;
gboolean result;
GArray *combinations = NULL;
guint64 bands;
guint j;
guint n_expected_combinations = 0;
@@ -617,10 +628,12 @@ test_syscfg (void)
n_expected_combinations++;
}
combinations = mm_huawei_parse_syscfg_test (syscfg_tests[i].str, NULL, &error);
result = mm_huawei_parse_syscfg_test (syscfg_tests[i].str, &combinations, &bands, &error);
g_assert_true (result);
g_assert_no_error (error);
g_assert (combinations != NULL);
g_assert_cmpuint (combinations->len, ==, n_expected_combinations);
g_assert_cmpuint (bands, ==, syscfg_tests[i].expected_bands);
for (j = 0; j < combinations->len; j++) {
MMHuaweiSyscfgCombination *single;
@@ -665,6 +678,7 @@ typedef struct {
const gchar *format;
MMModemMode allowed;
MMModemMode preferred;
guint64 bands;
} SyscfgResponseTest;
static const SyscfgResponseTest syscfg_response_tests[] = {
@@ -672,45 +686,60 @@ static const SyscfgResponseTest syscfg_response_tests[] = {
.str = "^SYSCFG: 2,0,400000,0,3\r\n",
.format = "^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_2G),
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.bands = 0x400000,
},
{
.str = "^SYSCFG: 2,1,400000,0,3\r\n",
.format = "^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_2G),
.preferred = MM_MODEM_MODE_2G
.preferred = MM_MODEM_MODE_2G,
.bands = 0x400000,
},
{
.str = "^SYSCFG: 2,2,400000,0,3\r\n",
.format = "^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_2G),
.preferred = MM_MODEM_MODE_3G
.preferred = MM_MODEM_MODE_3G,
.bands = 0x400000,
},
{
.str = "^SYSCFG: 13,0,400000,0,3\r\n",
.format = "^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.allowed = MM_MODEM_MODE_2G,
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.bands = 0x400000,
},
{
.str = "^SYSCFG: 14,0,400000,0,3\r\n",
.format = "^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.allowed = MM_MODEM_MODE_3G,
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.bands = 0x400000,
},
{
/* mode: 3G > 2G, band: ANY */
.str = "^SYSCFG:2,2,3FFFFFFF,1,2\r\n",
.format = "^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_2G),
.preferred = MM_MODEM_MODE_3G,
.bands = MM_HUAWEI_SYSCFG_BAND_ANY,
},
{
/* Non-sensical acquisition order (WCDMA-only but acquire WCDMA-then-GSM */
.str = "^SYSCFG: 14,2,400000,0,3\r\n",
.format = "^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.allowed = MM_MODEM_MODE_3G,
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.bands = 0x400000,
},
{
/* Non-sensical acquisition order (GSM-only but acquire GSM-then-WCDMA */
.str = "^SYSCFG: 13,1,400000,0,3\r\n",
.format = "^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n",
.allowed = MM_MODEM_MODE_2G,
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.bands = 0x400000,
}
};
@@ -720,21 +749,26 @@ test_syscfg_response (void)
guint i;
for (i = 0; i < G_N_ELEMENTS (syscfg_response_tests); i++) {
gboolean result;
GArray *combinations = NULL;
const MMHuaweiSyscfgCombination *found;
guint64 supported_bands;
guint64 current_bands;
MMModemModeCombination current_mode;
GError *error = NULL;
combinations = mm_huawei_parse_syscfg_test (syscfg_response_tests[i].format, NULL, NULL);
result = mm_huawei_parse_syscfg_test (syscfg_response_tests[i].format, &combinations, &supported_bands, NULL);
g_assert_true (result);
g_assert (combinations != NULL);
found = mm_huawei_parse_syscfg_response (syscfg_response_tests[i].str,
combinations,
&error);
result = mm_huawei_parse_syscfg_response (syscfg_response_tests[i].str,
&current_mode,
&current_bands,
&error);
g_assert_no_error (error);
g_assert (found != NULL);
g_assert_cmpuint (found->allowed, ==, syscfg_response_tests[i].allowed);
g_assert_cmpuint (found->preferred, ==, syscfg_response_tests[i].preferred);
g_assert_cmpuint (current_mode.allowed, ==, syscfg_response_tests[i].allowed);
g_assert_cmpuint (current_mode.preferred, ==, syscfg_response_tests[i].preferred);
g_assert_cmpuint (current_bands, ==, syscfg_response_tests[i].bands);
g_array_unref (combinations);
}
@@ -748,6 +782,8 @@ test_syscfg_response (void)
typedef struct {
const gchar *str;
MMHuaweiSyscfgexCombination expected_modes[MAX_SYSCFGEX_COMBINATIONS];
guint64 gsm_umts_bands;
guint64 lte_bands;
} SyscfgexTest;
static const SyscfgexTest syscfgex_tests[] = {
@@ -780,7 +816,9 @@ static const SyscfgexTest syscfgex_tests[] = {
.preferred = MM_MODEM_MODE_NONE
},
{ NULL, 0, 0 }
}
},
.gsm_umts_bands = 0x2000004e80380,
.lte_bands = 0x800c5,
},
{
"^SYSCFGEX: (\"030201\",\"0302\",\"03\",\"99\"),"
@@ -806,7 +844,9 @@ static const SyscfgexTest syscfgex_tests[] = {
.preferred = MM_MODEM_MODE_NONE
},
{ NULL, 0, 0 }
}
},
.gsm_umts_bands = 0x2000004e80380,
.lte_bands = 0x800c5,
},
{
"^SYSCFGEX: (\"03\"),"
@@ -822,7 +862,9 @@ static const SyscfgexTest syscfgex_tests[] = {
.preferred = MM_MODEM_MODE_NONE
},
{ NULL, 0, 0 }
}
},
.gsm_umts_bands = 0x2000004e80380,
.lte_bands = 0x800c5,
},
{
"^SYSCFGEX: (\"00\",\"01\",\"02\",\"0102\",\"0201\"),"
@@ -857,7 +899,9 @@ static const SyscfgexTest syscfgex_tests[] = {
.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G),
.preferred = MM_MODEM_MODE_3G
}
}
},
.gsm_umts_bands = 0x2000006e80180,
.lte_bands = 0x0,
}
};
@@ -868,7 +912,10 @@ test_syscfgex (void)
for (i = 0; i < G_N_ELEMENTS (syscfgex_tests); i++) {
GError *error = NULL;
gboolean result;
GArray *combinations = NULL;
guint64 gsm_umts_bands;
guint64 lte_bands;
guint j;
guint n_expected_combinations = 0;
@@ -877,10 +924,17 @@ test_syscfgex (void)
n_expected_combinations++;
}
combinations = mm_huawei_parse_syscfgex_test (syscfgex_tests[i].str, &error);
result = mm_huawei_parse_syscfgex_test (syscfgex_tests[i].str,
&combinations,
&gsm_umts_bands,
&lte_bands,
&error);
g_assert_true (result);
g_assert_no_error (error);
g_assert (combinations != NULL);
g_assert_cmpuint (combinations->len, ==, n_expected_combinations);
g_assert_cmpuint(gsm_umts_bands, ==, syscfgex_tests[i].gsm_umts_bands);
g_assert_cmpuint(lte_bands, ==, syscfgex_tests[i].lte_bands);
for (j = 0; j < combinations->len; j++) {
MMHuaweiSyscfgexCombination *single;
@@ -924,6 +978,9 @@ typedef struct {
const gchar *format;
MMModemMode allowed;
MMModemMode preferred;
guint64 gsm_umts_bands;
guint64 lte_bands;
} SyscfgexResponseTest;
static const SyscfgexResponseTest syscfgex_response_tests[] = {
@@ -936,7 +993,9 @@ static const SyscfgexResponseTest syscfgex_response_tests[] = {
"((800c5,\"LTE2100/LTE1800/LTE2600/LTE900/LTE800\"),(7fffffffffffffff,\"All bands\"))"
"\r\n",
.allowed = (MM_MODEM_MODE_4G | MM_MODEM_MODE_3G | MM_MODEM_MODE_2G),
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.gsm_umts_bands = 0x2000004e80380,
.lte_bands = 0x800c5,
},
{
.str = "^SYSCFGEX: \"03\",3FFFFFFF,1,2,7FFFFFFFFFFFFFFF",
@@ -947,7 +1006,9 @@ static const SyscfgexResponseTest syscfgex_response_tests[] = {
"((800c5,\"LTE2100/LTE1800/LTE2600/LTE900/LTE800\"),(7fffffffffffffff,\"All bands\"))"
"\r\n",
.allowed = MM_MODEM_MODE_4G,
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.gsm_umts_bands = 0x2000004e80380,
.lte_bands = 0x800c5,
},
{
.str = "^SYSCFGEX: \"02\",3FFFFFFF,1,2,7FFFFFFFFFFFFFFF",
@@ -958,7 +1019,9 @@ static const SyscfgexResponseTest syscfgex_response_tests[] = {
"((800c5,\"LTE2100/LTE1800/LTE2600/LTE900/LTE800\"),(7fffffffffffffff,\"All bands\"))"
"\r\n",
.allowed = MM_MODEM_MODE_3G,
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.gsm_umts_bands = 0x2000004e80380,
.lte_bands = 0x800c5,
},
{
.str = "^SYSCFGEX: \"01\",3FFFFFFF,1,2,7FFFFFFFFFFFFFFF",
@@ -969,7 +1032,9 @@ static const SyscfgexResponseTest syscfgex_response_tests[] = {
"((800c5,\"LTE2100/LTE1800/LTE2600/LTE900/LTE800\"),(7fffffffffffffff,\"All bands\"))"
"\r\n",
.allowed = MM_MODEM_MODE_2G,
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.gsm_umts_bands = 0x2000004e80380,
.lte_bands = 0x800c5,
},
{
.str = "^SYSCFGEX: \"00\",3fffffff,1,2,",
@@ -980,7 +1045,9 @@ static const SyscfgexResponseTest syscfgex_response_tests[] = {
"," /* NOTE: Non-LTE modem, LTE Bands EMPTY */
"\r\n",
.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G),
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.gsm_umts_bands = 0x2000006e80180,
.lte_bands = 0x0,
},
{
.str = "^SYSCFGEX: \"01\",3fffffff,1,2,",
@@ -991,7 +1058,9 @@ static const SyscfgexResponseTest syscfgex_response_tests[] = {
"," /* NOTE: Non-LTE modem, LTE Bands EMPTY */
"\r\n",
.allowed = MM_MODEM_MODE_2G,
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.gsm_umts_bands = 0x2000006e80180,
.lte_bands = 0x0,
},
{
.str = "^SYSCFGEX: \"02\",3fffffff,1,2,",
@@ -1002,7 +1071,9 @@ static const SyscfgexResponseTest syscfgex_response_tests[] = {
"," /* NOTE: Non-LTE modem, LTE Bands EMPTY */
"\r\n",
.allowed = MM_MODEM_MODE_3G,
.preferred = MM_MODEM_MODE_NONE
.preferred = MM_MODEM_MODE_NONE,
.gsm_umts_bands = 0x2000006e80180,
.lte_bands = 0x0,
},
{
.str = "^SYSCFGEX: \"0102\",3fffffff,1,2,",
@@ -1013,7 +1084,9 @@ static const SyscfgexResponseTest syscfgex_response_tests[] = {
"," /* NOTE: Non-LTE modem, LTE Bands EMPTY */
"\r\n",
.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G),
.preferred = MM_MODEM_MODE_2G
.preferred = MM_MODEM_MODE_2G,
.gsm_umts_bands = 0x2000006e80180,
.lte_bands = 0x0,
},
{
.str = "^SYSCFGEX: \"0201\",3fffffff,1,2,",
@@ -1024,7 +1097,9 @@ static const SyscfgexResponseTest syscfgex_response_tests[] = {
"," /* NOTE: Non-LTE modem, LTE Bands EMPTY */
"\r\n",
.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G),
.preferred = MM_MODEM_MODE_3G
.preferred = MM_MODEM_MODE_3G,
.gsm_umts_bands = 0x2000006e80180,
.lte_bands = 0x0,
}
};
@@ -1034,21 +1109,50 @@ test_syscfgex_response (void)
guint i;
for (i = 0; i < G_N_ELEMENTS (syscfgex_response_tests); i++) {
gboolean result;
GArray *combinations = NULL;
const MMHuaweiSyscfgexCombination *found;
guint64 supported_gsm_umts_bands;
guint64 supported_lte_bands;
MMModemModeCombination current_combination;
guint64 current_gsm_umts_bands;
guint64 current_lte_bands;
GError *error = NULL;
combinations = mm_huawei_parse_syscfgex_test (syscfgex_response_tests[i].format, NULL);
result = mm_huawei_parse_syscfgex_test (syscfgex_response_tests[i].format,
&combinations,
&supported_gsm_umts_bands,
&supported_lte_bands,
NULL);
g_assert_true (result);
g_assert (combinations != NULL);
found = mm_huawei_parse_syscfgex_response (syscfgex_response_tests[i].str,
combinations,
&error);
result = mm_huawei_parse_syscfgex_response (syscfgex_response_tests[i].str,
&current_combination,
&current_gsm_umts_bands,
&current_lte_bands,
&error);
if (current_combination.allowed == MM_MODEM_MODE_ANY) {
/* current mode: any -> all supported */
guint j;
current_combination.allowed = MM_MODEM_MODE_NONE;
for (j = 0; j < combinations->len; j++) {
current_combination.allowed |= g_array_index (combinations, MMHuaweiSyscfgexCombination, j).allowed;
}
}
if (current_gsm_umts_bands == MM_HUAWEI_SYSCFG_BAND_ANY)
current_gsm_umts_bands = supported_gsm_umts_bands;
if (current_lte_bands == MM_HUAWEI_SYSCFGEX_BAND_ANY_LTE)
current_lte_bands = supported_lte_bands;
g_assert_true (result);
g_assert_no_error (error);
g_assert (found != NULL);
g_assert_cmpuint (found->allowed, ==, syscfgex_response_tests[i].allowed);
g_assert_cmpuint (found->preferred, ==, syscfgex_response_tests[i].preferred);
g_assert_cmpuint (current_combination.allowed, ==, syscfgex_response_tests[i].allowed);
g_assert_cmpuint (current_combination.preferred, ==, syscfgex_response_tests[i].preferred);
g_assert_cmpuint (current_gsm_umts_bands, ==, syscfgex_response_tests[i].gsm_umts_bands);
g_assert_cmpuint (current_lte_bands, ==, syscfgex_response_tests[i].lte_bands);
g_array_unref (combinations);
}