broadband-modem-cinterion: implement load_current_modes

Signed-off-by: Lukas Voegl <lvoegl@tdt.de>
This commit is contained in:
Lukas Voegl
2024-11-20 12:07:20 +00:00
committed by Aleksander Morgado
parent 32435b430f
commit 68e725d45e
4 changed files with 294 additions and 0 deletions
@@ -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;
@@ -1680,6 +1681,133 @@ load_supported_modes (MMIfaceModem *_self,
task);
}
/*****************************************************************************/
/* 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) */
@@ -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;
@@ -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;
}
@@ -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 */
@@ -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 ();
}