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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -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,
|
||||
¤t_mode,
|
||||
¤t_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,
|
||||
<e_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,
|
||||
¤t_combination,
|
||||
¤t_gsm_umts_bands,
|
||||
¤t_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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user