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

Problem with HTTP and PSM on Thingy:91

Hello,

I'm trying to develop an application sending GPS over HTTP requests.

I started from the "https client" and "agps" samples in the NRF Connect SDK: the single examples work fine.

I'm having trouble in merging the http example into the agps one.

After the modem configuration, I'm trying to execute the http request:

	err = modem_configure();
	if (err) {
		LOG_ERR("Modem configuration failed with error %d",
			err);
		return;
	}

#if HTTP_TEST
	err = getaddrinfo("XXX-dev-iot.azurewebsites.net", NULL, &hints, &res);
	if (err) {
		printk("getaddrinfo() failed, err %d\n", errno);
		return;
	}

	((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTPS_PORT);

	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);
	if (fd == -1) {
		printk("Failed to open socket!\n");
		//goto clean_up;
	}

	/* Setup TLS socket options */
	err = tls_setup(fd);
	if (err) {
		//goto clean_up;
	}

       
	printk("Connecting to %s\n", "XXX-dev-iot.azurewebsites.net");
	err = connect(fd, res->ai_addr, sizeof(struct sockaddr_in));
	if (err) {
		printk("connect() failed, err: %d\n", errno);
		//goto clean_up;
	}

	off = 0;
	do {
		bytes = send(fd, &send_buf[off], HTTP_HEAD_LEN - off, 0);
		if (bytes < 0) {
			printk("send() failed, err %d\n", errno);
			//goto clean_up;
		}
		off += bytes;
	} while (off < HTTP_HEAD_LEN);

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

	off = 0;
	do {
		bytes = recv(fd, &recv_buf[off], RECV_BUF_SIZE - off, 0);
		if (bytes < 0) {
			printk("recv() failed, err %d\n", errno);
			//goto clean_up;
		}
		off += bytes;
	} while (bytes != 0 /* peer closed connection */);

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

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

	printk("Finished, closing socket.\n");

Code stucks after the send command:

AT+CGACT?


+CGACT: 0,1


OK


Connecting to XXX-dev-iot.azurewebsites.net


Sent 116 bytes


+CSCON: 0

I believe that the PDM active time elapses during the receive command.

I tried to:

  • remove the PDM using lte_lc_psm_req(false)
  • increase the PDM active timemodyfing CONFIG_LTE_PSM_REQ_RAT in configuration file

These attempts didn't work: it's like the PDM active time does not change.

Do you have any suggestion? Am I doing something wrong?

Thank you

  • Hello!

    Could I have a look at how you have merged the samples? From what I can see you are correct that the device enters a not connected state after transmission. Could you try to experiment with other CONFIG_LTE_PSM_REQ_RAT values? Some values could be rejected by the network provider.

    Best regards,
    Carl Richard

  • Hi Carl,

    thank you for your answer.

    This is the main.c file:

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #define HTTP_TEST 1
    #define AZURE_TEST 1
    
    #include <zephyr.h>
    #include <stdio.h>
    #include <modem/lte_lc.h>
    #include <net/cloud.h>
    #include <net/socket.h>
    #include <dk_buttons_and_leds.h>
    #include <drivers/gps.h>
    #include <sys/reboot.h>
    #if defined(CONFIG_NRF_CLOUD_PGPS)
    #include <net/nrf_cloud_agps.h>
    #include <net/nrf_cloud_pgps.h>
    #include <date_time.h>
    #include <pm_config.h>
    #endif
    
    
    
    
    #if HTTP_TEST
    #include <string.h>
    #include <stdlib.h>
    #include <modem/nrf_modem_lib.h>
    #include <net/tls_credentials.h>
    #include <modem/lte_lc.h>
    #include <modem/at_cmd.h>
    #include <modem/at_notif.h>
    #include <modem/modem_key_mgmt.h>
    
    #define HTTPS_PORT 443
    #if AZURE_TEST
    #define HTTP_HEAD                                   \
    	"POST /api/dummy HTTP/1.1\r\n"              \
    	"Host: XXX-dev-iot.azurewebsites.net\r\n"   \
            "Content-Type: application/json\r\n"        \
            "Content-Length: 0\r\n"                     \
            "Connection: close\r\n\r\n"
    #else
    #define HTTP_HEAD                                                              \
    	"HEAD / HTTP/1.1\r\n"                                                  \
    	"Host: example.com:443\r\n"                                            \
    	"Connection: close\r\n\r\n"
    #endif                 
    
    #define HTTP_HEAD_LEN (sizeof(HTTP_HEAD) - 1)
    #define HTTP_HDR_END "\r\n\r\n"
    #define RECV_BUF_SIZE 2048
    #define TLS_SEC_TAG 42
    static const char send_buf[] = HTTP_HEAD;
    static char recv_buf[RECV_BUF_SIZE];
    /* Certificate for `example.com` */
    static const char cert[] = {
    #if AZURE_TEST
    	#include "../cert/azurewebsites-net.pem"
    #else
    	#include "../cert/DigiCertGlobalRootCA.pem"
    #endif
    };
    BUILD_ASSERT(sizeof(cert) < KB(4), "Certificate too large");
    
    int http_send(void);
    #endif
    
    #include <logging/log.h>
    
    #define SERVICE_INFO_GPS "{\"state\":{\"reported\":{\"device\": \
    			  {\"serviceInfo\":{\"ui\":[\"GPS\"]}}}}}"
    
    LOG_MODULE_REGISTER(agps_sample, CONFIG_AGPS_SAMPLE_LOG_LEVEL);
    
    static struct cloud_backend *cloud_backend;
    static const struct device *gps_dev;
    static uint64_t start_search_timestamp;
    static uint64_t fix_timestamp;
    static struct k_work gps_start_work;
    static struct k_work_delayable reboot_work;
    
    #if defined(CONFIG_NRF_CLOUD_PGPS)
    static struct k_work manage_pgps_work;
    static struct k_work notify_pgps_work;
    static struct gps_agps_request agps_request;
    #endif
    
    static void gps_start_work_fn(struct k_work *work);
    
    #if defined(CONFIG_NRF_CLOUD_PGPS)
    static struct nrf_cloud_pgps_prediction *prediction;
    
    void pgps_handler(enum nrf_cloud_pgps_event event,
    		  struct nrf_cloud_pgps_prediction *p)
    {
    	/* GPS unit asked for it, but we didn't have it; check now */
    	LOG_INF("event: %d", event);
    	if (event == PGPS_EVT_AVAILABLE) {
    		prediction = p;
    		k_work_submit(&manage_pgps_work);
    	}
    }
    
    static void manage_pgps(struct k_work *work)
    {
    	ARG_UNUSED(work);
    	int err;
    
    	LOG_INF("Sending prediction to modem...");
    	err = nrf_cloud_pgps_inject(prediction, &agps_request, NULL);
    	if (err) {
    		LOG_ERR("Unable to send prediction to modem: %d", err);
    	}
    
    	err = nrf_cloud_pgps_preemptive_updates();
    	if (err) {
    		LOG_ERR("Error requesting updates: %d", err);
    	}
    }
    
    static void notify_pgps(struct k_work *work)
    {
    	ARG_UNUSED(work);
    	int err;
    
    	err = nrf_cloud_pgps_notify_prediction();
    	if (err) {
    		LOG_ERR("error requesting notification of prediction availability: %d", err);
    	}
    }
    #endif
    
    static void cloud_send_msg(void)
    {
    	int err;
    
    	LOG_DBG("Publishing message: %s", log_strdup(CONFIG_CLOUD_MESSAGE));
    
    	struct cloud_msg msg = {
    		.qos = CLOUD_QOS_AT_MOST_ONCE,
    		.endpoint.type = CLOUD_EP_MSG,
    		.buf = CONFIG_CLOUD_MESSAGE,
    		.len = sizeof(CONFIG_CLOUD_MESSAGE)
    	};
    
    	err = cloud_send(cloud_backend, &msg);
    	if (err) {
    		LOG_ERR("cloud_send failed, error: %d", err);
    	}
    }
    
    static void gps_start_work_fn(struct k_work *work)
    {
    	int err;
    	struct gps_config gps_cfg = {
    		.nav_mode = GPS_NAV_MODE_PERIODIC,
    		.power_mode = GPS_POWER_MODE_DISABLED,
    		.timeout = 120,
    		.interval = 240,
    		.priority = true,
    	};
    
    	ARG_UNUSED(work);
    
    #if defined(CONFIG_NRF_CLOUD_PGPS)
    	static bool initialized;
    
    	if (!initialized) {
    		struct nrf_cloud_pgps_init_param param = {
    			.event_handler = pgps_handler,
    			.storage_base = PM_MCUBOOT_SECONDARY_ADDRESS,
    			.storage_size = PM_MCUBOOT_SECONDARY_SIZE};
    
    		err = nrf_cloud_pgps_init(&param);
    		if (err) {
    			LOG_ERR("Error from PGPS init: %d", err);
    		} else {
    			initialized = true;
    		}
    	}
    #endif
    
    	err = gps_start(gps_dev, &gps_cfg);
    	if (err) {
    		LOG_ERR("Failed to start GPS, error: %d", err);
    		return;
    	}
    
    	LOG_INF("Periodic GPS search started with interval %d s, timeout %d s",
    		gps_cfg.interval, gps_cfg.timeout);
    }
    
    static void on_agps_needed(struct gps_agps_request request)
    {
    #if defined(CONFIG_AGPS)
    	int err = gps_agps_request_send(request, GPS_SOCKET_NOT_PROVIDED);
    
    	if (err) {
    		LOG_ERR("Failed to request A-GPS data, error: %d", err);
    		return;
    	}
    #endif
    #if defined(CONFIG_NRF_CLOUD_PGPS)
    	/* AGPS data not expected, so move on to PGPS */
    	if (!nrf_cloud_agps_request_in_progress()) {
    		k_work_submit(&notify_pgps_work);
    	}
    #endif
    }
    
    static void send_service_info(void)
    {
    	int err;
    	struct cloud_msg msg = {
    		.qos = CLOUD_QOS_AT_MOST_ONCE,
    		.endpoint.type = CLOUD_EP_STATE,
    		.buf = SERVICE_INFO_GPS,
    		.len = strlen(SERVICE_INFO_GPS)
    	};
    
    	err = cloud_send(cloud_backend, &msg);
    	if (err) {
    		LOG_ERR("Failed to send message to cloud, error: %d", err);
    		return;
    	}
    
    	LOG_INF("Service info sent to cloud");
    }
    
    static void cloud_event_handler(const struct cloud_backend *const backend,
    				const struct cloud_event *const evt,
    				void *user_data)
    {
    	int err = 0;
    
    	ARG_UNUSED(backend);
    	ARG_UNUSED(user_data);
    
    	switch (evt->type) {
    	case CLOUD_EVT_CONNECTING:
    		LOG_INF("CLOUD_EVT_CONNECTING");
    		break;
    	case CLOUD_EVT_CONNECTED:
    		LOG_INF("CLOUD_EVT_CONNECTED");
    		break;
    	case CLOUD_EVT_READY:
    		LOG_INF("CLOUD_EVT_READY");
    		/* Update nRF Cloud with GPS service info signifying that it
    		 * has GPS capabilities. */
    		send_service_info();
    		k_work_submit(&gps_start_work);
    		break;
    	case CLOUD_EVT_DISCONNECTED:
    		LOG_INF("CLOUD_EVT_DISCONNECTED");
    		break;
    	case CLOUD_EVT_ERROR:
    		LOG_INF("CLOUD_EVT_ERROR");
    		break;
    	case CLOUD_EVT_DATA_SENT:
    		LOG_INF("CLOUD_EVT_DATA_SENT");
    		break;
    	case CLOUD_EVT_DATA_RECEIVED:
    		LOG_INF("CLOUD_EVT_DATA_RECEIVED");
    
    		/* Convenience functionality for remote testing.
    		 * The device is reset if it receives "{"reboot":true}"
    		 * from the cloud. The command can be sent using the terminal
    		 * card on the device page on nrfcloud.com.
    		 */
    		if (evt->data.msg.buf[0] == '{') {
    			int ret = strncmp(evt->data.msg.buf,
    				      "{\"reboot\":true}",
    				      strlen("{\"reboot\":true}"));
    
    			if (ret == 0) {
    				/* The work item may already be scheduled
    				 * because of the button being pressed,
    				 * so use rescheduling here to get the work
    				 * submitted with no delay.
    				 */
    				k_work_reschedule(&reboot_work, K_NO_WAIT);
    			}
    			break;
    		}
    
    #if defined(CONFIG_AGPS)
    		err = gps_process_agps_data(evt->data.msg.buf, evt->data.msg.len);
    		if (!err) {
    			LOG_INF("A-GPS data processed");
    #if defined(CONFIG_NRF_CLOUD_PGPS)
    			/* call us back when prediction is ready */
    			k_work_submit(&notify_pgps_work);
    #endif
    			/* data was valid; no need to pass to other handlers */
    			break;
    		}
    #endif
    #if defined(CONFIG_NRF_CLOUD_PGPS)
    		err = nrf_cloud_pgps_process(evt->data.msg.buf, evt->data.msg.len);
    		if (err) {
    			LOG_ERR("Error processing PGPS packet: %d", err);
    		}
    #else
    		if (err) {
    			LOG_INF("Unable to process agps data, error: %d", err);
    		}
    #endif
    		break;
    	case CLOUD_EVT_PAIR_REQUEST:
    		LOG_INF("CLOUD_EVT_PAIR_REQUEST");
    		break;
    	case CLOUD_EVT_PAIR_DONE:
    		LOG_INF("CLOUD_EVT_PAIR_DONE");
    		break;
    	case CLOUD_EVT_FOTA_DONE:
    		LOG_INF("CLOUD_EVT_FOTA_DONE");
    		break;
    	case CLOUD_EVT_FOTA_ERROR:
    		LOG_INF("CLOUD_EVT_FOTA_ERROR");
    		break;
    	default:
    		LOG_INF("Unknown cloud event type: %d", evt->type);
    		break;
    	}
    }
    
    static void print_pvt_data(struct gps_pvt *pvt_data)
    {
    	char buf[300];
    	size_t len;
    
    	len = snprintf(buf, sizeof(buf),
    		      "\r\n\tLongitude:  %f\r\n\t"
    		      "Latitude:   %f\r\n\t"
    		      "Altitude:   %f\r\n\t"
    		      "Speed:      %f\r\n\t"
    		      "Heading:    %f\r\n\t"
    		      "Date:       %02u-%02u-%02u\r\n\t"
    		      "Time (UTC): %02u:%02u:%02u\r\n",
    		      pvt_data->longitude, pvt_data->latitude,
    		      pvt_data->altitude, pvt_data->speed, pvt_data->heading,
    		      pvt_data->datetime.year, pvt_data->datetime.month,
    		      pvt_data->datetime.day, pvt_data->datetime.hour,
    		      pvt_data->datetime.minute, pvt_data->datetime.seconds);
    	if (len < 0) {
    		LOG_ERR("Could not construct PVT print");
    	} else {
    		LOG_INF("%s", log_strdup(buf));
    	}
    }
    
    static void print_satellite_stats(struct gps_pvt *pvt_data)
    {
    	uint8_t tracked = 0;
    	uint32_t tracked_sats = 0;
    	static uint32_t prev_tracked_sats;
    	char print_buf[100];
    	size_t print_buf_len;
    
    	for (int i = 0; i < GPS_PVT_MAX_SV_COUNT; ++i) {
    		if ((pvt_data->sv[i].sv > 0) &&
    		    (pvt_data->sv[i].sv < 33)) {
    			tracked++;
    			tracked_sats |= BIT(pvt_data->sv[i].sv - 1);
    		}
    	}
    
    	if ((tracked_sats == 0) || (tracked_sats == prev_tracked_sats)) {
    		if (tracked_sats != prev_tracked_sats) {
    			prev_tracked_sats = tracked_sats;
    			LOG_DBG("Tracking no satellites");
    		}
    
    		return;
    	}
    
    	prev_tracked_sats = tracked_sats;
    	print_buf_len = snprintk(print_buf, sizeof(print_buf), "Tracking:  ");
    
    	for (size_t i = 0; i < 32; i++) {
    		if (tracked_sats & BIT(i)) {
    			print_buf_len +=
    				snprintk(&print_buf[print_buf_len - 1],
    					 sizeof(print_buf) - print_buf_len,
    					 "%d  ", i + 1);
    			if (print_buf_len < 0) {
    				LOG_ERR("Failed to print satellite stats");
    				break;
    			}
    		}
    	}
    
    	LOG_INF("%s", log_strdup(print_buf));
    	LOG_DBG("Searching for %lld seconds",
    		(k_uptime_get() - start_search_timestamp) / 1000);
    }
    
    static void send_nmea(char *nmea)
    {
    	int err;
    	char buf[150];
    	struct cloud_msg msg = {
    		.qos = CLOUD_QOS_AT_MOST_ONCE,
    		.endpoint.type = CLOUD_EP_MSG,
    		.buf = buf,
    	};
    
    	msg.len = snprintf(buf, sizeof(buf),
    		"{"
    			"\"appId\":\"GPS\","
    			"\"data\":\"%s\","
    			"\"messageType\":\"DATA\""
    		"}", nmea);
    	if (msg.len < 0) {
    		LOG_ERR("Failed to create GPS cloud message");
    		return;
    	}
    
    	err = cloud_send(cloud_backend, &msg);
    	if (err) {
    		LOG_ERR("Failed to send message to cloud, error: %d", err);
    		return;
    	}
    #if HTTP_TEST
            http_send();
    #endif
    	LOG_INF("GPS position sent to cloud");
            k_work_submit(&gps_start_work);
    }
    
    static void gps_handler(const struct device *dev, struct gps_event *evt)
    {
    	ARG_UNUSED(dev);
    
    	switch (evt->type) {
    	case GPS_EVT_SEARCH_STARTED:
    		LOG_INF("GPS_EVT_SEARCH_STARTED");
    		start_search_timestamp = k_uptime_get();
    		break;
    	case GPS_EVT_SEARCH_STOPPED:
    		LOG_INF("GPS_EVT_SEARCH_STOPPED");
    		break;
    	case GPS_EVT_SEARCH_TIMEOUT:
    		LOG_INF("GPS_EVT_SEARCH_TIMEOUT");
    		break;
    	case GPS_EVT_OPERATION_BLOCKED:
    		LOG_INF("GPS_EVT_OPERATION_BLOCKED");
    		break;
    	case GPS_EVT_OPERATION_UNBLOCKED:
    		LOG_INF("GPS_EVT_OPERATION_UNBLOCKED");
    		break;
    	case GPS_EVT_AGPS_DATA_NEEDED:
    		LOG_INF("GPS_EVT_AGPS_DATA_NEEDED");
    #if defined(CONFIG_NRF_CLOUD_PGPS)
    		LOG_INF("A-GPS request from modem; emask:0x%08X amask:0x%08X utc:%u "
    			"klo:%u neq:%u tow:%u pos:%u int:%u",
    			evt->agps_request.sv_mask_ephe, evt->agps_request.sv_mask_alm,
    			evt->agps_request.utc, evt->agps_request.klobuchar,
    			evt->agps_request.nequick, evt->agps_request.system_time_tow,
    			evt->agps_request.position, evt->agps_request.integrity);
    		memcpy(&agps_request, &evt->agps_request, sizeof(agps_request));
    #endif
    		on_agps_needed(evt->agps_request);
    		break;
    	case GPS_EVT_PVT:
    		print_satellite_stats(&evt->pvt);
    		break;
    	case GPS_EVT_PVT_FIX:
    		fix_timestamp = k_uptime_get();
    
    		LOG_INF("---------       FIX       ---------");
    		LOG_INF("Time to fix: %d seconds",
    			(uint32_t)(fix_timestamp - start_search_timestamp) / 1000);
    		print_pvt_data(&evt->pvt);
    		LOG_INF("-----------------------------------");
    #if defined(CONFIG_NRF_CLOUD_PGPS) && defined(CONFIG_PGPS_STORE_LOCATION)
    		nrf_cloud_pgps_set_location(evt->pvt.latitude, evt->pvt.longitude);
    #endif
    		break;
    	case GPS_EVT_NMEA_FIX:
    		send_nmea(evt->nmea.buf);
    		break;
    	default:
    		break;
    	}
    }
    
    static void reboot_work_fn(struct k_work *work)
    {
    	LOG_WRN("Rebooting in 2 seconds...");
    	k_sleep(K_SECONDS(2));
    	sys_reboot(0);
    }
    
    static void work_init(void)
    {
    	k_work_init(&gps_start_work, gps_start_work_fn);
    	k_work_init_delayable(&reboot_work, reboot_work_fn);
    
    #if defined(CONFIG_NRF_CLOUD_PGPS)
    	k_work_init(&manage_pgps_work, manage_pgps);
    	k_work_init(&notify_pgps_work, notify_pgps);
    #endif
    }
    
    static int modem_configure(void)
    {
    	int err = 0;
    
    	if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT)) {
    		/* Do nothing, modem is already turned on
    		 * and connected.
    		 */
    	} else {
    		LOG_INF("Connecting to LTE network. This may take minutes.");
    
    #if defined(CONFIG_LTE_POWER_SAVING_MODE)
    		err = lte_lc_psm_req(true);
    		if (err) {
    			LOG_ERR("PSM request failed, error: %d", err);
    			return err;
    		}
                    
    		LOG_INF("PSM mode requested");
    #endif
    
    		err = lte_lc_init_and_connect();
    		if (err) {
    			LOG_ERR("LTE link could not be established, error: %d",
    				err);
    			return err;
    		}
    
    		LOG_INF("Connected to LTE network");
    	}
    
    	return err;
    }
    
    static void button_handler(uint32_t button_states, uint32_t has_changed)
    {
    	if (has_changed & button_states & DK_BTN1_MSK) {
    
    		//cloud_send_msg();
                    http_send();
    
    		k_work_schedule(&reboot_work, K_SECONDS(3));
    	} else if (has_changed & ~button_states & DK_BTN1_MSK) {
    		k_work_cancel_delayable(&reboot_work);
    	}
    }
    
    #if defined(CONFIG_DATE_TIME)
    static void date_time_event_handler(const struct date_time_evt *evt)
    {
    	case DATE_TIME_OBTAINED_MODEM:
    	switch (evt->type) {
    		LOG_INF("DATE_TIME_OBTAINED_MODEM");
    		break;
    	case DATE_TIME_OBTAINED_NTP:
    		LOG_INF("DATE_TIME_OBTAINED_NTP");
    		break;
    	case DATE_TIME_OBTAINED_EXT:
    		LOG_INF("DATE_TIME_OBTAINED_EXT");
    		break;
    	case DATE_TIME_NOT_OBTAINED:
    		LOG_INF("DATE_TIME_NOT_OBTAINED");
    		break;
    	default:
    		break;
    	}
    }
    #endif
    
    
    #if HTTP_TEST
    /* Provision certificate to modem */
    int cert_provision(void)
    {
    	int err;
    	bool exists;
    	uint8_t unused;
    
    	err = modem_key_mgmt_exists(TLS_SEC_TAG,
    				    MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN,
    				    &exists, &unused);
    	if (err) {
    		printk("Failed to check for certificates err %d\n", err);
    		return err;
    	}
    
    	if (exists) {
    		/* For the sake of simplicity we delete what is provisioned
    		 * with our security tag and reprovision our certificate.
    		 */
    		err = modem_key_mgmt_delete(TLS_SEC_TAG,
    					    MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN);
    		if (err) {
    			printk("Failed to delete existing certificate, err %d\n",
    			       err);
    		}
    	}
    
    	printk("Provisioning certificate\n");
    
    	/*  Provision certificate to the modem */
    	err = modem_key_mgmt_write(TLS_SEC_TAG,
    				   MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN,
    				   cert, sizeof(cert) - 1);
    	if (err) {
    		printk("Failed to provision certificate, err %d\n", err);
    		return err;
    	}
    
    	return 0;
    }
    
    /* Setup TLS options on a given socket */
    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;
    }
    
    int http_send()
    {
            int err;
    	int fd;
    	char *p;
    	int bytes;
    	size_t off;
    	struct addrinfo *res;
    	struct addrinfo hints = {
    		.ai_family = AF_INET,
    		.ai_socktype = SOCK_STREAM,
    	};
    
    #if AZURE_TEST  
    	err = getaddrinfo("XXX-dev-iot.azurewebsites.net", NULL, &hints, &res);
    #else
    	err = getaddrinfo("example.com", NULL, &hints, &res);
    #endif
            if (err) {
    		printk("getaddrinfo() failed, err %d\n", errno);
    		return;
    	}
    
    	((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTPS_PORT);
    
    	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);
    	if (fd == -1) {
    		printk("Failed to open socket!\n");
    		goto clean_up;
    	}
    
    	/* Setup TLS socket options */
    	err = tls_setup(fd);
    	if (err) {
    		goto clean_up;
    	}
    
    #if AZURE_TEST       
    	printk("Connecting to %s\n", "XXX-dev-iot.azurewebsites.net");
    #else
    	printk("Connecting to %s\n", "example.com");
    #endif
            err = connect(fd, res->ai_addr, sizeof(struct sockaddr_in));
    	if (err) {
    		printk("connect() failed, err: %d\n", errno);
    		goto clean_up;
    	}
    
    	off = 0;
    	do {
    		bytes = send(fd, &send_buf[off], HTTP_HEAD_LEN - off, 0);
    		if (bytes < 0) {
    			printk("send() failed, err %d\n", errno);
    			goto clean_up;
    		}
    		off += bytes;
    	} while (off < HTTP_HEAD_LEN);
            
    	printk("Sent %d bytes\n", off);
            
    	off = 0;
    	do {
    		bytes = recv(fd, &recv_buf[off], RECV_BUF_SIZE - off, 0);
    		if (bytes < 0) {
    			printk("recv() failed, err %d\n", errno);
    			goto clean_up;
    		}
    		off += bytes;
    	} while (bytes != 0 /* peer closed connection */);
            
    	printk("Received %d bytes\n", off);
            
    	/* Print HTTP response */
    	p = strstr(recv_buf, "\r\n");
    	if (p) {
    		off = p - recv_buf;
    		recv_buf[off + 1] = '\0';
    		printk("\n>\t %s\n\n", recv_buf);
    	}
    
           	printk("Finished, closing socket.\n");
    
    
    clean_up:
    	freeaddrinfo(res);
    	(void)close(fd);
            return 0;
    }
    #endif
    
    
    void main(void)
    {
    	int err;
    
    	LOG_INF("A-GPS sample has started");
    
    	cloud_backend = cloud_get_binding("NRF_CLOUD");
    	__ASSERT(cloud_backend, "Could not get binding to cloud backend");
    
    	err = cloud_init(cloud_backend, cloud_event_handler);
    	if (err) {
    		LOG_ERR("Cloud backend could not be initialized, error: %d",
    			err);
    		return;
    	}
    
    #if HTTP_TEST
    	/* Provision certificates before connecting to the LTE network */
    	err = cert_provision();
    	if (err) {
    		return;
    	}
    #endif
    
    	work_init();
    
    	err = modem_configure();
    	if (err) {
    		LOG_ERR("Modem configuration failed with error %d",
    			err);
    		return;
    	}
    
    #if HTTP_TEST
            http_send();
    #endif
    
    	gps_dev = device_get_binding("NRF9160_GPS");
    	if (gps_dev == NULL) {
    		LOG_ERR("Could not get binding to nRF9160 GPS");
    		return;
    	}
    
    	err = gps_init(gps_dev, gps_handler);
    	if (err) {
    		LOG_ERR("Could not initialize GPS, error: %d", err);
    		return;
    	}
    
    	err = dk_buttons_init(button_handler);
    	if (err) {
    		LOG_ERR("Buttons could not be initialized, error: %d", err);
    		LOG_WRN("Continuing without button funcitonality");
    	}
    
    #if defined(CONFIG_DATE_TIME)
    	date_time_update_async(date_time_event_handler);
    #endif
    
    	err = cloud_connect(cloud_backend);
    	if (err) {
    		LOG_ERR("Cloud connection failed, error: %d", err);
    		return;
    	}
    
    	/* The cloud connection is polled in a thread in the backend.
    	 * Events will be received to cloud_event_handler() when data is
    	 * received from the cloud.
    	 */
    }
    

    You can see that the http request is sent by http_send() function.

    MaybeI I was wrong about the PSM... I tried to add "Connection: close" to the http message and now http_send() works when called inside the main function.

    However, when I call http_send() from the button_handler() function, the problem persists.

    Here is the log:

    D: Tracking: 0 Using: 0 Unhealthy: 0
    D: Seconds since last fix 58
    D: Waiting for time window to operate
    I: GPS_EVT_OPERATION_BLOCKED
    D: GPS has time window to operate
    I: GPS_EVT_OPERATION_UNBLOCKED
    D: Tracking: 0 Using: 0 Unhealthy: 0
    D: Seconds since last fix 67
    D: Tracking: 0 Using: 0 Unhealthy: 0
    D: Seconds since last fix 68
    %CESQ: 58,2,30,4
    +CSCON: 1
    Connecting to XXX-dev-iot.azurewebsites.net
    D: Waiting for time window to operate
    I: GPS_EVT_OPERATION_BLOCKED
    %CESQ: 56,2,25,3
    Sent 135 bytes
    %CESQ: 57,2,31,4
    +CSCON: 0
    D: GPS has time window to operate
    I: GPS_EVT_OPERATION_UNBLOCKED
    I: Tracking: 7
    D: Tracking SV 7: not used, healthy
    D: Tracking: 1 Using: 0 Unhealthy: 0
    D: Seconds since last fix 89

  • Hello again!

    That's interesting! There may be an issue priorities or calling the http_send() from an interrupt handler. Could you try to implement the send function as a work item, and post it to the queue from the button handler instead?

    Best regards,
    Carl Richard

Related