GNSS Development Guide_V1.3
1 Revision History
Version |
Date |
Author |
Revision Description |
|---|---|---|---|
Rev1.0 |
2024-11-25 |
WTY |
Initial document creation |
Rev1.1 |
2025-02-19 |
WTY |
1. Updated the description of the |
Rev1.2 |
2025-08-11 |
ZLC |
Updated positioning system description |
Rev1.3 |
2026-07-23 |
ZXQ |
Updated according to review suggestions and added module descriptions for NT26K2E0_0G and NT26K2E1_0G |
2 Introduction
2.1 GNSS Feature Overview
This document describes the LTE-EC71X GNSS API. The API is declared in components/kernel/lierda_api/liot_gnss/liot_gnss.h.
GNSS data comes from the GNSS positioning chip inside the module. The GNSS chip receives satellite navigation signals and outputs NMEA data. The application layer can call liot_gnss_get_nmea() to obtain specified raw NMEA sentences, or call liot_gnss_get_location() to obtain positioning information parsed by the SDK, including UTC time, latitude and longitude, altitude, course, speed, positioning status, HDOP horizontal dilution of precision, and the number of satellites used in the solution.
The precision indicators in this document are based on API output fields, mainly including hdop, fix, and satcount. hdop indicates the horizontal dilution of precision, fix indicates the positioning mode, and satcount indicates the number of satellites used in the solution. Actual positioning accuracy is affected by satellite signal quality, antenna design, installation position, obstruction environment, and whether AGNSS is enabled. This document does not guarantee a fixed meter-level accuracy.
Currently, only Lierda NT26KCNE20GNA, NT26KCNE20GNB, NT26K2E0_0G, and NT26K2E1_0G modules support GNSS positioning. The NT26KCNE20GNA/NT26K2E0_0G module uses the CC1161W positioning chip internally and supports GPS, BeiDou, Galileo, and GLONASS multi-system positioning. The positioning system combination can be configured through the gnsscfg_type parameter in liot_gnss_config_t. The NT26KCNE20GNB/NT26K2E1_0G module uses the CC1177W positioning chip internally and supports only BeiDou positioning. If gnsscfg_type is configured for other satellite systems, the configuration does not take effect.
The demo program is located in examples/demo/src/demo_gnss.c. When APPDEMO_GNSS_EN is enabled, it creates liot_gnss_demo_thread. The demo uses an event queue to process GNSS callbacks and one-shot timers to control GNSS shutdown and restart. The current default macro is GNSS_TEST_E1_0G, which configures GNSS_IC_CC1177W and BeiDou-only positioning.
2.2 Platform GNSS Core Concepts
2.2.1 GNSS / BDS
GNSS is the general term for global navigation satellite systems, including GPS, BeiDou, GLONASS, Galileo, and other systems. BDS (BeiDou) is China’s satellite navigation system.
2.2.2 Positioning Mode (Fix)
fix indicates the current GNSS positioning mode and is a key field for judging whether the positioning result is reliable.
Value |
Meaning |
|---|---|
1 |
Not positioned |
2 |
2D positioning |
3 |
3D positioning |
2D positioning usually requires at least 3 satellites for the solution and can only provide latitude and longitude information, with relatively lower positioning accuracy. 3D positioning usually requires at least 4 satellites for the solution and can provide latitude, longitude, and altitude information. It is the target state for obtaining reliable location data.
2.2.3 NMEA Sentences
NMEA is the standard data format output by GNSS receivers. Different NMEA sentences contain different types of information, such as position, time, speed, course, satellite list, and positioning quality.
Sentence |
Description |
|---|---|
GGA |
Positioning quality, UTC time, latitude and longitude, altitude, satellite count, etc. |
RMC |
Recommended minimum positioning information, including time, latitude and longitude, speed, course, etc. |
GSV |
Satellites in view |
GSA |
DOP precision factors and satellites used for positioning |
VTG |
Course over ground and ground speed |
GLL |
Latitude, longitude, and UTC time |
The application layer can call liot_gnss_get_nmea() to obtain specified NMEA sentences. If more detailed raw positioning information is required, customers can parse the corresponding NMEA sentences according to their service requirements.
2.2.4 AGNSS (Assisted Positioning)
AGNSS is an assisted GNSS positioning feature. It can use assistance information provided through the cellular network to accelerate the GNSS chip’s first positioning time (TTFF).
AGNSS depends on data call and network connectivity. Before using AGNSS, ensure that the cellular network is registered, data call is established, and the AGNSS server and authentication information are correctly configured. In the demo code, when AGNSS_DEMO_ENABLE is 1, liot_agnss_config(NULL) is called and the code waits for the related network process to complete. In production products, valid liot_agnss_config_t parameters should be configured according to the information assigned by the platform.
2.3 Module Support Differences
Different modules integrate different GNSS chips internally and support different satellite positioning systems. When calling liot_gnss_config(), users must correctly configure the gnss_ic_model and gnsscfg_type combination in liot_gnss_config_t according to the actual module model.
Module Model |
GNSS Chip |
Supported Positioning Systems |
Recommended Configuration |
|---|---|---|---|
NT26KCNE20GNA / NT26K2E0_0G |
CC1161W |
Supports GPS, BeiDou, GLONASS, and Galileo multi-mode fused positioning |
Configure |
NT26KCNE20GNB / NT26K2E1_0G |
CC1177W |
Supports only BeiDou positioning |
Configure |
NT26KCNE20GNB/NT26K2E1_0G supports only BeiDou positioning. Even if gnsscfg_type is configured as GPS, GLONASS, or Galileo, the configuration does not take effect.
3 API Function Overview
Function |
Description |
|---|---|
|
Configure GNSS module parameters |
|
Configure AGNSS parameters |
|
Open the GNSS module |
|
Close the GNSS module |
|
Get positioning information |
|
Get specified NMEA sentences |
|
Close the GNSS chip backup power |
4 Type Descriptions
4.1 liot_gnss_errcode_e
GNSS API execution result error codes.
Declaration
typedef enum
{
LIOT_GNSS_SUCCESS = LIOT_SUCCESS,
LIOT_GNSS_EXECUTE_ERR = 1,
LIOT_GNSS_PARAM_ERR,
} liot_gnss_errcode_e;
Parameters
LIOT_GNSS_SUCCESS: Function executed successfully.LIOT_GNSS_EXECUTE_ERR: Function execution error.LIOT_GNSS_PARAM_ERR: Input parameter error.
4.2 liot_gnss_config_t
GNSS module configuration parameters.
Declaration
typedef struct
{
liot_gnss_ic_model_e gnss_ic_model; // Can be configured as GNSS_IC_CC1161W or GNSS_IC_CC1177W
uint8_t gnssnmea_type; // Configure NMEA sentence output type
uint8_t gnsscfg_type; // Configure system combination for positioning
uint8_t apflash; // apflash switch
uint8_t agnss_mode; // agnss switch
} liot_gnss_config_t;
Parameters
gnss_ic_model: GNSS positioning chip model. It can be configured asGNSS_IC_CC1161WorGNSS_IC_CC1177W. For parameter meanings, see section 4.8liot_gnss_ic_model_e.gnssnmea_type: NMEA type output by GNSS through the callback function. Different binary bits correspond to different NMEA sentences. Configurable values correspond toliot_gnss_nmea_type_e.gnsscfg_type: Positioning system used by GNSS. Different binary bits correspond to different positioning systems. Configurable values correspond toliot_gnss_cfg_type_e.apflash: AP FLASH save switch. When configured as 1, the GNSS module saves key positioning assistance information to the module’s internal AP FLASH, such as the last position and ephemeris data, to speed up positioning during the next startup. This feature occupies internal FLASH space. Configure it as 0 to disable this feature.agnss_mode: AGNSS switch. When configured as 1, assisted positioning is enabled. Before using it, ensure that the cellular network connection is ready andliot_agnss_config()has been called to complete AGNSS parameter configuration. Configure it as 0 to disable AGNSS.
4.3 liot_agnss_config_t
AGNSS function configuration parameters.
Declaration
typedef struct
{
uint8_t agnss_url[LIERDA_GNSS_APGS_URL_MAX];
uint8_t cid[64];
uint8_t mid[64];
uint8_t pw[64];
} liot_agnss_config_t;
Parameters
agnss_url: AGNSS server address. It can be configured as a platform-provided or customer-provided AGNSS server domain name/address. The maximum length isLIERDA_GNSS_APGS_URL_MAX. A custom server must be compatible with the AGNSS service protocol used by the module and must support authentication withcid,mid, andpw.cid: AGNSS platform user name.mid: AGNSS platform customer identifier.pw: AGNSS platform password.
The current demo code calls liot_agnss_config(NULL) and does not demonstrate custom AGNSS server configuration. If a custom server is required in a production product, pass valid liot_agnss_config_t parameters.
4.4 liot_gnss_loc_info_t
Positioning information parameter structure.
Declaration
typedef struct {
uint8_t fs; // Positioning status: 0-No positioning, 1-Single point positioning, 2-Differential positioning
char utc[20]; // UTC time YYMMDDhhmmss.sss
char latitude[14]; // Latitude
char longitude[14]; // Longitude
char hdop[8]; // HDOP horizontal precision factor
char altitude[10]; // Altitude in meters
uint8_t fix; // Positioning status: 1-Not positioned, 2-2D positioning, 3-3D positioning
char cog[10]; // Ground course based on true north
char speedkm[10]; // Speed in kilometers per hour
char speedkn[10]; // Speed in knots
uint8_t satcount; // Number of satellites
} liot_gnss_loc_info_t;
Parameters
fs: Positioning status. 0-No positioning, 1-Single point positioning, 2-Differential positioning.utc: UTC time, in YYMMDDhhmmss.sss format.latitude: Latitude, in ddmm.mmmmN/S format (dd: degrees, range 00-89; mm.mmmm: minutes, range 00.0000-59.9999; N/S: north/south latitude).longitude: Longitude, in dddmm.mmmmE/W format (ddd: degrees, range 00-179; mm.mmmm: minutes, range 00.0000-59.9999; E/W: east/west longitude).hdop: Horizontal dilution of precision (HDOP). It reflects horizontal positioning precision. A smaller value indicates higher horizontal positioning precision.altitude: Antenna altitude. Unit: meters.fix: GNSS positioning mode. Values are: 1-Not positioned, 2-2D positioning, 3-3D positioning. Usually, location data is considered reliable only whenfixequals 3.cog: Ground course based on true north.speedkm: Ground speed. Unit: kilometers per hour.speedkn: Ground speed. Unit: knots.satcount: Number of satellites used in the position solution.
4.5 liot_gnss_event_type_e
Event types in GNSS event callbacks.
Declaration
typedef enum
{
LIOT_GNSS_EVENT_GNSS_ERROR = 0,
LIOT_GNSS_EVENT_GNSS_READY,
LIOT_GNSS_EVENT_GNSS_CLOSED,
LIOT_GNSS_EVENT_GNSS_NMEA,
LIOT_GNSS_EVENT_FARMWARE_OK,
LIOT_GNSS_EVENT_FARMWARE_ERROR,
LIOT_GNSS_EVENT_AGNSS_OK,
LIOT_GNSS_EVENT_AGNSS_ERROR,
} liot_gnss_event_type_e;
Parameters
LIOT_GNSS_EVENT_GNSS_ERROR: GNSS error occurred.LIOT_GNSS_EVENT_GNSS_READY: GNSS is ready.LIOT_GNSS_EVENT_GNSS_CLOSED: GNSS is closed.LIOT_GNSS_EVENT_GNSS_NMEA: GNSS outputs NMEA sentences.LIOT_GNSS_EVENT_FARMWARE_OK: GNSS firmware loaded successfully.LIOT_GNSS_EVENT_FARMWARE_ERROR: GNSS firmware loading failed.LIOT_GNSS_EVENT_AGNSS_OK: AGNSS configuration succeeded.LIOT_GNSS_EVENT_AGNSS_ERROR: AGNSS configuration failed.
4.6 liot_gnss_nmea_type_e
GNSS NMEA sentence configuration enumeration.
Declaration
typedef enum
{
LIOT_GNSS_NMEA_TYPE_GGA = 0x0001,
LIOT_GNSS_NMEA_TYPE_RMC = 0x0002,
LIOT_GNSS_NMEA_TYPE_GSV = 0x0004,
LIOT_GNSS_NMEA_TYPE_GSA = 0x0008,
LIOT_GNSS_NMEA_TYPE_VTG = 0x0010,
LIOT_GNSS_NMEA_TYPE_GLL = 0x0020,
} liot_gnss_nmea_type_e;
Parameters
LIOT_GNSS_NMEA_TYPE_GGA: GGA sentence.LIOT_GNSS_NMEA_TYPE_RMC: RMC sentence.LIOT_GNSS_NMEA_TYPE_GSV: GSV sentence.LIOT_GNSS_NMEA_TYPE_GSA: GSA sentence.LIOT_GNSS_NMEA_TYPE_VTG: VTG sentence.LIOT_GNSS_NMEA_TYPE_GLL: GLL sentence.
4.7 liot_gnss_cfg_type_e
GNSS positioning system configuration enumeration.
Declaration
typedef enum
{
LIOT_GNSS_CFG_TYPE_GPS = 0x01,
LIOT_GNSS_CFG_TYPE_BEIDOU = 0x02,
LIOT_GNSS_CFG_TYPE_GLONASS = 0x04,
LIOT_GNSS_CFG_TYPE_GALILEO = 0x08,
} liot_gnss_cfg_type_e;
Parameters
LIOT_GNSS_CFG_TYPE_GPS: GPS satellite system.LIOT_GNSS_CFG_TYPE_BEIDOU: BeiDou satellite system.LIOT_GNSS_CFG_TYPE_GLONASS: GLONASS satellite system.LIOT_GNSS_CFG_TYPE_GALILEO: Galileo satellite system.
4.8 liot_gnss_ic_model_e
GNSS positioning chip model.
Declaration
typedef enum
{
GNSS_IC_CC1161W = 0,
GNSS_IC_CC1177W,
} liot_gnss_ic_model_e;
Parameters
GNSS_IC_CC1161W: CC1161W positioning chip. It supports GPS, BeiDou, Galileo, and GLONASS multi-mode fused positioning.GNSS_IC_CC1177W: CC1177W positioning chip. It supports only BeiDou positioning.
4.9 LiotGnssEventCb
GNSS event callback function type.
Declaration
typedef void (*LiotGnssEventCb) (liot_gnss_event_type_e event, uint8_t *data, uint16_t datalen);
Parameters
event: Event type.data: Pointer to event-related data.datalen: Data length, in bytes.
5 API Function Details
5.1 liot_gnss_config
This function is used to configure GNSS parameters.
Declaration
liot_gnss_errcode_e liot_gnss_config(liot_gnss_config_t *config);
Parameters
config:[In]GNSS configuration information. See section 4.2liot_gnss_config_t.
Return Value
LIOT_GNSS_SUCCESS: Configuration succeeded.LIOT_GNSS_PARAM_ERR: Parameter error.
5.2 liot_agnss_config
This function is used to configure AGNSS parameters.
Declaration
liot_gnss_errcode_e liot_agnss_config(liot_agnss_config_t *config);
Parameters
config:[In]AGNSS configuration information. See section 4.3liot_agnss_config_t.
Return Value
LIOT_GNSS_SUCCESS: Configuration succeeded.
5.3 liot_gnss_open
This function is used to open GNSS.
Declaration
liot_gnss_errcode_e liot_gnss_open(LiotGnssEventCb event_cb);
Parameters
event_cb:[In]GNSS event callback function. See section 4.9LiotGnssEventCb.
Return Value
LIOT_GNSS_SUCCESS: GNSS module opened successfully.LIOT_GNSS_EXECUTE_ERR: Failed to open the GNSS module.
5.4 liot_gnss_close
This function is used to close GNSS.
Declaration
liot_gnss_errcode_e liot_gnss_close(void);
Return Value
LIOT_GNSS_SUCCESS: GNSS module closed successfully.LIOT_GNSS_EXECUTE_ERR: Failed to close the GNSS module.
5.5 liot_gnss_get_location
This function is used to obtain positioning information.
Declaration
liot_gnss_errcode_e liot_gnss_get_location(liot_gnss_loc_info_t *loc_info);
Parameters
loc_info:[Out]GNSS positioning information. See section 4.4liot_gnss_loc_info_t.
Return Value
LIOT_GNSS_SUCCESS: Positioning information obtained successfully.
5.6 liot_gnss_get_nmea
This function is used to obtain specified NMEA sentences.
Declaration
liot_gnss_errcode_e liot_gnss_get_nmea(uint16_t nmea_type, char *respBuf[], uint16_t respMaxNumber, uint16_t *respNumber);
Parameters
nmea_type:[In]NMEA sentence type. Different binary bits correspond to different NMEA sentences. Configurable values correspond to section 4.6liot_gnss_nmea_type_e.respBuf:[Out]String pointer array used to return NMEA sentences. After the function succeeds, it dynamically allocates memory for the firstrespNumberpointers in therespBufarray and stores each NMEA sentence in the corresponding memory. After the data is used, the user must release each allocated string pointer inrespBufone by one to avoid memory leaks. In the current OpenCPU example,liot_rtos_free()is used for release.respMaxNumber:[In]Maximum number of NMEA sentences that can be read.respNumber:[Out]Actual number of NMEA sentences read.
Return Value
LIOT_GNSS_SUCCESS: NMEA sentences obtained successfully.LIOT_GNSS_PARAM_ERR: Parameter error. No valid NMEA type was specified.LIOT_GNSS_EXECUTE_ERR: Failed to obtain NMEA sentences.
5.7 liot_gnss_close_backup_power
This function is used to forcibly close the GNSS module backup power. It can succeed only when the backup power is enabled.
Note: Closing the backup power clears positioning assistance information cached in the GNSS chip RAM. The next startup will be a cold start, and the first positioning time may become longer. Usually, this function is called only when the GNSS state needs to be completely reset.
Declaration
liot_gnss_errcode_e liot_gnss_close_backup_power(void);
Return Value
LIOT_GNSS_SUCCESS: Backup power closed successfully.LIOT_GNSS_EXECUTE_ERR: Failed to close backup power, or backup power is not enabled.
6 Code Example
The following example is consistent with the main logic in examples/demo/src/demo_gnss.c:
liot_gnss_demo_thread()creates the message queue, GNSS work timer, and restart timer after startup.start_gnss_module()configures and opens GNSS. By default, it usesGNSS_TEST_E1_0G, that is,GNSS_IC_CC1177Wwith BeiDou-only positioning.The GNSS callback
liot_gnss_demo_event()sends events to the queue for processing. NMEA data is copied first to avoid invalid use of the original pointer after the callback returns.GNSS runs for
GNSS_WORK_TIMEOUT, then closes, waits forGNSS_RESTART_TIMEOUT, and starts again.
#include <stdio.h>
#include <string.h>
#include "lierda_app_main.h"
#include "liot_os.h"
#include "liot_gnss.h"
#include "liot_datacall.h"
#define AGNSS_DEMO_ENABLE 1
#define GNSS_TEST_E1_0G
//#define GNSS_TEST_E0_0G
// Timer related definitions
#define GNSS_WORK_TIMEOUT (60*1000) // 1 minute
#define GNSS_RESTART_TIMEOUT (10*1000) // 10 seconds
char gnss_nmea_data[1024];
uint8_t gnss_ready_state = 0;
// Global queue handles and timer handles
liot_queue_t gnss_queuehandle = NULL;
liot_timer_t gnss_work_timer = NULL;
liot_timer_t gnss_restart_timer = NULL;
#define GNSS_QUEUE_MAX 10
// Demo internal message type
typedef enum {
GNSS_DEMO_MSG_GNSS_EVENT = 0,
GNSS_DEMO_MSG_WORK_TIMEOUT,
GNSS_DEMO_MSG_RESTART_TIMEOUT
} gnss_demo_msg_type_e;
// GNSS event structure
typedef struct {
gnss_demo_msg_type_e msg_type;
liot_gnss_event_type_e event_type;
uint8_t *data;
uint16_t datalen;
uint8_t data_owned;
} gnss_event_msg_t;
// GNSS state enumeration
typedef enum {
GNSS_STATE_IDLE = 0,
GNSS_STATE_RUNNING,
GNSS_STATE_CLOSING,
GNSS_STATE_RESTARTING
} gnss_state_e;
gnss_state_e g_gnss_state = GNSS_STATE_IDLE;
static void gnss_demo_free_msg_data(gnss_event_msg_t *msg)
{
if(msg && msg->data_owned && msg->data)
{
liot_rtos_free(msg->data);
}
if(msg)
{
msg->data = NULL;
msg->datalen = 0;
msg->data_owned = 0;
}
}
static int gnss_demo_queue_send(gnss_event_msg_t *msg)
{
int ret = LIOT_SUCCESS;
if(msg == NULL || gnss_queuehandle == NULL)
{
gnss_demo_free_msg_data(msg);
liot_trace("GNSS demo queue is not ready");
return -1;
}
ret = liot_rtos_queue_release(gnss_queuehandle, sizeof(gnss_event_msg_t), (uint8 *)msg, 0);
if(ret != LIOT_SUCCESS)
{
gnss_demo_free_msg_data(msg);
liot_trace("GNSS demo queue send failed, ret=%d", ret);
}
return ret;
}
void liot_show_mem(void)
{
//Print out SRAM information
liot_trace("========== rtos Get TotalHeapSize:%dKB,FreeHeapSize:%dKB,MinFreeHeapSize:%dKB,MaxFreeBlockSize:%dKB",
(liot_xPortGetTotalHeapSize()) >> 10, (liot_xPortGetFreeHeapSize()) >> 10,
(liot_xPortGetMinimumEverFreeHeapSize()) >> 10, (liot_xPortGetMaximumFreeBlockSize()) >> 10);
}
/**
* @brief GNSS event callback function
* @details Sends GNSS events to message queue for processing
*/
void liot_gnss_demo_event(liot_gnss_event_type_e event, uint8_t *data, uint16_t datalen)
{
liot_trace("liot_gnss_demo_event %d", event);
gnss_event_msg_t event_msg = {0};
event_msg.msg_type = GNSS_DEMO_MSG_GNSS_EVENT;
event_msg.event_type = event;
event_msg.datalen = datalen;
// Note: For NMEA data, need to copy data content as original data pointer may become invalid after callback
if(data && datalen > 0 && (event == LIOT_GNSS_EVENT_GNSS_NMEA)) {
event_msg.data = liot_rtos_malloc(datalen + 1);
if(event_msg.data) {
memcpy(event_msg.data, data, datalen);
event_msg.data[datalen] = '\0';
event_msg.data_owned = 1;
} else {
liot_trace("GNSS NMEA data malloc failed, len=%d", datalen);
return;
}
} else {
event_msg.data = data;
}
gnss_demo_queue_send(&event_msg);
}
/**
* @brief 1 minute work timer callback function
* @details Closes GNSS module after timer timeout
*/
void gnss_work_timer_callback(void *param)
{
liot_trace("GNSS work timer timeout, closing GNSS...");
// Send internal close request to queue
gnss_event_msg_t close_msg = {0};
close_msg.msg_type = GNSS_DEMO_MSG_WORK_TIMEOUT;
close_msg.data = NULL;
close_msg.datalen = 0;
gnss_demo_queue_send(&close_msg);
}
/**
* @brief 10 second restart timer callback function
* @details Reopens GNSS module after timer timeout
*/
void gnss_restart_timer_callback(void *param)
{
liot_trace("GNSS restart timer timeout, restarting GNSS...");
// Send internal restart request to queue
gnss_event_msg_t restart_msg = {0};
restart_msg.msg_type = GNSS_DEMO_MSG_RESTART_TIMEOUT;
restart_msg.data = NULL;
restart_msg.datalen = 0;
gnss_demo_queue_send(&restart_msg);
}
/**
* @brief Get GNSS demo data
* @details Retrieves and prints GNSS positioning information and NMEA data
*/
void liot_gnss_get_demo_data(void)
{
liot_gnss_loc_info_t loc_info = {0};
char *nmea_data[10] = {NULL};
uint16_t nmea_data_len = 0;
liot_trace("get demo data...");
// Get NMEA data
if(liot_gnss_get_nmea(LIOT_GNSS_NMEA_TYPE_GSA, nmea_data, 10, &nmea_data_len) == LIOT_GNSS_SUCCESS)
{
for(int i=0; i<nmea_data_len; i++)
{
liot_trace("%s", nmea_data[i]);
liot_rtos_free(nmea_data[i]);
nmea_data[i] = NULL;
}
}
else
{
liot_trace("Failed to get GSA NMEA data");
}
nmea_data_len = 0;
if(liot_gnss_get_nmea(LIOT_GNSS_NMEA_TYPE_VTG, nmea_data, 10, &nmea_data_len) == LIOT_GNSS_SUCCESS)
{
for(int i=0; i<nmea_data_len; i++)
{
liot_trace("%s", nmea_data[i]);
liot_rtos_free(nmea_data[i]);
nmea_data[i] = NULL;
}
}
else
{
liot_trace("Failed to get VTG NMEA data");
}
// Get positioning information
memset(&loc_info, 0, sizeof(loc_info));
if(liot_gnss_get_location(&loc_info) == LIOT_GNSS_SUCCESS)
{
liot_trace("utc: %s, fix_type: %d, num_sats: %d", loc_info.utc, loc_info.fix, loc_info.satcount);
liot_trace("Latitude: %s, Longitude: %s", loc_info.latitude, loc_info.longitude);
}
else
{
liot_trace("Failed to get GNSS location");
}
}
/**
* @brief Start GNSS module
* @details Configures and opens GNSS module, starts work timer
*/
void start_gnss_module(void)
{
liot_gnss_config_t gnss_config = {0};
liot_trace("Starting GNSS module...");
// GNSS configuration
#if defined (GNSS_TEST_E0_0G)
gnss_config.gnss_ic_model = GNSS_IC_CC1161W;
gnss_config.gnsscfg_type = LIOT_GNSS_CFG_TYPE_GPS | LIOT_GNSS_CFG_TYPE_BEIDOU;
#elif defined (GNSS_TEST_E1_0G)
gnss_config.gnss_ic_model = GNSS_IC_CC1177W;
gnss_config.gnsscfg_type = LIOT_GNSS_CFG_TYPE_BEIDOU;
#endif
gnss_config.gnssnmea_type = LIOT_GNSS_NMEA_TYPE_GGA | LIOT_GNSS_NMEA_TYPE_GSA;
gnss_config.apflash = 0;
gnss_config.agnss_mode = 0;
#if AGNSS_DEMO_ENABLE
liot_agnss_config(NULL);
liot_rtos_task_sleep_ms(10000);
#endif
// Configure and open GNSS
if(liot_gnss_config(&gnss_config) != LIOT_GNSS_SUCCESS) {
g_gnss_state = GNSS_STATE_IDLE;
liot_trace("Failed to configure GNSS module");
return;
}
if(liot_gnss_open(liot_gnss_demo_event) == LIOT_GNSS_SUCCESS) {
g_gnss_state = GNSS_STATE_RUNNING;
liot_trace("GNSS module opened successfully");
// Start 1 minute work timer
liot_rtos_timer_start(gnss_work_timer, GNSS_WORK_TIMEOUT);
liot_trace("GNSS work timer started for %d ms", GNSS_WORK_TIMEOUT);
} else {
g_gnss_state = GNSS_STATE_IDLE;
liot_trace("Failed to open GNSS module");
}
}
/**
* @brief Stop GNSS module
* @details Closes GNSS module, starts restart timer
*/
void stop_gnss_module(void)
{
liot_trace("Stopping GNSS module...");
if(liot_gnss_close() == LIOT_GNSS_SUCCESS) {
g_gnss_state = GNSS_STATE_IDLE;
gnss_ready_state = 0;
liot_trace("GNSS module closed successfully");
// Start 10 second restart timer
liot_rtos_timer_start(gnss_restart_timer, GNSS_RESTART_TIMEOUT);
liot_trace("GNSS restart timer started for %d ms", GNSS_RESTART_TIMEOUT);
liot_show_mem();
} else {
g_gnss_state = GNSS_STATE_RUNNING;
liot_trace("Failed to close GNSS module");
}
}
/**
* @brief GNSS demo main thread
* @details Uses event-driven approach to handle GNSS operations and timer control
*/
void liot_gnss_demo_thread(void *argv)
{
gnss_event_msg_t event_msg = {0};
int ret = 0;
liot_rtos_task_sleep_ms(2000);
liot_trace("max--GNSS demo thread started");
// Create queue
if(liot_rtos_queue_create(&gnss_queuehandle, sizeof(gnss_event_msg_t), GNSS_QUEUE_MAX) != LIOT_SUCCESS)
{
liot_trace("Failed to create GNSS demo queue");
return;
}
// Create timers
if(liot_rtos_timer_create(&gnss_work_timer, LIOT_TimerOnce, gnss_work_timer_callback, NULL) != LIOT_SUCCESS)
{
liot_trace("Failed to create GNSS work timer");
return;
}
if(liot_rtos_timer_create(&gnss_restart_timer, LIOT_TimerOnce, gnss_restart_timer_callback, NULL) != LIOT_SUCCESS)
{
liot_trace("Failed to create GNSS restart timer");
return;
}
// Start GNSS module
start_gnss_module();
liot_trace("GNSS demo started, waiting for events...");
// Event processing loop
while(1)
{
ret = liot_rtos_queue_wait(gnss_queuehandle, (uint8 *)&event_msg, sizeof(gnss_event_msg_t), LIOT_WAIT_FOREVER);
if (ret != LIOT_SUCCESS)
{
continue;
}
// Process demo internal messages and GNSS events
switch(event_msg.msg_type)
{
case GNSS_DEMO_MSG_WORK_TIMEOUT:
{
if(g_gnss_state == GNSS_STATE_RUNNING)
{
g_gnss_state = GNSS_STATE_CLOSING;
stop_gnss_module();
}
else
{
liot_trace("Ignore GNSS work timeout in state %d", g_gnss_state);
}
}
break;
case GNSS_DEMO_MSG_RESTART_TIMEOUT:
{
if(g_gnss_state == GNSS_STATE_IDLE)
{
g_gnss_state = GNSS_STATE_RESTARTING;
start_gnss_module();
}
else
{
liot_trace("Ignore GNSS restart timeout in state %d", g_gnss_state);
}
}
break;
case GNSS_DEMO_MSG_GNSS_EVENT:
{
switch(event_msg.event_type)
{
case LIOT_GNSS_EVENT_GNSS_READY:
{
liot_trace("GNSS is ready");
gnss_ready_state = 1;
liot_show_mem();
}
break;
case LIOT_GNSS_EVENT_GNSS_NMEA:
{
if(event_msg.data && event_msg.datalen > 0)
{
uint16_t copy_len = event_msg.datalen;
if(copy_len >= sizeof(gnss_nmea_data))
{
copy_len = sizeof(gnss_nmea_data) - 1;
liot_trace("GNSS NMEA data truncated, len=%d", event_msg.datalen);
}
memset(gnss_nmea_data, 0, sizeof(gnss_nmea_data));
memcpy(gnss_nmea_data, (char *)event_msg.data, copy_len);
gnss_nmea_data[copy_len] = '\0';
liot_trace("GNSS NMEA: %s", gnss_nmea_data);
}
gnss_demo_free_msg_data(&event_msg);
}
break;
case LIOT_GNSS_EVENT_GNSS_CLOSED:
{
liot_trace("GNSS is closed");
}
break;
case LIOT_GNSS_EVENT_GNSS_ERROR:
{
liot_trace("GNSS error occurred");
}
break;
default:
{
liot_trace("Unknown GNSS event: %d", event_msg.event_type);
}
break;
}
}
break;
default:
{
liot_trace("Unknown GNSS demo message: %d", event_msg.msg_type);
}
break;
}
}
}
6.1 GNSS Startup Flow Analysis
Configuration first: Before starting GNSS, parameter configuration must be completed. In the example,
start_gnss_module()first configuresgnss_ic_modelandgnsscfg_typeaccording to the module model, and then callsliot_gnss_config()to write GNSS parameters. If AGNSS is required,liot_agnss_config()should also be called first to configure assisted positioning parameters.Event-driven flow:
liot_gnss_open()opens the GNSS module and registers the event callback. After the API succeeds, it returns immediately. GNSS ready, NMEA output, close, error, and other states are reported through theliot_gnss_demo_event()callback. The application layer should not assume that GNSS positioning has completed whenliot_gnss_open()returns.Asynchronous ready wait: The current example uses a message queue to wait for GNSS events.
liot_gnss_demo_event()sends callback events to the queue, and the main loop callsliot_rtos_queue_wait()to wait for and process events. WhenLIOT_GNSS_EVENT_GNSS_READYis received,gnss_ready_stateis set to 1, indicating that GNSS is ready. This is the way the example waits for asynchronous readiness.
Run result:
7 Notes
In this hardware version, the Cat.1 chip and GNSS chip are connected through UART2, and GNSS power is controlled by AGPIO3 and AGPIO5 of the Cat.1 chip. Do not reuse UART2, AGPIO3, or AGPIO5 for other functions; otherwise, the module may work abnormally.
The internal positioning chip of NT26KCNE20GNA/NT26K2E0_0G is CC1161W, and the internal positioning chip of NT26KCNE20GNB/NT26K2E1_0G is CC1177W. Configure the
gnss_ic_modelparameter correctly according to the module model.The CC1177W positioning chip inside NT26KCNE20GNB/NT26K2E1_0G supports only BeiDou positioning. If other parameters are configured in
gnsscfg_type, they do not take effect.Enabling assisted positioning can improve positioning accuracy.
The current example defines
GNSS_TEST_E1_0Gby default. To testGNSS_TEST_E0_0G, switch the corresponding macro and configureGNSS_IC_CC1161Wand GPS + BeiDou fused positioning according to the source code.In the current example,
GNSS_WORK_TIMEOUTis 60 seconds andGNSS_RESTART_TIMEOUTis 10 seconds. GNSS runs for 60 seconds after opening, then closes, waits for 10 seconds, and restarts.The NMEA strings returned by
liot_gnss_get_nmea()are allocated by the API. The example usesliot_rtos_free()to release them.The
datapointer in the callback should not be stored for long-term use after the callback returns. In theLIOT_GNSS_EVENT_GNSS_NMEAevent, the example copies NMEA data first and then processes it through the queue.In the current example, when
AGNSS_DEMO_ENABLEis 1,liot_agnss_config(NULL)is called and the code waits for 10 seconds, butgnss_config.agnss_modeis set to 0. If AGNSS is required in a production product, configure validliot_agnss_config_tparameters according to the actual platform and enableagnss_modeaccordingly.

