From 3b33bd3bfad7cc262fafe35f2f19526751a3f66b Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Thu, 9 Jan 2025 16:32:10 +0100 Subject: [PATCH] examples: zephyr: location: add nRF91 support Add nRF91 specific cellular tower information fetching and use when requesting location data. Use current cell only for now, as that is the only information provided with the tested modem and SIM card. Leave logs for neighbour cells enabled, so that extending this sample in the future is easy. Signed-off-by: Marcin Niestroj --- examples/zephyr/location/CMakeLists.txt | 1 + examples/zephyr/location/Kconfig | 1 + examples/zephyr/location/README.md | 10 ++ examples/zephyr/location/sample.yaml | 2 + examples/zephyr/location/socs/nrf9151_ns.conf | 41 +++++ examples/zephyr/location/socs/nrf9160_ns.conf | 38 ++++ examples/zephyr/location/src/cellular_nrf91.c | 163 ++++++++++++++++++ 7 files changed, 256 insertions(+) create mode 100644 examples/zephyr/location/socs/nrf9151_ns.conf create mode 100644 examples/zephyr/location/socs/nrf9160_ns.conf create mode 100644 examples/zephyr/location/src/cellular_nrf91.c diff --git a/examples/zephyr/location/CMakeLists.txt b/examples/zephyr/location/CMakeLists.txt index 412514fe1..40ccc0fe0 100644 --- a/examples/zephyr/location/CMakeLists.txt +++ b/examples/zephyr/location/CMakeLists.txt @@ -8,3 +8,4 @@ project(location) target_sources(app PRIVATE src/main.c) target_sources_ifdef(CONFIG_GOLIOTH_CELLULAR_PLAYBACK app PRIVATE src/cellular_playback.c) target_sources_ifdef(CONFIG_GOLIOTH_WIFI_PLAYBACK app PRIVATE src/wifi_playback.c) +target_sources_ifdef(CONFIG_SOC_SERIES_NRF91X app PRIVATE src/cellular_nrf91.c) diff --git a/examples/zephyr/location/Kconfig b/examples/zephyr/location/Kconfig index 98df34512..ca1b4caba 100644 --- a/examples/zephyr/location/Kconfig +++ b/examples/zephyr/location/Kconfig @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 configdefault GOLIOTH_LOCATION_CELLULAR + default y if SOC_SERIES_NRF91X default y if GOLIOTH_CELLULAR_PLAYBACK configdefault GOLIOTH_LOCATION_WIFI diff --git a/examples/zephyr/location/README.md b/examples/zephyr/location/README.md index 1ef427000..57ef70776 100644 --- a/examples/zephyr/location/README.md +++ b/examples/zephyr/location/README.md @@ -172,6 +172,16 @@ $ west build -b nrf52840dk/nrf52840 examples/zephyr/location $ west flash ``` +#### nRF9160 DK + +On your host computer open a terminal window, locate the source code of +this sample application (i.e., `examples/zephyr/location`) and type: + +```console +$ west build -b nrf9160dk/nrf9160/ns examples/zephyr/location +$ west flash +``` + ### Sample output This is the output from the serial console: diff --git a/examples/zephyr/location/sample.yaml b/examples/zephyr/location/sample.yaml index cbb891b96..356e41d8d 100644 --- a/examples/zephyr/location/sample.yaml +++ b/examples/zephyr/location/sample.yaml @@ -14,6 +14,8 @@ tests: - native_sim - native_sim/native/64 - nrf52840dk/nrf52840 + - nrf9151dk/nrf9151/ns + - nrf9160dk/nrf9160/ns sample.golioth.location.wifi_only: extra_configs: - CONFIG_GOLIOTH_CELLULAR_PLAYBACK=n diff --git a/examples/zephyr/location/socs/nrf9151_ns.conf b/examples/zephyr/location/socs/nrf9151_ns.conf new file mode 100644 index 000000000..bd3086af5 --- /dev/null +++ b/examples/zephyr/location/socs/nrf9151_ns.conf @@ -0,0 +1,41 @@ +# General config +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_NEWLIB_LIBC=y + +# Networking +CONFIG_NET_SOCKETS_OFFLOAD=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV6_NBR_CACHE=n +CONFIG_NET_IPV6_MLD=n + +# Increase native TLS socket implementation, so that it is chosen instead of +# offloaded nRF91 sockets +CONFIG_NET_SOCKETS_TLS_PRIORITY=35 + +# Modem library +CONFIG_NRF_MODEM_LIB=y + +# LTE connectivity with network connection manager +CONFIG_NRF_MODEM_LIB_NET_IF=y +CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_START=y +CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_CONNECT=y +CONFIG_NET_CONNECTION_MANAGER=y +CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=1024 + +# Increased sysworkq size, due to LTE connectivity +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +# Disable options y-selected by NCS for no good reason +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED=n +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=n + +# MbedTLS configuration to support p-384 curve. These options +# enable using the MbedTLS built-in support for operations not +# supported by the default nRF Oberon crypto backend +CONFIG_NORDIC_SECURITY_BACKEND=n +CONFIG_MBEDTLS_LEGACY_CRYPTO_C=y + +# Generate MCUboot compatible images +CONFIG_BOOTLOADER_MCUBOOT=y + +CONFIG_LTE_LC_NEIGHBOR_CELL_MEAS_MODULE=y diff --git a/examples/zephyr/location/socs/nrf9160_ns.conf b/examples/zephyr/location/socs/nrf9160_ns.conf new file mode 100644 index 000000000..cdc20bd73 --- /dev/null +++ b/examples/zephyr/location/socs/nrf9160_ns.conf @@ -0,0 +1,38 @@ +# General config +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_NEWLIB_LIBC=y + +# Networking +CONFIG_NET_SOCKETS_OFFLOAD=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV6_NBR_CACHE=n +CONFIG_NET_IPV6_MLD=n + +# Increase native TLS socket implementation, so that it is chosen instead of +# offloaded nRF91 sockets +CONFIG_NET_SOCKETS_TLS_PRIORITY=35 + +# Modem library +CONFIG_NRF_MODEM_LIB=y + +# LTE connectivity with network connection manager +CONFIG_NRF_MODEM_LIB_NET_IF=y +CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_START=y +CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_CONNECT=y +CONFIG_NET_CONNECTION_MANAGER=y +CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=1024 + +# Increased sysworkq size, due to LTE connectivity +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +# Disable options y-selected by NCS for no good reason +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED=n +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=n + +# MbedTLS configuration to support p-384 curve. These options +# enable using the MbedTLS built-in support for operations not +# supported by the default nRF Oberon crypto backend +CONFIG_NORDIC_SECURITY_BACKEND=n +CONFIG_MBEDTLS_LEGACY_CRYPTO_C=y + +CONFIG_LTE_LC_NEIGHBOR_CELL_MEAS_MODULE=y diff --git a/examples/zephyr/location/src/cellular_nrf91.c b/examples/zephyr/location/src/cellular_nrf91.c new file mode 100644 index 000000000..b87680e10 --- /dev/null +++ b/examples/zephyr/location/src/cellular_nrf91.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2025 Golioth, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(cellular_nrf91); + +#include + +#include "cellular.h" + +/* Indicates when individual ncellmeas operation is completed. This is internal to this file. */ +static K_SEM_DEFINE(scan_cellular_sem_ncellmeas_evt, 0, 1); + +static enum lte_lc_lte_mode lte_mode; +static struct lte_lc_ncell neighbor_cells[CONFIG_LTE_NEIGHBOR_CELLS_MAX]; +static struct lte_lc_cells_info scan_cellular_info = { + .neighbor_cells = neighbor_cells, +}; + +static const char *lte_mode_to_str(enum lte_lc_lte_mode mode) +{ + switch (mode) + { + case LTE_LC_LTE_MODE_LTEM: + return "LTEM"; + case LTE_LC_LTE_MODE_NBIOT: + return "NBIOT"; + case LTE_LC_LTE_MODE_NONE: + return "NONE"; + } + + return "unknown"; +} + +static void lte_ind_handler(const struct lte_lc_evt *const evt) +{ + switch (evt->type) + { + case LTE_LC_EVT_LTE_MODE_UPDATE: + LOG_INF("LTE mode: %s", lte_mode_to_str(evt->lte_mode)); + lte_mode = evt->lte_mode; + break; + case LTE_LC_EVT_CELL_UPDATE: + LOG_INF("LTE cell changed: Cell ID: %d, Tracking area: %d", + evt->cell.id, + evt->cell.tac); + break; + case LTE_LC_EVT_NEIGHBOR_CELL_MEAS: + LOG_INF("LTE current cell: MCC %d, MNC %d, Cell ID: %d, Tracking area: %d", + evt->cells_info.current_cell.mcc, + evt->cells_info.current_cell.mnc, + evt->cells_info.current_cell.id, + evt->cells_info.current_cell.tac); + + LOG_INF( + "Cell measurements results received: " + "ncells_count=%d, gci_cells_count=%d, current_cell.id=0x%08X", + evt->cells_info.ncells_count, + evt->cells_info.gci_cells_count, + evt->cells_info.current_cell.id); + + if (evt->cells_info.current_cell.id != LTE_LC_CELL_EUTRAN_ID_INVALID) + { + /* Copy current cell information. We are seeing this is not set for GCI + * search sometimes but we have it for the previous normal neighbor search. + */ + memcpy(&scan_cellular_info.current_cell, + &evt->cells_info.current_cell, + sizeof(struct lte_lc_cell)); + } + + /* Copy neighbor cell information if present */ + if (evt->cells_info.ncells_count > 0 && evt->cells_info.neighbor_cells) + { + memcpy(scan_cellular_info.neighbor_cells, + evt->cells_info.neighbor_cells, + sizeof(struct lte_lc_ncell) * evt->cells_info.ncells_count); + + scan_cellular_info.ncells_count = evt->cells_info.ncells_count; + } + else + { + LOG_DBG("No neighbor cell information from modem"); + } + + /* 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 cellular_info_get(struct golioth_cellular_info *infos, + size_t num_max_infos, + size_t *num_returned_infos) +{ + struct lte_lc_ncellmeas_params params = { + .search_type = LTE_LC_NEIGHBOR_SEARCH_TYPE_EXTENDED_LIGHT, + }; + struct lte_lc_cell *current = &scan_cellular_info.current_cell; + int err; + + err = lte_lc_neighbor_cell_measurement(¶ms); + if (err) + { + return err; + } + + err = k_sem_take(&scan_cellular_sem_ncellmeas_evt, K_FOREVER); + if (err) + { + /* Semaphore was reset so stop search procedure */ + err = 0; + } + + switch (lte_mode) + { + case LTE_LC_LTE_MODE_LTEM: + infos[0].type = GOLIOTH_CELLULAR_TYPE_LTECATM; + break; + case LTE_LC_LTE_MODE_NBIOT: + infos[0].type = GOLIOTH_CELLULAR_TYPE_NBIOT; + break; + default: + *num_returned_infos = 0; + return 0; + } + + infos[0].mcc = current->mcc; + infos[0].mnc = current->mnc; + infos[0].id = current->id; + + *num_returned_infos = 1; + + return 0; +} + +static int cellular_nrf91_init(void) +{ + lte_lc_register_handler(lte_ind_handler); + + return 0; +} + +SYS_INIT(cellular_nrf91_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);