Skip to content

Commit

Permalink
applications: asset_tracker_v2: Fix Wi-Fi+GNSS location priority
Browse files Browse the repository at this point in the history
ATv2 is ignoring the result of the cloud location methods
(Wi-Fi and cellular) and simply indicating to Location library
that location is unknown. Hence, Location library will fallback to
next method.

This is fine when you have location method priority order as GNSS,
Wi-Fi and Cellular and there is nothing to fallback after WiFi and
cellular. However, when the priorities are Wi-Fi, GNSS and
Cellular, you don't want to fallback to GNSS if Wi-Fi positioning
returns a valid location.

Implemented support for waiting for the location from the cloud and
acting based on the outcome. If the cloud backend doesn't support
returning the location back to the device, Location library will be
still indicated that the location is unknown and it'll do fallback
to GNSS.

Signed-off-by: Tommi Rantanen <[email protected]>
  • Loading branch information
trantanen authored and nordicjm committed Sep 8, 2023
1 parent e166aef commit 2cac07c
Show file tree
Hide file tree
Showing 18 changed files with 336 additions and 83 deletions.
15 changes: 14 additions & 1 deletion applications/asset_tracker_v2/doc/location_module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Wi-Fi positioning has the following limitations:

The Wi-Fi configuration uses both flash and SRAM extensively.
You can configure the number of scan results with the :kconfig:option:`CONFIG_LOCATION_METHOD_WIFI_SCANNING_RESULTS_MAX_CNT` Kconfig option to reduce SRAM consumption.
Align the :kconfig:option:`CONFIG_WIFI_MGMT_SCAN_MAX_BSS_CNT` Kconfig option with :kconfig:option:`CONFIG_LOCATION_METHOD_WIFI_SCANNING_RESULTS_MAX_CNT`.
You can also change the value of the :kconfig:option:`CONFIG_HEAP_MEM_POOL_SIZE` Kconfig option.

Module internals
Expand All @@ -100,7 +101,19 @@ All incoming events from other modules are handled in the context of the Applica

The :ref:`lib_location` library handles cellular and Wi-Fi positioning together when the location request method list has them next to each other.
This means that LTE neighbor cell measurements and Wi-Fi scanning results are combined into the same :c:enum:`LOCATION_EVT_CLOUD_LOCATION_EXT_REQUEST` event.
The location module responds to the :ref:`lib_location` library with unknown location resolution, because it does not request the location back from cloud service.

The location module sends the cellular and Wi-Fi positioning request forward with :c:enum:`LOCATION_MODULE_EVT_CLOUD_LOCATION_DATA_READY` event,
and waits for an event from the cloud module on the result of the positioning.
This result is forwarded to the :ref:`lib_location` library.
Depending on the cloud integration, positioning result from the cloud service might be requested or not.
The result must be indicated with one of the following events:

* :c:enum:`CLOUD_EVT_CLOUD_LOCATION_RECEIVED`: Location has been resolved successfully.
The :ref:`lib_location` library does not continue to use other positioning methods and the location request completes quickly.
* :c:enum:`CLOUD_EVT_CLOUD_LOCATION_ERROR`: Location resolution failed.
The :ref:`lib_location` library performs a fallback to the next positioning method in the priority list.
* :c:enum:`CLOUD_EVT_CLOUD_LOCATION_UNKNOWN`: Location resolution result is unknown, that is, cloud integration is not capable of or configured to resolve it.
The :ref:`lib_location` library performs a fallback to the next positioning method.

Configuration options
*********************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ CONFIG_DK_LIBRARY=n
# Actual configs for the Wi-Fi
CONFIG_WIFI=y
CONFIG_WIFI_NRF700X=y
# Align this with CONFIG_LOCATION_METHOD_WIFI_SCANNING_RESULTS_MAX_CNT
CONFIG_WIFI_MGMT_SCAN_MAX_BSS_CNT=30

# Wi-Fi location
CONFIG_LOCATION_METHOD_WIFI=y
CONFIG_LOCATION_REQUEST_DEFAULT_METHOD_FIRST_GNSS=y
CONFIG_LOCATION_REQUEST_DEFAULT_METHOD_SECOND_WIFI=y
CONFIG_LOCATION_REQUEST_DEFAULT_METHOD_THIRD_CELLULAR=y

# Align this with CONFIG_WIFI_MGMT_SCAN_MAX_BSS_CNT
CONFIG_LOCATION_METHOD_WIFI_SCANNING_RESULTS_MAX_CNT=30
CONFIG_LOCATION_WORKQUEUE_STACK_SIZE=8192
# Needed to handle more scan results
Expand Down
5 changes: 5 additions & 0 deletions applications/asset_tracker_v2/src/cloud/aws_iot_integration.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,11 @@ int cloud_wrap_cloud_location_send(char *buf, size_t len, bool ack, uint32_t id)
return 0;
}

bool cloud_wrap_cloud_location_response_wait(void)
{
return false;
}

int cloud_wrap_agps_request_send(char *buf, size_t len, bool ack, uint32_t id)
{
int err;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,11 @@ int cloud_wrap_cloud_location_send(char *buf, size_t len, bool ack, uint32_t id)
return 0;
}

bool cloud_wrap_cloud_location_response_wait(void)
{
return false;
}

int cloud_wrap_agps_request_send(char *buf, size_t len, bool ack, uint32_t id)
{
int err;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,24 @@ int cloud_codec_encode_cloud_location(
return -ENOMEM;
}

if (!cloud_location->neighbor_cells_valid) {
err = -ENODATA;
goto exit;
}

err = json_common_neighbor_cells_data_add(root_obj, &cloud_location->neighbor_cells,
JSON_COMMON_ADD_DATA_TO_OBJECT);
if (err) {
goto exit;
if (cloud_location->neighbor_cells_valid) {
err = json_common_neighbor_cells_data_add(root_obj, &cloud_location->neighbor_cells,
JSON_COMMON_ADD_DATA_TO_OBJECT);
if (err) {
goto exit;
}
}

#if defined(CONFIG_LOCATION_METHOD_WIFI)
err = json_common_wifi_ap_data_add(root_obj, &cloud_location->wifi_access_points,
JSON_COMMON_ADD_DATA_TO_OBJECT);
if (err) {
goto exit;
if (cloud_location->wifi_access_points_valid) {
err = json_common_wifi_ap_data_add(root_obj, &cloud_location->wifi_access_points,
JSON_COMMON_ADD_DATA_TO_OBJECT);
if (err) {
goto exit;
}
}
#endif


buffer = cJSON_PrintUnformatted(root_obj);
if (buffer == NULL) {
LOG_ERR("Failed to allocate memory for JSON string");
Expand All @@ -115,6 +113,12 @@ int cloud_codec_encode_cloud_location(
return err;
}

int cloud_codec_decode_cloud_location(const char *input, size_t input_len,
struct location_data *location)
{
return -ENOTSUP;
}

int cloud_codec_encode_agps_request(struct cloud_codec_data *output,
struct cloud_data_agps_request *agps_request)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,21 @@ int cloud_codec_encode_cloud_location(
return -ENOMEM;
}

if (!cloud_location->neighbor_cells_valid) {
err = -ENODATA;
goto exit;
}

err = json_common_neighbor_cells_data_add(root_obj, &cloud_location->neighbor_cells,
JSON_COMMON_ADD_DATA_TO_OBJECT);
if (err) {
goto exit;
if (cloud_location->neighbor_cells_valid) {
err = json_common_neighbor_cells_data_add(root_obj, &cloud_location->neighbor_cells,
JSON_COMMON_ADD_DATA_TO_OBJECT);
if (err) {
goto exit;
}
}

#if defined(CONFIG_LOCATION_METHOD_WIFI)
err = json_common_wifi_ap_data_add(root_obj, &cloud_location->wifi_access_points,
JSON_COMMON_ADD_DATA_TO_OBJECT);
if (err) {
goto exit;
if (cloud_location->wifi_access_points_valid) {
err = json_common_wifi_ap_data_add(root_obj, &cloud_location->wifi_access_points,
JSON_COMMON_ADD_DATA_TO_OBJECT);
if (err) {
goto exit;
}
}
#endif

Expand All @@ -84,6 +83,13 @@ int cloud_codec_encode_cloud_location(
return err;
}


int cloud_codec_decode_cloud_location(const char *input, size_t input_len,
struct location_data *location)
{
return -ENOTSUP;
}

int cloud_codec_encode_agps_request(struct cloud_codec_data *output,
struct cloud_data_agps_request *agps_request)
{
Expand Down
22 changes: 22 additions & 0 deletions applications/asset_tracker_v2/src/cloud/cloud_codec/cloud_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
#include <cJSON_os.h>
#include <zephyr/net/net_ip.h>
#include <modem/lte_lc.h>
#if defined(CONFIG_LOCATION)
#include <modem/location.h>
#endif
#include <net/wifi_location_common.h>
#include <nrf_modem_gnss.h>

Expand Down Expand Up @@ -319,6 +322,25 @@ int cloud_codec_encode_cloud_location(
struct cloud_codec_data *output,
struct cloud_data_cloud_location *cloud_location);

/* Foward declaration */
struct location_data;

/**
* @brief Decode received cloud location data.
*
* @param[in] input String buffer with encoded cloud location data.
* @param[in] input_len Length of input.
* @param[out] location Storage for the decoded cloud location data.
*
* @retval 0 on success.
* @retval -EFAULT if cloud returned with error to the location request.
* @retval -ENOMEM if codec could not allocate memory.
* @retval -ENOTSUP if the function is not supported by the backend.
* @return 0 on success or negative error value on failure.
*/
int cloud_codec_decode_cloud_location(const char *input, size_t input_len,
struct location_data *location);

/**
* @brief Encode cloud codec A-GPS request.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ int cloud_codec_init(struct cloud_data_cfg *cfg, cloud_codec_evt_handler_t event
}

int cloud_codec_encode_cloud_location(struct cloud_codec_data *output,
struct cloud_data_cloud_location *cloud_location)
struct cloud_data_cloud_location *cloud_location)
{
ARG_UNUSED(output);

Expand All @@ -101,6 +101,12 @@ int cloud_codec_encode_cloud_location(struct cloud_codec_data *output,
return 0;
}

int cloud_codec_decode_cloud_location(const char *input, size_t input_len,
struct location_data *location)
{
return -ENOTSUP;
}

int cloud_codec_encode_agps_request(struct cloud_codec_data *output,
struct cloud_data_agps_request *agps_request)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,29 @@ int cloud_codec_encode_cloud_location(
return -ENOTSUP;
}

int cloud_codec_decode_cloud_location(const char *input, size_t input_len,
struct location_data *location)
{
ARG_UNUSED(input_len);

int err;
struct nrf_cloud_location_result result;

err = nrf_cloud_location_process(input, &result);
if (err == 0) {
#if defined(CONFIG_LOCATION)
location->latitude = result.lat;
location->longitude = result.lon;
location->accuracy = result.unc;
#endif
/* Date and time are not filled because they are not used anyway */
} else if (err == 1) {
/* Unexpected response from cloud is treated similarly to error from cloud */
err = -EFAULT;
}
return err;
}

int cloud_codec_encode_agps_request(struct cloud_codec_data *output,
struct cloud_data_agps_request *agps_request)
{
Expand Down
12 changes: 12 additions & 0 deletions applications/asset_tracker_v2/src/cloud/cloud_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ enum cloud_wrap_event_type {
* Payload is of type @ref cloud_wrap_event_data.
*/
CLOUD_WRAP_EVT_PGPS_DATA_RECEIVED,
/** Data received from cloud integration layer.
* Payload is of type @ref cloud_wrap_event_data.
*/
CLOUD_WRAP_EVT_CLOUD_LOCATION_RESULT_RECEIVED,
/** Reboot request received from cloud. */
CLOUD_WRAP_EVT_REBOOT_REQUEST,
/** Request to connect to LTE. */
Expand Down Expand Up @@ -210,6 +214,14 @@ int cloud_wrap_ui_send(char *buf, size_t len, bool ack, uint32_t id,
*/
int cloud_wrap_cloud_location_send(char *buf, size_t len, bool ack, uint32_t id);

/**
* @brief Indicates whether cloud implementation can and is configured to return the resolved
* location back to the device.
*
* @return Indicates whether resolved location is sent back to the device.
*/
bool cloud_wrap_cloud_location_response_wait(void);

/**
* @brief Send A-GPS request to cloud.
*
Expand Down
21 changes: 20 additions & 1 deletion applications/asset_tracker_v2/src/cloud/nrf_cloud_integration.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,16 @@ static void nrf_cloud_event_handler(const struct nrf_cloud_evt *evt)
notify = true;
break;
case NRF_CLOUD_EVT_RX_DATA_LOCATION:
LOG_DBG("NRF_CLOUD_EVT_RX_DATA_LOCATION");
LOG_DBG("NRF_CLOUD_EVT_RX_DATA_LOCATION: %s", (char *)evt->data.ptr);

/* If GNSS is NOT the first priority, we'll handle the cloud response */
if (!IS_ENABLED(CONFIG_LOCATION_REQUEST_DEFAULT_METHOD_FIRST_GNSS)) {
cloud_wrap_evt.type = CLOUD_WRAP_EVT_CLOUD_LOCATION_RESULT_RECEIVED;
cloud_wrap_evt.data.buf = (char *)evt->data.ptr;
cloud_wrap_evt.data.len = evt->data.len;

notify = true;
}
break;
case NRF_CLOUD_EVT_USER_ASSOCIATION_REQUEST:
LOG_WRN("NRF_CLOUD_EVT_USER_ASSOCIATION_REQUEST");
Expand Down Expand Up @@ -440,6 +449,16 @@ int cloud_wrap_cloud_location_send(char *buf, size_t len, bool ack, uint32_t id)
return 0;
}

bool cloud_wrap_cloud_location_response_wait(void)
{
/* If GNSS is the first priority, then we can ignore the location response from the cloud */
if (IS_ENABLED(CONFIG_LOCATION_REQUEST_DEFAULT_METHOD_FIRST_GNSS)) {
return false;
} else {
return true;
}
}

#if defined(CONFIG_LOCATION_METHOD_WIFI)
int cloud_wrap_wifi_access_points_send(char *buf, size_t len, bool ack, uint32_t id)
{
Expand Down
6 changes: 6 additions & 0 deletions applications/asset_tracker_v2/src/events/cloud_module_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ static char *get_evt_type_str(enum cloud_module_event_type type)
return "CLOUD_EVT_REBOOT_REQUEST";
case CLOUD_EVT_CONFIG_RECEIVED:
return "CLOUD_EVT_CONFIG_RECEIVED";
case CLOUD_EVT_CLOUD_LOCATION_RECEIVED:
return "CLOUD_EVT_CLOUD_LOCATION_RECEIVED";
case CLOUD_EVT_CLOUD_LOCATION_ERROR:
return "CLOUD_EVT_CLOUD_LOCATION_ERROR";
case CLOUD_EVT_CLOUD_LOCATION_UNKNOWN:
return "CLOUD_EVT_CLOUD_LOCATION_UNKNOWN";
case CLOUD_EVT_CONFIG_EMPTY:
return "CLOUD_EVT_CONFIG_EMPTY";
case CLOUD_EVT_DATA_SEND_QOS:
Expand Down
24 changes: 21 additions & 3 deletions applications/asset_tracker_v2/src/events/cloud_module_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include <app_event_manager.h>
#include <app_event_manager_profiler_tracer.h>
#include <qos.h>
#if defined(CONFIG_LOCATION)
#include <modem/location.h>
#endif

#include "cloud/cloud_codec/cloud_codec.h"

Expand Down Expand Up @@ -67,6 +70,17 @@ enum cloud_module_event_type {
*/
CLOUD_EVT_CONFIG_RECEIVED,

/** Cloud location data has been received from cloud.
* The payload associated with this event is of type @ref location_data.
*/
CLOUD_EVT_CLOUD_LOCATION_RECEIVED,

/** Cloud location response has been received but location could not be resolved. */
CLOUD_EVT_CLOUD_LOCATION_ERROR,

/** Cloud location resolution is unknown. */
CLOUD_EVT_CLOUD_LOCATION_UNKNOWN,

/** An empty device configuration has been received from cloud. */
CLOUD_EVT_CONFIG_EMPTY,

Expand Down Expand Up @@ -115,13 +129,17 @@ struct cloud_module_event {
enum cloud_module_event_type type;

union {
/** Variable that contains a new configuration received from the cloud service. */
/** New configuration received from the cloud service. */
struct cloud_data_cfg config;
/** Variable that contains data that was attempted to be sent. Could be used
#if defined(CONFIG_LOCATION)
/** Cloud location data received from the cloud service. */
struct location_data cloud_location;
#endif
/** Data that was attempted to be sent. Could be used
* to free allocated data post transmission.
*/
struct cloud_module_data_ack ack;
/** Variable that contains the message that should be sent to cloud. */
/** The message that should be sent to cloud. */
struct qos_data message;
/** Module ID, used when acknowledging shutdown requests. */
uint32_t id;
Expand Down
Loading

0 comments on commit 2cac07c

Please sign in to comment.