GNSS 开发指导_V1.3
1 修订记录
版本 |
日期 |
作者 |
修订内容 |
|---|---|---|---|
Rev1.0 |
2024-11-25 |
WTY |
创建文档 |
Rev1.1 |
2025-02-19 |
WTY |
1. 修改 4.4 章节对 |
Rev1.2 |
2025-08-11 |
ZLC |
修改定位系统说明 |
Rev1.3 |
2026-07-23 |
ZXQ |
根据建议修改,增加 NT26K2E0_0G 和 NT26K2E1_0G 的模组说明 |
2 简介
2.1 GNSS 功能概述
本文档介绍 LTE-EC71X GNSS 接口 API 情况,API 接口位于 components/kernel/lierda_api/liot_gnss/liot_gnss.h 文件声明。
GNSS 数据来源于模组内部的 GNSS 定位芯片。GNSS 芯片接收卫星导航系统信号后输出 NMEA 数据,应用层可通过 liot_gnss_get_nmea() 获取指定类型的原始 NMEA 语句,也可通过 liot_gnss_get_location() 获取 SDK 解析后的定位信息,包括 UTC 时间、经纬度、海拔、航向、速度、定位状态、HDOP 水平精度因子和参与解算的卫星数量等。
本文档中的精度指标以接口输出字段为准,主要包括 hdop、fix 和 satcount。其中 hdop 表示水平精度因子,fix 表示定位模式,satcount 表示参与解算的卫星数量。实际定位精度会受卫星信号质量、天线设计、安装位置、遮挡环境和是否启用 AGNSS 等因素影响,本文档不对固定米级精度作保证。
当前仅 Lierda NT26KCNE20GNA、NT26KCNE20GNB、NT26K2E0_0G、NT26K2E1_0G 模组支持 GNSS 定位功能。NT26KCNE20GNA/NT26K2E0_0G 内部定位芯片为 CC1161W,支持 GPS、北斗、伽利略和 GLONASS 多系统定位,可通过 liot_gnss_config_t 中的 gnsscfg_type 参数配置定位系统组合。NT26KCNE20GNB/NT26K2E1_0G 内部定位芯片为 CC1177W,仅支持单北斗定位,如果将 gnsscfg_type 配置为其他卫星系统,配置不会实际生效。
示例程序位于 examples/demo/src/demo_gnss.c,通过 APPDEMO_GNSS_EN 创建 liot_gnss_demo_thread。示例采用事件队列处理 GNSS 回调,并使用一次性定时器控制 GNSS 关闭和重启流程;当前默认定义 GNSS_TEST_E1_0G,配置 GNSS_IC_CC1177W 和单北斗定位系统。
2.2 平台 GNSS 核心概念
2.2.1 GNSS / BDS
GNSS 指全球卫星导航系统总称,包括 GPS、北斗、GLONASS、Galileo 等系统。BDS(北斗)是中国的卫星导航系统。
2.2.2 定位模式(Fix)
fix 用于表示当前 GNSS 定位模式,是判断定位结果是否可靠的关键字段。
值 |
含义 |
|---|---|
1 |
未定位 |
2 |
2D 定位 |
3 |
3D 定位 |
2D 定位通常至少需要 3 颗卫星参与解算,只能提供经纬度信息,定位精度相对较差。3D 定位通常至少需要 4 颗卫星参与解算,可提供经纬度和海拔信息,是获取可靠位置数据的目标状态。
2.2.3 NMEA 语句
NMEA 是 GNSS 接收机输出的标准数据格式。不同 NMEA 语句包含不同类型的信息,例如位置、时间、速度、航向、卫星列表和定位质量等。
语句 |
说明 |
|---|---|
GGA |
定位质量、UTC 时间、经纬度、海拔、卫星数量等 |
RMC |
推荐最小定位信息,包括时间、经纬度、速度、航向等 |
GSV |
可见卫星信息 |
GSA |
DOP 精度因子和参与定位的卫星信息 |
VTG |
地面航向和地面速度 |
GLL |
经纬度和 UTC 时间 |
应用层可通过 liot_gnss_get_nmea() 获取指定类型的 NMEA 语句。客户如需更详细的原始定位信息,可根据业务需要解析对应 NMEA 语句。
2.2.4 AGNSS(辅助定位)
AGNSS 是辅助 GNSS 定位功能,可利用蜂窝网络提供的辅助信息加速 GNSS 芯片首次定位时间(TTFF)。
AGNSS 依赖数据拨号(Data Call)和网络连接。在使用 AGNSS 前,应确保蜂窝网络已注册、数据拨号已建立,并正确配置 AGNSS 服务器和鉴权信息。示例代码中 AGNSS_DEMO_ENABLE 为 1 时会调用 liot_agnss_config(NULL) 并等待网络相关流程完成;正式产品中应根据平台分配的信息配置有效的 liot_agnss_config_t 参数。
2.3 模组支持差异
不同模组内部集成的 GNSS 芯片不同,支持的卫星定位系统也不同。调用 liot_gnss_config() 时,必须根据实际模组型号正确配置 liot_gnss_config_t 中的 gnss_ic_model 和 gnsscfg_type 组合。
模组型号 |
GNSS 芯片 |
支持定位系统 |
推荐配置 |
|---|---|---|---|
NT26KCNE20GNA / NT26K2E0_0G |
CC1161W |
支持 GPS、北斗、GLONASS、Galileo 多模融合定位 |
|
NT26KCNE20GNB / NT26K2E1_0G |
CC1177W |
仅支持单北斗系统定位 |
|
NT26KCNE20GNB/NT26K2E1_0G 仅支持单北斗定位,即使将 gnsscfg_type 配置为 GPS、GLONASS 或 Galileo,也不会实际生效。
3 API 函数概览
函数 |
说明 |
|---|---|
|
配置gnss模块参数 |
|
配置agnss功能参数 |
|
开启gnss模块 |
|
关闭gnss模块 |
|
获取定位信息 |
|
获取指令NMEA语句 |
|
关闭GNSS芯片备用电源 |
4 类型说明
4.1 liot_gnss_errcode_e
GNSS API 执行结果错误码。
声明
typedef enum
{
LIOT_GNSS_SUCCESS = LIOT_SUCCESS,
LIOT_GNSS_EXECUTE_ERR = 1,
LIOT_GNSS_PARAM_ERR,
} liot_gnss_errcode_e;
参数
LIOT_GNSS_SUCCESS:函数执行成功。LIOT_GNSS_EXECUTE_ERR:函数执行错误。LIOT_GNSS_PARAM_ERR:传入参数错误。
4.2 liot_gnss_config_t
GNSS 模块配置参数。
声明
typedef struct
{
liot_gnss_ic_model_e gnss_ic_model; // 可配置为 GNSS_IC_CC1161W 或 GNSS_IC_CC1177W
uint8_t gnssnmea_type; // 配置 nmea 语句输出类型
uint8_t gnsscfg_type; // 配置各系统组合进行定位
uint8_t apflash; // apflash 开关
uint8_t agnss_mode; // agnss 开关
} liot_gnss_config_t;
参数
gnss_ic_model:GNSS定位芯片型号,可配置为GNSS_IC_CC1161W或GNSS_IC_CC1177W,参数含义参考 4.8liot_gnss_ic_model_e。gnssnmea_type:GNSS通过回调函数输出的NMEA类型,不同二进制数据位对应不同NMEA语句,可配置参数与liot_gnss_nmea_type_e类型对应。gnsscfg_type:GNSS使用的定位系统,不同二进制数据位对应不同的定位系统,可配置参数与liot_gnss_cfg_type_e类型对应。apflash:AP FLASH 保存开关。配置为 1 时,GNSS 模块会将关键定位辅助信息保存到模组内部 AP FLASH,例如上次位置、星历数据等,用于下次启动时加快定位速度。该功能会占用模组内部 FLASH 空间。配置为 0 时关闭该功能。agnss_mode:AGNSS 功能开关。配置为 1 时开启辅助定位,使用前必须确保蜂窝网络连接已就绪,并已调用liot_agnss_config()完成 AGNSS 参数配置。配置为 0 时关闭 AGNSS 功能。
4.3 liot_agnss_config_t
AGNSS 功能配置参数。
声明
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;
参数
agnss_url:AGNSS 服务器地址,可配置为平台或客户提供的 AGNSS 服务器域名/地址,最大长度为LIERDA_GNSS_APGS_URL_MAX。自定义服务器必须兼容模组使用的 AGNSS 服务协议,并能配合cid、mid、pw完成鉴权。cid:AGNSS 平台用户名。mid:AGNSS 平台客户标识。pw:AGNSS 平台密码。
当前示例代码中调用 liot_agnss_config(NULL),未演示自定义 AGNSS 服务器配置;正式产品如需使用自定义服务器,应传入有效的 liot_agnss_config_t 参数。
4.4 liot_gnss_loc_info_t
定位信息参数结构体。
声明
typedef struct {
uint8_t fs; // 定位状态:0-无定位,1-单点定位 2-差分定位
char utc[20]; // UTC时间 YYMMDDhhmmss.sss
char latitude[14]; // 纬度
char longitude[14]; // 经度
char hdop[8]; // HDOP 水平精度因子
char altitude[10]; // 海拔 米
uint8_t fix; // 定位状态:1-未定位, 2-2D 定位,3-3D 定位
char cog[10]; // 以真北方向为基准的地面航向
char speedkm[10]; // 速度 千米/小时
char speedkn[10]; // 速度 节
uint8_t satcount; // 卫星数目
} liot_gnss_loc_info_t;
参数
fs:定位状态,0-无定位,1-单点定位,2-差分定位。utc:UTC时间,格式为YYMMDDhhmmss.sss。latitude:纬度,格式为ddmm.mmmmN/S(dd:度,范围:00~89;mm.mmmm:分,范围:00.0000~59.9999;N/S:北纬/南纬)longitude:经度,格式为dddmm.mmmmN/S(ddd:度,范围:00~179;mm.mmmm:分,范围:00.0000~59.9999;E/W:东经/西经)hdop:水平精度因子(HDOP),用于反映水平定位精度,数值越小表示水平定位精度越高。altitude:天线的海拔高度。单位:米fix:GNSS 定位模式,取值含义为:1-未定位,2-2D 定位,3-3D 定位。通常只有fix等于 3 时,获取的位置数据才被认为是可靠的。cog:以真北方向为基准的地面航向。speedkm:地面速率。单位:千米/时。speedkn:地面速率。单位:节。satcount:参与应用解算位置的卫星数量。
4.5 liot_gnss_event_type_e
GNSS 事件回调中的事件类型。
声明
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;
参数
LIOT_GNSS_EVENT_GNSS_ERROR:GNSS出现错误。LIOT_GNSS_EVENT_GNSS_READY:GNSS已准备就绪。LIOT_GNSS_EVENT_GNSS_CLOSED:GNSS已关闭。LIOT_GNSS_EVENT_GNSS_NMEA:GNSS输出NMEA语句。LIOT_GNSS_EVENT_FARMWARE_OK:GNSS固件加载成功。LIOT_GNSS_EVENT_FARMWARE_ERROR:GNSS固件加载失败。LIOT_GNSS_EVENT_AGNSS_OK:AGNSS功能配置成功。LIOT_GNSS_EVENT_AGNSS_ERROR:AGNSS配置失败。
4.6 liot_gnss_nmea_type_e
GNSS NMEA语句配置枚举。
声明
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;
参数
LIOT_GNSS_NMEA_TYPE_GGA:GGA 语句。LIOT_GNSS_NMEA_TYPE_RMC:RMC 语句。LIOT_GNSS_NMEA_TYPE_GSV:GSV 语句。LIOT_GNSS_NMEA_TYPE_GSA:GSA 语句。LIOT_GNSS_NMEA_TYPE_VTG:VTG 语句。LIOT_GNSS_NMEA_TYPE_GLL:GLL 语句。
4.7 liot_gnss_cfg_type_e
GNSS 定位系统配置枚举。
声明
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;
参数
LIOT_GNSS_CFG_TYPE_GPS:GPS卫星系统。LIOT_GNSS_CFG_TYPE_BEIDOU:北斗卫星系统。LIOT_GNSS_CFG_TYPE_GLONASS:Glonass卫星系统。LIOT_GNSS_CFG_TYPE_GALILEO:伽利略卫星系统。
4.8 liot_gnss_ic_model_e
GNSS 定位芯片型号。
声明
typedef enum
{
GNSS_IC_CC1161W = 0,
GNSS_IC_CC1177W,
} liot_gnss_ic_model_e;
参数
GNSS_IC_CC1161W:CC1161W定位芯片,支持GPS、北斗、伽利略和Glonass定位系统多模融合定位。GNSS_IC_CC1177W:CC1177W定位芯片,仅支持单北斗系统定位。
4.9 LiotGnssEventCb
GNSS 事件回调函数类型。
声明
typedef void (*LiotGnssEventCb) (liot_gnss_event_type_e event, uint8_t *data, uint16_t datalen);
参数
event:事件类型。data:事件相关数据指针。datalen:数据长度,单位字节。
5 API 函数详解
5.1 liot_gnss_config
该函数用于配置GNSS参数
声明
liot_gnss_errcode_e liot_gnss_config(liot_gnss_config_t *config);
参数
config:[In]GNSS 配置信息,格式参考 4.2liot_gnss_config_t。
返回值
LIOT_GNSS_SUCCESS:配置成功。LIOT_GNSS_PARAM_ERR:参数错误。
5.2 liot_agnss_config
该函数用于配置AGNSS参数
声明
liot_gnss_errcode_e liot_agnss_config(liot_agnss_config_t *config);
参数
config:[In]AGNSS 配置信息,格式参考 4.3liot_agnss_config_t。
返回值
LIOT_GNSS_SUCCESS:配置成功。
5.3 liot_gnss_open
该函数用于开启GNSS
声明
liot_gnss_errcode_e liot_gnss_open(LiotGnssEventCb event_cb);
参数
event_cb:[In]GNSS 事件回调函数,格式参考 4.9LiotGnssEventCb。
返回值
LIOT_GNSS_SUCCESS:GNSS模块开启成功。LIOT_GNSS_EXECUTE_ERR:GNSS模块开启失败。
5.4 liot_gnss_close
该函数用于关闭GNSS
声明
liot_gnss_errcode_e liot_gnss_close(void);
返回值
LIOT_GNSS_SUCCESS:GNSS模块关闭成功。LIOT_GNSS_EXECUTE_ERR:GNSS模块关闭失败。
5.5 liot_gnss_get_location
该函数用于获取定位信息
声明
liot_gnss_errcode_e liot_gnss_get_location(liot_gnss_loc_info_t *loc_info);
参数
loc_info:[Out]GNSS 定位信息,格式参考 4.4liot_gnss_loc_info_t。
返回值
LIOT_GNSS_SUCCESS:定位信息获取成功。
5.6 liot_gnss_get_nmea
该函数用于获取指定NMEA语句
声明
liot_gnss_errcode_e liot_gnss_get_nmea(uint16_t nmea_type, char *respBuf[], uint16_t respMaxNumber, uint16_t *respNumber);
参数
nmea_type:[In]NMEA 语句类型,不同二进制数据位对应不同NMEA语句,可配置参数与 4.6liot_gnss_nmea_type_e类型对应。respBuf:[Out]字符串指针数组,用于返回 NMEA 语句。函数执行成功后,会为respBuf数组中的前respNumber个指针动态分配地址空间,并将每条 NMEA 语句存储到对应空间中。数据应用完成后,用户必须逐个释放respBuf数组中已分配的每一个字符串指针,避免内存泄漏;在当前 OpenCPU 示例中使用liot_rtos_free()释放。respMaxNumber:[In]可读取的NMEA语句最大数量。respNumber:[Out]实际读取的NMEA语句数量。
返回值
LIOT_GNSS_SUCCESS:NMEA语句获取成功。LIOT_GNSS_PARAM_ERR:参数错误,未指定有效NMEA类型。LIOT_GNSS_EXECUTE_ERR:NMEA语句获取失败。
5.7 liot_gnss_close_backup_power
该函数用于强制关闭GNSS模块备用电源,备用电源处于开启状态时才能成功关闭。
注意:关闭备用电源会清空 GNSS 芯片 RAM 中缓存的定位辅助信息;下次启动时 GNSS 将进行冷启动(Cold Start),首次定位时间可能变长。通常仅在需要彻底重置 GNSS 状态时调用。
声明
liot_gnss_errcode_e liot_gnss_close_backup_power(void);
返回值
LIOT_GNSS_SUCCESS:备用电源关闭成功。LIOT_GNSS_EXECUTE_ERR:备用电源关闭失败,或备用电源未开启。
6 代码示例
以下示例与 examples/demo/src/demo_gnss.c 的主要逻辑保持一致:
liot_gnss_demo_thread()启动后创建消息队列、GNSS 工作定时器和重启定时器。start_gnss_module()配置并打开 GNSS,默认使用GNSS_TEST_E1_0G,即GNSS_IC_CC1177W+ 单北斗定位。GNSS 回调
liot_gnss_demo_event()将事件投递到队列中处理;NMEA 数据会先拷贝,避免回调返回后原始指针失效。GNSS 运行
GNSS_WORK_TIMEOUT后关闭,等待GNSS_RESTART_TIMEOUT后再次启动。
#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 启动流程分析
配置优先:启动 GNSS 前必须先完成参数配置。示例中
start_gnss_module()先根据模组型号配置gnss_ic_model和gnsscfg_type,再调用liot_gnss_config()写入 GNSS 参数;如需使用 AGNSS,还应先调用liot_agnss_config()配置辅助定位参数。事件驱动:
liot_gnss_open()用于打开 GNSS 模块并注册事件回调,接口调用成功后会立即返回。GNSS 就绪、NMEA 输出、关闭、错误等状态通过liot_gnss_demo_event()回调上报,应用层不应假设liot_gnss_open()返回后 GNSS 已经完成定位。异步就绪等待:当前示例使用消息队列等待 GNSS 事件。
liot_gnss_demo_event()将回调事件投递到队列,主循环通过liot_rtos_queue_wait()等待并处理事件;当收到LIOT_GNSS_EVENT_GNSS_READY后,将gnss_ready_state置为 1,表示 GNSS 已就绪。这是等待异步就绪的方式。
运行结果:
7 注意事项
该版本硬件中 Cat.1 芯片和 GNSS 芯片通过 UART2 连接,GNSS 电源通过 Cat.1 芯片 AGPIO3、AGPIO5 控制,请勿将 UART2、AGPIO3、AGPIO5 复用为其他功能,可能会导致模组工作异常。
NT26KCNE20GNA/NT26K2E0_0G 模组内部定位芯片为 CC1161W、NT26KCNE20GNB/NT26K2E1_0G 模组内部定位芯片为 CC1177W,使用时请按照对应型号正确配置
gnss_ic_model参数。NT26KCNE20GNB/NT26K2E1_0G 模组内部的定位芯片 CC1177W 仅支持单北斗卫星系统定位,如果在
gnsscfg_type配置项中将其配置为其他参数,不会实际生效。开启辅助定位将改善定位精度。
当前示例默认定义
GNSS_TEST_E1_0G。如需测试GNSS_TEST_E0_0G,需切换对应宏,并按源码中的配置使用GNSS_IC_CC1161W和 GPS + 北斗融合定位。当前示例中
GNSS_WORK_TIMEOUT为 60 秒,GNSS_RESTART_TIMEOUT为 10 秒;GNSS 打开后运行 60 秒并关闭,再等待 10 秒后重启。liot_gnss_get_nmea()返回的 NMEA 字符串由接口分配,示例中使用liot_rtos_free()释放。回调中的
data指针不应在回调返回后长期保存;示例在LIOT_GNSS_EVENT_GNSS_NMEA事件中先复制 NMEA 数据,再通过队列处理。当前示例中
AGNSS_DEMO_ENABLE为 1 时会调用liot_agnss_config(NULL)并等待 10 秒,但gnss_config.agnss_mode设置为 0;如需正式使用 AGNSS,请按实际平台配置有效liot_agnss_config_t参数并同步开启agnss_mode。

