I'm attempting t to turn on and off GPS function while LTE is on, but it doesn't work out. I merged mqtt_simple and gps example programs into a new project. What's wrong with the program?
In configure_gps_off_on function, buf stores "ERROR" in the line of bytes_received = recv(at_sock, buf, 2, 0), which means that receiving data through socket does not work.
ncs version: 1.0.0
In version 1.0.0, is it possible to use LTE and GPS at the same time?
<prj.conf> # General config CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_NEWLIB_LIBC=y CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y # Networking CONFIG_NETWORKING=y CONFIG_NET_SOCKETS_OFFLOAD=y CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETS_POSIX_NAMES=y CONFIG_STDOUT_CONSOLE=y CONFIG_LOG=y CONFIG_LOG_DEFAULT_LEVEL=4 # LTE link control CONFIG_LTE_LINK_CONTROL=y CONFIG_LTE_AUTO_INIT_AND_CONNECT=n # BSD library CONFIG_BSD_LIBRARY=y # AT Host CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_AT_HOST_LIBRARY=y # MQTT CONFIG_MQTT_LIB=y CONFIG_MQTT_LIB_TLS=n # Appliaction CONFIG_MQTT_PUB_TOPIC="myPubTopic" CONFIG_MQTT_SUB_TOPIC="mySubTopic" CONFIG_MQTT_CLIENT_ID="myClientID" CONFIG_MQTT_BROKER_HOSTNAME="xxxxxxxx.com" CONFIG_MQTT_BROKER_PORT=xxxx # Main thread CONFIG_MAIN_THREAD_PRIORITY=7 CONFIG_MAIN_STACK_SIZE=4096 CONFIG_HEAP_MEM_POOL_SIZE=1024 # Disable native network stack to save some memory CONFIG_NET_IPV4=n CONFIG_NET_IPV6=n CONFIG_NET_UDP=n CONFIG_NET_TCP=n CONFIG_NET_RX_STACK_SIZE=256 CONFIG_NET_TX_STACK_SIZE=256
<main.c>
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
*/
#include <zephyr.h>
#include <stdio.h>
#include <uart.h>
#include <string.h>
#include <net/mqtt.h>
#include <nrf_socket.h>
#include <net/socket.h>
#include <lte_lc.h>
#include <stdio.h>
#define MQTT_USERNAME "username"
#define MQTT_PASSWORD "password"
#define AT_XSYSTEMMODE_EN_M1_GPS "AT\%XSYSTEMMODE=1,0,1,0" // %XSYSTEMMODE=<M1_support>,<NB1_support>,<GNSS_support>,<LTE_preference>
#define AT_XSYSTEMMODE_EN_M1 "AT\%XSYSTEMMODE=1,0,0,0"
#define AT_CFUN_EN_MODEM "AT+CFUN=1"
/* Set the modem functional mode.
* 0 – Power off
* 1 – Normal mode
* 4 – Offline mode
* 44 – Offline mode without shutting down UICC */
#ifdef CONFIG_BOARD_NRF9160_PCA10090NS
#define AT_MAGPIO_EN_GPS "AT\%XMAGPIO=1,0,0,1,1,1574,1577" // %XMAGPIO=<MAGPIO0>,<MAGPIO1>,<MAGPIO2>,<The number of frequency ranges>,<state_0>,<flo_0>,<fhi_0><state_1>,<flo_1>,<fhi_1>,...
#define AT_MAGPIO_DIS "AT\%XMAGPIO"
#endif
#define GPS_EN true
#define GPS_DIS false
static int fd;
static char nmea_strings[10][NRF_GNSS_NMEA_MAX_LEN];
static u32_t nmea_string_cnt;
static bool got_first_fix;
static bool update_terminal;
static u64_t fix_timestamp;
nrf_gnss_data_frame_t last_fix;
/* Buffers for MQTT client. */
static u8_t rx_buffer[CONFIG_MQTT_MESSAGE_BUFFER_SIZE];
static u8_t tx_buffer[CONFIG_MQTT_MESSAGE_BUFFER_SIZE];
static u8_t payload_buf[CONFIG_MQTT_PAYLOAD_BUFFER_SIZE];
/* The mqtt client struct */
static struct mqtt_client client;
/* MQTT Broker details. */
static struct sockaddr_storage broker;
/* Connected flag */
static bool connected;
/* File descriptor */
static struct pollfd fds;
#if defined(CONFIG_BSD_LIBRARY)
/**@brief Recoverable BSD library error. */
void bsd_recoverable_error_handler(uint32_t err)
{
printk("bsdlib recoverable error: %u\n", err);
}
/**@brief Irrecoverable BSD library error. */
void bsd_irrecoverable_error_handler(uint32_t err)
{
printk("bsdlib irrecoverable error: %u\n", err);
__ASSERT_NO_MSG(false);
}
#endif /* defined(CONFIG_BSD_LIBRARY) */
/* GPS setting*/
static int configure_gps_off_on(bool status)
{
int at_sock;
int bytes_sent;
int bytes_received;
char buf[2];
char *at_commands[3];
if(status == GPS_EN){
at_commands[0] = AT_XSYSTEMMODE_EN_M1_GPS;
at_commands[1] = AT_MAGPIO_EN_GPS;
} else {
at_commands[0] = AT_XSYSTEMMODE_EN_M1;
at_commands[1] = AT_MAGPIO_DIS;
}
at_commands[2] = AT_CFUN_EN_MODEM;
printf("at_commands[0] = %s\n", at_commands[0]);
printf("at_commands[1] = %s\n", at_commands[1]);
printf("at_commands[2] = %s\n", at_commands[2]);
at_sock = socket(AF_LTE, 0, NPROTO_AT); // retunr 4
printk("at_sock = %u\n", at_sock);
if (at_sock < 0) {
printk("Error1\n");
return -1;
}
for (int i = 0; i < ARRAY_SIZE(at_commands); i++) {
bytes_sent = send(at_sock, at_commands[i], strlen(at_commands[i]), 0);
printk("at_commands[i] = %s\n", at_commands[i]);
printk("strlen(at_commands[i]) = %u\n", strlen(at_commands[i]));
if (bytes_sent < 0) {
close(at_sock);
printk("Error2\n");
return -1;
}
do {
bytes_received = recv(at_sock, buf, 2, 0); // this is not successful
} while (bytes_received == 0);
printk("buf = %s\n", buf); // "ER"
if (memcmp(buf, "OK", 2) != 0) {
close(at_sock);
printk("Error3\n"); // reach here
return -1;
}
}
close(at_sock);
return 0;
}
static int init_gps(void)
{
u16_t fix_retry = 0;
u16_t fix_interval = 1;
u16_t nmea_mask = NRF_CONFIG_NMEA_GSV_MASK |
NRF_CONFIG_NMEA_GSA_MASK |
NRF_CONFIG_NMEA_GLL_MASK |
NRF_CONFIG_NMEA_GGA_MASK |
NRF_CONFIG_NMEA_RMC_MASK;
int retval;
if (configure_gps_off_on(GPS_EN) != 0) {
printk("Failed to enable GPS\n");
return -1;
}
fd = nrf_socket(NRF_AF_LOCAL, NRF_SOCK_DGRAM, NRF_PROTO_GNSS);
if (fd >= 0) {
printk("Socket created\n");
} else {
printk("Could not init socket (err: %d)\n", fd);
return -1;
}
retval = nrf_setsockopt(fd,
NRF_SOL_GNSS,
NRF_SO_GNSS_FIX_RETRY,
&fix_retry,
sizeof(uint16_t));
if (retval != 0) {
printk("Failed to set fix retry value\n");
return -1;
}
retval = nrf_setsockopt(fd,
NRF_SOL_GNSS,
NRF_SO_GNSS_FIX_INTERVAL,
&fix_interval,
sizeof(uint16_t));
if (retval != 0) {
printk("Failed to set fix interval value\n");
return -1;
}
retval = nrf_setsockopt(fd,
NRF_SOL_GNSS,
NRF_SO_GNSS_NMEA_MASK,
&nmea_mask,
sizeof(uint16_t));
if (retval != 0) {
printk("Failed to set nmea mask\n");
return -1;
}
retval = nrf_setsockopt(fd,
NRF_SOL_GNSS,
NRF_SO_GNSS_START,
NULL,
0);
if (retval != 0) {
printk("Failed to start GPS\n");
return -1;
}
return 0;
}
int process_gps_data(nrf_gnss_data_frame_t *gps_data)
{
int retval;
retval = nrf_recv(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:
if ((gps_data->pvt.flags &
NRF_GNSS_PVT_FLAG_FIX_VALID_BIT)
== NRF_GNSS_PVT_FLAG_FIX_VALID_BIT) {
if (!got_first_fix) {
got_first_fix = true;
}
fix_timestamp = k_uptime_get();
memcpy(&last_fix, gps_data, sizeof(nrf_gnss_data_frame_t));
nmea_string_cnt = 0;
update_terminal = true;
}
break;
case NRF_GNSS_NMEA_DATA_ID:
if (nmea_string_cnt < 10) {
memcpy(nmea_strings[nmea_string_cnt++],
gps_data->nmea,
retval);
}
break;
default:
break;
}
}
return retval;
}
static void print_pvt_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);
}
/**@brief Function to print strings without null-termination
*/
static void data_print(u8_t *prefix, u8_t *data, size_t len)
{
char buf[len + 1];
memcpy(buf, data, len);
buf[len] = 0;
printk("%s%s\n", prefix, buf);
}
/**@brief Function to publish data on the configured topic
*/
static int data_publish(struct mqtt_client *c, enum mqtt_qos qos,
u8_t *data, size_t len)
{
struct mqtt_publish_param param;
param.message.topic.qos = qos;
param.message.topic.topic.utf8 = CONFIG_MQTT_PUB_TOPIC;
param.message.topic.topic.size = strlen(CONFIG_MQTT_PUB_TOPIC);
param.message.payload.data = data;
param.message.payload.len = len;
param.message_id = sys_rand32_get();
param.dup_flag = 0;
param.retain_flag = 0;
data_print("Publishing: ", data, len);
printk("to topic: %s len: %u\n",
CONFIG_MQTT_PUB_TOPIC,
(unsigned int)strlen(CONFIG_MQTT_PUB_TOPIC));
return mqtt_publish(c, ¶m);
}
/**@brief Function to subscribe to the configured topic
*/
static int subscribe(void)
{
struct mqtt_topic subscribe_topic = {
.topic = {
.utf8 = CONFIG_MQTT_SUB_TOPIC,
.size = strlen(CONFIG_MQTT_SUB_TOPIC)
},
.qos = MQTT_QOS_1_AT_LEAST_ONCE
};
const struct mqtt_subscription_list subscription_list = {
.list = &subscribe_topic,
.list_count = 1,
.message_id = 1234
};
printk("Subscribing to: %s len %u\n", CONFIG_MQTT_SUB_TOPIC,
(unsigned int)strlen(CONFIG_MQTT_SUB_TOPIC));
return mqtt_subscribe(&client, &subscription_list);
}
/**@brief Function to read the published payload.
*/
static int publish_get_payload(struct mqtt_client *c, size_t length)
{
u8_t *buf = payload_buf;
u8_t *end = buf + length;
if (length > sizeof(payload_buf)) {
return -EMSGSIZE;
}
while (buf < end) {
int ret = mqtt_read_publish_payload(c, buf, end - buf);
if (ret < 0) {
int err;
if (ret != -EAGAIN) {
return ret;
}
printk("mqtt_read_publish_payload: EAGAIN\n");
err = poll(&fds, 1, K_SECONDS(CONFIG_MQTT_KEEPALIVE));
if (err > 0 && (fds.revents & POLLIN) == POLLIN) {
continue;
} else {
return -EIO;
}
}
if (ret == 0) {
return -EIO;
}
buf += ret;
}
return 0;
}
/**@brief MQTT client event handler
*/
void mqtt_evt_handler(struct mqtt_client *const c,
const struct mqtt_evt *evt)
{
int err;
switch (evt->type) {
case MQTT_EVT_CONNACK:
if (evt->result != 0) {
printk("MQTT connect failed %d\n", evt->result);
break;
}
connected = true;
printk("[%s:%d] MQTT client connected!\n", __func__, __LINE__);
subscribe();
break;
case MQTT_EVT_DISCONNECT:
printk("[%s:%d] MQTT client disconnected %d\n", __func__,
__LINE__, evt->result);
connected = false;
break;
case MQTT_EVT_PUBLISH: {
const struct mqtt_publish_param *p = &evt->param.publish;
printk("[%s:%d] MQTT PUBLISH result=%d len=%d\n", __func__,
__LINE__, evt->result, p->message.payload.len);
err = publish_get_payload(c, p->message.payload.len);
if (err >= 0) {
data_print("Received: ", payload_buf,
p->message.payload.len);
/* Echo back received data */
data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE,
payload_buf, p->message.payload.len);
} else {
printk("mqtt_read_publish_payload: Failed! %d\n", err);
printk("Disconnecting MQTT client...\n");
err = mqtt_disconnect(c);
if (err) {
printk("Could not disconnect: %d\n", err);
}
}
} break;
case MQTT_EVT_PUBACK:
if (evt->result != 0) {
printk("MQTT PUBACK error %d\n", evt->result);
break;
}
printk("[%s:%d] PUBACK packet id: %u\n", __func__, __LINE__,
evt->param.puback.message_id);
break;
case MQTT_EVT_SUBACK:
if (evt->result != 0) {
printk("MQTT SUBACK error %d\n", evt->result);
break;
}
printk("[%s:%d] SUBACK packet id: %u\n", __func__, __LINE__,
evt->param.suback.message_id);
break;
default:
printk("[%s:%d] default: %d\n", __func__, __LINE__,
evt->type);
break;
}
}
/**@brief Resolves the configured hostname and
* initializes the MQTT broker structure
*/
static void broker_init(void)
{
int err;
struct addrinfo *result;
struct addrinfo *addr;
struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM
};
err = getaddrinfo(CONFIG_MQTT_BROKER_HOSTNAME, NULL, &hints, &result);
if (err) {
printk("ERROR: getaddrinfo failed %d\n", err);
return;
}
addr = result;
err = -ENOENT;
/* Look for address of the broker. */
while (addr != NULL) {
/* IPv4 Address. */
if (addr->ai_addrlen == sizeof(struct sockaddr_in)) {
struct sockaddr_in *broker4 =
((struct sockaddr_in *)&broker);
char ipv4_addr[NET_IPV4_ADDR_LEN];
broker4->sin_addr.s_addr =
((struct sockaddr_in *)addr->ai_addr)
->sin_addr.s_addr;
broker4->sin_family = AF_INET;
broker4->sin_port = htons(CONFIG_MQTT_BROKER_PORT);
inet_ntop(AF_INET, &broker4->sin_addr.s_addr,
ipv4_addr, sizeof(ipv4_addr));
printk("IPv4 Address found %s\n", ipv4_addr);
break;
} else {
printk("ai_addrlen = %u should be %u or %u\n",
(unsigned int)addr->ai_addrlen,
(unsigned int)sizeof(struct sockaddr_in),
(unsigned int)sizeof(struct sockaddr_in6));
}
addr = addr->ai_next;
break;
}
/* Free the address. */
freeaddrinfo(result);
}
/**@brief Initialize the MQTT client structure
*/
static void client_init(struct mqtt_client *client)
{
mqtt_client_init(client);
broker_init();
static struct mqtt_utf8 password;
static struct mqtt_utf8 user_name;
password.utf8 = (u8_t*)MQTT_PASSWORD;
password.size = strlen(MQTT_PASSWORD);
user_name.utf8 = (u8_t*)MQTT_USERNAME;
user_name.size = strlen(MQTT_USERNAME);
/* MQTT client configuration */
client->broker = &broker;
client->evt_cb = mqtt_evt_handler;
client->client_id.utf8 = (u8_t *)CONFIG_MQTT_CLIENT_ID;
client->client_id.size = strlen(CONFIG_MQTT_CLIENT_ID);
client->password = &password;
client->user_name = &user_name;
client->protocol_version = MQTT_VERSION_3_1_1;
/* MQTT buffers configuration */
client->rx_buf = rx_buffer;
client->rx_buf_size = sizeof(rx_buffer);
client->tx_buf = tx_buffer;
client->tx_buf_size = sizeof(tx_buffer);
/* MQTT transport configuration */
client->transport.type = MQTT_TRANSPORT_NON_SECURE;
}
/**@brief Initialize the file descriptor structure used by poll.
*/
static int fds_init(struct mqtt_client *c)
{
if (c->transport.type == MQTT_TRANSPORT_NON_SECURE) {
fds.fd = c->transport.tcp.sock;
} else {
#if defined(CONFIG_MQTT_LIB_TLS)
fds.fd = c->transport.tls.sock;
#else
return -ENOTSUP;
#endif
}
fds.events = POLLIN;
return 0;
}
/**@brief Configures modem to provide LTE link. Blocks until link is
* successfully established.
*/
static void modem_configure(void)
{
#if defined(CONFIG_LTE_LINK_CONTROL)
if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT)) {
/* Do nothing, modem is already turned on
* and connected.
*/
} else {
int err;
printk("LTE Link Connecting ...\n");
err = lte_lc_init_and_connect();
__ASSERT(err == 0, "LTE link could not be established.");
printk("LTE Link Connected!\n");
}
#endif
}
int8_t poll_and_check_rcv_data(u32_t interval_msec){
int err = poll(&fds, 1, interval_msec); // Check if any data comes through LTE-M. When it is waiting for an incoming data, it sleeps
int8_t ret = 0;
if (err < 0) {
printk("ERROR: poll %d\n", errno);
return -1;
}
/* Check if data is received through LTE-M */
/* Caution!! These are mandatory */
if ((fds.revents & POLLIN) == POLLIN) {
err = mqtt_input(&client); // if a publish event comes, mqtt_evt_handler is called here
if (err != 0) {
printk("ERROR: mqtt_input %d\n", err);
return -1;
}
}
if ((fds.revents & POLLERR) == POLLERR) {
printk("POLLERR\n");
return -1;
}
if ((fds.revents & POLLNVAL) == POLLNVAL) {
printk("POLLNVAL\n");
return -1;
}
return ret;
}
void main(void)
{
int err;
printk("The MQTT simple sample started\n");
modem_configure();
client_init(&client);
err = mqtt_connect(&client);
if (err != 0) {
printk("ERROR: mqtt_connect %d\n", err);
return;
}
err = fds_init(&client);
if (err != 0) {
printk("ERROR: fds_init %d\n", err);
return;
}
poll_and_check_rcv_data(K_SECONDS(5));
/* GPS variables */
nrf_gnss_data_frame_t gps_data;
while (1) {
printk("Staring GPS application\n");
if (init_gps() != 0) {
printk("init_app fail\n");
}
printk("Getting GPS data...\n");
do {
/* Loop until we don't have more
* data to read
*/
} while (process_gps_data(&gps_data) > 0);
printk("---------------------------------\n");
print_pvt_data(&last_fix);
/* If gps data is broken, get it again */
printk("---------------------------------\n");
configure_gps_off_on(GPS_DIS);
k_sleep(K_SECONDS(20));
}
}
<result> ***** Booting Zephyr OS v1.14.99-ncs2-rc3 ***** The MQTT simple sample started LTE Link Connecting ... LTE Link Connected! IPv4 Address found xxx.xx.xx.xxx [mqtt_evt_handler:389] MQTT client connected! Subscribing to: my/subscribe/topic len 18 Staring GPS application at_commands[0] = AT%XSYSTEMMODE=1,0,1,0 at_commands[1] = AT%XMAGPIO=1,0,0,1,1,1574,1577 at_commands[2] = AT+CFUN=1 at_sock = 4 at_commands[i] = AT%XSYSTEMMODE=1,0,1,0 strlen(at_commands[i]) = 22 buf = ER Error3 Failed to enable GPS init_app fail Getting GPS data... --------------------------------- Longitude: 0.000000 Latitude: 0.000000 Altitude: 0.000000 Speed: 0.000000 Heading: 0.000000 Date: 00-00-00 Time (UTC): 00:00:00 --------------------------------- at_commands[0] = AT%XSYSTEMMODE=1,0,0,0 at_commands[1] = AT%XMAGPIO at_commands[2] = AT+CFUN=1 at_sock = 4 at_commands[i] = AT%XSYSTEMMODE=1,0,0,0 strlen(at_commands[i]) = 22 buf = ER Error3