simtech: rework enabling/disabling unsolicited events

We will explicitly query for +AUTOCSQ and +CNSMOD support before
trying to enable them.

If +AUTOCSQ is supported and correctly enabled, we'll request signal
quality polling to be disabled.

If +CNSMOD is supported and correctly enabled, we'll request access
technology polling to be disabled.
This commit is contained in:
Aleksander Morgado
2019-09-17 12:39:20 +02:00
parent 1277ebb4cc
commit 7fcefc7af0

View File

@@ -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
own_enable_unsolicited_events_ready (MMBaseModem *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
static void enable_unsolicited_events_context_step (GTask *task);
mm_base_modem_at_sequence_full_finish (self, res, NULL, &error);
if (error)
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
static void
autocsq_set_enabled_ready (MMBaseModem *self,
GAsyncResult *res,
GTask *task)
{
EnableUnsolicitedEventsContext *ctx;
GError *error = NULL;
gboolean csq_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 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 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
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
self->priv->autocsq_support = FEATURE_SUPPORTED;
/* go to next step */
ctx->step++;
enable_unsolicited_events_context_step (task);
}
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;
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);
}
ctx = g_task_get_task_data (task);
static void
own_disable_unsolicited_events_ready (MMBaseModem *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
mm_base_modem_at_sequence_full_finish (self, res, NULL, &error);
if (error) {
if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error)) {
g_task_return_error (task, error);
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);
/* go to next step */
ctx->step++;
disable_unsolicited_events_context_step (task);
}
static void
modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data)
cnsmod_set_disabled_ready (MMBaseModem *self,
GAsyncResult *res,
GTask *task)
{
/* 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;
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 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;
}
}
static void
modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer 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",