[PATCHv2] mbm: query supported modes to the modem with +CFUN=?
Dan Williams
dcbw at redhat.com
Mon Jan 4 12:02:59 PST 2016
On Mon, 2015-12-21 at 17:36 +0100, Aleksander Morgado wrote:
> We were trying to load the generic modes supported reported by either
> *CNTI=2 or
> AT+WS46=?, so that then we could filter out the MBM-specific modes
> unsupported.
LGTM; returns the right supported modes for my MD300 and TM-506.
Dan
> But, this may not be ideal, as both these two commands may fail:
>
> [mm-broadband-modem.c:1612] modem_load_supported_modes(): loading
> supported modes...
> [mm-port-serial.c:1237] mm_port_serial_open(): (ttyACM1) device
> open count is 3 (open)
> [mm-port-serial.c:1294] _close_internal(): (ttyACM1) device open
> count is 2 (close)
> [mm-port-serial-at.c:440] debug_log(): (ttyACM1): -->
> 'AT*CNTI=2<CR>'
> [mm-port-serial-at.c:440] debug_log(): (ttyACM1): <--
> '<CR><LF>ERROR<CR><LF>'
> [mm-serial-parsers.c:364] mm_serial_parser_v1_parse(): Got
> failure code 100: Unknown error
> [mm-broadband-modem.c:1546] supported_modes_cnti_ready(): Generic
> query of supported 3GPP networks with *CNTI failed: 'Unknown error'
> [mm-port-serial.c:1237] mm_port_serial_open(): (ttyACM1) device
> open count is 3 (open)
> [mm-port-serial.c:1294] _close_internal(): (ttyACM1) device open
> count is 2 (close)
> [mm-port-serial-at.c:440] debug_log(): (ttyACM1): -->
> 'AT+WS46=?<CR>'
> [mm-port-serial-at.c:440] debug_log(): (ttyACM1): <--
> '<CR><LF>ERROR<CR><LF>'
> [mm-serial-parsers.c:364] mm_serial_parser_v1_parse(): Got
> failure code 100: Unknown error
> [mm-broadband-modem.c:1494] supported_modes_ws46_test_ready():
> Generic query of supported 3GPP networks with WS46=? failed: 'Unknown
> error'
> [mm-iface-modem.c:3974] load_supported_modes_ready(): couldn't
> load Supported Modes: 'Couldn't retrieve supported modes'
>
> Instead, we'll ask the modem for the list of modes supported, and
> return that
> directly.
> ---
> plugins/mbm/mm-broadband-modem-mbm.c | 93 ++++++++++---------
> --
> plugins/mbm/mm-modem-helpers-mbm.c | 100
> ++++++++++++++++++++++-
> plugins/mbm/mm-modem-helpers-mbm.h | 14 ++++
> plugins/mbm/tests/test-modem-helpers-mbm.c | 62 +++++++++++++-
> src/mm-modem-helpers.c | 126 +++++++++++++++----
> ----------
> 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 fa291d6..dc480f8 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 42653d8..55557f2 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.1
> 5.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 ef15845..7001cd6 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 0c48894..79a5dbe 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,\"1
> 30.67.15.198\")\r\n",
> + { "*E2IPCFG:
> (1,\"46.157.32.246\")(2,\"46.157.32.243\")(3,\"193.213.112.4\")(3,\"1
> 30.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 19fe81e..17ad8d2 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 e92b6c0..3be7c7b 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,
> --
> 2.6.2
> _______________________________________________
> ModemManager-devel mailing list
> ModemManager-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/modemmanager-devel
More information about the ModemManager-devel
mailing list