aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-07-25 17:37:44 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-08-29 17:26:42 +0200
commit40f96158af253e3efcee274e8e09430e364e1c14 (patch)
treeadb44d9cb04e77dbac0800d08544e87bff95d0ca /src
parent629f452d0746156d8adc61290305eba22ac25890 (diff)
broadband-modem-qmi: implement signal quality loading using QMI
Diffstat (limited to 'src')
-rw-r--r--src/mm-broadband-modem-qmi.c242
-rw-r--r--src/mm-broadband-modem-qmi.h2
2 files changed, 244 insertions, 0 deletions
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index 192e250a..3c08f286 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -38,6 +38,11 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmi, mm_broadband_modem_qmi, MM_TYPE_BRO
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init));
+struct _MMBroadbandModemQmiPrivate {
+ /* Signal quality related */
+ gboolean has_get_signal_info;
+};
+
/*****************************************************************************/
static gboolean
@@ -1114,6 +1119,232 @@ modem_load_supported_bands (MMIfaceModem *self,
}
/*****************************************************************************/
+/* Load signal quality (Modem interface) */
+
+/* Limit the value betweeen [-113,-51] and scale it to a percentage */
+#define STRENGTH_TO_QUALITY(strength) \
+ (100 - ((CLAMP (strength, -113, -51) + 51) * 100 / (-113 + 51)))
+
+typedef struct {
+ MMBroadbandModemQmi *self;
+ QmiClient *client;
+ GSimpleAsyncResult *result;
+} LoadSignalQualityContext;
+
+static void
+load_signal_quality_context_complete_and_free (LoadSignalQualityContext *ctx)
+{
+ g_simple_async_result_complete (ctx->result);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->client);
+ g_object_unref (ctx->self);
+ g_free (ctx);
+}
+
+static guint
+load_signal_quality_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return 0;
+
+ return GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (res)));
+}
+
+static void load_signal_quality_context_step (LoadSignalQualityContext *ctx);
+
+static gint8
+signal_info_get_quality (MMBroadbandModemQmi *self,
+ QmiMessageNasGetSignalInfoOutput *output)
+{
+ gint8 rssi_max = 0;
+ gint8 rssi;
+
+ /* We do not report per-technology signal quality, so just get the highest
+ * one of the ones reported. */
+
+ if (qmi_message_nas_get_signal_info_output_get_cdma_signal_strength (output, &rssi, NULL, NULL) &&
+ rssi > rssi_max)
+ rssi_max = rssi;
+
+ if (qmi_message_nas_get_signal_info_output_get_hdr_signal_strength (output, &rssi, NULL, NULL, NULL, NULL) &&
+ rssi > rssi_max)
+ rssi_max = rssi;
+
+ if (qmi_message_nas_get_signal_info_output_get_gsm_signal_strength (output, &rssi, NULL) &&
+ rssi > rssi_max)
+ rssi_max = rssi;
+
+ if (qmi_message_nas_get_signal_info_output_get_wcdma_signal_strength (output, &rssi, NULL, NULL) &&
+ rssi > rssi_max)
+ rssi_max = rssi;
+
+ if (qmi_message_nas_get_signal_info_output_get_lte_signal_strength (output, &rssi, NULL, NULL, NULL, NULL) &&
+ rssi > rssi_max)
+ rssi_max = rssi;
+
+ /* This RSSI comes as negative dBms */
+ return STRENGTH_TO_QUALITY (rssi_max);
+}
+
+static void
+get_signal_info_ready (QmiClientNas *client,
+ GAsyncResult *res,
+ LoadSignalQualityContext *ctx)
+{
+ QmiMessageNasGetSignalInfoOutput *output;
+ GError *error = NULL;
+ guint quality;
+
+ output = qmi_client_nas_get_signal_info_finish (client, res, &error);
+ if (!output) {
+ /* If the command is not supported, fallback to the deprecated one */
+ if (g_error_matches (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_UNSUPPORTED)) {
+ g_error_free (error);
+ ctx->self->priv->has_get_signal_info = FALSE;
+ load_signal_quality_context_step (ctx);
+ return;
+ }
+
+ g_simple_async_result_take_error (ctx->result, error);
+ load_signal_quality_context_complete_and_free (ctx);
+ return;
+ }
+
+ if (!qmi_message_nas_get_signal_info_output_get_result (output, &error)) {
+ qmi_message_nas_get_signal_info_output_unref (output);
+ g_simple_async_result_take_error (ctx->result, error);
+ load_signal_quality_context_complete_and_free (ctx);
+ return;
+ }
+
+ quality = signal_info_get_quality (ctx->self, output);
+
+ g_simple_async_result_set_op_res_gpointer (
+ ctx->result,
+ GUINT_TO_POINTER (quality),
+ NULL);
+
+ qmi_message_nas_get_signal_info_output_unref (output);
+ load_signal_quality_context_complete_and_free (ctx);
+}
+
+static gint8
+signal_strength_get_quality (MMBroadbandModemQmi *self,
+ QmiMessageNasGetSignalStrengthOutput *output)
+{
+ GArray *array = NULL;
+ gint8 signal_max = 0;
+
+ /* We do not report per-technology signal quality, so just get the highest
+ * one of the ones reported. */
+
+ /* The mandatory one is always present */
+ qmi_message_nas_get_signal_strength_output_get_signal_strength (output, &signal_max, NULL, NULL);
+
+ /* On multimode devices we may get more */
+ if (qmi_message_nas_get_signal_strength_output_get_strength_list (output, &array, NULL)) {
+ guint i;
+
+ for (i = 0; i < array->len; i++) {
+ QmiMessageNasGetSignalStrengthOutputStrengthListElement *element;
+
+ element = &g_array_index (array, QmiMessageNasGetSignalStrengthOutputStrengthListElement, i);
+ if (element->strength > signal_max)
+ signal_max = element->strength;
+ }
+ }
+
+ /* This signal strength comes as negative dBms */
+ return STRENGTH_TO_QUALITY (signal_max);
+}
+
+static void
+get_signal_strength_ready (QmiClientNas *client,
+ GAsyncResult *res,
+ LoadSignalQualityContext *ctx)
+{
+ QmiMessageNasGetSignalStrengthOutput *output;
+ GError *error = NULL;
+ guint quality;
+
+ output = qmi_client_nas_get_signal_strength_finish (client, res, &error);
+ if (!output) {
+ g_simple_async_result_take_error (ctx->result, error);
+ load_signal_quality_context_complete_and_free (ctx);
+ return;
+ }
+
+ if (!qmi_message_nas_get_signal_strength_output_get_result (output, &error)) {
+ qmi_message_nas_get_signal_strength_output_unref (output);
+ g_simple_async_result_take_error (ctx->result, error);
+ load_signal_quality_context_complete_and_free (ctx);
+ return;
+ }
+
+ quality = signal_strength_get_quality (ctx->self, output);
+
+ g_simple_async_result_set_op_res_gpointer (
+ ctx->result,
+ GUINT_TO_POINTER (quality),
+ NULL);
+
+ qmi_message_nas_get_signal_strength_output_unref (output);
+ load_signal_quality_context_complete_and_free (ctx);
+}
+
+static void
+load_signal_quality_context_step (LoadSignalQualityContext *ctx)
+{
+ if (ctx->self->priv->has_get_signal_info) {
+ qmi_client_nas_get_signal_info (QMI_CLIENT_NAS (ctx->client),
+ NULL,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)get_signal_info_ready,
+ ctx);
+ return;
+ }
+
+ /* Fallback to the deprecated mode if the new one not supported */
+ qmi_client_nas_get_signal_strength (QMI_CLIENT_NAS (ctx->client),
+ NULL,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)get_signal_strength_ready,
+ ctx);
+}
+
+static void
+load_signal_quality (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ LoadSignalQualityContext *ctx;
+ QmiClient *client = NULL;
+
+ if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
+ QMI_SERVICE_NAS, &client,
+ callback, user_data))
+ return;
+
+ ctx = g_new0 (LoadSignalQualityContext, 1);
+ ctx->self = g_object_ref (self);
+ ctx->client = g_object_ref (client);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ load_signal_quality);
+
+ mm_dbg ("loading signal quality...");
+ load_signal_quality_context_step (ctx);
+}
+
+/*****************************************************************************/
/* Create SIM (Modem interface) */
static MMSim *
@@ -1763,6 +1994,13 @@ mm_broadband_modem_qmi_new (const gchar *device,
static void
mm_broadband_modem_qmi_init (MMBroadbandModemQmi *self)
{
+ /* Initialize private data */
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_BROADBAND_MODEM_QMI,
+ MMBroadbandModemQmiPrivate);
+
+ /* Always try to use the newest command available first */
+ self->priv->has_get_signal_info = TRUE;
}
static void
@@ -1805,6 +2043,8 @@ iface_modem_init (MMIfaceModem *iface)
iface->load_unlock_retries_finish = modem_load_unlock_retries_finish;
iface->load_supported_bands = modem_load_supported_bands;
iface->load_supported_bands_finish = modem_load_supported_bands_finish;
+ iface->load_signal_quality = load_signal_quality;
+ iface->load_signal_quality_finish = load_signal_quality_finish;
/* Create QMI-specific SIM */
iface->create_sim = create_sim;
@@ -1833,6 +2073,8 @@ mm_broadband_modem_qmi_class_init (MMBroadbandModemQmiClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (MMBroadbandModemQmiPrivate));
+
object_class->finalize = finalize;
broadband_modem_class->initialization_started = initialization_started;
diff --git a/src/mm-broadband-modem-qmi.h b/src/mm-broadband-modem-qmi.h
index c0995d9e..6c79e5eb 100644
--- a/src/mm-broadband-modem-qmi.h
+++ b/src/mm-broadband-modem-qmi.h
@@ -27,9 +27,11 @@
typedef struct _MMBroadbandModemQmi MMBroadbandModemQmi;
typedef struct _MMBroadbandModemQmiClass MMBroadbandModemQmiClass;
+typedef struct _MMBroadbandModemQmiPrivate MMBroadbandModemQmiPrivate;
struct _MMBroadbandModemQmi {
MMBroadbandModem parent;
+ MMBroadbandModemQmiPrivate *priv;
};
struct _MMBroadbandModemQmiClass{