From 53bcdaa8c3962abbf2a2f638c64173a7657ab560 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Thu, 21 Oct 2021 00:10:06 +0200 Subject: broadband-modem-mbim: update extended signal info on MBIM notifications We process the MBIM signal state notification and use it to update the extended signal quality information in the Signal interface. --- src/mm-broadband-modem-mbim.c | 29 ++++-- src/mm-modem-helpers-mbim.c | 236 +++++++++++++++++++++++++++++++++++++++++- src/mm-modem-helpers-mbim.h | 33 ++++++ 3 files changed, 291 insertions(+), 7 deletions(-) diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c index be2e7dd9..fef05d4a 100644 --- a/src/mm-broadband-modem-mbim.c +++ b/src/mm-broadband-modem-mbim.c @@ -3553,14 +3553,22 @@ basic_connect_notification_signal_state (MMBroadbandModemMbim *self, g_autoptr(GError) error = NULL; g_autoptr(MbimRsrpSnrInfoArray) rsrp_snr = NULL; guint32 rsrp_snr_count = 0; - guint32 rssi; + guint32 coded_rssi; + guint32 coded_error_rate; guint32 quality; + MbimDataClass data_class; + g_autoptr(MMSignal) cdma = NULL; + g_autoptr(MMSignal) evdo = NULL; + g_autoptr(MMSignal) gsm = NULL; + g_autoptr(MMSignal) umts = NULL; + g_autoptr(MMSignal) lte = NULL; + g_autoptr(MMSignal) nr5g = NULL; if (mbim_device_check_ms_mbimex_version (device, 2, 0)) { if (!mbim_message_ms_basic_connect_v2_signal_state_notification_parse ( notification, - &rssi, - NULL, /* error_rate */ + &coded_rssi, + &coded_error_rate, NULL, /* signal_strength_interval */ NULL, /* rssi_threshold */ NULL, /* error_rate_threshold */ @@ -3574,8 +3582,8 @@ basic_connect_notification_signal_state (MMBroadbandModemMbim *self, } else { if (!mbim_message_signal_state_notification_parse ( notification, - &rssi, - NULL, /* error_rate */ + &coded_rssi, + &coded_error_rate, NULL, /* signal_strength_interval */ NULL, /* rssi_threshold */ NULL, /* error_rate_threshold */ @@ -3586,8 +3594,17 @@ basic_connect_notification_signal_state (MMBroadbandModemMbim *self, mm_obj_dbg (self, "proccessed signal state indication"); } - quality = mm_signal_quality_from_mbim_signal_state (rssi, rsrp_snr, rsrp_snr_count, self); + quality = mm_signal_quality_from_mbim_signal_state (coded_rssi, rsrp_snr, rsrp_snr_count, self); mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality); + + /* Best guess of current data class */ + data_class = self->priv->highest_available_data_class; + if (data_class == 0) + data_class = self->priv->available_data_classes; + + if (mm_signal_from_mbim_signal_state (data_class, coded_rssi, coded_error_rate, rsrp_snr, rsrp_snr_count, + self, &cdma, &evdo, &gsm, &umts, <e, &nr5g)) + mm_iface_modem_signal_update (MM_IFACE_MODEM_SIGNAL (self), cdma, evdo, gsm, umts, lte, nr5g); } static void diff --git a/src/mm-modem-helpers-mbim.c b/src/mm-modem-helpers-mbim.c index 8157f9f6..25e87e0e 100644 --- a/src/mm-modem-helpers-mbim.c +++ b/src/mm-modem-helpers-mbim.c @@ -10,7 +10,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details: * - * Copyright (C) 2013 Aleksander Morgado + * Copyright (C) 2013-2021 Aleksander Morgado */ #include "mm-modem-helpers-mbim.h" @@ -558,6 +558,84 @@ mm_bearer_ip_family_to_mbim_context_ip_type (MMBearerIpFamily ip_family, /*****************************************************************************/ +/* index in the array is the code point (8 possible values), and the actual + * value is the lower limit of the error rate range. */ +static const gdouble bit_error_rate_ranges[] = { 0.00, 0.20, 0.40, 0.80, 1.60, 3.20, 6.40, 12.80 }; +static const gdouble frame_error_rate_ranges[] = { 0.00, 0.01, 0.10, 0.50, 1.00, 2.00, 4.00, 8.00 }; + +gboolean +mm_signal_error_rate_percentage_from_coded_value (guint coded_value, + gdouble *out_percentage, + gboolean is_gsm, + GError **error) +{ + if ((is_gsm && (coded_value >= G_N_ELEMENTS (bit_error_rate_ranges))) || + (!is_gsm && (coded_value >= G_N_ELEMENTS (frame_error_rate_ranges)))) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "error rate coded value out of range: %u", coded_value); + return FALSE; + } + + *out_percentage = (is_gsm ? bit_error_rate_ranges[coded_value] : frame_error_rate_ranges[coded_value]); + return TRUE; +} + +/*****************************************************************************/ + +gboolean +mm_signal_rssi_from_coded_value (guint coded_value, + gdouble *out_rssi, + GError **error) +{ + /* expected values between 0 and 31 */ + if (coded_value > 31) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "rssi coded value out of range: %u", coded_value); + return FALSE; + } + + *out_rssi = (gdouble)coded_value - 113; + return TRUE; +} + +/*****************************************************************************/ + +gboolean +mm_signal_rsrp_from_coded_value (guint coded_value, + gdouble *out_rsrp, + GError **error) +{ + /* expected values between 0 and 126 */ + if (coded_value > 126) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "rsrp coded value out of range: %u", coded_value); + return FALSE; + } + + *out_rsrp = (gdouble)coded_value - 156; + return TRUE; +} + +/*****************************************************************************/ + +gboolean +mm_signal_snr_from_coded_value (guint coded_value, + gdouble *out_snr, + GError **error) +{ + /* expected values between 0 and 126 */ + if (coded_value > 127) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "snr coded value out of range: %u", coded_value); + return FALSE; + } + + *out_snr = ((gdouble)coded_value)/2 - 23; + return TRUE; +} + +/*****************************************************************************/ + MMSmsState mm_sms_state_from_mbim_message_status (MbimSmsStatus status) { @@ -617,3 +695,159 @@ mm_signal_quality_from_mbim_signal_state (guint rssi, return quality; } + +static MMSignal ** +select_mbim_signal_with_data_class (MbimDataClass data_class, + MMSignal **cdma, + MMSignal **evdo, + MMSignal **gsm, + MMSignal **umts, + MMSignal **lte, + MMSignal **nr5g) +{ + switch (data_class) { + case MBIM_DATA_CLASS_5G_NSA: + case MBIM_DATA_CLASS_5G_SA: + return nr5g; + case MBIM_DATA_CLASS_LTE: + return lte; + case MBIM_DATA_CLASS_UMTS: + case MBIM_DATA_CLASS_HSDPA: + case MBIM_DATA_CLASS_HSUPA: + return umts; + case MBIM_DATA_CLASS_GPRS: + case MBIM_DATA_CLASS_EDGE: + return gsm; + case MBIM_DATA_CLASS_1XEVDO: + case MBIM_DATA_CLASS_1XEVDO_REVA: + case MBIM_DATA_CLASS_1XEVDV: + case MBIM_DATA_CLASS_3XRTT: + case MBIM_DATA_CLASS_1XEVDO_REVB: + return evdo; + case MBIM_DATA_CLASS_1XRTT: + return cdma; + case MBIM_DATA_CLASS_UMB: + case MBIM_DATA_CLASS_CUSTOM: + default: + return NULL; + } +} + +gboolean +mm_signal_from_mbim_signal_state (MbimDataClass data_class, + guint coded_rssi, + guint coded_error_rate, + MbimRsrpSnrInfoArray *rsrp_snr, + guint32 rsrp_snr_count, + gpointer log_object, + MMSignal **out_cdma, + MMSignal **out_evdo, + MMSignal **out_gsm, + MMSignal **out_umts, + MMSignal **out_lte, + MMSignal **out_nr5g) +{ + MMSignal **tmp; + MMSignal **last_updated = NULL; + guint n_out_updated = 0; + + *out_cdma = NULL; + *out_evdo = NULL; + *out_gsm = NULL; + *out_umts = NULL; + *out_lte = NULL; + *out_nr5g = NULL; + + /* When MBIMEx v2.0 is available, we get LTE+5GNR information reported + * in the RSRP/SNR list of items. */ + if (rsrp_snr && rsrp_snr_count) { + guint i; + + for (i = 0; i < rsrp_snr_count; i++) { + MbimRsrpSnrInfo *info; + + info = rsrp_snr[i]; + + tmp = select_mbim_signal_with_data_class (info->system_type, + out_cdma, out_evdo, + out_gsm, out_umts, out_lte, out_nr5g); + if (!tmp || ((info->rsrp == 0xFFFFFFFF) && (info->snr == 0xFFFFFFFF))) + continue; + + last_updated = tmp; + n_out_updated++; + + *tmp = mm_signal_new (); + + mm_signal_set_rsrp (*tmp, MM_SIGNAL_UNKNOWN); + if (info->rsrp != 0xFFFFFFFF) { + g_autoptr(GError) error = NULL; + gdouble rsrp; + + if (!mm_signal_rsrp_from_coded_value (info->rsrp, &rsrp, &error)) + mm_obj_dbg (log_object, "couldn't convert RSRP coded value '%u': %s", info->rsrp, error->message); + else + mm_signal_set_rsrp (*tmp, rsrp); + } + + mm_signal_set_snr (*tmp, MM_SIGNAL_UNKNOWN); + if (info->snr != 0xFFFFFFFF) { + g_autoptr(GError) error = NULL; + gdouble snr; + + if (!mm_signal_snr_from_coded_value (info->snr, &snr, &error)) + mm_obj_dbg (log_object, "couldn't convert SNR coded value '%u': %s", info->snr, error->message); + else + mm_signal_set_snr (*tmp, snr); + } + } + } + + /* The MBIM v1.0 details (RSSI, error rate) will only be set if + * the target access technology is known without any doubt. + * E.g. if we are in 5GNSA (4G+5G), we will only set the fields + * if one of them has valid values. If both have valid values, + * we'll skip updating RSSI and error rate, as we wouldn't know + * to which of them applies. */ + if (n_out_updated > 1) + return TRUE; + + if (n_out_updated == 0) { + tmp = select_mbim_signal_with_data_class (data_class, + out_cdma, out_evdo, + out_gsm, out_umts, out_lte, out_nr5g); + if (!tmp) + return FALSE; + *tmp = mm_signal_new (); + } else { + tmp = last_updated; + g_assert (tmp && *tmp); + } + + mm_signal_set_error_rate (*tmp, MM_SIGNAL_UNKNOWN); + if (coded_error_rate != 99) { + g_autoptr(GError) error = NULL; + gdouble error_rate; + + if (!mm_signal_error_rate_percentage_from_coded_value (coded_error_rate, + &error_rate, + data_class == (MBIM_DATA_CLASS_GPRS | MBIM_DATA_CLASS_EDGE), + &error)) + mm_obj_dbg (log_object, "couldn't convert error rate coded value '%u': %s", coded_error_rate, error->message); + else + mm_signal_set_error_rate (*tmp, error_rate); + } + + mm_signal_set_rssi (*tmp, MM_SIGNAL_UNKNOWN); + if (coded_rssi != 99) { + g_autoptr(GError) error = NULL; + gdouble rssi; + + if (!mm_signal_rssi_from_coded_value (coded_rssi, &rssi, &error)) + mm_obj_dbg (log_object, "couldn't convert RSSI coded value '%u': %s", coded_rssi, error->message); + else + mm_signal_set_rssi (*tmp, rssi); + } + + return TRUE; +} diff --git a/src/mm-modem-helpers-mbim.h b/src/mm-modem-helpers-mbim.h index a2b9aee0..2c3d2bae 100644 --- a/src/mm-modem-helpers-mbim.h +++ b/src/mm-modem-helpers-mbim.h @@ -19,6 +19,9 @@ #include #include +#define _LIBMM_INSIDE_MM +#include + #include /*****************************************************************************/ @@ -61,6 +64,23 @@ MbimContextType mm_bearer_apn_type_to_mbim_context_type (MMBearerApnT gpointer log_object, GError **error); +gboolean mm_signal_error_rate_percentage_from_coded_value (guint coded_value, + gdouble *out_percentage, + gboolean is_gsm, + GError **error); + +gboolean mm_signal_rssi_from_coded_value (guint coded_value, + gdouble *out_rssi, + GError **error); + +gboolean mm_signal_rsrp_from_coded_value (guint coded_value, + gdouble *out_rsrp, + GError **error); + +gboolean mm_signal_snr_from_coded_value (guint coded_value, + gdouble *out_snr, + GError **error); + /*****************************************************************************/ /* MBIM/SMS to MM translations */ @@ -73,4 +93,17 @@ guint mm_signal_quality_from_mbim_signal_state (guint rssi, guint32 rsrp_snr_count, gpointer log_object); +gboolean mm_signal_from_mbim_signal_state (MbimDataClass data_class, + guint coded_rssi, + guint coded_error_rate, + MbimRsrpSnrInfoArray *rsrp_snr, + guint32 rsrp_snr_count, + gpointer log_object, + MMSignal **out_cdma, + MMSignal **out_evdo, + MMSignal **out_gsm, + MMSignal **out_umts, + MMSignal **out_lte, + MMSignal **out_nr5g); + #endif /* MM_MODEM_HELPERS_MBIM_H */ -- cgit v1.2.3