broadband-modem-mbim: cell-info core logic implementation

Handling of gdbus interface changes for additional
properties(service cell type and bandwidth) in
broadband modem mbim.

Co-author: Shilpa Shivakumar
This commit is contained in:
som
2022-11-02 12:05:42 +05:30
committed by Aleksander Morgado
parent e8d63c1743
commit d1ed6114a8
3 changed files with 401 additions and 46 deletions

View File

@@ -20,6 +20,7 @@
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <math.h>
#include "mm-modem-helpers-mbim.h"
#include "mm-broadband-modem-mbim.h"
@@ -2323,9 +2324,34 @@ modem_reset (MMIfaceModem *_self,
/*****************************************************************************/
/* Cell info retrieval */
typedef enum {
GET_CELL_INFO_STEP_FIRST,
GET_CELL_INFO_STEP_RFIM,
GET_CELL_INFO_STEP_CELL_INFO,
GET_CELL_INFO_STEP_LAST
} GetCellInfoStep;
typedef struct {
GetCellInfoStep step;
GList *rfim_info_list;
GList *cell_info_list;
GError *saved_error;
} GetCellInfoContext;
static void
get_cell_info_context_free (GetCellInfoContext *ctx)
{
mm_rfim_info_list_free (ctx->rfim_info_list);
g_assert (!ctx->saved_error);
g_free (ctx);
}
static void get_cell_info_step (MbimDevice *device,
GTask *task);
static GList *
modem_get_cell_info_finish (MMIfaceModem *self,
GAsyncResult *res,
modem_get_cell_info_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_pointer (G_TASK (res), error);
@@ -2365,13 +2391,16 @@ base_stations_info_query_ready (MbimDevice *device,
g_autoptr(MbimCellInfoServingNrArray) nr_serving_cells = NULL;
guint32 nr_neighboring_cells_count = 0;
g_autoptr(MbimCellInfoNeighboringNrArray) nr_neighboring_cells = NULL;
GetCellInfoContext *ctx;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
response = mbim_device_command_finish (device, res, &error);
if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) {
g_task_return_error (task, error);
g_object_unref (task);
ctx->saved_error = error;
ctx->step = GET_CELL_INFO_STEP_LAST;
get_cell_info_step (device, task);
return;
}
@@ -2430,8 +2459,9 @@ base_stations_info_query_ready (MbimDevice *device,
}
if (error) {
g_task_return_error (task, error);
g_object_unref (task);
ctx->saved_error = error;
ctx->step = GET_CELL_INFO_STEP_LAST;
get_cell_info_step (device, task);
return;
}
@@ -2577,18 +2607,33 @@ base_stations_info_query_ready (MbimDevice *device,
}
if (lte_serving_cell) {
GList *l;
info = mm_cell_info_lte_new_from_dictionary (NULL);
mm_cell_info_set_serving (info, TRUE);
CELL_INFO_SET_STR (lte_serving_cell->provider_id, lte_set_operator_id, MM_CELL_INFO_LTE);
CELL_INFO_SET_HEXSTR (lte_serving_cell->tac, 0xFFFFFFFF, "", lte_set_tac, MM_CELL_INFO_LTE);
CELL_INFO_SET_HEXSTR (lte_serving_cell->cell_id, 0xFFFFFFFF, "", lte_set_ci, MM_CELL_INFO_LTE);
CELL_INFO_SET_HEXSTR (lte_serving_cell->physical_cell_id, 0xFFFFFFFF, "", lte_set_physical_ci, MM_CELL_INFO_LTE);
CELL_INFO_SET_UINT (lte_serving_cell->earfcn, 0xFFFFFFFF, lte_set_earfcn, MM_CELL_INFO_LTE);
CELL_INFO_SET_INT_DOUBLE (lte_serving_cell->rsrp, 0xFFFFFFFF, lte_set_rsrp, MM_CELL_INFO_LTE);
CELL_INFO_SET_INT_DOUBLE (lte_serving_cell->rsrq, 0xFFFFFFFF, lte_set_rsrq, MM_CELL_INFO_LTE);
CELL_INFO_SET_UINT (lte_serving_cell->timing_advance, 0xFFFFFFFF, lte_set_timing_advance, MM_CELL_INFO_LTE);
CELL_INFO_SET_STR (lte_serving_cell->provider_id, lte_set_operator_id, MM_CELL_INFO_LTE);
CELL_INFO_SET_HEXSTR (lte_serving_cell->tac, 0xFFFFFFFF, "", lte_set_tac, MM_CELL_INFO_LTE);
CELL_INFO_SET_HEXSTR (lte_serving_cell->cell_id, 0xFFFFFFFF, "", lte_set_ci, MM_CELL_INFO_LTE);
CELL_INFO_SET_HEXSTR (lte_serving_cell->physical_cell_id, 0xFFFFFFFF, "", lte_set_physical_ci, MM_CELL_INFO_LTE);
CELL_INFO_SET_UINT (lte_serving_cell->earfcn, 0xFFFFFFFF, lte_set_earfcn, MM_CELL_INFO_LTE);
CELL_INFO_SET_INT_DOUBLE (lte_serving_cell->rsrp, 0xFFFFFFFF, lte_set_rsrp, MM_CELL_INFO_LTE);
CELL_INFO_SET_INT_DOUBLE (lte_serving_cell->rsrq, 0xFFFFFFFF, lte_set_rsrq, MM_CELL_INFO_LTE);
CELL_INFO_SET_UINT (lte_serving_cell->timing_advance, 0xFFFFFFFF, lte_set_timing_advance, MM_CELL_INFO_LTE);
/* Update cell info with the radio frequency information received previously */
for (l = ctx->rfim_info_list; l; l = g_list_next (l)) {
MMRfInfo *data;
data = (MMRfInfo *)(l->data);
if (fabs ((mm_get_downlink_carrier_frequency (lte_serving_cell->earfcn, self)) - data->center_frequency) < FREQUENCY_TOLERENCE) {
mm_obj_dbg (self, "Merging radio frequency data with lte serving cell info");
CELL_INFO_SET_UINT (data->serving_cell_type, MM_SERVING_CELL_TYPE_INVALID, lte_set_serving_cell_type, MM_CELL_INFO_LTE);
CELL_INFO_SET_UINT (data->bandwidth, 0xFFFFFFFF, lte_set_bandwidth, MM_CELL_INFO_LTE);
ctx->rfim_info_list = g_list_delete_link (ctx->rfim_info_list, l);
mm_rf_info_free (data);
}
}
list = g_list_append (list, g_steal_pointer (&info));
}
@@ -2632,19 +2677,35 @@ base_stations_info_query_ready (MbimDevice *device,
guint i;
for (i = 0; i < nr_serving_cells_count; i++) {
GList *l;
info = mm_cell_info_nr5g_new_from_dictionary (NULL);
mm_cell_info_set_serving (info, TRUE);
CELL_INFO_SET_STR (nr_serving_cells[i]->provider_id, nr5g_set_operator_id, MM_CELL_INFO_NR5G);
CELL_INFO_SET_HEXSTR (nr_serving_cells[i]->tac, 0xFFFFFFFF, "", nr5g_set_tac, MM_CELL_INFO_NR5G);
CELL_INFO_SET_HEXSTR (nr_serving_cells[i]->nci, 0xFFFFFFFFFFFFFFFF, G_GINT64_MODIFIER, nr5g_set_ci, MM_CELL_INFO_NR5G);
CELL_INFO_SET_HEXSTR (nr_serving_cells[i]->physical_cell_id, 0xFFFFFFFF, "", nr5g_set_physical_ci, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT (nr_serving_cells[i]->nrarfcn, 0xFFFFFFFF, nr5g_set_nrarfcn, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT_DOUBLE_SCALED (nr_serving_cells[i]->rsrp, 0xFFFFFFFF, -156, nr5g_set_rsrp, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT_DOUBLE_SCALED (nr_serving_cells[i]->rsrq, 0xFFFFFFFF, -43, nr5g_set_rsrq, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT_DOUBLE_SCALED (nr_serving_cells[i]->sinr, 0xFFFFFFFF, -23, nr5g_set_sinr, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT (nr_serving_cells[i]->timing_advance, 0xFFFFFFFFFFFFFFFF, nr5g_set_timing_advance, MM_CELL_INFO_NR5G);
CELL_INFO_SET_STR (nr_serving_cells[i]->provider_id, nr5g_set_operator_id, MM_CELL_INFO_NR5G);
CELL_INFO_SET_HEXSTR (nr_serving_cells[i]->tac, 0xFFFFFFFF, "", nr5g_set_tac, MM_CELL_INFO_NR5G);
CELL_INFO_SET_HEXSTR (nr_serving_cells[i]->nci, 0xFFFFFFFFFFFFFFFF, G_GINT64_MODIFIER, nr5g_set_ci, MM_CELL_INFO_NR5G);
CELL_INFO_SET_HEXSTR (nr_serving_cells[i]->physical_cell_id, 0xFFFFFFFF, "", nr5g_set_physical_ci, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT (nr_serving_cells[i]->nrarfcn, 0xFFFFFFFF, nr5g_set_nrarfcn, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT_DOUBLE_SCALED (nr_serving_cells[i]->rsrp, 0xFFFFFFFF, -156, nr5g_set_rsrp, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT_DOUBLE_SCALED (nr_serving_cells[i]->rsrq, 0xFFFFFFFF, -43, nr5g_set_rsrq, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT_DOUBLE_SCALED (nr_serving_cells[i]->sinr, 0xFFFFFFFF, -23, nr5g_set_sinr, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT (nr_serving_cells[i]->timing_advance, 0xFFFFFFFFFFFFFFFF, nr5g_set_timing_advance, MM_CELL_INFO_NR5G);
/* Update cell info with the radio frequency information received previously */
for (l = ctx->rfim_info_list; l; l = g_list_next (l)) {
MMRfInfo *data;
data = (MMRfInfo *)(l->data);
/* Comparing the derived frequncy value from NRARFCN with received center frequency data to map the NR CELL */
if (fabs ((mm_get_frequency_from_nrarfcn (nr_serving_cells[i]->nrarfcn, self) * HERTZ_CONV) - data->center_frequency) < FREQUENCY_TOLERENCE) {
mm_obj_dbg (self, "Merging radio frequency data with 5gnr serving cell info");
CELL_INFO_SET_UINT (data->serving_cell_type, MM_SERVING_CELL_TYPE_INVALID, nr5g_set_serving_cell_type, MM_CELL_INFO_NR5G);
CELL_INFO_SET_UINT (data->bandwidth, 0xFFFFFFFF, nr5g_set_bandwidth, MM_CELL_INFO_NR5G);
ctx->rfim_info_list = g_list_delete_link (ctx->rfim_info_list, l);
mm_rf_info_free (data);
}
}
list = g_list_append (list, g_steal_pointer (&info));
}
}
@@ -2674,44 +2735,137 @@ base_stations_info_query_ready (MbimDevice *device,
#undef CELL_INFO_SET_INT_DOUBLE
#undef CELL_INFO_SET_UINT_DOUBLE_SCALED
g_task_return_pointer (task, list, (GDestroyNotify)cell_info_list_free);
g_object_unref (task);
ctx->cell_info_list = list;
ctx->step++;
get_cell_info_step (device, task);
}
static void
modem_get_cell_info (MMIfaceModem *_self,
GAsyncReadyCallback callback,
gpointer user_data)
check_rfim_query_ready (MbimDevice *device,
GAsyncResult *res,
GTask *task)
{
MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
GTask *task;
MbimDevice *device;
MbimMessage *message;
g_autoptr(MbimMessage) response = NULL;
MbimIntelRfimFrequencyValueArray *freq_info;
guint freq_count;
GetCellInfoContext *ctx;
MMBroadbandModemMbim *self;
if (!peek_device (self, &device, callback, user_data))
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
response = mbim_device_command_finish (device, res, NULL);
if (response &&
mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, NULL) &&
mbim_message_intel_thermal_rf_rfim_response_parse (response,
&freq_count,
&freq_info,
NULL)) {
ctx->rfim_info_list = mm_rfim_info_list_from_mbim_intel_rfim_frequency_value_array (freq_info,
freq_count,
self);
mbim_intel_rfim_frequency_value_array_free (freq_info);
} else {
mm_obj_dbg (self, "Fetching of bandwidth and serving cell type data failed");
}
ctx->step++;
get_cell_info_step (device, task);
}
static void
get_cell_info_step (MbimDevice *device,
GTask *task)
{
MMBroadbandModemMbim *self;
GetCellInfoContext *ctx;
g_autoptr(MbimMessage) message = NULL;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
/* Don't run new steps if we're cancelled */
if (g_task_return_error_if_cancelled (task)) {
g_object_unref (task);
return;
}
task = g_task_new (self, NULL, callback, user_data);
switch (ctx->step) {
case GET_CELL_INFO_STEP_FIRST:
if (!self->priv->is_base_stations_info_supported) {
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"base stations info is not supported");
g_object_unref (task);
return;
}
ctx->step++;
/* Default capacity is 15 */
if (mbim_device_check_ms_mbimex_version (device, 3, 0))
message = mbim_message_ms_basic_connect_extensions_v3_base_stations_info_query_new (15, 15, 15, 15, 15, 15, NULL);
else
message = mbim_message_ms_basic_connect_extensions_base_stations_info_query_new (15, 15, 15, 15, 15, NULL);
/* fall through */
case GET_CELL_INFO_STEP_RFIM: {
mm_obj_dbg (self, "Obtaining RFIM data...");
message = mbim_message_intel_thermal_rf_rfim_query_new (NULL);
mbim_device_command (device,
message,
10,
NULL,
(GAsyncReadyCallback)check_rfim_query_ready,
task);
return;
}
mbim_device_command (device,
message,
300,
NULL,
(GAsyncReadyCallback)base_stations_info_query_ready,
task);
case GET_CELL_INFO_STEP_CELL_INFO: {
mm_obj_dbg (self, "Obtaining cell info...");
/* Default capacity is 15 */
if (mbim_device_check_ms_mbimex_version (device, 3, 0))
message = mbim_message_ms_basic_connect_extensions_v3_base_stations_info_query_new (15, 15, 15, 15, 15, 15, NULL);
else
message = mbim_message_ms_basic_connect_extensions_base_stations_info_query_new (15, 15, 15, 15, 15, NULL);
mbim_device_command (device,
message,
300,
NULL,
(GAsyncReadyCallback)base_stations_info_query_ready,
task);
return;
}
case GET_CELL_INFO_STEP_LAST:
if (ctx->saved_error)
g_task_return_error (task, g_steal_pointer (&ctx->saved_error));
else if (ctx->cell_info_list)
g_task_return_pointer (task, ctx->cell_info_list, (GDestroyNotify)cell_info_list_free);
else
g_assert_not_reached ();
g_object_unref (task);
return;
default:
break;
}
g_assert_not_reached ();
}
static void
modem_get_cell_info (MMIfaceModem *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
MbimDevice *device;
GTask *task;
GetCellInfoContext *ctx;
if (!peek_device (self, &device, callback, user_data))
return;
task = g_task_new (self, NULL, callback, user_data);
ctx = g_new0 (GetCellInfoContext, 1);
ctx->step = GET_CELL_INFO_STEP_FIRST;
g_task_set_task_data (task, ctx, (GDestroyNotify)get_cell_info_context_free);
get_cell_info_step (device, task);
}
/*****************************************************************************/

View File

@@ -1229,3 +1229,174 @@ mm_signal_from_mbim_signal_state (MbimDataClass data_class,
return TRUE;
}
/*****************************************************************************/
void
mm_rf_info_free (MMRfInfo *rf_data)
{
g_free(rf_data);
}
void
mm_rfim_info_list_free (GList *rfim_info_list)
{
g_list_free_full (rfim_info_list, (GDestroyNotify) g_free);
}
GList *
mm_rfim_info_list_from_mbim_intel_rfim_frequency_value_array (MbimIntelRfimFrequencyValueArray *freq_info,
guint freq_count,
gpointer log_object)
{
GList *info_list = NULL;
guint i;
g_return_val_if_fail (freq_info != NULL, NULL);
for (i = 0; i < freq_count; i++) {
MMRfInfo* info;
/* If Cell info value indicates radio off, then other parameters are invalid.
* So those data will be ignored. */
if (freq_info[i]->serving_cell_info != MBIM_INTEL_SERVING_CELL_INFO_RADIO_OFF) {
info = g_new0 (MMRfInfo, 1);
info->serving_cell_type = MM_SERVING_CELL_TYPE_UNKNOWN;
switch (freq_info[i]->serving_cell_info) {
case MBIM_INTEL_SERVING_CELL_INFO_PCELL:
info->serving_cell_type = MM_SERVING_CELL_TYPE_PCELL;
break;
case MBIM_INTEL_SERVING_CELL_INFO_SCELL:
info->serving_cell_type = MM_SERVING_CELL_TYPE_SCELL;
break;
case MBIM_INTEL_SERVING_CELL_INFO_PSCELL:
info->serving_cell_type = MM_SERVING_CELL_TYPE_PSCELL;
break;
case MBIM_INTEL_SERVING_CELL_INFO_SSCELL:
info->serving_cell_type = MM_SERVING_CELL_TYPE_SSCELL;
break;
case MBIM_INTEL_SERVING_CELL_INFO_RADIO_OFF:
default:
info->serving_cell_type = MM_SERVING_CELL_TYPE_INVALID;
}
info->bandwidth = freq_info[i]->bandwidth;
info->center_frequency = freq_info[i]->center_frequency;
info_list = g_list_append (info_list, info);
} else
mm_obj_dbg (log_object, "Ignoring radio frequency information due to cell radio off");
}
return info_list;
}
typedef struct LteDlRangeData {
guint8 band;
gdouble fdl_low;
guint32 n_offs_dl;
guint32 range_dl1;
guint32 range_dl2;
} LteDlRangeData;
static LteDlRangeData lte_dl_range_data [] = {
{ 1, 2110, 0, 0, 599},
{ 2, 1930, 600, 600, 1199},
{ 3, 1805, 1200, 1200, 1949},
{ 4, 2110, 1950, 1950, 2399},
{ 5, 869, 2400, 2400, 2649},
{ 6, 875, 2650, 2650, 2749},
{ 7, 2620, 2750, 2750, 3449},
{ 8, 925, 3450, 3450, 3799},
{ 9, 1844.9, 3800, 3800, 4149},
{ 10, 2110, 4150, 4150, 4749},
{ 11, 1475.9, 4750, 4750, 4949},
{ 12, 728, 5000, 5000, 5179},
{ 13, 746, 5180, 5180, 5279},
{ 14, 758, 5280, 5280, 5379},
{ 17, 734, 5730, 5730, 5849},
{ 18, 860, 5850, 5850, 5999},
{ 19, 875, 6000, 6000, 6149},
{ 20, 791, 6150, 6150, 6449},
{ 21, 1495.9, 6450, 6450, 6599},
{ 33, 1900, 36000, 36000, 36199},
{ 34, 2010, 36200, 36200, 36349},
{ 35, 1850, 36350, 36350, 36949},
{ 36, 1930, 36950, 36950, 37549},
{ 37, 1910, 37550, 37550, 37749},
{ 38, 2570, 37750, 37750, 38249},
{ 39, 1880, 38250, 38250, 38649},
{ 40, 2300, 38650, 38650, 39649}
};
#define NUM_EUTRA_BANDS (sizeof (lte_dl_range_data) / sizeof (LteDlRangeData))
static guint8
mm_get_downlink_carrier_band (guint32 earfcn,
gpointer log_object)
{
guint8 i;
for (i = 0; i < NUM_EUTRA_BANDS; ++i) {
if (lte_dl_range_data[i].range_dl1 <= earfcn && lte_dl_range_data[i].range_dl2 >= earfcn) {
mm_obj_dbg (log_object, "Found matching band: %d for earfcn: %d" , i, earfcn);
return i;
}
}
mm_obj_dbg (log_object, "invalid earfcn: %d ", earfcn);
return NUM_EUTRA_BANDS;
}
gdouble
mm_get_downlink_carrier_frequency (guint32 earfcn,
gpointer log_object)
{
guint8 i;
i = mm_get_downlink_carrier_band (earfcn,log_object);
if (i == NUM_EUTRA_BANDS)
return 0.0;
return 1.0e6 * (lte_dl_range_data[i].fdl_low + 0.1 * (earfcn - lte_dl_range_data[i].n_offs_dl));
}
typedef struct NrRangeData {
guint global_khz;
guint range_offset;
guint nrarfcn_offset;
guint range_first;
guint range_last;
} NrRangeData ;
static NrRangeData nr_range_data [] = {
{ 5, 0, 0, 0, 599999},
{ 15, 3000000, 600000, 600000, 2016666},
{ 60, 24250080, 2016667, 2016667, 3279165}
};
#define NUM_NR_RANGE_DATA (sizeof (nr_range_data) / sizeof (NrRangeData))
static guint8
mm_get_nr_range_data (guint32 nrarfcn,
gpointer log_object)
{
guint8 i;
for (i = 0; i < NUM_NR_RANGE_DATA; ++i) {
if (nr_range_data[i].range_first <= nrarfcn && nr_range_data[i].range_last >= nrarfcn) {
mm_obj_dbg (log_object, "Found matching NR range: %d for nrarfcn: %d" , i, nrarfcn);
return i;
}
}
mm_obj_dbg (log_object, "invalid nrarfcn: %d ", nrarfcn);
return NUM_NR_RANGE_DATA;
}
gdouble
mm_get_frequency_from_nrarfcn (guint32 nrarfcn,
gpointer log_object)
{
guint8 i;
i = mm_get_nr_range_data (nrarfcn,log_object);
if (i == NUM_NR_RANGE_DATA)
return 0.0;
return nr_range_data[i].range_offset + nr_range_data[i].global_khz * (nrarfcn - nr_range_data[i].nrarfcn_offset);
}

View File

@@ -143,4 +143,34 @@ gboolean mm_signal_from_mbim_signal_state (MbimDataClass data_class,
MMSignal **out_lte,
MMSignal **out_nr5g);
/*****************************************************************************/
/* RF utilities */
/*****************************************************************************/
/* Value defined to allow tolerence in the center frequency comparison logic */
#define FREQUENCY_TOLERENCE 300
/* Value used to convert KHz value to Hz */
#define HERTZ_CONV 1000
typedef struct {
MMServingCellType serving_cell_type;
guint32 bandwidth;
guint64 center_frequency;
} MMRfInfo;
void mm_rf_info_free (MMRfInfo *rf_data);
void mm_rfim_info_list_free (GList *rfim_info_list);
GList *mm_rfim_info_list_from_mbim_intel_rfim_frequency_value_array (MbimIntelRfimFrequencyValueArray *freq_info,
guint freq_count,
gpointer log_object);
gdouble mm_get_downlink_carrier_frequency (guint32 earfcn,
gpointer log_object);
gdouble mm_get_frequency_from_nrarfcn (guint32 nrarfcn,
gpointer log_object);
#endif /* MM_MODEM_HELPERS_MBIM_H */