Merge request !1323 from 'mbim-data-class-unknown'

broadband-modem-mbim: consistently handle custom data classes

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1323
This commit is contained in:
Dan Williams
2025-04-03 20:58:04 +00:00
8 changed files with 370 additions and 62 deletions
+4
View File
@@ -166,6 +166,7 @@ print_signal_info (void)
gchar *lte_rsrq = NULL;
gchar *lte_snr = NULL;
gchar *lte_error_rate = NULL;
gchar *nr5g_rssi = NULL;
gchar *nr5g_rsrp = NULL;
gchar *nr5g_rsrq = NULL;
gchar *nr5g_snr = NULL;
@@ -235,6 +236,8 @@ print_signal_info (void)
signal = mm_modem_signal_peek_nr5g (ctx->modem_signal);
if (signal) {
if ((value = mm_signal_get_rssi (signal)) != MM_SIGNAL_UNKNOWN)
nr5g_rssi = g_strdup_printf ("%.2lf", value);
if ((value = mm_signal_get_rsrq (signal)) != MM_SIGNAL_UNKNOWN)
nr5g_rsrq = g_strdup_printf ("%.2lf", value);
if ((value = mm_signal_get_rsrp (signal)) != MM_SIGNAL_UNKNOWN)
@@ -267,6 +270,7 @@ print_signal_info (void)
mmcli_output_string_take_typed (MMC_F_SIGNAL_LTE_RSRP, lte_rsrp, "dBm");
mmcli_output_string_take_typed (MMC_F_SIGNAL_LTE_SNR, lte_snr, "dB");
mmcli_output_string_take_typed (MMC_F_SIGNAL_LTE_ERROR_RATE, lte_error_rate, "%%");
mmcli_output_string_take_typed (MMC_F_SIGNAL_5G_RSSI, nr5g_rssi, "dBm");
mmcli_output_string_take_typed (MMC_F_SIGNAL_5G_RSRQ, nr5g_rsrq, "dB");
mmcli_output_string_take_typed (MMC_F_SIGNAL_5G_RSRP, nr5g_rsrp, "dBm");
mmcli_output_string_take_typed (MMC_F_SIGNAL_5G_SNR, nr5g_snr, "dB");
+1
View File
@@ -202,6 +202,7 @@ static FieldInfo field_infos[] = {
[MMC_F_SIGNAL_LTE_RSRP] = { "modem.signal.lte.rsrp", "rsrp", MMC_S_MODEM_SIGNAL_LTE, },
[MMC_F_SIGNAL_LTE_SNR] = { "modem.signal.lte.snr", "s/n", MMC_S_MODEM_SIGNAL_LTE, },
[MMC_F_SIGNAL_LTE_ERROR_RATE] = { "modem.signal.lte.error-rate", "error rate", MMC_S_MODEM_SIGNAL_LTE, },
[MMC_F_SIGNAL_5G_RSSI] = { "modem.signal.5g.rssi", "rssi", MMC_S_MODEM_SIGNAL_5G, },
[MMC_F_SIGNAL_5G_RSRQ] = { "modem.signal.5g.rsrq", "rsrq", MMC_S_MODEM_SIGNAL_5G, },
[MMC_F_SIGNAL_5G_RSRP] = { "modem.signal.5g.rsrp", "rsrp", MMC_S_MODEM_SIGNAL_5G, },
[MMC_F_SIGNAL_5G_SNR] = { "modem.signal.5g.snr", "s/n", MMC_S_MODEM_SIGNAL_5G, },
+1
View File
@@ -214,6 +214,7 @@ typedef enum {
MMC_F_SIGNAL_LTE_RSRP,
MMC_F_SIGNAL_LTE_SNR,
MMC_F_SIGNAL_LTE_ERROR_RATE,
MMC_F_SIGNAL_5G_RSSI,
MMC_F_SIGNAL_5G_RSRQ,
MMC_F_SIGNAL_5G_RSRP,
MMC_F_SIGNAL_5G_SNR,
+80 -42
View File
@@ -130,7 +130,7 @@ struct _MMBroadbandModemMbimPrivate {
/* Queried and cached capabilities */
MbimCellularClass caps_cellular_class;
MbimDataClass caps_data_class;
gchar *caps_custom_data_class;
MbimDataClass caps_custom_data_class;
MbimSmsCaps caps_sms;
guint caps_max_sessions;
gchar *caps_device_id;
@@ -518,6 +518,8 @@ device_caps_query_ready (MbimDevice *device,
MMBroadbandModemMbim *self;
GError *error = NULL;
LoadCurrentCapabilitiesContext *ctx;
MbimDataClass caps_data_class = MBIM_DATA_CLASS_NONE;
g_autofree gchar *caps_custom_data_class_str;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
@@ -550,7 +552,7 @@ device_caps_query_ready (MbimDevice *device,
NULL, /* lte_band_class_array */
NULL, /* nr_band_class_array_size */
NULL, /* nr_band_class_array */
&self->priv->caps_custom_data_class,
&caps_custom_data_class_str,
&self->priv->caps_device_id,
&self->priv->caps_firmware_info,
&self->priv->caps_hardware_info,
@@ -560,7 +562,7 @@ device_caps_query_ready (MbimDevice *device,
return;
}
/* Translate data class v3 to standard data class to simplify further usage of the field */
self->priv->caps_data_class = mm_mbim_data_class_from_mbim_data_class_v3_and_subclass (data_class_v3, data_subclass);
caps_data_class = mm_mbim_data_class_from_mbim_data_class_v3_and_subclass (data_class_v3, data_subclass);
} else if (mbim_device_check_ms_mbimex_version (device, 2, 0)) {
if (!mbim_message_ms_basic_connect_extensions_device_caps_response_parse (
response,
@@ -568,11 +570,11 @@ device_caps_query_ready (MbimDevice *device,
&self->priv->caps_cellular_class,
NULL, /* voice_class */
NULL, /* sim_class */
&self->priv->caps_data_class,
&caps_data_class,
&self->priv->caps_sms,
NULL, /* ctrl_caps */
&self->priv->caps_max_sessions,
&self->priv->caps_custom_data_class,
&caps_custom_data_class_str,
&self->priv->caps_device_id,
&self->priv->caps_firmware_info,
&self->priv->caps_hardware_info,
@@ -589,11 +591,11 @@ device_caps_query_ready (MbimDevice *device,
&self->priv->caps_cellular_class,
NULL, /* voice_class */
NULL, /* sim_class */
&self->priv->caps_data_class,
&caps_data_class,
&self->priv->caps_sms,
NULL, /* ctrl_caps */
&self->priv->caps_max_sessions,
&self->priv->caps_custom_data_class,
&caps_custom_data_class_str,
&self->priv->caps_device_id,
&self->priv->caps_firmware_info,
&self->priv->caps_hardware_info,
@@ -604,9 +606,14 @@ device_caps_query_ready (MbimDevice *device,
}
}
/* Normalize data class capabilities to include any custom data class */
self->priv->caps_custom_data_class = mm_mbim_data_class_from_custom_caps (caps_data_class,
caps_custom_data_class_str);
self->priv->caps_data_class = mm_modem_mbim_normalize_data_class_mask (caps_data_class,
self->priv->caps_custom_data_class);
ctx->current_mbim = mm_modem_capability_from_mbim_device_caps (self->priv->caps_cellular_class,
self->priv->caps_data_class,
self->priv->caps_custom_data_class);
self->priv->caps_data_class);
complete_current_capabilities (task);
}
@@ -708,8 +715,7 @@ load_supported_capabilities_mbim (GTask *task)
/* Current capabilities should have been cached already, just assume them */
current = mm_modem_capability_from_mbim_device_caps (self->priv->caps_cellular_class,
self->priv->caps_data_class,
self->priv->caps_custom_data_class);
self->priv->caps_data_class);
if (current != 0) {
supported = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 1);
g_array_append_val (supported, current);
@@ -1067,7 +1073,7 @@ load_supported_modes_mbim (GTask *task,
}
/* Build all */
mask_all = mm_modem_mode_from_mbim_data_class (self->priv->caps_data_class, self->priv->caps_custom_data_class);
mask_all = mm_modem_mode_from_mbim_data_class (self->priv->caps_data_class);
mode.allowed = mask_all;
mode.preferred = MM_MODEM_MODE_NONE;
all = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1);
@@ -1188,11 +1194,14 @@ register_state_current_modes_query_ready (MbimDevice *device,
GAsyncResult *res,
GTask *task)
{
MMBroadbandModemMbim *self;
g_autoptr(MbimMessage) response = NULL;
MMModemModeCombination *mode = NULL;
GError *error = NULL;
MbimDataClass preferred_data_classes;
self = g_task_get_source_object (task);
response = mbim_device_command_finish (device, res, &error);
if (!response ||
!mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error) ||
@@ -1214,8 +1223,12 @@ register_state_current_modes_query_ready (MbimDevice *device,
return;
}
/* Normalize preferred data class to include any custom data class */
preferred_data_classes = mm_modem_mbim_normalize_data_class_mask (preferred_data_classes,
self->priv->caps_custom_data_class);
mode = g_new0 (MMModemModeCombination, 1);
mode->allowed = mm_modem_mode_from_mbim_data_class (preferred_data_classes, NULL);
mode->allowed = mm_modem_mode_from_mbim_data_class (preferred_data_classes);
mode->preferred = MM_MODEM_MODE_NONE;
g_task_return_pointer (task, mode, (GDestroyNotify)g_free);
g_object_unref (task);
@@ -1301,9 +1314,17 @@ complete_pending_allowed_modes_action (MMBroadbandModemMbim *self,
if (!self->priv->pending_allowed_modes_action)
return;
/* requested_data_classes is de-normalized (since we just sent it to the modem) */
requested_data_classes = (MbimDataClass) GPOINTER_TO_UINT (g_task_get_task_data (self->priv->pending_allowed_modes_action));
requested_modes = mm_modem_mode_from_mbim_data_class (requested_data_classes, NULL);
preferred_modes = mm_modem_mode_from_mbim_data_class (preferred_data_classes, NULL);
requested_modes = mm_modem_mode_from_mbim_data_class (requested_data_classes);
/* But preferred_data_classes is normalized (since we just pulled it out of
* an MBIM message). De-normalize preferred_data_classes so we can compare
* it to requested_data_classes.
*/
preferred_data_classes = mm_modem_mbim_normalize_data_class_mask (preferred_data_classes,
self->priv->caps_custom_data_class);
preferred_modes = mm_modem_mode_from_mbim_data_class (preferred_data_classes);
/* only early complete on success, as we don't know if they're going to be
* intermediate indications emitted before the preference change is valid */
@@ -1367,8 +1388,8 @@ register_state_current_modes_set_ready (MbimDevice *device,
return;
}
requested_modes = mm_modem_mode_from_mbim_data_class (requested_data_classes, NULL);
preferred_modes = mm_modem_mode_from_mbim_data_class (preferred_data_classes, NULL);
requested_modes = mm_modem_mode_from_mbim_data_class (requested_data_classes);
preferred_modes = mm_modem_mode_from_mbim_data_class (preferred_data_classes);
if (requested_modes != preferred_modes) {
g_autofree gchar *requested_modes_str = NULL;
@@ -1422,6 +1443,7 @@ modem_set_current_modes (MMIfaceModem *_self,
GTask *task;
MbimDevice *device;
g_autoptr(GCancellable) cancellable = NULL;
MbimDataClass normalized_class;
if (!peek_device (self, &device, callback, user_data))
return;
@@ -1445,11 +1467,17 @@ modem_set_current_modes (MMIfaceModem *_self,
/* Limit ANY to the currently supported modes */
if (allowed == MM_MODEM_MODE_ANY)
allowed = mm_modem_mode_from_mbim_data_class (self->priv->caps_data_class, self->priv->caps_custom_data_class);
allowed = mm_modem_mode_from_mbim_data_class (self->priv->caps_data_class);
self->priv->requested_data_class = mm_mbim_data_class_from_modem_mode (allowed,
mm_iface_modem_is_3gpp (_self),
mm_iface_modem_is_cdma (_self));
normalized_class = mm_mbim_data_class_from_modem_mode (allowed,
mm_iface_modem_is_3gpp (_self),
mm_iface_modem_is_cdma (_self));
/* Replace any normalized data class with MBIM_DATA_CLASS_CUSTOM
* before sending back to the modem.
*/
self->priv->requested_data_class = mm_modem_mbim_denormalize_data_class_mask (normalized_class,
self->priv->caps_custom_data_class);
/* Store the ongoing allowed modes action, so that we can finish the
* operation early via indications, instead of waiting for the modem
@@ -2183,6 +2211,18 @@ modem_power_down (MMIfaceModem *self,
/*****************************************************************************/
/* Signal quality loading (Modem interface) */
static MbimDataClass
enabled_cache_best_available_data_class (MMBroadbandModemMbim *self)
{
MbimDataClass data_class;
/* Best guess of current data class */
data_class = self->priv->enabled_cache.highest_available_data_class;
if (data_class == 0)
data_class = self->priv->enabled_cache.available_data_classes;
return data_class;
}
static guint
modem_load_signal_quality_finish (MMIfaceModem *self,
GAsyncResult *res,
@@ -2255,10 +2295,7 @@ signal_state_query_ready (MbimDevice *device,
if (error)
g_task_return_error (task, error);
else {
/* Best guess of current data class */
data_class = self->priv->enabled_cache.highest_available_data_class;
if (data_class == 0)
data_class = self->priv->enabled_cache.available_data_classes;
data_class = enabled_cache_best_available_data_class (self);
if (mm_signal_from_mbim_signal_state (data_class, rssi, error_rate, rsrp_snr, rsrp_snr_count,
self, &cdma, &evdo, &gsm, &umts, &lte, &nr5g))
mm_iface_modem_signal_update (MM_IFACE_MODEM_SIGNAL (self), cdma, evdo, gsm, umts, lte, nr5g);
@@ -4914,11 +4951,7 @@ basic_connect_notification_signal_state (MMBroadbandModemMbim *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->enabled_cache.highest_available_data_class;
if (data_class == 0)
data_class = self->priv->enabled_cache.available_data_classes;
data_class = enabled_cache_best_available_data_class (self);
if (mm_signal_from_mbim_signal_state (data_class, coded_rssi, coded_error_rate, rsrp_snr, rsrp_snr_count,
self, &cdma, &evdo, &gsm, &umts, &lte, &nr5g))
mm_iface_modem_signal_update (MM_IFACE_MODEM_SIGNAL (self), cdma, evdo, gsm, umts, lte, nr5g);
@@ -4981,11 +5014,10 @@ static void
update_access_technologies (MMBroadbandModemMbim *self)
{
MMModemAccessTechnology act;
MbimDataClass data_class;
act = mm_modem_access_technology_from_mbim_data_class (self->priv->enabled_cache.highest_available_data_class);
if (act == MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN)
act = mm_modem_access_technology_from_mbim_data_class (self->priv->enabled_cache.available_data_classes);
data_class = enabled_cache_best_available_data_class (self);
act = mm_modem_access_technology_from_mbim_data_class (data_class);
mm_iface_modem_3gpp_update_access_technologies (MM_IFACE_MODEM_3GPP (self), act);
}
@@ -5271,6 +5303,13 @@ common_process_register_state (MMBroadbandModemMbim *self,
}
}
/* Normalize preferred and available data classes to include any custom data class */
preferred_data_classes = mm_modem_mbim_normalize_data_class_mask (preferred_data_classes,
self->priv->caps_custom_data_class);
available_data_classes = mm_modem_mbim_normalize_data_class_mask (available_data_classes,
self->priv->caps_custom_data_class);
nw_error = mm_broadband_modem_mbim_normalize_nw_error (self, nw_error);
nw_error_str = mbim_nw_error_get_string (nw_error);
available_data_classes_str = mbim_data_class_build_string_from_mask (available_data_classes);
@@ -5753,9 +5792,12 @@ common_process_packet_service (MMBroadbandModemMbim *self,
if (packet_service_state == MBIM_PACKET_SERVICE_STATE_ATTACHED) {
if (data_class_v3)
self->priv->enabled_cache.highest_available_data_class = mm_mbim_data_class_from_mbim_data_class_v3_and_subclass (data_class_v3, data_subclass);
else
self->priv->enabled_cache.highest_available_data_class = data_class;
data_class = mm_mbim_data_class_from_mbim_data_class_v3_and_subclass (data_class_v3, data_subclass);
/* Normalize data class to include any custom data class */
data_class = mm_modem_mbim_normalize_data_class_mask (data_class,
self->priv->caps_custom_data_class);
self->priv->enabled_cache.highest_available_data_class = data_class;
} else if (packet_service_state == MBIM_PACKET_SERVICE_STATE_DETACHED) {
self->priv->enabled_cache.highest_available_data_class = 0;
}
@@ -7532,10 +7574,7 @@ mbimexv2_signal_state_query_ready (MbimDevice *device,
result = g_slice_new0 (SignalLoadValuesResult);
/* Best guess of current data class */
data_class = self->priv->enabled_cache.highest_available_data_class;
if (data_class == 0)
data_class = self->priv->enabled_cache.available_data_classes;
data_class = enabled_cache_best_available_data_class (self);
if (!mm_signal_from_mbim_signal_state (
data_class, rssi, error_rate, rsrp_snr, rsrp_snr_count, self,
NULL, NULL, &result->gsm, &result->umts, &result->lte, &result->nr5g)) {
@@ -10393,7 +10432,6 @@ finalize (GObject *object)
{
MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (object);
g_free (self->priv->caps_custom_data_class);
g_free (self->priv->caps_device_id);
g_free (self->priv->caps_firmware_info);
g_free (self->priv->caps_hardware_info);
+70 -15
View File
@@ -25,10 +25,77 @@
/*****************************************************************************/
typedef struct {
const gchar *custom_class;
const MbimDataClass primary_data_class;
const MbimDataClass secondary_data_class;
} CustomDataClass;
static const CustomDataClass custom_data_classes[] = {
/* "5GSA/TDS": Quectel RM502Q */
{ "5GSA", MBIM_DATA_CLASS_5G_SA, MBIM_DATA_CLASS_NONE },
/* "5G/TDS": Telit FN990, Quectel RM502Q, Gosuncn GM800
* "5G": Dell Snapdragon X55/Foxconn T99W175
*/
{ "5G", MBIM_DATA_CLASS_5G_NSA, MBIM_DATA_CLASS_5G_SA },
/* "HSPA+": Dell DW5821e/Foxconn T77W968, Huawei EM820W */
{ "HSPA+", MBIM_DATA_CLASS_HSDPA | MBIM_DATA_CLASS_HSUPA, MBIM_DATA_CLASS_NONE },
};
MbimDataClass
mm_mbim_data_class_from_custom_caps (MbimDataClass orig_data_class,
const gchar *custom_data_class)
{
guint i;
if (orig_data_class & MBIM_DATA_CLASS_CUSTOM) {
for (i = 0; i < G_N_ELEMENTS (custom_data_classes); i++) {
if (strstr (custom_data_class, custom_data_classes[i].custom_class)) {
/* If the original data class already includes the primary custom
* class add the secondary instead. Devices sometimes report a variant
* of the custom class depending on MBIMex version.
*
* For example, Foxconn X55 supports SA but reports "...,lte,custom"
* with MBIMex1 and "...,lte,5g-nsa,custom" with MBIMex2. Fix that
* up with the highest level we can be sure the device supports.
*/
if (orig_data_class & custom_data_classes[i].primary_data_class)
return custom_data_classes[i].secondary_data_class;
else
return custom_data_classes[i].primary_data_class;
}
}
}
return MBIM_DATA_CLASS_NONE;
}
MbimDataClass
mm_modem_mbim_normalize_data_class_mask (MbimDataClass orig_data_class,
MbimDataClass custom_data_class)
{
if (orig_data_class & MBIM_DATA_CLASS_CUSTOM) {
orig_data_class |= custom_data_class;
orig_data_class &= ~MBIM_DATA_CLASS_CUSTOM;
}
return orig_data_class;
}
MbimDataClass
mm_modem_mbim_denormalize_data_class_mask (MbimDataClass orig_data_class,
MbimDataClass custom_data_class)
{
if (orig_data_class & custom_data_class) {
orig_data_class &= ~custom_data_class;
orig_data_class |= MBIM_DATA_CLASS_CUSTOM;
}
return orig_data_class;
}
/*****************************************************************************/
MMModemCapability
mm_modem_capability_from_mbim_device_caps (MbimCellularClass caps_cellular_class,
MbimDataClass caps_data_class,
const gchar *caps_custom_data_class)
MbimDataClass caps_data_class)
{
MMModemCapability mask = 0;
@@ -43,12 +110,6 @@ mm_modem_capability_from_mbim_device_caps (MbimCellularClass caps_cellular_clas
if (caps_data_class & MBIM_DATA_CLASS_LTE)
mask |= MM_MODEM_CAPABILITY_LTE;
/* e.g. Gosuncn GM800 reports MBIM custom data class "5G/TDS" */
if ((caps_data_class & MBIM_DATA_CLASS_CUSTOM) && caps_custom_data_class) {
if (strstr (caps_custom_data_class, "5G"))
mask |= MM_MODEM_CAPABILITY_5GNR;
}
/* Support for devices with Microsoft extensions */
if (caps_data_class & (MBIM_DATA_CLASS_5G_NSA | MBIM_DATA_CLASS_5G_SA))
mask |= MM_MODEM_CAPABILITY_5GNR;
@@ -148,8 +209,7 @@ mm_modem_3gpp_packet_service_state_from_mbim_packet_service_state (MbimPacketSer
/*****************************************************************************/
MMModemMode
mm_modem_mode_from_mbim_data_class (MbimDataClass data_class,
const gchar *caps_custom_data_class)
mm_modem_mode_from_mbim_data_class (MbimDataClass data_class)
{
MMModemMode mask = MM_MODEM_MODE_NONE;
@@ -166,11 +226,6 @@ mm_modem_mode_from_mbim_data_class (MbimDataClass data_class,
if (data_class & (MBIM_DATA_CLASS_5G_NSA |
MBIM_DATA_CLASS_5G_SA))
mask |= MM_MODEM_MODE_5G;
/* Some modems (e.g. Telit FN990) reports MBIM custom data class "5G/TDS" */
if ((data_class & MBIM_DATA_CLASS_CUSTOM) && caps_custom_data_class) {
if (strstr (caps_custom_data_class, "5G"))
mask |= MM_MODEM_MODE_5G;
}
/* 3GPP2... */
if (data_class & MBIM_DATA_CLASS_1XRTT)
+12 -5
View File
@@ -27,9 +27,17 @@
/*****************************************************************************/
/* MBIM/BasicConnect to MM translations */
MMModemCapability mm_modem_capability_from_mbim_device_caps (MbimCellularClass caps_cellular_class,
MbimDataClass caps_data_class,
const gchar *caps_custom_data_class);
MbimDataClass mm_mbim_data_class_from_custom_caps (MbimDataClass orig_data_class,
const gchar *custom_data_class);
MbimDataClass mm_modem_mbim_normalize_data_class_mask (MbimDataClass orig_data_class,
MbimDataClass custom_data_class);
MbimDataClass mm_modem_mbim_denormalize_data_class_mask (MbimDataClass orig_data_class,
MbimDataClass custom_data_class);
MMModemCapability mm_modem_capability_from_mbim_device_caps (MbimCellularClass caps_cellular_class,
MbimDataClass caps_data_class);
MMModemLock mm_modem_lock_from_mbim_pin_type (MbimPinType pin_type);
@@ -40,8 +48,7 @@ MMModem3gppPacketServiceState mm_modem_3gpp_packet_service_state_from_mbim_packe
MbimDataClass mm_mbim_data_class_from_mbim_data_class_v3_and_subclass (MbimDataClassV3 data_class_v3,
MbimDataSubclass data_subclass);
MMModemMode mm_modem_mode_from_mbim_data_class (MbimDataClass data_class,
const gchar *caps_custom_data_class);
MMModemMode mm_modem_mode_from_mbim_data_class (MbimDataClass data_class);
MbimDataClass mm_mbim_data_class_from_modem_mode (MMModemMode modem_mode,
gboolean is_3gpp,
+4
View File
@@ -25,6 +25,10 @@ if enable_qmi
test_units += {'modem-helpers-qmi': libkerneldevice_dep}
endif
if enable_mbim
test_units += {'modem-helpers-mbim': libkerneldevice_dep}
endif
foreach test_unit, test_deps: test_units
test_name = 'test-' + test_unit
+198
View File
@@ -0,0 +1,198 @@
/* -*- 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) 2025 Dan Williams <dan@ioncontrol.co>
*/
#include <glib.h>
#include <glib-object.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <ModemManager.h>
#define _LIBMM_INSIDE_MM
#include <libmm-glib.h>
#include "mm-enums-types.h"
#include "mm-flags-types.h"
#include "mm-modem-helpers-mbim.h"
#include "mm-log-test.h"
/*****************************************************************************/
typedef struct {
const MbimDataClass data_class;
const gdouble rssi;
const gdouble rscp;
const gdouble ecio;
const gdouble sinr;
const gdouble io;
const gdouble rsrq;
const gdouble rsrp;
const gdouble snr;
const gdouble error_rate;
} ExpectedSignal;
typedef struct {
const gchar *detail;
const gboolean expect_success;
const MbimDataClass data_class;
const guint coded_rssi;
const guint coded_error_rate;
const MbimRsrpSnrInfo rsrp_snr[2];
const ExpectedSignal expected[2];
} SignalStateTestcase;
const SignalStateTestcase signal_tests[] = {
{ "5g-no-rsrp-snr",
TRUE,
MBIM_DATA_CLASS_5G_SA,
16, 99,
{ { .system_type = MBIM_DATA_CLASS_NONE }, { .system_type = MBIM_DATA_CLASS_NONE } },
{ { MBIM_DATA_CLASS_5G_SA,
-97,
MM_SIGNAL_UNKNOWN,
MM_SIGNAL_UNKNOWN,
MM_SIGNAL_UNKNOWN,
MM_SIGNAL_UNKNOWN,
MM_SIGNAL_UNKNOWN,
MM_SIGNAL_UNKNOWN,
MM_SIGNAL_UNKNOWN,
MM_SIGNAL_UNKNOWN,
},
{ MBIM_DATA_CLASS_NONE }
},
},
};
#if 0
typedef struct {
guint32 rsrp;
guint32 snr;
guint32 rsrp_threshold;
guint32 snr_threshold;
guint32 system_type;
} MbimRsrpSnrInfo;
#endif
static MMSignal *
select_signal_for_data_class (MbimDataClass data_class,
MMSignal **cdma,
MMSignal **evdo,
MMSignal **gsm,
MMSignal **umts,
MMSignal **lte,
MMSignal **nr5g)
{
if (data_class & (MBIM_DATA_CLASS_5G_NSA |
MBIM_DATA_CLASS_5G_SA))
return *nr5g;
if (data_class & (MBIM_DATA_CLASS_LTE))
return *lte;
if (data_class & (MBIM_DATA_CLASS_UMTS |
MBIM_DATA_CLASS_HSDPA |
MBIM_DATA_CLASS_HSUPA))
return *umts;
if (data_class & (MBIM_DATA_CLASS_GPRS |
MBIM_DATA_CLASS_EDGE))
return *gsm;
if (data_class & (MBIM_DATA_CLASS_1XEVDO |
MBIM_DATA_CLASS_1XEVDO_REVA |
MBIM_DATA_CLASS_1XEVDV |
MBIM_DATA_CLASS_3XRTT |
MBIM_DATA_CLASS_1XEVDO_REVB))
return *evdo;
if (data_class & MBIM_DATA_CLASS_1XRTT)
return *cdma;
return NULL;
}
static void
test_signal_state_case (gconstpointer user_data)
{
const SignalStateTestcase *tc = user_data;
gboolean success;
guint count;
g_autoptr(MMSignal) cdma;
g_autoptr(MMSignal) evdo;
g_autoptr(MMSignal) gsm;
g_autoptr(MMSignal) umts;
g_autoptr(MMSignal) lte;
g_autoptr(MMSignal) nr5g;
MMSignal *tmp;
for (count = 0;
count < G_N_ELEMENTS (tc->rsrp_snr) && tc->rsrp_snr[count].system_type;
count++);
success = mm_signal_from_mbim_signal_state (tc->data_class,
tc->coded_rssi,
tc->coded_error_rate,
(MbimRsrpSnrInfo **) &tc->rsrp_snr,
count,
NULL,
&cdma,
&evdo,
&gsm,
&umts,
&lte,
&nr5g);
g_assert_cmpint (success, ==, tc->expect_success);
for (count = 0;
count < G_N_ELEMENTS (tc->expected) && (tc->expected[count].data_class != MBIM_DATA_CLASS_NONE);
count++) {
tmp = select_signal_for_data_class (tc->expected[count].data_class,
&cdma, &evdo, &gsm, &umts, &lte, &nr5g);
g_assert (tmp);
g_assert_cmpfloat (mm_signal_get_rssi (tmp), ==, tc->expected[count].rssi);
g_assert_cmpfloat (mm_signal_get_rscp (tmp), ==, tc->expected[count].rscp);
g_assert_cmpfloat (mm_signal_get_ecio (tmp), ==, tc->expected[count].ecio);
g_assert_cmpfloat (mm_signal_get_sinr (tmp), ==, tc->expected[count].sinr);
g_assert_cmpfloat (mm_signal_get_io (tmp), ==, tc->expected[count].io);
g_assert_cmpfloat (mm_signal_get_rsrq (tmp), ==, tc->expected[count].rsrq);
g_assert_cmpfloat (mm_signal_get_rsrp (tmp), ==, tc->expected[count].rsrp);
g_assert_cmpfloat (mm_signal_get_snr (tmp), ==, tc->expected[count].snr);
g_assert_cmpfloat (mm_signal_get_error_rate (tmp), ==, tc->expected[count].error_rate);
}
if (count == 0 ) {
g_assert (!cdma);
g_assert (!evdo);
g_assert (!gsm);
g_assert (!umts);
g_assert (!lte);
g_assert (!nr5g);
}
}
/*****************************************************************************/
int main (int argc, char **argv)
{
guint i;
setlocale (LC_ALL, "");
g_test_init (&argc, &argv, NULL);
for (i = 0; i < G_N_ELEMENTS (signal_tests); i++) {
g_autofree gchar *detail;
detail = g_strdup_printf ("/MM/mbim/signal-state/%s", signal_tests[i].detail);
g_test_add_data_func (detail, &signal_tests[i], test_signal_state_case);
}
return g_test_run ();
}