aboutsummaryrefslogtreecommitdiff
path: root/plugins/simtech/mm-broadband-modem-simtech.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/simtech/mm-broadband-modem-simtech.c')
-rw-r--r--plugins/simtech/mm-broadband-modem-simtech.c437
1 files changed, 359 insertions, 78 deletions
diff --git a/plugins/simtech/mm-broadband-modem-simtech.c b/plugins/simtech/mm-broadband-modem-simtech.c
index feb08470..c08d5f4d 100644
--- a/plugins/simtech/mm-broadband-modem-simtech.c
+++ b/plugins/simtech/mm-broadband-modem-simtech.c
@@ -51,9 +51,17 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemSimtech, mm_broadband_modem_simtech, MM_
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_SIMTECH, shared_simtech_init))
+typedef enum {
+ FEATURE_SUPPORT_UNKNOWN,
+ FEATURE_NOT_SUPPORTED,
+ FEATURE_SUPPORTED
+} FeatureSupport;
+
struct _MMBroadbandModemSimtechPrivate {
- GRegex *cnsmod_regex;
- GRegex *csq_regex;
+ FeatureSupport cnsmod_support;
+ FeatureSupport autocsq_support;
+ GRegex *cnsmod_regex;
+ GRegex *csq_regex;
};
/*****************************************************************************/
@@ -214,7 +222,21 @@ modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp *self,
}
/*****************************************************************************/
-/* Enabling unsolicited events (3GPP interface) */
+/* Enable unsolicited events (3GPP interface) */
+
+typedef enum {
+ ENABLE_UNSOLICITED_EVENTS_STEP_FIRST,
+ ENABLE_UNSOLICITED_EVENTS_STEP_PARENT,
+ ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_CNSMOD,
+ ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_CNSMOD,
+ ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_AUTOCSQ,
+ ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_AUTOCSQ,
+ ENABLE_UNSOLICITED_EVENTS_STEP_LAST,
+} EnableUnsolicitedEventsStep;
+
+typedef struct {
+ EnableUnsolicitedEventsStep step;
+} EnableUnsolicitedEventsContext;
static gboolean
modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self,
@@ -224,35 +246,113 @@ modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self,
return g_task_propagate_boolean (G_TASK (res), error);
}
+static void enable_unsolicited_events_context_step (GTask *task);
+
static void
-own_enable_unsolicited_events_ready (MMBaseModem *self,
- GAsyncResult *res,
- GTask *task)
+autocsq_set_enabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
{
- GError *error = NULL;
+ EnableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+ gboolean csq_urcs_enabled = FALSE;
- mm_base_modem_at_sequence_full_finish (self, res, NULL, &error);
- if (error)
- g_task_return_error (task, error);
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_dbg ("Couldn't enable automatic signal quality reporting: %s", error->message);
+ g_error_free (error);
+ } else
+ csq_urcs_enabled = TRUE;
+
+ /* Disable access technology polling if we can use the +CSQ URCs */
+ g_object_set (self,
+ MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, csq_urcs_enabled,
+ NULL);
+
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
+}
+
+static void
+autocsq_test_ready (MMBaseModem *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemSimtech *self;
+ EnableUnsolicitedEventsContext *ctx;
+
+ self = MM_BROADBAND_MODEM_SIMTECH (_self);
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (_self, res, NULL))
+ self->priv->autocsq_support = FEATURE_NOT_SUPPORTED;
else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
+ self->priv->autocsq_support = FEATURE_SUPPORTED;
+
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
}
-static const MMBaseModemAtCommand unsolicited_enable_sequence[] = {
- /* Autoreport access technology changes */
- { "+CNSMOD=1", 20, FALSE, NULL },
- /* Autoreport CSQ (first arg), and only report when it changes (second arg) */
- { "+AUTOCSQ=1,1", 5, FALSE, NULL },
- { NULL }
-};
+static void
+cnsmod_set_enabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ EnableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+ gboolean cnsmod_urcs_enabled = FALSE;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_dbg ("Couldn't enable automatic access technology reporting: %s", error->message);
+ g_error_free (error);
+ } else
+ cnsmod_urcs_enabled = TRUE;
+
+ /* Disable access technology polling if we can use the +CNSMOD URCs */
+ g_object_set (self,
+ MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED, cnsmod_urcs_enabled,
+ NULL);
+
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
+}
+
+static void
+cnsmod_test_ready (MMBaseModem *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemSimtech *self;
+ EnableUnsolicitedEventsContext *ctx;
+
+ self = MM_BROADBAND_MODEM_SIMTECH (_self);
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (_self, res, NULL))
+ self->priv->cnsmod_support = FEATURE_NOT_SUPPORTED;
+ else
+ self->priv->cnsmod_support = FEATURE_SUPPORTED;
+
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
+}
static void
parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
GTask *task)
{
- GError *error = NULL;
+ EnableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
if (!iface_modem_3gpp_parent->enable_unsolicited_events_finish (self, res, &error)) {
g_task_return_error (task, error);
@@ -260,16 +360,91 @@ parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self,
return;
}
- /* Our own enable now */
- mm_base_modem_at_sequence_full (
- MM_BASE_MODEM (self),
- mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
- unsolicited_enable_sequence,
- NULL, /* response_processor_context */
- NULL, /* response_processor_context_free */
- NULL, /* cancellable */
- (GAsyncReadyCallback)own_enable_unsolicited_events_ready,
- task);
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
+}
+
+static void
+enable_unsolicited_events_context_step (GTask *task)
+{
+ MMBroadbandModemSimtech *self;
+ EnableUnsolicitedEventsContext *ctx;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ switch (ctx->step) {
+ case ENABLE_UNSOLICITED_EVENTS_STEP_FIRST:
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_PARENT:
+ iface_modem_3gpp_parent->enable_unsolicited_events (
+ MM_IFACE_MODEM_3GPP (self),
+ (GAsyncReadyCallback)parent_enable_unsolicited_events_ready,
+ task);
+ return;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_CNSMOD:
+ if (self->priv->cnsmod_support == FEATURE_SUPPORT_UNKNOWN) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CNSMOD=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback)cnsmod_test_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_CNSMOD:
+ if (self->priv->cnsmod_support == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ /* Autoreport +CNSMOD when it changes */
+ "+CNSMOD=1",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)cnsmod_set_enabled_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_AUTOCSQ:
+ if (self->priv->autocsq_support == FEATURE_SUPPORT_UNKNOWN) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+AUTOCSQ=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback)autocsq_test_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_AUTOCSQ:
+ if (self->priv->autocsq_support == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ /* Autoreport+ CSQ (first arg), and only report when it changes (second arg) */
+ "+AUTOCSQ=1,1",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)autocsq_set_enabled_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_LAST:
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
}
static void
@@ -277,80 +452,173 @@ modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- /* Chain up parent's enable */
- iface_modem_3gpp_parent->enable_unsolicited_events (
- self,
- (GAsyncReadyCallback)parent_enable_unsolicited_events_ready,
- g_task_new (self, NULL, callback, user_data));
+ EnableUnsolicitedEventsContext *ctx;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ ctx = g_new (EnableUnsolicitedEventsContext, 1);
+ ctx->step = ENABLE_UNSOLICITED_EVENTS_STEP_FIRST;
+ g_task_set_task_data (task, ctx, g_free);
+
+ enable_unsolicited_events_context_step (task);
}
/*****************************************************************************/
-/* Disabling unsolicited events (3GPP interface) */
+/* Disable unsolicited events (3GPP interface) */
+
+typedef enum {
+ DISABLE_UNSOLICITED_EVENTS_STEP_FIRST,
+ DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_AUTOCSQ,
+ DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_CNSMOD,
+ DISABLE_UNSOLICITED_EVENTS_STEP_PARENT,
+ DISABLE_UNSOLICITED_EVENTS_STEP_LAST,
+} DisableUnsolicitedEventsStep;
+
+typedef struct {
+ DisableUnsolicitedEventsStep step;
+} DisableUnsolicitedEventsContext;
static gboolean
-modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
- GAsyncResult *res,
- GError **error)
+modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
-static const MMBaseModemAtCommand unsolicited_disable_sequence[] = {
- { "+CNSMOD=0", 3, FALSE, NULL },
- { "+AUTOCSQ=0", 3, FALSE, NULL },
- { NULL }
-};
+static void disable_unsolicited_events_context_step (GTask *task);
static void
parent_disable_unsolicited_events_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
GTask *task)
{
- GError *error = NULL;
+ DisableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
- if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error))
+ if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error)) {
g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
+ g_object_unref (task);
+ return;
+ }
+
+ /* go to next step */
+ ctx->step++;
+ disable_unsolicited_events_context_step (task);
}
static void
-own_disable_unsolicited_events_ready (MMBaseModem *self,
- GAsyncResult *res,
- GTask *task)
+cnsmod_set_disabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
{
- GError *error = NULL;
+ DisableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
- mm_base_modem_at_sequence_full_finish (self, res, NULL, &error);
- if (error) {
- g_task_return_error (task, error);
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_dbg ("Couldn't disable automatic access technology reporting: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* go to next step */
+ ctx->step++;
+ disable_unsolicited_events_context_step (task);
+}
+
+static void
+autocsq_set_disabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ DisableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_dbg ("Couldn't disable automatic signal quality reporting: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* go to next step */
+ ctx->step++;
+ disable_unsolicited_events_context_step (task);
+}
+
+static void
+disable_unsolicited_events_context_step (GTask *task)
+{
+ MMBroadbandModemSimtech *self;
+ DisableUnsolicitedEventsContext *ctx;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ switch (ctx->step) {
+ case DISABLE_UNSOLICITED_EVENTS_STEP_FIRST:
+ /* fall down to next step */
+ ctx->step++;
+
+ case DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_AUTOCSQ:
+ if (self->priv->autocsq_support == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+AUTOCSQ=0",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)autocsq_set_disabled_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_CNSMOD:
+ if (self->priv->cnsmod_support == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CNSMOD=0",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)cnsmod_set_disabled_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case DISABLE_UNSOLICITED_EVENTS_STEP_PARENT:
+ iface_modem_3gpp_parent->disable_unsolicited_events (
+ MM_IFACE_MODEM_3GPP (self),
+ (GAsyncReadyCallback)parent_disable_unsolicited_events_ready,
+ task);
+ return;
+
+ case DISABLE_UNSOLICITED_EVENTS_STEP_LAST:
+ g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
-
- /* Next, chain up parent's disable */
- iface_modem_3gpp_parent->disable_unsolicited_events (
- MM_IFACE_MODEM_3GPP (self),
- (GAsyncReadyCallback)parent_disable_unsolicited_events_ready,
- task);
}
static void
-modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- /* Our own disable first */
- mm_base_modem_at_sequence_full (
- MM_BASE_MODEM (self),
- mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
- unsolicited_disable_sequence,
- NULL, /* response_processor_context */
- NULL, /* response_processor_context_free */
- NULL, /* cancellable */
- (GAsyncReadyCallback)own_disable_unsolicited_events_ready,
- g_task_new (self, NULL, callback, user_data));
+ DisableUnsolicitedEventsContext *ctx;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ ctx = g_new (DisableUnsolicitedEventsContext, 1);
+ ctx->step = DISABLE_UNSOLICITED_EVENTS_STEP_FIRST;
+ g_task_set_task_data (task, ctx, g_free);
+
+ disable_unsolicited_events_context_step (task);
}
/*****************************************************************************/
@@ -409,21 +677,31 @@ cnsmod_query_ready (MMBaseModem *self,
}
static void
-load_access_technologies (MMIfaceModem *self,
+load_access_technologies (MMIfaceModem *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GTask *task;
+ MMBroadbandModemSimtech *self;
+ GTask *task;
+ self = MM_BROADBAND_MODEM_SIMTECH (_self);
task = g_task_new (self, NULL, callback, user_data);
/* Launch query only for 3GPP modems */
- if (!mm_iface_modem_is_3gpp (self)) {
+ if (!mm_iface_modem_is_3gpp (_self)) {
g_task_return_int (task, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
g_object_unref (task);
return;
}
+ g_assert (self->priv->cnsmod_support != FEATURE_SUPPORT_UNKNOWN);
+ if (self->priv->cnsmod_support == FEATURE_NOT_SUPPORTED) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Loading access technologies with +CNSMOD is not supported");
+ g_object_unref (task);
+ return;
+ }
+
mm_base_modem_at_command (
MM_BASE_MODEM (self),
"AT+CNSMOD?",
@@ -942,6 +1220,9 @@ mm_broadband_modem_simtech_init (MMBroadbandModemSimtech *self)
MM_TYPE_BROADBAND_MODEM_SIMTECH,
MMBroadbandModemSimtechPrivate);
+ self->priv->cnsmod_support = FEATURE_SUPPORT_UNKNOWN;
+ self->priv->autocsq_support = FEATURE_SUPPORT_UNKNOWN;
+
self->priv->cnsmod_regex = g_regex_new ("\\r\\n\\+CNSMOD:\\s*(\\d)\\r\\n",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
self->priv->csq_regex = g_regex_new ("\\r\\n\\+CSQ:\\s*(\\d+),(\\d+)\\r\\n",