From 7f014add61da3e0411d742756ce372fc0e2aee30 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 16 May 2025 11:16:57 -0500 Subject: broadband-modem,modem-helpers: generalize call end regex creation Signed-off-by: Dan Williams --- src/mm-broadband-modem.c | 3 +-- src/mm-modem-helpers.c | 14 ++++++++++++++ src/mm-modem-helpers.h | 6 ++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 41159a6c..e0f277fe 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -8473,8 +8473,7 @@ set_voice_in_call_unsolicited_events_handlers (MMBroadbandModem *self, g_autoptr(GRegex) in_call_event_regex = NULL; guint i; - in_call_event_regex = g_regex_new ("\\r\\n(NO CARRIER|BUSY|NO ANSWER|NO DIALTONE)(\\r)?\\r\\n$", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + in_call_event_regex = mm_call_end_regex_get (); ports[0] = MM_PORT_SERIAL_AT (ports_ctx->primary); ports[1] = MM_PORT_SERIAL_AT (ports_ctx->secondary); diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 926b1997..c6fa13fc 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -482,6 +482,20 @@ mm_at_quote_string (const gchar *input) /*****************************************************************************/ +GRegex * +mm_call_end_regex_get (void) +{ + /* Example: + * NO ANSWER + */ + return g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n", + G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW | G_REGEX_OPTIMIZE, + 0, + NULL); +} + +/*****************************************************************************/ + GRegex * mm_voice_ring_regex_get (void) { diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index 469492b2..73203c8b 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -85,6 +85,12 @@ gchar *mm_bcd_to_string (const guint8 *bcd, */ gchar *mm_at_quote_string (const gchar *input); +/*****************************************************************************/ +/* CALL specific helpers and utilities */ +/*****************************************************************************/ + +GRegex *mm_call_end_regex_get (void); + /*****************************************************************************/ /* VOICE specific helpers and utilities */ /*****************************************************************************/ -- cgit v1.2.3-70-g09d2 From 24f9309d6ecd559d24c54391fadef76cdbde1097 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 16 May 2025 11:19:59 -0500 Subject: serial-parsers,port-serial-at: move echo removal into serial parser Mainly because we need somewhere to stash the call end regex, and it's silly to have a 3rd instance of that in MMPortSerialAt when we already have one in the serial parsers that MMPortSerialAt relies on pretty heavily. Signed-off-by: Dan Williams --- src/mm-base-modem.c | 1 + src/mm-port-probe.c | 1 + src/mm-port-serial-at.c | 27 +++++------------------- src/mm-port-serial-at.h | 6 ++++-- src/mm-serial-parsers.c | 21 ++++++++++++++++++ src/mm-serial-parsers.h | 2 ++ src/plugins/wavecom/mm-broadband-modem-wavecom.c | 1 + src/tests/test-at-serial-port.c | 6 +++++- test/mmtty.c | 1 + 9 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c index eb7c04ca..3558775b 100644 --- a/src/mm-base-modem.c +++ b/src/mm-base-modem.c @@ -468,6 +468,7 @@ base_modem_internal_grab_port (MMBaseModem *self, if (MM_IS_PORT_SERIAL_AT (port)) { mm_port_serial_at_set_response_parser (MM_PORT_SERIAL_AT (port), mm_serial_parser_v1_parse, + mm_serial_parser_v1_remove_echo, mm_serial_parser_v1_new (), mm_serial_parser_v1_destroy); /* Prefer plugin-provided flags to the generic ones */ diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c index 6b53907b..b3bac90c 100644 --- a/src/mm-port-probe.c +++ b/src/mm-port-probe.c @@ -1434,6 +1434,7 @@ serial_open_at (MMPortProbe *self) NULL); mm_port_serial_at_set_response_parser (MM_PORT_SERIAL_AT (ctx->serial), mm_serial_parser_v1_parse, + mm_serial_parser_v1_remove_echo, parser, mm_serial_parser_v1_destroy); } diff --git a/src/mm-port-serial-at.c b/src/mm-port-serial-at.c index 90c0af70..ca2cc540 100644 --- a/src/mm-port-serial-at.c +++ b/src/mm-port-serial-at.c @@ -42,6 +42,7 @@ enum { struct _MMPortSerialAtPrivate { /* Response parser data */ MMPortSerialAtResponseParserFn response_parser_fn; + MMPortSerialAtRemoveEchoFn remove_echo_fn; gpointer response_parser_user_data; GDestroyNotify response_parser_notify; @@ -61,6 +62,7 @@ struct _MMPortSerialAtPrivate { void mm_port_serial_at_set_response_parser (MMPortSerialAt *self, MMPortSerialAtResponseParserFn fn, + MMPortSerialAtRemoveEchoFn echo_fn, gpointer user_data, GDestroyNotify notify) { @@ -70,30 +72,11 @@ mm_port_serial_at_set_response_parser (MMPortSerialAt *self, self->priv->response_parser_notify (self->priv->response_parser_user_data); self->priv->response_parser_fn = fn; + self->priv->remove_echo_fn = echo_fn; self->priv->response_parser_user_data = user_data; self->priv->response_parser_notify = notify; } -void -mm_port_serial_at_remove_echo (GByteArray *response) -{ - guint i; - - if (response->len <= 2) - return; - - for (i = 0; i < (response->len - 1); i++) { - /* If there is any content before the first - * , assume it's echo or garbage, and skip it */ - if (response->data[i] == '\r' && response->data[i + 1] == '\n') { - if (i > 0) - g_byte_array_remove_range (response, 0, i); - /* else, good, we're already started with */ - break; - } - } -} - static MMPortSerialResponseType parse_response (MMPortSerial *port, GByteArray *response, @@ -109,7 +92,7 @@ parse_response (MMPortSerial *port, /* Remove echo */ if (self->priv->remove_echo) - mm_port_serial_at_remove_echo (response); + self->priv->remove_echo_fn (self->priv->response_parser_user_data, response); /* If there's no response to receive, we're done; e.g. if we only got * unsolicited messages */ @@ -243,7 +226,7 @@ parse_unsolicited (MMPortSerial *port, GByteArray *response) /* Remove echo */ if (self->priv->remove_echo) - mm_port_serial_at_remove_echo (response); + self->priv->remove_echo_fn (self->priv->response_parser_user_data, response); for (iter = self->priv->unsolicited_msg_handlers; iter; iter = iter->next) { MMAtUnsolicitedMsgHandler *handler = (MMAtUnsolicitedMsgHandler *) iter->data; diff --git a/src/mm-port-serial-at.h b/src/mm-port-serial-at.h index 9ed6a218..8377d8da 100644 --- a/src/mm-port-serial-at.h +++ b/src/mm-port-serial-at.h @@ -65,6 +65,9 @@ typedef void (*MMPortSerialAtUnsolicitedMsgFn) (MMPortSerialAt *port, GMatchInfo *match_info, gpointer user_data); +typedef void (*MMPortSerialAtRemoveEchoFn) (gpointer user_data, + GByteArray *response); + #define MM_PORT_SERIAL_AT_REMOVE_ECHO "remove-echo" #define MM_PORT_SERIAL_AT_INIT_SEQUENCE_ENABLED "init-sequence-enabled" #define MM_PORT_SERIAL_AT_INIT_SEQUENCE "init-sequence" @@ -97,6 +100,7 @@ void mm_port_serial_at_enable_unsolicited_msg_handler (MMPortSerialAt *self, void mm_port_serial_at_set_response_parser (MMPortSerialAt *self, MMPortSerialAtResponseParserFn fn, + MMPortSerialAtRemoveEchoFn echo_fn, gpointer user_data, GDestroyNotify notify); @@ -113,8 +117,6 @@ gchar *mm_port_serial_at_command_finish (MMPortSerialAt *self, GError **error); /* Just for unit tests */ -void mm_port_serial_at_remove_echo (GByteArray *response); - void mm_port_serial_at_set_flags (MMPortSerialAt *self, MMPortSerialAtFlag flags); diff --git a/src/mm-serial-parsers.c b/src/mm-serial-parsers.c index a577faee..d8dc1e5d 100644 --- a/src/mm-serial-parsers.c +++ b/src/mm-serial-parsers.c @@ -160,6 +160,27 @@ mm_serial_parser_v1_add_filter (gpointer data, parser->filter_user_data = user_data; } +void +mm_serial_parser_v1_remove_echo (gpointer data, + GByteArray *response) +{ + guint i; + + if (response->len <= 2) + return; + + for (i = 0; i < (response->len - 1); i++) { + /* If there is any content before the first + * , assume it's echo or garbage, and skip it */ + if (response->data[i] == '\r' && response->data[i + 1] == '\n') { + if (i > 0) + g_byte_array_remove_range (response, 0, i); + /* else, good, we're already started with */ + break; + } + } +} + gboolean mm_serial_parser_v1_parse (gpointer data, GString *response, diff --git a/src/mm-serial-parsers.h b/src/mm-serial-parsers.h index 523597b9..268f03f7 100644 --- a/src/mm-serial-parsers.h +++ b/src/mm-serial-parsers.h @@ -26,6 +26,8 @@ gboolean mm_serial_parser_v1_parse (gpointer parser, GString *response, gpointer log_object, GError **error); +void mm_serial_parser_v1_remove_echo (gpointer parser, + GByteArray *response); void mm_serial_parser_v1_destroy (gpointer parser); gboolean mm_serial_parser_v1_is_known_error (const GError *error); diff --git a/src/plugins/wavecom/mm-broadband-modem-wavecom.c b/src/plugins/wavecom/mm-broadband-modem-wavecom.c index 99930110..7220df74 100644 --- a/src/plugins/wavecom/mm-broadband-modem-wavecom.c +++ b/src/plugins/wavecom/mm-broadband-modem-wavecom.c @@ -1245,6 +1245,7 @@ setup_ports (MMBroadbandModem *self) mm_port_serial_at_set_response_parser (MM_PORT_SERIAL_AT (primary), mm_serial_parser_v1_parse, + mm_serial_parser_v1_remove_echo, parser, mm_serial_parser_v1_destroy); } diff --git a/src/tests/test-at-serial-port.c b/src/tests/test-at-serial-port.c index 5372c478..5592971d 100644 --- a/src/tests/test-at-serial-port.c +++ b/src/tests/test-at-serial-port.c @@ -89,6 +89,7 @@ at_serial_echo_removal (void) guint i; for (i = 0; i < G_N_ELEMENTS (echo_removal_tests); i++) { + gpointer parser; GByteArray *ba; /* Note that we add last NUL also to the byte array, so that we can compare @@ -98,7 +99,9 @@ at_serial_echo_removal (void) (guint8 *)echo_removal_tests[i].original, strlen (echo_removal_tests[i].original) + 1); - mm_port_serial_at_remove_echo (ba); + parser = mm_serial_parser_v1_new (); + mm_serial_parser_v1_remove_echo (parser, ba); + mm_serial_parser_v1_destroy (parser); g_assert_cmpstr ((gchar *)ba->data, ==, echo_removal_tests[i].without_echo); @@ -119,6 +122,7 @@ _run_parse_test (const ParseResponseTest tests[], guint number_of_tests) parser = mm_serial_parser_v1_new (); response = g_string_new (tests[i].response); found = mm_serial_parser_v1_parse (parser, response, NULL, &error); + mm_serial_parser_v1_destroy (parser); /* Verify if we expect a match or not */ g_assert_cmpint (found, ==, tests[i].found); diff --git a/test/mmtty.c b/test/mmtty.c index db22c268..42cc826f 100644 --- a/test/mmtty.c +++ b/test/mmtty.c @@ -237,6 +237,7 @@ start_cb (void) /* Set common response parser */ mm_port_serial_at_set_response_parser (MM_PORT_SERIAL_AT (port), mm_serial_parser_v1_parse, + mm_serial_parser_v1_remove_echo, mm_serial_parser_v1_new (), mm_serial_parser_v1_destroy); -- cgit v1.2.3-70-g09d2 From c3c6fdc55e5a45f9bf0611ec0925fd0702aff316 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 16 May 2025 11:21:01 -0500 Subject: serial-parsers: don't echo-remove strange call start/end URCs Some Sierra devices omit the leading from call start/end URCs like NO CARRIER and CONNECT, which caused the echo-removal code to remove from the response buffer because the leading did not exist. That can break call control and hangup handling on those devices. Signed-off-by: Dan Williams --- src/mm-modem-helpers.c | 6 +++++- src/mm-serial-parsers.c | 36 ++++++++++++++++++++++++++++++++---- src/tests/test-at-serial-port.c | 2 ++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index c6fa13fc..d69951be 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -487,8 +487,12 @@ mm_call_end_regex_get (void) { /* Example: * NO ANSWER + * NO CARRIER + * BUSY + * + * Some Sierra devices omit the leading for in-call responses. */ - return g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n", + return g_regex_new ("(\\r)?\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n", G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); diff --git a/src/mm-serial-parsers.c b/src/mm-serial-parsers.c index d8dc1e5d..0823afac 100644 --- a/src/mm-serial-parsers.c +++ b/src/mm-serial-parsers.c @@ -17,8 +17,11 @@ #include #include +#define _LIBMM_INSIDE_MM + #include "mm-error-helpers.h" #include "mm-serial-parsers.h" +#include "mm-modem-helpers.h" #include "mm-log-object.h" /* Clean up the response by removing control characters like etc */ @@ -92,7 +95,8 @@ typedef struct { GRegex *regex_cms_error_str; GRegex *regex_ezx_error; GRegex *regex_unknown_error; - GRegex *regex_connect_failed; + GRegex *regex_call_start; + GRegex *regex_call_end; GRegex *regex_na; GRegex *regex_custom_error; /* User-provided parser filter */ @@ -117,7 +121,8 @@ mm_serial_parser_v1_new (void) parser->regex_cms_error_str = g_regex_new ("\\r\\n\\+CMS ERROR:\\s*([^\\n\\r]+)\\r\\n", flags, 0, NULL); parser->regex_ezx_error = g_regex_new ("\\r\\nMODEM ERROR:\\s*(\\d+)\\r\\n", flags, 0, NULL); parser->regex_unknown_error = g_regex_new ("\\r\\n(ERROR)|(COMMAND NOT SUPPORT)\\r\\n", flags, 0, NULL); - parser->regex_connect_failed = g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n", flags, 0, NULL); + parser->regex_call_start = g_regex_new ("(\\r)?\\n(CONNECT)\\r\\n", flags, 0, NULL); + parser->regex_call_end = mm_call_end_regex_get (); /* Samsung Z810 may reply "NA" to report a not-available error */ parser->regex_na = g_regex_new ("\\r\\nNA\\r\\n", flags, 0, NULL); @@ -164,11 +169,33 @@ void mm_serial_parser_v1_remove_echo (gpointer data, GByteArray *response) { + MMSerialParserV1 *parser = (MMSerialParserV1 *) data; guint i; if (response->len <= 2) return; + /* Some devices omit the leading from call end responses which would + * otherwise fail the checks below and be removed. We want to leave + * them in the response. + */ + if (g_regex_match_full (parser->regex_call_end, + (const gchar *) response->data, + response->len, + 0, + 0, + NULL, + NULL)) + return; + if (g_regex_match_full (parser->regex_call_start, + (const gchar *) response->data, + response->len, + 0, + 0, + NULL, + NULL)) + return; + for (i = 0; i < (response->len - 1); i++) { /* If there is any content before the first * , assume it's echo or garbage, and skip it */ @@ -337,7 +364,7 @@ mm_serial_parser_v1_parse (gpointer data, g_clear_pointer (&match_info, g_match_info_free); /* Connection failures */ - found = g_regex_match_full (parser->regex_connect_failed, + found = g_regex_match_full (parser->regex_call_end, response->str, response->len, 0, 0, &match_info, NULL); if (found) { @@ -417,7 +444,8 @@ mm_serial_parser_v1_destroy (gpointer data) g_regex_unref (parser->regex_cms_error_str); g_regex_unref (parser->regex_ezx_error); g_regex_unref (parser->regex_unknown_error); - g_regex_unref (parser->regex_connect_failed); + g_regex_unref (parser->regex_call_start); + g_regex_unref (parser->regex_call_end); g_regex_unref (parser->regex_na); if (parser->regex_custom_successful) diff --git a/src/tests/test-at-serial-port.c b/src/tests/test-at-serial-port.c index 5592971d..bd608461 100644 --- a/src/tests/test-at-serial-port.c +++ b/src/tests/test-at-serial-port.c @@ -46,6 +46,8 @@ static const EchoRemovalTest echo_removal_tests[] = { { "echo echo\r\nthis is valid\r\nand so is this", "\r\nthis is valid\r\nand so is this" }, { "\r\nthis is valid\r\nand so is this", "\r\nthis is valid\r\nand so is this" }, { "\r\nthis is valid\r\nand so is this\r\n", "\r\nthis is valid\r\nand so is this\r\n" }, + { "\nNO CARRIER\r\n", "\nNO CARRIER\r\n" }, + { "\nCONNECT\r\n", "\nCONNECT\r\n" }, }; static const ParseResponseTest parse_ok_tests[] = { -- cgit v1.2.3-70-g09d2