cinterion: setup/cleanup time unsolicited events

We will parse +CTZU URCs, which end up getting in the way of other
commands if we don't process them.

Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/issues/135
This commit is contained in:
Aleksander Morgado
2019-07-09 13:55:51 +02:00
parent fe11a3fa1f
commit d833b8644c
4 changed files with 262 additions and 3 deletions

View File

@@ -46,12 +46,14 @@ 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 iface_modem_voice_init (MMIfaceModemVoice *iface);
static void iface_modem_time_init (MMIfaceModemTime *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; static MMIfaceModemVoice *iface_modem_voice_parent;
static MMIfaceModemTime *iface_modem_time_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)
@@ -59,6 +61,7 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion,
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_IFACE_MODEM_VOICE, iface_modem_voice_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_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 {
@@ -1985,11 +1988,29 @@ peek_parent_voice_interface (MMSharedCinterion *self)
return iface_modem_voice_parent; return iface_modem_voice_parent;
} }
static void
iface_modem_time_init (MMIfaceModemTime *iface)
{
iface_modem_time_parent = g_type_interface_peek_parent (iface);
iface->setup_unsolicited_events = mm_shared_cinterion_time_setup_unsolicited_events;
iface->setup_unsolicited_events_finish = mm_shared_cinterion_time_setup_unsolicited_events_finish;
iface->cleanup_unsolicited_events = mm_shared_cinterion_time_cleanup_unsolicited_events;
iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_time_cleanup_unsolicited_events_finish;
}
static MMIfaceModemTime *
peek_parent_time_interface (MMSharedCinterion *self)
{
return iface_modem_time_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; iface->peek_parent_voice_interface = peek_parent_voice_interface;
iface->peek_parent_time_interface = peek_parent_time_interface;
} }
static void static void

View File

@@ -31,15 +31,18 @@
#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 iface_modem_voice_init (MMIfaceModemVoice *iface);
static void iface_modem_time_init (MMIfaceModemTime *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; static MMIfaceModemVoice *iface_modem_voice_parent;
static MMIfaceModemTime *iface_modem_time_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_IFACE_MODEM_VOICE, iface_modem_voice_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init)) G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init))
/*****************************************************************************/ /*****************************************************************************/
@@ -109,11 +112,29 @@ peek_parent_voice_interface (MMSharedCinterion *self)
return iface_modem_voice_parent; return iface_modem_voice_parent;
} }
static void
iface_modem_time_init (MMIfaceModemTime *iface)
{
iface_modem_time_parent = g_type_interface_peek_parent (iface);
iface->setup_unsolicited_events = mm_shared_cinterion_time_setup_unsolicited_events;
iface->setup_unsolicited_events_finish = mm_shared_cinterion_time_setup_unsolicited_events_finish;
iface->cleanup_unsolicited_events = mm_shared_cinterion_time_cleanup_unsolicited_events;
iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_time_cleanup_unsolicited_events_finish;
}
static MMIfaceModemTime *
peek_parent_time_interface (MMSharedCinterion *self)
{
return iface_modem_time_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; iface->peek_parent_voice_interface = peek_parent_voice_interface;
iface->peek_parent_time_interface = peek_parent_time_interface;
} }
static void static void

View File

@@ -53,11 +53,15 @@ typedef struct {
MMIfaceModemVoice *iface_modem_voice_parent; MMIfaceModemVoice *iface_modem_voice_parent;
FeatureSupport slcc_support; FeatureSupport slcc_support;
GRegex *slcc_regex; GRegex *slcc_regex;
/* time */
MMIfaceModemTime *iface_modem_time_parent;
GRegex *ctzu_regex;
} Private; } Private;
static void static void
private_free (Private *ctx) private_free (Private *ctx)
{ {
g_regex_unref (ctx->ctzu_regex);
g_regex_unref (ctx->slcc_regex); g_regex_unref (ctx->slcc_regex);
g_slice_free (Private, ctx); g_slice_free (Private, ctx);
} }
@@ -80,8 +84,9 @@ get_private (MMSharedCinterion *self)
priv->sgpsc_support = FEATURE_SUPPORT_UNKNOWN; priv->sgpsc_support = FEATURE_SUPPORT_UNKNOWN;
priv->slcc_support = FEATURE_SUPPORT_UNKNOWN; priv->slcc_support = FEATURE_SUPPORT_UNKNOWN;
priv->slcc_regex = mm_cinterion_get_slcc_regex (); priv->slcc_regex = mm_cinterion_get_slcc_regex ();
priv->ctzu_regex = mm_cinterion_get_ctzu_regex ();
/* Setup parent class' MMIfaceModemLocation and MMIfaceModemVoice */ /* Setup parent class' MMIfaceModemLocation, MMIfaceModemVoice and MMIfaceModemTime */
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);
@@ -89,6 +94,9 @@ get_private (MMSharedCinterion *self)
g_assert (MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_voice_interface); 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); priv->iface_modem_voice_parent = MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_voice_interface (self);
g_assert (MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_time_interface);
priv->iface_modem_time_parent = MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_time_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);
} }
@@ -1333,6 +1341,191 @@ mm_shared_cinterion_voice_check_support (MMIfaceModemVoice *self,
task); task);
} }
/*****************************************************************************/
/* Common setup/cleanup time unsolicited events */
static void
ctzu_received (MMPortSerialAt *port,
GMatchInfo *match_info,
MMSharedCinterion *self)
{
gchar *iso8601 = NULL;
MMNetworkTimezone *tz = NULL;
GError *error = NULL;
if (!mm_cinterion_parse_ctzu_urc (match_info, &iso8601, &tz, &error)) {
mm_dbg ("Couldn't process +CTZU URC: %s", error->message);
g_error_free (error);
return;
}
g_assert (iso8601);
mm_dbg ("+CTZU URC received: %s", iso8601);
mm_iface_modem_time_update_network_time (MM_IFACE_MODEM_TIME (self), iso8601);
g_free (iso8601);
g_assert (tz);
mm_iface_modem_time_update_network_timezone (MM_IFACE_MODEM_TIME (self), tz);
g_object_unref (tz);
}
static void
common_time_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));
mm_dbg ("%s up time unsolicited events...",
enable ? "Setting" : "Cleaning");
for (i = 0; i < G_N_ELEMENTS (ports); i++) {
if (!ports[i])
continue;
mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
priv->ctzu_regex,
enable ? (MMPortSerialAtUnsolicitedMsgFn)ctzu_received : NULL,
enable ? self : NULL,
NULL);
}
}
/*****************************************************************************/
/* Cleanup unsolicited events (Time interface) */
gboolean
mm_shared_cinterion_time_cleanup_unsolicited_events_finish (MMIfaceModemTime *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
parent_time_cleanup_unsolicited_events_ready (MMIfaceModemTime *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
Private *priv;
priv = get_private (MM_SHARED_CINTERION (self));
if (!priv->iface_modem_time_parent->cleanup_unsolicited_events_finish (self, res, &error)) {
mm_warn ("Couldn't cleanup parent time unsolicited events: %s", error->message);
g_error_free (error);
}
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
void
mm_shared_cinterion_time_cleanup_unsolicited_events (MMIfaceModemTime *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_time_parent);
/* our own cleanup first */
common_time_setup_cleanup_unsolicited_events (MM_SHARED_CINTERION (self), FALSE);
if (priv->iface_modem_time_parent->cleanup_unsolicited_events &&
priv->iface_modem_time_parent->cleanup_unsolicited_events_finish) {
/* Chain up parent's cleanup */
priv->iface_modem_time_parent->cleanup_unsolicited_events (
self,
(GAsyncReadyCallback)parent_time_cleanup_unsolicited_events_ready,
task);
return;
}
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
/*****************************************************************************/
/* Setup unsolicited events (Time interface) */
gboolean
mm_shared_cinterion_time_setup_unsolicited_events_finish (MMIfaceModemTime *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
own_time_setup_unsolicited_events (GTask *task)
{
MMSharedCinterion *self;
self = g_task_get_source_object (task);
/* our own setup next */
common_time_setup_cleanup_unsolicited_events (MM_SHARED_CINTERION (self), TRUE);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
parent_time_setup_unsolicited_events_ready (MMIfaceModemTime *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
Private *priv;
priv = get_private (MM_SHARED_CINTERION (self));
if (!priv->iface_modem_time_parent->cleanup_unsolicited_events_finish (self, res, &error)) {
mm_warn ("Couldn't cleanup parent time unsolicited events: %s", error->message);
g_error_free (error);
}
own_time_setup_unsolicited_events (task);
}
void
mm_shared_cinterion_time_setup_unsolicited_events (MMIfaceModemTime *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_time_parent);
if (priv->iface_modem_time_parent->setup_unsolicited_events &&
priv->iface_modem_time_parent->setup_unsolicited_events_finish) {
/* chain up parent's setup first */
priv->iface_modem_time_parent->setup_unsolicited_events (
self,
(GAsyncReadyCallback)parent_time_setup_unsolicited_events_ready,
task);
return;
}
own_time_setup_unsolicited_events (task);
}
/*****************************************************************************/ /*****************************************************************************/
static void static void

View File

@@ -27,6 +27,7 @@
#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" #include "mm-iface-modem-voice.h"
#include "mm-iface-modem-time.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))
@@ -43,10 +44,16 @@ struct _MMSharedCinterion {
/* Peek voice interface of the parent class of the object */ /* Peek voice interface of the parent class of the object */
MMIfaceModemVoice * (* peek_parent_voice_interface) (MMSharedCinterion *self); MMIfaceModemVoice * (* peek_parent_voice_interface) (MMSharedCinterion *self);
/* Peek time interface of the parent class of the object */
MMIfaceModemTime * (* peek_parent_time_interface) (MMSharedCinterion *self);
}; };
GType mm_shared_cinterion_get_type (void); GType mm_shared_cinterion_get_type (void);
/*****************************************************************************/
/* Location interface */
void mm_shared_cinterion_location_load_capabilities (MMIfaceModemLocation *self, void mm_shared_cinterion_location_load_capabilities (MMIfaceModemLocation *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
@@ -71,7 +78,7 @@ gboolean mm_shared_cinterion_disable_location_gathering_finish (MMI
GError **error); GError **error);
/*****************************************************************************/ /*****************************************************************************/
/* Create call (Voice interface) */ /* Voice interface */
MMBaseCall *mm_shared_cinterion_create_call (MMIfaceModemVoice *self, MMBaseCall *mm_shared_cinterion_create_call (MMIfaceModemVoice *self,
MMCallDirection direction, MMCallDirection direction,
@@ -112,4 +119,21 @@ gboolean mm_shared_cinterion_voice_disable_unsolicited_events_finish (MMIfaceMod
GAsyncResult *res, GAsyncResult *res,
GError **error); GError **error);
/*****************************************************************************/
/* Time interface */
void mm_shared_cinterion_time_setup_unsolicited_events (MMIfaceModemTime *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_shared_cinterion_time_setup_unsolicited_events_finish (MMIfaceModemTime *self,
GAsyncResult *res,
GError **error);
void mm_shared_cinterion_time_cleanup_unsolicited_events (MMIfaceModemTime *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_shared_cinterion_time_cleanup_unsolicited_events_finish (MMIfaceModemTime *self,
GAsyncResult *res,
GError **error);
#endif /* MM_SHARED_CINTERION_H */ #endif /* MM_SHARED_CINTERION_H */