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,7 +51,15 @@ 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_IFACE_MODEM_LOCATION, iface_modem_location_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_SIMTECH, shared_simtech_init)) G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_SIMTECH, shared_simtech_init))
typedef enum {
FEATURE_SUPPORT_UNKNOWN,
FEATURE_NOT_SUPPORTED,
FEATURE_SUPPORTED
} FeatureSupport;
struct _MMBroadbandModemSimtechPrivate { struct _MMBroadbandModemSimtechPrivate {
FeatureSupport cnsmod_support;
FeatureSupport autocsq_support;
GRegex *cnsmod_regex; GRegex *cnsmod_regex;
GRegex *csq_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 static gboolean
modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self, modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self,
@@ -224,52 +246,205 @@ modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self,
return g_task_propagate_boolean (G_TASK (res), error); return g_task_propagate_boolean (G_TASK (res), error);
} }
static void enable_unsolicited_events_context_step (GTask *task);
static void static void
own_enable_unsolicited_events_ready (MMBaseModem *self, autocsq_set_enabled_ready (MMBaseModem *self,
GAsyncResult *res, GAsyncResult *res,
GTask *task) GTask *task)
{ {
EnableUnsolicitedEventsContext *ctx;
GError *error = NULL; GError *error = NULL;
gboolean csq_urcs_enabled = FALSE;
mm_base_modem_at_sequence_full_finish (self, res, NULL, &error); ctx = g_task_get_task_data (task);
if (error)
g_task_return_error (task, error); if (!mm_base_modem_at_command_finish (self, res, &error)) {
else mm_dbg ("Couldn't enable automatic signal quality reporting: %s", error->message);
g_task_return_boolean (task, TRUE); g_error_free (error);
g_object_unref (task); } 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[] = { static void
/* Autoreport access technology changes */ autocsq_test_ready (MMBaseModem *_self,
{ "+CNSMOD=1", 20, FALSE, NULL }, GAsyncResult *res,
/* Autoreport CSQ (first arg), and only report when it changes (second arg) */ GTask *task)
{ "+AUTOCSQ=1,1", 5, FALSE, NULL }, {
{ NULL } 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 static void
parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self, parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self,
GAsyncResult *res, GAsyncResult *res,
GTask *task) GTask *task)
{ {
EnableUnsolicitedEventsContext *ctx;
GError *error = NULL; GError *error = NULL;
ctx = g_task_get_task_data (task);
if (!iface_modem_3gpp_parent->enable_unsolicited_events_finish (self, res, &error)) { if (!iface_modem_3gpp_parent->enable_unsolicited_events_finish (self, res, &error)) {
g_task_return_error (task, error); g_task_return_error (task, error);
g_object_unref (task); g_object_unref (task);
return; return;
} }
/* Our own enable now */ /* go to next step */
mm_base_modem_at_sequence_full ( ctx->step++;
MM_BASE_MODEM (self), enable_unsolicited_events_context_step (task);
mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)), }
unsolicited_enable_sequence,
NULL, /* response_processor_context */ static void
NULL, /* response_processor_context_free */ enable_unsolicited_events_context_step (GTask *task)
NULL, /* cancellable */ {
(GAsyncReadyCallback)own_enable_unsolicited_events_ready, 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); 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 static void
@@ -277,15 +452,32 @@ modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
/* Chain up parent's enable */ EnableUnsolicitedEventsContext *ctx;
iface_modem_3gpp_parent->enable_unsolicited_events ( GTask *task;
self,
(GAsyncReadyCallback)parent_enable_unsolicited_events_ready, task = g_task_new (self, NULL, callback, user_data);
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 static gboolean
modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self, modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
@@ -295,45 +487,121 @@ modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
return g_task_propagate_boolean (G_TASK (res), error); return g_task_propagate_boolean (G_TASK (res), error);
} }
static const MMBaseModemAtCommand unsolicited_disable_sequence[] = { static void disable_unsolicited_events_context_step (GTask *task);
{ "+CNSMOD=0", 3, FALSE, NULL },
{ "+AUTOCSQ=0", 3, FALSE, NULL },
{ NULL }
};
static void static void
parent_disable_unsolicited_events_ready (MMIfaceModem3gpp *self, parent_disable_unsolicited_events_ready (MMIfaceModem3gpp *self,
GAsyncResult *res, GAsyncResult *res,
GTask *task) GTask *task)
{ {
DisableUnsolicitedEventsContext *ctx;
GError *error = NULL; GError *error = NULL;
if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error)) ctx = g_task_get_task_data (task);
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error)) {
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) {
g_task_return_error (task, error); g_task_return_error (task, error);
g_object_unref (task); g_object_unref (task);
return; return;
} }
/* Next, chain up parent's disable */ /* go to next step */
ctx->step++;
disable_unsolicited_events_context_step (task);
}
static void
cnsmod_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 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 ( iface_modem_3gpp_parent->disable_unsolicited_events (
MM_IFACE_MODEM_3GPP (self), MM_IFACE_MODEM_3GPP (self),
(GAsyncReadyCallback)parent_disable_unsolicited_events_ready, (GAsyncReadyCallback)parent_disable_unsolicited_events_ready,
task); task);
return;
case DISABLE_UNSOLICITED_EVENTS_STEP_LAST:
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
} }
static void static void
@@ -341,16 +609,16 @@ modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
/* Our own disable first */ DisableUnsolicitedEventsContext *ctx;
mm_base_modem_at_sequence_full ( GTask *task;
MM_BASE_MODEM (self),
mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)), task = g_task_new (self, NULL, callback, user_data);
unsolicited_disable_sequence,
NULL, /* response_processor_context */ ctx = g_new (DisableUnsolicitedEventsContext, 1);
NULL, /* response_processor_context_free */ ctx->step = DISABLE_UNSOLICITED_EVENTS_STEP_FIRST;
NULL, /* cancellable */ g_task_set_task_data (task, ctx, g_free);
(GAsyncReadyCallback)own_disable_unsolicited_events_ready,
g_task_new (self, NULL, callback, user_data)); disable_unsolicited_events_context_step (task);
} }
/*****************************************************************************/ /*****************************************************************************/
@@ -409,21 +677,31 @@ cnsmod_query_ready (MMBaseModem *self,
} }
static void static void
load_access_technologies (MMIfaceModem *self, load_access_technologies (MMIfaceModem *_self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
MMBroadbandModemSimtech *self;
GTask *task; GTask *task;
self = MM_BROADBAND_MODEM_SIMTECH (_self);
task = g_task_new (self, NULL, callback, user_data); task = g_task_new (self, NULL, callback, user_data);
/* Launch query only for 3GPP modems */ /* 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_task_return_int (task, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
g_object_unref (task); g_object_unref (task);
return; 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_at_command (
MM_BASE_MODEM (self), MM_BASE_MODEM (self),
"AT+CNSMOD?", "AT+CNSMOD?",
@@ -942,6 +1220,9 @@ mm_broadband_modem_simtech_init (MMBroadbandModemSimtech *self)
MM_TYPE_BROADBAND_MODEM_SIMTECH, MM_TYPE_BROADBAND_MODEM_SIMTECH,
MMBroadbandModemSimtechPrivate); 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", self->priv->cnsmod_regex = g_regex_new ("\\r\\n\\+CNSMOD:\\s*(\\d)\\r\\n",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
self->priv->csq_regex = g_regex_new ("\\r\\n\\+CSQ:\\s*(\\d+),(\\d+)\\r\\n", self->priv->csq_regex = g_regex_new ("\\r\\n\\+CSQ:\\s*(\\d+),(\\d+)\\r\\n",