telit: manage QSS transitions
Currently, Telit's SIM swap implementation is stateless and based on #QSS unsolicited messages 0/1 (SIM_REMOVED/SIM_INSERTED). However, the user might have configured the modem in order to provide a more detailed information, with #QSS values 2/3 (SIM UNLOCKED/SIM READY). In this case and with current implementation, even receiving "#QSS: 3" will trigger the "SIM swap" logic. The same issue might occur in other use cases too, i.e. with SIM locked or when the message is received from both USB ports. This patch makes SIM swap implementation stateful, and it considers as an actual SIM swap, only transitions from #QSS: 0 to #QSS: 1/2/3 and vice versa.
This commit is contained in:

committed by
Aleksander Morgado

parent
b5e94185bb
commit
4cd5044bfd
2
.gitignore
vendored
2
.gitignore
vendored
@@ -175,6 +175,8 @@ Makefile.in
|
|||||||
|
|
||||||
/plugins/ublox/mm-ublox-enums-types.[ch]
|
/plugins/ublox/mm-ublox-enums-types.[ch]
|
||||||
|
|
||||||
|
/plugins/telit/mm-telit-enums-types.[ch]
|
||||||
|
|
||||||
/test/lsudev
|
/test/lsudev
|
||||||
/test/mmtty
|
/test/mmtty
|
||||||
/test/mmrules
|
/test/mmrules
|
||||||
|
@@ -224,45 +224,6 @@ libmm_utils_novatel_la_SOURCES = \
|
|||||||
NOVATEL_COMMON_COMPILER_FLAGS = -I$(top_srcdir)/plugins/novatel
|
NOVATEL_COMMON_COMPILER_FLAGS = -I$(top_srcdir)/plugins/novatel
|
||||||
NOVATEL_COMMON_LIBADD_FLAGS = $(builddir)/libmm-utils-novatel.la
|
NOVATEL_COMMON_LIBADD_FLAGS = $(builddir)/libmm-utils-novatel.la
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# common telit support
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
# Common telit helpers library
|
|
||||||
noinst_LTLIBRARIES += libhelpers-telit.la
|
|
||||||
libhelpers_telit_la_SOURCES = \
|
|
||||||
telit/mm-modem-helpers-telit.c \
|
|
||||||
telit/mm-modem-helpers-telit.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
noinst_PROGRAMS += test-modem-helpers-telit
|
|
||||||
test_modem_helpers_telit_SOURCES = \
|
|
||||||
telit/tests/test-mm-modem-helpers-telit.c \
|
|
||||||
$(NULL)
|
|
||||||
test_modem_helpers_telit_CPPFLAGS = \
|
|
||||||
-I$(top_srcdir)/plugins/telit \
|
|
||||||
$(NULL)
|
|
||||||
test_modem_helpers_telit_LDADD = \
|
|
||||||
$(builddir)/libhelpers-telit.la \
|
|
||||||
$(top_builddir)/src/libhelpers.la \
|
|
||||||
$(top_builddir)/libmm-glib/libmm-glib.la \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
# Common telit modem support library
|
|
||||||
noinst_LTLIBRARIES += libmm-utils-telit.la
|
|
||||||
libmm_utils_telit_la_SOURCES = \
|
|
||||||
telit/mm-common-telit.c \
|
|
||||||
telit/mm-common-telit.h \
|
|
||||||
telit/mm-broadband-modem-telit.c \
|
|
||||||
telit/mm-broadband-modem-telit.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
TELIT_COMMON_COMPILER_FLAGS = -I$(top_srcdir)/plugins/telit
|
|
||||||
TELIT_COMMON_LIBADD_FLAGS = \
|
|
||||||
$(builddir)/libhelpers-telit.la \
|
|
||||||
$(builddir)/libmm-utils-telit.la \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# plugin: generic
|
# plugin: generic
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -818,6 +779,46 @@ libmm_plugin_via_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
|
|||||||
# plugin: telit
|
# plugin: telit
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES += libhelpers-telit.la
|
||||||
|
|
||||||
|
TELIT_ENUMS_INPUTS = \
|
||||||
|
$(top_srcdir)/plugins/telit/mm-modem-helpers-telit.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
TELIT_ENUMS_GENERATED = \
|
||||||
|
telit/mm-telit-enums-types.h \
|
||||||
|
telit/mm-telit-enums-types.c \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
telit/mm-telit-enums-types.h: Makefile.am $(TELIT_ENUMS_INPUTS) $(top_srcdir)/build-aux/mm-enums-template.h
|
||||||
|
$(AM_V_GEN) \
|
||||||
|
$(MKDIR_P) telit; \
|
||||||
|
$(GLIB_MKENUMS) \
|
||||||
|
--fhead "#include \"mm-modem-helpers-telit.h\"\n#ifndef __MM_TELIT_ENUMS_TYPES_H__\n#define __MM_TELIT_ENUMS_TYPES_H__\n" \
|
||||||
|
--template $(top_srcdir)/build-aux/mm-enums-template.h \
|
||||||
|
--ftail "#endif /* __MM_TELIT_ENUMS_TYPES_H__ */\n" \
|
||||||
|
$(TELIT_ENUMS_INPUTS) > $@
|
||||||
|
|
||||||
|
telit/mm-telit-enums-types.c: Makefile.am $(top_srcdir)/build-aux/mm-enums-template.c telit/mm-telit-enums-types.h
|
||||||
|
$(AM_V_GEN) \
|
||||||
|
$(MKDIR_P) telit; \
|
||||||
|
$(GLIB_MKENUMS) \
|
||||||
|
--fhead "#include \"mm-telit-enums-types.h\"" \
|
||||||
|
--template $(top_srcdir)/build-aux/mm-enums-template.c \
|
||||||
|
$(TELIT_ENUMS_INPUTS) > $@
|
||||||
|
|
||||||
|
libhelpers_telit_la_SOURCES = \
|
||||||
|
telit/mm-modem-helpers-telit.c \
|
||||||
|
telit/mm-modem-helpers-telit.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
nodist_libhelpers_telit_la_SOURCES = $(TELIT_ENUMS_GENERATED)
|
||||||
|
|
||||||
|
libhelpers_telit_la_CPPFLAGS = $(PLUGIN_TELIT_COMPILER_FLAGS)
|
||||||
|
|
||||||
|
BUILT_SOURCES += $(TELIT_ENUMS_GENERATED)
|
||||||
|
CLEANFILES += $(TELIT_ENUMS_GENERATED)
|
||||||
|
|
||||||
pkglib_LTLIBRARIES += libmm-plugin-telit.la
|
pkglib_LTLIBRARIES += libmm-plugin-telit.la
|
||||||
libmm_plugin_telit_la_SOURCES = \
|
libmm_plugin_telit_la_SOURCES = \
|
||||||
telit/mm-plugin-telit.c \
|
telit/mm-plugin-telit.c \
|
||||||
@@ -831,6 +832,34 @@ dist_udevrules_DATA += telit/77-mm-telit-port-types.rules
|
|||||||
|
|
||||||
AM_CFLAGS += -DTESTUDEVRULESDIR_TELIT=\"${srcdir}/telit\"
|
AM_CFLAGS += -DTESTUDEVRULESDIR_TELIT=\"${srcdir}/telit\"
|
||||||
|
|
||||||
|
noinst_PROGRAMS += test-modem-helpers-telit
|
||||||
|
test_modem_helpers_telit_SOURCES = \
|
||||||
|
telit/tests/test-mm-modem-helpers-telit.c \
|
||||||
|
$(NULL)
|
||||||
|
test_modem_helpers_telit_CPPFLAGS = \
|
||||||
|
-I$(top_srcdir)/plugins/telit \
|
||||||
|
$(NULL)
|
||||||
|
test_modem_helpers_telit_LDADD = \
|
||||||
|
$(builddir)/libhelpers-telit.la \
|
||||||
|
$(top_builddir)/src/libhelpers.la \
|
||||||
|
$(top_builddir)/libmm-glib/libmm-glib.la \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
# Common telit modem support library
|
||||||
|
noinst_LTLIBRARIES += libmm-utils-telit.la
|
||||||
|
libmm_utils_telit_la_SOURCES = \
|
||||||
|
telit/mm-common-telit.c \
|
||||||
|
telit/mm-common-telit.h \
|
||||||
|
telit/mm-broadband-modem-telit.c \
|
||||||
|
telit/mm-broadband-modem-telit.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
TELIT_COMMON_COMPILER_FLAGS = -I$(top_srcdir)/plugins/telit
|
||||||
|
TELIT_COMMON_LIBADD_FLAGS = \
|
||||||
|
$(builddir)/libhelpers-telit.la \
|
||||||
|
$(builddir)/libmm-utils-telit.la \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# plugin: mtk
|
# plugin: mtk
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include "mm-iface-modem-3gpp.h"
|
#include "mm-iface-modem-3gpp.h"
|
||||||
#include "mm-broadband-modem-telit.h"
|
#include "mm-broadband-modem-telit.h"
|
||||||
#include "mm-modem-helpers-telit.h"
|
#include "mm-modem-helpers-telit.h"
|
||||||
|
#include "mm-telit-enums-types.h"
|
||||||
|
|
||||||
static void iface_modem_init (MMIfaceModem *iface);
|
static void iface_modem_init (MMIfaceModem *iface);
|
||||||
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
||||||
@@ -51,6 +52,7 @@ typedef enum {
|
|||||||
|
|
||||||
struct _MMBroadbandModemTelitPrivate {
|
struct _MMBroadbandModemTelitPrivate {
|
||||||
FeatureSupport csim_lock_support;
|
FeatureSupport csim_lock_support;
|
||||||
|
MMTelitQssStatus qss_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -91,49 +93,54 @@ modem_after_sim_unlock (MMIfaceModem *self,
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Setup SIM hot swap (Modem interface) */
|
/* Setup SIM hot swap (Modem interface) */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
QSS_SETUP_STEP_FIRST,
|
||||||
|
QSS_SETUP_STEP_QUERY,
|
||||||
|
QSS_SETUP_STEP_ENABLE_PRIMARY_PORT,
|
||||||
|
QSS_SETUP_STEP_ENABLE_SECONDARY_PORT,
|
||||||
|
QSS_SETUP_STEP_LAST
|
||||||
|
} QssSetupStep;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
QssSetupStep step;
|
||||||
|
GError *primary_error;
|
||||||
|
GError *secondary_error;
|
||||||
|
} QssSetupContext;
|
||||||
|
|
||||||
|
static void qss_setup_step (GTask *task);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
telit_qss_unsolicited_handler (MMPortSerialAt *port,
|
telit_qss_unsolicited_handler (MMPortSerialAt *port,
|
||||||
GMatchInfo *match_info,
|
GMatchInfo *match_info,
|
||||||
MMBroadbandModemTelit *self)
|
MMBroadbandModemTelit *self)
|
||||||
{
|
{
|
||||||
guint qss;
|
MMTelitQssStatus cur_qss_status;
|
||||||
|
MMTelitQssStatus prev_qss_status;
|
||||||
|
|
||||||
if (!mm_get_uint_from_match_info (match_info, 1, &qss))
|
if (!mm_get_int_from_match_info (match_info, 1, (gint*)&cur_qss_status))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (qss) {
|
prev_qss_status = self->priv->qss_status;
|
||||||
case 0:
|
self->priv->qss_status = cur_qss_status;
|
||||||
mm_info ("QSS: SIM removed");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
mm_info ("QSS: SIM inserted");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
mm_info ("QSS: SIM inserted and PIN unlocked");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
mm_info ("QSS: SIM inserted and PIN locked");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mm_warn ("QSS: unknown QSS value %d", qss);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mm_broadband_modem_update_sim_hot_swap_detected (MM_BROADBAND_MODEM (self));
|
if (cur_qss_status != prev_qss_status)
|
||||||
|
mm_dbg ("QSS: status changed '%s -> %s",
|
||||||
|
mm_telit_qss_status_get_string (prev_qss_status),
|
||||||
|
mm_telit_qss_status_get_string (cur_qss_status));
|
||||||
|
|
||||||
|
if ((prev_qss_status == QSS_STATUS_SIM_REMOVED && cur_qss_status != QSS_STATUS_SIM_REMOVED) ||
|
||||||
|
(prev_qss_status > QSS_STATUS_SIM_REMOVED && cur_qss_status == QSS_STATUS_SIM_REMOVED)) {
|
||||||
|
mm_info ("QSS: SIM swap detected");
|
||||||
|
mm_broadband_modem_update_sim_hot_swap_detected (MM_BROADBAND_MODEM (self));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
MMBroadbandModemTelit *self;
|
|
||||||
GSimpleAsyncResult *result;
|
|
||||||
} ToggleQssUnsolicitedContext;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
toggle_qss_unsolicited_context_complete_and_free (ToggleQssUnsolicitedContext *ctx)
|
qss_setup_context_free (QssSetupContext *ctx)
|
||||||
{
|
{
|
||||||
g_simple_async_result_complete (ctx->result);
|
g_clear_error (&(ctx->primary_error));
|
||||||
g_object_unref (ctx->result);
|
g_clear_error (&(ctx->secondary_error));
|
||||||
g_object_unref (ctx->self);
|
g_slice_free (QssSetupContext, ctx);
|
||||||
g_slice_free (ToggleQssUnsolicitedContext, ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -141,87 +148,192 @@ modem_setup_sim_hot_swap_finish (MMIfaceModem *self,
|
|||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
telit_qss_toggle_ready (MMBaseModem *self,
|
telit_qss_enable_ready (MMBaseModem *modem,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
ToggleQssUnsolicitedContext *ctx)
|
GTask *task)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
MMBroadbandModemTelit *self;
|
||||||
|
QssSetupContext *ctx;
|
||||||
|
MMPortSerialAt *primary;
|
||||||
|
MMPortSerialAt *secondary;
|
||||||
|
GRegex *pattern;
|
||||||
|
|
||||||
mm_base_modem_at_command_finish (self, res, &error);
|
self = MM_BROADBAND_MODEM_TELIT (g_task_get_source_object (task));
|
||||||
|
ctx = g_task_get_task_data (task);
|
||||||
|
|
||||||
|
mm_base_modem_at_command_finish (modem, res, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
mm_warn ("Enable QSS failed: %s", error->message);
|
if (ctx->step == QSS_SETUP_STEP_ENABLE_PRIMARY_PORT) {
|
||||||
g_simple_async_result_set_error (ctx->result,
|
mm_warn ("QSS: error enabling unsolicited on primary port: %s", error->message);
|
||||||
MM_CORE_ERROR,
|
ctx->primary_error = error;
|
||||||
MM_CORE_ERROR_FAILED,
|
} else if (ctx->step == QSS_SETUP_STEP_ENABLE_SECONDARY_PORT) {
|
||||||
"Could not enable QSS");
|
mm_warn ("QSS: error enabling unsolicited on secondary port: %s", error->message);
|
||||||
} else {
|
ctx->secondary_error = error;
|
||||||
MMPortSerialAt *primary;
|
} else {
|
||||||
MMPortSerialAt *secondary;
|
g_assert_not_reached ();
|
||||||
GRegex *pattern;
|
}
|
||||||
|
goto next_step;
|
||||||
|
}
|
||||||
|
|
||||||
pattern = g_regex_new ("#QSS:\\s*([0-3])\\r\\n", G_REGEX_RAW, 0, NULL);
|
pattern = g_regex_new ("#QSS:\\s*([0-3])\\r\\n", G_REGEX_RAW, 0, NULL);
|
||||||
g_assert (pattern);
|
g_assert (pattern);
|
||||||
|
|
||||||
primary = mm_base_modem_peek_port_primary (MM_BASE_MODEM (ctx->self));
|
if (ctx->step == QSS_SETUP_STEP_ENABLE_PRIMARY_PORT) {
|
||||||
|
primary = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
|
||||||
mm_port_serial_at_add_unsolicited_msg_handler (
|
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||||
primary,
|
primary,
|
||||||
pattern,
|
pattern,
|
||||||
(MMPortSerialAtUnsolicitedMsgFn)telit_qss_unsolicited_handler,
|
(MMPortSerialAtUnsolicitedMsgFn)telit_qss_unsolicited_handler,
|
||||||
ctx->self,
|
self,
|
||||||
NULL);
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
secondary = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (ctx->self));
|
if (ctx->step == QSS_SETUP_STEP_ENABLE_SECONDARY_PORT) {
|
||||||
if (secondary)
|
secondary = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
|
||||||
|
if (!secondary) {
|
||||||
mm_port_serial_at_add_unsolicited_msg_handler (
|
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||||
secondary,
|
secondary,
|
||||||
pattern,
|
pattern,
|
||||||
(MMPortSerialAtUnsolicitedMsgFn)telit_qss_unsolicited_handler,
|
(MMPortSerialAtUnsolicitedMsgFn)telit_qss_unsolicited_handler,
|
||||||
ctx->self,
|
self,
|
||||||
NULL);
|
NULL);
|
||||||
|
} else {
|
||||||
g_regex_unref (pattern);
|
mm_warn ("QSS could not set handler on secondary port: no secondary port found.");
|
||||||
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
ctx->secondary_error = g_error_new (MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_FAILED,
|
||||||
|
"QSS could not set handler hat secondary port: no secondary port found.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_qss_unsolicited_context_complete_and_free (ctx);
|
g_regex_unref (pattern);
|
||||||
|
|
||||||
|
next_step:
|
||||||
|
ctx->step++;
|
||||||
|
qss_setup_step (task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
telit_qss_query_ready (MMBaseModem *modem,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
MMBroadbandModemTelit *self;
|
||||||
|
GError *error = NULL;
|
||||||
|
const gchar *response;
|
||||||
|
MMTelitQssStatus qss_status;
|
||||||
|
QssSetupContext *ctx;
|
||||||
|
|
||||||
|
self = MM_BROADBAND_MODEM_TELIT (g_task_get_source_object (task));
|
||||||
|
ctx = g_task_get_task_data (task);
|
||||||
|
|
||||||
|
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||||
|
if (error) {
|
||||||
|
mm_warn ("Could not get \"#QSS?\" reply: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
goto next_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
qss_status = mm_telit_parse_qss_query (response, &error);
|
||||||
|
if (error) {
|
||||||
|
mm_warn ("QSS query parse error: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
goto next_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_info ("QSS: current status is '%s'", mm_telit_qss_status_get_string (qss_status));
|
||||||
|
self->priv->qss_status = qss_status;
|
||||||
|
|
||||||
|
next_step:
|
||||||
|
ctx->step++;
|
||||||
|
qss_setup_step (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qss_setup_step (GTask *task)
|
||||||
|
{
|
||||||
|
QssSetupContext *ctx;
|
||||||
|
MMBroadbandModemTelit *self;
|
||||||
|
|
||||||
|
self = MM_BROADBAND_MODEM_TELIT (g_task_get_source_object (task));
|
||||||
|
ctx = g_task_get_task_data (task);
|
||||||
|
|
||||||
|
switch (ctx->step) {
|
||||||
|
case QSS_SETUP_STEP_FIRST:
|
||||||
|
/* Fall back on next step */
|
||||||
|
ctx->step++;
|
||||||
|
case QSS_SETUP_STEP_QUERY:
|
||||||
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||||
|
"#QSS?",
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
(GAsyncReadyCallback) telit_qss_query_ready,
|
||||||
|
task);
|
||||||
|
return;
|
||||||
|
case QSS_SETUP_STEP_ENABLE_PRIMARY_PORT:
|
||||||
|
mm_base_modem_at_command_full (MM_BASE_MODEM (self),
|
||||||
|
mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
|
||||||
|
"#QSS=1",
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
FALSE, /* raw */
|
||||||
|
NULL, /* cancellable */
|
||||||
|
(GAsyncReadyCallback) telit_qss_enable_ready,
|
||||||
|
task);
|
||||||
|
return;
|
||||||
|
case QSS_SETUP_STEP_ENABLE_SECONDARY_PORT: {
|
||||||
|
MMPortSerialAt *port;
|
||||||
|
|
||||||
|
port = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
|
||||||
|
if (port) {
|
||||||
|
mm_base_modem_at_command_full (MM_BASE_MODEM (self),
|
||||||
|
port,
|
||||||
|
"#QSS=1",
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
FALSE, /* raw */
|
||||||
|
NULL, /* cancellable */
|
||||||
|
(GAsyncReadyCallback) telit_qss_enable_ready,
|
||||||
|
task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fall back to next step */
|
||||||
|
ctx->step++;
|
||||||
|
}
|
||||||
|
case QSS_SETUP_STEP_LAST:
|
||||||
|
if (ctx->primary_error && ctx->secondary_error) {
|
||||||
|
g_task_return_new_error (task,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_FAILED,
|
||||||
|
"QSS: couldn't enable unsolicited");
|
||||||
|
} else {
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
}
|
||||||
|
g_object_unref (task);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
modem_setup_sim_hot_swap (MMIfaceModem *self,
|
modem_setup_sim_hot_swap (MMIfaceModem *self,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
ToggleQssUnsolicitedContext *ctx;
|
QssSetupContext *ctx;
|
||||||
MMPortSerialAt *port;
|
GTask *task;
|
||||||
|
|
||||||
mm_dbg ("Telit SIM hot swap: Enable QSS");
|
task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
|
||||||
ctx = g_slice_new0 (ToggleQssUnsolicitedContext);
|
ctx = g_slice_new0 (QssSetupContext);
|
||||||
ctx->self = g_object_ref (MM_BROADBAND_MODEM_TELIT (self));
|
ctx->step = QSS_SETUP_STEP_FIRST;
|
||||||
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
|
||||||
callback,
|
|
||||||
user_data,
|
|
||||||
modem_setup_sim_hot_swap);
|
|
||||||
|
|
||||||
port = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
|
g_task_set_task_data (task, ctx, (GDestroyNotify) qss_setup_context_free);
|
||||||
if (!port)
|
qss_setup_step (task);
|
||||||
port = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
|
|
||||||
|
|
||||||
mm_base_modem_at_command_full (MM_BASE_MODEM (self),
|
|
||||||
port,
|
|
||||||
"#QSS=1",
|
|
||||||
3,
|
|
||||||
FALSE,
|
|
||||||
FALSE, /* raw */
|
|
||||||
NULL, /* cancellable */
|
|
||||||
(GAsyncReadyCallback) telit_qss_toggle_ready,
|
|
||||||
ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -427,7 +539,6 @@ modem_load_current_bands (MMIfaceModem *self,
|
|||||||
ctx);
|
ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Load supported bands (Modem interface) */
|
/* Load supported bands (Modem interface) */
|
||||||
|
|
||||||
@@ -1313,6 +1424,7 @@ mm_broadband_modem_telit_init (MMBroadbandModemTelit *self)
|
|||||||
MMBroadbandModemTelitPrivate);
|
MMBroadbandModemTelitPrivate);
|
||||||
|
|
||||||
self->priv->csim_lock_support = FEATURE_SUPPORT_UNKNOWN;
|
self->priv->csim_lock_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
|
self->priv->qss_status = QSS_STATUS_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -587,3 +587,23 @@ mm_telit_get_band_flags_from_string (const gchar *flag_str,
|
|||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* #QSS? response parser */
|
||||||
|
MMTelitQssStatus
|
||||||
|
mm_telit_parse_qss_query (const gchar *response,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gint qss_status;
|
||||||
|
gint qss_mode;
|
||||||
|
|
||||||
|
qss_status = QSS_STATUS_UNKNOWN;
|
||||||
|
if (sscanf (response, "#QSS: %d,%d", &qss_mode, &qss_status) != 2) {
|
||||||
|
g_propagate_error (error,
|
||||||
|
g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||||
|
"Could not parse \"#QSS?\" response: %s",
|
||||||
|
response));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (MMTelitQssStatus)qss_status;
|
||||||
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#define MM_MODEM_HELPERS_TELIT_H
|
#define MM_MODEM_HELPERS_TELIT_H
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include "ModemManager.h"
|
||||||
|
|
||||||
#define MAX_BANDS_LIST_LEN 20
|
#define MAX_BANDS_LIST_LEN 20
|
||||||
|
|
||||||
@@ -98,4 +99,15 @@ gboolean mm_telit_update_4g_bands(GArray** bands, GMatchInfo *match_info, GError
|
|||||||
|
|
||||||
void mm_telit_get_band_flag (GArray *bands_array, gint *flag_2g, gint *flag_3g, gint *flag_4g);
|
void mm_telit_get_band_flag (GArray *bands_array, gint *flag_2g, gint *flag_3g, gint *flag_4g);
|
||||||
|
|
||||||
|
/* #QSS? response parser */
|
||||||
|
typedef enum { /*< underscore_name=mm_telit_qss_status >*/
|
||||||
|
QSS_STATUS_UNKNOWN = -1,
|
||||||
|
QSS_STATUS_SIM_REMOVED,
|
||||||
|
QSS_STATUS_SIM_INSERTED,
|
||||||
|
QSS_STATUS_SIM_INSERTED_AND_UNLOCKED,
|
||||||
|
QSS_STATUS_SIM_INSERTED_AND_READY,
|
||||||
|
} MMTelitQssStatus;
|
||||||
|
|
||||||
|
MMTelitQssStatus mm_telit_parse_qss_query (const gchar *response, GError **error);
|
||||||
|
|
||||||
#endif /* MM_MODEM_HELPERS_TELIT_H */
|
#endif /* MM_MODEM_HELPERS_TELIT_H */
|
||||||
|
@@ -502,6 +502,43 @@ test_telit_get_4g_bnd_flag (void)
|
|||||||
g_array_free (bands_array, TRUE);
|
g_array_free (bands_array, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* response;
|
||||||
|
MMTelitQssStatus expected_qss;
|
||||||
|
const char *error_message;
|
||||||
|
} QssParseTest;
|
||||||
|
|
||||||
|
static QssParseTest qss_parse_tests [] = {
|
||||||
|
{"#QSS: 0,0", QSS_STATUS_SIM_REMOVED, NULL},
|
||||||
|
{"#QSS: 1,0", QSS_STATUS_SIM_REMOVED, NULL},
|
||||||
|
{"#QSS: 0,1", QSS_STATUS_SIM_INSERTED, NULL},
|
||||||
|
{"#QSS: 0,2", QSS_STATUS_SIM_INSERTED_AND_UNLOCKED, NULL},
|
||||||
|
{"#QSS: 0,3", QSS_STATUS_SIM_INSERTED_AND_READY, NULL},
|
||||||
|
{"#QSS:0,3", QSS_STATUS_SIM_INSERTED_AND_READY, NULL},
|
||||||
|
{"#QSS: 0, 3", QSS_STATUS_SIM_INSERTED_AND_READY, NULL},
|
||||||
|
{"#QSS: 0", QSS_STATUS_UNKNOWN, "Could not parse \"#QSS?\" response: #QSS: 0"},
|
||||||
|
{"QSS:0,1", QSS_STATUS_UNKNOWN, "Could not parse \"#QSS?\" response: QSS:0,1"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_telit_parse_qss_query (void)
|
||||||
|
{
|
||||||
|
MMTelitQssStatus actual_qss_status;
|
||||||
|
GError *error = NULL;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (qss_parse_tests); i++) {
|
||||||
|
actual_qss_status = mm_telit_parse_qss_query (qss_parse_tests[i].response, &error);
|
||||||
|
|
||||||
|
g_assert_cmpint (actual_qss_status, ==, qss_parse_tests[i].expected_qss);
|
||||||
|
if (qss_parse_tests[i].error_message) {
|
||||||
|
g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED);
|
||||||
|
g_assert_cmpstr (error->message, ==, qss_parse_tests[i].error_message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
setlocale (LC_ALL, "");
|
setlocale (LC_ALL, "");
|
||||||
@@ -516,5 +553,6 @@ int main (int argc, char **argv)
|
|||||||
g_test_add_func ("/MM/telit/bands/current/set_bands/2g", test_telit_get_2g_bnd_flag);
|
g_test_add_func ("/MM/telit/bands/current/set_bands/2g", test_telit_get_2g_bnd_flag);
|
||||||
g_test_add_func ("/MM/telit/bands/current/set_bands/3g", test_telit_get_3g_bnd_flag);
|
g_test_add_func ("/MM/telit/bands/current/set_bands/3g", test_telit_get_3g_bnd_flag);
|
||||||
g_test_add_func ("/MM/telit/bands/current/set_bands/4g", test_telit_get_4g_bnd_flag);
|
g_test_add_func ("/MM/telit/bands/current/set_bands/4g", test_telit_get_4g_bnd_flag);
|
||||||
|
g_test_add_func ("/MM/telit/qss/query", test_telit_parse_qss_query);
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user