GNSS Development Guide_V1.3

Chinese

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 fix parameter in section 4.4
2. Added notes for the NT26KCNE20GNB model change
3. Added the gnss_ic_model parameter description in section 4.2
4. Added section 4.8 for the liot_gnss_ic_model_e type
5. Updated the code example
6. Added special notes for NT26KCNE20GNB in the notes section

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 gnss_ic_model as GNSS_IC_CC1161W; configure gnsscfg_type according to the required positioning system combination

NT26KCNE20GNB / NT26K2E1_0G

CC1177W

Supports only BeiDou positioning

Configure gnss_ic_model as GNSS_IC_CC1177W; configure gnsscfg_type as LIOT_GNSS_CFG_TYPE_BEIDOU

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

liot_gnss_config()

Configure GNSS module parameters

liot_agnss_config()

Configure AGNSS parameters

liot_gnss_open()

Open the GNSS module

liot_gnss_close()

Close the GNSS module

liot_gnss_get_location()

Get positioning information

liot_gnss_get_nmea()

Get specified NMEA sentences

liot_gnss_close_backup_power()

Close the GNSS chip backup power

4 Type Descriptions

4.1 liot_gnss_errcode_e

GNSS API execution result error codes.

  1. Declaration

typedef enum
{
    LIOT_GNSS_SUCCESS = LIOT_SUCCESS,
    LIOT_GNSS_EXECUTE_ERR = 1,
    LIOT_GNSS_PARAM_ERR,
} liot_gnss_errcode_e;
  1. 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.

  1. 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;
  1. Parameters

  • gnss_ic_model: GNSS positioning chip model. It can be configured as GNSS_IC_CC1161W or GNSS_IC_CC1177W. For parameter meanings, see section 4.8 liot_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 to liot_gnss_nmea_type_e.

  • gnsscfg_type: Positioning system used by GNSS. Different binary bits correspond to different positioning systems. Configurable values correspond to liot_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 and liot_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.

  1. 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;
  1. 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 is LIERDA_GNSS_APGS_URL_MAX. A custom server must be compatible with the AGNSS service protocol used by the module and must support authentication with cid, mid, and pw.

  • 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.

  1. 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;
  1. 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 when fix equals 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.

  1. 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;
  1. 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.

  1. 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;
  1. 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.

  1. 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;
  1. 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.

  1. Declaration

typedef enum
{
    GNSS_IC_CC1161W = 0,
    GNSS_IC_CC1177W,
} liot_gnss_ic_model_e;
  1. 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.

  1. Declaration

typedef void (*LiotGnssEventCb) (liot_gnss_event_type_e event, uint8_t *data, uint16_t datalen);
  1. 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.

  1. Declaration

liot_gnss_errcode_e liot_gnss_config(liot_gnss_config_t *config);
  1. Parameters

  • config: [In] GNSS configuration information. See section 4.2 liot_gnss_config_t.

  1. 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.

  1. Declaration

liot_gnss_errcode_e liot_agnss_config(liot_agnss_config_t *config);
  1. Parameters

  • config: [In] AGNSS configuration information. See section 4.3 liot_agnss_config_t.

  1. Return Value

  • LIOT_GNSS_SUCCESS: Configuration succeeded.

5.3 liot_gnss_open

This function is used to open GNSS.

  1. Declaration

liot_gnss_errcode_e liot_gnss_open(LiotGnssEventCb event_cb);
  1. Parameters

  • event_cb: [In] GNSS event callback function. See section 4.9 LiotGnssEventCb.

  1. 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.

  1. Declaration

liot_gnss_errcode_e liot_gnss_close(void);
  1. 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.

  1. Declaration

liot_gnss_errcode_e liot_gnss_get_location(liot_gnss_loc_info_t *loc_info);
  1. Parameters

  • loc_info: [Out] GNSS positioning information. See section 4.4 liot_gnss_loc_info_t.

  1. Return Value

  • LIOT_GNSS_SUCCESS: Positioning information obtained successfully.

5.6 liot_gnss_get_nmea

This function is used to obtain specified NMEA sentences.

  1. Declaration

liot_gnss_errcode_e liot_gnss_get_nmea(uint16_t nmea_type, char *respBuf[], uint16_t respMaxNumber, uint16_t *respNumber);
  1. Parameters

  • nmea_type: [In] NMEA sentence type. Different binary bits correspond to different NMEA sentences. Configurable values correspond to section 4.6 liot_gnss_nmea_type_e.

  • respBuf: [Out] String pointer array used to return NMEA sentences. After the function succeeds, it dynamically allocates memory for the first respNumber pointers in the respBuf array and stores each NMEA sentence in the corresponding memory. After the data is used, the user must release each allocated string pointer in respBuf one 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.

  1. 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.

  1. Declaration

liot_gnss_errcode_e liot_gnss_close_backup_power(void);
  1. 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:

  1. liot_gnss_demo_thread() creates the message queue, GNSS work timer, and restart timer after startup.

  2. start_gnss_module() configures and opens GNSS. By default, it uses GNSS_TEST_E1_0G, that is, GNSS_IC_CC1177W with BeiDou-only positioning.

  3. 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.

  4. GNSS runs for GNSS_WORK_TIMEOUT, then closes, waits for GNSS_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

  1. Configuration first: Before starting GNSS, parameter configuration must be completed. In the example, start_gnss_module() first configures gnss_ic_model and gnsscfg_type according to the module model, and then calls liot_gnss_config() to write GNSS parameters. If AGNSS is required, liot_agnss_config() should also be called first to configure assisted positioning parameters.

  2. 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 the liot_gnss_demo_event() callback. The application layer should not assume that GNSS positioning has completed when liot_gnss_open() returns.

  3. 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 calls liot_rtos_queue_wait() to wait for and process events. When LIOT_GNSS_EVENT_GNSS_READY is received, gnss_ready_state is set to 1, indicating that GNSS is ready. This is the way the example waits for asynchronous readiness.

Run result:

_images/gnss-guide/image_1.png
_images/gnss-guide/image_2.png

7 Notes

  1. 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.

  2. 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_model parameter correctly according to the module model.

  3. 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.

  4. Enabling assisted positioning can improve positioning accuracy.

  5. The current example defines GNSS_TEST_E1_0G by default. To test GNSS_TEST_E0_0G, switch the corresponding macro and configure GNSS_IC_CC1161W and GPS + BeiDou fused positioning according to the source code.

  6. In the current example, GNSS_WORK_TIMEOUT is 60 seconds and GNSS_RESTART_TIMEOUT is 10 seconds. GNSS runs for 60 seconds after opening, then closes, waits for 10 seconds, and restarts.

  7. The NMEA strings returned by liot_gnss_get_nmea() are allocated by the API. The example uses liot_rtos_free() to release them.

  8. The data pointer in the callback should not be stored for long-term use after the callback returns. In the LIOT_GNSS_EVENT_GNSS_NMEA event, the example copies NMEA data first and then processes it through the queue.

  9. In the current example, when AGNSS_DEMO_ENABLE is 1, liot_agnss_config(NULL) is called and the code waits for 10 seconds, but gnss_config.agnss_mode is set to 0. If AGNSS is required in a production product, configure valid liot_agnss_config_t parameters according to the actual platform and enable agnss_mode accordingly.