simtech: handle 'VOICE CALL' URCs
Just processing and parsing them for now, so that they don't interfere with other commands: $ sudo mmcli --call 1 --accept error: couldn't accept the call: 'GDBus.Error:org.freedesktop.ModemManager1.Error.Core.Failed: Couldn't accept the call: Unhandled response ' VOICE CALL: BEGIN''
This commit is contained in:
@@ -93,3 +93,58 @@ mm_simtech_call_info_list_free (GList *call_info_list)
|
|||||||
{
|
{
|
||||||
mm_3gpp_call_info_list_free (call_info_list);
|
mm_3gpp_call_info_list_free (call_info_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* <CR><LF>VOICE CALL: BEGIN<CR><LF>
|
||||||
|
* <CR><LF>VOICE CALL: END: 000041<CR><LF>
|
||||||
|
*/
|
||||||
|
GRegex *
|
||||||
|
mm_simtech_get_voice_call_urc_regex (void)
|
||||||
|
{
|
||||||
|
return g_regex_new ("\\r\\nVOICE CALL:\\s*([A-Z]+)(?::\\s*(\\d+))?\\r\\n",
|
||||||
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_simtech_parse_voice_call_urc (GMatchInfo *match_info,
|
||||||
|
gboolean *start_or_stop,
|
||||||
|
guint *duration,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GError *inner_error = NULL;
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
str = mm_get_string_unquoted_from_match_info (match_info, 1);
|
||||||
|
if (!str) {
|
||||||
|
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||||
|
"Couldn't read voice call URC action");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (str, "BEGIN") == 0) {
|
||||||
|
*start_or_stop = TRUE;
|
||||||
|
*duration = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (str, "END") == 0) {
|
||||||
|
*start_or_stop = FALSE;
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 2, duration))
|
||||||
|
*duration = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||||
|
"Unknown voice call URC action: %s", str);
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_free (str);
|
||||||
|
if (inner_error) {
|
||||||
|
g_propagate_error (error, inner_error);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
@@ -36,4 +36,13 @@ gboolean mm_simtech_parse_clcc_list (const gchar *str,
|
|||||||
GError **error);
|
GError **error);
|
||||||
void mm_simtech_call_info_list_free (GList *call_info_list);
|
void mm_simtech_call_info_list_free (GList *call_info_list);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* VOICE CALL URC helpers */
|
||||||
|
|
||||||
|
GRegex *mm_simtech_get_voice_call_urc_regex (void);
|
||||||
|
gboolean mm_simtech_parse_voice_call_urc (GMatchInfo *match_info,
|
||||||
|
gboolean *start_or_stop,
|
||||||
|
guint *duration,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
#endif /* MM_MODEM_HELPERS_SIMTECH_H */
|
#endif /* MM_MODEM_HELPERS_SIMTECH_H */
|
||||||
|
@@ -52,11 +52,13 @@ typedef struct {
|
|||||||
MMIfaceModemVoice *iface_modem_voice_parent;
|
MMIfaceModemVoice *iface_modem_voice_parent;
|
||||||
FeatureSupport clcc_urc_support;
|
FeatureSupport clcc_urc_support;
|
||||||
GRegex *clcc_urc_regex;
|
GRegex *clcc_urc_regex;
|
||||||
|
GRegex *voice_call_regex;
|
||||||
} Private;
|
} Private;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
private_free (Private *ctx)
|
private_free (Private *ctx)
|
||||||
{
|
{
|
||||||
|
g_regex_unref (ctx->voice_call_regex);
|
||||||
g_regex_unref (ctx->clcc_urc_regex);
|
g_regex_unref (ctx->clcc_urc_regex);
|
||||||
g_slice_free (Private, ctx);
|
g_slice_free (Private, ctx);
|
||||||
}
|
}
|
||||||
@@ -77,6 +79,7 @@ get_private (MMSharedSimtech *self)
|
|||||||
priv->cgps_support = FEATURE_SUPPORT_UNKNOWN;
|
priv->cgps_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
priv->clcc_urc_support = FEATURE_SUPPORT_UNKNOWN;
|
priv->clcc_urc_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
priv->clcc_urc_regex = mm_simtech_get_clcc_urc_regex ();
|
priv->clcc_urc_regex = mm_simtech_get_clcc_urc_regex ();
|
||||||
|
priv->voice_call_regex = mm_simtech_get_voice_call_urc_regex ();
|
||||||
|
|
||||||
/* Setup parent class' MMIfaceModemLocation and MMIfaceModemVoice */
|
/* Setup parent class' MMIfaceModemLocation and MMIfaceModemVoice */
|
||||||
|
|
||||||
@@ -798,6 +801,34 @@ clcc_urc_received (MMPortSerialAt *port,
|
|||||||
g_free (full);
|
g_free (full);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
voice_call_urc_received (MMPortSerialAt *port,
|
||||||
|
GMatchInfo *match_info,
|
||||||
|
MMSharedSimtech *self)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
gboolean start_or_stop = FALSE; /* start = TRUE, stop = FALSE */
|
||||||
|
guint duration = 0;
|
||||||
|
|
||||||
|
if (!mm_simtech_parse_voice_call_urc (match_info, &start_or_stop, &duration, &error)) {
|
||||||
|
mm_warn ("couldn't parse VOICE CALL URC: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_or_stop) {
|
||||||
|
mm_dbg ("voice call started");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duration) {
|
||||||
|
mm_dbg ("voice call finished (duration: %us)", duration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_dbg ("voice call finished");
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
common_voice_setup_cleanup_unsolicited_events (MMSharedSimtech *self,
|
common_voice_setup_cleanup_unsolicited_events (MMSharedSimtech *self,
|
||||||
gboolean enable)
|
gboolean enable)
|
||||||
@@ -808,10 +839,6 @@ common_voice_setup_cleanup_unsolicited_events (MMSharedSimtech *self,
|
|||||||
|
|
||||||
priv = get_private (MM_SHARED_SIMTECH (self));
|
priv = get_private (MM_SHARED_SIMTECH (self));
|
||||||
|
|
||||||
/* If +CLCC URCs not supported, we're done */
|
|
||||||
if (priv->clcc_urc_support == FEATURE_NOT_SUPPORTED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
|
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
|
||||||
ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
|
ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
|
||||||
|
|
||||||
@@ -819,9 +846,16 @@ common_voice_setup_cleanup_unsolicited_events (MMSharedSimtech *self,
|
|||||||
if (!ports[i])
|
if (!ports[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (priv->clcc_urc_support == FEATURE_SUPPORTED)
|
||||||
|
mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
|
||||||
|
priv->clcc_urc_regex,
|
||||||
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)clcc_urc_received : NULL,
|
||||||
|
enable ? self : NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
|
mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
|
||||||
priv->clcc_urc_regex,
|
priv->voice_call_regex,
|
||||||
enable ? (MMPortSerialAtUnsolicitedMsgFn)clcc_urc_received : NULL,
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)voice_call_urc_received : NULL,
|
||||||
enable ? self : NULL,
|
enable ? self : NULL,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
@@ -143,6 +143,56 @@ test_clcc_urc_complex (void)
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_test_voice_call_urc (const gchar *urc,
|
||||||
|
gboolean expected_start_or_stop,
|
||||||
|
guint expected_duration)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
gboolean start_or_stop = FALSE; /* start = TRUE, stop = FALSE */
|
||||||
|
guint duration = 0;
|
||||||
|
GRegex *voice_call_regex = NULL;
|
||||||
|
gboolean result;
|
||||||
|
GMatchInfo *match_info = NULL;
|
||||||
|
|
||||||
|
voice_call_regex = mm_simtech_get_voice_call_urc_regex ();
|
||||||
|
|
||||||
|
/* Same matching logic as done in MMSerialPortAt when processing URCs! */
|
||||||
|
result = g_regex_match_full (voice_call_regex, urc, -1, 0, 0, &match_info, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (result);
|
||||||
|
|
||||||
|
result = mm_simtech_parse_voice_call_urc (match_info, &start_or_stop, &duration, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (result);
|
||||||
|
|
||||||
|
g_assert_cmpuint (expected_start_or_stop, ==, start_or_stop);
|
||||||
|
g_assert_cmpuint (expected_duration, ==, duration);
|
||||||
|
|
||||||
|
g_match_info_free (match_info);
|
||||||
|
g_regex_unref (voice_call_regex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_voice_call_begin_urc (void)
|
||||||
|
{
|
||||||
|
common_test_voice_call_urc ("\r\nVOICE CALL: BEGIN\r\n", TRUE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_voice_call_end_urc (void)
|
||||||
|
{
|
||||||
|
common_test_voice_call_urc ("\r\nVOICE CALL: END\r\n", FALSE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_voice_call_end_duration_urc (void)
|
||||||
|
{
|
||||||
|
common_test_voice_call_urc ("\r\nVOICE CALL: END: 000041\r\n", FALSE, 41);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
_mm_log (const char *loc,
|
_mm_log (const char *loc,
|
||||||
const char *func,
|
const char *func,
|
||||||
@@ -173,5 +223,9 @@ int main (int argc, char **argv)
|
|||||||
g_test_add_func ("/MM/simtech/clcc/urc/multiple", test_clcc_urc_multiple);
|
g_test_add_func ("/MM/simtech/clcc/urc/multiple", test_clcc_urc_multiple);
|
||||||
g_test_add_func ("/MM/simtech/clcc/urc/complex", test_clcc_urc_complex);
|
g_test_add_func ("/MM/simtech/clcc/urc/complex", test_clcc_urc_complex);
|
||||||
|
|
||||||
|
g_test_add_func ("/MM/simtech/voicecall/urc/begin", test_voice_call_begin_urc);
|
||||||
|
g_test_add_func ("/MM/simtech/voicecall/urc/end", test_voice_call_end_urc);
|
||||||
|
g_test_add_func ("/MM/simtech/voicecall/urc/end-duration", test_voice_call_end_duration_urc);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user