diff options
author | Oliver Kästner <git@oliver-kaestner.de> | 2024-04-07 21:48:52 +0200 |
---|---|---|
committer | Oliver Kästner <git@oliver-kaestner.de> | 2024-04-11 19:36:01 +0000 |
commit | 469d310397ea62953f3f7c84526c2f25eda363fe (patch) | |
tree | 9903358086e1c38df0783eba3f02df7b89961514 | |
parent | 338b299fe2b759fa2bf20b408f128944c388af29 (diff) |
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.
-rw-r--r-- | src/plugins/huawei/mm-broadband-modem-huawei.c | 587 | ||||
-rw-r--r-- | src/plugins/huawei/mm-modem-helpers-huawei.c | 368 | ||||
-rw-r--r-- | src/plugins/huawei/mm-modem-helpers-huawei.h | 33 | ||||
-rw-r--r-- | src/plugins/huawei/tests/test-modem-helpers-huawei.c | 192 |
4 files changed, 845 insertions, 335 deletions
diff --git a/src/plugins/huawei/mm-broadband-modem-huawei.c b/src/plugins/huawei/mm-broadband-modem-huawei.c index b3d80cca..ca142d4a 100644 --- a/src/plugins/huawei/mm-broadband-modem-huawei.c +++ b/src/plugins/huawei/mm-broadband-modem-huawei.c @@ -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; - - 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 huawei_to_bands_array (gsm_umts_bands, G_N_ELEMENTS (gsm_umts_bands), huawei, bands_array, error); +} - 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) { + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +syscfg_load_current_bands_ready (MMBroadbandModemHuawei *self, + GAsyncResult *res, + GTask *task) +{ const gchar *response; - GArray *bands_array = NULL; + GError *error = NULL; + GArray *bands_array = NULL; - response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); - if (!response) - return NULL; + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); + if (response) { + guint64 huawei_bands; - if (!parse_syscfg (response, &bands_array, error)) - return NULL; + 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; - return bands_array; + 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, +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; + if (!g_task_propagate_boolean (G_TASK (res), error)) { + return 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); + /* check SYSCFGEX first */ + if (self->priv->syscfgex_supported_modes) { + MMModemModeCombination mode; + 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), + 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; - guint i; - GArray *combinations; + 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), - 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++) { 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 (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); + 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; + + 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; } @@ -1124,6 +1308,17 @@ prefmode_test_ready (MMBroadbandModemHuawei *self, } 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, gpointer user_data) @@ -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; diff --git a/src/plugins/huawei/mm-modem-helpers-huawei.c b/src/plugins/huawei/mm-modem-helpers-huawei.c index 23ffc153..f5a55e9c 100644 --- a/src/plugins/huawei/mm-modem-helpers-huawei.c +++ b/src/plugins/huawei/mm-modem-helpers-huawei.c @@ -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 FALSE; + } + } - if (inner_error) { - g_propagate_error (error, inner_error); - return NULL; + /* 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 out; + 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; - - /* 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 (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; + + 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; } /*****************************************************************************/ @@ -936,6 +1010,32 @@ huawei_syscfgex_combination_free (MMHuaweiSyscfgexCombination *item) } 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, MMModemMode *preferred) @@ -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; + + str = mm_strip_quotes (split[0]); + len = strlen(str); + + 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; + } + } } - /* Look for current modes among the supported ones */ - for (i = 0; i < supported_mode_combinations->len; i++) { - const MMHuaweiSyscfgexCombination *combination; + if (current_gsm_umts_bands_out != NULL) { + *current_gsm_umts_bands_out = 0; - combination = &g_array_index (supported_mode_combinations, - MMHuaweiSyscfgexCombination, - i); - if (g_str_equal (str, combination->mode_str)) { - g_strfreev (split); - return combination; + 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; } } - 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_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; } /*****************************************************************************/ diff --git a/src/plugins/huawei/mm-modem-helpers-huawei.h b/src/plugins/huawei/mm-modem-helpers-huawei.h index 3d1a4b22..6fbfd9c3 100644 --- a/src/plugins/huawei/mm-modem-helpers-huawei.h +++ b/src/plugins/huawei/mm-modem-helpers-huawei.h @@ -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 */ diff --git a/src/plugins/huawei/tests/test-modem-helpers-huawei.c b/src/plugins/huawei/tests/test-modem-helpers-huawei.c index 1a686f93..724ee7dc 100644 --- a/src/plugins/huawei/tests/test-modem-helpers-huawei.c +++ b/src/plugins/huawei/tests/test-modem-helpers-huawei.c @@ -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); } |