This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Modem errors when combining HTTPS and GPS

Hi,

After building and testing separate HTPS and GPS examples, I am getting modem errors when combining both projects into one application. One of our goals is to send GPS data over HTTPS to our server, and I have successfully gotten these examples to work individually, but now receive these errors when combining into one.

I am not sure if my prj,conf file is wrong, or if there was a step I missed when combining the applications, but I am wondering if someone can take a look at my project and see if there are any errors I missed or if there are certain issues with combining HTTPS and GPS

#include "https.h"

char prod_num[] = "200001-A";
char serial_num[] = "10000001";
char tok[] = "5e9564ab-7ac4-4b26-8e5f-8222cdcdcf24";
char firmware_tok[] = "e4828545-0c1b-429c-a932-f355de7a6307";
char postData[SEND_BUFF_SIZE];
char postGPSData[SEND_BUFF_SIZE];

/*
 * Copyright (c) 2019 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
 */


#ifdef CONFIG_SUPL_CLIENT_LIB
#include <supl_os_client.h>
#include <supl_session.h>
#include "supl_support.h"
#endif

#define AT_XSYSTEMMODE      "AT\%XSYSTEMMODE=1,0,1,0"
#define AT_ACTIVATE_GPS     "AT+CFUN=31"
#define AT_ACTIVATE_LTE     "AT+CFUN=21"
#define AT_DEACTIVATE_LTE   "AT+CFUN=20"
#define AT_COEX0            "AT\%XCOEX0"
#define GNSS_INIT_AND_START 1
#define GNSS_STOP           2
#define GNSS_RESTART        3

#define AT_CMD_SIZE(x) (sizeof(x) - 1)

#ifdef CONFIG_BOARD_NRF9160DK_NRF9160NS
#define AT_MAGPIO      "AT\%XMAGPIO=1,0,0,1,1,1574,1577"
#ifdef CONFIG_GPS_SAMPLE_ANTENNA_ONBOARD
#define AT_COEX0       "AT\%XCOEX0=1,1,1565,1586"
#elif CONFIG_GPS_SAMPLE_ANTENNA_EXTERNAL
#define AT_COEX0       "AT\%XCOEX0"
#endif
#endif /* CONFIG_BOARD_NRF9160DK_NRF9160NS */

#ifdef CONFIG_BOARD_THINGY91_NRF9160NS
#define AT_MAGPIO      "AT\%XMAGPIO=1,1,1,7,1,746,803,2,698,748,2,1710,2200," \
			"3,824,894,4,880,960,5,791,849,7,1565,1586"
#ifdef CONFIG_GPS_SAMPLE_ANTENNA_ONBOARD
#define AT_COEX0       "AT\%XCOEX0=1,1,1565,1586"
#elif CONFIG_GPS_SAMPLE_ANTENNA_EXTERNAL
#define AT_COEX0       "AT\%XCOEX0"
#endif
#endif /* CONFIG_BOARD_THINGY91_NRF9160NS */

static const char update_indicator[] = {'\\', '|', '/', '-'};
static const char *const at_commands[] = {
	AT_XSYSTEMMODE,
#if defined(CONFIG_BOARD_NRF9160DK_NRF9160NS) || \
	defined(CONFIG_BOARD_THINGY91_NRF9160NS)
	AT_MAGPIO,
	AT_COEX0,
#endif
	AT_ACTIVATE_GPS
};

static int                   gnss_fd;
static char                  nmea_strings[10][NRF_GNSS_NMEA_MAX_LEN];
static uint32_t                 nmea_string_cnt;

static bool                  got_fix;
static uint64_t                 fix_timestamp;
static nrf_gnss_data_frame_t last_pvt;

K_SEM_DEFINE(lte_ready, 0, 1);

void bsd_recoverable_error_handler(uint32_t error)
{
	printf("Err: %lu\n", (unsigned long)error);
}

static int setup_modem(void)
{
	for (int i = 0; i < ARRAY_SIZE(at_commands); i++) {
      
		if (at_cmd_write(at_commands[i], NULL, 0, NULL) != 0) {
                        printk("Failed Command: %s\n", at_commands[i]);
			return -1;
		}
	}

	return 0;
}

#ifdef CONFIG_SUPL_CLIENT_LIB
/* Accepted network statuses read from modem */
static const char status1[] = "+CEREG: 1";
static const char status2[] = "+CEREG:1";
static const char status3[] = "+CEREG: 5";
static const char status4[] = "+CEREG:5";

static void wait_for_lte(void *context, const char *response)
{
	if (!memcmp(status1, response, AT_CMD_SIZE(status1)) ||
		!memcmp(status2, response, AT_CMD_SIZE(status2)) ||
		!memcmp(status3, response, AT_CMD_SIZE(status3)) ||
		!memcmp(status4, response, AT_CMD_SIZE(status4))) {
		k_sem_give(&lte_ready);
	}
}

static int activate_lte(bool activate)
{
	if (activate) {
		if (at_cmd_write(AT_ACTIVATE_LTE, NULL, 0, NULL) != 0) {
			return -1;
		}

		at_notif_register_handler(NULL, wait_for_lte);
		if (at_cmd_write("AT+CEREG=2", NULL, 0, NULL) != 0) {
			return -1;
		}

		k_sem_take(&lte_ready, K_FOREVER);

		at_notif_deregister_handler(NULL, wait_for_lte);
		if (at_cmd_write("AT+CEREG=0", NULL, 0, NULL) != 0) {
			return -1;
		}
	} else {
		if (at_cmd_write(AT_DEACTIVATE_LTE, NULL, 0, NULL) != 0) {
			return -1;
		}
	}

	return 0;
}
#endif

static int gnss_ctrl(uint32_t ctrl)
{
	int retval;

	nrf_gnss_fix_retry_t    fix_retry    = 0;
	nrf_gnss_fix_interval_t fix_interval = 1;
	nrf_gnss_delete_mask_t	delete_mask  = 0;
	nrf_gnss_nmea_mask_t	nmea_mask    = NRF_GNSS_NMEA_GSV_MASK |
					       NRF_GNSS_NMEA_GSA_MASK |
					       NRF_GNSS_NMEA_GLL_MASK |
					       NRF_GNSS_NMEA_GGA_MASK |
					       NRF_GNSS_NMEA_RMC_MASK;

	if (ctrl == GNSS_INIT_AND_START) {
		gnss_fd = nrf_socket(NRF_AF_LOCAL,
				     NRF_SOCK_DGRAM,
				     NRF_PROTO_GNSS);

		if (gnss_fd >= 0) {
			printk("GPS Socket created\n");
		} else {
			printk("Could not init socket (err: %d)\n", gnss_fd);
			return -1;
		}

		retval = nrf_setsockopt(gnss_fd,
					NRF_SOL_GNSS,
					NRF_SO_GNSS_FIX_RETRY,
					&fix_retry,
					sizeof(fix_retry));
		if (retval != 0) {
			printk("Failed to set fix retry value\n");
			return -1;
		}

		retval = nrf_setsockopt(gnss_fd,
					NRF_SOL_GNSS,
					NRF_SO_GNSS_FIX_INTERVAL,
					&fix_interval,
					sizeof(fix_interval));
		if (retval != 0) {
			printk("Failed to set fix interval value\n");
			return -1;
		}

		retval = nrf_setsockopt(gnss_fd,
					NRF_SOL_GNSS,
					NRF_SO_GNSS_NMEA_MASK,
					&nmea_mask,
					sizeof(nmea_mask));
		if (retval != 0) {
			printk("Failed to set nmea mask\n");
			return -1;
		}
	}

	if ((ctrl == GNSS_INIT_AND_START) ||
	    (ctrl == GNSS_RESTART)) {
		retval = nrf_setsockopt(gnss_fd,
					NRF_SOL_GNSS,
					NRF_SO_GNSS_START,
					&delete_mask,
					sizeof(delete_mask));
		if (retval != 0) {
			printk("Failed to start GPS\n");
			return -1;
		}
	}

	if (ctrl == GNSS_STOP) {
		retval = nrf_setsockopt(gnss_fd,
					NRF_SOL_GNSS,
					NRF_SO_GNSS_STOP,
					&delete_mask,
					sizeof(delete_mask));
		if (retval != 0) {
			printk("Failed to stop GPS\n");
			return -1;
		}
	}

	return 0;
}

static int init_app(void)
{
	int retval;

	if (setup_modem() != 0) {
		printk("Failed to initialize modem\n");
		return -1;
	}

	retval = gnss_ctrl(GNSS_INIT_AND_START);

	return retval;
}

static void print_satellite_stats(nrf_gnss_data_frame_t *pvt_data)
{
	uint8_t  tracked          = 0;
	uint8_t  in_fix           = 0;
	uint8_t  unhealthy        = 0;

	for (int i = 0; i < NRF_GNSS_MAX_SATELLITES; ++i) {

		if ((pvt_data->pvt.sv[i].sv > 0) &&
		    (pvt_data->pvt.sv[i].sv < 33)) {

			tracked++;

			if (pvt_data->pvt.sv[i].flags &
					NRF_GNSS_SV_FLAG_USED_IN_FIX) {
				in_fix++;
			}

			if (pvt_data->pvt.sv[i].flags &
					NRF_GNSS_SV_FLAG_UNHEALTHY) {
				unhealthy++;
			}
		}
	}

	printk("Tracking: %d Using: %d Unhealthy: %d\n", tracked,
							 in_fix,
							 unhealthy);
}

static void print_gnss_stats(nrf_gnss_data_frame_t *pvt_data)
{
	if (pvt_data->pvt.flags & NRF_GNSS_PVT_FLAG_DEADLINE_MISSED) {
		printk("GNSS notification deadline missed\n");
	}
	if (pvt_data->pvt.flags & NRF_GNSS_PVT_FLAG_NOT_ENOUGH_WINDOW_TIME) {
		printk("GNSS operation blocked by insufficient time windows\n");
	}
}

static void print_fix_data(nrf_gnss_data_frame_t *pvt_data)
{
	printf("Longitude:  %f\n", pvt_data->pvt.longitude);
	printf("Latitude:   %f\n", pvt_data->pvt.latitude);
	printf("Altitude:   %f\n", pvt_data->pvt.altitude);
	printf("Speed:      %f\n", pvt_data->pvt.speed);
	printf("Heading:    %f\n", pvt_data->pvt.heading);
	printk("Date:       %02u-%02u-%02u\n", pvt_data->pvt.datetime.day,
					       pvt_data->pvt.datetime.month,
					       pvt_data->pvt.datetime.year);
	printk("Time (UTC): %02u:%02u:%02u\n", pvt_data->pvt.datetime.hour,
					       pvt_data->pvt.datetime.minute,
					      pvt_data->pvt.datetime.seconds);
}

static void print_nmea_data(void)
{
	for (int i = 0; i < nmea_string_cnt; ++i) {
		printk("%s", nmea_strings[i]);
	}
}

int process_gps_data(nrf_gnss_data_frame_t *gps_data)
{
	int retval;

	retval = nrf_recv(gnss_fd,
			  gps_data,
			  sizeof(nrf_gnss_data_frame_t),
			  NRF_MSG_DONTWAIT);

	if (retval > 0) {

		switch (gps_data->data_id) {
		case NRF_GNSS_PVT_DATA_ID:
			memcpy(&last_pvt,
			       gps_data,
			       sizeof(nrf_gnss_data_frame_t));
			nmea_string_cnt = 0;
			got_fix = false;

			if ((gps_data->pvt.flags &
				NRF_GNSS_PVT_FLAG_FIX_VALID_BIT)
				== NRF_GNSS_PVT_FLAG_FIX_VALID_BIT) {

				got_fix = true;
				fix_timestamp = k_uptime_get();
			}
			break;

		case NRF_GNSS_NMEA_DATA_ID:
			if (nmea_string_cnt < 10) {
				memcpy(nmea_strings[nmea_string_cnt++],
				       gps_data->nmea,
				       retval);
			}
			break;

		case NRF_GNSS_AGPS_DATA_ID:
#ifdef CONFIG_SUPL_CLIENT_LIB
			printk("\033[1;1H");
			printk("\033[2J");
			printk("New AGPS data requested, contacting SUPL server, flags %d\n",
			       gps_data->agps.data_flags);
			gnss_ctrl(GNSS_STOP);
			activate_lte(true);
			printk("Established LTE link\n");
			if (open_supl_socket() == 0) {
				printf("Starting SUPL session\n");
				supl_session(&gps_data->agps);
				printk("Done\n");
				close_supl_socket();
			}
			activate_lte(false);
			gnss_ctrl(GNSS_RESTART);
			k_sleep(K_MSEC(2000));
#endif
			break;

		default:
			break;
		}
	}

	return retval;
}

#ifdef CONFIG_SUPL_CLIENT_LIB
int inject_agps_type(void *agps,
		     size_t agps_size,
		     nrf_gnss_agps_data_type_t type,
		     void *user_data)
{
	ARG_UNUSED(user_data);
	int retval = nrf_sendto(gnss_fd,
				agps,
				agps_size,
				0,
				&type,
				sizeof(type));

	if (retval != 0) {
		printk("Failed to send AGNSS data, type: %d (err: %d)\n",
		       type,
		       errno);
		return -1;
	}

	printk("Injected AGPS data, flags: %d, size: %d\n", type, agps_size);

	return 0;
}
#endif



//static const struct spi_config spi_cfg = {
//	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB |
//		     SPI_MODE_CPOL | SPI_MODE_CPHA,
//	.frequency = 4000000,
//	.slave = 0,
//};
//
//struct device *spi_dev;
//struct device *i2c;
//
//static void spi_init(void)
//{
//    const char* const spiName = "SPI_3";
//    spi_dev = device_get_binding(spiName);
//
//    if (spi_dev == NULL) {
//        printk("Could not get %s device\n", spiName);
//        return;
//    }
//}


int main()
{
        int err;
        bool hasData = false;
        nrf_gnss_data_frame_t gps_data;
	uint8_t cnt = 0;
        memset(&postData, 0, sizeof(postData));

	err = bsdlib_init();
	if (err)
	{
		printk("Failed to initialize bsdlib!");
		return;
	}

	/* Initialize AT comms in order to provision the certificate */
	err = at_comms_init();
	if (err)
	{
		return;
	}

	printk("Waiting for network.. \n");
	err = lte_lc_init_and_connect();
	if (err)
	{
		printk("Failed to connect to the LTE network, err %d\n", err);
		return;
	}
	printk("Connected to LTE Network\n");


        printk("Starting GPS application\n");

	if (init_app() != 0) {
		return -1;
	}
        
        printk("Getting GPS data...\n");

        
	while (!hasData) {

		do {
			/* Loop until we don't have more
			 * data to read
			 */
		} while (process_gps_data(&gps_data) > 0);

		if (IS_ENABLED(CONFIG_GPS_SAMPLE_NMEA_ONLY)) {
			print_nmea_data();
			nmea_string_cnt = 0;
		} else {
			printk("\033[1;1H");
			printk("\033[2J");
			print_satellite_stats(&last_pvt);
			print_gnss_stats(&last_pvt);
			printk("---------------------------------\n");

			if (!got_fix) {
				printk("Seconds since last fix: %lld\n",
				       (k_uptime_get() - fix_timestamp) / 1000);
				cnt++;
				printk("Searching [%c]\n",
				       update_indicator[cnt%4]);
			} else {
				print_fix_data(&last_pvt);
                                printk("Fixed data receieved. Exiting loop\n");
                                hasData = true;
			}

			printk("\nNMEA strings:\n\n");
			print_nmea_data();
			printk("---------------------------------");
		}

		k_sleep(K_MSEC(500));
	}

        sprintf(postGPSData, "{\"product_number\": \"%s\",\"serial_number\": \"%s\",\"token\": \"%s\",\"timestamp\": \"xxxx-xx-xx xx:xx:xx\", \"device_data\": [{\"al\": %f}, {\"ak\": %f}]}", prod_num, serial_num, tok, last_pvt.pvt.longitude, last_pvt.pvt.latitude);

	printk("HTTPS client sample started\n\r");
        sprintf(postData, "{\"product_number\": \"%s\",\"serial_number\": \"%s\",\"token\": \"%s\",\"firmware_token\": \"%s\"}", prod_num, serial_num, tok, firmware_tok);
        printk("data to be sent: %s\n", postData);
    
	post_request("/api/device/capture", "fleet-test.staflsystems.com", postGPSData);
	//get_request();

	while (1)
	{
		k_cpu_idle();
	}
    return 0;
}
#include "https.h"

int at_comms_init()
{
	int err;

	err = at_cmd_init();
	if (err)
	{
		printk("Failed to initialize AT commands, err %d\n", err);
		return err;
	}

	err = at_notif_init();
	if (err)
	{
		printk("Failed to initialize AT notifications, err %d\n", err);
		return err;
    }

	return 0;
}


int tls_setup(int fd)
{
	int err;
	int verify;

	/* Security tag that we have provisioned the certificate with */
	const sec_tag_t tls_sec_tag[] = {
		TLS_SEC_TAG,
	};

	/* Set up TLS peer verification */
	enum
	{
		NONE = 0,
		OPTIONAL = 1,
		REQUIRED = 2,
	};

	verify = REQUIRED;

	err = setsockopt(fd, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(verify));
	if (err)
	{
		printk("Failed to setup peer verification, err %d\n", errno);
		return err;
	}

	/* Associate the socket with the security tag
	 * we have provisioned the certificate with.
	 */
	err = setsockopt(fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_sec_tag,
					 sizeof(tls_sec_tag));
	if (err)
	{
		printk("Failed to setup TLS sec tag, err %d\n", errno);
		return err;
	}

	return 0;
}

char* parseRecv(const char *input)
{
	char *pch = NULL;

    //search for the end of the response headers for the meat of the content
	pch = strstr(input, "\r\n\r\n");

    //return pointer to start of what we want
	return pch;
}
void get_request(const char *path, const char *host)
{
	int err;
	int bytes, sockfd, totalBytes = 0;
	size_t off;
	struct addrinfo *res;
	struct addrinfo hints;

	char sendBuff[SEND_BUFF_SIZE];
	char recBuff[RECV_BUFF_SIZE];
	int sendLength = sprintf(sendBuff,
							 GET_TEMPLATE,
							 path,
							 host);

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;

	printk("HTTP GET started..\n\r");

	err = getaddrinfo(host, NULL, &hints, &res);
	if (err)
	{
		printk("getaddrinfo errno %d\n", errno);
		/* No clean up needed, just return */
		return;
	}

	printk("Address info received\n\r");
	((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTPS_PORT);

	sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);
	if (sockfd == -1)
	{
		printk("Failed to open socket\n");
		return;
	}
	enum
	{
		NONE = 0,
		OPTIONAL = 1,
		REQUIRED = 2,
	};

	int verify = OPTIONAL;

	err = setsockopt(sockfd, SOL_TLS, TLS_PEER_VERIFY, &verify,
					 sizeof(verify));
	if (err)
	{
		printk("setsockopt err: %d\n", errno);
	}

	err = connect(sockfd, (struct sockaddr *)res->ai_addr, sizeof(struct sockaddr_in));
	if (err > 0)
	{
		printk("connect err: %d\n", errno);
		return; //goto clean_up;
	}

	off = 0;
	printk("%s\n", sendBuff);
	do
	{
		bytes = send(sockfd, sendBuff, sendLength - off, 0);
		if (bytes < 0)
		{
			printk("send() failed, err %d\n", errno);
			return; //goto clean_up;
		}
		off += bytes;
	} while (off < sendLength);

	printk("Sent %d bytes\n", off);

	do
	{
		/* TODO: make a proper timeout *
            * Current solution will just hang 
            * until remote side closes connection */
		bytes = recv(sockfd, recBuff, RECV_BUFF_SIZE, 0);
		totalBytes += bytes;
		printk("total number of bytes: %d\n", totalBytes);
		printk("num bytes: %d\n", bytes);
		if (bytes < 0)
		{
			printk("\nrecv errno: %d\n", errno);
			break;
		}
		printk("%s\n", recBuff);
	} while (bytes > 0);

	printk("Received %d bytes\n", off);

	printk("\n\rFinished. Closing socket\r\n");
	freeaddrinfo(res);
	err = close(sockfd);
}
void post_request(const char *path, const char *host, char *sendData)
{
	int err;
	char *p = NULL; //pointer to response
	int bytes, sockfd, totalBytes = 0;
	size_t off;
	struct addrinfo *res;
	struct addrinfo hints;

	char sendBuff[SEND_BUFF_SIZE];
	char recBuff[RECV_BUFF_SIZE];
	memset(&recBuff, 0, sizeof(recBuff));
	int sendLength = snprintf(sendBuff,
							  500,
							  POST_TEMPLATE,
							  path,
							  host,
							  strlen(sendData),
							  SEND_DATA);

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;

	printk("HTTP POST started..\n\r");

	err = getaddrinfo(host, NULL, &hints, &res);
	if (err)
	{
		printk("getaddrinfo errno %d\n", errno);
		/* No clean up needed, just return */
		return;
	}

	printk("Address info received\n\r");
	((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTPS_PORT);

	sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);

	err = tls_setup(sockfd);
	if (err)
	{
		return;
	}
	enum
	{
		NONE = 0,
		OPTIONAL = 1,
		REQUIRED = 2,
	};

	int verify = OPTIONAL;

	err = setsockopt(sockfd, SOL_TLS, TLS_PEER_VERIFY, &verify,
					 sizeof(verify));
	if (err)
	{
		printk("setsockopt err: %d\n", errno);
	}

	err = connect(sockfd, (struct sockaddr *)res->ai_addr, sizeof(struct sockaddr_in));
	if (err > 0)
	{
		printk("connect err: %d\n", errno);
		return; //goto cleanup
	}

	off = 0;
	do
	{
		bytes = send(sockfd, sendBuff, sendLength - off, 0);
		if (bytes < 0)
		{
			printk("send() failed, err %d\n", errno);
			return;
		}
		off += bytes;
	} while (off < sendLength);

	printk("Sent %d bytes\n", off);

	do
	{
		/* TODO: make a proper timeout *
		 * Current solution will just hang 
		 * until remote side closes connection */
		bytes = recv(sockfd, recBuff, RECV_BUFF_SIZE, 0);
		totalBytes += bytes;
		if (bytes < 0)
		{
			printk("\nrecv errno: %d\n", errno);
			break;
		}
		printk("%s\n", recBuff);
	} while (bytes > 0);

	printk("%s\n", recBuff);
	printk("Received %d bytes\n", off);

	//	/* Print HTTP response */
	//	p = strstr(recBuff, "\r\n");
	//	if (p) {
	//		off = p - recBuff;
	//		recBuff[off + 1] = '\0';
	//		printk("\n>\t %s\n\n", recBuff);
	//	}

	printk("\n\rFinished. Closing socket\r\n");
	freeaddrinfo(res);
	err = close(sockfd);

	p = parseRecv(recBuff);
	printk("Filtered response: %s", p);
}
6433.https.h
#
# Copyright (c) 2019 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
#

cmake_minimum_required(VERSION 3.8.2)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(NONE)

target_sources(app PRIVATE src/main.c)

zephyr_include_directories(src)

add_subdirectory(src/https)

CONFIG_BSD_LIBRARY=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
CONFIG_AT_CMD=y
CONFIG_AT_NOTIF=y

# Enable SUPL client support
CONFIG_SUPL_CLIENT_LIB=n

# Networking
CONFIG_NETWORKING=y
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y

# Disable native network stack to save some memory
CONFIG_NET_NATIVE=n

CONFIG_MODEM_KEY_MGMT=y
CONFIG_LTE_LINK_CONTROL=y


# Main thread
CONFIG_HEAP_MEM_POOL_SIZE=2048
CONFIG_MAIN_STACK_SIZE=4096

  • Hi,

    What errors do you get?

    When and where do you get them?

    A detailed description of the actual errors/faulty behavior is usually quite important and helpful in these kinds of cases.

    Best regards,

    Didrik

  • Hi Didrik,

    Thanks for your quick response. Sorry, I totally forgot to include the printout from the terminal emulator and my errors.

    Alright so at first I was just getting a Failed to Initialize Modem error, form inside the init_app() function, which sends over the commands to start GPS. I added a few printk statements inside the setup_modem() function, and printed out the command that failed to send, and it was the "AT\%XSYSTEMMODE=1,0,1,0" command (note, this worked when I ran the GPS application on its own).

    In my main function, I was setting up the GPS first, attempting to gather data, and then setting up HTTPS, but I switched the order after the modem errors. Now, I am failing to connect to the LTE network, with err -120. The strange thing is I haven't encountered these errors when I run these applications separately.

    I took a deeper look at the SYSTEMMODE command, and it looks like only one modem mode is allowed at once? I am wondering if I need to switch modes after setting up each application or something like that. Let me know what you think.

    Thanks!

    Sincerely,

    Kyle Garland

  • I think (at least a part of) your problem is that you try to initialize things twice.

    Both the bsdlib and lte_link_control library will by default initialize and connect to the network during startup, before the application is started.

    You can disable this behavior by adding CONFIG_BSD_LIBRARY_SYS_INIT=n and CONFIG_AUTO_INIT_AND_CONNECT=n to your prj.conf.

    Could you try to add those, and see if that helps you?

     

    kgarland789 said:
    I took a deeper look at the SYSTEMMODE command, and it looks like only one modem mode is allowed at once?

     You can enable one LTE mode (LTE-M or NB-IoT) and GPS at once. So you can enable both LTE-M and GPS with AT%XSYSTEMMODE=1,0,1,0.

    The flow of operations in your application should probably be something like this (assuming bsdlib and lte_link_control is not initialized automatically).

    1. Initialize bsdlib

    2. Initialize at_cmd

    3. Send any extra AT commands that is not handled by the lte_link_control library (take a look at the Kconfig file to see what options you have)

    4. Initialize lte_link_control

    From here, you must decide if you want to do 'LTE stuff' or 'GPS stuff' first.

    If you want to start with the GPS, you do the necessary initialization and search for a fix before you connect to the LTE network.

    If you want to do 'LTE stuff', you can replace 'lte_lc_init' with 'lte_lc_init_and_connect' in step 4 to connect to the network.

    When you are connected to the network, you can open a socket, and do network stuff.

    Also, remember that you cannot use the GPS and LTE radios at the same time. So you will have to ensure that the LTE radio is inactive (either because you have turned off LTE, or because you are using PSM or eDRX) when you are using the GPS.

  • Hi Didrik,

    Thank you for the detailed response. I think at this point, I want to get the GPS data first, and when I get a good fix on the satellite, send that information to the server over https, and then repeat every 1 second or so. Our application is eventually going to get a bit more complicated but I think for now this is good.

    I will try what you have suggested and hopefully get back to you soon, but I do have a few questions in the meantime:

    Since we cannot use GPS and LTE radios at the same time, would I need to disable the LTE radio while getting GPS data and then re-enable it when I start the HTTPS part of the application? If so, how would I accomplish this (what commands disables the LTE modem) and could I set some sort of flag that toggles the LTE radio so I can have my code repeat in a loop forever?

    I'm still familiarizing myself with using LTE and Zephyr, so where in the docs could I find the difference between lte_lc_init and lte_lc_init_and_connect functions?

    I think that is all for now. Thanks again for the detailed response!

    Sincerely,

    Kyle Garland

  • kgarland789 said:
    I'm still familiarizing myself with using LTE and Zephyr, so where in the docs could I find the difference between lte_lc_init and lte_lc_init_and_connect functions?

     https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.3.0/nrf/include/modem/lte_lc.html#_CPPv411lte_lc_initv

    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.3.0/nrf/include/modem/lte_lc.html#_CPPv414lte_lc_connectv

    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.3.0/nrf/include/modem/lte_lc.html#_CPPv423lte_lc_init_and_connectv

    The lte_lc_init funtion configures the modem based on the Kconfig options you have set.

    The lte_lc_connect function connects to the cellular network.

    lte_lc_init_and_connect is simply a wrapper that first calls lte_lc_init, then lte_lc_connect.

    You can find their implementation here: https://github.com/nrfconnect/sdk-nrf/blob/master/lib/lte_link_control/lte_lc.c#L516

     

    kgarland789 said:
    Since we cannot use GPS and LTE radios at the same time, would I need to disable the LTE radio while getting GPS data and then re-enable it when I start the HTTPS part of the application? If so, how would I accomplish this (what commands disables the LTE modem) and could I set some sort of flag that toggles the LTE radio so I can have my code repeat in a loop forever?

     There are a few different ways to solve this, with different strengths and drawbacks depending on you use case.

    The perhaps most obvious way to do it is to disable the LTE stack when you run the GPS. You can disable and enable the LTE stack separatly from the GNSS stack by sending AT+CFUN=20 or 21 to the modem. This will always work, in any network with any SIM card. But, you will have to re-attach to the network each time you want to send (or listen for) data. This causes higher power consumption due to the extra attach requests needed. In addition, you are only allowed to attempt to attach to a network 30 times per hour, so if you have short reporting intervals, you will be blocked from connecting to the network for a while.

    Another option is to use PSM (Power Saving Mode). This is a feature which let you inform the network that you do not expect any downlink data for a while. If granted for by the network, the device will turn of its radio for the given period of time. When it wakes up again, it will only have to do a Tracking Area Update (TAU), not a full reattach to the network. Unfortunatly, roaming devices will often not be granted PSM by the network. Different networks also have different PSM values that they allow, e.g. Verizon only grant PSM if you request 3 hours or longer. But, you can still send data at any time, you can just not receive any.

    When connected to the network, or after each data transfer, there is a period where the device has to listen for incoming messages. But during this period, the device is not in RX continuously, it will still have some short periods of sleep inbetween. eDRX (extended discontinuous reception) let you extend these periods of sleep. Again, this is something that must be requested from the network, and will usually not be granted to roaming devices.

    You can read more about eDRX and PSM here: https://www.nordicsemi.com/Products/Low-power-cellular-IoT

    If you are using an iBasis SIM card, we have some data on which features are supported on what networks here:https://devzone.nordicsemi.com/nordic/cellular-iot-guides/b/hardware-design/posts/ibasis-esim-national-coverage-update

    All that said, the GPS performance has been improved a lot in later versions. The modem will run the GPS whenever there is enough time, as long as the GPS is running. With the use of A-GPS, it will also not need a very long time to get a fix, and if it already has a fix, the next fix will also be much faster. It is therefore possible to get GPS fixes without any extra measures to give the GPS more time, but this will not work with a cold start.

Related