Currently, LM940 is expected to have not LTE band extended, however they have been introduced since version 24.01.516. This change adds a software revision compare function for Telit modem limited to LM9x0 modems (LM940 and LM960 share the same revision format string) to verify if the current LM940 software revision is equal or newer than 24.01.516 and enable/disable LTE band extended accordingly.
796 lines
25 KiB
C
796 lines
25 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details:
|
|
*
|
|
* Copyright (C) 2019 Daniele Palmas <dnlplm@gmail.com>
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <glib-object.h>
|
|
#include <gio/gio.h>
|
|
|
|
#define _LIBMM_INSIDE_MM
|
|
#include <libmm-glib.h>
|
|
|
|
#include "mm-log-object.h"
|
|
#include "mm-iface-modem.h"
|
|
#include "mm-iface-modem-location.h"
|
|
#include "mm-base-modem.h"
|
|
#include "mm-base-modem-at.h"
|
|
#include "mm-modem-helpers-telit.h"
|
|
#include "mm-shared-telit.h"
|
|
|
|
/*****************************************************************************/
|
|
/* Private data context */
|
|
|
|
#define TELIT_LM940_EXT_LTE_BND_SW_REVISION "24.01.516"
|
|
|
|
#define PRIVATE_TAG "shared-telit-private-tag"
|
|
static GQuark private_quark;
|
|
|
|
typedef struct {
|
|
MMIfaceModem *iface_modem_parent;
|
|
gboolean alternate_3g_bands;
|
|
gboolean ext_4g_bands;
|
|
GArray *supported_bands;
|
|
GArray *supported_modes;
|
|
gchar *software_package_version;
|
|
} Private;
|
|
|
|
static void
|
|
private_free (Private *priv)
|
|
{
|
|
if (priv->supported_bands)
|
|
g_array_unref (priv->supported_bands);
|
|
if (priv->supported_modes)
|
|
g_array_unref (priv->supported_modes);
|
|
g_free (priv->software_package_version);
|
|
g_slice_free (Private, priv);
|
|
}
|
|
|
|
static gboolean
|
|
has_alternate_3g_bands (const gchar *revision)
|
|
{
|
|
MMTelitModel model;
|
|
|
|
model = mm_telit_model_from_revision (revision);
|
|
return (model == MM_TELIT_MODEL_FN980 ||
|
|
model == MM_TELIT_MODEL_FN990 ||
|
|
model == MM_TELIT_MODEL_LM940 ||
|
|
model == MM_TELIT_MODEL_LM960 ||
|
|
model == MM_TELIT_MODEL_LN920);
|
|
}
|
|
|
|
static gboolean
|
|
is_bnd_4g_format_hex (const gchar *revision)
|
|
{
|
|
MMTelitModel model;
|
|
|
|
model = mm_telit_model_from_revision (revision);
|
|
|
|
return (model == MM_TELIT_MODEL_FN980 ||
|
|
model == MM_TELIT_MODEL_LE910C1 ||
|
|
model == MM_TELIT_MODEL_LM940 ||
|
|
model == MM_TELIT_MODEL_LM960 ||
|
|
model == MM_TELIT_MODEL_LN920);
|
|
}
|
|
|
|
static gboolean
|
|
has_extended_4g_bands (const gchar *revision)
|
|
{
|
|
MMTelitModel model;
|
|
|
|
model = mm_telit_model_from_revision (revision);
|
|
if (model == MM_TELIT_MODEL_LM940)
|
|
return mm_telit_software_revision_cmp (revision, TELIT_LM940_EXT_LTE_BND_SW_REVISION) >= MM_TELIT_SW_REV_CMP_EQUAL;
|
|
|
|
return (model == MM_TELIT_MODEL_FN980 ||
|
|
model == MM_TELIT_MODEL_FN990 ||
|
|
model == MM_TELIT_MODEL_LM960 ||
|
|
model == MM_TELIT_MODEL_LN920);
|
|
}
|
|
|
|
static Private *
|
|
get_private (MMSharedTelit *self)
|
|
{
|
|
Private *priv;
|
|
|
|
if (G_UNLIKELY (!private_quark))
|
|
private_quark = g_quark_from_static_string (PRIVATE_TAG);
|
|
|
|
priv = g_object_get_qdata (G_OBJECT (self), private_quark);
|
|
if (!priv) {
|
|
priv = g_slice_new0 (Private);
|
|
|
|
if (MM_SHARED_TELIT_GET_INTERFACE (self)->peek_parent_modem_interface)
|
|
priv->iface_modem_parent = MM_SHARED_TELIT_GET_INTERFACE (self)->peek_parent_modem_interface (self);
|
|
|
|
g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free);
|
|
}
|
|
|
|
return priv;
|
|
}
|
|
|
|
void
|
|
mm_shared_telit_store_supported_modes (MMSharedTelit *self,
|
|
GArray *modes)
|
|
{
|
|
Private *priv;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
priv->supported_modes = g_array_ref (modes);
|
|
}
|
|
|
|
void
|
|
mm_shared_telit_store_revision (MMSharedTelit *self,
|
|
const gchar *revision)
|
|
{
|
|
Private *priv;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
g_clear_pointer (&priv->software_package_version, g_free);
|
|
priv->software_package_version = g_strdup (revision);
|
|
priv->alternate_3g_bands = has_alternate_3g_bands (revision);
|
|
priv->ext_4g_bands = has_extended_4g_bands (revision);
|
|
}
|
|
|
|
void
|
|
mm_shared_telit_get_bnd_parse_config (MMIfaceModem *self, MMTelitBNDParseConfig *config)
|
|
{
|
|
Private *priv;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
|
|
config->modem_is_2g = mm_iface_modem_is_2g (self);
|
|
config->modem_is_3g = mm_iface_modem_is_3g (self);
|
|
config->modem_is_4g = mm_iface_modem_is_4g (self);
|
|
config->modem_alternate_3g_bands = priv->alternate_3g_bands;
|
|
config->modem_has_hex_format_4g_bands = is_bnd_4g_format_hex (priv->software_package_version);
|
|
config->modem_ext_4g_bands = priv->ext_4g_bands;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Load current mode (Modem interface) */
|
|
|
|
gboolean
|
|
mm_shared_telit_load_current_modes_finish (MMIfaceModem *self,
|
|
GAsyncResult *res,
|
|
MMModemMode *allowed,
|
|
MMModemMode *preferred,
|
|
GError **error)
|
|
{
|
|
const gchar *response;
|
|
const gchar *str;
|
|
gint a;
|
|
|
|
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
|
|
if (!response)
|
|
return FALSE;
|
|
|
|
str = mm_strip_tag (response, "+WS46: ");
|
|
|
|
if (!sscanf (str, "%d", &a)) {
|
|
g_set_error (error,
|
|
MM_CORE_ERROR,
|
|
MM_CORE_ERROR_FAILED,
|
|
"Couldn't parse +WS46 response: '%s'",
|
|
response);
|
|
return FALSE;
|
|
}
|
|
|
|
*preferred = MM_MODEM_MODE_NONE;
|
|
switch (a) {
|
|
case 12:
|
|
*allowed = MM_MODEM_MODE_2G;
|
|
return TRUE;
|
|
case 22:
|
|
*allowed = MM_MODEM_MODE_3G;
|
|
return TRUE;
|
|
case 25:
|
|
if (mm_iface_modem_is_3gpp_lte (self))
|
|
*allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G);
|
|
else
|
|
*allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
|
|
return TRUE;
|
|
case 28:
|
|
*allowed = MM_MODEM_MODE_4G;
|
|
return TRUE;
|
|
case 29:
|
|
*allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
|
|
return TRUE;
|
|
case 30:
|
|
*allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_4G);
|
|
return TRUE;
|
|
case 31:
|
|
*allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G);
|
|
return TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
g_set_error (error,
|
|
MM_CORE_ERROR,
|
|
MM_CORE_ERROR_FAILED,
|
|
"Couldn't parse unexpected +WS46 response: '%s'",
|
|
response);
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
mm_shared_telit_load_current_modes (MMIfaceModem *self,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
|
"+WS46?",
|
|
3,
|
|
FALSE,
|
|
callback,
|
|
user_data);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Load supported bands (Modem interface) */
|
|
|
|
GArray *
|
|
mm_shared_telit_modem_load_supported_bands_finish (MMIfaceModem *self,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_pointer (G_TASK (res), error);
|
|
}
|
|
|
|
static void
|
|
load_supported_bands_ready (MMBaseModem *self,
|
|
GAsyncResult *res,
|
|
GTask *task)
|
|
{
|
|
const gchar *response;
|
|
GError *error = NULL;
|
|
Private *priv;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
|
|
response = mm_base_modem_at_command_finish (self, res, &error);
|
|
if (!response)
|
|
g_task_return_error (task, error);
|
|
else {
|
|
GArray *bands;
|
|
MMTelitBNDParseConfig config;
|
|
|
|
mm_shared_telit_get_bnd_parse_config (MM_IFACE_MODEM (self), &config);
|
|
|
|
bands = mm_telit_parse_bnd_test_response (response, &config, self, &error);
|
|
if (!bands)
|
|
g_task_return_error (task, error);
|
|
else {
|
|
/* Store supported bands to be able to build ANY when setting */
|
|
priv->supported_bands = g_array_ref (bands);
|
|
if (priv->ext_4g_bands)
|
|
mm_obj_dbg (self, "telit modem using extended 4G band setup");
|
|
g_task_return_pointer (task, bands, (GDestroyNotify)g_array_unref);
|
|
}
|
|
}
|
|
|
|
g_object_unref (task);
|
|
}
|
|
|
|
static void
|
|
load_supported_bands_at (MMIfaceModem *self,
|
|
GTask *task)
|
|
{
|
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
|
"#BND=?",
|
|
3,
|
|
TRUE,
|
|
(GAsyncReadyCallback) load_supported_bands_ready,
|
|
task);
|
|
}
|
|
|
|
static void
|
|
parent_load_supported_bands_ready (MMIfaceModem *self,
|
|
GAsyncResult *res,
|
|
GTask *task)
|
|
{
|
|
GArray *bands;
|
|
GError *error = NULL;
|
|
Private *priv;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
|
|
bands = priv->iface_modem_parent->load_supported_bands_finish (MM_IFACE_MODEM (self), res, &error);
|
|
if (bands) {
|
|
g_task_return_pointer (task, bands, (GDestroyNotify)g_array_unref);
|
|
g_object_unref (task);
|
|
} else {
|
|
mm_obj_dbg (self, "parent load supported bands failure, falling back to AT commands");
|
|
load_supported_bands_at (self, task);
|
|
g_clear_error (&error);
|
|
}
|
|
}
|
|
|
|
void
|
|
mm_shared_telit_modem_load_supported_bands (MMIfaceModem *self,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
GTask *task;
|
|
Private *priv;
|
|
|
|
task = g_task_new (self, NULL, callback, user_data);
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
|
|
if (priv->iface_modem_parent &&
|
|
priv->iface_modem_parent->load_supported_bands &&
|
|
priv->iface_modem_parent->load_supported_bands_finish) {
|
|
priv->iface_modem_parent->load_supported_bands (self,
|
|
(GAsyncReadyCallback) parent_load_supported_bands_ready,
|
|
task);
|
|
} else
|
|
load_supported_bands_at (self, task);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Load current bands (Modem interface) */
|
|
|
|
GArray *
|
|
mm_shared_telit_modem_load_current_bands_finish (MMIfaceModem *self,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_pointer (G_TASK (res), error);
|
|
}
|
|
|
|
static void
|
|
load_current_bands_ready (MMBaseModem *self,
|
|
GAsyncResult *res,
|
|
GTask *task)
|
|
{
|
|
const gchar *response;
|
|
GError *error = NULL;
|
|
|
|
response = mm_base_modem_at_command_finish (self, res, &error);
|
|
if (!response)
|
|
g_task_return_error (task, error);
|
|
else {
|
|
GArray *bands;
|
|
MMTelitBNDParseConfig config;
|
|
|
|
mm_shared_telit_get_bnd_parse_config (MM_IFACE_MODEM (self), &config);
|
|
|
|
bands = mm_telit_parse_bnd_query_response (response, &config, self, &error);
|
|
if (!bands)
|
|
g_task_return_error (task, error);
|
|
else
|
|
g_task_return_pointer (task, bands, (GDestroyNotify)g_array_unref);
|
|
}
|
|
|
|
g_object_unref (task);
|
|
}
|
|
|
|
static void
|
|
load_current_bands_at (MMIfaceModem *self,
|
|
GTask *task)
|
|
{
|
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
|
"#BND?",
|
|
3,
|
|
FALSE,
|
|
(GAsyncReadyCallback) load_current_bands_ready,
|
|
task);
|
|
}
|
|
|
|
static void
|
|
parent_load_current_bands_ready (MMIfaceModem *self,
|
|
GAsyncResult *res,
|
|
GTask *task)
|
|
{
|
|
GArray *bands;
|
|
GError *error = NULL;
|
|
Private *priv;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
|
|
bands = priv->iface_modem_parent->load_current_bands_finish (MM_IFACE_MODEM (self), res, &error);
|
|
if (bands) {
|
|
g_task_return_pointer (task, bands, (GDestroyNotify)g_array_unref);
|
|
g_object_unref (task);
|
|
} else {
|
|
mm_obj_dbg (self, "parent load current bands failure, falling back to AT commands");
|
|
load_current_bands_at (self, task);
|
|
g_clear_error (&error);
|
|
}
|
|
}
|
|
|
|
void
|
|
mm_shared_telit_modem_load_current_bands (MMIfaceModem *self,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
GTask *task;
|
|
Private *priv;
|
|
|
|
task = g_task_new (self, NULL, callback, user_data);
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
|
|
if (priv->iface_modem_parent &&
|
|
priv->iface_modem_parent->load_current_bands &&
|
|
priv->iface_modem_parent->load_current_bands_finish) {
|
|
priv->iface_modem_parent->load_current_bands (self,
|
|
(GAsyncReadyCallback) parent_load_current_bands_ready,
|
|
task);
|
|
} else
|
|
load_current_bands_at (self, task);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Set current bands (Modem interface) */
|
|
|
|
gboolean
|
|
mm_shared_telit_modem_set_current_bands_finish (MMIfaceModem *self,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_boolean (G_TASK (res), error);
|
|
}
|
|
|
|
static void
|
|
set_current_bands_ready (MMBaseModem *self,
|
|
GAsyncResult *res,
|
|
GTask *task)
|
|
{
|
|
GError *error = NULL;
|
|
|
|
mm_base_modem_at_command_finish (self, res, &error);
|
|
if (error)
|
|
g_task_return_error (task, error);
|
|
else
|
|
g_task_return_boolean (task, TRUE);
|
|
|
|
g_object_unref (task);
|
|
}
|
|
|
|
static void
|
|
set_current_bands_at (MMIfaceModem *self,
|
|
GTask *task)
|
|
{
|
|
GError *error = NULL;
|
|
gchar *cmd;
|
|
GArray *bands_array;
|
|
MMTelitBNDParseConfig config;
|
|
|
|
bands_array = g_task_get_task_data (task);
|
|
g_assert (bands_array);
|
|
|
|
if (bands_array->len == 1 && g_array_index (bands_array, MMModemBand, 0) == MM_MODEM_BAND_ANY) {
|
|
Private *priv;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
if (!priv->supported_bands) {
|
|
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
|
"Couldn't build ANY band settings: unknown supported bands");
|
|
g_object_unref (task);
|
|
return;
|
|
}
|
|
bands_array = priv->supported_bands;
|
|
}
|
|
|
|
mm_shared_telit_get_bnd_parse_config (self, &config);
|
|
cmd = mm_telit_build_bnd_request (bands_array, &config, &error);
|
|
if (!cmd) {
|
|
g_task_return_error (task, error);
|
|
g_object_unref (task);
|
|
return;
|
|
}
|
|
|
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
|
cmd,
|
|
20,
|
|
FALSE,
|
|
(GAsyncReadyCallback)set_current_bands_ready,
|
|
task);
|
|
g_free (cmd);
|
|
}
|
|
|
|
static void
|
|
parent_set_current_bands_ready (MMIfaceModem *self,
|
|
GAsyncResult *res,
|
|
GTask *task)
|
|
{
|
|
GError *error = NULL;
|
|
Private *priv;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
|
|
if (priv->iface_modem_parent->set_current_bands_finish (MM_IFACE_MODEM (self), res, &error)) {
|
|
g_task_return_boolean (task, TRUE);
|
|
g_object_unref (task);
|
|
} else {
|
|
g_clear_error (&error);
|
|
set_current_bands_at (self, task);
|
|
}
|
|
}
|
|
|
|
void
|
|
mm_shared_telit_modem_set_current_bands (MMIfaceModem *self,
|
|
GArray *bands_array,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
GTask *task;
|
|
Private *priv;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
|
|
task = g_task_new (self, NULL, callback, user_data);
|
|
g_task_set_task_data (task, g_array_ref (bands_array), (GDestroyNotify)g_array_unref);
|
|
|
|
if (priv->iface_modem_parent &&
|
|
priv->iface_modem_parent->set_current_bands &&
|
|
priv->iface_modem_parent->set_current_bands_finish) {
|
|
priv->iface_modem_parent->set_current_bands (self,
|
|
bands_array,
|
|
(GAsyncReadyCallback) parent_set_current_bands_ready,
|
|
task);
|
|
} else
|
|
set_current_bands_at (self, task);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Set current modes (Modem interface) */
|
|
|
|
gboolean
|
|
mm_shared_telit_set_current_modes_finish (MMIfaceModem *self,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_boolean (G_TASK (res), error);
|
|
}
|
|
|
|
static void
|
|
ws46_set_ready (MMBaseModem *self,
|
|
GAsyncResult *res,
|
|
GTask *task)
|
|
{
|
|
GError *error = NULL;
|
|
|
|
mm_base_modem_at_command_finish (self, res, &error);
|
|
if (error)
|
|
/* Let the error be critical. */
|
|
g_task_return_error (task, error);
|
|
else
|
|
g_task_return_boolean (task, TRUE);
|
|
g_object_unref (task);
|
|
}
|
|
|
|
void
|
|
mm_shared_telit_set_current_modes (MMIfaceModem *self,
|
|
MMModemMode allowed,
|
|
MMModemMode preferred,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
GTask *task;
|
|
gchar *command;
|
|
Private *priv;
|
|
gint ws46_mode = -1;
|
|
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
task = g_task_new (self, NULL, callback, user_data);
|
|
|
|
if (allowed == MM_MODEM_MODE_ANY && priv->supported_modes) {
|
|
guint i;
|
|
|
|
allowed = MM_MODEM_MODE_NONE;
|
|
/* Process list of modes to gather supported ones */
|
|
for (i = 0; i < priv->supported_modes->len; i++) {
|
|
if (g_array_index (priv->supported_modes, MMModemMode, i) & MM_MODEM_MODE_2G)
|
|
allowed |= MM_MODEM_MODE_2G;
|
|
if (g_array_index (priv->supported_modes, MMModemMode, i) & MM_MODEM_MODE_3G)
|
|
allowed |= MM_MODEM_MODE_3G;
|
|
if (g_array_index (priv->supported_modes, MMModemMode, i) & MM_MODEM_MODE_4G)
|
|
allowed |= MM_MODEM_MODE_4G;
|
|
}
|
|
}
|
|
|
|
if (allowed == MM_MODEM_MODE_2G)
|
|
ws46_mode = 12;
|
|
else if (allowed == MM_MODEM_MODE_3G)
|
|
ws46_mode = 22;
|
|
else if (allowed == MM_MODEM_MODE_4G)
|
|
ws46_mode = 28;
|
|
else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) {
|
|
if (mm_iface_modem_is_3gpp_lte (self))
|
|
ws46_mode = 29;
|
|
else
|
|
ws46_mode = 25;
|
|
} else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_4G))
|
|
ws46_mode = 30;
|
|
else if (allowed == (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G))
|
|
ws46_mode = 31;
|
|
else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G))
|
|
ws46_mode = 25;
|
|
|
|
/* Telit modems do not support preferred mode selection */
|
|
if ((ws46_mode < 0) || (preferred != MM_MODEM_MODE_NONE)) {
|
|
gchar *allowed_str;
|
|
gchar *preferred_str;
|
|
|
|
allowed_str = mm_modem_mode_build_string_from_mask (allowed);
|
|
preferred_str = mm_modem_mode_build_string_from_mask (preferred);
|
|
g_task_return_new_error (task,
|
|
MM_CORE_ERROR,
|
|
MM_CORE_ERROR_FAILED,
|
|
"Requested mode (allowed: '%s', preferred: '%s') not "
|
|
"supported by the modem.",
|
|
allowed_str,
|
|
preferred_str);
|
|
g_free (allowed_str);
|
|
g_free (preferred_str);
|
|
|
|
g_object_unref (task);
|
|
return;
|
|
}
|
|
|
|
command = g_strdup_printf ("AT+WS46=%d", ws46_mode);
|
|
mm_base_modem_at_command (
|
|
MM_BASE_MODEM (self),
|
|
command,
|
|
10,
|
|
FALSE,
|
|
(GAsyncReadyCallback) ws46_set_ready,
|
|
task);
|
|
g_free (command);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Revision loading */
|
|
|
|
gchar *
|
|
mm_shared_telit_modem_load_revision_finish (MMIfaceModem *self,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_pointer (G_TASK (res), error);
|
|
}
|
|
|
|
static void
|
|
load_revision_ready (MMBaseModem *self,
|
|
GAsyncResult *res,
|
|
GTask *task)
|
|
{
|
|
GError *error;
|
|
GVariant *result;
|
|
|
|
result = mm_base_modem_at_sequence_finish (self, res, NULL, &error);
|
|
if (!result) {
|
|
g_task_return_error (task, error);
|
|
g_object_unref (task);
|
|
} else {
|
|
gchar *revision = NULL;
|
|
|
|
revision = g_variant_dup_string (result, NULL);
|
|
mm_shared_telit_store_revision (MM_SHARED_TELIT (self), revision);
|
|
g_task_return_pointer (task, revision, g_free);
|
|
g_object_unref (task);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* parse AT#SWPKGV command
|
|
* Execution command returns the software package version without #SWPKGV: command echo.
|
|
* The response is as follows:
|
|
*
|
|
* AT#SWPKGV
|
|
* <Telit Software Package Version>-<Production Parameters Version>
|
|
* <Modem FW Version> (Usually the same value returned by AT+GMR)
|
|
* <Production Parameters Version>
|
|
* <Application FW Version>
|
|
*/
|
|
static MMBaseModemAtResponseProcessorResult
|
|
software_package_version_ready (MMBaseModem *self,
|
|
gpointer none,
|
|
const gchar *command,
|
|
const gchar *response,
|
|
gboolean last_command,
|
|
const GError *error,
|
|
GVariant **result,
|
|
GError **result_error)
|
|
{
|
|
gchar *version = NULL;
|
|
|
|
if (error) {
|
|
*result = NULL;
|
|
|
|
/* Ignore AT errors (ie, ERROR or CMx ERROR) */
|
|
if (error->domain != MM_MOBILE_EQUIPMENT_ERROR || last_command) {
|
|
*result_error = g_error_copy (error);
|
|
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_FAILURE;
|
|
}
|
|
|
|
*result_error = NULL;
|
|
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE;
|
|
}
|
|
|
|
version = mm_telit_parse_swpkgv_response (response);
|
|
if (!version)
|
|
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE;
|
|
|
|
*result = g_variant_new_take_string (version);
|
|
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS;
|
|
}
|
|
|
|
static const MMBaseModemAtCommand revisions[] = {
|
|
{ "#SWPKGV", 3, TRUE, software_package_version_ready },
|
|
{ "+CGMR", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors },
|
|
{ "+GMR", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors },
|
|
{ NULL }
|
|
};
|
|
|
|
void
|
|
mm_shared_telit_modem_load_revision (MMIfaceModem *self,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
GTask *task;
|
|
Private *priv;
|
|
|
|
task = g_task_new (self, NULL, callback, user_data);
|
|
priv = get_private (MM_SHARED_TELIT (self));
|
|
|
|
mm_obj_dbg (self, "loading revision...");
|
|
if (priv->software_package_version) {
|
|
g_task_return_pointer (task,
|
|
g_strdup (priv->software_package_version),
|
|
g_free);
|
|
g_object_unref (task);
|
|
return;
|
|
}
|
|
|
|
mm_base_modem_at_sequence (
|
|
MM_BASE_MODEM (self),
|
|
revisions,
|
|
NULL, /* response_processor_context */
|
|
NULL, /* response_processor_context_free */
|
|
(GAsyncReadyCallback) load_revision_ready,
|
|
task);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
shared_telit_init (gpointer g_iface)
|
|
{
|
|
}
|
|
|
|
GType
|
|
mm_shared_telit_get_type (void)
|
|
{
|
|
static GType shared_telit_type = 0;
|
|
|
|
if (!G_UNLIKELY (shared_telit_type)) {
|
|
static const GTypeInfo info = {
|
|
sizeof (MMSharedTelit), /* class_size */
|
|
shared_telit_init, /* base_init */
|
|
NULL, /* base_finalize */
|
|
};
|
|
|
|
shared_telit_type = g_type_register_static (G_TYPE_INTERFACE, "MMSharedTelit", &info, 0);
|
|
g_type_interface_add_prerequisite (shared_telit_type, MM_TYPE_IFACE_MODEM);
|
|
}
|
|
|
|
return shared_telit_type;
|
|
}
|
|
|