diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | plugins/Makefile.am | 107 | ||||
-rw-r--r-- | plugins/telit/mm-broadband-modem-telit.c | 266 | ||||
-rw-r--r-- | plugins/telit/mm-modem-helpers-telit.c | 20 | ||||
-rw-r--r-- | plugins/telit/mm-modem-helpers-telit.h | 12 | ||||
-rw-r--r-- | plugins/telit/tests/test-mm-modem-helpers-telit.c | 38 |
6 files changed, 329 insertions, 116 deletions
@@ -175,6 +175,8 @@ Makefile.in /plugins/ublox/mm-ublox-enums-types.[ch] +/plugins/telit/mm-telit-enums-types.[ch] + /test/lsudev /test/mmtty /test/mmrules diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 2a4ff2b6..2b67349f 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -225,45 +225,6 @@ NOVATEL_COMMON_COMPILER_FLAGS = -I$(top_srcdir)/plugins/novatel 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 ################################################################################ @@ -818,6 +779,46 @@ libmm_plugin_via_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS) # 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 libmm_plugin_telit_la_SOURCES = \ 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\" +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 ################################################################################ diff --git a/plugins/telit/mm-broadband-modem-telit.c b/plugins/telit/mm-broadband-modem-telit.c index 1a873fec..bedb1f68 100644 --- a/plugins/telit/mm-broadband-modem-telit.c +++ b/plugins/telit/mm-broadband-modem-telit.c @@ -32,6 +32,7 @@ #include "mm-iface-modem-3gpp.h" #include "mm-broadband-modem-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_3gpp_init (MMIfaceModem3gpp *iface); @@ -51,6 +52,7 @@ typedef enum { struct _MMBroadbandModemTelitPrivate { FeatureSupport csim_lock_support; + MMTelitQssStatus qss_status; }; /*****************************************************************************/ @@ -91,49 +93,54 @@ modem_after_sim_unlock (MMIfaceModem *self, /*****************************************************************************/ /* 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 telit_qss_unsolicited_handler (MMPortSerialAt *port, GMatchInfo *match_info, 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; - switch (qss) { - case 0: - 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; - } + prev_qss_status = self->priv->qss_status; + self->priv->qss_status = cur_qss_status; - 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)); -typedef struct { - MMBroadbandModemTelit *self; - GSimpleAsyncResult *result; -} ToggleQssUnsolicitedContext; + 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)); + } +} 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_object_unref (ctx->result); - g_object_unref (ctx->self); - g_slice_free (ToggleQssUnsolicitedContext, ctx); + g_clear_error (&(ctx->primary_error)); + g_clear_error (&(ctx->secondary_error)); + g_slice_free (QssSetupContext, ctx); } static gboolean @@ -141,87 +148,192 @@ modem_setup_sim_hot_swap_finish (MMIfaceModem *self, GAsyncResult *res, 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 -telit_qss_toggle_ready (MMBaseModem *self, +telit_qss_enable_ready (MMBaseModem *modem, GAsyncResult *res, - ToggleQssUnsolicitedContext *ctx) + GTask *task) { GError *error = NULL; + MMBroadbandModemTelit *self; + QssSetupContext *ctx; + MMPortSerialAt *primary; + MMPortSerialAt *secondary; + GRegex *pattern; + + self = MM_BROADBAND_MODEM_TELIT (g_task_get_source_object (task)); + ctx = g_task_get_task_data (task); - mm_base_modem_at_command_finish (self, res, &error); + mm_base_modem_at_command_finish (modem, res, &error); if (error) { - mm_warn ("Enable QSS failed: %s", error->message); - g_simple_async_result_set_error (ctx->result, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not enable QSS"); - } else { - MMPortSerialAt *primary; - MMPortSerialAt *secondary; - GRegex *pattern; + if (ctx->step == QSS_SETUP_STEP_ENABLE_PRIMARY_PORT) { + mm_warn ("QSS: error enabling unsolicited on primary port: %s", error->message); + ctx->primary_error = error; + } else if (ctx->step == QSS_SETUP_STEP_ENABLE_SECONDARY_PORT) { + mm_warn ("QSS: error enabling unsolicited on secondary port: %s", error->message); + ctx->secondary_error = error; + } else { + g_assert_not_reached (); + } + goto next_step; + } - pattern = g_regex_new ("#QSS:\\s*([0-3])\\r\\n", G_REGEX_RAW, 0, NULL); - g_assert (pattern); + pattern = g_regex_new ("#QSS:\\s*([0-3])\\r\\n", G_REGEX_RAW, 0, NULL); + 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 ( primary, pattern, (MMPortSerialAtUnsolicitedMsgFn)telit_qss_unsolicited_handler, - ctx->self, + self, NULL); + } - secondary = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (ctx->self)); - if (secondary) + if (ctx->step == QSS_SETUP_STEP_ENABLE_SECONDARY_PORT) { + secondary = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); + if (!secondary) { mm_port_serial_at_add_unsolicited_msg_handler ( secondary, pattern, (MMPortSerialAtUnsolicitedMsgFn)telit_qss_unsolicited_handler, - ctx->self, + self, NULL); + } else { + mm_warn ("QSS could not set handler on secondary port: no secondary port found."); + 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."); + } + } + + g_regex_unref (pattern); + +next_step: + ctx->step++; + qss_setup_step (task); +} - g_regex_unref (pattern); - g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); +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; } - toggle_qss_unsolicited_context_complete_and_free (ctx); + 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 modem_setup_sim_hot_swap (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { - ToggleQssUnsolicitedContext *ctx; - MMPortSerialAt *port; + QssSetupContext *ctx; + 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->self = g_object_ref (MM_BROADBAND_MODEM_TELIT (self)); - 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)); - if (!port) - 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); + ctx = g_slice_new0 (QssSetupContext); + ctx->step = QSS_SETUP_STEP_FIRST; + + g_task_set_task_data (task, ctx, (GDestroyNotify) qss_setup_context_free); + qss_setup_step (task); } /*****************************************************************************/ @@ -427,7 +539,6 @@ modem_load_current_bands (MMIfaceModem *self, ctx); } - /*****************************************************************************/ /* Load supported bands (Modem interface) */ @@ -1313,6 +1424,7 @@ mm_broadband_modem_telit_init (MMBroadbandModemTelit *self) MMBroadbandModemTelitPrivate); self->priv->csim_lock_support = FEATURE_SUPPORT_UNKNOWN; + self->priv->qss_status = QSS_STATUS_UNKNOWN; } static void diff --git a/plugins/telit/mm-modem-helpers-telit.c b/plugins/telit/mm-modem-helpers-telit.c index 8353c45d..a58644d1 100644 --- a/plugins/telit/mm-modem-helpers-telit.c +++ b/plugins/telit/mm-modem-helpers-telit.c @@ -587,3 +587,23 @@ mm_telit_get_band_flags_from_string (const gchar *flag_str, 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; +} diff --git a/plugins/telit/mm-modem-helpers-telit.h b/plugins/telit/mm-modem-helpers-telit.h index b693732a..24c39e08 100644 --- a/plugins/telit/mm-modem-helpers-telit.h +++ b/plugins/telit/mm-modem-helpers-telit.h @@ -17,6 +17,7 @@ #define MM_MODEM_HELPERS_TELIT_H #include <glib.h> +#include "ModemManager.h" #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); +/* #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 */ diff --git a/plugins/telit/tests/test-mm-modem-helpers-telit.c b/plugins/telit/tests/test-mm-modem-helpers-telit.c index 30080104..dba635a2 100644 --- a/plugins/telit/tests/test-mm-modem-helpers-telit.c +++ b/plugins/telit/tests/test-mm-modem-helpers-telit.c @@ -502,6 +502,43 @@ test_telit_get_4g_bnd_flag (void) 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) { 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/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/qss/query", test_telit_parse_qss_query); return g_test_run (); } |