[PATCH 1/8] helpers: new parser for AT+IFC=?

Aleksander Morgado aleksander at aleksander.es
Tue Apr 18 17:09:09 UTC 2017


On 25/03/17 19:32, Aleksander Morgado wrote:
> Instead of having the parser return separate list of supported flow
> controls for TE and TA, we simplify it by only returning those
> settings that apply to both TE and TA.
> 
> This logic isn't perfect either, though, as some settings (e.g. '3' in
> TE in some modems, specifying a different XON/XOFF behavior) may not
> have a corresponding setting in the other end.
> 
> The most common cases we care about (i.e. standard XON/XOFF, RTS/CTS)
> should be properly reported with this logic.
> ---

This has been merged to git master.

>  src/mm-modem-helpers.c         | 113 +++++++++++++++++++++++++++++++++++++++++
>  src/mm-modem-helpers.h         |  17 +++++++
>  src/tests/test-modem-helpers.c | 100 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 230 insertions(+)
> 
> diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
> index fc95e28f..587e6896 100644
> --- a/src/mm-modem-helpers.c
> +++ b/src/mm-modem-helpers.c
> @@ -525,6 +525,119 @@ mm_voice_clip_regex_get (void)
>  
>  /*************************************************************************/
>  
> +static MMFlowControl
> +flow_control_array_to_mask (GArray      *array,
> +                            const gchar *item)
> +{
> +    MMFlowControl mask = MM_FLOW_CONTROL_UNKNOWN;
> +    guint         i;
> +
> +    for (i = 0; i < array->len; i++) {
> +        guint mode;
> +
> +        mode = g_array_index (array, guint, i);
> +        switch (mode) {
> +            case 0:
> +                mm_dbg ("%s supports no flow control", item);
> +                mask |= MM_FLOW_CONTROL_NONE;
> +                break;
> +            case 1:
> +                mm_dbg ("%s supports XON/XOFF flow control", item);
> +                mask |= MM_FLOW_CONTROL_XON_XOFF;
> +                break;
> +            case 2:
> +                mm_dbg ("%s supports RTS/CTS flow control", item);
> +                mask |= MM_FLOW_CONTROL_RTS_CTS;
> +                break;
> +            default:
> +                break;
> +        }
> +    }
> +
> +    return mask;
> +}
> +
> +static MMFlowControl
> +flow_control_match_info_to_mask (GMatchInfo   *match_info,
> +                                 guint         index,
> +                                 const gchar  *item,
> +                                 GError      **error)
> +{
> +    MMFlowControl  mask  = MM_FLOW_CONTROL_UNKNOWN;
> +    gchar         *aux   = NULL;
> +    GArray        *array = NULL;
> +
> +    if (!(aux = mm_get_string_unquoted_from_match_info (match_info, index))) {
> +        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
> +                     "Error retrieving list of supported %s flow control methods", item);
> +        goto out;
> +    }
> +
> +    if (!(array = mm_parse_uint_list (aux, error))) {
> +        g_prefix_error (error, "Error parsing list of supported %s flow control methods: ", item);
> +        goto out;
> +    }
> +
> +    if ((mask = flow_control_array_to_mask (array, item)) == MM_FLOW_CONTROL_UNKNOWN) {
> +        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
> +                     "No known %s flow control method given", item);
> +        goto out;
> +    }
> +
> +out:
> +    g_clear_pointer (&aux,  g_free);
> +    g_clear_pointer (&array, g_array_unref);
> +
> +    return mask;
> +}
> +
> +MMFlowControl
> +mm_parse_ifc_test_response (const gchar  *response,
> +                            GError      **error)
> +{
> +    GRegex        *r;
> +    GError        *inner_error = NULL;
> +    GMatchInfo    *match_info  = NULL;
> +    MMFlowControl  te_mask     = MM_FLOW_CONTROL_UNKNOWN;
> +    MMFlowControl  ta_mask     = MM_FLOW_CONTROL_UNKNOWN;
> +    MMFlowControl  mask        = MM_FLOW_CONTROL_UNKNOWN;
> +
> +    r = g_regex_new ("(?:\\+IFC:)?\\s*\\((.*)\\),\\((.*)\\)(?:\\r\\n)?", 0, 0, NULL);
> +    g_assert (r != NULL);
> +
> +    g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
> +    if (inner_error)
> +        goto out;
> +
> +    if (!g_match_info_matches (match_info)) {
> +        inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't match response");
> +        goto out;
> +    }
> +
> +    /* Parse TE flow control methods */
> +    if ((te_mask = flow_control_match_info_to_mask (match_info, 1, "TE", &inner_error)) == MM_FLOW_CONTROL_UNKNOWN)
> +        goto out;
> +
> +    /* Parse TA flow control methods */
> +    if ((ta_mask = flow_control_match_info_to_mask (match_info, 2, "TA", &inner_error)) == MM_FLOW_CONTROL_UNKNOWN)
> +        goto out;
> +
> +    /* Only those methods in both TA and TE will be the ones we report */
> +    mask = te_mask & ta_mask;
> +
> +out:
> +
> +    g_clear_pointer (&match_info, g_match_info_free);
> +    g_regex_unref (r);
> +
> +    if (inner_error)
> +        g_propagate_error (error, inner_error);
> +
> +    return mask;
> +}
> +
> +/*************************************************************************/
> +
>  /* +CREG: <stat>                      (GSM 07.07 CREG=1 unsolicited) */
>  #define CREG1 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9])"
>  
> diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
> index 33af48b6..ea5ba422 100644
> --- a/src/mm-modem-helpers.h
> +++ b/src/mm-modem-helpers.h
> @@ -95,6 +95,23 @@ GRegex *mm_voice_cring_regex_get(void);
>  GRegex *mm_voice_clip_regex_get (void);
>  
>  /*****************************************************************************/
> +/* SERIAL specific helpers and utilities */
> +
> +/* AT+IFC=? response parser.
> + * For simplicity, we'll only consider flow control methods available in both
> + * TE and TA. */
> +
> +typedef enum {
> +    MM_FLOW_CONTROL_UNKNOWN   = 0,
> +    MM_FLOW_CONTROL_NONE      = 1 << 0,  /* IFC=0,0 */
> +    MM_FLOW_CONTROL_XON_XOFF  = 1 << 1,  /* IFC=1,1 */
> +    MM_FLOW_CONTROL_RTS_CTS   = 1 << 2,  /* IFC=2,2 */
> +} MMFlowControl;
> +
> +MMFlowControl mm_parse_ifc_test_response (const gchar  *response,
> +                                          GError      **error);
> +
> +/*****************************************************************************/
>  /* 3GPP specific helpers and utilities */
>  /*****************************************************************************/
>  
> diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
> index 1fc8c353..a6e2f655 100644
> --- a/src/tests/test-modem-helpers.c
> +++ b/src/tests/test-modem-helpers.c
> @@ -33,6 +33,93 @@
>      g_assert_cmpfloat (fabs (val1 - val2), <, tolerance)
>  
>  /*****************************************************************************/
> +/* Test IFC=? responses */
> +
> +static void
> +test_ifc_response (const gchar         *str,
> +                   const MMFlowControl  expected)
> +{
> +    MMFlowControl  mask;
> +    GError        *error = NULL;
> +
> +    mask = mm_parse_ifc_test_response (str, &error);
> +    g_assert_no_error (error);
> +    g_assert_cmpuint (mask, ==, expected);
> +}
> +
> +static void
> +test_ifc_response_all_simple (void)
> +{
> +    test_ifc_response ("+IFC (0,1,2),(0,1,2)", (MM_FLOW_CONTROL_NONE | MM_FLOW_CONTROL_XON_XOFF | MM_FLOW_CONTROL_RTS_CTS));
> +}
> +
> +static void
> +test_ifc_response_all_groups (void)
> +{
> +    test_ifc_response ("+IFC (0-2),(0-2)", (MM_FLOW_CONTROL_NONE | MM_FLOW_CONTROL_XON_XOFF | MM_FLOW_CONTROL_RTS_CTS));
> +}
> +
> +static void
> +test_ifc_response_none_only (void)
> +{
> +    test_ifc_response ("+IFC (0),(0)", MM_FLOW_CONTROL_NONE);
> +}
> +
> +static void
> +test_ifc_response_xon_xoff_only (void)
> +{
> +    test_ifc_response ("+IFC (1),(1)", MM_FLOW_CONTROL_XON_XOFF);
> +}
> +
> +static void
> +test_ifc_response_rts_cts_only (void)
> +{
> +    test_ifc_response ("+IFC (2),(2)", MM_FLOW_CONTROL_RTS_CTS);
> +}
> +
> +static void
> +test_ifc_response_no_xon_xoff (void)
> +{
> +    test_ifc_response ("+IFC (0,2),(0,2)", (MM_FLOW_CONTROL_NONE | MM_FLOW_CONTROL_RTS_CTS));
> +}
> +
> +static void
> +test_ifc_response_no_xon_xoff_in_ta (void)
> +{
> +    test_ifc_response ("+IFC (0,1,2),(0,2)", (MM_FLOW_CONTROL_NONE | MM_FLOW_CONTROL_RTS_CTS));
> +}
> +
> +static void
> +test_ifc_response_no_xon_xoff_in_te (void)
> +{
> +    test_ifc_response ("+IFC (0,2),(0,1,2)", (MM_FLOW_CONTROL_NONE | MM_FLOW_CONTROL_RTS_CTS));
> +}
> +
> +static void
> +test_ifc_response_no_rts_cts_simple (void)
> +{
> +    test_ifc_response ("+IFC (0,1),(0,1)", (MM_FLOW_CONTROL_NONE | MM_FLOW_CONTROL_XON_XOFF));
> +}
> +
> +static void
> +test_ifc_response_no_rts_cts_groups (void)
> +{
> +    test_ifc_response ("+IFC (0-1),(0-1)", (MM_FLOW_CONTROL_NONE | MM_FLOW_CONTROL_XON_XOFF));
> +}
> +
> +static void
> +test_ifc_response_all_simple_and_unknown (void)
> +{
> +    test_ifc_response ("+IFC (0,1,2,3),(0,1,2)", (MM_FLOW_CONTROL_NONE | MM_FLOW_CONTROL_XON_XOFF | MM_FLOW_CONTROL_RTS_CTS));
> +}
> +
> +static void
> +test_ifc_response_all_groups_and_unknown (void)
> +{
> +    test_ifc_response ("+IFC (0-3),(0-2)", (MM_FLOW_CONTROL_NONE | MM_FLOW_CONTROL_XON_XOFF | MM_FLOW_CONTROL_RTS_CTS));
> +}
> +
> +/*****************************************************************************/
>  /* Test WS46=? responses */
>  
>  static void
> @@ -3488,6 +3575,19 @@ int main (int argc, char **argv)
>      suite = g_test_get_root ();
>      reg_data = reg_test_data_new ();
>  
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_all_simple, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_all_groups, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_none_only, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_xon_xoff_only, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_rts_cts_only, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_no_xon_xoff, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_no_xon_xoff_in_ta, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_no_xon_xoff_in_te, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_no_rts_cts_simple, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_no_rts_cts_groups, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_all_simple_and_unknown, NULL));
> +    g_test_suite_add (suite, TESTCASE (test_ifc_response_all_groups_and_unknown, NULL));
> +
>      g_test_suite_add (suite, TESTCASE (test_ws46_response_generic_2g3g4g, NULL));
>      g_test_suite_add (suite, TESTCASE (test_ws46_response_generic_2g3g, NULL));
>      g_test_suite_add (suite, TESTCASE (test_ws46_response_generic_2g3g_v2, NULL));
> 


-- 
Aleksander
https://aleksander.es


More information about the ModemManager-devel mailing list