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(<e_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(<e_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);
}
#
# 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