diff options
-rw-r--r-- | plugins/mbm/mm-broadband-modem-mbm.c | 93 | ||||
-rw-r--r-- | plugins/mbm/mm-modem-helpers-mbm.c | 100 | ||||
-rw-r--r-- | plugins/mbm/mm-modem-helpers-mbm.h | 14 | ||||
-rw-r--r-- | plugins/mbm/tests/test-modem-helpers-mbm.c | 62 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 126 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 2 |
6 files changed, 281 insertions, 116 deletions
diff --git a/plugins/mbm/mm-broadband-modem-mbm.c b/plugins/mbm/mm-broadband-modem-mbm.c index fa291d65d..dc480f803 100644 --- a/plugins/mbm/mm-broadband-modem-mbm.c +++ b/plugins/mbm/mm-broadband-modem-mbm.c @@ -35,6 +35,7 @@ #include "mm-bearer-list.h" #include "mm-errors-types.h" #include "mm-modem-helpers.h" +#include "mm-modem-helpers-mbm.h" #include "mm-broadband-modem-mbm.h" #include "mm-broadband-bearer-mbm.h" #include "mm-sim-mbm.h" @@ -59,12 +60,6 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbm, mm_broadband_modem_mbm, MM_TYPE_BRO G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)) -#define MBM_NETWORK_MODE_OFFLINE 0 -#define MBM_NETWORK_MODE_ANY 1 -#define MBM_NETWORK_MODE_LOW_POWER 4 -#define MBM_NETWORK_MODE_2G 5 -#define MBM_NETWORK_MODE_3G 6 - #define MBM_E2NAP_DISCONNECTED 0 #define MBM_E2NAP_CONNECTED 1 #define MBM_E2NAP_CONNECTING 2 @@ -204,59 +199,55 @@ modem_after_sim_unlock (MMIfaceModem *self, /* Load supported modes (Modem interface) */ static GArray * -load_supported_modes_finish (MMIfaceModem *self, +load_supported_modes_finish (MMIfaceModem *_self, GAsyncResult *res, GError **error) { - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) - return NULL; - - return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); -} - -static void -parent_load_supported_modes_ready (MMIfaceModem *self, - GAsyncResult *res, - GSimpleAsyncResult *simple) -{ - GError *error = NULL; - GArray *all; + MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self); + const gchar *response; + guint32 mask = 0; GArray *combinations; - GArray *filtered; MMModemModeCombination mode; - all = iface_modem_parent->load_supported_modes_finish (self, res, &error); - if (!all) { - g_simple_async_result_take_error (simple, error); - g_simple_async_result_complete (simple); - g_object_unref (simple); - return; - } + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); + if (!response) + return FALSE; + + if (!mm_mbm_parse_cfun_test (response, &mask, error)) + return FALSE; /* Build list of combinations */ combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 3); /* 2G only */ - mode.allowed = MM_MODEM_MODE_2G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); + if (mask & (1 << MBM_NETWORK_MODE_2G)) { + mode.allowed = MM_MODEM_MODE_2G; + mode.preferred = MM_MODEM_MODE_NONE; + g_array_append_val (combinations, mode); + } + /* 3G only */ - mode.allowed = MM_MODEM_MODE_3G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); + if (mask & (1 << MBM_NETWORK_MODE_3G)) { + mode.allowed = MM_MODEM_MODE_3G; + mode.preferred = MM_MODEM_MODE_NONE; + g_array_append_val (combinations, mode); + } + /* 2G and 3G */ - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); + if (mask & (1 << MBM_NETWORK_MODE_ANY)) { + mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); + mode.preferred = MM_MODEM_MODE_NONE; + g_array_append_val (combinations, mode); + } - /* Filter out those unsupported modes */ - filtered = mm_filter_supported_modes (all, combinations); - g_array_unref (all); - g_array_unref (combinations); + if (combinations->len == 0) { + g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Couldn't load any supported mode"); + g_array_unref (combinations); + return NULL; + } - g_simple_async_result_set_op_res_gpointer (simple, filtered, (GDestroyNotify) g_array_unref); - g_simple_async_result_complete (simple); - g_object_unref (simple); + return combinations; } static void @@ -264,14 +255,12 @@ load_supported_modes (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { - /* Run parent's loading */ - iface_modem_parent->load_supported_modes ( - MM_IFACE_MODEM (self), - (GAsyncReadyCallback)parent_load_supported_modes_ready, - g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - load_supported_modes)); + mm_base_modem_at_command (MM_BASE_MODEM (self), + "+CFUN=?", + 3, + FALSE, + callback, + user_data); } /*****************************************************************************/ diff --git a/plugins/mbm/mm-modem-helpers-mbm.c b/plugins/mbm/mm-modem-helpers-mbm.c index 42653d884..55557f20c 100644 --- a/plugins/mbm/mm-modem-helpers-mbm.c +++ b/plugins/mbm/mm-modem-helpers-mbm.c @@ -89,7 +89,7 @@ mm_mbm_parse_e2ipcfg_response (const gchar *response, } /* *E2IPCFG: (1,<IP>)(2,<gateway>)(3,<DNS>)(3,<DNS>) - * + * * *E2IPCFG: (1,"46.157.32.246")(2,"46.157.32.243")(3,"193.213.112.4")(3,"130.67.15.198") * *E2IPCFG: (1,"fe80:0000:0000:0000:0000:0000:e537:1801")(3,"2001:4600:0004:0fff:0000:0000:0000:0054")(3,"2001:4600:0004:1fff:0000:0000:0000:0054") * *E2IPCFG: (1,"fe80:0000:0000:0000:0000:0027:b7fe:9401")(3,"fd00:976a:0000:0000:0000:0000:0000:0009") @@ -164,3 +164,101 @@ done: return !!*ip_config; } +/*****************************************************************************/ + +#define CFUN_TAG "+CFUN:" + +static void +add_supported_mode (guint32 *mask, + guint mode) +{ + g_assert (mask); + + if (mode >= 32) + g_warning ("Ignored unexpected mode in +CFUN match: %d", mode); + else + *mask |= (1 << mode); +} + +gboolean +mm_mbm_parse_cfun_test (const gchar *response, + guint32 *supported_mask, + GError **error) +{ + gchar **groups; + guint32 mask = 0; + + g_assert (supported_mask); + + if (!response || !g_str_has_prefix (response, CFUN_TAG)) { + g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Missing " CFUN_TAG " prefix"); + return FALSE; + } + + /* + * AT+CFUN=? + * +CFUN: (0,1,4-6),(0,1) + * OK + */ + + /* Strip tag from response */ + response = mm_strip_tag (response, CFUN_TAG); + + /* Split response in (groups) */ + groups = mm_split_string_groups (response); + + /* First group is the one listing supported modes */ + if (groups && groups[0]) { + gchar **supported_modes; + + supported_modes = g_strsplit_set (groups[0], ", ", -1); + if (supported_modes) { + guint i; + + for (i = 0; supported_modes[i]; i++) { + gchar *separator; + guint mode; + + if (!supported_modes[i][0]) + continue; + + /* Check if this is a range that's being given to us */ + separator = strchr (supported_modes[i], '-'); + if (separator) { + gchar *first_str; + gchar *last_str; + guint first; + guint last; + + *separator = '\0'; + first_str = supported_modes[i]; + last_str = separator + 1; + + if (!mm_get_uint_from_str (first_str, &first)) + g_warning ("Couldn't match range start: '%s'", first_str); + else if (!mm_get_uint_from_str (last_str, &last)) + g_warning ("Couldn't match range stop: '%s'", last_str); + else if (first >= last) + g_warning ("Couldn't match range: wrong first '%s' and last '%s' items", first_str, last_str); + else { + for (mode = first; mode <= last; mode++) + add_supported_mode (&mask, mode); + } + } else { + if (!mm_get_uint_from_str (supported_modes[i], &mode)) + g_warning ("Couldn't match mode: '%s'", supported_modes[i]); + else + add_supported_mode (&mask, mode); + } + } + + g_strfreev (supported_modes); + } + } + g_strfreev (groups); + + if (mask) + *supported_mask = mask; + return !!mask; +} diff --git a/plugins/mbm/mm-modem-helpers-mbm.h b/plugins/mbm/mm-modem-helpers-mbm.h index ef15845dc..7001cd64e 100644 --- a/plugins/mbm/mm-modem-helpers-mbm.h +++ b/plugins/mbm/mm-modem-helpers-mbm.h @@ -24,4 +24,18 @@ gboolean mm_mbm_parse_e2ipcfg_response (const gchar *response, MMBearerIpConfig **out_ip6_config, GError **error); +typedef enum { + MBM_NETWORK_MODE_OFFLINE = 0, + MBM_NETWORK_MODE_ANY = 1, + MBM_NETWORK_MODE_LOW_POWER = 4, + MBM_NETWORK_MODE_2G = 5, + MBM_NETWORK_MODE_3G = 6, +} MbmNetworkMode; + +/* AT+CFUN=? test parser + * Returns a bitmask, bit index set for the supported modes reported */ +gboolean mm_mbm_parse_cfun_test (const gchar *response, + guint32 *supported_mask, + GError **error); + #endif /* MM_MODEM_HELPERS_MBM_H */ diff --git a/plugins/mbm/tests/test-modem-helpers-mbm.c b/plugins/mbm/tests/test-modem-helpers-mbm.c index 0c48894b7..79a5dbe6d 100644 --- a/plugins/mbm/tests/test-modem-helpers-mbm.c +++ b/plugins/mbm/tests/test-modem-helpers-mbm.c @@ -28,6 +28,8 @@ #include "mm-modem-helpers.h" #include "mm-modem-helpers-mbm.h" +#define ENABLE_TEST_MESSAGE_TRACES + /*****************************************************************************/ /* Test *E2IPCFG responses */ @@ -47,7 +49,7 @@ typedef struct { } E2ipcfgTest; static const E2ipcfgTest tests[] = { - { "*E2IPCFG: (1,\"46.157.32.246\")(2,\"46.157.32.243\")(3,\"193.213.112.4\")(3,\"130.67.15.198\")\r\n", + { "*E2IPCFG: (1,\"46.157.32.246\")(2,\"46.157.32.243\")(3,\"193.213.112.4\")(3,\"130.67.15.198\")\r\n", "46.157.32.246", "46.157.32.243", "193.213.112.4", "130.67.15.198", NULL, NULL }, @@ -130,6 +132,63 @@ test_e2ipcfg (void) } /*****************************************************************************/ +/* Test +CFUN test responses */ + +#define MAX_MODES 32 + +typedef struct { + const gchar *str; + guint32 expected_mask; +} CfunTest; + +static const CfunTest cfun_tests[] = { + { + "+CFUN: (0,1,4-6),(1-0)\r\n", + ((1 << MBM_NETWORK_MODE_OFFLINE) | + (1 << MBM_NETWORK_MODE_ANY) | + (1 << MBM_NETWORK_MODE_LOW_POWER) | + (1 << MBM_NETWORK_MODE_2G) | + (1 << MBM_NETWORK_MODE_3G)) + }, + { + "+CFUN: (0,1,4-6)\r\n", + ((1 << MBM_NETWORK_MODE_OFFLINE) | + (1 << MBM_NETWORK_MODE_ANY) | + (1 << MBM_NETWORK_MODE_LOW_POWER) | + (1 << MBM_NETWORK_MODE_2G) | + (1 << MBM_NETWORK_MODE_3G)) + }, + { + "+CFUN: (0,1,4)\r\n", + ((1 << MBM_NETWORK_MODE_OFFLINE) | + (1 << MBM_NETWORK_MODE_ANY) | + (1 << MBM_NETWORK_MODE_LOW_POWER)) + }, + { + "+CFUN: (0,1)\r\n", + ((1 << MBM_NETWORK_MODE_OFFLINE) | + (1 << MBM_NETWORK_MODE_ANY)) + }, +}; + +static void +test_cfun (void) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (cfun_tests); i++) { + guint32 mask; + gboolean success; + GError *error = NULL; + + success = mm_mbm_parse_cfun_test (cfun_tests[i].str, &mask, &error); + g_assert_no_error (error); + g_assert (success); + g_assert_cmpuint (mask, ==, cfun_tests[i].expected_mask); + } +} + +/*****************************************************************************/ void _mm_log (const char *loc, @@ -159,6 +218,7 @@ int main (int argc, char **argv) g_test_init (&argc, &argv, NULL); g_test_add_func ("/MM/mbm/e2ipcfg", test_e2ipcfg); + g_test_add_func ("/MM/mbm/cfun", test_cfun); return g_test_run (); } diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 19fe81ef4..17ad8d28c 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -68,6 +68,69 @@ mm_strip_tag (const gchar *str, const gchar *cmd) /*****************************************************************************/ +gchar ** +mm_split_string_groups (const gchar *str) +{ + GPtrArray *array; + const gchar *start; + const gchar *next; + + array = g_ptr_array_new (); + + /* + * Manually parse splitting groups. Groups may be single elements, or otherwise + * lists given between parenthesis, e.g.: + * + * ("SM","ME"),("SM","ME"),("SM","ME") + * "SM","SM","SM" + * "SM",("SM","ME"),("SM","ME") + */ + + /* Iterate string splitting groups */ + for (start = str; start; start = next) { + gchar *item; + gssize len = -1; + + /* skip leading whitespaces */ + while (*start == ' ') + start++; + + if (*start == '(') { + start++; + next = strchr (start, ')'); + if (next) { + len = next - start; + next = strchr (next, ','); + if (next) + next++; + } + } else { + next = strchr (start, ','); + if (next) { + len = next - start; + next++; + } + } + + if (len < 0) + item = g_strdup (start); + else + item = g_strndup (start, len); + + g_ptr_array_add (array, item); + } + + if (array->len > 0) { + g_ptr_array_add (array, NULL); + return (gchar **) g_ptr_array_free (array, FALSE); + } + + g_ptr_array_unref (array); + return NULL; +} + +/*****************************************************************************/ + guint mm_count_bits_set (gulong number) { @@ -1290,67 +1353,6 @@ storage_from_str (const gchar *str) return MM_SMS_STORAGE_UNKNOWN; } -static gchar ** -helper_split_groups (const gchar *str) -{ - GPtrArray *array; - const gchar *start; - const gchar *next; - - array = g_ptr_array_new (); - - /* - * Manually parse splitting groups. Groups may be single elements, or otherwise - * lists given between parenthesis, e.g.: - * - * ("SM","ME"),("SM","ME"),("SM","ME") - * "SM","SM","SM" - * "SM",("SM","ME"),("SM","ME") - */ - - /* Iterate string splitting groups */ - for (start = str; start; start = next) { - gchar *item; - gssize len = -1; - - /* skip leading whitespaces */ - while (*start == ' ') - start++; - - if (*start == '(') { - start++; - next = strchr (start, ')'); - if (next) { - len = next - start; - next = strchr (next, ','); - if (next) - next++; - } - } else { - next = strchr (start, ','); - if (next) { - len = next - start; - next++; - } - } - - if (len < 0) - item = g_strdup (start); - else - item = g_strndup (start, len); - - g_ptr_array_add (array, item); - } - - if (array->len > 0) { - g_ptr_array_add (array, NULL); - return (gchar **) g_ptr_array_free (array, FALSE); - } - - g_ptr_array_unref (array); - return NULL; -} - gboolean mm_3gpp_parse_cpms_test_response (const gchar *reply, GArray **mem1, @@ -1370,7 +1372,7 @@ mm_3gpp_parse_cpms_test_response (const gchar *reply, #define N_EXPECTED_GROUPS 3 - split = helper_split_groups (mm_strip_tag (reply, "+CPMS:")); + split = mm_split_string_groups (mm_strip_tag (reply, "+CPMS:")); if (!split) return FALSE; diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index e92b6c0ac..3be7c7be5 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -51,6 +51,8 @@ gchar *mm_strip_quotes (gchar *str); const gchar *mm_strip_tag (const gchar *str, const gchar *cmd); +gchar **mm_split_string_groups (const gchar *str); + guint mm_count_bits_set (gulong number); gchar *mm_create_device_identifier (guint vid, |