cinterion: support ^SLCC URCs as part of voice management
This command will give us URCs whenever the extended list of current calls changes, which includes information about the actual state of each call, even for calls in waiting state. Therefore, as this is a URC that applies to all calls, it's enabled and disabled as part of the modem voice interface, instead of doing it as part of the call object itself (i.e. not treated as an in-call URC).
This commit is contained in:
@@ -34,6 +34,7 @@
|
|||||||
#include "mm-iface-modem-3gpp.h"
|
#include "mm-iface-modem-3gpp.h"
|
||||||
#include "mm-iface-modem-messaging.h"
|
#include "mm-iface-modem-messaging.h"
|
||||||
#include "mm-iface-modem-location.h"
|
#include "mm-iface-modem-location.h"
|
||||||
|
#include "mm-iface-modem-voice.h"
|
||||||
#include "mm-base-modem-at.h"
|
#include "mm-base-modem-at.h"
|
||||||
#include "mm-broadband-modem-cinterion.h"
|
#include "mm-broadband-modem-cinterion.h"
|
||||||
#include "mm-modem-helpers-cinterion.h"
|
#include "mm-modem-helpers-cinterion.h"
|
||||||
@@ -44,17 +45,20 @@ static void iface_modem_init (MMIfaceModem *iface);
|
|||||||
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
||||||
static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
|
static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
|
||||||
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
||||||
|
static void iface_modem_voice_init (MMIfaceModemVoice *iface);
|
||||||
static void shared_cinterion_init (MMSharedCinterion *iface);
|
static void shared_cinterion_init (MMSharedCinterion *iface);
|
||||||
|
|
||||||
static MMIfaceModem *iface_modem_parent;
|
static MMIfaceModem *iface_modem_parent;
|
||||||
static MMIfaceModem3gpp *iface_modem_3gpp_parent;
|
static MMIfaceModem3gpp *iface_modem_3gpp_parent;
|
||||||
static MMIfaceModemLocation *iface_modem_location_parent;
|
static MMIfaceModemLocation *iface_modem_location_parent;
|
||||||
|
static MMIfaceModemVoice *iface_modem_voice_parent;
|
||||||
|
|
||||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion, MM_TYPE_BROADBAND_MODEM, 0,
|
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion, MM_TYPE_BROADBAND_MODEM, 0,
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
|
||||||
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init)
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init))
|
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init))
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -1956,10 +1960,32 @@ peek_parent_location_interface (MMSharedCinterion *self)
|
|||||||
return iface_modem_location_parent;
|
return iface_modem_location_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iface_modem_voice_init (MMIfaceModemVoice *iface)
|
||||||
|
{
|
||||||
|
iface_modem_voice_parent = g_type_interface_peek_parent (iface);
|
||||||
|
|
||||||
|
iface->enable_unsolicited_events = mm_shared_cinterion_voice_enable_unsolicited_events;
|
||||||
|
iface->enable_unsolicited_events_finish = mm_shared_cinterion_voice_enable_unsolicited_events_finish;
|
||||||
|
iface->disable_unsolicited_events = mm_shared_cinterion_voice_disable_unsolicited_events;
|
||||||
|
iface->disable_unsolicited_events_finish = mm_shared_cinterion_voice_disable_unsolicited_events_finish;
|
||||||
|
iface->setup_unsolicited_events = mm_shared_cinterion_voice_setup_unsolicited_events;
|
||||||
|
iface->setup_unsolicited_events_finish = mm_shared_cinterion_voice_setup_unsolicited_events_finish;
|
||||||
|
iface->cleanup_unsolicited_events = mm_shared_cinterion_voice_cleanup_unsolicited_events;
|
||||||
|
iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_voice_cleanup_unsolicited_events_finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MMIfaceModemVoice *
|
||||||
|
peek_parent_voice_interface (MMSharedCinterion *self)
|
||||||
|
{
|
||||||
|
return iface_modem_voice_parent;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
shared_cinterion_init (MMSharedCinterion *iface)
|
shared_cinterion_init (MMSharedCinterion *iface)
|
||||||
{
|
{
|
||||||
iface->peek_parent_location_interface = peek_parent_location_interface;
|
iface->peek_parent_location_interface = peek_parent_location_interface;
|
||||||
|
iface->peek_parent_voice_interface = peek_parent_voice_interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -26,16 +26,20 @@
|
|||||||
#include "mm-log.h"
|
#include "mm-log.h"
|
||||||
#include "mm-errors-types.h"
|
#include "mm-errors-types.h"
|
||||||
#include "mm-iface-modem-location.h"
|
#include "mm-iface-modem-location.h"
|
||||||
|
#include "mm-iface-modem-voice.h"
|
||||||
#include "mm-broadband-modem-qmi-cinterion.h"
|
#include "mm-broadband-modem-qmi-cinterion.h"
|
||||||
#include "mm-shared-cinterion.h"
|
#include "mm-shared-cinterion.h"
|
||||||
|
|
||||||
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
||||||
|
static void iface_modem_voice_init (MMIfaceModemVoice *iface);
|
||||||
static void shared_cinterion_init (MMSharedCinterion *iface);
|
static void shared_cinterion_init (MMSharedCinterion *iface);
|
||||||
|
|
||||||
static MMIfaceModemLocation *iface_modem_location_parent;
|
static MMIfaceModemLocation *iface_modem_location_parent;
|
||||||
|
static MMIfaceModemVoice *iface_modem_voice_parent;
|
||||||
|
|
||||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmiCinterion, mm_broadband_modem_qmi_cinterion, MM_TYPE_BROADBAND_MODEM_QMI, 0,
|
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmiCinterion, mm_broadband_modem_qmi_cinterion, MM_TYPE_BROADBAND_MODEM_QMI, 0,
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
|
||||||
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init)
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init))
|
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init))
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -80,10 +84,32 @@ peek_parent_location_interface (MMSharedCinterion *self)
|
|||||||
return iface_modem_location_parent;
|
return iface_modem_location_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iface_modem_voice_init (MMIfaceModemVoice *iface)
|
||||||
|
{
|
||||||
|
iface_modem_voice_parent = g_type_interface_peek_parent (iface);
|
||||||
|
|
||||||
|
iface->enable_unsolicited_events = mm_shared_cinterion_voice_enable_unsolicited_events;
|
||||||
|
iface->enable_unsolicited_events_finish = mm_shared_cinterion_voice_enable_unsolicited_events_finish;
|
||||||
|
iface->disable_unsolicited_events = mm_shared_cinterion_voice_disable_unsolicited_events;
|
||||||
|
iface->disable_unsolicited_events_finish = mm_shared_cinterion_voice_disable_unsolicited_events_finish;
|
||||||
|
iface->setup_unsolicited_events = mm_shared_cinterion_voice_setup_unsolicited_events;
|
||||||
|
iface->setup_unsolicited_events_finish = mm_shared_cinterion_voice_setup_unsolicited_events_finish;
|
||||||
|
iface->cleanup_unsolicited_events = mm_shared_cinterion_voice_cleanup_unsolicited_events;
|
||||||
|
iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_voice_cleanup_unsolicited_events_finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MMIfaceModemVoice *
|
||||||
|
peek_parent_voice_interface (MMSharedCinterion *self)
|
||||||
|
{
|
||||||
|
return iface_modem_voice_parent;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
shared_cinterion_init (MMSharedCinterion *iface)
|
shared_cinterion_init (MMSharedCinterion *iface)
|
||||||
{
|
{
|
||||||
iface->peek_parent_location_interface = peek_parent_location_interface;
|
iface->peek_parent_location_interface = peek_parent_location_interface;
|
||||||
|
iface->peek_parent_voice_interface = peek_parent_voice_interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -667,3 +667,131 @@ mm_cinterion_get_access_technology_from_sind_psinfo (guint val)
|
|||||||
return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
|
return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* ^SLCC psinfo helper */
|
||||||
|
|
||||||
|
GRegex *
|
||||||
|
mm_cinterion_get_slcc_regex (void)
|
||||||
|
{
|
||||||
|
/* The list of active calls displayed with this URC will always be terminated
|
||||||
|
* with an empty line preceded by prefix "^SLCC: ", in order to indicate the end
|
||||||
|
* of the list.
|
||||||
|
*/
|
||||||
|
return g_regex_new ("\\r\\n(\\^SLCC: .*\\r\\n)*\\^SLCC: \\r\\n",
|
||||||
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cinterion_call_info_free (MMCallInfo *info)
|
||||||
|
{
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
g_free (info->number);
|
||||||
|
g_slice_free (MMCallInfo, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_cinterion_parse_slcc_list (const gchar *str,
|
||||||
|
GList **out_list,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GRegex *r;
|
||||||
|
GList *list = NULL;
|
||||||
|
GError *inner_error = NULL;
|
||||||
|
GMatchInfo *match_info = NULL;
|
||||||
|
|
||||||
|
static const MMCallDirection cinterion_call_direction[] = {
|
||||||
|
[0] = MM_CALL_DIRECTION_OUTGOING,
|
||||||
|
[1] = MM_CALL_DIRECTION_INCOMING,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const MMCallState cinterion_call_state[] = {
|
||||||
|
[0] = MM_CALL_STATE_ACTIVE,
|
||||||
|
[1] = MM_CALL_STATE_HELD,
|
||||||
|
[2] = MM_CALL_STATE_DIALING, /* Dialing (MOC) */
|
||||||
|
[3] = MM_CALL_STATE_RINGING_OUT, /* Alerting (MOC) */
|
||||||
|
[4] = MM_CALL_STATE_RINGING_IN, /* Incoming (MTC) */
|
||||||
|
[5] = MM_CALL_STATE_WAITING, /* Waiting (MTC) */
|
||||||
|
};
|
||||||
|
|
||||||
|
g_assert (out_list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1 2 3 4 5 6 7 8 9
|
||||||
|
* ^SLCC: <idx>, <dir>, <stat>, <mode>, <mpty>, <Reserved>[, <number>, <type>[,<alpha>]]
|
||||||
|
* [^SLCC: <idx>, <dir>, <stat>, <mode>, <mpty>, <Reserved>[, <number>, <type>[,<alpha>]]]
|
||||||
|
* [... ]
|
||||||
|
* ^SLCC :
|
||||||
|
*/
|
||||||
|
|
||||||
|
r = g_regex_new ("\\^SLCC:\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)" /* mandatory fields */
|
||||||
|
"(?:,\\s*([^,]*),\\s*(\\d+)" /* number and type */
|
||||||
|
"(?:,\\s*([^,]*)" /* alpha */
|
||||||
|
")?)?$",
|
||||||
|
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, str, strlen (str), 0, 0, &match_info, &inner_error);
|
||||||
|
if (inner_error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Parse the results */
|
||||||
|
while (g_match_info_matches (match_info)) {
|
||||||
|
MMCallInfo *call_info;
|
||||||
|
guint aux;
|
||||||
|
|
||||||
|
call_info = g_slice_new0 (MMCallInfo);
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 1, &call_info->index)) {
|
||||||
|
mm_warn ("couldn't parse call index from ^SLCC line");
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 2, &aux) ||
|
||||||
|
(aux >= G_N_ELEMENTS (cinterion_call_direction))) {
|
||||||
|
mm_warn ("couldn't parse call direction from ^SLCC line");
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
call_info->direction = cinterion_call_direction[aux];
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 3, &aux) ||
|
||||||
|
(aux >= G_N_ELEMENTS (cinterion_call_state))) {
|
||||||
|
mm_warn ("couldn't parse call state from ^SLCC line");
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
call_info->state = cinterion_call_state[aux];
|
||||||
|
|
||||||
|
if (g_match_info_get_match_count (match_info) >= 8)
|
||||||
|
call_info->number = mm_get_string_unquoted_from_match_info (match_info, 7);
|
||||||
|
|
||||||
|
list = g_list_append (list, call_info);
|
||||||
|
call_info = NULL;
|
||||||
|
|
||||||
|
next:
|
||||||
|
cinterion_call_info_free (call_info);
|
||||||
|
g_match_info_next (match_info, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_clear_pointer (&match_info, g_match_info_free);
|
||||||
|
g_regex_unref (r);
|
||||||
|
|
||||||
|
if (inner_error) {
|
||||||
|
mm_cinterion_call_info_list_free (list);
|
||||||
|
g_propagate_error (error, inner_error);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_list = list;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mm_cinterion_call_info_list_free (GList *call_info_list)
|
||||||
|
{
|
||||||
|
g_list_free_full (call_info_list, (GDestroyNotify) cinterion_call_info_free);
|
||||||
|
}
|
||||||
|
@@ -87,4 +87,15 @@ gboolean mm_cinterion_parse_smong_response (const gchar *response,
|
|||||||
|
|
||||||
MMModemAccessTechnology mm_cinterion_get_access_technology_from_sind_psinfo (guint val);
|
MMModemAccessTechnology mm_cinterion_get_access_technology_from_sind_psinfo (guint val);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* ^SLCC URC helpers */
|
||||||
|
|
||||||
|
GRegex *mm_cinterion_get_slcc_regex (void);
|
||||||
|
|
||||||
|
/* MMCallInfo list management */
|
||||||
|
gboolean mm_cinterion_parse_slcc_list (const gchar *str,
|
||||||
|
GList **out_list,
|
||||||
|
GError **error);
|
||||||
|
void mm_cinterion_call_info_list_free (GList *call_info_list);
|
||||||
|
|
||||||
#endif /* MM_MODEM_HELPERS_CINTERION_H */
|
#endif /* MM_MODEM_HELPERS_CINTERION_H */
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "mm-base-modem.h"
|
#include "mm-base-modem.h"
|
||||||
#include "mm-base-modem-at.h"
|
#include "mm-base-modem-at.h"
|
||||||
#include "mm-shared-cinterion.h"
|
#include "mm-shared-cinterion.h"
|
||||||
|
#include "mm-modem-helpers-cinterion.h"
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Private data context */
|
/* Private data context */
|
||||||
@@ -42,16 +43,22 @@ typedef enum {
|
|||||||
} FeatureSupport;
|
} FeatureSupport;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/* location */
|
||||||
MMIfaceModemLocation *iface_modem_location_parent;
|
MMIfaceModemLocation *iface_modem_location_parent;
|
||||||
MMModemLocationSource supported_sources;
|
MMModemLocationSource supported_sources;
|
||||||
MMModemLocationSource enabled_sources;
|
MMModemLocationSource enabled_sources;
|
||||||
FeatureSupport sgpss_support;
|
FeatureSupport sgpss_support;
|
||||||
FeatureSupport sgpsc_support;
|
FeatureSupport sgpsc_support;
|
||||||
|
/* voice */
|
||||||
|
MMIfaceModemVoice *iface_modem_voice_parent;
|
||||||
|
FeatureSupport slcc_support;
|
||||||
|
GRegex *slcc_regex;
|
||||||
} Private;
|
} Private;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
private_free (Private *ctx)
|
private_free (Private *ctx)
|
||||||
{
|
{
|
||||||
|
g_regex_unref (ctx->slcc_regex);
|
||||||
g_slice_free (Private, ctx);
|
g_slice_free (Private, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,11 +78,17 @@ get_private (MMSharedCinterion *self)
|
|||||||
priv->enabled_sources = MM_MODEM_LOCATION_SOURCE_NONE;
|
priv->enabled_sources = MM_MODEM_LOCATION_SOURCE_NONE;
|
||||||
priv->sgpss_support = FEATURE_SUPPORT_UNKNOWN;
|
priv->sgpss_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
priv->sgpsc_support = FEATURE_SUPPORT_UNKNOWN;
|
priv->sgpsc_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
|
priv->slcc_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
|
priv->slcc_regex = mm_cinterion_get_slcc_regex ();
|
||||||
|
|
||||||
|
/* Setup parent class' MMIfaceModemLocation and MMIfaceModemVoice */
|
||||||
|
|
||||||
/* Setup parent class' MMIfaceModemLocation */
|
|
||||||
g_assert (MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_location_interface);
|
g_assert (MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_location_interface);
|
||||||
priv->iface_modem_location_parent = MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_location_interface (self);
|
priv->iface_modem_location_parent = MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_location_interface (self);
|
||||||
|
|
||||||
|
g_assert (MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_voice_interface);
|
||||||
|
priv->iface_modem_voice_parent = MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_voice_interface (self);
|
||||||
|
|
||||||
g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free);
|
g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -785,6 +798,437 @@ mm_shared_cinterion_enable_location_gathering (MMIfaceModemLocation *self,
|
|||||||
enable_location_gathering_context_gps_step (task);
|
enable_location_gathering_context_gps_step (task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Common enable/disable voice unsolicited events */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gboolean enable;
|
||||||
|
MMPortSerialAt *primary;
|
||||||
|
MMPortSerialAt *secondary;
|
||||||
|
gchar *slcc_command;
|
||||||
|
gboolean slcc_primary_done;
|
||||||
|
gboolean slcc_secondary_done;
|
||||||
|
} VoiceUnsolicitedEventsContext;
|
||||||
|
|
||||||
|
static void
|
||||||
|
voice_unsolicited_events_context_free (VoiceUnsolicitedEventsContext *ctx)
|
||||||
|
{
|
||||||
|
g_clear_object (&ctx->secondary);
|
||||||
|
g_clear_object (&ctx->primary);
|
||||||
|
g_free (ctx->slcc_command);
|
||||||
|
g_slice_free (VoiceUnsolicitedEventsContext, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
common_voice_enable_disable_unsolicited_events_finish (MMSharedCinterion *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_voice_enable_disable_unsolicited_events (GTask *task);
|
||||||
|
|
||||||
|
static void
|
||||||
|
slcc_command_ready (MMBaseModem *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
Private *priv;
|
||||||
|
VoiceUnsolicitedEventsContext *ctx;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (self));
|
||||||
|
ctx = g_task_get_task_data (task);
|
||||||
|
|
||||||
|
if (!mm_base_modem_at_command_finish (self, res, &error)) {
|
||||||
|
if (priv->slcc_support == FEATURE_SUPPORT_UNKNOWN)
|
||||||
|
priv->slcc_support = FEATURE_NOT_SUPPORTED;
|
||||||
|
mm_dbg ("Couldn't %s ^SLCC reporting: '%s'",
|
||||||
|
ctx->enable ? "enable" : "disable",
|
||||||
|
error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
} else if (priv->slcc_support == FEATURE_SUPPORT_UNKNOWN)
|
||||||
|
priv->slcc_support = FEATURE_SUPPORTED;
|
||||||
|
|
||||||
|
/* Continue on next port */
|
||||||
|
run_voice_enable_disable_unsolicited_events (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run_voice_enable_disable_unsolicited_events (GTask *task)
|
||||||
|
{
|
||||||
|
MMSharedCinterion *self;
|
||||||
|
Private *priv;
|
||||||
|
VoiceUnsolicitedEventsContext *ctx;
|
||||||
|
MMPortSerialAt *port = NULL;
|
||||||
|
|
||||||
|
self = MM_SHARED_CINTERION (g_task_get_source_object (task));
|
||||||
|
priv = get_private (self);
|
||||||
|
ctx = g_task_get_task_data (task);
|
||||||
|
|
||||||
|
/* If not ^SLCC supported, we're done */
|
||||||
|
if (priv->slcc_support == FEATURE_NOT_SUPPORTED) {
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx->slcc_primary_done && ctx->primary) {
|
||||||
|
mm_dbg ("%s ^SLCC extended list of current calls reporting in primary port...",
|
||||||
|
ctx->enable ? "Enabling" : "Disabling");
|
||||||
|
ctx->slcc_primary_done = TRUE;
|
||||||
|
port = ctx->primary;
|
||||||
|
} else if (!ctx->slcc_secondary_done && ctx->secondary) {
|
||||||
|
mm_dbg ("%s ^SLCC extended list of current calls reporting in secondary port...",
|
||||||
|
ctx->enable ? "Enabling" : "Disabling");
|
||||||
|
ctx->slcc_secondary_done = TRUE;
|
||||||
|
port = ctx->secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port) {
|
||||||
|
mm_base_modem_at_command_full (MM_BASE_MODEM (self),
|
||||||
|
port,
|
||||||
|
ctx->slcc_command,
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
FALSE,
|
||||||
|
NULL,
|
||||||
|
(GAsyncReadyCallback)slcc_command_ready,
|
||||||
|
task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fully done now */
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_voice_enable_disable_unsolicited_events (MMSharedCinterion *self,
|
||||||
|
gboolean enable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
VoiceUnsolicitedEventsContext *ctx;
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
|
||||||
|
ctx = g_slice_new0 (VoiceUnsolicitedEventsContext);
|
||||||
|
ctx->enable = enable;
|
||||||
|
if (enable)
|
||||||
|
ctx->slcc_command = g_strdup ("^SLCC=1");
|
||||||
|
else
|
||||||
|
ctx->slcc_command = g_strdup ("^SLCC=0");
|
||||||
|
ctx->primary = mm_base_modem_get_port_primary (MM_BASE_MODEM (self));
|
||||||
|
ctx->secondary = mm_base_modem_get_port_secondary (MM_BASE_MODEM (self));
|
||||||
|
g_task_set_task_data (task, ctx, (GDestroyNotify) voice_unsolicited_events_context_free);
|
||||||
|
|
||||||
|
run_voice_enable_disable_unsolicited_events (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Disable unsolicited events (Voice interface) */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_shared_cinterion_voice_disable_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parent_voice_disable_unsolicited_events_ready (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
Private *priv;
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (self));
|
||||||
|
|
||||||
|
if (!priv->iface_modem_voice_parent->disable_unsolicited_events_finish (self, res, &error)) {
|
||||||
|
mm_warn ("Couldn't disable parent voice unsolicited events: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
voice_disable_unsolicited_events_ready (MMSharedCinterion *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
Private *priv;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!common_voice_enable_disable_unsolicited_events_finish (self, res, &error)) {
|
||||||
|
mm_warn ("Couldn't disable Cinterion-specific voice unsolicited events: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (self));
|
||||||
|
g_assert (priv->iface_modem_voice_parent);
|
||||||
|
g_assert (priv->iface_modem_voice_parent->disable_unsolicited_events);
|
||||||
|
g_assert (priv->iface_modem_voice_parent->disable_unsolicited_events_finish);
|
||||||
|
|
||||||
|
/* Chain up parent's disable */
|
||||||
|
priv->iface_modem_voice_parent->disable_unsolicited_events (
|
||||||
|
MM_IFACE_MODEM_VOICE (self),
|
||||||
|
(GAsyncReadyCallback)parent_voice_disable_unsolicited_events_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mm_shared_cinterion_voice_disable_unsolicited_events (MMIfaceModemVoice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
|
||||||
|
/* our own disabling first */
|
||||||
|
common_voice_enable_disable_unsolicited_events (MM_SHARED_CINTERION (self),
|
||||||
|
FALSE,
|
||||||
|
(GAsyncReadyCallback) voice_disable_unsolicited_events_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Enable unsolicited events (Voice interface) */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_shared_cinterion_voice_enable_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
voice_enable_unsolicited_events_ready (MMSharedCinterion *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!common_voice_enable_disable_unsolicited_events_finish (self, res, &error)) {
|
||||||
|
mm_warn ("Couldn't enable Cinterion-specific voice unsolicited events: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parent_voice_enable_unsolicited_events_ready (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
Private *priv;
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (self));
|
||||||
|
|
||||||
|
if (!priv->iface_modem_voice_parent->enable_unsolicited_events_finish (self, res, &error)) {
|
||||||
|
mm_warn ("Couldn't enable parent voice unsolicited events: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* our own enabling next */
|
||||||
|
common_voice_enable_disable_unsolicited_events (MM_SHARED_CINTERION (self),
|
||||||
|
TRUE,
|
||||||
|
(GAsyncReadyCallback) voice_enable_unsolicited_events_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mm_shared_cinterion_voice_enable_unsolicited_events (MMIfaceModemVoice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Private *priv;
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (self));
|
||||||
|
g_assert (priv->iface_modem_voice_parent);
|
||||||
|
g_assert (priv->iface_modem_voice_parent->enable_unsolicited_events);
|
||||||
|
g_assert (priv->iface_modem_voice_parent->enable_unsolicited_events_finish);
|
||||||
|
|
||||||
|
/* chain up parent's enable first */
|
||||||
|
priv->iface_modem_voice_parent->enable_unsolicited_events (
|
||||||
|
self,
|
||||||
|
(GAsyncReadyCallback)parent_voice_enable_unsolicited_events_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Common setup/cleanup voice unsolicited events */
|
||||||
|
|
||||||
|
static void
|
||||||
|
slcc_received (MMPortSerialAt *port,
|
||||||
|
GMatchInfo *match_info,
|
||||||
|
MMSharedCinterion *self)
|
||||||
|
{
|
||||||
|
gchar *full;
|
||||||
|
GError *error = NULL;
|
||||||
|
GList *call_info_list = NULL;
|
||||||
|
|
||||||
|
full = g_match_info_fetch (match_info, 0);
|
||||||
|
|
||||||
|
if (!mm_cinterion_parse_slcc_list (full, &call_info_list, &error)) {
|
||||||
|
mm_warn ("couldn't parse ^SLCC list: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
} else
|
||||||
|
mm_iface_modem_voice_report_all_calls (MM_IFACE_MODEM_VOICE (self), call_info_list);
|
||||||
|
|
||||||
|
mm_cinterion_call_info_list_free (call_info_list);
|
||||||
|
g_free (full);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_voice_setup_cleanup_unsolicited_events (MMSharedCinterion *self,
|
||||||
|
gboolean enable)
|
||||||
|
{
|
||||||
|
Private *priv;
|
||||||
|
MMPortSerialAt *ports[2];
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (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));
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (ports); i++) {
|
||||||
|
if (!ports[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
|
||||||
|
priv->slcc_regex,
|
||||||
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)slcc_received : NULL,
|
||||||
|
enable ? self : NULL,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Cleanup unsolicited events (Voice interface) */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_shared_cinterion_voice_cleanup_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parent_voice_cleanup_unsolicited_events_ready (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
Private *priv;
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (self));
|
||||||
|
|
||||||
|
if (!priv->iface_modem_voice_parent->cleanup_unsolicited_events_finish (self, res, &error)) {
|
||||||
|
mm_warn ("Couldn't cleanup parent voice unsolicited events: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mm_shared_cinterion_voice_cleanup_unsolicited_events (MMIfaceModemVoice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Private *priv;
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (self));
|
||||||
|
g_assert (priv->iface_modem_voice_parent);
|
||||||
|
g_assert (priv->iface_modem_voice_parent->cleanup_unsolicited_events);
|
||||||
|
g_assert (priv->iface_modem_voice_parent->cleanup_unsolicited_events_finish);
|
||||||
|
|
||||||
|
/* our own cleanup first */
|
||||||
|
common_voice_setup_cleanup_unsolicited_events (MM_SHARED_CINTERION (self), FALSE);
|
||||||
|
|
||||||
|
/* Chain up parent's cleanup */
|
||||||
|
priv->iface_modem_voice_parent->cleanup_unsolicited_events (
|
||||||
|
self,
|
||||||
|
(GAsyncReadyCallback)parent_voice_cleanup_unsolicited_events_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Setup unsolicited events (Voice interface) */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_shared_cinterion_voice_setup_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parent_voice_setup_unsolicited_events_ready (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
Private *priv;
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (self));
|
||||||
|
|
||||||
|
if (!priv->iface_modem_voice_parent->cleanup_unsolicited_events_finish (self, res, &error)) {
|
||||||
|
mm_warn ("Couldn't cleanup parent voice unsolicited events: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* our own setup next */
|
||||||
|
common_voice_setup_cleanup_unsolicited_events (MM_SHARED_CINTERION (self), TRUE);
|
||||||
|
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mm_shared_cinterion_voice_setup_unsolicited_events (MMIfaceModemVoice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Private *priv;
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
|
||||||
|
priv = get_private (MM_SHARED_CINTERION (self));
|
||||||
|
g_assert (priv->iface_modem_voice_parent);
|
||||||
|
g_assert (priv->iface_modem_voice_parent->setup_unsolicited_events);
|
||||||
|
g_assert (priv->iface_modem_voice_parent->setup_unsolicited_events_finish);
|
||||||
|
|
||||||
|
/* chain up parent's setup first */
|
||||||
|
priv->iface_modem_voice_parent->setup_unsolicited_events (
|
||||||
|
self,
|
||||||
|
(GAsyncReadyCallback)parent_voice_setup_unsolicited_events_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include "mm-broadband-modem.h"
|
#include "mm-broadband-modem.h"
|
||||||
#include "mm-iface-modem.h"
|
#include "mm-iface-modem.h"
|
||||||
#include "mm-iface-modem-location.h"
|
#include "mm-iface-modem-location.h"
|
||||||
|
#include "mm-iface-modem-voice.h"
|
||||||
|
|
||||||
#define MM_TYPE_SHARED_CINTERION (mm_shared_cinterion_get_type ())
|
#define MM_TYPE_SHARED_CINTERION (mm_shared_cinterion_get_type ())
|
||||||
#define MM_SHARED_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SHARED_CINTERION, MMSharedCinterion))
|
#define MM_SHARED_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SHARED_CINTERION, MMSharedCinterion))
|
||||||
@@ -39,6 +40,9 @@ struct _MMSharedCinterion {
|
|||||||
|
|
||||||
/* Peek location interface of the parent class of the object */
|
/* Peek location interface of the parent class of the object */
|
||||||
MMIfaceModemLocation * (* peek_parent_location_interface) (MMSharedCinterion *self);
|
MMIfaceModemLocation * (* peek_parent_location_interface) (MMSharedCinterion *self);
|
||||||
|
|
||||||
|
/* Peek voice interface of the parent class of the object */
|
||||||
|
MMIfaceModemVoice * (* peek_parent_voice_interface) (MMSharedCinterion *self);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType mm_shared_cinterion_get_type (void);
|
GType mm_shared_cinterion_get_type (void);
|
||||||
@@ -66,4 +70,32 @@ gboolean mm_shared_cinterion_disable_location_gathering_finish (MMI
|
|||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
void mm_shared_cinterion_voice_setup_unsolicited_events (MMIfaceModemVoice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gboolean mm_shared_cinterion_voice_setup_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
void mm_shared_cinterion_voice_cleanup_unsolicited_events (MMIfaceModemVoice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gboolean mm_shared_cinterion_voice_cleanup_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
void mm_shared_cinterion_voice_enable_unsolicited_events (MMIfaceModemVoice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gboolean mm_shared_cinterion_voice_enable_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
void mm_shared_cinterion_voice_disable_unsolicited_events (MMIfaceModemVoice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gboolean mm_shared_cinterion_voice_disable_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
#endif /* MM_SHARED_CINTERION_H */
|
#endif /* MM_SHARED_CINTERION_H */
|
||||||
|
@@ -667,6 +667,131 @@ test_smong_response_other (void)
|
|||||||
common_test_smong_response (response, MM_MODEM_ACCESS_TECHNOLOGY_GPRS);
|
common_test_smong_response (response, MM_MODEM_ACCESS_TECHNOLOGY_GPRS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Test ^SLCC URCs */
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_test_slcc_urc (const gchar *urc,
|
||||||
|
const MMCallInfo *expected_call_info_list,
|
||||||
|
guint expected_call_info_list_size)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
GRegex *slcc_regex = NULL;
|
||||||
|
gboolean result;
|
||||||
|
GMatchInfo *match_info = NULL;
|
||||||
|
gchar *str;
|
||||||
|
GList *call_info_list = NULL;
|
||||||
|
GList *l;
|
||||||
|
|
||||||
|
|
||||||
|
slcc_regex = mm_cinterion_get_slcc_regex ();
|
||||||
|
|
||||||
|
/* Same matching logic as done in MMSerialPortAt when processing URCs! */
|
||||||
|
result = g_regex_match_full (slcc_regex, urc, -1, 0, 0, &match_info, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (result);
|
||||||
|
|
||||||
|
/* read full matched content */
|
||||||
|
str = g_match_info_fetch (match_info, 0);
|
||||||
|
g_assert (str);
|
||||||
|
|
||||||
|
result = mm_cinterion_parse_slcc_list (str, &call_info_list, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (result);
|
||||||
|
|
||||||
|
g_print ("found %u calls\n", g_list_length (call_info_list));
|
||||||
|
|
||||||
|
if (expected_call_info_list) {
|
||||||
|
g_assert (call_info_list);
|
||||||
|
g_assert_cmpuint (g_list_length (call_info_list), ==, expected_call_info_list_size);
|
||||||
|
} else
|
||||||
|
g_assert (!call_info_list);
|
||||||
|
|
||||||
|
for (l = call_info_list; l; l = g_list_next (l)) {
|
||||||
|
const MMCallInfo *call_info = (const MMCallInfo *)(l->data);
|
||||||
|
gboolean found = FALSE;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
g_print ("call at index %u: direction %s, state %s, number %s\n",
|
||||||
|
call_info->index,
|
||||||
|
mm_call_direction_get_string (call_info->direction),
|
||||||
|
mm_call_state_get_string (call_info->state),
|
||||||
|
call_info->number ? call_info->number : "n/a");
|
||||||
|
|
||||||
|
for (i = 0; !found && i < expected_call_info_list_size; i++)
|
||||||
|
found = ((call_info->index == expected_call_info_list[i].index) &&
|
||||||
|
(call_info->direction == expected_call_info_list[i].direction) &&
|
||||||
|
(call_info->state == expected_call_info_list[i].state) &&
|
||||||
|
(g_strcmp0 (call_info->number, expected_call_info_list[i].number) == 0));
|
||||||
|
|
||||||
|
g_assert (found);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_match_info_free (match_info);
|
||||||
|
g_regex_unref (slcc_regex);
|
||||||
|
g_free (str);
|
||||||
|
|
||||||
|
mm_cinterion_call_info_list_free (call_info_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_slcc_urc_empty (void)
|
||||||
|
{
|
||||||
|
const gchar *urc = "\r\n^SLCC: \r\n";
|
||||||
|
|
||||||
|
common_test_slcc_urc (urc, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_slcc_urc_single (void)
|
||||||
|
{
|
||||||
|
static const MMCallInfo expected_call_info_list[] = {
|
||||||
|
{ 1, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, "123456789" }
|
||||||
|
};
|
||||||
|
|
||||||
|
const gchar *urc =
|
||||||
|
"\r\n^SLCC: 1,1,0,0,0,0,\"123456789\",161"
|
||||||
|
"\r\n^SLCC: \r\n";
|
||||||
|
|
||||||
|
common_test_slcc_urc (urc, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_slcc_urc_multiple (void)
|
||||||
|
{
|
||||||
|
static const MMCallInfo expected_call_info_list[] = {
|
||||||
|
{ 1, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, NULL },
|
||||||
|
{ 2, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, "123456789" },
|
||||||
|
{ 3, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, "987654321" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const gchar *urc =
|
||||||
|
"\r\n^SLCC: 1,1,0,0,1,0" /* number unknown */
|
||||||
|
"\r\n^SLCC: 2,1,0,0,1,0,\"123456789\",161"
|
||||||
|
"\r\n^SLCC: 3,1,0,0,1,0,\"987654321\",161,\"Alice\""
|
||||||
|
"\r\n^SLCC: \r\n";
|
||||||
|
|
||||||
|
common_test_slcc_urc (urc, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_slcc_urc_complex (void)
|
||||||
|
{
|
||||||
|
static const MMCallInfo expected_call_info_list[] = {
|
||||||
|
{ 1, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, "123456789" },
|
||||||
|
{ 2, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_WAITING, "987654321" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const gchar *urc =
|
||||||
|
"\r\n^CIEV: 1,0" /* some different URC before our match */
|
||||||
|
"\r\n^SLCC: 1,1,0,0,0,0,\"123456789\",161"
|
||||||
|
"\r\n^SLCC: 2,1,5,0,0,0,\"987654321\",161"
|
||||||
|
"\r\n^SLCC: \r\n"
|
||||||
|
"\r\n^CIEV: 1,0" /* some different URC after our match */;
|
||||||
|
|
||||||
|
common_test_slcc_urc (urc, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list));
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -706,6 +831,10 @@ int main (int argc, char **argv)
|
|||||||
g_test_add_func ("/MM/cinterion/sind/response/simstatus", test_sind_response_simstatus);
|
g_test_add_func ("/MM/cinterion/sind/response/simstatus", test_sind_response_simstatus);
|
||||||
g_test_add_func ("/MM/cinterion/smong/response/tc63i", test_smong_response_tc63i);
|
g_test_add_func ("/MM/cinterion/smong/response/tc63i", test_smong_response_tc63i);
|
||||||
g_test_add_func ("/MM/cinterion/smong/response/other", test_smong_response_other);
|
g_test_add_func ("/MM/cinterion/smong/response/other", test_smong_response_other);
|
||||||
|
g_test_add_func ("/MM/cinterion/slcc/urc/empty", test_slcc_urc_empty);
|
||||||
|
g_test_add_func ("/MM/cinterion/slcc/urc/single", test_slcc_urc_single);
|
||||||
|
g_test_add_func ("/MM/cinterion/slcc/urc/multiple", test_slcc_urc_multiple);
|
||||||
|
g_test_add_func ("/MM/cinterion/slcc/urc/complex", test_slcc_urc_complex);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user