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