[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