aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/cinterion/mm-broadband-modem-cinterion.c131
-rw-r--r--src/plugins/cinterion/mm-modem-helpers-cinterion.c61
-rw-r--r--src/plugins/cinterion/mm-modem-helpers-cinterion.h7
-rw-r--r--src/plugins/cinterion/tests/test-modem-helpers-cinterion.c95
4 files changed, 294 insertions, 0 deletions
diff --git a/src/plugins/cinterion/mm-broadband-modem-cinterion.c b/src/plugins/cinterion/mm-broadband-modem-cinterion.c
index 9cdd4a3f..b3643021 100644
--- a/src/plugins/cinterion/mm-broadband-modem-cinterion.c
+++ b/src/plugins/cinterion/mm-broadband-modem-cinterion.c
@@ -110,6 +110,7 @@ struct _MMBroadbandModemCinterionPrivate {
FeatureSupport smoni_support;
FeatureSupport sind_simstatus_support;
FeatureSupport sxrat_support;
+ FeatureSupport ws46_support;
/* Mode combination to apply if "any" requested */
MMModemMode any_allowed;
@@ -1681,6 +1682,133 @@ load_supported_modes (MMIfaceModem *_self,
}
/*****************************************************************************/
+/* Load initial allowed/preferred modes (Modem interface) */
+
+typedef struct {
+ MMModemMode allowed;
+ MMModemMode preferred;
+} LoadCurrentModesResult;
+
+static gboolean
+load_current_modes_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ MMModemMode *allowed,
+ MMModemMode *preferred,
+ GError **error)
+{
+ g_autofree LoadCurrentModesResult *result = NULL;
+
+ result = g_task_propagate_pointer (G_TASK (res), error);
+ if (!result)
+ return FALSE;
+
+ *allowed = result->allowed;
+ *preferred = result->preferred;
+ return TRUE;
+}
+
+static void
+ws46_query_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autofree LoadCurrentModesResult *result = NULL;
+ g_autoptr(GError) error = NULL;
+ const gchar *response;
+
+ result = g_new0 (LoadCurrentModesResult, 1);
+ result->allowed = MM_MODEM_MODE_NONE;
+ result->preferred = MM_MODEM_MODE_NONE;
+
+ response = mm_base_modem_at_command_finish (self, res, &error);
+ if (!response) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ if (!mm_cinterion_parse_ws46_response (response,
+ &(result->allowed),
+ &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_pointer (task, g_steal_pointer (&result), g_free);
+ g_object_unref (task);
+}
+
+static void
+ws46_test_ready (MMIfaceModem3gpp *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
+ g_autoptr(GError) error = NULL;
+ const gchar *response;
+
+ response = mm_base_modem_at_command_finish (MM_BASE_MODEM(self), res, &error);
+ if (!response) {
+ self->priv->ws46_support = FEATURE_NOT_SUPPORTED;
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "WS46 not supported");
+ g_object_unref (task);
+ return;
+ }
+
+ self->priv->ws46_support = FEATURE_SUPPORTED;
+
+ /* Use WS46 to query allowed modes */
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+WS46?",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)ws46_query_ready,
+ task);
+}
+
+static void
+load_current_modes (MMIfaceModem *_self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ if (self->priv->ws46_support == FEATURE_SUPPORT_UNKNOWN) {
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (self),
+ "+WS46=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback)ws46_test_ready,
+ task);
+ return;
+ }
+ if (self->priv->ws46_support == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (self),
+ "+WS46?",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)ws46_query_ready,
+ task);
+ return;
+ }
+
+ /* +WS46 feature not supported */
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Unable to load current modes: WS46 not supported");
+ g_object_unref (task);
+}
+
+/*****************************************************************************/
/* Set current modes (Modem interface) */
static gboolean
@@ -2846,6 +2974,7 @@ mm_broadband_modem_cinterion_init (MMBroadbandModemCinterion *self)
self->priv->smoni_support = FEATURE_SUPPORT_UNKNOWN;
self->priv->sind_simstatus_support = FEATURE_SUPPORT_UNKNOWN;
self->priv->sxrat_support = FEATURE_SUPPORT_UNKNOWN;
+ self->priv->ws46_support = FEATURE_SUPPORT_UNKNOWN;
self->priv->ciev_regex = g_regex_new ("\\r\\n\\+CIEV:\\s*([a-z]+),(\\d+)\\r\\n",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
@@ -3140,6 +3269,8 @@ iface_modem_init (MMIfaceModemInterface *iface)
iface->create_bearer_finish = cinterion_modem_create_bearer_finish;
iface->load_supported_modes = load_supported_modes;
iface->load_supported_modes_finish = load_supported_modes_finish;
+ iface->load_current_modes = load_current_modes;
+ iface->load_current_modes_finish = load_current_modes_finish;
iface->set_current_modes = set_current_modes;
iface->set_current_modes_finish = set_current_modes_finish;
iface->load_supported_bands = load_supported_bands;
diff --git a/src/plugins/cinterion/mm-modem-helpers-cinterion.c b/src/plugins/cinterion/mm-modem-helpers-cinterion.c
index 52b2baf8..b2ef89a9 100644
--- a/src/plugins/cinterion/mm-modem-helpers-cinterion.c
+++ b/src/plugins/cinterion/mm-modem-helpers-cinterion.c
@@ -1993,6 +1993,7 @@ mm_cinterion_build_cops_set_command (MMModemMode mode,
if (mode != MM_MODEM_MODE_ANY) {
/* append <RaT> */
if (!modem_mode_to_cops_uint (mode, &cops_mode, error)) {
+ g_string_free (command, TRUE);
return FALSE;
}
g_string_append_printf (command, ",%u", cops_mode);
@@ -2002,3 +2003,63 @@ mm_cinterion_build_cops_set_command (MMModemMode mode,
*out = g_string_free (command, FALSE);
return TRUE;
}
+
+gboolean
+mm_cinterion_parse_ws46_response (const gchar *response,
+ MMModemMode *result,
+ GError **error)
+{
+ g_autoptr(GRegex) r = NULL;
+ g_autoptr(GMatchInfo) match_info = NULL;
+ guint mode_num;
+
+ r = g_regex_new ("\\+WS46:\\s*(\\d+)",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ g_assert (r != NULL);
+
+ if (!g_regex_match (r, response, 0, &match_info)) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Failed to parse WS46 response '%s'",
+ response);
+ return FALSE;
+ }
+
+ if (!mm_get_uint_from_match_info (match_info, 1, &mode_num)) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Failed to get mode from WS46 response '%s'",
+ response);
+ return FALSE;
+ }
+
+ switch (mode_num) {
+ case 12:
+ /* GSM digital cellular (GERAN only) */
+ *result = MM_MODEM_MODE_2G;
+ break;
+ case 22:
+ /* UTRAN only */
+ *result = MM_MODEM_MODE_3G;
+ break;
+ case 25:
+ /* GERAN, UTRAN and E-UTRAN */
+ *result = MM_MODEM_MODE_ANY;
+ break;
+ case 28:
+ /* E-UTRAN only */
+ *result = MM_MODEM_MODE_4G;
+ break;
+ default:
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Unknown WS46 mode '%u'",
+ mode_num);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/src/plugins/cinterion/mm-modem-helpers-cinterion.h b/src/plugins/cinterion/mm-modem-helpers-cinterion.h
index 36b88315..08b80955 100644
--- a/src/plugins/cinterion/mm-modem-helpers-cinterion.h
+++ b/src/plugins/cinterion/mm-modem-helpers-cinterion.h
@@ -237,4 +237,11 @@ gboolean mm_cinterion_build_cops_set_command (MMModemMode mode,
gchar **out,
GError **error);
+/*****************************************************************************/
+/* +WS46 response parser */
+
+gboolean mm_cinterion_parse_ws46_response (const gchar *response,
+ MMModemMode *result,
+ GError **error);
+
#endif /* MM_MODEM_HELPERS_CINTERION_H */
diff --git a/src/plugins/cinterion/tests/test-modem-helpers-cinterion.c b/src/plugins/cinterion/tests/test-modem-helpers-cinterion.c
index ae76223c..e5857ede 100644
--- a/src/plugins/cinterion/tests/test-modem-helpers-cinterion.c
+++ b/src/plugins/cinterion/tests/test-modem-helpers-cinterion.c
@@ -1981,6 +1981,96 @@ test_cops_any (void)
g_assert_cmpstr (cops_command, ==, "+COPS=0");
}
+static void
+test_ws46_response_2g (void)
+{
+ MMModemMode mode = MM_MODEM_MODE_NONE;
+ GError *error = NULL;
+ gboolean res;
+ const gchar *response =
+ "+WS46: 12\r\n"
+ "\r\n";
+
+ res = mm_cinterion_parse_ws46_response (response,
+ &mode,
+ &error);
+ g_assert_no_error (error);
+ g_assert (res == TRUE);
+ g_assert (mode == MM_MODEM_MODE_2G);
+}
+
+static void
+test_ws46_response_3g (void)
+{
+ MMModemMode mode = MM_MODEM_MODE_NONE;
+ GError *error = NULL;
+ gboolean res;
+ const gchar *response =
+ "+WS46: 22\r\n"
+ "\r\n";
+
+ res = mm_cinterion_parse_ws46_response (response,
+ &mode,
+ &error);
+ g_assert_no_error (error);
+ g_assert (res == TRUE);
+ g_assert (mode == MM_MODEM_MODE_3G);
+}
+
+static void
+test_ws46_response_4g (void)
+{
+ MMModemMode mode = MM_MODEM_MODE_NONE;
+ GError *error = NULL;
+ gboolean res;
+ const gchar *response =
+ "+WS46: 28\r\n"
+ "\r\n";
+
+ res = mm_cinterion_parse_ws46_response (response,
+ &mode,
+ &error);
+ g_assert_no_error (error);
+ g_assert (res == TRUE);
+ g_assert (mode == MM_MODEM_MODE_4G);
+}
+
+static void
+test_ws46_response_any (void)
+{
+ MMModemMode mode = MM_MODEM_MODE_NONE;
+ GError *error = NULL;
+ gboolean res;
+ const gchar *response =
+ "+WS46: 25\r\n"
+ "\r\n";
+
+ res = mm_cinterion_parse_ws46_response (response,
+ &mode,
+ &error);
+ g_assert_no_error (error);
+ g_assert (res == TRUE);
+ g_assert (mode == MM_MODEM_MODE_ANY);
+}
+
+static void
+test_ws46_response_other (void)
+{
+ MMModemMode mode = MM_MODEM_MODE_NONE;
+ GError *error = NULL;
+ gboolean res;
+ const gchar *response =
+ "+WS46: 8\r\n"
+ "\r\n";
+
+ res = mm_cinterion_parse_ws46_response (response,
+ &mode,
+ &error);
+ g_assert (res == FALSE);
+ g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED);
+ g_clear_error (&error);
+}
+
typedef struct {
const gchar *str;
MMModemMode allowed;
@@ -2095,6 +2185,11 @@ int main (int argc, char **argv)
g_test_add_func ("/MM/cinterion/cops/only-operator", test_cops_only_operator);
g_test_add_func ("/MM/cinterion/cops/operator-and-mode", test_cops_operator_and_mode);
g_test_add_func ("/MM/cinterion/cops/any", test_cops_any);
+ g_test_add_func ("/MM/cinterion/ws46/response/2g", test_ws46_response_2g);
+ g_test_add_func ("/MM/cinterion/ws46/response/3g", test_ws46_response_3g);
+ g_test_add_func ("/MM/cinterion/ws46/response/4g", test_ws46_response_4g);
+ g_test_add_func ("/MM/cinterion/ws46/response/any", test_ws46_response_any);
+ g_test_add_func ("/MM/cinterion/ws46/response/other", test_ws46_response_other);
return g_test_run ();
}