[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