diff options
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 (); } |