diff options
-rw-r--r-- | src/mm-modem-helpers.c | 113 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 17 | ||||
-rw-r--r-- | src/tests/test-modem-helpers.c | 100 |
3 files changed, 230 insertions, 0 deletions
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index b4556176..679f9252 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 a74924e3..bd10b940 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 ae0eec99..b59c5900 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 @@ -3536,6 +3623,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)); |