nRF9151 custom board – GNSS sample fails with “Failed to activate GNSS functional mode”

Hi Nordic Team,

I have developed a custom board using the nRF9151 controller.
I am testing the GNSS sample from nRF Connect SDK v3.0.0.
When I flash and run the firmware, I see the following output in RTT Viewer:

Hardware Details:

  • SoC: nRF9151

  • Board: Custom design (based on nRF9151 DK reference)

Software Details:

  • nRF Connect SDK: v3.0.0

  • Toolchain: nRF Connect for VS Code

  • Sample Used: nrf/samples/nrf9160/gnss

  • Build target: nrf9151dk_nrf9151

    How can I solve this issue?


Best regards

Arun

Parents
  • Hi,

    I have tested unmodified sample on nrf9151-dk and I could not replicate reported error.

    Which version of the modem firmware do you use on your custom board?

    Sample Used: nrf/samples/nrf9160/gnss

    The GNSS sample is located in nrf\samples\cellular\gnss in NCS v3.0.0.

    Build target: nrf9151dk_nrf9151

    You can try to build the sample for nrf9151dk/nrf9151/ns as specified in GNSS sample documentation.

    I have developed a custom board using the nRF9151 controller.

     Does the error come when building for nrf9151-dk or for custom board?

    Best regards,
    Dejan

  • Hi Dejan,

    Sorry for the confusion — I’m actually using the nrf/samples/cellular/gnss example from NCS v3.0.0, not nrf/samples/nrf9160/gnss.
    The build target I used is nrf9151dk_nrf9151 ns.

    There were no errors during build or compilation, and I uploaded the firmware to my custom board using the nRF9151 DK as a programmer.

    After uploading, when I open RTT Viewer, I see the following error:

    Could you please advise on what might be causing this issue?

    Best regards,
    Arun

  • Hi Arun,

    Which modem firmware version do you use?

    Best regards,
    Dejan

Reply Children
  • Hi Dejan,

    I’m using modem firmware version 1.3.5 along with NCS v3.0.0.

    Best regards,
    Arun

  • Hi Arun,

    RTT logging is not enabled by default in the project configuration. Have you modified GNSS sample in any way?

    Best regards,
    Dejan

  • Hi Dejan,

    Yes, I’ve added the following configurations in the prj.conf file to enable RTT logging:

    CONFIG_USE_SEGGER_RTT=y
    CONFIG_RTT_CONSOLE=y
    CONFIG_LOG=y
    CONFIG_LOG_BACKEND_RTT=y
    CONFIG_LOG_BACKEND_UART=n
    CONFIG_LOG_MODE_IMMEDIATE=y
    CONFIG_PRINTK=y
    CONFIG_STDOUT_CONSOLE=y

    In the main file, I only added

    #include <zephyr/sys/printk.h>

    Other than that, I haven’t made any modifications to the GNSS sample.

    Best regards,
    Arun

  • Hi Arun,

    Can you try to remove occurrences of printk (from your code and configuration) and leave only logging enabled? What is the result?

    Best regards,
    Dejan

  • Hi Dejan,

    I removed all occurrences of printk from both the project source files and the configuration file, but it’s still showing the same error.

    I’m using the nRF52 DK as a programmer to flash my nRF9151 board.
    I upload the firmware using nRF Connect for Desktop (Programmer tab), and since I can’t see any output in the serial terminal, I’m using J-Link RTT Viewer to monitor the logs.

    I’ve attached my main.c and prj.conf files — could you please check and let me know if anything is missing or needs to be modified?

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <zephyr/kernel.h>
    #include <zephyr/logging/log.h>
    #include <nrf_modem_at.h>
    #include <nrf_modem_gnss.h>
    #include <modem/lte_lc.h>
    #include <modem/nrf_modem_lib.h>
    #include <date_time.h>
    
    
    LOG_MODULE_REGISTER(gnss_sample, CONFIG_GNSS_SAMPLE_LOG_LEVEL);
    
    #define PI 3.14159265358979323846
    #define EARTH_RADIUS_METERS (6371.0 * 1000.0)
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE) || defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    static struct k_work_q gnss_work_q;
    
    #define GNSS_WORKQ_THREAD_STACK_SIZE 2304
    #define GNSS_WORKQ_THREAD_PRIORITY   5
    
    K_THREAD_STACK_DEFINE(gnss_workq_stack_area, GNSS_WORKQ_THREAD_STACK_SIZE);
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE || CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    #include "assistance.h"
    
    static struct nrf_modem_gnss_agnss_data_frame last_agnss;
    static struct k_work agnss_data_get_work;
    static volatile bool requesting_assistance;
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    static struct k_work_delayable ttff_test_got_fix_work;
    static struct k_work_delayable ttff_test_prepare_work;
    static struct k_work ttff_test_start_work;
    static double time_to_fix;
    #endif
    
    static const char update_indicator[] = {'\\', '|', '/', '-'};
    
    static struct nrf_modem_gnss_pvt_data_frame last_pvt;
    static uint64_t fix_timestamp;
    static uint32_t time_blocked;
    
    /* Reference position. */
    static bool ref_used;
    static double ref_latitude;
    static double ref_longitude;
    
    K_MSGQ_DEFINE(nmea_queue, sizeof(struct nrf_modem_gnss_nmea_data_frame *), 10, 4);
    static K_SEM_DEFINE(pvt_data_sem, 0, 1);
    static K_SEM_DEFINE(time_sem, 0, 1);
    
    static struct k_poll_event events[2] = {
    	K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    					K_POLL_MODE_NOTIFY_ONLY,
    					&pvt_data_sem, 0),
    	K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_MSGQ_DATA_AVAILABLE,
    					K_POLL_MODE_NOTIFY_ONLY,
    					&nmea_queue, 0),
    };
    
    BUILD_ASSERT(IS_ENABLED(CONFIG_LTE_NETWORK_MODE_LTE_M_GPS) ||
    	     IS_ENABLED(CONFIG_LTE_NETWORK_MODE_NBIOT_GPS) ||
    	     IS_ENABLED(CONFIG_LTE_NETWORK_MODE_LTE_M_NBIOT_GPS),
    	     "CONFIG_LTE_NETWORK_MODE_LTE_M_GPS, "
    	     "CONFIG_LTE_NETWORK_MODE_NBIOT_GPS or "
    	     "CONFIG_LTE_NETWORK_MODE_LTE_M_NBIOT_GPS must be enabled");
    
    BUILD_ASSERT((sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE) == 1 &&
    	      sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE) == 1) ||
    	     (sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE) > 1 &&
    	      sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE) > 1),
    	     "CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE and "
    	     "CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE must be both either set or empty");
    
    /* Returns the distance between two coordinates in meters. The distance is calculated using the
     * haversine formula.
     */
    static double distance_calculate(double lat1, double lon1,
    				 double lat2, double lon2)
    {
    	double d_lat_rad = (lat2 - lat1) * PI / 180.0;
    	double d_lon_rad = (lon2 - lon1) * PI / 180.0;
    
    	double lat1_rad = lat1 * PI / 180.0;
    	double lat2_rad = lat2 * PI / 180.0;
    
    	double a = pow(sin(d_lat_rad / 2), 2) +
    		   pow(sin(d_lon_rad / 2), 2) *
    		   cos(lat1_rad) * cos(lat2_rad);
    
    	double c = 2 * asin(sqrt(a));
    
    	return EARTH_RADIUS_METERS * c;
    }
    
    static void print_distance_from_reference(struct nrf_modem_gnss_pvt_data_frame *pvt_data)
    {
    	if (!ref_used) {
    		return;
    	}
    
    	double distance = distance_calculate(pvt_data->latitude, pvt_data->longitude,
    					     ref_latitude, ref_longitude);
    
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)) {
    		LOG_INF("Distance from reference: %.01f", distance);
    	} else {
    		printf("\nDistance from reference: %.01f\n", distance);
    	}
    }
    
    static void gnss_event_handler(int event)
    {
    	int retval;
    	struct nrf_modem_gnss_nmea_data_frame *nmea_data;
    
    	switch (event) {
    	case NRF_MODEM_GNSS_EVT_PVT:
    		retval = nrf_modem_gnss_read(&last_pvt, sizeof(last_pvt), NRF_MODEM_GNSS_DATA_PVT);
    		if (retval == 0) {
    			k_sem_give(&pvt_data_sem);
    		}
    		break;
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	case NRF_MODEM_GNSS_EVT_FIX:
    		/* Time to fix is calculated here, but it's printed from a delayed work to avoid
    		 * messing up the NMEA output.
    		 */
    		time_to_fix = (k_uptime_get() - fix_timestamp) / 1000.0;
    		k_work_schedule_for_queue(&gnss_work_q, &ttff_test_got_fix_work, K_MSEC(100));
    		k_work_schedule_for_queue(&gnss_work_q, &ttff_test_prepare_work,
    					  K_SECONDS(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST_INTERVAL));
    		break;
    #endif /* CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    	case NRF_MODEM_GNSS_EVT_NMEA:
    		nmea_data = k_malloc(sizeof(struct nrf_modem_gnss_nmea_data_frame));
    		if (nmea_data == NULL) {
    			LOG_ERR("Failed to allocate memory for NMEA");
    			break;
    		}
    
    		retval = nrf_modem_gnss_read(nmea_data,
    					     sizeof(struct nrf_modem_gnss_nmea_data_frame),
    					     NRF_MODEM_GNSS_DATA_NMEA);
    		if (retval == 0) {
    			retval = k_msgq_put(&nmea_queue, &nmea_data, K_NO_WAIT);
    		}
    
    		if (retval != 0) {
    			k_free(nmea_data);
    		}
    		break;
    
    	case NRF_MODEM_GNSS_EVT_AGNSS_REQ:
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    		retval = nrf_modem_gnss_read(&last_agnss,
    					     sizeof(last_agnss),
    					     NRF_MODEM_GNSS_DATA_AGNSS_REQ);
    		if (retval == 0) {
    			k_work_submit_to_queue(&gnss_work_q, &agnss_data_get_work);
    		}
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    		break;
    
    	default:
    		break;
    	}
    }
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    #if defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    K_SEM_DEFINE(lte_ready, 0, 1);
    
    static void lte_lc_event_handler(const struct lte_lc_evt *const evt)
    {
    	switch (evt->type) {
    	case LTE_LC_EVT_NW_REG_STATUS:
    		if ((evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME) ||
    		    (evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_ROAMING)) {
    			LOG_INF("Connected to LTE network");
    			k_sem_give(&lte_ready);
    		}
    		break;
    
    	default:
    		break;
    	}
    }
    
    void lte_connect(void)
    {
    	int err;
    
    	LOG_INF("Connecting to LTE network");
    
    	err = lte_lc_func_mode_set(LTE_LC_FUNC_MODE_ACTIVATE_LTE);
    	if (err) {
    		LOG_ERR("Failed to activate LTE, error: %d", err);
    		return;
    	}
    
    	k_sem_take(&lte_ready, K_FOREVER);
    
    	/* Wait for a while, because with IPv4v6 PDN the IPv6 activation takes a bit more time. */
    	k_sleep(K_SECONDS(1));
    }
    
    void lte_disconnect(void)
    {
    	int err;
    
    	err = lte_lc_func_mode_set(LTE_LC_FUNC_MODE_DEACTIVATE_LTE);
    	if (err) {
    		LOG_ERR("Failed to deactivate LTE, error: %d", err);
    		return;
    	}
    
    	LOG_INF("LTE disconnected");
    }
    #endif /* CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND */
    
    static const char *get_system_string(uint8_t system_id)
    {
    	switch (system_id) {
    	case NRF_MODEM_GNSS_SYSTEM_INVALID:
    		return "invalid";
    
    	case NRF_MODEM_GNSS_SYSTEM_GPS:
    		return "GPS";
    
    	case NRF_MODEM_GNSS_SYSTEM_QZSS:
    		return "QZSS";
    
    	default:
    		return "unknown";
    	}
    }
    
    static void agnss_data_get_work_fn(struct k_work *item)
    {
    	ARG_UNUSED(item);
    
    	int err;
    
    	/* GPS data need is always expected to be present and first in list. */
    	__ASSERT(last_agnss.system_count > 0,
    		 "GNSS system data need not found");
    	__ASSERT(last_agnss.system[0].system_id == NRF_MODEM_GNSS_SYSTEM_GPS,
    		 "GPS data need not found");
    
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_SUPL)
    	/* SUPL doesn't usually provide NeQuick ionospheric corrections and satellite real time
    	 * integrity information. If GNSS asks only for those, the request should be ignored.
    	 */
    	if (last_agnss.system[0].sv_mask_ephe == 0 &&
    	    last_agnss.system[0].sv_mask_alm == 0 &&
    	    (last_agnss.data_flags & ~(NRF_MODEM_GNSS_AGNSS_NEQUICK_REQUEST |
    				       NRF_MODEM_GNSS_AGNSS_INTEGRITY_REQUEST)) == 0) {
    		LOG_INF("Ignoring assistance request for only NeQuick and/or integrity");
    		return;
    	}
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_SUPL */
    
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_MINIMAL)
    	/* With minimal assistance, the request should be ignored if no GPS time or position
    	 * is requested.
    	 */
    	if (!(last_agnss.data_flags & NRF_MODEM_GNSS_AGNSS_GPS_SYS_TIME_AND_SV_TOW_REQUEST) &&
    	    !(last_agnss.data_flags & NRF_MODEM_GNSS_AGNSS_POSITION_REQUEST)) {
    		LOG_INF("Ignoring assistance request because no GPS time or position is requested");
    		return;
    	}
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_MINIMAL */
    
    	if (last_agnss.data_flags == 0 &&
    	    last_agnss.system[0].sv_mask_ephe == 0 &&
    	    last_agnss.system[0].sv_mask_alm == 0) {
    		LOG_INF("Ignoring assistance request because only QZSS data is requested");
    		return;
    	}
    
    	requesting_assistance = true;
    
    	LOG_INF("Assistance data needed: data_flags: 0x%02x", last_agnss.data_flags);
    	for (int i = 0; i < last_agnss.system_count; i++) {
    		LOG_INF("Assistance data needed: %s ephe: 0x%llx, alm: 0x%llx",
    			get_system_string(last_agnss.system[i].system_id),
    			last_agnss.system[i].sv_mask_ephe,
    			last_agnss.system[i].sv_mask_alm);
    	}
    
    #if defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    	lte_connect();
    #endif /* CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND */
    
    	err = assistance_request(&last_agnss);
    	if (err) {
    		LOG_ERR("Failed to request assistance data");
    	}
    
    #if defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    	lte_disconnect();
    #endif /* CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND */
    
    	requesting_assistance = false;
    }
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    static void ttff_test_got_fix_work_fn(struct k_work *item)
    {
    	LOG_INF("Time to fix: %.01f s", time_to_fix);
    	if (time_blocked > 0) {
    		LOG_INF("Time GNSS was blocked by LTE: %u s", time_blocked);
    	}
    	print_distance_from_reference(&last_pvt);
    	LOG_INF("Sleeping for %u s", CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST_INTERVAL);
    }
    
    static int ttff_test_force_cold_start(void)
    {
    	int err;
    	uint32_t delete_mask;
    
    	LOG_INF("Deleting GNSS data");
    
    	/* Delete everything else except the TCXO offset. */
    	delete_mask = NRF_MODEM_GNSS_DELETE_EPHEMERIDES |
    		      NRF_MODEM_GNSS_DELETE_ALMANACS |
    		      NRF_MODEM_GNSS_DELETE_IONO_CORRECTION_DATA |
    		      NRF_MODEM_GNSS_DELETE_LAST_GOOD_FIX |
    		      NRF_MODEM_GNSS_DELETE_GPS_TOW |
    		      NRF_MODEM_GNSS_DELETE_GPS_WEEK |
    		      NRF_MODEM_GNSS_DELETE_UTC_DATA |
    		      NRF_MODEM_GNSS_DELETE_GPS_TOW_PRECISION;
    
    	/* With minimal assistance, we want to keep the factory almanac. */
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_ASSISTANCE_MINIMAL)) {
    		delete_mask &= ~NRF_MODEM_GNSS_DELETE_ALMANACS;
    	}
    
    	err = nrf_modem_gnss_nv_data_delete(delete_mask);
    	if (err) {
    		LOG_ERR("Failed to delete GNSS data");
    		return -1;
    	}
    
    	return 0;
    }
    
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD)
    static bool qzss_assistance_is_supported(void)
    {
    	char resp[32];
    
    	if (nrf_modem_at_cmd(resp, sizeof(resp), "AT+CGMM") == 0) {
    		/* nRF9160 does not support QZSS assistance, while nRF91x1 do. */
    		if (strstr(resp, "nRF9160") != NULL) {
    			return false;
    		}
    	}
    
    	return true;
    }
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD */
    
    static void ttff_test_prepare_work_fn(struct k_work *item)
    {
    	/* Make sure GNSS is stopped before next start. */
    	nrf_modem_gnss_stop();
    
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST_COLD_START)) {
    		if (ttff_test_force_cold_start() != 0) {
    			return;
    		}
    	}
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST_COLD_START)) {
    		/* All A-GNSS data is always requested before GNSS is started. */
    		last_agnss.data_flags =
    			NRF_MODEM_GNSS_AGNSS_GPS_UTC_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_KLOBUCHAR_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_NEQUICK_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_GPS_SYS_TIME_AND_SV_TOW_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_POSITION_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_INTEGRITY_REQUEST;
    		last_agnss.system_count = 1;
    		last_agnss.system[0].sv_mask_ephe = 0xffffffff;
    		last_agnss.system[0].sv_mask_alm = 0xffffffff;
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD)
    		if (qzss_assistance_is_supported()) {
    			last_agnss.system_count = 2;
    			last_agnss.system[1].sv_mask_ephe = 0x3ff;
    			last_agnss.system[1].sv_mask_alm = 0x3ff;
    		}
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD */
    
    		k_work_submit_to_queue(&gnss_work_q, &agnss_data_get_work);
    	} else {
    		/* Start and stop GNSS to trigger possible A-GNSS data request. If new A-GNSS
    		 * data is needed it is fetched before GNSS is started.
    		 */
    		nrf_modem_gnss_start();
    		nrf_modem_gnss_stop();
    	}
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    
    	k_work_submit_to_queue(&gnss_work_q, &ttff_test_start_work);
    }
    
    static void ttff_test_start_work_fn(struct k_work *item)
    {
    	LOG_INF("Starting GNSS");
    	if (nrf_modem_gnss_start() != 0) {
    		LOG_ERR("Failed to start GNSS");
    		return;
    	}
    
    	fix_timestamp = k_uptime_get();
    	time_blocked = 0;
    }
    #endif /* CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    static void date_time_evt_handler(const struct date_time_evt *evt)
    {
    	k_sem_give(&time_sem);
    }
    
    static int modem_init(void)
    {
    	if (IS_ENABLED(CONFIG_DATE_TIME)) {
    		date_time_register_handler(date_time_evt_handler);
    	}
    
    #if defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    	lte_lc_register_handler(lte_lc_event_handler);
    #elif !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    	lte_lc_psm_req(true);
    
    	LOG_INF("Connecting to LTE network");
    
    	if (lte_lc_connect() != 0) {
    		LOG_ERR("Failed to connect to LTE network");
    		return -1;
    	}
    
    	LOG_INF("Connected to LTE network");
    
    	if (IS_ENABLED(CONFIG_DATE_TIME)) {
    		LOG_INF("Waiting for current time");
    
    		/* Wait for an event from the Date Time library. */
    		k_sem_take(&time_sem, K_MINUTES(10));
    
    		if (!date_time_is_valid()) {
    			LOG_WRN("Failed to get current time, continuing anyway");
    		}
    	}
    #endif
    
    	return 0;
    }
    
    static int sample_init(void)
    {
    	int err = 0;
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE) || defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	struct k_work_queue_config cfg = {
    		.name = "gnss_work_q",
    		.no_yield = false
    	};
    
    	k_work_queue_start(
    		&gnss_work_q,
    		gnss_workq_stack_area,
    		K_THREAD_STACK_SIZEOF(gnss_workq_stack_area),
    		GNSS_WORKQ_THREAD_PRIORITY,
    		&cfg);
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE || CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    	k_work_init(&agnss_data_get_work, agnss_data_get_work_fn);
    
    	err = assistance_init(&gnss_work_q);
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	k_work_init_delayable(&ttff_test_got_fix_work, ttff_test_got_fix_work_fn);
    	k_work_init_delayable(&ttff_test_prepare_work, ttff_test_prepare_work_fn);
    	k_work_init(&ttff_test_start_work, ttff_test_start_work_fn);
    #endif /* CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    	return err;
    }
    
    static int gnss_init_and_start(void)
    {
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE) || defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    	/* Enable GNSS. */
    	if (lte_lc_func_mode_set(LTE_LC_FUNC_MODE_ACTIVATE_GNSS) != 0) {
    		LOG_ERR("Failed to activate GNSS functional mode");
    		return -1;
    	}
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE || CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND */
    
    	/* Configure GNSS. */
    	if (nrf_modem_gnss_event_handler_set(gnss_event_handler) != 0) {
    		LOG_ERR("Failed to set GNSS event handler");
    		return -1;
    	}
    
    	/* Enable all supported NMEA messages. */
    	uint16_t nmea_mask = NRF_MODEM_GNSS_NMEA_RMC_MASK |
    			     NRF_MODEM_GNSS_NMEA_GGA_MASK |
    			     NRF_MODEM_GNSS_NMEA_GLL_MASK |
    			     NRF_MODEM_GNSS_NMEA_GSA_MASK |
    			     NRF_MODEM_GNSS_NMEA_GSV_MASK;
    
    	if (nrf_modem_gnss_nmea_mask_set(nmea_mask) != 0) {
    		LOG_ERR("Failed to set GNSS NMEA mask");
    		return -1;
    	}
    
    	/* Make QZSS satellites visible in the NMEA output. */
    	if (nrf_modem_gnss_qzss_nmea_mode_set(NRF_MODEM_GNSS_QZSS_NMEA_MODE_CUSTOM) != 0) {
    		LOG_WRN("Failed to enable custom QZSS NMEA mode");
    	}
    
    	/* This use case flag should always be set. */
    	uint8_t use_case = NRF_MODEM_GNSS_USE_CASE_MULTIPLE_HOT_START;
    
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_PERIODIC) &&
    	    !IS_ENABLED(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)) {
    		/* Disable GNSS scheduled downloads when assistance is used. */
    		use_case |= NRF_MODEM_GNSS_USE_CASE_SCHED_DOWNLOAD_DISABLE;
    	}
    
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_LOW_ACCURACY)) {
    		use_case |= NRF_MODEM_GNSS_USE_CASE_LOW_ACCURACY;
    	}
    
    	if (nrf_modem_gnss_use_case_set(use_case) != 0) {
    		LOG_WRN("Failed to set GNSS use case");
    	}
    
    #if defined(CONFIG_NRF_CLOUD_AGNSS_ELEVATION_MASK)
    	if (nrf_modem_gnss_elevation_threshold_set(CONFIG_NRF_CLOUD_AGNSS_ELEVATION_MASK) != 0) {
    		LOG_ERR("Failed to set elevation threshold");
    		return -1;
    	}
    	LOG_DBG("Set elevation threshold to %u", CONFIG_NRF_CLOUD_AGNSS_ELEVATION_MASK);
    #endif
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_CONTINUOUS)
    	/* Default to no power saving. */
    	uint8_t power_mode = NRF_MODEM_GNSS_PSM_DISABLED;
    
    #if defined(CONFIG_GNSS_SAMPLE_POWER_SAVING_MODERATE)
    	power_mode = NRF_MODEM_GNSS_PSM_DUTY_CYCLING_PERFORMANCE;
    #elif defined(CONFIG_GNSS_SAMPLE_POWER_SAVING_HIGH)
    	power_mode = NRF_MODEM_GNSS_PSM_DUTY_CYCLING_POWER;
    #endif
    
    	if (nrf_modem_gnss_power_mode_set(power_mode) != 0) {
    		LOG_ERR("Failed to set GNSS power saving mode");
    		return -1;
    	}
    #endif /* CONFIG_GNSS_SAMPLE_MODE_CONTINUOUS */
    
    	/* Default to continuous tracking. */
    	uint16_t fix_retry = 0;
    	uint16_t fix_interval = 1;
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_PERIODIC)
    	fix_retry = CONFIG_GNSS_SAMPLE_PERIODIC_TIMEOUT;
    	fix_interval = CONFIG_GNSS_SAMPLE_PERIODIC_INTERVAL;
    #elif defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	/* Single fix for TTFF test mode. */
    	fix_retry = 0;
    	fix_interval = 0;
    #endif
    
    	if (nrf_modem_gnss_fix_retry_set(fix_retry) != 0) {
    		LOG_ERR("Failed to set GNSS fix retry");
    		return -1;
    	}
    
    	if (nrf_modem_gnss_fix_interval_set(fix_interval) != 0) {
    		LOG_ERR("Failed to set GNSS fix interval");
    		return -1;
    	}
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	k_work_schedule_for_queue(&gnss_work_q, &ttff_test_prepare_work, K_NO_WAIT);
    #else /* !CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    	if (nrf_modem_gnss_start() != 0) {
    		LOG_ERR("Failed to start GNSS");
    		return -1;
    	}
    #endif
    
    	return 0;
    }
    
    static bool output_paused(void)
    {
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE) || defined(CONFIG_GNSS_SAMPLE_LOG_LEVEL_OFF)
    	return false;
    #else
    	return (requesting_assistance || assistance_is_active()) ? true : false;
    #endif
    }
    
    static void print_satellite_stats(struct nrf_modem_gnss_pvt_data_frame *pvt_data)
    {
    	uint8_t tracked   = 0;
    	uint8_t in_fix    = 0;
    	uint8_t unhealthy = 0;
    
    	for (int i = 0; i < NRF_MODEM_GNSS_MAX_SATELLITES; ++i) {
    		if (pvt_data->sv[i].sv > 0) {
    			tracked++;
    
    			if (pvt_data->sv[i].flags & NRF_MODEM_GNSS_SV_FLAG_USED_IN_FIX) {
    				in_fix++;
    			}
    
    			if (pvt_data->sv[i].flags & NRF_MODEM_GNSS_SV_FLAG_UNHEALTHY) {
    				unhealthy++;
    			}
    		}
    	}
    
    	printf("Tracking: %2d Using: %2d Unhealthy: %d\n", tracked, in_fix, unhealthy);
    }
    
    static void print_flags(struct nrf_modem_gnss_pvt_data_frame *pvt_data)
    {
    	if (pvt_data->flags & NRF_MODEM_GNSS_PVT_FLAG_DEADLINE_MISSED) {
    		printf("GNSS operation blocked by LTE\n");
    	}
    	if (pvt_data->flags & NRF_MODEM_GNSS_PVT_FLAG_NOT_ENOUGH_WINDOW_TIME) {
    		printf("Insufficient GNSS time windows\n");
    	}
    	if (pvt_data->flags & NRF_MODEM_GNSS_PVT_FLAG_SLEEP_BETWEEN_PVT) {
    		printf("Sleep period(s) between PVT notifications\n");
    	}
    	if (pvt_data->flags & NRF_MODEM_GNSS_PVT_FLAG_SCHED_DOWNLOAD) {
    		printf("Scheduled navigation data download\n");
    	}
    }
    
    static void print_fix_data(struct nrf_modem_gnss_pvt_data_frame *pvt_data)
    {
    	printf("Latitude:          %.06f\n", pvt_data->latitude);
    	printf("Longitude:         %.06f\n", pvt_data->longitude);
    	printf("Accuracy:          %.01f m\n", (double)pvt_data->accuracy);
    	printf("Altitude:          %.01f m\n", (double)pvt_data->altitude);
    	printf("Altitude accuracy: %.01f m\n", (double)pvt_data->altitude_accuracy);
    	printf("Speed:             %.01f m/s\n", (double)pvt_data->speed);
    	printf("Speed accuracy:    %.01f m/s\n", (double)pvt_data->speed_accuracy);
    	printf("V. speed:          %.01f m/s\n", (double)pvt_data->vertical_speed);
    	printf("V. speed accuracy: %.01f m/s\n", (double)pvt_data->vertical_speed_accuracy);
    	printf("Heading:           %.01f deg\n", (double)pvt_data->heading);
    	printf("Heading accuracy:  %.01f deg\n", (double)pvt_data->heading_accuracy);
    	printf("Date:              %04u-%02u-%02u\n",
    	       pvt_data->datetime.year,
    	       pvt_data->datetime.month,
    	       pvt_data->datetime.day);
    	printf("Time (UTC):        %02u:%02u:%02u.%03u\n",
    	       pvt_data->datetime.hour,
    	       pvt_data->datetime.minute,
    	       pvt_data->datetime.seconds,
    	       pvt_data->datetime.ms);
    // 	printf("PDOP:              %.01f\n", (double)pvt_data->pdop);
    // 	printf("HDOP:              %.01f\n", (double)pvt_data->hdop);
    // 	printf("VDOP:              %.01f\n", (double)pvt_data->vdop);
    // 	printf("TDOP:              %.01f\n", (double)pvt_data->tdop);
     }
    
    int main(void)
    {
    	int err;
    	uint8_t cnt = 0;
    	struct nrf_modem_gnss_nmea_data_frame *nmea_data;
    
    	LOG_INF("Starting GNSS sample");
    
    	err = nrf_modem_lib_init();
    	if (err) {
    		LOG_ERR("Modem library initialization failed, error: %d", err);
    		return err;
    	}
    
    	/* Initialize reference coordinates (if used). */
    	if (sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE) > 1 &&
    	    sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE) > 1) {
    		ref_used = true;
    		ref_latitude = atof(CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE);
    		ref_longitude = atof(CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE);
    	}
    
    	if (modem_init() != 0) {
    		LOG_ERR("Failed to initialize modem");
    		return -1;
    	}
    
    	if (sample_init() != 0) {
    		LOG_ERR("Failed to initialize sample");
    		return -1;
    	}
    
    	if (gnss_init_and_start() != 0) {
    		LOG_ERR("Failed to initialize and start GNSS");
    		return -1;
    	}
    
    	fix_timestamp = k_uptime_get();
    
    	for (;;) {
    		(void)k_poll(events, 2, K_FOREVER);
    
    		if (events[0].state == K_POLL_STATE_SEM_AVAILABLE &&
    		    k_sem_take(events[0].sem, K_NO_WAIT) == 0) {
    			/* New PVT data available */
    
    			if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)) {
    				/* TTFF test mode. */
    
    				/* Calculate the time GNSS has been blocked by LTE. */
    				if (last_pvt.flags & NRF_MODEM_GNSS_PVT_FLAG_DEADLINE_MISSED) {
    					time_blocked++;
    				}
    			} else if (IS_ENABLED(CONFIG_GNSS_SAMPLE_NMEA_ONLY)) {
    				/* NMEA-only output mode. */
    
    				if (output_paused()) {
    					goto handle_nmea;
    				}
    
    				if (last_pvt.flags & NRF_MODEM_GNSS_PVT_FLAG_FIX_VALID) {
    					print_distance_from_reference(&last_pvt);
    				}
    			} else {
    				/* PVT and NMEA output mode. */
    
    				if (output_paused()) {
    					goto handle_nmea;
    				}
    
    				printf("\033[1;1H");
    				printf("\033[2J");
    				print_satellite_stats(&last_pvt);
    				print_flags(&last_pvt);
    				printf("-----------------------------------\n");
    
    				if (last_pvt.flags & NRF_MODEM_GNSS_PVT_FLAG_FIX_VALID) {
    					fix_timestamp = k_uptime_get();
    					print_fix_data(&last_pvt);
    					print_distance_from_reference(&last_pvt);
    				} else {
    					printf("Seconds since last fix: %d\n",
    					       (uint32_t)((k_uptime_get() - fix_timestamp) / 1000));
    					cnt++;
    					printf("Searching [%c]\n", update_indicator[cnt%4]);
    				}
    
    				printf("\nNMEA strings:\n\n");
    			}
    		}
    
    handle_nmea:
    		if (events[1].state == K_POLL_STATE_MSGQ_DATA_AVAILABLE &&
    		    k_msgq_get(events[1].msgq, &nmea_data, K_NO_WAIT) == 0) {
    			/* New NMEA data available */
    
    			if (!output_paused()) {
    				printf("%s", nmea_data->nmea_str);
    			}
    			k_free(nmea_data);
    		}
    
    		events[0].state = K_POLL_STATE_NOT_READY;
    		events[1].state = K_POLL_STATE_NOT_READY;
    	}
    
    	return 0;
    }
    

    #
    # Copyright (c) 2019 Nordic Semiconductor ASA
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
    # Enable RTT Console and Logging
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_RTT_CONSOLE=y
    CONFIG_LOG_BACKEND_RTT=y
    CONFIG_LOG_BACKEND_UART=n
    
    # General
    CONFIG_FPU=y
    CONFIG_NRF_MODEM_LIB=y
    CONFIG_STDOUT_CONSOLE=y
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_PICOLIBC_IO_FLOAT=y
    CONFIG_LOG=y
    CONFIG_LOG_MODE_IMMEDIATE=y
    
    # GNSS sample
    # Enable to use nRF Cloud A-GNSS
    CONFIG_NRF_CLOUD=y
    CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD=n
    
    # LTE Link Control
    CONFIG_LTE_LINK_CONTROL=y
    # Request eDRX from the network
    CONFIG_LTE_LC_EDRX_MODULE=y
    CONFIG_LTE_EDRX_REQ=y
    # PSM requested periodic TAU 8 hours
    CONFIG_LTE_LC_PSM_MODULE=y
    CONFIG_LTE_PSM_REQ_RPTAU="00101000"
    # PSM requested active time 6 seconds
    CONFIG_LTE_PSM_REQ_RAT="00000011"
    
    # AT Host library - Used to send AT commands directy from an UART terminal and to allow
    #		    integration with nRF Connect for Desktop LTE Link monitor application.
    CONFIG_AT_HOST_LIBRARY=y
    
    # Networking
    CONFIG_NETWORKING=y
    CONFIG_NET_SOCKETS_OFFLOAD=y
    CONFIG_NET_SOCKETS=y
    CONFIG_POSIX_API=y
    # Disable native network stack to save some memory
    CONFIG_NET_NATIVE=n
    
    # Memory and stack configuration
    CONFIG_HEAP_MEM_POOL_SIZE=2048
    CONFIG_MAIN_STACK_SIZE=4096
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1536
    

    Best regards,
    Arun

Related