Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: location: Add support for GCI cell #11549

Merged
merged 2 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/nrf/libraries/modem/location.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ The supported location methods are as follows:
* Cellular positioning

* Uses :ref:`lte_lc_readme` for getting a list of nearby cellular base stations.
* Neighbor cell measurement is performed with :c:enum:`LTE_LC_NEIGHBOR_SEARCH_TYPE_EXTENDED_COMPLETE` search type.
A GCI search with :c:enum:`LTE_LC_NEIGHBOR_SEARCH_TYPE_GCI_EXTENDED_LIGHT` search type is performed if the previous search did not find enough cells.
For more details on GCI search, see :c:member:`location_cellular_config.cell_count`.
* The ``cloud location`` method handles sending cell information to the selected location service and getting the calculated location back to the device.

* Wi-Fi positioning
Expand Down Expand Up @@ -182,6 +185,7 @@ when :c:func:`location_config_defaults_set` function is called:
* :kconfig:option:`CONFIG_LOCATION_REQUEST_DEFAULT_GNSS_VISIBILITY_DETECTION`
* :kconfig:option:`CONFIG_LOCATION_REQUEST_DEFAULT_GNSS_PRIORITY_MODE`
* :kconfig:option:`CONFIG_LOCATION_REQUEST_DEFAULT_CELLULAR_TIMEOUT`
* :kconfig:option:`CONFIG_LOCATION_REQUEST_DEFAULT_CELLULAR_CELL_COUNT`
* :kconfig:option:`CONFIG_LOCATION_REQUEST_DEFAULT_WIFI_TIMEOUT`

Usage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,10 @@ Modem libraries

* Updated the :c:func:`nrf_modem_lib_shutdown` function to allow the modem to be in flight mode (``CFUN=4``) when shutting down the modem.

* :ref:`lib_location` library:

* Neighbor cell search is modified to use GCI search depending on :c:member:`location_cellular_config.cell_count` value.

* :ref:`pdn_readme` library:

* Updated the library to allow a ``PDP_type``-only configuration in the :c:func:`pdn_ctx_configure` function.
Expand Down
29 changes: 29 additions & 0 deletions include/modem/location.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ struct location_cellular_config {
* @ref location_config_defaults_set function is called and can be changed
* at build time with CONFIG_LOCATION_REQUEST_DEFAULT_CELLULAR_TIMEOUT configuration.
*
* Timeout only applies to neighbor cell search, not the cloud communication.
* Timeout for the entire location request specified in @ref location_config structure
* is still valid.
* When CONFIG_LOCATION_SERVICE_EXTERNAL is enabled, this timeout stops when
* event LOCATION_EVT_CLOUD_LOCATION_EXT_REQUEST is sent. However, timeout specified in
* @ref location_config structure is still valid.
Expand All @@ -354,6 +357,28 @@ struct location_cellular_config {
* This parameter is ignored when CONFIG_LOCATION_SERVICE_EXTERNAL is enabled.
*/
enum location_service service;

/**
* @brief Number of cells to be requested for cellular positioning.
*
* @details Default value is 4. It is applied when
* @ref location_config_defaults_set function is called and can be changed
* at build time with CONFIG_LOCATION_REQUEST_DEFAULT_CELLULAR_CELL_COUNT configuration.
*
* Maximum value is 15.
*
* Zero indicates that only normal neighbor cell search is performed but no GCI search.
*
* If there are less than requested number of neighbor cells (including current cell),
* GCI (surrounding) cells are requested also.
*
* Note that even if there are a lot of cells available, the number of cells
* used for positioning may be lower than the requested number of cells due to
* the behavior of the search algorithm. Also, the number of cells used for
* positioning may be higher than the requested number of cells if there are
* more neighbor cells (including current cell).
*/
uint8_t cell_count;
};

/** Wi-Fi positioning configuration. */
Expand All @@ -366,6 +391,10 @@ struct location_wifi_config {
* @ref location_config_defaults_set function is called and can be changed
* at build time with CONFIG_LOCATION_REQUEST_DEFAULT_WIFI_TIMEOUT configuration.
*
* Timeout only applies to Wi-Fi scan, not the cloud communication.
* Timeout for the entire location request specified in @ref location_config structure
* is still valid.
*
* When CONFIG_LOCATION_SERVICE_EXTERNAL is enabled, this timeout stops when
* event LOCATION_EVT_CLOUD_LOCATION_EXT_REQUEST is sent. However, timeout specified in
* @ref location_config structure is still valid.
Expand Down
8 changes: 8 additions & 0 deletions lib/location/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,14 @@ config LOCATION_REQUEST_DEFAULT_CELLULAR_TIMEOUT
Default value used in location_config_defaults_set() function for timeout
member within location_cellular_config structure.

config LOCATION_REQUEST_DEFAULT_CELLULAR_CELL_COUNT
int "Number of requested cellular neighbors"
default 4
range 0 15
help
Default value used in location_config_defaults_set() function for cell_count
member within location_cellular_config structure.

endif # LOCATION_METHOD_CELLULAR

if LOCATION_METHOD_WIFI
Expand Down
1 change: 1 addition & 0 deletions lib/location/location.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ static void location_config_method_defaults_set(
#if defined(CONFIG_LOCATION_METHOD_CELLULAR)
method->cellular.timeout = CONFIG_LOCATION_REQUEST_DEFAULT_CELLULAR_TIMEOUT;
method->cellular.service = LOCATION_SERVICE_ANY;
method->cellular.cell_count = CONFIG_LOCATION_REQUEST_DEFAULT_CELLULAR_CELL_COUNT;
#endif
} else if (method_type == LOCATION_METHOD_WIFI) {
#if defined(CONFIG_LOCATION_METHOD_WIFI)
Expand Down
3 changes: 3 additions & 0 deletions lib/location/location_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ void location_core_config_log(const struct location_config *config)
LOG_DBG(" Service: %s (%d)",
location_core_service_str(config->methods[i].cellular.service),
config->methods[i].cellular.service);
LOG_DBG(" Cell count: %d", config->methods[i].cellular.cell_count);
#if defined(CONFIG_LOCATION_METHOD_WIFI)
} else if (type == LOCATION_METHOD_WIFI) {
LOG_DBG(" Timeout: %dms", config->methods[i].wifi.timeout);
Expand Down Expand Up @@ -365,6 +366,8 @@ static int location_core_location_get_pos(void)

location_core_current_config_set(&loc_req_info.config);
/* Location request starts from the first method */
loc_req_info.timeout_uptime = (loc_req_info.config.timeout != SYS_FOREVER_MS) ?
k_uptime_get() + loc_req_info.config.timeout : SYS_FOREVER_MS;
loc_req_info.execute_fallback = true;
loc_req_info.current_method_index = 0;
requested_method = loc_req_info.methods[loc_req_info.current_method_index];
Expand Down
6 changes: 6 additions & 0 deletions lib/location/location_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ struct location_request_info {

/** Whether to perform fallback for current location request processing. */
bool execute_fallback;

/**
* Device uptime when location request timer expires.
* This is used in cloud location method to calculate timeout for the cloud operation.
*/
int64_t timeout_uptime;
};

struct location_method_api {
Expand Down
32 changes: 10 additions & 22 deletions lib/location/method_cloud_location.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct method_cloud_location_start_work_args {
struct k_work work_item;
const struct location_wifi_config *wifi_config;
const struct location_cellular_config *cell_config;
int64_t starting_uptime_ms;
int64_t locreq_timeout_uptime;
};

static struct method_cloud_location_start_work_args method_cloud_location_start_work;
Expand All @@ -44,19 +44,13 @@ static void method_cloud_location_positioning_work_fn(struct k_work *work)
const struct location_cellular_config *cell_config = work_data->cell_config;
struct wifi_scan_info *scan_wifi_info = NULL;
struct lte_lc_cells_info *scan_cellular_info = NULL;
int64_t scan_start_time;
int32_t used_timeout_ms;
int err = 0;
#if defined(CONFIG_LOCATION_METHOD_WIFI)
struct k_sem wifi_scan_ready;

k_sem_init(&wifi_scan_ready, 0, 1);
#endif
#if defined(CONFIG_LOCATION_METHOD_CELLULAR)
struct k_sem ncellmeas_ready;

k_sem_init(&ncellmeas_ready, 0, 1);
#endif

if (wifi_config != NULL && cell_config != NULL) {
used_timeout_ms = MIN(cell_config->timeout, wifi_config->timeout);
Expand All @@ -68,7 +62,6 @@ static void method_cloud_location_positioning_work_fn(struct k_work *work)
}

location_core_timer_start(used_timeout_ms);
scan_start_time = k_uptime_get();

#if defined(CONFIG_LOCATION_METHOD_WIFI)
if (wifi_config != NULL) {
Expand All @@ -78,8 +71,7 @@ static void method_cloud_location_positioning_work_fn(struct k_work *work)

#if defined(CONFIG_LOCATION_METHOD_CELLULAR)
if (cell_config != NULL) {
err = scan_cellular_start(&ncellmeas_ready);
k_sem_take(&ncellmeas_ready, K_FOREVER);
err = scan_cellular_start(cell_config->cell_count);
scan_cellular_info = scan_cellular_results_get();
}
#endif
Expand Down Expand Up @@ -118,12 +110,11 @@ static void method_cloud_location_positioning_work_fn(struct k_work *work)
#else
struct location_data location;
struct location_data location_result = { 0 };
int64_t scan_time;
struct cloud_service_pos_req params = {
.cell_data = scan_cellular_info,
.wifi_data = scan_wifi_info,
.service = (cell_config != NULL) ? cell_config->service : wifi_config->service,
.timeout_ms = used_timeout_ms
.timeout_ms = SYS_FOREVER_MS
trantanen marked this conversation as resolved.
Show resolved Hide resolved
};

if (!location_utils_is_default_pdn_active()) {
Expand All @@ -138,19 +129,16 @@ static void method_cloud_location_positioning_work_fn(struct k_work *work)
/* Scannings done at this point of time. Store current time to response. */
location_utils_systime_to_location_datetime(&location_result.datetime);

/* Calculate timeout for cloud request */
if (used_timeout_ms != SYS_FOREVER_MS) {
/* +1 to round the time up */
scan_time = (k_uptime_get() - scan_start_time) + 1;

/* Check if timeout has already elapsed */
if (scan_time >= used_timeout_ms) {
/* Timeout for cloud request is the remaining time from the location request timeout.
* Notice that it's not from the method timeout, which only applies to the scan procedure.
*/
if (work_data->locreq_timeout_uptime != SYS_FOREVER_MS) {
params.timeout_ms = work_data->locreq_timeout_uptime - k_uptime_get();
if (params.timeout_ms < 0) {
LOG_WRN("Timeout occurred during scannings");
err = -ETIMEDOUT;
goto end;
}
/* Take time used for neighbour cell measurements into account */
params.timeout_ms = used_timeout_ms - scan_time;
}

/* Request location from the cloud */
Expand Down Expand Up @@ -216,7 +204,7 @@ int method_cloud_location_get(const struct location_request_info *request)
method_cloud_location_start_work.wifi_config = request->wifi;
}

method_cloud_location_start_work.starting_uptime_ms = k_uptime_get();
method_cloud_location_start_work.locreq_timeout_uptime = request->timeout_uptime;
k_work_submit_to_queue(
location_core_work_queue_get(),
&method_cloud_location_start_work.work_item);
Expand Down
94 changes: 77 additions & 17 deletions lib/location/scan_cellular.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,17 @@
LOG_MODULE_DECLARE(location, CONFIG_LOCATION_LOG_LEVEL);

static struct lte_lc_ncell neighbor_cells[CONFIG_LTE_NEIGHBOR_CELLS_MAX];
static struct lte_lc_cell gci_cells[CONFIG_LTE_NEIGHBOR_CELLS_MAX];
static struct lte_lc_cells_info scan_cellular_info = {
.neighbor_cells = neighbor_cells
.neighbor_cells = neighbor_cells,
.gci_cells = gci_cells
};
static struct k_sem *scan_cellular_ready;

static bool running;
/* Indicates when individual ncellmeas operation is completed. This is internal to this file. */
static struct k_sem scan_cellular_sem_ncellmeas_evt;
/* Requested number of cells to be searched. */
static int8_t scan_cellular_cell_count;

struct lte_lc_cells_info *scan_cellular_results_get(void)
{
Expand All @@ -36,10 +43,11 @@ void scan_cellular_lte_ind_handler(const struct lte_lc_evt *const evt)
{
switch (evt->type) {
case LTE_LC_EVT_NEIGHBOR_CELL_MEAS: {
if (scan_cellular_ready == NULL) {
if (!running) {
return;
}
LOG_DBG("Cell measurements results received");
LOG_DBG("Cell measurements results received: ncells_count=%d, gci_cells_count=%d",
evt->cells_info.ncells_count, evt->cells_info.gci_cells_count);

/* Copy current cell information */
memcpy(&scan_cellular_info.current_cell,
Expand All @@ -54,30 +62,46 @@ void scan_cellular_lte_ind_handler(const struct lte_lc_evt *const evt)

scan_cellular_info.ncells_count = evt->cells_info.ncells_count;
} else {
scan_cellular_info.ncells_count = 0;
LOG_DBG("No neighbor cell information from modem.");
LOG_DBG("No neighbor cell information from modem");
}

k_sem_give(scan_cellular_ready);
scan_cellular_ready = NULL;
/* Copy surrounding cell information if present */
if (evt->cells_info.gci_cells_count > 0 && evt->cells_info.gci_cells) {
memcpy(scan_cellular_info.gci_cells,
evt->cells_info.gci_cells,
sizeof(struct lte_lc_cell) * evt->cells_info.gci_cells_count);

scan_cellular_info.gci_cells_count = evt->cells_info.gci_cells_count;
} else {
LOG_DBG("No surrounding cell information from modem");

}

k_sem_give(&scan_cellular_sem_ncellmeas_evt);
} break;
default:
break;
}
}

int scan_cellular_start(struct k_sem *ncellmeas_ready)
int scan_cellular_start(uint8_t cell_count)
{
struct location_utils_modem_params_info modem_params = { 0 };
struct lte_lc_ncellmeas_params ncellmeas_params = {
.search_type = LTE_LC_NEIGHBOR_SEARCH_TYPE_EXTENDED_COMPLETE,
.gci_count = 0
};
int err;

scan_cellular_ready = ncellmeas_ready;
running = true;
scan_cellular_cell_count = cell_count;
scan_cellular_info.current_cell.id = LTE_LC_CELL_EUTRAN_ID_INVALID;
scan_cellular_info.ncells_count = 0;
scan_cellular_info.gci_cells_count = 0;

LOG_DBG("Triggering cell measurements");

/* Starting measurements with lte_lc default parameters */
err = lte_lc_neighbor_cell_measurement(NULL);
err = lte_lc_neighbor_cell_measurement(&ncellmeas_params);
if (err) {
LOG_WRN("Failed to initiate neighbor cell measurements: %d, "
"next: fallback to get modem parameters",
Expand All @@ -99,23 +123,57 @@ int scan_cellular_start(struct k_sem *ncellmeas_ready)
scan_cellular_info.current_cell.id = modem_params.cell_id;
scan_cellular_info.current_cell.phys_cell_id = modem_params.phys_cell_id;
}
k_sem_give(scan_cellular_ready);
scan_cellular_ready = NULL;
goto end;
}
err = k_sem_take(&scan_cellular_sem_ncellmeas_evt, K_FOREVER);
if (err) {
/* Semaphore was reset so stop search procedure */
err = 0;
goto end;
}

/* Calculate the number of GCI cells to be requested.
* We should subtract 1 for current cell as ncell_count won't include it.
* GCI count requested from modem includes also current cell so we should add 1.
* So these two cancel each other.
*/
scan_cellular_cell_count = scan_cellular_cell_count - scan_cellular_info.ncells_count;

LOG_DBG("scan_cellular_start: scan_cellular_cell_count=%d", scan_cellular_cell_count);

if (scan_cellular_cell_count > 1) {

ncellmeas_params.search_type = LTE_LC_NEIGHBOR_SEARCH_TYPE_GCI_EXTENDED_LIGHT;
ncellmeas_params.gci_count = scan_cellular_cell_count;

err = lte_lc_neighbor_cell_measurement(&ncellmeas_params);
if (err) {
LOG_WRN("Failed to initiate GCI cell measurements: %d", err);
/* Clearing 'err' because normal neighbor search has succeeded
* so those are still valid and positioning can procede with that data
*/
err = 0;
goto end;
}
k_sem_take(&scan_cellular_sem_ncellmeas_evt, K_FOREVER);
}

end:
running = false;
return err;
}

int scan_cellular_cancel(void)
{
if (scan_cellular_ready != NULL) {
if (running) {
/* Cancel/stopping might trigger a NCELLMEAS notification */
(void)lte_lc_neighbor_cell_measurement_cancel();
k_sem_reset(scan_cellular_ready);
k_sem_reset(&scan_cellular_sem_ncellmeas_evt);
} else {
return -EPERM;
}

scan_cellular_ready = NULL;
running = false;

return 0;
}
Expand All @@ -124,5 +182,7 @@ int scan_cellular_init(void)
{
lte_lc_register_handler(scan_cellular_lte_ind_handler);

k_sem_init(&scan_cellular_sem_ncellmeas_evt, 0, 1);

return 0;
}
2 changes: 1 addition & 1 deletion lib/location/scan_cellular.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <modem/lte_lc.h>

int scan_cellular_init(void);
int scan_cellular_start(struct k_sem *ncellmeas_ready);
int scan_cellular_start(uint8_t cell_count);
struct lte_lc_cells_info *scan_cellular_results_get(void);
int scan_cellular_cancel(void);

Expand Down
Loading