diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2013-11-07 23:30:53 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2013-12-09 23:07:19 +0100 |
commit | 677dd7da91b001a5eeb53f2e1b54b7935b764a66 (patch) | |
tree | 7410af1cc1a707462861f1aa6c0171becf510a41 | |
parent | ceb578a824c60310c64d7a972afb12282fd7af35 (diff) |
huawei: new ^SYSCFG=? test parser
-rw-r--r-- | plugins/huawei/mm-modem-helpers-huawei.c | 299 | ||||
-rw-r--r-- | plugins/huawei/mm-modem-helpers-huawei.h | 13 | ||||
-rw-r--r-- | plugins/huawei/tests/test-modem-helpers-huawei.c | 150 |
3 files changed, 462 insertions, 0 deletions
diff --git a/plugins/huawei/mm-modem-helpers-huawei.c b/plugins/huawei/mm-modem-helpers-huawei.c index 7a1e8eeb..bd1e867f 100644 --- a/plugins/huawei/mm-modem-helpers-huawei.c +++ b/plugins/huawei/mm-modem-helpers-huawei.c @@ -15,6 +15,8 @@ */ #include <string.h> +#include <stdlib.h> +#include <stdio.h> #include <ModemManager.h> #define _LIBMM_INSIDE_MM @@ -363,3 +365,300 @@ mm_huawei_parse_prefmode_test (const gchar *response, return out; } + +/*****************************************************************************/ +/* ^SYSCFG test parser */ + +static gchar ** +split_groups (const gchar *str, + GError **error) +{ + const gchar *p = str; + GPtrArray *out; + guint groups = 0; + + /* + * Split string: (a),((b1),(b2)),,(d),((e1),(e2)) + * Into: + * - a + * - (b1),(b2) + * - + * - d + * - (e1),(e2) + */ + + out = g_ptr_array_new_with_free_func (g_free); + + while (TRUE) { + const gchar *start; + guint inner_groups; + + /* Skip whitespaces */ + while (*p == ' ' || *p == '\r' || *p == '\n') + p++; + + /* We're done, return */ + if (*p == '\0') { + g_ptr_array_set_size (out, out->len + 1); + return (gchar **) g_ptr_array_free (out, FALSE); + } + + /* Group separators */ + if (groups > 0) { + if (*p != ',') { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unexpected group separator"); + g_ptr_array_unref (out); + return NULL; + } + p++; + } + + /* Skip whitespaces */ + while (*p == ' ' || *p == '\r' || *p == '\n') + p++; + + /* New group */ + groups++; + + /* Empty group? */ + if (*p == ',' || *p == '\0') { + g_ptr_array_add (out, g_strdup ("")); + continue; + } + + /* No group start? */ + if (*p != '(') { + /* Error */ + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Expected '(' not found"); + g_ptr_array_unref (out); + return NULL; + } + p++; + + inner_groups = 0; + start = p; + while (TRUE) { + if (*p == '(') { + inner_groups++; + p++; + continue; + } + + if (*p == '\0') { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Early end of string found, unfinished group"); + g_ptr_array_unref (out); + return NULL; + } + + if (*p == ')') { + gchar *group; + + if (inner_groups > 0) { + inner_groups--; + p++; + continue; + } + + group = g_strndup (start, p - start); + g_ptr_array_add (out, group); + p++; + break; + } + + /* keep on */ + p++; + } + } + + g_assert_not_reached (); +} + +static gboolean +mode_from_syscfg (guint huawei_mode, + MMModemMode *modem_mode, + GError **error) +{ + g_assert (modem_mode != NULL); + + *modem_mode = MM_MODEM_MODE_NONE; + switch (huawei_mode) { + case 2: + *modem_mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G; + break; + case 13: + *modem_mode = MM_MODEM_MODE_2G; + break; + case 14: + *modem_mode = MM_MODEM_MODE_3G; + break; + case 16: + /* ignore */ + break; + default: + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "No translation from huawei prefmode '%u' to mode", + huawei_mode); + } + + return *modem_mode != MM_MODEM_MODE_NONE ? TRUE : FALSE; +} + +static GArray * +parse_syscfg_modes (const gchar *modes_str, + const gchar *acqorder_str, + GError **error) +{ + GArray *out; + gchar **split; + guint i; + gint min_acqorder = 0; + gint max_acqorder = 0; + + /* Start parsing acquisition order */ + if (!sscanf (acqorder_str, "%d-%d", &min_acqorder, &max_acqorder)) + mm_dbg ("Error parsing ^SYSCFG acquisition order range (%s)", acqorder_str); + + /* Just in case, we default to supporting only auto */ + if (max_acqorder < min_acqorder) { + min_acqorder = 0; + max_acqorder = 0; + } + + /* Now parse modes */ + split = g_strsplit (modes_str, ",", -1); + out = g_array_sized_new (FALSE, + FALSE, + sizeof (MMHuaweiSyscfgCombination), + g_strv_length (split)); + for (i = 0; split[i]; i++) { + guint val; + guint allowed = MM_MODEM_MODE_NONE; + GError *inner_error = NULL; + MMHuaweiSyscfgCombination combination; + + if (!mm_get_uint_from_str (mm_strip_quotes (split[i]), &val)) { + mm_dbg ("Error parsing ^SYSCFG mode value: %s", split[i]); + continue; + } + + if (!mode_from_syscfg (val, &allowed, &inner_error)) { + if (inner_error) { + mm_dbg ("Unhandled ^SYSCFG: %s", inner_error->message); + g_error_free (inner_error); + } + continue; + } + + switch (allowed) { + case MM_MODEM_MODE_2G: + case MM_MODEM_MODE_3G: + /* single mode */ + combination.allowed = allowed; + combination.preferred = MM_MODEM_MODE_NONE; + combination.mode = val; + combination.acqorder = 0; + g_array_append_val (out, combination); + break; + case (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G): + /* 2G and 3G; auto */ + combination.allowed = allowed; + combination.mode = val; + if (min_acqorder == 0) { + combination.preferred = MM_MODEM_MODE_NONE; + combination.acqorder = 0; + g_array_append_val (out, combination); + } + /* 2G and 3G; 2G preferred */ + if (min_acqorder <= 1 && max_acqorder >= 1) { + combination.preferred = MM_MODEM_MODE_2G; + combination.acqorder = 1; + g_array_append_val (out, combination); + } + /* 2G and 3G; 3G preferred */ + if (min_acqorder <= 2 && max_acqorder >= 2) { + combination.preferred = MM_MODEM_MODE_3G; + combination.acqorder = 2; + g_array_append_val (out, combination); + } + break; + default: + g_assert_not_reached (); + } + } + + /* If we didn't build a valid array of combinations, return an error */ + if (out->len == 0) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Cannot parse list of allowed mode combinations: '%s,%s'", + modes_str, + acqorder_str); + g_array_unref (out); + return NULL; + } + + return out; +} + +GArray * +mm_huawei_parse_syscfg_test (const gchar *response, + GError **error) +{ + gchar **split; + 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; + } + + /* Examples: + * + * ^SYSCFG:(2,13,14,16), + * (0-3), + * ((400000,"WCDMA2100")), + * (0-2), + * (0-4) + */ + split = split_groups (mm_strip_tag (response, "^SYSCFG:"), error); + if (!split) + return NULL; + + /* We expect 5 string chunks */ + if (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], &inner_error); + + g_strfreev (split); + + if (inner_error) { + g_propagate_error (error, inner_error); + return NULL; + } + + return out; +} diff --git a/plugins/huawei/mm-modem-helpers-huawei.h b/plugins/huawei/mm-modem-helpers-huawei.h index 00191b2d..d0cbf693 100644 --- a/plugins/huawei/mm-modem-helpers-huawei.h +++ b/plugins/huawei/mm-modem-helpers-huawei.h @@ -63,4 +63,17 @@ typedef struct { GArray *mm_huawei_parse_prefmode_test (const gchar *response, GError **error); +/*****************************************************************************/ +/* ^SYSCFG test parser */ + +typedef struct { + guint mode; + guint acqorder; + MMModemMode allowed; + MMModemMode preferred; +} MMHuaweiSyscfgCombination; + +GArray *mm_huawei_parse_syscfg_test (const gchar *response, + GError **error); + #endif /* MM_MODEM_HELPERS_HUAWEI_H */ diff --git a/plugins/huawei/tests/test-modem-helpers-huawei.c b/plugins/huawei/tests/test-modem-helpers-huawei.c index c7b8b778..fbf287f0 100644 --- a/plugins/huawei/tests/test-modem-helpers-huawei.c +++ b/plugins/huawei/tests/test-modem-helpers-huawei.c @@ -374,6 +374,155 @@ test_prefmode (void) } /*****************************************************************************/ +/* Test ^SYSCFG=? responses */ + +#define MAX_SYSCFG_COMBINATIONS 5 + +typedef struct { + const gchar *str; + MMHuaweiSyscfgCombination expected_modes[MAX_SYSCFG_COMBINATIONS]; +} SyscfgTest; + +static const SyscfgTest syscfg_tests[] = { + { + "^SYSCFG:(2,13,14,16),(0-3),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n", + { + { + .mode = 2, + .acqorder = 0, + .allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_2G), + .preferred = MM_MODEM_MODE_NONE + }, + { + .mode = 2, + .acqorder = 1, + .allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_2G), + .preferred = MM_MODEM_MODE_2G + }, + { + .mode = 2, + .acqorder = 2, + .allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_2G), + .preferred = MM_MODEM_MODE_3G + }, + { + .mode = 13, + .acqorder = 0, + .allowed = MM_MODEM_MODE_2G, + .preferred = MM_MODEM_MODE_NONE + }, + { + .mode = 14, + .acqorder = 0, + .allowed = MM_MODEM_MODE_3G, + .preferred = MM_MODEM_MODE_NONE + } + } + }, + { + "^SYSCFG:(2,13,14,16),(0),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n", + { + { + .mode = 2, + .acqorder = 0, + .allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_2G), + .preferred = MM_MODEM_MODE_NONE + }, + { + .mode = 13, + .acqorder = 0, + .allowed = MM_MODEM_MODE_2G, + .preferred = MM_MODEM_MODE_NONE + }, + { + .mode = 14, + .acqorder = 0, + .allowed = MM_MODEM_MODE_3G, + .preferred = MM_MODEM_MODE_NONE + }, + { 0, 0, 0, 0 } + } + }, + { + "^SYSCFG:(13),(0),((400000,\"WCDMA2100\")),(0-2),(0-4)\r\n", + { + { + .mode = 13, + .acqorder = 0, + .allowed = MM_MODEM_MODE_2G, + .preferred = MM_MODEM_MODE_NONE + }, + { 0, 0, 0, 0 } + } + } +}; + +static void +test_syscfg (void) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (syscfg_tests); i++) { + GError *error = NULL; + GArray *combinations = NULL; + guint j; + guint n_expected_combinations = 0; + + for (j = 0; j < MAX_SYSCFG_COMBINATIONS; j++) { + if (syscfg_tests[i].expected_modes[j].mode != 0) + n_expected_combinations++; + } + + combinations = mm_huawei_parse_syscfg_test (syscfg_tests[i].str, &error); + g_assert_no_error (error); + g_assert (combinations != NULL); + g_assert_cmpuint (combinations->len, ==, n_expected_combinations); + +#if defined ENABLE_TEST_MESSAGE_TRACES + for (j = 0; j < combinations->len; j++) { + MMHuaweiSyscfgCombination *single; + gchar *allowed_str; + gchar *preferred_str; + + single = &g_array_index (combinations, MMHuaweiSyscfgCombination, j); + allowed_str = mm_modem_mode_build_string_from_mask (single->allowed); + preferred_str = mm_modem_mode_build_string_from_mask (single->preferred); + mm_dbg ("Test[%u], Combination[%u]: %u, %u, \"%s\", \"%s\"", + i, + j, + single->mode, + single->acqorder, + allowed_str, + preferred_str); + g_free (allowed_str); + g_free (preferred_str); + } +#endif + + for (j = 0; j < combinations->len; j++) { + MMHuaweiSyscfgCombination *single; + guint k; + gboolean found = FALSE; + + single = &g_array_index (combinations, MMHuaweiSyscfgCombination, j); + for (k = 0; k <= n_expected_combinations; k++) { + if (single->allowed == syscfg_tests[i].expected_modes[k].allowed && + single->preferred == syscfg_tests[i].expected_modes[k].preferred && + single->mode == syscfg_tests[i].expected_modes[k].mode && + single->acqorder == syscfg_tests[i].expected_modes[k].acqorder) { + found = TRUE; + break; + } + } + + g_assert (found == TRUE); + } + + g_array_unref (combinations); + } +} + +/*****************************************************************************/ void _mm_log (const char *loc, @@ -406,6 +555,7 @@ int main (int argc, char **argv) g_test_add_func ("/MM/huawei/sysinfo", test_sysinfo); g_test_add_func ("/MM/huawei/sysinfoex", test_sysinfoex); g_test_add_func ("/MM/huawei/prefmode", test_prefmode); + g_test_add_func ("/MM/huawei/syscfg", test_syscfg); return g_test_run (); } |