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

GPS stops updating timestamp after a few days of uptime indoors

GPS sample stops updating timestamp after a few days of uptime indoors


Tested devices: Thingy:91, nRF9160dk
Tested firmwares: mfw_nrf9160_1.2.1, mfw_nrf9160_1.2.2

Demo
https://youtu.be/i9pUtTnjjOo

Workaround:
Restart nRF9160. The issue will occur again within a couple of days.

  • Hi!

    Thanks for bringing this to our attention. I will try to reproduce this on my end, and I have also forwarded all the information in your ticket to the GPS team to take a look. 

    Perhaps it would be useful to take a modem trace from when this bug occurs. If that is at all possible on your end, that could be helpful. 

    Best regards,

    Heidi

  • Hi again! Could you please also provide us with the full log file?

    And are you using the GPS sample in NCS out-of-box or a modified version? If it's modified, please also provide your application code. 

  • Hello Heidi!

    Unfortunately I am working actively with my Thingy:91 and do not have a spare board to leave running for a few days. I also power off the computer over night, so the only possible way for capturing the modem trace would require another Thingy. I can also use my OpenWRT router to capture the data. The router firmware is compiled with support for ACM and I can see see the Thingy:91 messages. I also have a tool which forwards them to a TCP or UDP port. I can also save them to a file, but I lack a second Thingy.

    Since there were some limitations in the tagged release, I switched to master. I am currently on nrf
    commit e0d62535662ed6e04730b53f5c7b92fa58cedabf

    Then I made a tiny change that should not affect the behaviour of the GPS sample. On Thingy:91, one of the LEDs is turned on when there is a fix, and off otherwise. On the nRF9160dk, there is some additional code which sends (uart_ble_send) a copy of the NMEA data over the second UART, which is then routed to the BLE chip nRF52840, and then to my iPhone.

    I have experienced the issue on both Thingy:91 and nRF9160dk. connectivity_bridge for nRF9160dk has a few changes: route the second UART.TX from nRF9160 to nRF52840.RX. Any data arrived at nRF52840.RX is send to the USB nRF52840.TX just before it is sent over BLE.

    All projects are available in 4572.projects.7z here:

    https://devzone.nordicsemi.com/f/nordic-q-a/67372/connectivity_bridge-malfunctions-when-ble-client-disconnects-and-reconnects

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
    #include <zephyr.h>
    #include <zephyr/types.h>
    #include <sys/ring_buffer.h>
    
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/uuid.h>
    #include <bluetooth/gatt.h>
    #include <bluetooth/hci.h>
    #include <bluetooth/services/nus.h>
    
    #define MODULE ble_handler
    #include "module_state_event.h"
    #include "peer_conn_event.h"
    #include "ble_ctrl_event.h"
    #include "ble_data_event.h"
    #include "uart_data_event.h"
    
    #include <logging/log.h>
    LOG_MODULE_REGISTER(MODULE, CONFIG_BRIDGE_BLE_LOG_LEVEL);
    
    #define BLE_RX_BLOCK_SIZE (CONFIG_BT_L2CAP_TX_MTU - 3)
    #define BLE_RX_BUF_COUNT 4
    #define BLE_SLAB_ALIGNMENT 4
    
    #define BLE_TX_BUF_SIZE (CONFIG_BRIDGE_BUF_SIZE * 2)
    
    #define BLE_AD_IDX_FLAGS 0
    #define BLE_AD_IDX_NAME 1
    
    #define ATT_MIN_PAYLOAD 20 /* Minimum L2CAP MTU minus ATT header */
    
    static void bt_send_work_handler(struct k_work *work);
    
    K_MEM_SLAB_DEFINE(ble_rx_slab, BLE_RX_BLOCK_SIZE, BLE_RX_BUF_COUNT, BLE_SLAB_ALIGNMENT);
    RING_BUF_DECLARE(ble_tx_ring_buf, BLE_TX_BUF_SIZE);
    
    static K_SEM_DEFINE(ble_tx_sem, 0, 1);
    
    static K_WORK_DEFINE(bt_send_work, bt_send_work_handler);
    
    static struct bt_conn *current_conn;
    static struct bt_gatt_exchange_params exchange_params;
    static uint32_t nus_max_send_len;
    static atomic_t ready;
    static atomic_t active;
    
    static char bt_device_name[CONFIG_BT_DEVICE_NAME_MAX + 1] = CONFIG_BT_DEVICE_NAME;
    
    static struct bt_data ad[] = {
    	[BLE_AD_IDX_FLAGS] = BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    	[BLE_AD_IDX_NAME] = BT_DATA(BT_DATA_NAME_COMPLETE, bt_device_name, (sizeof(CONFIG_BT_DEVICE_NAME) - 1)),
    };
    
    static const struct bt_data sd[] = {
    	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL),
    };
    
    static void exchange_func(struct bt_conn *conn, uint8_t err,
    			  struct bt_gatt_exchange_params *params)
    {
    	if (!err) {
    		nus_max_send_len = bt_nus_get_mtu(conn);
    	}
    }
    
    static void connected(struct bt_conn *conn, uint8_t err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	if (err) {
    		LOG_WRN("Connection failed (err %u)", err);
    		return;
    	}
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    	LOG_INF("Connected %s", log_strdup(addr));
    
    	current_conn = bt_conn_ref(conn);
    	exchange_params.func = exchange_func;
    
    	err = bt_gatt_exchange_mtu(current_conn, &exchange_params);
    	if (err) {
    		LOG_WRN("bt_gatt_exchange_mtu: %d", err);
    	}
    
    	ring_buf_reset(&ble_tx_ring_buf);
    
    	struct peer_conn_event *event = new_peer_conn_event();
    
    	event->peer_id = PEER_ID_BLE;
    	event->dev_idx = 0;
    	event->baudrate = 0; /* Don't care */
    	event->conn_state = PEER_STATE_CONNECTED;
    	EVENT_SUBMIT(event);
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    	LOG_INF("Disconnected: %s (reason %u)", log_strdup(addr), reason);
    
    	if (current_conn) {
    		bt_conn_unref(current_conn);
    		current_conn = NULL;
    	}
    
    	struct peer_conn_event *event = new_peer_conn_event();
    
    	event->peer_id = PEER_ID_BLE;
    	event->dev_idx = 0;
    	event->baudrate = 0; /* Don't care */
    	event->conn_state = PEER_STATE_DISCONNECTED;
    	EVENT_SUBMIT(event);
    }
    
    static struct bt_conn_cb conn_callbacks = {
    	.connected    = connected,
    	.disconnected = disconnected,
    };
    
    static void bt_send_work_handler(struct k_work *work)
    {
    	uint16_t len;
    	uint8_t *buf;
    	int err;
    	bool notif_disabled = false;
    
    	do {
    		len = ring_buf_get_claim(&ble_tx_ring_buf, &buf, nus_max_send_len);
    
    		err = bt_nus_send(current_conn, buf, len);
    		if (err == -EINVAL) {
    			notif_disabled = true;
    			len = 0;
    		} else if (err) {
    			len = 0;
    		}
    
    		if (len)
    		{
    			uint16_t rem = len;
    			char msg[512];
    
    			while (rem)
    			{
    				uint16_t count = rem;
    
    				if (count > sizeof(msg) - 1)
    				{
    					count = sizeof(msg) - 1;
    				}
    
    				rem -= count;
    
    				memcpy(msg, buf, count);
    				msg[count] = '\0';
    				printk("%s", msg);
    			}
    		}
    
    
    		err = ring_buf_get_finish(&ble_tx_ring_buf, len);
    		if (err) {
    			LOG_ERR("ring_buf_get_finish: %d", err);
    			break;
    		}
    	} while (len != 0 && !ring_buf_is_empty(&ble_tx_ring_buf));
    
    	if (notif_disabled) {
    		/* Peer has not enabled notifications: don't accumulate data */
    		ring_buf_reset(&ble_tx_ring_buf);
    	}
    }
    
    static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data,
    			  uint16_t len)
    {
    	void *buf;
    	uint16_t remainder;
    
    	remainder = len;
    
    	do {
    		uint16_t copy_len;
    		int err;
    
    		err = k_mem_slab_alloc(&ble_rx_slab, &buf, K_NO_WAIT);
    		if (err) {
    			LOG_WRN("BLE RX overflow");
    			break;
    		}
    
    		copy_len = remainder > BLE_RX_BLOCK_SIZE ?
    			BLE_RX_BLOCK_SIZE : remainder;
    		remainder -= copy_len;
    		memcpy(buf, data, copy_len);
    
    		struct ble_data_event *event = new_ble_data_event();
    
    		event->buf = buf;
    		event->len = copy_len;
    		EVENT_SUBMIT(event);
    	} while (remainder);
    }
    
    static void bt_sent_cb(struct bt_conn *conn)
    {
    	if (ring_buf_is_empty(&ble_tx_ring_buf)) {
    		return;
    	}
    
    	k_work_submit(&bt_send_work);
    }
    
    static struct bt_nus_cb nus_cb = {
    	.received = bt_receive_cb,
    	.sent = bt_sent_cb,
    };
    
    static void adv_start(void)
    {
    	int err;
    
    	if (!atomic_get(&ready)) {
    		/* Advertising will start when ready */
    		return;
    	}
    
    	err = bt_le_adv_start(
    		BT_LE_ADV_PARAM(
    			BT_LE_ADV_OPT_CONNECTABLE,
    			BT_GAP_ADV_SLOW_INT_MIN,
    			BT_GAP_ADV_SLOW_INT_MAX,
    			NULL),
    		ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    	if (err) {
    		LOG_ERR("bt_le_adv_start: %d", err);
    	} else {
    		module_set_state(MODULE_STATE_READY);
    	}
    }
    
    static void adv_stop(void)
    {
    	int err;
    
    	err = bt_le_adv_stop();
    	if (err) {
    		LOG_ERR("bt_le_adv_stop: %d", err);
    	} else {
    		module_set_state(MODULE_STATE_STANDBY);
    	}
    }
    
    static void name_update(const char *name)
    {
    	int err;
    
    	err = bt_set_name(name);
    	if (err) {
    		LOG_WRN("bt_set_name: %d", err);
    		return;
    	}
    
    	strcpy(bt_device_name, name);
    	ad[BLE_AD_IDX_NAME].data_len = strlen(name);
    
    	err = bt_le_adv_update_data(ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    	if (err && err != -EAGAIN) {
    		/* Ignore error return when advertising is not running */
    		LOG_WRN("bt_le_adv_update_data: %d", err);
    		return;
    	}
    }
    
    static void bt_ready(int err)
    {
    	if (err) {
    		LOG_ERR("%s: %d", __func__, err);
    		return;
    	}
    
    	err = bt_nus_init(&nus_cb);
    	if (err) {
    		LOG_ERR("bt_nus_init: %d", err);
    		return;
    	}
    
    	atomic_set(&ready, true);
    
    #if CONFIG_BRIDGE_BLE_ALWAYS_ON
    	atomic_set(&active, true);
    #endif
    
    	if (atomic_get(&active)) {
    		adv_start();
    	}
    }
    
    static bool event_handler(const struct event_header *eh)
    {
    	if (is_uart_data_event(eh)) {
    		const struct uart_data_event *event =
    			cast_uart_data_event(eh);
    
    		/* Only one BLE Service instance, mapped to UART_0 */
    		if (event->dev_idx != 0) {
    			return false;
    		}
    
    		if (current_conn == NULL) {
    			return false;
    		}
    
    		uint32_t written = ring_buf_put(
    			&ble_tx_ring_buf,
    			event->buf,
    			event->len);
    		if (written != event->len) {
    			LOG_WRN("UART_%d -> BLE overflow", event->dev_idx);
    		}
    
    		uint32_t buf_utilization =
    			(ring_buf_capacity_get(&ble_tx_ring_buf) -
    			ring_buf_space_get(&ble_tx_ring_buf));
    
    		/* Simple check to start transmission. */
    		/* If bt_send_work is already running, this has no effect */
    		if (buf_utilization == written) {
    			k_work_submit(&bt_send_work);
    		}
    
    		return false;
    	}
    
    	if (is_ble_data_event(eh)) {
    		const struct ble_data_event *event =
    			cast_ble_data_event(eh);
    
    		/* All subscribers have gotten a chance to copy data at this point */
    		k_mem_slab_free(&ble_rx_slab, (void **) &event->buf);
    
    		return false;
    	}
    
    	if (is_ble_ctrl_event(eh)) {
    		const struct ble_ctrl_event *event =
    			cast_ble_ctrl_event(eh);
    
    		switch (event->cmd) {
    		case BLE_CTRL_ENABLE:
    			if (!atomic_set(&active, true)) {
    				adv_start();
    			}
    			break;
    		case BLE_CTRL_DISABLE:
    			if (atomic_set(&active, false)) {
    				adv_stop();
    			}
    			break;
    		case BLE_CTRL_NAME_UPDATE:
    			name_update(event->param.name_update);
    			break;
    		default:
    			/* Unhandled control message */
    			__ASSERT_NO_MSG(false);
    			break;
    		}
    
    		return false;
    	}
    
    	if (is_module_state_event(eh)) {
    		const struct module_state_event *event =
    			cast_module_state_event(eh);
    
    		if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
    			int err;
    
    			atomic_set(&active, false);
    
    			nus_max_send_len = ATT_MIN_PAYLOAD;
    
    			err = bt_enable(bt_ready);
    			if (err) {
    				LOG_ERR("bt_enable: %d", err);
    				return false;
    			}
    
    			bt_conn_cb_register(&conn_callbacks);
    		}
    
    		return false;
    	}
    
    	/* If event is unhandled, unsubscribe. */
    	__ASSERT_NO_MSG(false);
    
    	return false;
    }
    
    EVENT_LISTENER(MODULE, event_handler);
    EVENT_SUBSCRIBE(MODULE, module_state_event);
    EVENT_SUBSCRIBE(MODULE, ble_ctrl_event);
    EVENT_SUBSCRIBE(MODULE, uart_data_event);
    EVENT_SUBSCRIBE_FINAL(MODULE, ble_data_event);
    

    connectivity_bridge-Thingy91-merged.7zconnectivity_bridge-nrf9160dk-merged.7z

    GPS-Thingy91-merged.7z

     

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
    #include <zephyr.h>
    #include <nrf_socket.h>
    #include <net/socket.h>
    #include <stdio.h>
    #include <modem/at_cmd.h>
    #include <modem/at_notif.h>
    #include <tracing/tracing_format.h>
    #include <device.h>
    #include <devicetree.h>
    #include <drivers/gpio.h>
    
    #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 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);
    
    // The devicetree node identifier for the "led0" alias.
    #if CONFIG_BOARD_THINGY91_NRF9160NS
    //#define LED0_NODE DT_ALIAS(sense_led2)
    #define LED0_NODE DT_ALIAS(led2)
    #else
    #define LED0_NODE DT_ALIAS(led0)
    #endif
    
    #if DT_NODE_HAS_STATUS(LED0_NODE, okay)
    #define LED0	DT_GPIO_LABEL(LED0_NODE, gpios)
    #define PIN	DT_GPIO_PIN(LED0_NODE, gpios)
    #if DT_PHA_HAS_CELL(LED0_NODE, gpios, flags)
    #define FLAGS	DT_GPIO_FLAGS(LED0_NODE, gpios)
    #endif
    #else
    // A build error here means your board isn't set up to blink an LED.
    #error "Unsupported board: led0 devicetree alias is not defined"
    #define LED0	""
    #define PIN	0
    #endif
    
    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) {
    			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]);
    
    #if CONFIG_TRACING_TEST
    		TRACING_STRING("%s", nmea_strings[i]);
    #endif
    
    #if CONFIG_UART_BLE
    		int uart_ble_send(char * msg, uint16_t length);
    		uart_ble_send(nmea_strings[i], strlen(nmea_strings[i]));
    #endif
    	}
    }
    
    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
    
    int main(void)
    {
    	nrf_gnss_data_frame_t gps_data;
    	uint8_t		      cnt = 0;
    	const struct device * dev_led0 = device_get_binding(LED0);
    
    	if (dev_led0)
    	{
    		if (gpio_pin_configure(dev_led0, PIN, GPIO_OUTPUT_ACTIVE | FLAGS) < 0)
    		{
    			dev_led0 = NULL;
    		}
    	}
    
    #ifdef CONFIG_SUPL_CLIENT_LIB
    	static struct supl_api supl_api = {
    		.read       = supl_read,
    		.write      = supl_write,
    		.handler    = inject_agps_type,
    		.logger     = supl_logger,
    		.counter_ms = k_uptime_get
    	};
    #endif
    
    	printk("Starting GPS application\n");
    
    	if (init_app() != 0) {
    		return -1;
    	}
    
    #ifdef CONFIG_SUPL_CLIENT_LIB
    	int rc = supl_init(&supl_api);
    
    	if (rc != 0) {
    		return rc;
    	}
    #endif
    
    	printk("Getting GPS data...\n");
    
    	while (1) {
    
    		do {
    			/* Loop until we don't have more
    			 * data to read
    			 */
    		} while (process_gps_data(&gps_data) > 0);
    
    		if (dev_led0)
    		{
    			gpio_pin_set(dev_led0, PIN, (int)got_fix);
    		}
    
    		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("\nNMEA strings:\n\n");
    			print_nmea_data();
    			printk("---------------------------------");
    		}
    
    		k_sleep(K_MSEC(500));
    	}
    
    	return 0;
    }
    
    /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
     /** @file
      *  @brief Nordic UART Bridge Service (NUS) sample
      */
    
    #include <zephyr/types.h>
    #include <zephyr.h>
    #include <drivers/uart.h>
    
    #include <device.h>
    #include <soc.h>
    
    #include <dk_buttons_and_leds.h>
    
    #include <settings/settings.h>
    
    #include <stdio.h>
    
    #include <logging/log.h>
    #include "uart_ble.h"
    
    #define LOG_MODULE_NAME uart_ble
    LOG_MODULE_REGISTER(LOG_MODULE_NAME);
    
    #define PRIORITY 7
    
    #define RUN_LED_BLINK_INTERVAL 1000
    
    #define UART_BUF_SIZE 512//CONFIG_BRIDGE_BUF_SIZE
    #define UART_WAIT_FOR_BUF_DELAY K_MSEC(50)
    #define UART_RX_TIMEOUT_MS 1
    
    static K_SEM_DEFINE(ble_init_ok, 0, 1);
    
    const static struct device * uart = NULL;
    static struct k_delayed_work uart_work;
    
    struct uart_data_t
    {
    	void * fifo_reserved;
    	uint8_t data[UART_BUF_SIZE];
    	uint16_t len;
    };
    
    //static struct uart_data_t buffers_tx[8];
    static struct uart_data_t buffers_rx[4];
    //static int buffers_tx_index = 0;
    static int buffers_rx_index = 0;
    
    static K_FIFO_DEFINE(fifo_uart_tx_data);
    static K_FIFO_DEFINE(fifo_uart_rx_data);
    
    
    //static struct uart_data_t * get_buffers_tx()
    //{
    //	int index = buffers_tx_index++;
    //
    //	if (buffers_tx_index >= sizeof(buffers_tx) / sizeof(*buffers_tx))
    //	{
    //		buffers_tx_index = 0;
    //	}
    //
    //	return &buffers_tx[index];
    //}
    
    static struct uart_data_t * get_buffers_rx()
    {
    	int index = buffers_rx_index++;
    
    	if (buffers_rx_index >= sizeof(buffers_rx) / sizeof(*buffers_rx))
    	{
    		buffers_rx_index = 0;
    	}
    
    	return &buffers_rx[index];
    }
    
    static void uart_cb(const struct device * dev, struct uart_event * evt, void * user_data)
    {
    	ARG_UNUSED(dev);
    
    	static uint8_t * current_buf;
    	static size_t aborted_len;
    	static bool buf_release;
    	struct uart_data_t * buf;
    	static uint8_t * aborted_buf;
    
    	switch (evt->type)
    	{
    	case UART_TX_DONE:
    		if ((evt->data.tx.len == 0) || (!evt->data.tx.buf))
    		{
    			return;
    		}
    
    		if (aborted_buf)
    		{
    			buf = CONTAINER_OF(aborted_buf, struct uart_data_t, data);
    			aborted_buf = NULL;
    			aborted_len = 0;
    		}
    		else
    		{
    			buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t, data);
    		}
    
    		k_free(buf);
    
    		buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT);
    
    		if (!buf)
    		{
    			return;
    		}
    
    		if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS))
    		{
    			printk("Failed to send data over UART\n");
    		}
    
    		break;
    
    	case UART_RX_RDY:
    		buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data);
    		buf->len += evt->data.rx.len;
    		buf_release = false;
    
    		if (buf->len == UART_BUF_SIZE)
    		{
    			k_fifo_put(&fifo_uart_rx_data, buf);
    		}
    		else if (
    			(evt->data.rx.buf[buf->len - 1] == '\n') ||
    			(evt->data.rx.buf[buf->len - 1] == '\r')
    			)
    		{
    			k_fifo_put(&fifo_uart_rx_data, buf);
    			current_buf = evt->data.rx.buf;
    			buf_release = true;
    			uart_rx_disable(uart);
    		}
    
    		break;
    
    	case UART_RX_DISABLED:
    		buf = get_buffers_rx();
    
    		if (buffers_rx_index >= sizeof(buffers_rx) / sizeof(*buffers_rx))
    		{
    			buffers_rx_index = 0;
    		}
    
    		if (buf)
    		{
    			buf->len = 0;
    		}
    		else
    		{
    			printk("UART_RX_DISABLED: Not able to allocate UART receive buffer\n");
    			k_delayed_work_submit(&uart_work, UART_WAIT_FOR_BUF_DELAY);
    			return;
    		}
    
    		uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS);
    
    		break;
    
    	case UART_RX_BUF_REQUEST:
    		buf = get_buffers_rx();
    
    		if (buf)
    		{
    			buf->len = 0;
    			uart_rx_buf_rsp(uart, buf->data, sizeof(buf->data));
    		}
    		else
    		{
    			printk("UART_RX_BUF_REQUEST: Not able to allocate UART receive buffer\n");
    		}
    
    		break;
    
    	case UART_RX_BUF_RELEASED:
    		buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t, data);
    
    		if (buf_release && (current_buf != evt->data.rx_buf.buf))
    		{
    			buf_release = false;
    			current_buf = NULL;
    		}
    
    		break;
    
    	case UART_TX_ABORTED:
    		if (!aborted_buf)
    		{
    			aborted_buf = (uint8_t *)evt->data.tx.buf;
    		}
    
    		aborted_len += evt->data.tx.len;
    		buf = CONTAINER_OF(aborted_buf, struct uart_data_t, data);
    
    		uart_tx(uart, &buf->data[aborted_len], buf->len - aborted_len, SYS_FOREVER_MS);
    
    		break;
    
    	default:
    		break;
    	}
    }
    
    static void uart_work_handler(struct k_work * item)
    {
    	struct uart_data_t * buf;
    
    	buf = get_buffers_rx();
    
    	if (buf)
    	{
    		buf->len = 0;
    	}
    	else
    	{
    		printk("uart_work_handler: Not able to allocate UART receive buffer\n");
    		k_delayed_work_submit(&uart_work, UART_WAIT_FOR_BUF_DELAY);
    
    		return;
    	}
    
    	uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS);
    }
    
    static int uart_init(void)
    {
    	int err;
    	struct uart_data_t * rx;
    
    	uart = device_get_binding(DT_LABEL(DT_NODELABEL(uart1)));
    
    	if (!uart)
    	{
    		return -ENXIO;
    	}
    
    	rx = get_buffers_rx();
    
    	if (rx)
    	{
    		rx->len = 0;
    	}
    	else
    	{
    		return -ENOMEM;
    	}
    
    	k_delayed_work_init(&uart_work, uart_work_handler);
    
    	err = uart_callback_set(uart, uart_cb, NULL);
    
    	if (err)
    	{
    		return err;
    	}
    
    	return uart_rx_enable(uart, rx->data, sizeof(rx->data), 50);
    }
    
    void main_1(void)
    {
    	int err = 0;
    
    	err = uart_init();
    
    	if (err)
    	{
    		return;
    	}
    
    	k_sem_give(&ble_init_ok);
    
    	if (IS_ENABLED(CONFIG_SETTINGS))
    	{
    		settings_load();
    	}
    
    	printk("Starting Nordic UART service example\n");
    
    	for (;;)
    	{
    		k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
    	}
    }
    
    int uart_ble_send(char * msg, uint16_t length)
    {
    	if (!uart)
    	{
    		int err = uart_init();
    
    		if (err)
    		{
    			printk("Failed to init UART\n");
    			return -1;
    		}
    	}
    
    	struct uart_data_t * tx = k_malloc(sizeof(*tx));
    
    	if (!tx)
    	{
    		printk("uart_ble_send: unable to allocate UART send buffer\n");
    		return -1;
    	}
    
    	tx->len = MIN(length, sizeof(tx->data) - 1);
    
    	memcpy(tx->data, msg, tx->len);
    
    	if (uart_tx(uart, tx->data, length, SYS_FOREVER_MS))
    	{
    		k_fifo_put(&fifo_uart_tx_data, tx);
    	}
    
    	return 0;
    }
    
    /*
    void ble_write_thread(void)
    {
    	// Don't go any further until BLE is initialized
    	k_sem_take(&ble_init_ok, K_FOREVER);
    
    	for (;;)
    	{
    		// Wait indefinitely for data to be sent over bluetooth
    		struct uart_data_t * buf = k_fifo_get(&fifo_uart_rx_data, K_FOREVER);
    
    		//if (bt_gatt_nus_send(NULL, buf->data, buf->len))
    		//{
    		//	printk("Failed to send data over BLE connection\n");
    		//}
    
    		//-k_free(buf);
    	}
    }
    
    //K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL, NULL, PRIORITY, 0, 0);
    */
    
    uart_ble.h

  • Thank you! I will forward this and also try to reproduce the issue again with your application running.

  • Hi!

    This issue was reported with the GPS sample, which uses the new GNSS API in NCS 1.6.0. So updating to NCS 1.6.0 should be enough to fix this. The key is to use the new GNSS API (nrf_modem_gnss.h) instead of the GNSS socket (nrf_socket.h).

Related