aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mm-modem-helpers.c113
-rw-r--r--src/mm-modem-helpers.h17
-rw-r--r--src/tests/test-modem-helpers.c100
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));