broadband-modem,voice: implement call waiting status setup/query with +CCWA
This commit is contained in:
@@ -7956,6 +7956,74 @@ modem_voice_transfer (MMIfaceModemVoice *self,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Call waiting setup (Voice interface) */
|
||||
|
||||
static gboolean
|
||||
modem_voice_call_waiting_setup_finish (MMIfaceModemVoice *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_voice_call_waiting_setup (MMIfaceModemVoice *self,
|
||||
gboolean enable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
gchar *cmd;
|
||||
|
||||
/* Enabling or disabling the call waiting service will only be allowed when
|
||||
* the modem is registered in the network, and so, CCWA URC handling will
|
||||
* always be setup at this point (as it's part of the modem enabling phase).
|
||||
* So, just enable or disable the service (second field) but leaving URCs
|
||||
* (first field) always enabled. */
|
||||
cmd = g_strdup_printf ("+CCWA=1,%u", enable);
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
cmd,
|
||||
60,
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Call waiting query (Voice interface) */
|
||||
|
||||
static gboolean
|
||||
modem_voice_call_waiting_query_finish (MMIfaceModemVoice *self,
|
||||
GAsyncResult *res,
|
||||
gboolean *status,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *response;
|
||||
|
||||
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
|
||||
if (!response)
|
||||
return FALSE;
|
||||
|
||||
return mm_3gpp_parse_ccwa_service_query_response (response, status, error);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_voice_call_waiting_query (MMIfaceModemVoice *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* This operation will only be allowed while enabled, and so, CCWA URC
|
||||
* handling would always be enabled at this point. So, just perform the
|
||||
* query, but leaving URCs enabled either way. */
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"+CCWA=1,2",
|
||||
60,
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ESN loading (CDMA interface) */
|
||||
|
||||
@@ -12196,6 +12264,10 @@ iface_modem_voice_init (MMIfaceModemVoice *iface)
|
||||
iface->leave_multiparty_finish = modem_voice_leave_multiparty_finish;
|
||||
iface->transfer = modem_voice_transfer;
|
||||
iface->transfer_finish = modem_voice_transfer_finish;
|
||||
iface->call_waiting_setup = modem_voice_call_waiting_setup;
|
||||
iface->call_waiting_setup_finish = modem_voice_call_waiting_setup_finish;
|
||||
iface->call_waiting_query = modem_voice_call_waiting_query;
|
||||
iface->call_waiting_query_finish = modem_voice_call_waiting_query_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -2723,6 +2723,85 @@ mm_3gpp_parse_cemode_query_response (const gchar *response,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* CCWA service query response parser */
|
||||
|
||||
gboolean
|
||||
mm_3gpp_parse_ccwa_service_query_response (const gchar *response,
|
||||
gboolean *status,
|
||||
GError **error)
|
||||
{
|
||||
GRegex *r;
|
||||
GError *inner_error = NULL;
|
||||
GMatchInfo *match_info = NULL;
|
||||
gint class_1_status = -1;
|
||||
|
||||
/*
|
||||
* AT+CCWA=<n>[,<mode>]
|
||||
* +CCWA: <status>,<class1>
|
||||
* [+CCWA: <status>,<class2>
|
||||
* [...]]
|
||||
* OK
|
||||
*
|
||||
* If <classX> is 255 it applies to ALL classes.
|
||||
*
|
||||
* We're only interested in class 1 (voice)
|
||||
*/
|
||||
r = g_regex_new ("\\+CCWA:\\s*(\\d+),\\s*(\\d+)$",
|
||||
G_REGEX_RAW | G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF,
|
||||
G_REGEX_MATCH_NEWLINE_CRLF,
|
||||
NULL);
|
||||
g_assert (r != NULL);
|
||||
|
||||
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
|
||||
if (inner_error)
|
||||
goto out;
|
||||
|
||||
/* Parse the results */
|
||||
while (g_match_info_matches (match_info)) {
|
||||
guint st;
|
||||
guint class;
|
||||
|
||||
if (!mm_get_uint_from_match_info (match_info, 2, &class))
|
||||
mm_warn ("couldn't parse class from +CCWA line");
|
||||
else if (class == 1 || class == 255) {
|
||||
if (!mm_get_uint_from_match_info (match_info, 1, &st))
|
||||
mm_warn ("couldn't parse status from +CCWA line");
|
||||
else {
|
||||
class_1_status = st;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_match_info_next (match_info, NULL);
|
||||
}
|
||||
|
||||
out:
|
||||
g_clear_pointer (&match_info, g_match_info_free);
|
||||
g_regex_unref (r);
|
||||
|
||||
if (inner_error) {
|
||||
g_propagate_error (error, inner_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (class_1_status < 0) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
|
||||
"call waiting status for voice class missing");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (class_1_status != 0 && class_1_status != 1) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
|
||||
"call waiting status for voice class invalid: %d", class_1_status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (status)
|
||||
*status = (gboolean) class_1_status;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static MMSmsStorage
|
||||
|
@@ -397,6 +397,12 @@ gboolean mm_3gpp_parse_cemode_query_response (const gchar *r
|
||||
MMModem3gppEpsUeModeOperation *out_mode,
|
||||
GError **error);
|
||||
|
||||
/* CCWA service query response parser */
|
||||
gboolean mm_3gpp_parse_ccwa_service_query_response (const gchar *response,
|
||||
gboolean *status,
|
||||
GError **error);
|
||||
|
||||
|
||||
/* Additional 3GPP-specific helpers */
|
||||
|
||||
MMModem3gppFacility mm_3gpp_acronym_to_facility (const gchar *str);
|
||||
|
@@ -4018,6 +4018,63 @@ test_ccwa_indication (void)
|
||||
g_regex_unref (r);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* +CCWA service query response testing */
|
||||
|
||||
static void
|
||||
common_test_ccwa_response (const gchar *response,
|
||||
gboolean expected_status,
|
||||
gboolean expected_error)
|
||||
{
|
||||
gboolean status = FALSE;
|
||||
GError *error = NULL;
|
||||
gboolean result;
|
||||
|
||||
result = mm_3gpp_parse_ccwa_service_query_response (response, &status, &error);
|
||||
|
||||
if (expected_error) {
|
||||
g_assert (!result);
|
||||
g_assert (error);
|
||||
g_error_free (error);
|
||||
} else {
|
||||
g_assert (result);
|
||||
g_assert_no_error (error);
|
||||
g_assert_cmpuint (status, ==, expected_status);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const gchar *response;
|
||||
gboolean expected_status;
|
||||
gboolean expected_error;
|
||||
} TestCcwa;
|
||||
|
||||
static TestCcwa test_ccwa[] = {
|
||||
{ "+CCWA: 0,255", FALSE, FALSE }, /* all disabled */
|
||||
{ "+CCWA: 1,255", TRUE, FALSE }, /* all enabled */
|
||||
{ "+CCWA: 0,1\r\n"
|
||||
"+CCWA: 0,4\r\n", FALSE, FALSE }, /* voice and fax disabled */
|
||||
{ "+CCWA: 1,1\r\n"
|
||||
"+CCWA: 1,4\r\n", TRUE, FALSE }, /* voice and fax enabled */
|
||||
{ "+CCWA: 0,2\r\n"
|
||||
"+CCWA: 0,4\r\n"
|
||||
"+CCWA: 0,8\r\n", FALSE, TRUE }, /* data, fax, sms disabled, voice not given */
|
||||
{ "+CCWA: 1,2\r\n"
|
||||
"+CCWA: 1,4\r\n"
|
||||
"+CCWA: 1,8\r\n", FALSE, TRUE }, /* data, fax, sms enabled, voice not given */
|
||||
{ "+CCWA: 2,1\r\n"
|
||||
"+CCWA: 2,4\r\n", FALSE, TRUE }, /* voice and fax enabled but unexpected state */
|
||||
};
|
||||
|
||||
static void
|
||||
test_ccwa_response (void)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_ccwa); i++)
|
||||
common_test_ccwa_response (test_ccwa[i].response, test_ccwa[i].expected_status, test_ccwa[i].expected_error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Test +CLCC URCs */
|
||||
|
||||
@@ -4435,6 +4492,7 @@ int main (int argc, char **argv)
|
||||
|
||||
g_test_suite_add (suite, TESTCASE (test_clip_indication, NULL));
|
||||
g_test_suite_add (suite, TESTCASE (test_ccwa_indication, NULL));
|
||||
g_test_suite_add (suite, TESTCASE (test_ccwa_response, NULL));
|
||||
|
||||
g_test_suite_add (suite, TESTCASE (test_clcc_response_empty, NULL));
|
||||
g_test_suite_add (suite, TESTCASE (test_clcc_response_single, NULL));
|
||||
|
Reference in New Issue
Block a user