From 243360caacc7ab96d8aac9c481df0a2c961a67ba Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 9 Apr 2013 14:10:32 -0500 Subject: broadband-modem-qmi: ignore invalid signal strengths Sometimes invalid signal strengths will be returned by the modem, which we should ignore. Otherwise they make the reported signal quality bounce around from eg 21% -> 100%, or cause access technology updates for radio interfaces that can't possible have a usable signal. --- src/mm-broadband-modem-qmi.c | 158 +++++++++++++++++++++++++++++-------------- 1 file changed, 109 insertions(+), 49 deletions(-) diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c index c33f707d..6afecdeb 100644 --- a/src/mm-broadband-modem-qmi.c +++ b/src/mm-broadband-modem-qmi.c @@ -1824,6 +1824,22 @@ modem_load_supported_modes (MMIfaceModem *self, #define STRENGTH_TO_QUALITY(strength) \ (guint8)(100 - ((CLAMP (strength, -113, -51) + 51) * 100 / (-113 + 51))) +static gboolean +qmi_dbm_valid (gint8 dbm, QmiNasRadioInterface radio_interface) +{ + /* Different radio interfaces have different signal quality bounds */ + switch (radio_interface) { + case QMI_NAS_RADIO_INTERFACE_CDMA_1X: + case QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO: + return (dbm > -125 && dbm < -30); + case QMI_NAS_RADIO_INTERFACE_UMTS: + return (dbm > -125 && dbm < -30); + default: + break; + } + return TRUE; +} + typedef struct { MMBroadbandModemQmi *self; QmiClient *client; @@ -1854,47 +1870,55 @@ load_signal_quality_finish (MMIfaceModem *self, #if defined WITH_NEWEST_QMI_COMMANDS -static gint8 +static gboolean signal_info_get_quality (MMBroadbandModemQmi *self, - QmiMessageNasGetSignalInfoOutput *output) + QmiMessageNasGetSignalInfoOutput *output, + gint8 *out_quality) { gint8 rssi_max = 0; gint8 rssi; - guint8 quality; + + g_assert (out_quality != NULL); /* 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)) { mm_dbg ("RSSI (CDMA): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_CDMA_1X)) + rssi = MAX (rssi, rssi_max); } if (qmi_message_nas_get_signal_info_output_get_hdr_signal_strength (output, &rssi, NULL, NULL, NULL, NULL)) { mm_dbg ("RSSI (HDR): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO)) + rssi = MAX (rssi, rssi_max); } if (qmi_message_nas_get_signal_info_output_get_gsm_signal_strength (output, &rssi, NULL)) { mm_dbg ("RSSI (GSM): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_GSM)) + rssi = MAX (rssi, rssi_max); } if (qmi_message_nas_get_signal_info_output_get_wcdma_signal_strength (output, &rssi, NULL, NULL)) { mm_dbg ("RSSI (WCDMA): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_UMTS)) + rssi = MAX (rssi, rssi_max); } if (qmi_message_nas_get_signal_info_output_get_lte_signal_strength (output, &rssi, NULL, NULL, NULL, NULL)) { mm_dbg ("RSSI (LTE): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_LTE)) + rssi = MAX (rssi, rssi_max); } /* This RSSI comes as negative dBms */ - quality = STRENGTH_TO_QUALITY (rssi_max); + *out_quality = STRENGTH_TO_QUALITY (rssi_max); + + mm_dbg ("RSSI: %d dBm --> %u%%", rssi_max, *out_quality); - mm_dbg ("RSSI: %d dBm --> %u%%", rssi_max, quality); - return quality; + return (rssi_max < 0); } static void @@ -1904,7 +1928,7 @@ get_signal_info_ready (QmiClientNas *client, { QmiMessageNasGetSignalInfoOutput *output; GError *error = NULL; - guint quality; + guint quality = 0; output = qmi_client_nas_get_signal_info_finish (client, res, &error); if (!output) { @@ -1920,7 +1944,15 @@ get_signal_info_ready (QmiClientNas *client, return; } - quality = signal_info_get_quality (ctx->self, output); + if (!signal_info_get_quality (ctx->self, output, &quality)) { + qmi_message_nas_get_signal_info_output_unref (output); + g_simple_async_result_set_error (ctx->result, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Signal info reported invalid signal strength."); + load_signal_quality_context_complete_and_free (ctx); + return; + } g_simple_async_result_set_op_res_gpointer ( ctx->result, @@ -1933,17 +1965,16 @@ get_signal_info_ready (QmiClientNas *client, #endif /* WITH_NEWEST_QMI_COMMANDS */ -static void +static gboolean signal_strength_get_quality_and_access_tech (MMBroadbandModemQmi *self, QmiMessageNasGetSignalStrengthOutput *output, guint8 *o_quality, MMModemAccessTechnology *o_act) { GArray *array = NULL; - gint8 signal_max; + gint8 signal_max = 0; QmiNasRadioInterface main_interface; MMModemAccessTechnology act; - guint8 quality; /* We do not report per-technology signal quality, so just get the highest * one of the ones reported. */ @@ -1954,6 +1985,10 @@ signal_strength_get_quality_and_access_tech (MMBroadbandModemQmi *self, qmi_nas_radio_interface_get_string (main_interface), signal_max); + /* Treat results as invalid if main signal strength is invalid */ + if (!qmi_dbm_valid (signal_max, main_interface)) + return FALSE; + act = mm_modem_access_technology_from_qmi_radio_interface (main_interface); /* On multimode devices we may get more */ @@ -1969,19 +2004,22 @@ signal_strength_get_quality_and_access_tech (MMBroadbandModemQmi *self, qmi_nas_radio_interface_get_string (element->radio_interface), element->strength); - signal_max = MAX (element->strength, signal_max); - - act |= mm_modem_access_technology_from_qmi_radio_interface (element->radio_interface); + if (qmi_dbm_valid (element->strength, element->radio_interface)) { + signal_max = MAX (element->strength, signal_max); + act |= mm_modem_access_technology_from_qmi_radio_interface (element->radio_interface); + } } } - /* This signal strength comes as negative dBms */ - quality = STRENGTH_TO_QUALITY (signal_max); + if (signal_max < 0) { + /* This signal strength comes as negative dBms */ + *o_quality = STRENGTH_TO_QUALITY (signal_max); + *o_act = act; - mm_dbg ("Signal strength: %d dBm --> %u%%", signal_max, quality); + mm_dbg ("Signal strength: %d dBm --> %u%%", signal_max, *o_quality); + } - *o_quality = quality; - *o_act = act; + return (signal_max < 0); } static void @@ -2008,7 +2046,15 @@ get_signal_strength_ready (QmiClientNas *client, return; } - signal_strength_get_quality_and_access_tech (ctx->self, output, &quality, &act); + if (!signal_strength_get_quality_and_access_tech (ctx->self, output, &quality, &act)) { + qmi_message_nas_get_signal_strength_output_unref (output); + g_simple_async_result_set_error (ctx->result, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "GetSignalStrength signal strength invalid."); + load_signal_quality_context_complete_and_free (ctx); + return; + } /* We update the access technologies directly here when loading signal * quality. It goes a bit out of context, but we can do it nicely */ @@ -5607,21 +5653,27 @@ event_report_indication_cb (QmiClientNas *client, &signal_strength, &signal_strength_radio_interface, NULL)) { - guint8 quality; - - /* This signal strength comes as negative dBms */ - quality = STRENGTH_TO_QUALITY (signal_strength); - - mm_dbg ("Signal strength indication (%s): %d dBm --> %u%%", - qmi_nas_radio_interface_get_string (signal_strength_radio_interface), - signal_strength, - quality); - - mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality); - mm_iface_modem_update_access_technologies ( - MM_IFACE_MODEM (self), - mm_modem_access_technology_from_qmi_radio_interface (signal_strength_radio_interface), - (MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK | MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK)); + if (qmi_dbm_valid (signal_strength, signal_strength_radio_interface)) { + guint8 quality; + + /* This signal strength comes as negative dBms */ + quality = STRENGTH_TO_QUALITY (signal_strength); + + mm_dbg ("Signal strength indication (%s): %d dBm --> %u%%", + qmi_nas_radio_interface_get_string (signal_strength_radio_interface), + signal_strength, + quality); + + mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality); + mm_iface_modem_update_access_technologies ( + MM_IFACE_MODEM (self), + mm_modem_access_technology_from_qmi_radio_interface (signal_strength_radio_interface), + (MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK | MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK)); + } else { + mm_dbg ("Ignoring invalid signal strength (%s): %d dBm", + qmi_nas_radio_interface_get_string (signal_strength_radio_interface), + signal_strength); + } } } @@ -5644,35 +5696,43 @@ signal_info_indication_cb (QmiClientNas *client, if (qmi_indication_nas_signal_info_output_get_cdma_signal_strength (output, &rssi, NULL, NULL)) { mm_dbg ("RSSI (CDMA): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_CDMA_1X)) + rssi = MAX (rssi, rssi_max); } if (qmi_indication_nas_signal_info_output_get_hdr_signal_strength (output, &rssi, NULL, NULL, NULL, NULL)) { mm_dbg ("RSSI (HDR): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO)) + rssi = MAX (rssi, rssi_max); } if (qmi_indication_nas_signal_info_output_get_gsm_signal_strength (output, &rssi, NULL)) { mm_dbg ("RSSI (GSM): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_GSM)) + rssi = MAX (rssi, rssi_max); } if (qmi_indication_nas_signal_info_output_get_wcdma_signal_strength (output, &rssi, NULL, NULL)) { mm_dbg ("RSSI (WCDMA): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_UMTS)) + rssi = MAX (rssi, rssi_max); } if (qmi_indication_nas_signal_info_output_get_lte_signal_strength (output, &rssi, NULL, NULL, NULL, NULL)) { mm_dbg ("RSSI (LTE): %d dBm", rssi); - rssi = MAX (rssi, rssi_max); + if (qmi_dbm_valid (rssi, QMI_NAS_RADIO_INTERFACE_LTE)) + rssi = MAX (rssi, rssi_max); } - /* This RSSI comes as negative dBms */ - quality = STRENGTH_TO_QUALITY (rssi_max); + if (rssi_max < 0) { + /* This RSSI comes as negative dBms */ + quality = STRENGTH_TO_QUALITY (rssi_max); - mm_dbg ("RSSI: %d dBm --> %u%%", rssi_max, quality); + mm_dbg ("RSSI: %d dBm --> %u%%", rssi_max, quality); - mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality); + mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality); + } else + mm_dbg ("Ignoring invalid signal strength: %d dBm", rssi_max); } #endif /* WITH_NEWEST_QMI_COMMANDS */ -- cgit v1.2.3