Ver código fonte

add:新增exgnss库和demo,新增exvib库和demo

liyuanlong 5 meses atrás
pai
commit
fff9efaa23

+ 21 - 20
module/Air8000/demo/gnss/lowpower.lua → module/Air8000/demo/gnss/combination/lowpower.lua

@@ -5,22 +5,25 @@
 @date    2025.07.27
 @author  李源龙
 @usage
-使用Air8000核心板,外接GPS天线,起一个60s定位一次的定时器,唤醒模块60s一定位,然后定位成功获取到经纬度发送到服务器上面,然后进入休眠
+使用Air8000整机开发板,外接GPS天线,起一个60s定位一次的定时器,唤醒模块60s一定位,
+然后定位成功获取到经纬度发送到服务器上面,然后进入休眠
 ]]
 
-gnss=require("gnss")
-tcp=require("tcp")
+tcp_client_main=require("tcp_client_main")
 
-local function mode1_cb(tag)
+local function lowpower_cb(tag)
     log.info("TAGmode1_cb+++++++++",tag)
-    local  rmc=gnss.getRmc(0)
-    log.info("nmea", "rmc", json.encode(gnss.getRmc(0)))
-    tcp.latlngfnc(rmc.lat,rmc.lng)
-    pm.power(pm.WORK_MODE, 1)
+    local  rmc=exgnss.rmc(0)    --获取rmc数据
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(0)))
+    local data=string.format('{"lat":%5f,"lng":%5f}', rmc.lat, rmc.lng)
+    sys.publish("SEND_DATA_REQ", "gnsslowpower", data) --发送数据到服务器
+    pm.power(pm.WORK_MODE, 1)--进入低功耗模式
+    pm.power(pm.WORK_MODE,1,1)--wifi进入低功耗模式
 end
-local function timer1()
-    pm.power(pm.WORK_MODE, 0)
-    gnss.open(gnss.TIMERORSUC,{tag="MODE1",val=60,cb=mode1_cb})
+
+local function lower_open()
+    pm.power(pm.WORK_MODE, 0)   --进入正常模式
+    exgnss.open(exgnss.TIMERORSUC,{tag="lowpower",val=60,cb=lowpower_cb})
 end
 
 local function gnss_fnc()
@@ -33,20 +36,18 @@ local function gnss_fnc()
         -- uartbaud=115200,    --串口波特率,780EGH和8000默认115200
         -- bind=1, --绑定uart端口进行GNSS数据读取,是否设置串口转发,指定串口号
         -- rtc=false    --定位成功后自动设置RTC true开启,flase关闭
-         ----因为GNSS使用辅助定位的逻辑,是模块下载星历文件,然后把数据发送给GNSS芯片,
+        ----因为GNSS使用辅助定位的逻辑,是模块下载星历文件,然后把数据发送给GNSS芯片,
         ----芯片解析星历文件需要10-30s,默认GNSS会开启20s,该逻辑如果不执行,会导致下一次GNSS开启定位是冷启动,
-        ----定位速度慢,大概35S左右,所以默认开启,如果可以接受下一次定位是冷启动,可以把agps_autoopen设置成false
+        ----定位速度慢,大概35S左右,所以默认开启,如果可以接受下一次定位是冷启动,可以把auto_open设置成false
         ----需要注意的是热启动在定位成功之后,需要再开启3s左右才能保证本次的星历获取完成,如果对定位速度有要求,建议这么处理
-        agps_autoopen=false 
+        auto_open=false 
     }
-    gnss.setup(gnssotps)
-    sys.timerLoopStart(timer1,60000)
-    gnss.open(gnss.TIMER,{tag="MODE1",val=20,cb=mode1_cb})
-    -- gpio.close(23)--此脚为gnss备电脚,功能是热启动和保存星历文件,关掉会没有热启动,常开功耗会增高
-    -- gpio.close(33) -- 如果功耗偏高,开始尝试关闭WAKEUPPAD1
+    exgnss.setup(gnssotps)  --配置GNSS参数
+    exgnss.open(exgnss.TIMERORSUC,{tag="lowpower",val=60,cb=lowpower_cb}) --打开一个60s的TIMERORSUC应用,该模式定位成功关闭
+    sys.timerLoopStart(lower_open,60000)       --每60s开启一次GNSS
+    -- gpio.close(24)--此脚为gnss备电脚和三轴加速度传感器的供电脚,功能是热启动和保存星历文件,关掉会没有热启动,常开功耗会增高0.5-1MA左右
     -- --关闭USB以后可以降低约150ua左右的功耗,如果不需要USB可以关闭
     pm.power(pm.USB, false)
-
 end
 
 sys.taskInit(gnss_fnc)

+ 67 - 0
module/Air8000/demo/gnss/combination/main.lua

@@ -0,0 +1,67 @@
+
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.07.27
+@author  李源龙
+@usage
+本demo演示的功能为:
+使用Air8000整机开发板,通过exgnss扩展库,开启GNSS定位,展示模块的三种功耗模式:正常模式,低功耗模式,PSM+模式 
+]]
+
+--[[
+必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
+PROJECT:项目名,ascii string类型
+        可以随便定义,只要不使用,就行
+VERSION:项目版本号,ascii string类型
+        如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
+            X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
+            因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
+        如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
+]]
+PROJECT = "gnsstest"
+VERSION = "001.000.000"
+
+--添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
+
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+exgnss=require("exgnss")    
+
+--以下功能每次只能打开一个用于测试,选择对应的功能进行测试
+
+require"normal"  --正常模式,搭配GNSS定时开启发送经纬度数据到服务器,不进入任何低功耗模式
+-- require"lowpower"    -- 低功耗模式,搭配GNSS定时开启发送经纬度数据到服务器,定位成功之后关闭GNSS进入低功耗模式
+-- require"psm"     -- PSM+模式,唤醒开启GNSS定位,定位成功之后发送经纬度数据到服务器,然后关闭GNSS进入PSM+模式
+-- require"vibration"  -- 振动检测模式,搭配GNSS触发震动检测之后,持续发送经纬度数据到服务器
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 17 - 14
module/Air8000/demo/gnss/normal.lua → module/Air8000/demo/gnss/combination/normal.lua

@@ -5,19 +5,21 @@
 @date    2025.07.27
 @author  李源龙
 @usage
-使用Air8000核心板,外接GPS天线,起一个60s定位一次的定时器,模块60s一定位,然后定位成功获取到经纬度发送到服务器上面
+使用Air8000整机开发板,外接GPS天线,定位然后发送经纬度数据给服务器,
+起一个60s定位一次的定时器,模块60s一定位,然后定位成功获取到经纬度发送到服务器上面
 ]]
--- gnss=require("gnss")
-tcp=require("tcp")
 
-local function mode1_cb(tag)
+tcp_client_main=require("tcp_client_main")
+
+local function normal_cb(tag)
     log.info("TAGmode1_cb+++++++++",tag)
-    local  rmc=gnss.getRmc(0)
-    log.info("nmea", "rmc", json.encode(gnss.getRmc(0)))
-    tcp.latlngfnc(rmc.lat,rmc.lng)
+    local  rmc=exgnss.rmc(0)    --获取rmc数据
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(0)))
+    local data=string.format('{"lat":%5f,"lng":%5f}', rmc.lat, rmc.lng)
+    sys.publish("SEND_DATA_REQ", "gnssnormal", data) --发送数据到服务器
 end
-local function timer1()
-    gnss.open(gnss.TIMERORSUC,{tag="MODE1",val=60,cb=mode1_cb})
+local function normal_open()
+    exgnss.open(exgnss.TIMERORSUC,{tag="normal",val=60,cb=normal_cb}) --打开一个60s的TIMERORSUC应用,该模式定位成功关闭
 end
 
 local function gnss_fnc()
@@ -32,13 +34,14 @@ local function gnss_fnc()
         -- rtc=false    --定位成功后自动设置RTC true开启,flase关闭
         ----因为GNSS使用辅助定位的逻辑,是模块下载星历文件,然后把数据发送给GNSS芯片,
         ----芯片解析星历文件需要10-30s,默认GNSS会开启20s,该逻辑如果不执行,会导致下一次GNSS开启定位是冷启动,
-        ----定位速度慢,大概35S左右,所以默认开启,如果可以接受下一次定位是冷启动,可以把agps_autoopen设置成false
+        ----定位速度慢,大概35S左右,所以默认开启,如果可以接受下一次定位是冷启动,可以把auto_open设置成false
         ----需要注意的是热启动在定位成功之后,需要再开启3s左右才能保证本次的星历获取完成,如果对定位速度有要求,建议这么处理
-        -- agps_autoopen=false 
+        -- auto_open=false 
     }
-    gnss.setup(gnssotps)
-    sys.timerLoopStart(timer1,60000)
-    gnss.open(gnss.TIMERORSUC,{tag="MODE1",val=60,cb=mode1_cb})
+    exgnss.setup(gnssotps)  --配置GNSS参数
+    exgnss.open(exgnss.TIMERORSUC,{tag="normal",val=60,cb=normal_cb}) --打开一个60s的TIMERORSUC应用,该模式定位成功关闭
+    sys.timerLoopStart(normal_open,60000)       --每60s开启一次GNSS
+    
 end
 
 sys.taskInit(gnss_fnc)

+ 32 - 11
module/Air8000/demo/gnss/psm.lua → module/Air8000/demo/gnss/combination/psm.lua

@@ -5,16 +5,19 @@
 @date    2025.07.27
 @author  李源龙
 @usage
-使用Air8000核心板,外接GPS天线,开启定位,获取到定位发送到服务器上面,然后启动一个60s的定时器唤醒PSM+模式
+使用Air8000整机开发板,外接GPS天线,开启定位,获取到定位发送到服务器上面,然后启动一个60s的定时器唤醒PSM+模式
 模块开启定位,然后定位成功获取到经纬度发送到服务器上面,然后进入PSM+模式,等待唤醒
 ]]
 pm.power(pm.WORK_MODE, 0) 
 local lat,lng
 
-
+-- 电脑访问:https://netlab.luatos.com/
+-- 点击 打开TCP 按钮,会创建一个TCP server
+-- 将server的地址和端口赋值给下面这两个变量
 local server_ip = "112.125.89.8" 
-local server_port = 47523 -- 换成自己的
-local period = 3 * 60 * 60 * 1000 -- 3小时唤醒一次
+local server_port = 43706 -- 换成自己的
+
+local period = 3 * 60 * 60 * 1000 -- 定时器唤醒时间,3小时唤醒一次
 
 local reason, slp_state = pm.lastReson() -- 获取唤醒原因
 log.info("wakeup state", pm.lastReson())
@@ -25,8 +28,10 @@ local function netCB(msg)
     log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
 end
 
+
 local function testTask(ip, port)
     local txData
+    --拼接处理定位数据和唤醒原因
     if reason == 0 then
         txData = "normal wakeup,"..string.format('{"lat":%5f,"lng":%5f}', lat, lng)
     elseif reason == 1 then
@@ -40,20 +45,33 @@ local function testTask(ip, port)
         mobile.flymode(0, false) -- 退出飞行模式,进入psm+前进入飞行模式,唤醒后需要主动退出
     end
 
-
     local netc, needBreak
     local result, param, is_err
+    -- 创建socket client对象
     netc = socket.create(nil, d1Name)
+    --关闭debug信息
     socket.debug(netc, false)
+    -- 配置socket client对象为netc
     socket.config(netc) 
     local retry = 0
+    --这边会尝试连接服务器并且发送,最多处理3次,如果3次都不行就退出,发送成功就直接退出
     while retry < 3 do
+        while not socket.adapter(socket.dft()) do
+            log.warn("tcp_client_main_task_func", "wait IP_READY")
+            -- 在此处阻塞等待联网成功成功的消息"IP_READY"
+            -- 或者等待30秒超时退出阻塞等待状态
+            sys.waitUntil("IP_READY", 30000)
+        end
+
         log.info(rtos.meminfo("sys"))
-        result = libnet.waitLink(d1Name, 0, netc)
+        -- 连接server
         result = libnet.connect(d1Name, 5000, netc, ip, port)
+
         if result then
             log.info("服务器连上了")
+            --连接成功发送数据
             result, param = libnet.tx(d1Name, 15000, netc, txData)
+            --如果发送失败就直接退出
             if not result then
                 log.info("服务器断开了", result, param)
                 break
@@ -63,17 +81,20 @@ local function testTask(ip, port)
         else
             log.info("服务器连接失败")
         end
+        --关闭socket
         libnet.close(d1Name, 5000, netc)
         retry = retry + 1
+        --如果发送成功结束循环
         if needBreak then
             break
         end
     end
+    socket.release(netc)
 
     uart.setup(1, 9600) -- 配置uart1,外部唤醒用
     
     -- 配置GPIO以达到最低功耗的目的
-	-- gpio.close(23) --此脚为gnss备电脚,功能是热启动和保存星历文件,关掉会没有热启动,常开功耗会增高
+	-- gpio.close(24) --此脚为gnss备电脚和三轴加速度传感器的供电脚,功能是热启动和保存星历文件,关掉会没有热启动,常开功耗会增高0.5-1MA左右
 
     pm.dtimerStart(3, period) -- 启动深度休眠定时器
 
@@ -87,8 +108,8 @@ end
 
 local function mode1_cb(tag)
     log.info("TAGmode1_cb+++++++++",tag)
-    local  rmc=gnss.getRmc(0)
-    log.info("nmea", "rmc", json.encode(gnss.getRmc(0)))
+    local  rmc=exgnss.rmc(0)
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(0)))
     lat,lng=rmc.lat,rmc.lng
     sysplus.taskInitEx(testTask, d1Name, netCB, server_ip, server_port)
 end
@@ -109,8 +130,8 @@ local function gnss_fnc()
         ----需要注意的是热启动在定位成功之后,需要再开启3s左右才能保证本次的星历获取完成,如果对定位速度有要求,建议这么处理
         -- agps_autoopen=false 
     }
-    gnss.setup(gnssotps)
-    gnss.open(gnss.TIMERORSUC,{tag="MODE1",val=60,cb=mode1_cb})
+    exgnss.setup(gnssotps)
+    exgnss.open(exgnss.TIMERORSUC,{tag="MODE1",val=60,cb=mode1_cb})
 end
 
 sys.taskInit(gnss_fnc)

+ 155 - 0
module/Air8000/demo/gnss/combination/readme.md

@@ -0,0 +1,155 @@
+
+## 演示功能概述
+
+使用Air8000整机开发板,本示例主要是利用exgnss库,实现了几种不同的应用场景,
+
+第一种场景是:正常模式,第一步先是通过tcp_client_main文件连接服务器,然后第二步模块会配置GNSS参数,开启GNSS应用,第三步会开启一个60s的定时器,定时器每60s会打开一个60sTIMERRORSUC应用,第四步定位成功之后关闭GNSS,然后获取rmc获取经纬度数据,发送经纬度数据到服务器上。
+
+第二种场景是:低功耗模式,第一步先是通过tcp_client_main文件连接服务器,然后第二步模块会配置GNSS参数,开启GNSS应用,第三步会开启一个60s的定时器,定时器每60s会进入正常模式,打开一个60sTIMERRORSUC应用,第四步定位成功之后关闭GNSS,然后获取rmc获取经纬度数据,发送经纬度数据到服务器上,进入低功耗模式。
+
+第三种场景是:PSM+模式,唤醒之后第一步是配置GNSS参数,开启GNSS应用,第二步定位成功之后关闭GNSS,然后获取rmc获取经纬度数据,拼接唤醒信息和经纬度信息,连接服务器,然后把数据发送数据到服务器上,配置休眠唤醒定时器 ,进入飞行模式,然后进入PSM+模式。
+
+第四种场景是:三轴加速度的应用场景,第一步先是通过tcp_client_main文件连接服务器,第二步配置GNSS参数,打开内部加速传感器,设置防抖和中断模式,关于中断触发提供了两种方案,有效震动模式和持续震动检测模式,第三步检测到有效震动或者持续震动后,打开GNSS,每隔5s获取rmc获取经纬度数据,发送经纬度数据到服务器上。
+
+## 演示硬件环境
+
+1、Air8000整机开发板一块
+
+2、TYPE-C USB数据线一根
+
+3、gnss天线一根
+
+4、Air8000整机开发板和数据线的硬件接线方式为
+
+- Air8000整机开发板通过TYPE-C USB口供电;(整机开发板的拨钮开关拨到USB供电)
+
+- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8000 V2010版本固件](https://docs.openluat.com/air8000/luatos/firmware/)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到核心板中
+
+3、烧录好后,板子开机将会在Luatools上看到如下打印:
+
+(1) 第一种场景演示:
+打开GNSS应用
+```lua
+[2025-08-13 17:52:14.073][000000000.420] I/user.全卫星开启
+[2025-08-13 17:52:14.105][000000000.420] I/user.agps开启
+
+```
+连接服务器成功回复:
+```lua
+[2025-08-13 17:52:16.557][000000006.653] I/user.tcp_client_main_task_func libnet.connect success
+```
+
+定位成功发送数据到服务器:
+```lua
+[2025-08-13 17:52:34.288][000000024.791] I/gnss Fixed 344787143 1141919779
+[2025-08-13 17:52:34.350][000000024.854] I/user.exgnss.statInd@1 true 2 normal 60 36 nil function: 0C7EFAA8
+[2025-08-13 17:52:34.367][000000024.855] I/user.exgnss.statInd@2 true 3 libagps 20 2 nil nil
+[2025-08-13 17:52:34.943][000000025.448] I/user.exgnss.timerFnc@1 2 normal 60 36 1
+[2025-08-13 17:52:34.961][000000025.448] I/user.TAGmode1_cb+++++++++ normal
+[2025-08-13 17:52:34.973][000000025.449] I/user.nmea rmc {"variation":0,"lat":3447.8713379,"min":52,"valid":true,"day":13,"lng":11419.1972656,"speed":1.0460000,"year":2025,"month":8,"sec":34,"hour":9,"course":15.3769999}
+[2025-08-13 17:52:34.984][000000025.450] I/user.exgnss.close 2 normal 60 function: 0C7EFAA8
+[2025-08-13 17:52:34.993][000000025.451] I/user.exgnss.timerFnc@2 3 libagps 20 2 nil
+[2025-08-13 17:52:35.010][000000025.452] I/user.DATA gnssnormal {"lat":3447.871338,"lng":11419.197266}
+[2025-08-13 17:52:35.026][000000025.453] I/user.tcp_client_main_task_func libnet.wait true true nil
+[2025-08-13 17:52:35.070][000000025.574] I/user.tcp_client_sender.proc send success
+```
+后续是循环这个操作,每60秒GNSS定位一次,每次定位成功后,通过TCP发送给服务器。
+
+(2) 第二种场景低功耗模式,第三种场景PSM+场景,可以直接用Air9000搭配看功耗分析,配合服务器看接收日志,目前没办法用USB线通过luatools看日志。
+
+
+(3)、三轴加速度的应用场景:
+联网成功连接服务器:
+```lua
+[2025-08-13 18:08:50.407][000000006.046] D/mobile NETIF_LINK_ON -> IP_READY
+[2025-08-13 18:08:50.442][000000006.047] I/user.tcp_client_main_task_func recv IP_READY
+[2025-08-13 18:08:50.469][000000006.048] D/socket connect to 112.125.89.8,47855
+[2025-08-13 18:08:50.489][000000006.068] D/mobile TIME_SYNC 0
+[2025-08-13 18:08:50.506][000000006.086] I/user.tcp_client_main_task_func libnet.connect success
+
+```
+有效震动触发场景开启GNSS:
+```lua
+[2025-08-13 18:11:01.380][000000137.275] I/user.int 1
+[2025-08-13 18:11:01.405][000000137.276] I/user.table.remove 0
+[2025-08-13 18:11:01.417][000000137.276] I/user.tick 136 false true
+[2025-08-13 18:11:01.433][000000137.276] I/user.tick2 0 0 0 11 136
+[2025-08-13 18:11:01.866][000000137.758] I/user.int 0
+[2025-08-13 18:11:02.005][000000137.893] I/user.int 1
+[2025-08-13 18:11:02.021][000000137.893] I/user.table.remove 0
+[2025-08-13 18:11:02.031][000000137.894] I/user.tick 137 false true
+[2025-08-13 18:11:02.044][000000137.894] I/user.tick2 0 0 11 136 137
+[2025-08-13 18:11:02.474][000000138.376] I/user.int 0
+[2025-08-13 18:11:02.741][000000138.635] I/user.int 1
+[2025-08-13 18:11:02.755][000000138.635] I/user.table.remove 0
+[2025-08-13 18:11:02.765][000000138.636] I/user.tick 138 false true
+[2025-08-13 18:11:02.780][000000138.636] I/user.tick2 0 11 136 137 138
+[2025-08-13 18:11:03.363][000000139.253] I/user.int 0
+[2025-08-13 18:11:03.537][000000139.438] I/user.int 1
+[2025-08-13 18:11:03.555][000000139.438] I/user.table.remove 0
+[2025-08-13 18:11:03.561][000000139.439] I/user.tick 139 false true
+[2025-08-13 18:11:03.574][000000139.439] I/user.tick2 11 136 137 138 139
+[2025-08-13 18:11:04.020][000000139.921] I/user.int 0
+[2025-08-13 18:11:04.586][000000140.478] I/user.int 0
+[2025-08-13 18:11:05.075][000000140.972] I/user.int 0
+[2025-08-13 18:11:05.202][000000141.093] I/user.tcp_client_main_task_func libnet.wait true false nil
+[2025-08-13 18:11:05.626][000000141.528] I/user.int 0
+[2025-08-13 18:11:06.145][000000142.035] I/user.int 1
+[2025-08-13 18:11:06.171][000000142.035] I/user.table.remove 11
+[2025-08-13 18:11:06.184][000000142.036] I/user.tick 141 true true
+[2025-08-13 18:11:06.192][000000142.036] I/user.tick2 136 137 138 139 141
+[2025-08-13 18:11:06.200][000000142.036] I/user.vib xxx
+[2025-08-13 18:11:06.210][000000142.037] I/user.nmea is_open false
+[2025-08-13 18:11:06.217][000000142.038] I/user.exgnss.open 1 vib nil function: 0C7EEE58
+[2025-08-13 18:11:06.228][000000142.038] Uart_ChangeBR 1338:uart2, 115200 115203 26000000 3611
+[2025-08-13 18:11:06.240][000000142.039] I/user.全卫星开启
+[2025-08-13 18:11:06.249][000000142.039] I/user.debug开启
+[2025-08-13 18:11:06.262][000000142.039] D/gnss Debug ON
+[2025-08-13 18:11:06.277][000000142.040] I/user.agps开启
+```
+触发之后每5s发送一次经纬度数据到服务器:
+```lua
+[2025-08-13 18:13:51.149][000000307.042] I/user.TAGmode1_cb+++++++++ nil
+[2025-08-13 18:13:51.152][000000307.044] I/user.nmea rmc {"variation":0,"lat":3447.8745117,"min":13,"valid":true,"day":13,"lng":11419.1962891,"speed":0.0730000,"year":2025,"month":8,"sec":50,"hour":10,"course":152.6990051}
+[2025-08-13 18:13:51.154][000000307.044] I/user.DATA gnssnormal {"lat":3447.874512,"lng":11419.196289}
+[2025-08-13 18:13:51.157][000000307.046] I/user.tcp_client_main_task_func libnet.wait true true nil
+[2025-08-13 18:13:51.241][000000307.129] I/user.tcp_client_sender.proc send success
+```
+
+持续震动检测模式,触发开始开启GNSS应用:
+```lua
+[2025-08-13 18:25:24.809][000000358.919] I/user.int 1
+[2025-08-13 18:25:24.822][000000358.921] I/user.x 0.35156250000000g y 0.31933593800000g z 1.9990234380000g
+[2025-08-13 18:25:24.833][000000358.922] I/user.nmea is_open false
+[2025-08-13 18:25:24.840][000000358.922] I/user.exgnss.open 1 vib nil function: 0C7EEEE0
+[2025-08-13 18:25:24.850][000000358.923] Uart_ChangeBR 1338:uart2, 115200 115203 26000000 3611
+[2025-08-13 18:25:24.863][000000358.924] I/user.全卫星开启
+[2025-08-13 18:25:24.875][000000358.924] I/user.debug开启
+[2025-08-13 18:25:24.886][000000358.924] D/gnss Debug ON
+[2025-08-13 18:25:24.900][000000358.925] I/user.agps开启
+```
+
+触发之后每5s发送一次经纬度数据到服务器:
+```lua
+[2025-08-13 18:25:32.220][000000366.338] I/user.exgnss.timerFnc@1 1 vib nil nil 1
+[2025-08-13 18:25:32.225][000000366.339] I/user.TAGmode1_cb+++++++++ vib
+[2025-08-13 18:25:32.233][000000366.340] I/user.nmea rmc {"variation":0,"lat":3447.8679199,"min":25,"valid":true,"day":13,"lng":11419.1962891,"speed":0.2490000,"year":2025,"month":8,"sec":32,"hour":10,"course":175.2010040}
+[2025-08-13 18:25:32.239][000000366.341] I/user.DATA gnssnormal {"lat":3447.867920,"lng":11419.196289}
+[2025-08-13 18:25:32.242][000000366.342] I/user.tcp_client_main_task_func libnet.wait true true nil
+[2025-08-13 18:25:32.353][000000366.473] I/user.tcp_client_sender.proc send success
+```
+
+

+ 142 - 0
module/Air8000/demo/gnss/combination/tcp_client_main.lua

@@ -0,0 +1,142 @@
+--[[
+@module  tcp_client_main
+@summary tcp client socket主应用功能模块 
+@version 1.0
+@date    2025.07.01
+@author  朱天华
+@usage
+本文件为tcp client socket主应用功能模块,核心业务逻辑为:
+1、创建一个tcp client socket,连接server;
+2、处理连接异常,出现异常后执行重连动作;
+3、调用tcp_client_receiver和tcp_client_sender中的外部接口,进行数据收发处理;
+
+本文件没有对外接口,直接在main.lua中require "tcp_client_main"就可以加载运行;
+]]
+
+local libnet = require "libnet"
+
+-- 加载tcp client socket数据接收功能模块
+local tcp_client_receiver = require "tcp_client_receiver"
+-- 加载tcp client socket数据发送功能模块
+local tcp_client_sender = require "tcp_client_sender"
+
+-- 电脑访问:https://netlab.luatos.com/
+-- 点击 打开TCP 按钮,会创建一个TCP server
+-- 将server的地址和端口赋值给下面这两个变量
+local SERVER_ADDR = "112.125.89.8"
+local SERVER_PORT = 44333
+
+-- tcp_client_main的任务名
+local TASK_NAME = tcp_client_sender.TASK_NAME
+
+
+-- 处理未识别的消息
+local function tcp_client_main_cbfunc(msg)
+	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
+end
+
+-- tcp client socket的任务处理函数
+local function tcp_client_main_task_func() 
+
+    local socket_client
+    local result, para1, para2
+
+    while true do
+        -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
+        while not socket.adapter(socket.dft()) do
+            log.warn("mqtt_client_main_task_func", "wait IP_READY", socket.dft())
+            -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
+            -- 或者等待1秒超时退出阻塞等待状态;
+            -- 注意:此处的1000毫秒超时不要修改的更长;
+            -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
+            -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
+            -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
+            sys.waitUntil("IP_READY", 1000)
+        end
+
+        -- 检测到了IP_READY消息
+        log.info("tcp_client_main_task_func", "recv IP_READY")
+
+        -- 创建socket client对象
+        socket_client = socket.create(nil, TASK_NAME)
+        -- 如果创建socket client对象失败
+        if not socket_client then
+            log.error("tcp_client_main_task_func", "socket.create error")
+            goto EXCEPTION_PROC
+        end
+
+        -- 配置socket client对象为tcp client
+        result = socket.config(socket_client)
+        -- 如果配置失败
+        if not result then
+            log.error("tcp_client_main_task_func", "socket.config error")
+            goto EXCEPTION_PROC
+        end
+
+        -- 连接server
+        result = libnet.connect(TASK_NAME, 15000, socket_client, SERVER_ADDR, SERVER_PORT)
+        -- 如果连接server失败
+        if not result then
+            log.error("tcp_client_main_task_func", "libnet.connect error")
+            goto EXCEPTION_PROC
+        end
+
+        log.info("tcp_client_main_task_func", "libnet.connect success")
+
+        -- 数据收发以及网络连接异常事件总处理逻辑
+        while true do
+            -- 数据接收处理(接收处理必须写在libnet.wait之前,因为老版本的内核固件要求必须这样,新版本的内核固件没这个要求,为了不出问题,写在libnet.wait之前就行了)
+            -- 如果处理失败,则退出循环
+            if not tcp_client_receiver.proc(socket_client) then
+                log.error("tcp_client_main_task_func", "tcp_client_receiver.proc error")
+                break
+            end
+
+            -- 数据发送处理
+            -- 如果处理失败,则退出循环
+            if not tcp_client_sender.proc(TASK_NAME, socket_client) then
+                log.error("tcp_client_main_task_func", "tcp_client_sender.proc error")
+                break
+            end
+
+            -- 阻塞等待socket.EVENT事件或者15秒钟超时
+            -- 以下三种业务逻辑会发布事件:
+            -- 1、socket client和server之间的连接出现异常(例如server主动断开,网络环境出现异常等),此时在内核固件中会发布事件socket.EVENT
+            -- 2、socket client接收到server发送过来的数据,此时在内核固件中会发布事件socket.EVENT
+            -- 3、socket client需要发送数据到server, 在tcp_client_sender.lua中会发布事件socket.EVENT
+			result, para1, para2 = libnet.wait(TASK_NAME, 15000, socket_client)
+            log.info("tcp_client_main_task_func", "libnet.wait", result, para1, para2)
+			
+			-- 如果连接异常,则退出循环
+			if not result then
+				log.warn("tcp_client_main_task_func", "connection exception")
+				break
+            end
+        end
+
+
+        -- 出现异常    
+        ::EXCEPTION_PROC::
+
+        -- 数据发送应用模块对来不及发送的数据做清空和通知失败处理
+        tcp_client_sender.exception_proc()
+
+        -- 如果存在socket client对象
+        if socket_client then
+            -- 关闭socket client连接
+            libnet.close(TASK_NAME, 5000, socket_client)
+
+            -- 释放socket client对象
+            socket.release(socket_client)
+            socket_client = nil
+        end
+        
+        -- 5秒后跳转到循环体开始位置,自动发起重连
+        sys.wait(5000)
+    end
+end
+
+--创建并且启动一个task
+--运行这个task的主函数tcp_client_main_task_func
+sysplus.taskInitEx(tcp_client_main_task_func, TASK_NAME, tcp_client_main_cbfunc)
+

+ 69 - 0
module/Air8000/demo/gnss/combination/tcp_client_receiver.lua

@@ -0,0 +1,69 @@
+--[[
+@module  tcp_client_receiver
+@summary tcp client socket数据接收应用功能模块 
+@version 1.0
+@date    2025.07.01
+@author  朱天华
+@usage
+本文件为tcp client socket数据接收应用功能模块,核心业务逻辑为:
+从内核读取接收到的数据,然后将数据发送给其他应用功能模块做进一步处理;
+
+本文件的对外接口有2个:
+1、tcp_client_receiver.proc(socket_client):数据接收应用逻辑处理入口,在tcp_client_main.lua中调用;
+2、sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp server: ", data):
+   将接收到的数据通过消息"RECV_DATA_FROM_SERVER"发布出去;
+   需要处理数据的应用功能模块订阅处理此消息即可,本demo项目中uart_app.lua中订阅处理了本消息;
+]]
+
+local tcp_client_receiver = {}
+
+-- socket数据接收缓冲区
+local recv_buff = nil
+
+-- 数据接收应用入口函数
+function tcp_client_receiver.proc(socket_client)
+    -- 如果socket数据接收缓冲区还没有申请过空间,则先申请内存空间
+    if recv_buff==nil then
+        recv_buff = zbuff.create(1024)
+        -- 当recv_buff不再使用时,不需要主动调用recv_buff:free()去释放
+        -- 因为Lua的垃圾处理器会自动释放recv_buff所申请的内存空间
+        -- 如果等不及垃圾处理器自动处理,在确定以后不会再使用recv_buff时,则可以主动调用recv_buff:free()释放内存空间
+    end
+
+    -- 循环从内核的缓冲区读取接收到的数据
+    -- 如果读取失败,返回false,退出
+    -- 如果读取成功,处理数据,并且继续循环读取
+    -- 如果读取成功,并且读出来的数据为空,表示已经没有数据可读,返回true,退出
+    while true do
+        -- 从内核的缓冲区中读取数据到recv_buff中
+        -- 如果recv_buff的存储空间不足,会自动扩容
+        local result = socket.rx(socket_client, recv_buff)
+        -- 读取数据失败
+        -- 有两种情况:
+        -- 1、recv_buff扩容失败
+        -- 2、socket client和server之间的连接断开
+        if not result then
+            log.error("tcp_client_receiver.proc", "socket.rx error")
+            return false
+        end
+
+        -- 如果读取到了数据, used()就必然大于0, 进行处理
+        if recv_buff:used() > 0 then
+            log.info("tcp_client_receiver.proc", "recv data len", recv_buff:used())
+            -- 读取socket数据接收缓冲区中的数据,赋值给data
+            local data = recv_buff:query()
+            -- 将数据data通过"RECV_DATA_FROM_SERVER"消息publish出去,给其他应用模块处理
+            sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp server: ", data)
+            table.insert(tab,data)
+            -- 清空socket数据接收缓冲区中的数据
+            recv_buff:del()
+            -- 读取成功,但是读出来的数据为空,表示已经没有数据可读,可以退出循环了
+        else
+            break
+        end
+    end
+
+    return true
+end
+
+return tcp_client_receiver

+ 111 - 0
module/Air8000/demo/gnss/combination/tcp_client_sender.lua

@@ -0,0 +1,111 @@
+--[[
+@module  tcp_client_sender
+@summary tcp client socket数据发送应用功能模块 
+@version 1.0
+@date    2025.07.01
+@author  朱天华
+@usage
+本文件为tcp client socket数据发送应用功能模块,核心业务逻辑为:
+1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
+2、tcp_client_main主任务调用tcp_client_sender.proc接口,遍历队列send_queue,逐条发送数据到server;
+3、tcp client socket和server之间的连接如果出现异常,tcp_client_main主任务调用tcp_client_sender.exception_proc接口,丢弃掉队列send_queue中未发送的数据;
+4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
+
+本文件的对外接口有3个:
+1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
+   其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
+   本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
+2、tcp_client_sender.proc:数据发送应用逻辑处理入口,在tcp_client_main.lua中调用;
+3、tcp_client_sender.exception_proc:数据发送应用逻辑异常处理入口,在tcp_client_main.lua中调用;
+]]
+
+local tcp_client_sender = {}
+
+local libnet = require "libnet"
+
+--[[
+数据发送队列,数据结构为:
+{
+    [1] = {data="data1", cb={func=callback_function1, para=callback_para1}},
+    [2] = {data="data2", cb={func=callback_function2, para=callback_para2}},
+}
+data的内容为真正要发送的数据,必须存在;
+func的内容为数据发送结果的用户回调函数,可以不存在
+para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
+]]
+local send_queue = {}
+
+-- tcp_client_main的任务名
+tcp_client_sender.TASK_NAME = "tcp_client_main"
+
+-- "SEND_DATA_REQ"消息的处理函数
+local function send_data_req_proc_func(tag, data, cb)
+    log.info("DATA",tag,data)
+    -- 将原始数据增加前缀,然后插入到发送队列send_queue中
+    table.insert(send_queue, {data=data, cb=cb})
+    -- 通知tcp_client_main主任务有数据需要发送
+    -- tcp_client_main主任务如果处在libnet.wait调用的阻塞等待状态,就会退出阻塞状态
+    sysplus.sendMsg(tcp_client_sender.TASK_NAME, socket.EVENT, 0)
+end
+
+-- 数据发送应用逻辑处理入口
+function tcp_client_sender.proc(task_name, socket_client)
+    local send_item
+    local result, buff_full
+
+    -- 遍历数据发送队列send_queue
+    while #send_queue>0 do
+        -- 取出来第一条数据赋值给send_item
+        -- 同时从队列send_queue中删除这一条数据
+        send_item = table.remove(send_queue,1)
+
+        -- 发送这条数据,超时时间15秒钟
+        result, buff_full = libnet.tx(task_name, 15000, socket_client, send_item.data)
+
+        -- 发送失败
+        if not result then
+            log.error("tcp_client_sender.proc", "libnet.tx error")
+
+            -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
+            if send_item.cb and send_item.cb.func then
+                send_item.cb.func(false, send_item.cb.para)
+            end
+
+            return false
+        end
+
+        -- 如果内核固件中缓冲区满了,则将send_item再次插入到send_queue的队首位置,等待下次尝试发送
+        if buff_full then
+            log.error("tcp_client_sender.proc", "buffer is full, wait for the next time")
+            table.insert(send_queue, 1, send_item)
+            return true
+        end
+
+        log.info("tcp_client_sender.proc", "send success")
+        -- 发送成功,如果当前发送的数据有用户回调函数,则执行用户回调函数
+        if send_item.cb and send_item.cb.func then
+            send_item.cb.func(true, send_item.cb.para)
+        end
+    end
+
+    return true
+end
+
+-- 数据发送应用逻辑异常处理入口
+function tcp_client_sender.exception_proc()
+    -- 遍历数据发送队列send_queue
+    while #send_queue>0 do
+        local send_item = table.remove(send_queue,1)
+        -- 发送失败,如果当前发送的数据有用户回调函数,则执行用户回调函数
+        if send_item.cb and send_item.cb.func then
+            send_item.cb.func(false, send_item.cb.para)
+        end
+    end
+end
+
+-- 订阅"SEND_DATA_REQ"消息;
+-- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
+-- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
+sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
+
+return tcp_client_sender

+ 165 - 0
module/Air8000/demo/gnss/combination/vibration.lua

@@ -0,0 +1,165 @@
+--[[
+@module  vibration
+@summary 利用加速度传感器da221实现中断触发gnss定位
+@version 1.0
+@date    2025.08.01
+@author  李源龙
+@usage
+使用Air8000利用内置的da221加速度传感器实现震动中断触发gnss定位,给了两种方式,
+第一种是加速度传感器震动之后触发,触发之后开始打开gnss,进行定位,定位成功之后每5s上传一次经纬度数据,
+假设10s内没有再触发震动,则关闭gnss,等待下一次震动触发
+
+第二种方式是震动触发之后计算为一次触发,如果10s内触发5次有效震动,则开启后续逻辑,如果10s内没有触发5次,
+则判定为无效震动,等待下一次触发,如果是有效震动就打开gnss,进行定位,
+定位成功之后每5s上传一次经纬度数据到服务器,有效震动触发之后有30分钟的等待时间,在此期间,如果触发有效震动则
+不去进行后续逻辑处理,30分钟时间到了之后,等待下一次有效震动
+具体使用哪种方式可以根据实际需求选择
+]]
+
+exvib=require("exvib")
+tcp_client_main=require("tcp_client_main")
+
+local intPin=gpio.WAKEUP2   --中断检测脚,内部固定wakeup2
+local tid   --获取定时打开的定时器id
+local num=0 --计数器 
+local ticktable={0,0,0,0,0} --存放5次中断的tick值,用于做有效震动对比
+local eff=false --有效震动标志位,用于判断是否触发定位
+
+
+local function vib_cb(tag)
+    log.info("TAGmode1_cb+++++++++",tag)
+     local  rmc=exgnss.rmc(0)    --获取rmc数据
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(0)))
+    local data=string.format('{"lat":%5f,"lng":%5f}', rmc.lat, rmc.lng)
+    sys.publish("SEND_DATA_REQ", "gnssnormal", data) --发送数据到服务器
+
+end
+--定位成功就5s发送一包数据到服务器
+local function gnss_state(event, ticks)
+    -- event取值有
+    -- "FIXED":string类型 定位成功
+    -- "LOSE": string类型 定位丢失
+    -- "CLOSE": string类型 GNSS关闭,仅配合使用gnss.lua有效
+
+    -- ticks number类型 是事件发生的时间,一般可以忽略
+    log.info("exgnss", "state", event)
+    if event=="FIXED" then
+        log.info("定位成功")
+    end
+end
+
+sys.subscribe("GNSS_STATE",gnss_state)
+
+--有效震动模式
+--tick计数器,每秒+1用于存放5次中断的tick值,用于做有效震动对比
+-- local function tick()
+--     num=num+1
+-- end
+-- --每秒运行一次计时
+-- sys.timerLoopStart(tick,1000)
+
+-- --有效震动判断
+-- local function ind()
+--     log.info("int", gpio.get(intPin))
+--     if gpio.get(intPin) == 1 then
+--         --接收数据如果大于5就删掉第一个
+--         if #ticktable>=5 then
+--             log.info("table.remove",table.remove(ticktable,1))
+--         end
+--         --存入新的tick值
+--         table.insert(ticktable,num)
+--         log.info("tick",num,(ticktable[5]-ticktable[1]<10),ticktable[5]>0)
+--         log.info("tick2",ticktable[1],ticktable[2],ticktable[3],ticktable[4],ticktable[5])
+--         --表长度为5且,第5次中断时间间隔减去第一次间隔小于10s,且第5次值为有效值
+--         if #ticktable>=5 and (ticktable[5]-ticktable[1]<10 and ticktable[1]>0) then
+--             log.info("vib", "xxx")
+--             --是否要去触发有效震动逻辑
+--             if eff==false then
+--                 sys.publish("EFFECTIVE_VIBRATION")
+--             end
+--         end
+--     end
+-- end
+
+-- --设置30s分钟之后再判断是否有效震动函数
+-- local function num_cb()
+--     eff=false
+-- end
+
+-- local function eff_vib()
+--     --触发之后eff设置为true,30分钟之后再触发有效震动
+--     eff=true
+--     --30分钟之后再触发有效震动
+--     sys.timerStart(num_cb,180000)
+--     --判断gnss是否处于打开状态
+--     if exgnss.is_active(exgnss.DEFAULT,{tag="vib"})~=true then
+--         log.info("nmea", "is_open", "false")
+--         exgnss.open(exgnss.DEFAULT,{tag="vib",cb=vib_cb}) 
+--         tid=sys.timerLoopStart(vib_cb, 5000)
+--     else
+--         log.info("nmea", "is_open", "true")
+--     end
+-- end
+
+-- sys.subscribe("EFFECTIVE_VIBRATION",eff_vib)
+
+
+
+--持续震动模式
+--10s没有触发中断就停止
+local function vib_close()
+    exgnss.close(exgnss.DEFAULT,{tag="vib"})
+    sys.timerStop(tid)
+end
+
+--持续震动模式中断函数
+local function ind()
+    log.info("int", gpio.get(intPin))
+    if gpio.get(intPin) == 1 then
+        --10s没有触发中断就停止
+        sys.timerStart(vib_close,10000)
+        local x,y,z =  exvib.read_xyz()      --读取x,y,z轴的数据
+        log.info("x", x..'g', "y", y..'g', "z", z..'g')
+        --判断gnss是否处于打开状态
+        if exgnss.is_active(exgnss.DEFAULT,{tag="vib"})~=true then
+            log.info("nmea", "is_open", "false")
+            exgnss.open(exgnss.DEFAULT,{tag="vib",cb=vib_cb}) 
+            tid=sys.timerLoopStart(vib_cb, 5000)
+        else
+            log.info("nmea", "is_open", "true")
+        end
+    end
+end
+
+
+local function gnss_fnc()
+    log.info("gnss_fnc111")
+    local gnssotps={
+        gnssmode=1, --1为卫星全定位,2为单北斗
+        agps_enable=true,    --是否使用AGPS,开启AGPS后定位速度更快,会访问服务器下载星历,星历时效性为北斗1小时,GPS4小时,默认下载星历的时间为1小时,即一小时内只会下载一次
+        debug=true,    --是否输出调试信息
+        -- uart=2,    --使用的串口,780EGH和8000默认串口2
+        -- uartbaud=115200,    --串口波特率,780EGH和8000默认115200
+        -- bind=1, --绑定uart端口进行GNSS数据读取,是否设置串口转发,指定串口号
+        -- rtc=false    --定位成功后自动设置RTC true开启,flase关闭
+        ----因为GNSS使用辅助定位的逻辑,是模块下载星历文件,然后把数据发送给GNSS芯片,
+        ----芯片解析星历文件需要10-30s,默认GNSS会开启20s,该逻辑如果不执行,会导致下一次GNSS开启定位是冷启动,
+        ----定位速度慢,大概35S左右,所以默认开启,如果可以接受下一次定位是冷启动,可以把auto_open设置成false
+        ----需要注意的是热启动在定位成功之后,需要再开启3s左右才能保证本次的星历获取完成,如果对定位速度有要求,建议这么处理
+        -- auto_open=false 
+    }
+    exgnss.setup(gnssotps)
+    -- 1,微小震动检测,用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
+    -- 2,运动检测,用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
+    -- 3,跌倒检测,用于人或物体瞬间跌倒时的检测;加速度量程8g;
+    --打开震动检测功能
+    exvib.open(1)
+    --设置gpio防抖100ms
+    gpio.debounce(intPin, 100)
+    --设置gpio中断触发方式wakeup2唤醒脚默认为双边沿触发
+    gpio.setup(intPin, ind)
+
+end
+
+sys.taskInit(gnss_fnc)
+

+ 0 - 160
module/Air8000/demo/gnss/da221.lua

@@ -1,160 +0,0 @@
-
-local da221={}
-
-local i2cId = 0
-local intPin = gpio.WAKEUP2
-local interruptMode = true      -- 中断模式
--- 是否打印日志
-local logSwitch = true
-local moduleName = "da221"
-
-local da221Addr = 0x27
-local soft_reset = {0x00, 0x24}         -- 软件复位地址
-local chipid_addr = 0x01                -- 芯片ID地址
-local rangeaddr = {0x0f, 0x00}          -- 设置加速度量程,默认2g
--- local rangeaddr = {0x0f, 0x01}          -- 设置加速度量程,默认4g
--- local rangeaddr = {0x0f, 0x10}          -- 设置加速度量程,默认8g
-local int_set1_reg = {0x16, 0x87}       --设置x,y,z发生变化时,产生中断
-local int_set2_reg = {0x17, 0x10}       --使能新数据中断,数据变化时,产生中断,本程序不设置
-local int_map1_reg = {0x19, 0x04}       --运动的时候,产生中断
-local int_map2_reg = {0x1a, 0x01}
-
-local active_dur_addr = {0x27, 0x01}    -- 设置激活时间,默认0x01
-local active_ths_addr = {0x28, 0x33}    -- 设置激活阈值,灵敏度最高
--- local active_ths_addr = {0x28, 0x80}    -- 设置激活阈值,灵敏度适中
--- local active_ths_addr = {0x28, 0xFE}    -- 设置激活阈值,灵敏度最低
-local odr_addr = {0x10, 0x08}           -- 设置采样率 100Hz
-local mode_addr = {0x11, 0x00}          -- 设置正常模式
-local int_latch_addr = {0x21, 0x02}     -- 设置中断锁存
-
-local x_lsb_reg = 0x02 -- X轴LSB寄存器地址
-local x_msb_reg = 0x03 -- X轴MSB寄存器地址
-local y_lsb_reg = 0x04 -- Y轴LSB寄存器地址
-local y_msb_reg = 0x05 -- Y轴MSB寄存器地址
-local z_lsb_reg = 0x06 -- Z轴LSB寄存器地址
-local z_msb_reg = 0x07 -- Z轴MSB寄存器地址
-
-local active_state = 0x0b -- 激活状态寄存器地址
-local active_state_data
-
---[[
-    获取da221的xyz轴数据
-@api da221.read_xyz()
-@return number x轴数据,number y轴数据,number z轴数据
-@usage
-    local x,y,z =  da221.read_xyz()      --读取x,y,z轴的数据
-        log.info("x", x..'g', "y", y..'g', "z", z..'g')
-]]
-function da221.read_xyz()
-    -- da221是LSB在前,MSB在后,每个寄存器都是1字节数据,每次读取都是6个寄存器数据一起获取
-    -- 因此直接从X轴LSB寄存器(0x02)开始连续读取6字节数据(X/Y/Z各2字节),避免出现数据撕裂问题
-    i2c.send(i2cId, da221Addr, x_lsb_reg, 1)
-    local recv_data = i2c.recv(i2cId, da221Addr, 6)
-
-    -- LSB数据格式为: D[3] D[2] D[1] D[0] unused unused unused unused
-    -- MSB数据格式为: D[11] D[10] D[9] D[8] D[7] D[6] D[5] D[4]
-    -- 数据位为12位,需要将MSB数据左移4位,LSB数据右移4位,最后进行或运算
-    -- 解析X轴数据 (LSB在前,MSB在后)
-    local x_data = (string.byte(recv_data, 2) << 4) | (string.byte(recv_data, 1) >> 4)
-
-    -- 解析Y轴数据 (LSB在前,MSB在后)
-    local y_data = (string.byte(recv_data, 4) << 4) | (string.byte(recv_data, 3) >> 4)
-
-    -- 解析Z轴数据 (LSB在前,MSB在后)
-    local z_data = (string.byte(recv_data, 6) << 4) | (string.byte(recv_data, 5) >> 4)
-
-    -- 转换为12位有符号整数
-    -- 判断X轴数据是否大于2047,若大于则表示数据为负数
-    -- 因为12位有符号整数的范围是 -2048 到 2047,原始数据为无符号形式,大于2047的部分需要转换为负数
-    -- 通过减去4096 (2^12) 将无符号数转换为对应的有符号负数
-    if x_data > 2047 then x_data = x_data - 4096 end
-    -- 判断Y轴数据是否大于2047,若大于则进行同样的有符号转换
-    if y_data > 2047 then y_data = y_data - 4096 end
-    -- 判断Z轴数据是否大于2047,若大于则进行同样的有符号转换
-    if z_data > 2047 then z_data = z_data - 4096 end
-
-    -- 转换为加速度值(单位:g)
-    local x_accel = x_data / 1024
-    local y_accel = y_data / 1024
-    local z_accel = z_data / 1024
-
-    -- 输出加速度值(单位:g)
-    return x_accel, y_accel, z_accel
-end
-
-
-local function da221_init()
-    gpio.setup(24, 1, gpio.PULLUP)  -- gsensor 开关
-    gpio.setup(164, 1, gpio.PULLUP) -- air8000 和解码芯片公用
-    gpio.setup(147, 1, gpio.PULLUP) -- camera的供电使能脚
-    log.info("da221 init...")
-    --关闭i2c
-    i2c.close(i2cId)
-    --重新打开i2c,i2c速度设置为低速
-    i2c.setup(i2cId, i2c.SLOW)
-
-    sys.wait(50)
-    i2c.send(i2cId, da221Addr, soft_reset, 1)
-    sys.wait(50)
-    i2c.send(i2cId, da221Addr, chipid_addr, 1)
-    local chipid = i2c.recv(i2cId, da221Addr, 1)
-    log.info("i2c", "chipid",chipid:toHex())
-    if string.byte(chipid) == 0x13 then
-        log.info("da221 init success")
-        sys.publish("DA221_INIT_SUCCESS")
-    else
-        log.info("da221 init fail")
-    end
-
-    -- 设置寄存器
-    i2c.send(i2cId, da221Addr, rangeaddr, 1)    --设置加速度量程,默认2g
-    sys.wait(5)
-    i2c.send(i2cId, da221Addr, int_set1_reg, 1) --设置x,y,z发生变化时,产生中断
-    sys.wait(5)
-    i2c.send(i2cId, da221Addr, int_map1_reg, 1)--运动的时候,产生中断
-    sys.wait(5)
-    i2c.send(i2cId, da221Addr, active_dur_addr, 1)-- 设置激活时间,默认0x00
-    sys.wait(5)
-    i2c.send(i2cId, da221Addr, active_ths_addr, 1)-- 设置激活阈值
-    sys.wait(5)
-    i2c.send(i2cId, da221Addr, mode_addr, 1)-- 设置模式
-    sys.wait(5)
-    i2c.send(i2cId, da221Addr, odr_addr, 1)-- 设置采样率
-    sys.wait(5)
-    i2c.send(i2cId, da221Addr, int_latch_addr, 1)-- 设置中断锁存 中断一旦触发将保持,直到手动清除
-    sys.wait(5)
-end
-
---[[
-    打开da221
-@api da221.open(mode)
-@number da221模式设置,1、静态/微动检测,使用场景:微振动检测、手势识别;2、常规运动监测,使用场景:运动监测、车载设备;3、高动态冲击检测,使用场景:碰撞检测、工业冲击
-@return nil
-@usage
-    da221.open(1)
-]]
-function da221.open(mode)
-    if mode==1 or tonumber(mode)==1 then
-        --轻微检测
-        log.info("轻微检测")
-        rangeaddr = {0x0f, 0x00}          -- 设置加速度量程,默认2g
-        active_ths_addr = {0x28, 0x1A}    -- 设置激活阈值
-        odr_addr = {0x10, 0x04}           -- 设置采样率 15.63Hz
-        active_dur_addr = {0x27, 0x01}    -- 设置激活时间,默认0x01
-    elseif mode==2 or tonumber(mode)==2 then
-        --常规检测
-        rangeaddr = {0x0f, 0x01}          -- 设置加速度量程,默认4g
-        active_ths_addr = {0x28, 0x26}    -- 设置激活阈值
-        odr_addr = {0x10, 0x08}           -- 设置采样率 250Hz
-        active_dur_addr = {0x27, 0x14}    -- 设置激活时间,默认0x01
-    elseif mode==3 or tonumber(mode)==3 then
-        --高动态检测
-        rangeaddr = {0x0f, 0x10}          -- 设置加速度量程,默认8g
-        active_ths_addr = {0x28, 0x80}    -- 设置激活阈值
-        odr_addr = {0x10, 0x0F}           -- 设置采样率 1000Hz
-        active_dur_addr = {0x27, 0x04}    -- 设置激活时间,默认0x01
-    end
-    sys.taskInit(da221_init)
-end
-
-return da221

+ 0 - 69
module/Air8000/demo/gnss/da221gnss.lua

@@ -1,69 +0,0 @@
---[[
-@module  da221gnss
-@summary 利用加速度传感器da221实现中断触发gnss定位
-@version 1.0
-@date    2025.08.01
-@author  李源龙
-@usage
-使用Air8000利用内置的da221加速度传感器实现中断触发gnss定位
-]]
-gnss=require("gnss")
-tcp=require("tcp")
-da221=require("da221")
-
-local intPin=gpio.WAKEUP2
-local tid
-local function mode1_cb(tag)
-    log.info("TAGmode1_cb+++++++++",tag)
-    local  rmc=gnss.getRmc(0)
-    log.info("nmea", "rmc", json.encode(gnss.getRmc(0)))
-    tcp.latlngfnc(rmc.lat,rmc.lng)
-end
-local function timer1()
-    gnss.close(gnss.DEFAULT,{tag="MODE1"})
-    sys.timerStop(tid)
-end
-
-local function ind()
-    log.info("int", gpio.get(intPin))
-    if gpio.get(intPin) == 1 then
-        sys.timerStart(timer1,10000)
-        local x,y,z =  da221.read_xyz()      --读取x,y,z轴的数据
-        log.info("x", x..'g', "y", y..'g', "z", z..'g')
-        if gnss.openres()~=true then
-            log.info("nmea", "openres", "false")
-            gnss.open(gnss.DEFAULT,{tag="MODE1",cb=mode1_cb}) 
-            tid=sys.timerLoopStart(mode1_cb, 5000)
-        else
-            log.info("nmea", "openres", "true")
-        end
-    end
-end
-
-local function gnss_fnc()
-    log.info("gnss_fnc111")
-    local gnssotps={
-        gnssmode=1, --1为卫星全定位,2为单北斗
-        agps_enable=true,    --是否使用AGPS,开启AGPS后定位速度更快,会访问服务器下载星历,星历时效性为北斗1小时,GPS4小时,默认下载星历的时间为1小时,即一小时内只会下载一次
-        debug=true,    --是否输出调试信息
-        -- uart=2,    --使用的串口,780EGH和8000默认串口2
-        -- uartbaud=115200,    --串口波特率,780EGH和8000默认115200
-        -- bind=1, --绑定uart端口进行GNSS数据读取,是否设置串口转发,指定串口号
-        -- rtc=false    --定位成功后自动设置RTC true开启,flase关闭
-        ----因为GNSS使用辅助定位的逻辑,是模块下载星历文件,然后把数据发送给GNSS芯片,
-        ----芯片解析星历文件需要10-30s,默认GNSS会开启20s,该逻辑如果不执行,会导致下一次GNSS开启定位是冷启动,
-        ----定位速度慢,大概35S左右,所以默认开启,如果可以接受下一次定位是冷启动,可以把agps_autoopen设置成false
-        ----需要注意的是热启动在定位成功之后,需要再开启3s左右才能保证本次的星历获取完成,如果对定位速度有要求,建议这么处理
-        -- agps_autoopen=false 
-    }
-    gnss.setup(gnssotps)
-    --1、静态/微动检测,使用场景:微振动检测、手势识别;
-    --2、常规运动监测,使用场景:运动监测、车载设备;
-    --3、高动态冲击检测,使用场景:碰撞检测、工业冲击
-    da221.open(1)
-    gpio.debounce(intPin, 100)
-    gpio.setup(intPin, ind)
-
-end
-
-sys.taskInit(gnss_fnc)

+ 0 - 223
module/Air8000/demo/gnss/lbsLoc2.lua

@@ -1,223 +0,0 @@
---[[
-@module lbsLoc2
-@summary 基站定位v2
-@version 1.0
-@date    2023.5.23
-@author  wendal
-@demo    lbsLoc2
-@usage
--- 注意:
--- 1. 因使用了sys.wait()所有api需要在协程中使用
--- 2. 仅支持单基站定位, 即当前联网的基站
--- 3. 本服务当前处于测试状态
-sys.taskInit(function()
-    sys.waitUntil("IP_READY", 30000)
-    -- mobile.reqCellInfo(60)
-    -- sys.wait(1000)
-    while mobile do -- 没有mobile库就没有基站定位
-        mobile.reqCellInfo(15)
-        sys.waitUntil("CELL_INFO_UPDATE", 3000)
-        local lat, lng, t = lbsLoc2.request(5000)
-        -- local lat, lng, t = lbsLoc2.request(5000, "bs.openluat.com")
-        log.info("lbsLoc2", lat, lng, (json.encode(t or {})))
-        sys.wait(60000)
-    end
-end)
-]]
-
-local sys = require "sys"
-
-local lbsLoc2 = {}
-
-local function numToBcdNum(inStr,destLen)
-    local l,t,num = string.len(inStr or ""),{}
-    destLen = destLen or (inStr:len()+1)/2
-    for i=1,l,2 do
-        num = tonumber(inStr:sub(i,i+1),16)
-        if i==l then
-            num = 0xf0+num
-        else
-            num = (num%0x10)*0x10 + (num-(num%0x10))/0x10
-        end
-        table.insert(t,num)
-    end
-
-    local s = string.char(unpack(t))
-
-    l = string.len(s)
-    if l < destLen then
-        s = s .. string.rep("\255",destLen-l)
-    elseif l > destLen then
-        s = string.sub(s,1,destLen)
-    end
-
-    return s
-end
-
---- BCD编码格式字符串 转化为 号码ASCII字符串(仅支持数字)
--- @string num 待转换字符串
--- @return string data,转换后的字符串
--- @usage
-local function bcdNumToNum(num)
-	local byte,v1,v2
-	local t = {}
-
-	for i=1,num:len() do
-		byte = num:byte(i)
-		v1,v2 = bit.band(byte,0x0f),bit.band(bit.rshift(byte,4),0x0f)
-
-		if v1 == 0x0f then break end
-		table.insert(t,v1)
-
-		if v2 == 0x0f then break end
-		table.insert(t,v2)
-	end
-
-	return table.concat(t)
-end
-
-lbsLoc2.imei = numToBcdNum(mobile.imei())
-
-local function enCellInfo(s)
-    -- 改造成单基站, 反正服务器也只认单基站
-    local v = s[1]
-    log.info("cell", json.encode(v))
-    local ret = pack.pack(">HHbbi",v.tac,v.mcc,v.mnc,31,v.cid)
-    return string.char(1)..ret
-end
-
-local function trans(str)
-    local s = str
-    if str:len()<10 then
-        s = str..string.rep("0",10-str:len())
-    end
-
-    return s:sub(1,3).."."..s:sub(4,10)
-end
-
---[[
-执行定位请求
-@api lbsLoc2.request(timeout, host, port, reqTime)
-@number 请求超时时间,单位毫秒,默认15000
-@number 服务器地址,有默认值,可以是域名,一般不需要填
-@number 服务器端口,默认12411,一般不需要填
-@bool   是否要求返回服务器时间
-@return string  若成功,返回定位坐标的纬度,否则会返还nil
-@return string  若成功,返回定位坐标的经度,否则会返还nil
-@return table   服务器时间,东八区时间. 当reqTime为true且定位成功才会返回
-@usage
--- 关于坐标系
--- 部分情况下会返回GCJ02坐标系, 部分情况返回的是WGS84坐标
--- 历史数据已经无法分辨具体坐标系
--- 鉴于两种坐标系之间的误差并不大,小于基站定位本身的误差, 纠偏的意义不大
-sys.taskInit(function()
-    sys.waitUntil("IP_READY", 30000)
-    -- mobile.reqCellInfo(60)
-    -- sys.wait(1000)
-    while mobile do -- 没有mobile库就没有基站定位
-        mobile.reqCellInfo(15)
-        sys.waitUntil("CELL_INFO_UPDATE", 3000)
-        local lat, lng, t = lbsLoc2.request(5000)
-        -- local lat, lng, t = lbsLoc2.request(5000, "bs.openluat.com")
-        log.info("lbsLoc2", lat, lng, (json.encode(t or {})))
-        sys.wait(60000)
-    end
-end)
-]]
-function lbsLoc2.request(timeout, host, port, reqTime)
-    if mobile.status() == 0 then
-        return
-    end
-    local hosts = host and {host} or {"free.bs.air32.cn", "bs.openluat.com"}
-    port = port and tonumber(port) or 12411
-    local sc = socket.create(nil, function(sc, event)
-        -- log.info("lbsLoc", "event", event, socket.ON_LINE, socket.TX_OK, socket.EVENT)
-        if event == socket.ON_LINE then
-            --log.info("lbsLoc", "已连接")
-            sys.publish("LBS_CONACK")
-        elseif event == socket.TX_OK then
-            --log.info("lbsLoc", "发送完成")
-            sys.publish("LBS_TX")
-        elseif event == socket.EVENT then
-            --log.info("lbsLoc", "有数据来")
-            sys.publish("LBS_RX")
-        end
-    end)
-    if sc == nil then
-        return
-    end
-    -- socket.debug(sc, true)
-    socket.config(sc, nil, true)
-    local rxbuff = zbuff.create(64)
-    for k, rhost in pairs(hosts) do
-        local reqStr = string.char(0, (reqTime and 4 or 0) +8) .. lbsLoc2.imei
-        local tmp = nil
-        if mobile.scell then
-            local scell = mobile.scell()
-            if scell and scell.mcc then
-                -- log.debug("lbsLoc2", "使用当前驻网基站的信息")
-                tmp = pack.pack(">bHHbbi", 1, scell.tac, scell.mcc, scell.mnc, 31, scell.eci)
-            end
-        end
-        if tmp == nil then
-            local cells = mobile.getCellInfo()
-            if cells == nil or #cells == 0 then
-                socket.release(sc)
-                return
-            end
-            reqStr = reqStr .. enCellInfo(cells)
-        else
-            reqStr = reqStr .. tmp
-        end
-        -- log.debug("lbsLoc2", "待发送数据", (reqStr:toHex()))
-        log.debug("lbsLoc2", rhost, port)
-        if socket.connect(sc, rhost, port) and sys.waitUntil("LBS_CONACK", 1000) then
-            if socket.tx(sc, reqStr) and sys.waitUntil("LBS_TX", 1000) then
-                socket.wait(sc)
-                if sys.waitUntil("LBS_RX", timeout or 15000) then
-                    local succ, data_len = socket.rx(sc, rxbuff)
-                    -- log.debug("lbsLoc", "rx", succ, data_len)
-                    if succ and data_len > 0 then
-                        socket.close(sc)
-                        break
-                    else
-                        log.debug("lbsLoc", "rx数据失败", rhost)
-                    end
-                else
-                    log.debug("lbsLoc", "等待数据超时", rhost)
-                end
-            else
-                log.debug("lbsLoc", "tx调用失败或TX_ACK超时", rhost)
-            end
-        else
-            log.debug("lbsLoc", "connect调用失败或CONACK超时", rhost)
-        end
-        socket.close(sc)
-        --sys.wait(100)
-    end
-    sys.wait(100)
-    socket.release(sc)
-    if rxbuff:used() > 0 then
-        local resp = rxbuff:toStr(0, rxbuff:used())
-        log.debug("lbsLoc2", "rx", (resp:toHex()))
-        if resp:len() >= 11 and(resp:byte(1) == 0 or resp:byte(1) == 0xFF) then
-            local lat = trans(bcdNumToNum(resp:sub(2, 6)))
-            local lng = trans(bcdNumToNum(resp:sub(7, 11)))
-            local t = nil
-            if resp:len() >= 17 then
-                t = {
-                    year=resp:byte(12) + 2000,
-                    month=resp:byte(13),
-                    day=resp:byte(14),
-                    hour=resp:byte(15),
-                    min=resp:byte(16),
-                    sec=resp:byte(17),
-                }
-            end
-            return lat, lng, t
-        end
-    end
-    rxbuff:del()
-end
-
-return lbsLoc2

+ 0 - 109
module/Air8000/demo/gnss/readme.md

@@ -1,109 +0,0 @@
-
-## 演示功能概述
-
-使用Air8000核心板,通过gnss.lua扩展库,开启GNSS定位,展示模块的三种功耗模式:正常模式,低功耗模式,PSM+模式 
-
-## 演示硬件环境
-
-1、Air8000核心板一块
-
-2、TYPE-C USB数据线一根
-
-3、gnss天线一根
-
-4、Air8000核心板和数据线的硬件接线方式为
-
-- Air8000核心板通过TYPE-C USB口供电;(核心板USB旁边的开关拨到on一端)
-
-- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
-
-
-## 演示软件环境
-
-1、Luatools下载调试工具
-
-2、[Air8000 V2010版本固件](https://docs.openluat.com/air8000/luatos/firmware/)
-
-## 演示核心步骤
-
-1、搭建好硬件环境
-
-2、通过Luatools将demo与固件烧录到核心板中
-
-3、烧录好后,板子开机将会在Luatools上看到如下打印:
-
-(1) 开机连接到服务器:
-
-```lua
-[2025-07-27 15:51:28.235][000000003.099] D/mobile NETIF_LINK_ON -> IP_READY
-[2025-07-27 15:51:28.287][000000003.100] D/socket connect to 112.125.89.8,45259
-[2025-07-27 15:51:28.338][000000003.100] network_socket_connect 1573:network 0 local port auto select 50641
-[2025-07-27 15:51:28.369][000000003.137] D/mobile TIME_SYNC 0
-[2025-07-27 15:51:28.419][000000003.151] network_default_socket_callback 1103:before process socket 0,event:0xf2000009(连接成功),state:3(正在连接),wait:2(等待连接完成)
-[2025-07-27 15:51:28.471][000000003.152] network_default_socket_callback 1107:after process socket 0,state:5(在线),wait:0(无等待)
-[2025-07-27 15:51:28.523][000000003.192] network_default_socket_callback 1103:before process socket 0,event:0xf2000004(发送成功),state:5(在线),wait:3(等待发送完成)
-[2025-07-27 15:51:28.564][000000003.192] network_default_socket_callback 1107:after process socket 0,state:5(在线),wait:0(无等待)
-[2025-07-27 15:51:28.615][000000003.194] I/user.3214816 114708 116960
-[2025-07-27 15:51:43.110][000000018.196] I/user.3214816 108516 116960
-[2025-07-27 15:51:58.123][000000033.198] I/user.3214816 108552 116960
-[2025-07-27 15:52:13.118][000000048.199] I/user.3214816 108632 116960
-
-```
-
-(2) 开启GNSS定位成功后发送数据到服务器:
-
-```lua
-[2025-07-27 15:52:25.226][000000060.305] I/user.gnss.open 2 MODE1 60 function: 0C7F0448
-[2025-07-27 15:52:25.260][000000060.306] Uart_ChangeBR 1338:uart2, 115200 115203 26000000 3611
-[2025-07-27 15:52:25.293][000000060.307] I/user.全卫星开启
-[2025-07-27 15:52:25.335][000000060.307] I/user.agps开启
-[2025-07-27 15:52:25.370][000000060.308] D/sntp query ntp.aliyun.com
-[2025-07-27 15:52:25.383][000000060.308] dns_run 674:ntp.aliyun.com state 0 id 1 ipv6 0 use dns server2, try 0
-[2025-07-27 15:52:25.392][000000060.313] I/user.gnss._open
-[2025-07-27 15:52:25.402][000000060.478] dns_run 691:dns all done ,now stop
-[2025-07-27 15:52:25.452][000000060.541] D/sntp Unix timestamp: 1753602745
-[2025-07-27 15:52:25.476][000000060.545] I/user.gnss.opts 开始执行AGPS
-[2025-07-27 15:52:25.505][000000060.549] I/user.os.time 1753602745
-[2025-07-27 15:52:25.526][000000060.549] I/user.agps_time 1753602626
-[2025-07-27 15:52:25.551][000000060.553] I/user.gnss.opts 星历不需要更新 119
-[2025-07-27 15:52:25.563][000000060.570] D/user.lbsLoc2 free.bs.air32.cn 12411
-[2025-07-27 15:52:25.583][000000060.571] D/socket connect to free.bs.air32.cn,12411
-[2025-07-27 15:52:25.596][000000060.571] dns_run 674:free.bs.air32.cn state 0 id 2 ipv6 0 use dns server2, try 0
-[2025-07-27 15:52:25.624][000000060.598] dns_run 691:dns all done ,now stop
-[2025-07-27 15:52:25.661][000000060.737] D/user.lbsLoc2 rx 0030540816031183837001
-[2025-07-27 15:52:25.681][000000060.740] I/user.lbsLoc2 34.580613000000 113.83807100000
-[2025-07-27 15:52:25.706][000000060.745] I/user.gnss.opts 写入星历数据 长度 5294
-[2025-07-27 15:52:25.743][000000060.746] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:25.764][000000060.846] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:25.859][000000060.947] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:25.971][000000061.048] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:26.071][000000061.149] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:26.166][000000061.250] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:26.225][000000061.313] I/user.gnss.timerFnc@1 2 MODE1 60 60 nil
-[2025-07-27 15:52:26.267][000000061.351] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:26.364][000000061.452] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:26.465][000000061.553] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:26.576][000000061.654] I/user.gnss AGNSS write >>> 512
-[2025-07-27 15:52:26.676][000000061.755] I/user.gnss AGNSS write >>> 174
-[2025-07-27 15:52:26.783][000000061.857] I/user.gnss.opts 写入GPS坐标 3434.8367800000 11350.284260000
-[2025-07-27 15:52:26.836][000000061.857] I/user.gnss.opts 参考时间 $AIDTIME,2025,7,27,7,52,26,000
-[2025-07-27 15:52:26.852][000000061.878] I/user.gnss.opts 写入AGPS参考位置 $AIDPOS,3434.8367800,N,11350.2842600,E,1.0
-
-[2025-07-27 15:52:27.233][000000062.314] I/user.gnss.timerFnc@1 2 MODE1 60 59 nil
-[2025-07-27 15:52:28.111][000000063.201] I/user.3214816 121176 121936
-[2025-07-27 15:52:28.228][000000063.315] I/user.gnss.timerFnc@1 2 MODE1 60 58 nil
-[2025-07-27 15:52:29.237][000000064.316] I/user.gnss.timerFnc@1 2 MODE1 60 57 nil
-[2025-07-27 15:52:30.236][000000065.317] I/user.gnss.timerFnc@1 2 MODE1 60 56 nil
-[2025-07-27 15:52:30.417][000000065.496] I/gnss Fixed 343481049 1135041395
-[2025-07-27 15:52:30.487][000000065.575] I/user.gnss.statInd@1 true 2 MODE1 60 55 nil function: 0C7F0448
-[2025-07-27 15:52:31.232][000000066.318] I/user.gnss.timerFnc@1 2 MODE1 60 55 1
-[2025-07-27 15:52:31.276][000000066.319] I/user.TAGmode1_cb+++++++++ MODE1
-[2025-07-27 15:52:31.319][000000066.320] I/user.nmea rmc {"variation":0,"lat":3434.8105469,"min":52,"valid":true,"day":27,"lng":11350.4140625,"speed":0.2220000,"year":2025,"month":7,"sec":30,"hour":7,"course":302.4410095}
-[2025-07-27 15:52:31.336][000000066.321] I/user.gnss.close 2 MODE1 60 function: 0C7F0448
-[2025-07-27 15:52:31.352][000000066.328] I/user.gnss._close
-[2025-07-27 15:52:31.373][000000066.330] I/user.发送到服务器数据,长度 38
-[2025-07-27 15:52:31.394][000000066.456] network_default_socket_callback 1103:before process socket 0,event:0xf2000004(发送成功),state:5(在线),wait:3(等待发送完成)
-[2025-07-27 15:52:31.412][000000066.456] network_default_socket_callback 1107:after process socket 0,state:5(在线),wait:0(无等待)
-[2025-07-27 15:52:31.427][000000066.457] I/user.3214816 119380 122432
-[2025-07-27 15:52:46.373][000000081.459] I/user.3214816 113240 122432
-```

+ 118 - 0
module/Air8000/demo/gnss/single/gnss.lua

@@ -0,0 +1,118 @@
+--[[
+@module  gnss
+@summary gnss应用测试功能模块
+@version 1.0
+@date    2025.07.27
+@author  李源龙
+@usage
+该文件演示的功能会用到exgnss.lua扩展库
+
+--关于exgnss的三种应用场景:
+exgnss.DEFAULT:
+--- exgnss应用模式1.
+-- 打开gnss后,gnss定位成功时,如果有回调函数,会调用回调函数
+-- 使用此应用模式调用exgnss.open打开的“gnss应用”,必须主动调用exgnss.close
+-- 或者exgnss.close_all才能关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
+-- 通俗点说就是一直打开,除非自己手动关闭掉
+
+exgnss.TIMERORSUC:
+--- exgnss应用模式2.
+-- 打开gnss后,如果在gnss开启最大时长到达时,没有定位成功,如果有回调函数,
+-- 会调用回调函数,然后自动关闭此“gnss应用”
+-- 打开gnss后,如果在gnss开启最大时长内,定位成功,如果有回调函数,
+-- 会调用回调函数,然后自动关闭此“gnss应用”
+-- 打开gnss后,在自动关闭此“gnss应用”前,可以调用exgnss.close或者
+-- exgnss.close_all主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
+-- 通俗点说就是设置规定时间打开,如果规定时间内定位成功就会自动关闭此应用,
+-- 如果没有定位成功,时间到了也会自动关闭此应用
+
+exgnss.TIMER:
+--- exgnss应用模式3.
+-- 打开gnss后,在gnss开启最大时长时间到达时,无论是否定位成功,如果有回调函数,
+-- 会调用回调函数,然后自动关闭此“gnss应用”
+-- 打开gnss后,在自动关闭此“gnss应用”前,可以调用exgnss.close或者exgnss.close_all
+-- 主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
+-- 通俗点说就是设置规定时间打开,无论是否定位成功,到了时间都会自动关闭此应用,
+-- 和第二种的区别在于定位成功之后不会自动关闭,到时间之后才会自动关闭
+
+本示例主要是展示exgnss库的三种应用模式,然后关闭操作和查询应用是否有效操作,还有关闭全部应用操作,
+以及定位成功之后如何使用exgnss库获取gnss的rmc数据
+]]
+
+local function mode1_cb(tag)
+    log.info("TAGmode1_cb+++++++++",tag)
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(2)))
+end
+
+local function mode2_cb(tag)
+    log.info("TAGmode2_cb+++++++++",tag)
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(2)))
+end
+
+local function mode3_cb(tag)
+    log.info("TAGmode3_cb+++++++++",tag)
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(2)))
+end
+
+local function gnss_fnc()
+    local gnssotps={
+        gnssmode=1, --1为卫星全定位,2为单北斗
+        agps_enable=true,    --是否使用AGPS,开启AGPS后定位速度更快,会访问服务器下载星历,星历时效性为北斗1小时,GPS4小时,默认下载星历的时间为1小时,即一小时内只会下载一次
+        debug=true,    --是否输出调试信息
+        -- uart=2,    --使用的串口,780EGH和8000默认串口2
+        -- uartbaud=115200,    --串口波特率,780EGH和8000默认115200
+        -- bind=1, --绑定uart端口进行GNSS数据读取,是否设置串口转发,指定串口号
+        -- rtc=false    --定位成功后自动设置RTC true开启,flase关闭
+         ----因为GNSS使用辅助定位的逻辑,是模块下载星历文件,然后把数据发送给GNSS芯片,
+        ----芯片解析星历文件需要10-30s,默认GNSS会开启20s,该逻辑如果不执行,会导致下一次GNSS开启定位是冷启动,
+        ----定位速度慢,大概35S左右,所以默认开启,如果可以接受下一次定位是冷启动,可以把auto_open设置成false
+        ----需要注意的是热启动在定位成功之后,需要再开启3s左右才能保证本次的星历获取完成,如果对定位速度有要求,建议这么处理
+        -- auto_open=false 
+    }
+    --设置gnss参数
+    exgnss.setup(gnssotps)
+    --开启gnss应用
+    exgnss.open(exgnss.TIMER,{tag="modeTimer",val=60,cb=mode1_cb})  --使用TIMER模式,开启60s后关闭
+    exgnss.open(exgnss.DEFAULT,{tag="modeDefault",cb=mode2_cb}) --使用DEFAULT模式,开启后一直运行  
+    exgnss.open(exgnss.TIMERORSUC,{tag="modeTimerorsuc",val=60,cb=mode3_cb})    --使用TIMERORSUC模式,开启60s,如果定位成功,则直接关闭
+    sys.wait(40000)
+    log.info("关闭一个gnss应用,然后查看下所有应用的状态")
+    --关闭一个gnss应用
+    exgnss.close(exgnss.TIMER,{tag="modeTimer"})--关闭tag为modeTimer应用
+    --查询3个gnss应用状态
+    log.info("gnss应用状态1",exgnss.is_active(exgnss.TIMER,{tag="modeTimer"}))
+    log.info("gnss应用状态2",exgnss.is_active(exgnss.DEFAULT,{tag="modeDefault"}))
+    log.info("gnss应用状态3",exgnss.is_active(exgnss.TIMERORSUC,{tag="modeTimerorsuc"}))
+    sys.wait(10000)
+    --关闭所有gnss应用
+    exgnss.close_all()
+    --查询3个gnss应用状态
+    log.info("gnss应用状态1",exgnss.is_active(exgnss.TIMER,{tag="modeTimer"}))
+    log.info("gnss应用状态2",exgnss.is_active(exgnss.DEFAULT,{tag="modeDefault"}))
+    log.info("gnss应用状态3",exgnss.is_active(exgnss.TIMERORSUC,{tag="modeTimerorsuc"}))
+    --查询最后一次定位结果
+    local loc= exgnss.last_loc()
+    if loc then
+        log.info("lastloc", loc.lat,loc.lng)
+    end
+end
+
+sys.taskInit(gnss_fnc)
+
+
+--GNSS定位状态的消息处理函数:
+local function gnss_state(event, ticks)
+    -- event取值有
+    -- "FIXED":string类型 定位成功
+    -- "LOSE": string类型 定位丢失
+    -- "CLOSE": string类型 GNSS关闭,仅配合使用gnss.lua有效
+
+    -- ticks number类型 是事件发生的时间,一般可以忽略
+    log.info("exgnss", "state", event)
+    if event=="FIXED" then
+        --获取rmc数据
+        --json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位,本示例保留5位小数
+        log.info("nmea", "rmc0", json.encode(exgnss.rmc(0),"5f"))
+    end
+end
+sys.subscribe("GNSS_STATE",gnss_state)

+ 4 - 6
module/Air8000/demo/gnss/main.lua → module/Air8000/demo/gnss/single/main.lua

@@ -7,7 +7,7 @@
 @author  李源龙
 @usage
 本demo演示的功能为:
-使用Air780GH核心板,通过gnss.lua扩展库,开启GNSS定位,展示模块的三种功耗模式:正常模式,低功耗模式,PSM+模式 
+使用Air8000整机开发板,通过exgnss.lua扩展库,开启GNSS定位,展示模块的三种应用状态
 ]]
 
 --[[
@@ -52,13 +52,11 @@ end
 --     log.info("mem.sys", rtos.meminfo("sys"))
 -- end, 3000)
 
-gnss=require("gnss")    
+exgnss=require("exgnss")    
 
 
-normal=require("normal")
--- lowpower=require("lowpower")
--- psm=require("psm")
--- da221gnss=require("da221gnss")
+require"gnss"
+
 
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句

+ 105 - 0
module/Air8000/demo/gnss/single/readme.md

@@ -0,0 +1,105 @@
+
+## 演示功能概述
+
+使用Air8000整机开发板,本示例主要是展示exgnss库的三种应用模式,
+
+exgnss.DEFAULT模式
+
+exgnss.TIMERORSUC模式
+
+exgnss.TIMER模式
+
+主要操作为:
+
+打开三种应用模式
+
+等待40秒关闭操作TIMER模式
+
+然后查询三种应用模式是否处于激活模式
+
+等待10秒关闭全部应用模式,再次查询三种模式是否处于激活模式
+
+然后获取最后一次的定位经纬度数据打印
+
+定位成功之后使用exgnss库获取gnss的rmc数据
+
+## 演示硬件环境
+
+1、Air8000整机开发板一块
+
+2、TYPE-C USB数据线一根
+
+3、gnss天线一根
+
+4、Air8000整机开发板和数据线的硬件接线方式为
+
+- Air8000整机开发板通过TYPE-C USB口供电;(整机开发板的拨钮开关拨到USB供电)
+
+- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8000 V2010版本固件](https://docs.openluat.com/air8000/luatos/firmware/)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到核心板中
+
+3、烧录好后,板子开机将会在Luatools上看到如下打印:
+
+(1) 开启GNSS应用:
+
+```lua
+[2025-08-13 17:30:59.548][000000000.449] I/user.全卫星开启
+[2025-08-13 17:30:59.587][000000000.449] I/user.debug开启
+[2025-08-13 17:30:59.633][000000000.449] D/gnss Debug ON
+[2025-08-13 17:30:59.697][000000000.449] I/user.agps开启
+[2025-08-13 17:30:59.779][000000000.450] W/user.gnss_agps wait IP_READY
+[2025-08-13 17:30:59.810][000000000.451] I/user.exgnss._open
+[2025-08-13 17:30:59.834][000000000.452] I/user.exgnss.open 1 modeDefault nil function: 0C7F7A20
+[2025-08-13 17:30:59.873][000000000.453] I/user.exgnss.open 2 modeTimerorsuc 60 function: 0C7FAFF0
+[2025-08-13 17:30:59.918][000000000.456] I/user.exgnss state OPEN
+
+```
+
+(2) GNSS定位成功:
+
+```lua
+[2025-08-13 17:31:05.314][000000008.890] I/gnss Fixed 344786478 1141919416
+[2025-08-13 17:31:05.331][000000008.892] I/user.exgnss state FIXED
+[2025-08-13 17:31:05.348][000000008.894] I/user.nmea rmc0 {"variation":0,"lat":3447.86475,"min":31,"valid":true,"day":13,"lng":11419.19336,"speed":0.01300,"year":2025,"month":8,"sec":4,"hour":9,"course":340.04800}
+[2025-08-13 17:31:05.361][000000008.894] I/user.exgnss.statInd@1 true 3 modeTimer 60 52 nil function: 0C7FB4B8
+[2025-08-13 17:31:05.369][000000008.895] I/user.exgnss.statInd@2 true 1 modeDefault nil nil nil function: 0C7F7A20
+[2025-08-13 17:31:05.387][000000008.896] I/user.exgnss.statInd@3 true 2 modeTimerorsuc 60 52 nil function: 0C7FAFF0
+[2025-08-13 17:31:05.401][000000008.896] I/user.exgnss.statInd@4 true 3 libagps 20 17 nil nil
+[2025-08-13 17:31:06.311][000000009.895] I/user.exgnss.timerFnc@1 3 modeTimer 60 52 nil
+[2025-08-13 17:31:06.324][000000009.896] I/user.exgnss.timerFnc@2 1 modeDefault nil nil 1
+[2025-08-13 17:31:06.329][000000009.896] I/user.TAGmode2_cb+++++++++ modeDefault
+[2025-08-13 17:31:06.335][000000009.897] I/user.nmea rmc {"variation":0,"lat":34.7977448,"min":31,"valid":true,"day":13,"lng":114.3199005,"speed":0.0130000,"year":2025,"month":8,"sec":4,"hour":9,"course":340.0480042}
+[2025-08-13 17:31:06.337][000000009.898] I/user.exgnss.timerFnc@3 2 modeTimerorsuc 60 52 1
+[2025-08-13 17:31:06.340][000000009.898] I/user.TAGmode3_cb+++++++++ modeTimerorsuc
+[2025-08-13 17:31:06.342][000000009.899] I/user.nmea rmc {"variation":0,"lat":34.7977448,"min":31,"valid":true,"day":13,"lng":114.3199005,"speed":0.0130000,"year":2025,"month":8,"sec":4,"hour":9,"course":340.0480042}
+[2025-08-13 17:31:06.344][000000009.900] I/user.exgnss.close 2 modeTimerorsuc 60 function: 0C7FAFF0
+[2025-08-13 17:31:06.349][000000009.900] I/user.exgnss.timerFnc@4 3 libagps 20 17 nil
+
+```
+3、到时间关闭所有应用:
+```lua
+[2025-08-13 17:31:46.861][000000050.455] I/user.exgnss.close 3 modeTimer 60 function: 0C7FB4B8
+[2025-08-13 17:31:46.876][000000050.455] I/user.TAGmode2_cb+++++++++ modeDefault
+[2025-08-13 17:31:46.892][000000050.456] I/user.nmea rmc {"variation":0,"lat":34.7977867,"min":31,"valid":true,"day":13,"lng":114.3198853,"speed":0,"year":2025,"month":8,"sec":46,"hour":9,"course":0}
+[2025-08-13 17:31:46.911][000000050.456] I/user.exgnss.close 1 modeDefault nil function: 0C7F7A20
+[2025-08-13 17:31:46.936][000000050.463] I/user.exgnss._close
+[2025-08-13 17:31:46.950][000000050.464] I/user.exgnss.close 2 modeTimerorsuc 60 function: 0C7FAFF0
+[2025-08-13 17:31:46.965][000000050.465] I/user.exgnss.close 3 libagps 20 nil
+[2025-08-13 17:31:46.982][000000050.465] I/user.gnss应用状态1
+[2025-08-13 17:31:46.997][000000050.465] I/user.gnss应用状态2
+[2025-08-13 17:31:47.013][000000050.466] I/user.gnss应用状态3
+[2025-08-13 17:31:47.027][000000050.469] I/user.lastloc 3447.8671900000 11419.193360000
+[2025-08-13 17:31:47.042][000000050.470] I/user.exgnss state CLOSE
+```

+ 0 - 151
module/Air8000/demo/gnss/tcp.lua

@@ -1,151 +0,0 @@
---[[
-@module  tcp
-@summary gnss使用psm测试功能模块
-@version 1.0
-@date    2025.07.27
-@author  李源龙
-@usage
-使用Air8000核心板,连接TCP服务器,实现TCP通信功能
-]]
-local tcp = {}
-local taskName = "TCP_TASK"             -- sysplus库用到的任务名称,也作为任务id
-
-local uartid = 1 -- 根据实际设备选取不同的uartid
-local uart_rx_buff = zbuff.create(1024)     -- 串口接收到的数据
-local libnet = require "libnet"         -- libnet库,支持tcp、udp协议所用的同步阻塞接口
-local ip = "112.125.89.8"               -- 连接tcp服务器的ip地址
-local port = 42009                 -- 连接tcp服务器的端口
-local connect_state = false             -- 连接状态 true:已连接   false:未连接
-local protocol = false                  -- 通讯协议 true:UDP协议  false:TCP协议
-local ssl = false                       -- 加密传输 true:加密     false:不加密
-local tx_buff = zbuff.create(1024)      -- 发送至tcp服务器的数据
-local rx_buff = zbuff.create(1024)      -- 从tcp服务器接收到的数据
-
---初始化
-uart.setup(
-    uartid,--串口id
-    9600,--波特率
-    8,--数据位
-    1--停止位
-)
-
--- 处理未识别的消息
-local function tcp_client_main_cbfunc(msg)
-	log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
-end
-
---
-function tcp.latlngfnc(lat,lng)
-    tx_buff:write(string.format('{"lat":%5f,"lng":%5f}', lat, lng))
-    if connect_state then
-        sys_send(taskName, socket.EVENT, 0)
-     end
-end
-
-function TCP_TASK()
-    -- 打印一下连接的目标ip和端口号
-    log.info("connect ip: ", ip, "port:", port)
-
-    while not socket.adapter() do
-        log.warn("gnss_agps", "wait IP_READY")
-        -- 在此处阻塞等待WIFI连接成功的消息"IP_READY"
-        -- 或者等待30秒超时退出阻塞等待状态
-        local result=sys.waitUntil("IP_READY", 30000)
-        if result == false then
-            log.warn("gnss_agps", "wait IP_READY timeout")
-            return
-        end
-    end
-
-    local socket_client
-    while true do
-        socket_client = socket.create(nil, taskName)     -- 创建socket对象
-        socket.debug(socket_client, true)                      -- 打开调试日志
-        socket.config(socket_client, nil, protocol, ssl)       -- 此配置为TCP连接,无SSL加密
-        -- 连接服务器,返回是否连接成功
-        result = libnet.connect(taskName, 15000, socket_client, ip, port)
-
-        -- 收取数据会触发回调, 这里的"receive" 是固定值不要修改。
-        uart.on(uartid, "receive", function(id, len)
-            while true do
-              local len = uart.rx(id, uart_rx_buff)   -- 接收串口收到的数据,并赋值到uart_rx_buff
-               if len <= 0 then    -- 接收到的字节长度为0 则退出
-                   break
-                end
-                -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
-                if connect_state then
-                   sys_send(taskName, socket.EVENT, 0)
-                end
-                break
-            end
-        end)
-
-        -- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
-        if result then
-            connect_state = true
-            libnet.tx(taskName, 0, socket_client, "TCP  CONNECT")
-        end
-
-        -- 连接上服务器后,等待处理接收服务器下行至模块的数据 和 发送串口的数据到服务器
-        while result do
-            succ, param, _, _ = socket.rx(socket_client, rx_buff)   -- 接收数据
-            if not succ then
-                log.info("服务器断开了", succ, param, ip, port)
-                break
-            end
-
-            if rx_buff:used() > 0 then
-                log.info("收到服务器数据,长度", rx_buff:used())
-
-                uart.tx(uartid, rx_buff)    -- 从服务器收到的数据转发 从串口输出
-                rx_buff:del()
-            end
-
-            tx_buff:copy(nil, uart_rx_buff)         -- 将串口数据赋值给tcp待发送数据的buff中
-            uart_rx_buff:del()                      -- 清除串口buff的数据长度
-            if tx_buff:used() > 0 then
-                log.info("发送到服务器数据,长度", tx_buff:used())
-                local result = libnet.tx(taskName, 0, socket_client, tx_buff)   -- 发送数据
-                if not result then
-                    log.info("发送失败了", result, param)
-                    break
-                end
-            end
-            tx_buff:del()
-
-            -- 如果zbuff对象长度超出,需要重新分配下空间
-            if uart_rx_buff:len() > 1024 then
-                uart_rx_buff:resize(1024)
-            end
-            if tx_buff:len() > 1024 then
-                tx_buff:resize(1024)
-            end
-            if rx_buff:len() > 1024 then
-                rx_buff:resize(1024)
-            end
-            log.info(rtos.meminfo("sys"))   -- 打印系统内存
-
-            -- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
-            result, param = libnet.wait(taskName, 15000, socket_client)
-            if not result then
-                log.info("服务器断开了", result, param)
-                break
-            end
-        end
-
-        -- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
-        connect_state = false
-        libnet.close(d1Name, 5000, socket_client)
-        socket.release(socket_client)
-        tx_buff:clear(0)
-        rx_buff:clear(0)
-        socket_client=nil
-        sys.wait(1000)
-    end
-
-end
-
--- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
-sysplus.taskInitEx(TCP_TASK, taskName, tcp_client_main_cbfunc)
-
-return tcp

+ 74 - 0
module/Air8000/demo/vibration/main.lua

@@ -0,0 +1,74 @@
+
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.07.27
+@author  李源龙
+@usage
+本demo演示的功能为:
+使用Air8000整机开发板,本示例主要是展示exvib库的使用,提供了三种场景应用:
+
+1,微小震动检测:用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
+
+2,运动检测:用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
+
+3,跌倒检测:用于人或物体瞬间跌倒时的检测;加速度量程8g;
+
+在震动检测方面提供了两种模式,有效震动模式和持续震动检测模式:
+
+持续震动检测模式:震动强度超过设定阈值时,会进入中断处理函数,获取xyz三轴的数据
+
+有效震动模式:当10秒内触发5次震动强度超过设定阈值时,持续触发震动事件,并执行相应的处理函数,30分钟内只能触发一次,直到30分钟之后,再重新开始检测
+]]
+
+--[[
+必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
+PROJECT:项目名,ascii string类型
+        可以随便定义,只要不使用,就行
+VERSION:项目版本号,ascii string类型
+        如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
+            X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
+            因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
+        如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
+]]
+PROJECT = "vibSingle"
+VERSION = "001.000.000"
+
+--添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
+
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+
+require"vibration"
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 119 - 0
module/Air8000/demo/vibration/readme.md

@@ -0,0 +1,119 @@
+
+## 演示功能概述
+
+使用Air8000整机开发板,本示例主要是展示exvib库的使用,提供了三种场景应用:
+
+1,微小震动检测:用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
+
+2,运动检测:用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
+
+3,跌倒检测:用于人或物体瞬间跌倒时的检测;加速度量程8g;
+
+在震动检测方面提供了两种模式,有效震动模式和持续震动检测模式:
+
+持续震动检测模式:震动强度超过设定阈值时,会进入中断处理函数,获取xyz三轴的数据
+
+有效震动模式:当10秒内触发5次震动强度超过设定阈值时,持续触发震动事件,并执行相应的处理函数,30分钟内只能触发一次,直到30分钟之后,再重新开始检测
+
+## 演示软件使用说明
+
+## 演示硬件环境
+
+1、Air8000整机开发板一块
+
+2、TYPE-C USB数据线一根
+
+3、gnss天线一根
+
+4、Air8000整机开发板和数据线的硬件接线方式为
+
+- Air8000整机开发板通过TYPE-C USB口供电;(整机开发板的拨钮开关拨到USB供电)
+
+- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8000 V2012版本固件](https://docs.openluat.com/air8000/luatos/firmware/)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到核心板中
+
+3、烧录好后,板子开机将会在Luatools上看到如下打印:
+
+(1) 持续震动模式:
+
+```lua
+[2025-08-15 17:32:31.960][000000000.440] I/user.轻微检测
+[2025-08-15 17:32:32.099][000000000.441] I2C_MasterSetup 426:I2C0, Total 260 HCNT 113 LCNT 136
+[2025-08-15 17:32:32.197][000000000.444] I/airlink AIRLINK_READY 391 version 0
+[2025-08-15 17:32:32.318][000000000.544] I/user.i2c chipid 13 2
+[2025-08-15 17:32:32.610][000000000.544] I/user.exvib init success
+[2025-08-15 17:32:36.715][000000006.720] D/mobile cid1, state0
+[2025-08-15 17:32:36.781][000000006.721] D/mobile bearer act 0, result 0
+[2025-08-15 17:32:36.830][000000006.722] D/mobile NETIF_LINK_ON -> IP_READY
+[2025-08-15 17:32:36.884][000000006.774] D/mobile TIME_SYNC 0
+[2025-08-15 17:32:38.175][000000012.037] I/user.int 1
+[2025-08-15 17:32:38.242][000000012.039] I/user.x -0.089843750000000g y -0.11523437500000g z 0.36523437500000g
+[2025-08-15 17:32:38.731][000000012.595] I/user.int 0
+[2025-08-15 17:32:39.342][000000013.214] I/user.int 1
+[2025-08-15 17:32:39.380][000000013.216] I/user.x -0.089843750000000g y 0.0048828120000000g z 0.95117187500000g
+[2025-08-15 17:32:39.826][000000013.697] I/user.int 0
+[2025-08-15 17:32:40.157][000000014.018] I/user.int 1
+[2025-08-15 17:32:40.185][000000014.020] I/user.x 0.0058593750000000g y 0.13769531200000g z 0.80468750000000g
+[2025-08-15 17:32:40.639][000000014.502] I/user.int 0
+[2025-08-15 17:32:41.201][000000015.059] I/user.int 0
+[2025-08-15 17:32:42.015][000000015.875] I/user.int 1
+[2025-08-15 17:32:42.078][000000015.878] I/user.x -0.032226562000000g y 0.015625000000000g z 0.80468750000000g
+[2025-08-15 17:32:42.562][000000016.433] I/user.int 0
+[2025-08-15 17:32:42.812][000000016.680] I/user.int 1
+[2025-08-15 17:32:42.842][000000016.683] I/user.x -0.0068359380000000g y -0.010742188000000g z 0.75585937500000g
+
+
+```
+
+(2) 有效震动模式:
+
+```lua
+[2025-08-15 17:34:46.576][000000000.370] I/user.轻微检测
+[2025-08-15 17:34:46.691][000000000.371] I2C_MasterSetup 426:I2C0, Total 260 HCNT 113 LCNT 136
+[2025-08-15 17:34:46.806][000000000.474] I/user.i2c chipid 13 2
+[2025-08-15 17:34:46.927][000000000.474] I/user.exvib init success
+[2025-08-15 17:34:48.798][000000006.056] D/mobile cid1, state0
+[2025-08-15 17:34:48.862][000000006.057] D/mobile bearer act 0, result 0
+[2025-08-15 17:34:48.925][000000006.057] D/mobile NETIF_LINK_ON -> IP_READY
+[2025-08-15 17:34:48.987][000000006.090] D/mobile TIME_SYNC 0
+[2025-08-15 17:34:49.083][000000009.291] I/user.int 1
+[2025-08-15 17:34:49.143][000000009.292] I/user.table.remove 0
+[2025-08-15 17:34:49.204][000000009.292] I/user.tick 8 true true
+[2025-08-15 17:34:49.262][000000009.293] I/user.tick2 0 0 0 0 8
+[2025-08-15 17:34:49.301][000000009.776] I/user.int 0
+[2025-08-15 17:34:49.436][000000009.911] I/user.int 1
+[2025-08-15 17:34:49.468][000000009.911] I/user.table.remove 0
+[2025-08-15 17:34:49.500][000000009.912] I/user.tick 9 true true
+[2025-08-15 17:34:49.529][000000009.912] I/user.tick2 0 0 0 8 9
+[2025-08-15 17:34:49.918][000000010.393] I/user.int 0
+[2025-08-15 17:34:50.492][000000010.963] I/user.int 1
+[2025-08-15 17:34:50.528][000000010.963] I/user.table.remove 0
+[2025-08-15 17:34:50.564][000000010.964] I/user.tick 10 false true
+[2025-08-15 17:34:50.597][000000010.964] I/user.tick2 0 0 8 9 10
+[2025-08-15 17:34:50.979][000000011.446] I/user.int 0
+[2025-08-15 17:34:51.352][000000011.829] I/user.int 1
+[2025-08-15 17:34:51.502][000000011.829] I/user.table.remove 0
+[2025-08-15 17:34:51.555][000000011.829] I/user.tick 11 false true
+[2025-08-15 17:34:51.612][000000011.830] I/user.tick2 0 8 9 10 11
+[2025-08-15 17:34:51.847][000000012.323] I/user.int 0
+[2025-08-15 17:34:52.034][000000012.508] I/user.int 1
+[2025-08-15 17:34:52.068][000000012.509] I/user.table.remove 0
+[2025-08-15 17:34:52.097][000000012.509] I/user.tick 12 true true
+[2025-08-15 17:34:52.129][000000012.510] I/user.tick2 8 9 10 11 12
+[2025-08-15 17:34:52.155][000000012.510] I/user.vib xxx
+[2025-08-15 17:34:52.184][000000012.511] I/user.触发有效震动
+[2025-08-15 17:34:52.514][000000012.992] I/user.int 0
+
+```

+ 108 - 0
module/Air8000/demo/vibration/vibration.lua

@@ -0,0 +1,108 @@
+--[[
+@module  vibration
+@summary 利用加速度传感器da221实现震动触发中断,然后处理逻辑
+@version 1.0
+@date    2025.08.01
+@author  李源龙
+@usage
+使用Air8000整机开发板,本示例主要是展示exvib库的使用,提供了三种场景应用:
+
+1,微小震动检测:用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
+
+2,运动检测:用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
+
+3,跌倒检测:用于人或物体瞬间跌倒时的检测;加速度量程8g;
+
+在震动检测方面提供了两种模式,有效震动模式和持续震动检测模式:
+
+持续震动检测模式:震动强度超过设定阈值时,会进入中断处理函数,获取xyz三轴的数据
+
+有效震动模式:当10秒内触发5次震动强度超过设定阈值时,持续触发震动事件,并执行相应的处理函数,30分钟内只能触发一次,直到30分钟之后,再重新开始检测
+]]
+
+exvib=require("exvib")
+
+local intPin=gpio.WAKEUP2   --中断检测脚,内部固定wakeup2
+local tid   --获取定时打开的定时器id
+local num=0 --计数器 
+local ticktable={0,0,0,0,0} --存放5次中断的tick值,用于做有效震动对比
+local eff=false --有效震动标志位,用于判断是否触发定位
+
+gpio.setup(164, 1, gpio.PULLUP) -- air8000整机板需要大概该电源控制i2c上电 和音频解码芯片共用,自己设计可以忽略掉
+gpio.setup(147, 1, gpio.PULLUP) -- air8000整机板需要大概该电源控制i2c上电 camera的供电使能脚,自己设计可以忽略掉
+--有效震动模式
+--tick计数器,每秒+1用于存放5次中断的tick值,用于做有效震动对比
+local function tick()
+    num=num+1
+end
+--每秒运行一次计时
+sys.timerLoopStart(tick,1000)
+
+--有效震动判断
+local function ind()
+    log.info("int", gpio.get(intPin))
+    if gpio.get(intPin) == 1 then
+        --接收数据如果大于5就删掉第一个
+        if #ticktable>=5 then
+            log.info("table.remove",table.remove(ticktable,1))
+        end
+        --存入新的tick值
+        table.insert(ticktable,num)
+        log.info("tick",num,(ticktable[5]-ticktable[1]<10),ticktable[5]>0)
+        log.info("tick2",ticktable[1],ticktable[2],ticktable[3],ticktable[4],ticktable[5])
+        --表长度为5且,第5次中断时间间隔减去第一次间隔小于10s,且第5次值为有效值
+        if #ticktable>=5 and (ticktable[5]-ticktable[1]<10 and ticktable[1]>0) then
+            log.info("vib", "xxx")
+            --是否要去触发有效震动逻辑
+            if eff==false then
+                sys.publish("EFFECTIVE_VIBRATION")
+            end
+        end
+    end
+end
+
+--设置30s分钟之后再判断是否有效震动函数
+local function num_cb()
+    eff=false
+end
+
+local function eff_vib()
+    log.info("触发有效震动")
+    --触发之后eff设置为true,30分钟之后再触发有效震动
+    eff=true
+    --30分钟之后再触发有效震动
+    sys.timerStart(num_cb,180000)
+end
+
+sys.subscribe("EFFECTIVE_VIBRATION",eff_vib)
+
+
+
+--持续震动模式
+
+--持续震动模式中断函数
+-- local function ind()
+--     log.info("int", gpio.get(intPin))
+--     --上升沿为触发震动中断
+--     if gpio.get(intPin) == 1 then
+--         local x,y,z =  exvib.read_xyz()      --读取x,y,z轴的数据
+--         log.info("x", x..'g', "y", y..'g', "z", z..'g')
+--     end
+-- end
+
+
+local function vib_fnc()
+    -- 1,微小震动检测,用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
+    -- 2,运动检测,用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
+    -- 3,跌倒检测,用于人或物体瞬间跌倒时的检测;加速度量程8g;
+    --打开震动检测功能
+    exvib.open(1)
+    --设置gpio防抖100ms
+    gpio.debounce(intPin, 100)
+    --设置gpio中断触发方式wakeup2唤醒脚默认为双边沿触发
+    gpio.setup(intPin, ind)
+
+end
+
+sys.taskInit(vib_fnc)
+

+ 209 - 214
module/Air8000/demo/gnss/gnss.lua → script/libs/exgnss.lua

@@ -1,60 +1,60 @@
 --[[
-@module gnss
-@summary gnss拓展库
+@module exgnss
+@summary exgnss扩展库
 @version 1.0
 @date    2025.07.16
 @author  李源龙
 @usage
 -- 用法实例
--- 注意:gnss.lua适用的产品范围,只能用于合宙内部集成GNSS功能的产品,目前有Air780EGH,Air8000系列
+-- 注意:exgnss.lua适用的产品范围,只能用于合宙内部集成GNSS功能的产品,目前有Air780EGH,Air8000系列
 -- 提醒: 本库输出的坐标,均为 WGS84 坐标系
 -- 如需要在国内地图使用, 要转换成对应地图的坐标系, 例如 GCJ02 BD09
 -- 相关链接: https://lbsyun.baidu.com/index.php?title=coordinate
 -- 相关链接: https://www.openluat.com/GPS-Offset.html
 
---关于gnss的三种应用场景:
-gnss.DEFAULT:
---- gnss应用模式1.
+--关于exgnss的三种应用场景:
+exgnss.DEFAULT:
+--- exgnss应用模式1.
 -- 打开gnss后,gnss定位成功时,如果有回调函数,会调用回调函数
--- 使用此应用模式调用gnss.open打开的“gnss应用”,必须主动调用gnss.close
--- 或者gnss.closeAll才能关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
+-- 使用此应用模式调用exgnss.open打开的“gnss应用”,必须主动调用exgnss.close
+-- 或者exgnss.close_all才能关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
 -- 通俗点说就是一直打开,除非自己手动关闭掉
 
-gnss.TIMERORSUC:
---- gnss应用模式2.
+exgnss.TIMERORSUC:
+--- exgnss应用模式2.
 -- 打开gnss后,如果在gnss开启最大时长到达时,没有定位成功,如果有回调函数,
 -- 会调用回调函数,然后自动关闭此“gnss应用”
 -- 打开gnss后,如果在gnss开启最大时长内,定位成功,如果有回调函数,
 -- 会调用回调函数,然后自动关闭此“gnss应用”
--- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者
--- gnss.closeAll主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
+-- 打开gnss后,在自动关闭此“gnss应用”前,可以调用exgnss.close或者
+-- exgnss.close_all主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
 -- 通俗点说就是设置规定时间打开,如果规定时间内定位成功就会自动关闭此应用,
 -- 如果没有定位成功,时间到了也会自动关闭此应用
 
-gnss.TIMER:
---- gnss应用模式3.
+exgnss.TIMER:
+--- exgnss应用模式3.
 -- 打开gnss后,在gnss开启最大时长时间到达时,无论是否定位成功,如果有回调函数,
 -- 会调用回调函数,然后自动关闭此“gnss应用”
--- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者gnss.closeAll
+-- 打开gnss后,在自动关闭此“gnss应用”前,可以调用exgnss.close或者exgnss.close_all
 -- 主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
 -- 通俗点说就是设置规定时间打开,无论是否定位成功,到了时间都会自动关闭此应用,
 -- 和第二种的区别在于定位成功之后不会自动关闭,到时间之后才会自动关闭
 
-gnss=require("gnss")    
+exgnss=require("exgnss")    
 
 local function mode1_cb(tag)
     log.info("TAGmode1_cb+++++++++",tag)
-    log.info("nmea", "rmc", json.encode(gnss.getRmc(2)))
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(2)))
 end
 
 local function mode2_cb(tag)
     log.info("TAGmode2_cb+++++++++",tag)
-    log.info("nmea", "rmc", json.encode(gnss.getRmc(2)))
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(2)))
 end
 
 local function mode3_cb(tag)
     log.info("TAGmode3_cb+++++++++",tag)
-    log.info("nmea", "rmc", json.encode(gnss.getRmc(2)))
+    log.info("nmea", "rmc", json.encode(exgnss.rmc(2)))
 end
 
 local function gnss_fnc()
@@ -66,30 +66,35 @@ local function gnss_fnc()
         -- uartbaud=115200,    --串口波特率,780EGH和8000默认115200
         -- bind=1, --绑定uart端口进行GNSS数据读取,是否设置串口转发,指定串口号
         -- rtc=false    --定位成功后自动设置RTC true开启,flase关闭
+         ----因为GNSS使用辅助定位的逻辑,是模块下载星历文件,然后把数据发送给GNSS芯片,
+        ----芯片解析星历文件需要10-30s,默认GNSS会开启20s,该逻辑如果不执行,会导致下一次GNSS开启定位是冷启动,
+        ----定位速度慢,大概35S左右,所以默认开启,如果可以接受下一次定位是冷启动,可以把auto_open设置成false
+        ----需要注意的是热启动在定位成功之后,需要再开启3s左右才能保证本次的星历获取完成,如果对定位速度有要求,建议这么处理
+        -- auto_open=false 
     }
     --设置gnss参数
-    gnss.setup(gnssotps)
+    exgnss.setup(gnssotps)
     --开启gnss应用
-    gnss.open(gnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
-    gnss.open(gnss.DEFAULT,{tag="MODE2",cb=mode2_cb})
-    gnss.open(gnss.TIMERORSUC,{tag="MODE3",val=60,cb=mode3_cb})
+    exgnss.open(exgnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
+    exgnss.open(exgnss.DEFAULT,{tag="MODE2",cb=mode2_cb})
+    exgnss.open(exgnss.TIMERORSUC,{tag="MODE3",val=60,cb=mode3_cb})
     sys.wait(40000)
     log.info("关闭一个gnss应用,然后查看下所有应用的状态")
     --关闭一个gnss应用
-    gnss.close(gnss.TIMER,{tag="MODE1"})
+    exgnss.close(exgnss.TIMER,{tag="MODE1"})
     --查询3个gnss应用状态
-    log.info("gnss应用状态1",gnss.isActive(gnss.TIMER,{tag="MODE1"}))
-    log.info("gnss应用状态2",gnss.isActive(gnss.DEFAULT,{tag="MODE2"}))
-    log.info("gnss应用状态3",gnss.isActive(gnss.TIMERORSUC,{tag="MODE3"}))
+    log.info("gnss应用状态1",exgnss.is_active(exgnss.TIMER,{tag="MODE1"}))
+    log.info("gnss应用状态2",exgnss.is_active(exgnss.DEFAULT,{tag="MODE2"}))
+    log.info("gnss应用状态3",exgnss.is_active(exgnss.TIMERORSUC,{tag="MODE3"}))
     sys.wait(10000)
     --关闭所有gnss应用
-    gnss.closeAll()
+    exgnss.close_all()
     --查询3个gnss应用状态
-    log.info("gnss应用状态1",gnss.isActive(gnss.TIMER,{tag="MODE1"}))
-    log.info("gnss应用状态2",gnss.isActive(gnss.DEFAULT,{tag="MODE2"}))
-    log.info("gnss应用状态3",gnss.isActive(gnss.TIMERORSUC,{tag="MODE3"}))
+    log.info("gnss应用状态1",exgnss.is_active(exgnss.TIMER,{tag="MODE1"}))
+    log.info("gnss应用状态2",exgnss.is_active(exgnss.DEFAULT,{tag="MODE2"}))
+    log.info("gnss应用状态3",exgnss.is_active(exgnss.TIMERORSUC,{tag="MODE3"}))
     --查询最后一次定位结果
-    local loc= gnss.getlastloc()
+    local loc= exgnss.last_loc()
     if loc then
         log.info("lastloc", loc.lat,loc.lng)
     end
@@ -101,17 +106,17 @@ sys.taskInit(gnss_fnc)
 --GNSS定位状态的消息处理函数:
 local function gnss_state(event, ticks)
     -- event取值有
-    -- FIXED:string类型 定位成功
-    -- LOSE: string类型 定位丢失
-    -- CLOSE: string类型 GNSS关闭,仅配合使用gnss.lua有效
+    -- "FIXED":string类型 定位成功
+    -- "LOSE": string类型 定位丢失
+    -- "CLOSE": string类型 GNSS关闭,仅配合使用gnss.lua有效
 
     -- ticks number类型 是事件发生的时间,一般可以忽略
-    log.info("gnss", "state", event)
+    log.info("exgnss", "state", event)
 end
-sys.subscribe(gnss_state)
+sys.subscribe("GNSS_STATE",gnss_state)
 
 ]]
-local gnss = {}
+local exgnss = {}
 --gnss开启标志,true表示开启状态,false或者nil表示关闭状态
 local openFlag
 --gnss定位标志,true表示,其余表示未定位
@@ -127,7 +132,7 @@ local taskFlag=false
 local agpsFlag=false
 
 --保存经纬度到文件区
-function gnss.saveloc(lat, lng)
+local function save_loc(lat,lng)
     if not lat or not lng then
         if libgnss.isFix() then
             local rmc = libgnss.getRmc(0)
@@ -146,14 +151,15 @@ function gnss.saveloc(lat, lng)
     io.writeFile("/hxxt_tm", tostring(now))
     -- log.info("now", now)
 end
+
 local tid
 
 sys.subscribe("GNSS_STATE", function(event)
     -- log.info("libagps","libagps is "..event)
     if event == "FIXED" then
-        gnss.saveloc()
-        tid=sys.timerLoopStart(gnss.saveloc,600000)
-        if gnss.opts.rtc==true then
+        save_loc()
+        tid=sys.timerLoopStart(save_loc,600000)
+        if exgnss.opts.rtc==true then
             sys.publish("NTP_UPDATE")
         end
     elseif event == "LOSE" or event == "CLOSE" then
@@ -163,7 +169,7 @@ sys.subscribe("GNSS_STATE", function(event)
 end)
 
 --agps操作,联网访问服务器获取星历数据
-local function _agps()
+local function agps()
     local lat, lng
 
     --此逻辑在agps定位成功之后,还会继续开启10s-15s,
@@ -171,9 +177,9 @@ local function _agps()
     --如果直接关闭gnss会导致gnss芯片的星历没有解析完毕,会影响下一次的定位为冷启动
     --如果对功耗有需求,需要定位快,可以每次都使用agps,不需要这句,直接屏蔽掉即可
     --代价是每次定位都会进行基站定位,
-    if gnss.opts.agps_autoopen~= false then
+    if exgnss.opts.auto_open~= false then
         log.info("libagps","libagps is open")
-        gnss.open(gnss.TIMER,{tag="libagps",val=20}) 
+        exgnss.open(exgnss.TIMER,{tag="libagps",val=20}) 
     else
 
     end
@@ -183,9 +189,9 @@ local function _agps()
     log.info("os.time",now)
     log.info("agps_time",agps_time)
     if now - agps_time > 3600 or io.fileSize("/hxxt.dat") < 1024 then
-        local url = gnss.opts.url
-        if not gnss.opts.url then
-            if gnss.opts.gnssmode and 2 == gnss.opts.gnssmode then
+        local url = exgnss.opts.url
+        if not exgnss.opts.url then
+            if exgnss.opts.gnssmode and 2 == exgnss.opts.gnssmode then
                 -- 单北斗
                 url = "http://download.openluat.com/9501-xingli/HXXT_BDS_AGNSS_DATA.dat"
             else
@@ -194,13 +200,13 @@ local function _agps()
         end
         local code = http.request("GET", url, nil, nil, {dst="/hxxt.dat"}).wait()
         if code and code == 200 then
-            log.info("gnss.opts", "下载星历成功", url)
+            log.info("exgnss.opts", "下载星历成功", url)
             io.writeFile("/hxxt_tm", tostring(now))
         else
-            log.info("gnss.opts", "下载星历失败", code)
+            log.info("exgnss.opts", "下载星历失败", code)
         end
     else
-        log.info("gnss.opts", "星历不需要更新", now - agps_time)
+        log.info("exgnss.opts", "星历不需要更新", now - agps_time)
     end
     --进行基站定位,给到gnss芯片一个大概的位置
     if mobile then
@@ -239,32 +245,32 @@ local function _agps()
     -- 写入星历
     local agps_data = io.readFile("/hxxt.dat")
     if agps_data and #agps_data > 1024 then
-        log.info("gnss.opts", "写入星历数据", "长度", #agps_data)
+        log.info("exgnss.opts", "写入星历数据", "长度", #agps_data)
         for offset=1,#agps_data,512 do
-            log.info("gnss", "AGNSS", "write >>>", #agps_data:sub(offset, offset + 511))
+            log.info("exgnss", "AGNSS", "write >>>", #agps_data:sub(offset, offset + 511))
             uart.write(gps_uart_id, agps_data:sub(offset, offset + 511))
             sys.wait(100) -- 等100ms反而更成功
         end
         -- uart.write(gps_uart_id, agps_data)
     else
-        log.info("gnss.opts", "没有星历数据")
+        log.info("exgnss.opts", "没有星历数据")
         return
     end
     -- "lat":23.4068813,"min":27,"valid":true,"day":27,"lng":113.2317505
     --如果没有经纬度的话,定位时间会变长,大概10-20s左右
     if not lat or not lng then
         -- lat, lng = 23.4068813, 113.2317505
-        log.info("gnss.opts", "没有GPS坐标", lat, lng)
+        log.info("exgnss.opts", "没有GPS坐标", lat, lng)
         return --暂时不写入参考位置
     else
-        log.info("gnss.opts", "写入GPS坐标", lat, lng)
+        log.info("exgnss.opts", "写入GPS坐标", lat, lng)
     end
     --写入时间
     local date = os.date("!*t")
     if date.year > 2023 then
         local str = string.format("$AIDTIME,%d,%d,%d,%d,%d,%d,000", date["year"], date["month"], date["day"],
             date["hour"], date["min"], date["sec"])
-        log.info("gnss.opts", "参考时间", str)
+        log.info("exgnss.opts", "参考时间", str)
         uart.write(gps_uart_id, str .. "\r\n")
         sys.wait(20)
     end
@@ -272,16 +278,16 @@ local function _agps()
     local str = string.format("$AIDPOS,%.7f,%s,%.7f,%s,1.0\r\n",
     lat > 0 and lat or (0 - lat), lat > 0 and 'N' or 'S',
     lng > 0 and lng or (0 - lng), lng > 0 and 'E' or 'W')
-    log.info("gnss.opts", "写入AGPS参考位置", str)
+    log.info("exgnss.opts", "写入AGPS参考位置", str)
     uart.write(gps_uart_id, str)
 
     -- 结束
-    gnss.opts.agps_tm = now
+    exgnss.opts.agps_tm = now
     agpsFlag=true
 end
 
 --执行agps操作判断
-function gnss.agps()
+local function is_agps()
     -- 如果不是强制写入AGPS信息, 而且是已经定位成功的状态,那就没必要了
     if libgnss.isFix() then return end
     -- 先判断一下时间
@@ -295,79 +301,63 @@ function gnss.agps()
             return
         end
     end
-    if not gnss.opts.agps_tm then
+    if not exgnss.opts.agps_tm then
         socket.sntp()
         sys.waitUntil("NTP_UPDATE", 5000)
     end
     local now = os.time()
     local agps_time = tonumber(io.readFile("/hxxt_tm") or "0") or 0
-    -- if ((not gnss.opts.agps_tm) and (now - agps_time > 300))  or  now - agps_time > 3600 then
-    if not gnss.opts.agps_tm  or  now - agps_time > 3600 then
+    -- if ((not exgnss.opts.agps_tm) and (now - agps_time > 300))  or  now - agps_time > 3600 then
+    if not exgnss.opts.agps_tm  or  now - agps_time > 3600 then
         -- 执行AGPS
-        log.info("gnss.opts", "开始执行AGPS")
-        sys.taskInit(_agps)
+        log.info("exgnss.opts", "开始执行AGPS")
+        sys.taskInit(agps)
     else
-        log.info("gnss.opts", "暂不需要写入AGPS")
+        log.info("exgnss.opts", "暂不需要写入AGPS")
     end
 end
 
---[[
-查询gnss是否处于打开状态
-@api gnss.openres()
-@boolean true表示打开,false/nil表示关闭
-@usage
---gnss没有打开。
- if gnss.openres()~=true then
-    log.info("nmea", "openres", "false")
-else
-    --gnss打开
-    log.info("nmea", "openres", "true")
-end
-]]
-function gnss.openres()
-    return openFlag
-end
 
 --打开gnss,内部函数使用,不推荐给脚本层使用
-local function _open()
+local function fnc_open()
     if openFlag then return end
     libgnss.clear() -- 清空数据,兼初始化
     uart.setup(uart_id, uart_baudrate)
     -- pm.power(pm.GPS, false)
     pm.power(pm.GPS, true)
-    if gnss.opts.gnssmode==1 then
+    if exgnss.opts.gnssmode==1 then
         --默认全开启
         log.info("全卫星开启")
-        elseif gnss.opts.gnssmode==2 then
+        elseif exgnss.opts.gnssmode==2 then
         --默认开启单北斗
         sys.timerStart(function()
             uart.write(uart_id, "$CFGSYS,h10\r\n")
         end,200)
         log.info("单北斗开启")
     end
-    if gnss.opts.debug==true then
+    if exgnss.opts.debug==true then
         log.info("debug开启")
         libgnss.debug(true)
-    elseif gnss.opts.debug==false then
+    elseif exgnss.opts.debug==false then
         log.info("debug关闭")
         libgnss.debug(false)
     end
-    if type(gnss.opts.bind)=="number"  then
+    if type(exgnss.opts.bind)=="number"  then
         log.info("绑定bind事件")
-        libgnss.bind(uart_id,gnss.opts.bind)
+        libgnss.bind(uart_id,exgnss.opts.bind)
     else
         libgnss.bind(uart_id)
     end
-    if gnss.opts.rtc==true then
+    if exgnss.opts.rtc==true then
         log.info("rtc开启")
         libgnss.rtcAuto(true)
-    elseif gnss.opts.rtc==false then
+    elseif exgnss.opts.rtc==false then
         log.info("rtc关闭")
         libgnss.rtcAuto(false)
     end
-    if gnss.opts.agps_enable==true then
+    if exgnss.opts.agps_enable==true then
         log.info("agps开启")
-        sys.taskInit(gnss.agps)
+        sys.taskInit(is_agps)
     end
     --设置输出VTG内容
     sys.timerStart(function()
@@ -379,19 +369,19 @@ local function _open()
     end,900)
     openFlag = true
     sys.publish("GNSS_STATE","OPEN")
-    log.info("gnss._open")
+    log.info("exgnss._open")
 end
 
 --关闭gnss,内部函数使用,不推荐给脚本层使用
-local function _close()
+local function fnc_close()
     if not openFlag then return end
-    gnss.saveloc()
+    save_loc()
     pm.power(pm.GPS, false)
     uart.close(uart_id)
     openFlag = false
     fixFlag = false
     sys.publish("GNSS_STATE","CLOSE",fixFlag)    
-    log.info("gnss._close")
+    log.info("exgnss._close")
     libgnss.clear()
 end
 
@@ -400,22 +390,22 @@ end
 --
 -- 打开gnss后,gnss定位成功时,如果有回调函数,会调用回调函数
 --
--- 使用此应用模式调用gnss.open打开的“gnss应用”,必须主动调用gnss.close或者gnss.closeAll才能关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
-gnss.DEFAULT = 1
+-- 使用此应用模式调用gnss.open打开的“gnss应用”,必须主动调用gnss.close或者gnss.close_all才能关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
+exgnss.DEFAULT = 1
 --- gnss应用模式2.
 --
 -- 打开gnss后,如果在gnss开启最大时长到达时,没有定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“gnss应用”
 --
 -- 打开gnss后,如果在gnss开启最大时长内,定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“gnss应用”
 --
--- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者gnss.closeAll主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
-gnss.TIMERORSUC = 2
+-- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者gnss.close_all主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
+exgnss.TIMERORSUC = 2
 --- gnss应用模式3.
 --
 -- 打开gnss后,在gnss开启最大时长时间到达时,无论是否定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“gnss应用”
 --
--- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者gnss.closeAll主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
-gnss.TIMER = 3
+-- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者gnss.close_all主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数
+exgnss.TIMER = 3
 
 --“gnss应用”表
 local tList = {}
@@ -459,7 +449,7 @@ local function addItem(mode,para)
     delItem(mode,para)
     local item,i,fnd = {flag=true, mode=mode, para=para}
     --如果是TIMERORSUC或者TIMER模式,初始化gnss工作剩余时间
-    if mode==gnss.TIMERORSUC or mode==gnss.TIMER then item.para.remain = para.val end
+    if mode==exgnss.TIMERORSUC or mode==exgnss.TIMER then item.para.remain = para.val end
     for i=1,#tList do
         --如果存在无效的“gnss应用”项,直接使用此位置
         if not tList[i].flag then
@@ -475,7 +465,7 @@ end
 --退出GNSS定时器
 local function existTimerItem()
     for i=1,#tList do
-        if tList[i].flag and (tList[i].mode==gnss.TIMERORSUC or tList[i].mode==gnss.TIMER or tList[i].para.delay) then return true end
+        if tList[i].flag and (tList[i].mode==exgnss.TIMERORSUC or tList[i].mode==exgnss.TIMER or tList[i].para.delay) then return true end
     end
 end
 
@@ -483,7 +473,7 @@ end
 local function timerFnc()
     for i=1,#tList do
         if tList[i].flag then
-            log.info("gnss.timerFnc@"..i,tList[i].mode,tList[i].para.tag,tList[i].para.val,tList[i].para.remain,tList[i].para.delay)
+            log.info("exgnss.timerFnc@"..i,tList[i].mode,tList[i].para.tag,tList[i].para.val,tList[i].para.remain,tList[i].para.delay)
             local rmn,dly,md,cb = tList[i].para.remain,tList[i].para.delay,tList[i].mode,tList[i].para.cb
 
             if rmn and rmn>0 then
@@ -494,23 +484,23 @@ local function timerFnc()
             end
             rmn = tList[i].para.remain
 
-            if libgnss.isFix() and md==gnss.TIMER and rmn==0 and not tList[i].para.delay then
+            if libgnss.isFix() and md==exgnss.TIMER and rmn==0 and not tList[i].para.delay then
                 tList[i].para.delay = 1
             end
             dly = tList[i].para.delay
             if libgnss.isFix() then
                 if dly and dly==0 then
                     if cb then cb(tList[i].para.tag) end
-                    if md == gnss.DEFAULT then
+                    if md == exgnss.DEFAULT then
                         tList[i].para.delay = nil
                     else
-                        gnss.close(md,tList[i].para)
+                        exgnss.close(md,tList[i].para)
                     end
                 end
             else
                 if rmn and rmn == 0 then
                     if cb then cb(tList[i].para.tag) end
-                    gnss.close(md,tList[i].para)
+                    exgnss.close(md,tList[i].para)
                 end
             end
         end
@@ -530,11 +520,11 @@ local function statInd(evt)
     if evt == "FIXED" then
         fixFlag = true
         for i=1,#tList do
-            log.info("gnss.statInd@"..i,tList[i].flag,tList[i].mode,tList[i].para.tag,tList[i].para.val,tList[i].para.remain,tList[i].para.delay,tList[i].para.cb)
+            log.info("exgnss.statInd@"..i,tList[i].flag,tList[i].mode,tList[i].para.tag,tList[i].para.val,tList[i].para.remain,tList[i].para.delay,tList[i].para.cb)
             if tList[i].flag then
-                if tList[i].mode ~= gnss.TIMER then
+                if tList[i].mode ~= exgnss.TIMER then
                     tList[i].para.delay = 1
-                    if tList[i].mode == gnss.DEFAULT then
+                    if tList[i].mode == exgnss.DEFAULT then
                         if existTimerItem() then sys.timerStart(timerFnc,1000) end
                     end
                 end
@@ -546,7 +536,7 @@ end
 
 --[[
 设置gnss定位参数
-@api gnss.setup(opts)
+@api exgnss.setup(opts)
 @table opts gnss定位参数,可选值gnssmode:定位卫星模式,1为卫星全定位,2为单北斗,默认为卫星全定位
 agps_enable:是否启用AGPS,true为启用,false为不启用,默认为false
 debug:是否输出调试信息到luatools,true为输出,false为不输出,默认为false
@@ -564,22 +554,27 @@ local gnssotps={
         -- uartbaud=115200,    --串口波特率,780EGH和8000默认115200
         -- bind=1, --绑定uart端口进行GNSS数据读取,是否设置串口转发,指定串口号
         -- rtc=false    --定位成功后自动设置RTC true开启,flase关闭
+         ----因为GNSS使用辅助定位的逻辑,是模块下载星历文件,然后把数据发送给GNSS芯片,
+        ----芯片解析星历文件需要10-30s,默认GNSS会开启20s,该逻辑如果不执行,会导致下一次GNSS开启定位是冷启动,
+        ----定位速度慢,大概35S左右,所以默认开启,如果可以接受下一次定位是冷启动,可以把auto_open设置成false
+        ----需要注意的是热启动在定位成功之后,需要再开启3s左右才能保证本次的星历获取完成,如果对定位速度有要求,建议这么处理
+        -- auto_open=false 
     }
-    gnss.setup(gnssotps)
+    exgnss.setup(gnssotps)
 ]]
-function gnss.setup(opts)
-    gnss.opts=opts
+function exgnss.setup(opts)
+    exgnss.opts=opts
     if hmeta.model():find("780EGH") or hmeta.model():find("8000") then
         uart_id=2
         uart_baudrate=115200
     else
-        if gnss.opts.uart_id then
-            uart_id=gnss.opts.uart_id
+        if exgnss.opts.uart_id then
+            uart_id=exgnss.opts.uart_id
         else
             uart_id=2    
         end
-        if gnss.opts.uartbaud then
-            uart_baudrate=gnss.opts.uartbaud
+        if exgnss.opts.uartbaud then
+            uart_baudrate=exgnss.opts.uartbaud
         else
             uart_baudrate=115200
         end
@@ -588,7 +583,7 @@ end
 
 --[[
 打开一个“gnss应用”
-@api gnss.open(mode,para)
+@api exgnss.open(mode,para)
 @number mode gnss应用模式,支持gnss.DEFAULT,gnss.TIMERORSUC,gnss.TIMER三种
 @param para table类型,gnss应用参数,para.tag:string类型,gnss应用标记,para.val:number类型,gnss应用开启最大时长,单位:秒,mode参数为gnss.TIMERORSUC或者gnss.TIMER时,此值才有意义;使用close接口时,不需要传入此参数,para.cb:gnss应用结束时的回调函数,回调函数的调用形式为para.cb(para.tag);使用close接口时,不需要传入此参数
 @return nil
@@ -604,26 +599,26 @@ end
 -- 2、gnss应用标记(必选)
 -- 3、gnss开启最大时长[可选]
 -- 4、回调函数[可选]
--- 例如gnss.open(gnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
--- gnss.TIMER为gnss应用模式,"MODE1"为gnss应用标记,60秒为gnss开启最大时长,mode1_cb为回调函数
-gnss.open(gnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
-gnss.open(gnss.DEFAULT,{tag="MODE2",cb=mode2_cb})
-gnss.open(gnss.TIMERORSUC,{tag="MODE3",val=60,cb=mode3_cb})
+-- 例如gnss.open(exgnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
+-- exgnss.TIMER为gnss应用模式,"MODE1"为gnss应用标记,60秒为gnss开启最大时长,mode1_cb为回调函数
+exgnss.open(exgnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
+exgnss.open(exgnss.DEFAULT,{tag="MODE2",cb=mode2_cb})
+exgnss.open(exgnss.TIMERORSUC,{tag="MODE3",val=60,cb=mode3_cb})
 ]]
-function gnss.open(mode,para)
-    assert((para and type(para) == "table" and para.tag and type(para.tag) == "string"),"gnss.open para invalid")
-    log.info("gnss.open",mode,para.tag,para.val,para.cb)
+function exgnss.open(mode,para)
+    assert((para and type(para) == "table" and para.tag and type(para.tag) == "string"),"exgnss.open para invalid")
+    log.info("exgnss.open",mode,para.tag,para.val,para.cb)
     --如果gnss定位成功
     if libgnss.isFix() then
-        if mode~=gnss.TIMER then
+        if mode~=exgnss.TIMER then
             --执行回调函数
             if para.cb then para.cb(para.tag) end
-            if mode==gnss.TIMERORSUC then return end
+            if mode==exgnss.TIMERORSUC then return end
         end
     end
     addItem(mode,para)
     --真正去打开gnss
-    _open()
+    fnc_open()
     --启动1秒的定时器
     if existTimerItem() and not sys.timerIsActive(timerFnc) then
         sys.timerStart(timerFnc,1000)
@@ -633,17 +628,17 @@ end
 
 --[[
 关闭一个“gnss应用”,只是从逻辑上关闭一个gnss应用,并不一定真正关闭gnss,是有所有的gnss应用都处于关闭状态,才会去真正关闭gnss
-@api gnss.close()
+@api exgnss.close()
 @number mode gnss应用模式,支持gnss.DEFAULT,gnss.TIMERORSUC,gnss.TIMER三种
 @param para table类型,gnss应用参数,para.tag:string类型,gnss应用标记,para.val:number类型,gnss应用开启最大时长,单位:秒,mode参数为gnss.TIMERORSUC或者gnss.TIMER时,此值才有意义;使用close接口时,不需要传入此参数,para.cb:gnss应用结束时的回调函数,回调函数的调用形式为para.cb(para.tag);使用close接口时,不需要传入此参数
 @return nil
 @usage
-gnss.open(gnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
-gnss.close(gnss.TIMER,{tag="MODE1"})
+exgnss.open(exgnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
+exgnss.close(exgnss.TIMER,{tag="MODE1"})
 ]]
-function gnss.close(mode,para)
-    assert((para and type(para)=="table" and para.tag and type(para.tag)=="string"),"gnss.close para invalid")
-    log.info("gnss.close",mode,para.tag,para.val,para.cb)
+function exgnss.close(mode,para)
+    assert((para and type(para)=="table" and para.tag and type(para.tag)=="string"),"exgnss.close para invalid")
+    log.info("exgnss.close",mode,para.tag,para.val,para.cb)
     --删除此“gnss应用”
     delItem(mode,para)
     local valid,i
@@ -653,42 +648,42 @@ function gnss.close(mode,para)
         end
     end
     --如果没有一个“gnss应用”有效,则关闭gnss
-    if not valid then _close() end
+    if not valid then fnc_close() end
 end
 
 --[[
 关闭所有“gnss应用”
-@api gnss.closeAll()
+@api exgnss.close_all()
 @return nil
 @usage
-gnss.open(gnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
-gnss.open(gnss.DEFAULT,{tag="MODE2",cb=mode2_cb})
-gnss.open(gnss.TIMERORSUC,{tag="MODE3",val=60,cb=mode3_cb})
-gnss.closeAll()
+exgnss.open(exgnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
+exgnss.open(exgnss.DEFAULT,{tag="MODE2",cb=mode2_cb})
+exgnss.open(exgnss.TIMERORSUC,{tag="MODE3",val=60,cb=mode3_cb})
+exgnss.close_all()
 ]]
-function gnss.closeAll()
+function exgnss.close_all()
     for i=1,#tList do
         if tList[i].flag and tList[i].para.cb then tList[i].para.cb(tList[i].para.tag) end
-        gnss.close(tList[i].mode,tList[i].para)
+        exgnss.close(tList[i].mode,tList[i].para)
     end
 end
 
 --[[
 判断一个“gnss应用”是否处于激活状态
-@api gnss.isActive(mode,para)
+@api exgnss.is_active(mode,para)
 @number mode gnss应用模式,支持gnss.DEFAULT,gnss.TIMERORSUC,gnss.TIMER三种
 @param para table类型,gnss应用参数,para.tag:string类型,gnss应用标记,para.val:number类型,gnss应用开启最大时长,单位:秒,mode参数为gnss.TIMERORSUC或者gnss.TIMER时,此值才有意义;使用close接口时,不需要传入此参数,para.cb:gnss应用结束时的回调函数,回调函数的调用形式为para.cb(para.tag);使用close接口时,不需要传入此参数,gnss应用模式和gnss应用标记唯一确定一个“gnss应用”,调用本接口查询状态时,mode和para.tag要和gnss.open打开一个“gnss应用”时传入的mode和para.tag保持一致
 @return bool result,处于激活状态返回true,否则返回nil
 @usage
-gnss.open(gnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
-gnss.open(gnss.DEFAULT,{tag="MODE2",cb=mode2_cb})
-gnss.open(gnss.TIMERORSUC,{tag="MODE3",val=60,cb=mode3_cb})
-log.info("gnss应用状态1",gnss.isActive(gnss.TIMER,{tag="MODE1"}))
-log.info("gnss应用状态2",gnss.isActive(gnss.DEFAULT,{tag="MODE2"}))
-log.info("gnss应用状态3",gnss.isActive(gnss.TIMERORSUC,{tag="MODE3"}))
+exgnss.open(exgnss.TIMER,{tag="MODE1",val=60,cb=mode1_cb})
+exgnss.open(exgnss.DEFAULT,{tag="MODE2",cb=mode2_cb})
+exgnss.open(exgnss.TIMERORSUC,{tag="MODE3",val=60,cb=mode3_cb})
+log.info("gnss应用状态1",exgnss.is_active(exgnss.TIMER,{tag="MODE1"}))
+log.info("gnss应用状态2",exgnss.is_active(exgnss.DEFAULT,{tag="MODE2"}))
+log.info("gnss应用状态3",exgnss.is_active(exgnss.TIMERORSUC,{tag="MODE3"}))
 ]]
-function gnss.isActive(mode,para)
-    assert((para and type(para)=="table" and para.tag and type(para.tag)=="string"),"gnss.isActive para invalid")
+function exgnss.is_active(mode,para)
+    assert((para and type(para)=="table" and para.tag and type(para.tag)=="string"),"exgnss.is_active para invalid")
     for i=1,#tList do
         if tList[i].flag and tList[i].mode==mode and tList[i].para.tag==para.tag then return true end
     end
@@ -699,19 +694,19 @@ sys.subscribe("GNSS_STATE",statInd)
 
 --[[
 当前是否已经定位成功
-@api gnss.isFix()
+@api exgnss.is_fix()
 @return boolean   true/false,定位成功返回true,否则返回false
 @usage
-log.info("nmea", "isFix", gnss.isFix())
+log.info("nmea", "is_fix", exgnss.is_fix())
 ]]
-function gnss.isFix()
+function exgnss.is_fix()
    return libgnss.isFix()
 end
 
 
 --[[
 获取number类型的位置和速度信息
-@api gnss.getIntLocation(speed_type)
+@api exgnss.int_location(speed_type)
 @number 速度单位,默认是m/h,
 0 - m/h 米/小时, 默认值, 整型
 1 - m/s 米/秒, 浮点数
@@ -722,29 +717,29 @@ end
 @return number speed数据, 单位根据speed_type决定,m/h, m/s, km/h, kn/h
 @usage
 --DDDDDDDDD格式是由DD.DDDDDDD*10000000转换而来,目的是作为整数,方便某些场景使用,示例:343482649对应的原始值是34.3482649
--- 该数据是通过RMC转换的,如果想获取更详细的可以用gnss.getRmc(1)
+-- 该数据是通过RMC转换的,如果想获取更详细的可以用exgnss.rmc(1)
 -- speed数据默认 米/小时,返回值例如:343482649	1135039700	390m/h
-log.info("nmea", "loc", gnss.getIntLocation())
+log.info("nmea", "loc", exgnss.int_location())
 -- speed数据米/秒,返回值例如:343482649	1135039700	0.1085478m/s
-log.info("nmea", "loc", gnss.getIntLocation(1))
+log.info("nmea", "loc", exgnss.int_location(1))
 -- speed数据千米/小时,返回值例如:343482649	1135039700	0.3907720km/h
-log.info("nmea", "loc", gnss.getIntLocation(2))
+log.info("nmea", "loc", exgnss.int_location(2))
 -- speed数据英里/小时,返回值例如:343482649	1135039700	0.2110000kn/h
-log.info("nmea", "loc", gnss.getIntLocation(3))
+log.info("nmea", "loc", exgnss.int_location(3))
 ]]
-function gnss.getIntLocation(speed_type)
-    return libgnss.getIntLocation(speed_type)
+function exgnss.int_location(speed_type)
+    return libgnss.int_location(speed_type)
 end
 
 
 --[[
 获取RMC的信息,经纬度,时间,速度,航向,定位是否有效,磁偏角
-@api gnss.getRmc(lnglat_mode)
+@api exgnss.rmc(lnglat_mode)
 @number 经纬度数据的格式, 0-ddmm.mmmmm格式, 1-DDDDDDDDD格式, 2-DD.DDDDDDD格式, 3-原始RMC字符串
 @return table/string rmc数据
 @usage
 -- 解析nmea
-log.info("nmea", "rmc", json.encode(gnss.getRmc(2)))
+log.info("nmea", "rmc", json.encode(exgnss.rmc(2)))
 -- 实例输出,获取值的解释
 -- {
 --     "course":344.9920044,     // 地面航向,单位为度,从北向起顺时针计算
@@ -762,31 +757,31 @@ log.info("nmea", "rmc", json.encode(gnss.getRmc(2)))
 -- }
 --模式0示例:
 --json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位,本示例保留5位小数
-log.info("nmea", "rmc0", json.encode(gnss.getRmc(0),"5f"))
+log.info("nmea", "rmc0", json.encode(exgnss.rmc(0),"5f"))
 {"variation":0,"lat":3434.82666,"min":54,"valid":true,"day":17,"lng":11350.39746,"speed":0.21100,"year":2025,"month":7,"sec":30,"hour":11,"course":344.99200}
 --模式1示例:
 --DDDDDDDDD格式是由DD.DDDDDDD*10000000转换而来,目的是作为整数,方便某些场景使用
-log.info("nmea", "rmc1", json.encode(gnss.getRmc(1)))
+log.info("nmea", "rmc1", json.encode(exgnss.rmc(1)))
 {"variation":0,"lat":345804414,"min":54,"valid":true,"day":17,"lng":1138399500,"speed":0.2110000,"year":2025,"month":7,"sec":30,"hour":11,"course":344.9920044}
 --模式2示例:
 --json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位
-log.info("nmea", "rmc2", json.encode(gnss.getRmc(2)))
+log.info("nmea", "rmc2", json.encode(exgnss.rmc(2)))
 {"variation":0,"lat":34.5804405,"min":54,"valid":true,"day":17,"lng":113.8399506,"speed":0.2110000,"year":2025,"month":7,"sec":30,"hour":11,"course":344.9920044}
 --模式3示例:
-log.info("nmea", "rmc3", gnss.getRmc(3))
+log.info("nmea", "rmc3", exgnss.rmc(3))
 $GNRMC,115430.000,A,3434.82649,N,11350.39700,E,0.211,344.992,170725,,,A,S*02\r
 ]]
-function gnss.getRmc(lnglat_mode)
+function exgnss.rmc(lnglat_mode)
     return libgnss.getRmc(lnglat_mode)
 end
 
 --[[
 获取原始GSV信息
-@api gnss.getGsv()
+@api exgnss.gsv()
 @return table 原始GSV数据
 @usage
 -- 解析nmea
-log.info("nmea", "gsv", json.encode(gnss.getGsv()))
+log.info("nmea", "gsv", json.encode(exgnss.gsv()))
 -- 实例输出
 -- {
 --     "total_sats":24,      // 总可见卫星数量
@@ -809,19 +804,19 @@ log.info("nmea", "gsv", json.encode(gnss.getGsv()))
 --     ]
 -- }
 ]]
-function gnss.getGsv() 
-    return libgnss.getGsv() 
+function exgnss.gsv() 
+    return libgnss.gsv() 
 end
 
 
 --[[
 获取原始GSA信息
-@api gnss.getGsa(data_mode)
+@api exgnss.gsa(data_mode)
 @number 模式,默认为0 -所有卫星系统全部输出在一起,1 - 每个卫星系统单独分开输出
 @return table 原始GSA数据
 @usage
 -- 获取
-log.info("nmea", "gsa", json.encode(gnss.getGsa()))
+log.info("nmea", "gsa", json.encode(exgnss.gsa()))
 -- 示例数据(模式0, 也就是默认模式)
 --sysid:1为GPS,4为北斗,2为GLONASS,3为Galileo
 {"pdop":1.1770000,  垂直精度因子,0.00 - 99.99,不定位时值为 99.99
@@ -833,7 +828,7 @@ log.info("nmea", "gsa", json.encode(gnss.getGsa()))
 }
 
 --模式1
-log.info("nmea", "gsa", json.encode(gnss.getGsa()))
+log.info("nmea", "gsa", json.encode(exgnss.gsa()))
 
 [{"pdop":1.1770000,"sats":[15,13,5,18,23,20,24],"vdop":1.0160000,"hdop":0.5940000,"sysid":1,"fix_type":3},
 {"pdop":1.1770000,"sats":[30,24,13,33,38,8,14,28,41,6,39,25],"vdop":1.0160000,"hdop":0.5940000,"sysid":4,"fix_type":3},
@@ -843,19 +838,19 @@ log.info("nmea", "gsa", json.encode(gnss.getGsa()))
 
 ]]
 
-function gnss.getGsa(data_mode)
-    return libgnss.getGsa(data_mode)
+function exgnss.gsa(data_mode)
+    return libgnss.gsa(data_mode)
 end
 
 
 --[[
 获取VTG速度信息
-@api gnss.getVtg(data_mode)
+@api exgnss.vtg(data_mode)
 @number 可选, 3-原始字符串, 不传或者传其他值, 则返回浮点值
 @return table/string 原始VTG数据
 @usage
 -- 解析nmea
-log.info("nmea", "vtg", json.encode(gnss.getVtg()))
+log.info("nmea", "vtg", json.encode(exgnss.vtg()))
 -- 示例
 {
     "speed_knots":0,        // 速度, 英里/小时
@@ -865,21 +860,21 @@ log.info("nmea", "vtg", json.encode(gnss.getVtg()))
 }
 
 --模式3
-log.info("nmea", "vtg", gnss.getVtg(3))
+log.info("nmea", "vtg", exgnss.vtg(3))
 -- 返回值:$GNVTG,0.000,T,,M,0.000,N,0.000,K,A*13\r
 -- 提醒: 在速度<5km/h时, 不会返回方向角
 ]]
-function gnss.getVtg(data_mode)
-    return  libgnss.getVtg(data_mode)
+function exgnss.vtg(data_mode)
+    return  libgnss.vtg(data_mode)
 end
 
 --获取原始ZDA时间和日期信息
 --[[
 获取原始ZDA时间和日期信息
-@api gnss.getZda()
+@api exgnss.zda()
 @return table 原始zda数据
 @usage
-log.info("nmea", "zda", json.encode(gnss.getZda()))
+log.info("nmea", "zda", json.encode(exgnss.zda()))
 -- 实例输出
 -- {
 --     "minute_offset":0,   // 本地时区的分钟, 一般固定输出0
@@ -892,17 +887,17 @@ log.info("nmea", "zda", json.encode(gnss.getZda()))
 --     "sec":14,           // 秒
 -- }
 ]]
-function gnss.getZda()
-    return  libgnss.getZda()
+function exgnss.zda()
+    return  libgnss.zda()
 end
 
 --[[
 获取GGA数据
-@api gnss.getGga(lnglat_mode)
+@api exgnss.gga(lnglat_mode)
 @number 经纬度数据的格式, 0-ddmm.mmmmm格式, 1-DDDDDDDDD格式, 2-DD.DDDDDDD格式, 3-原始GGA字符串
 @return table GGA数据, 若如不存在会返回nil
 @usage
-local gga = gnss.getGga(2)
+local gga = exgnss.gga(2)
 log.info("GGA", json.encode(gga, "11g"))
 --实例输出,获取值的解释:
 -- {
@@ -917,43 +912,43 @@ log.info("GGA", json.encode(gga, "11g"))
 -- }
 模式0示例:
 json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位,本示例保留5位小数
-local gga = gnss.getGga(0)
+local gga = exgnss.gga(0)
 if gga then
     log.info("GGA0", json.encode(gga, "5f"))
 end
 {"longitude":11419.19531,"dgps_age":0,"altitude":86.40000,"hdop":0.59400,"height":-13.70000,"fix_quality":1,"satellites_tracked":22,"latitude":3447.86914}
 模式1示例:
 DDDDDDDDD格式是由DD.DDDDDDD*10000000转换而来,目的是作为整数,方便某些场景使用
-local gga1 = gnss.getGga(1)
+local gga1 = exgnss.gga(1)
 if gga1 then
     log.info("GGA1", json.encode(gga1))
 end
 {"longitude":1143199103,"dgps_age":0,"altitude":86.4000015,"hdop":0.5940000,"height":-13.6999998,"fix_quality":1,"satellites_tracked":22,"latitude":347978178}
 模式2示例:
 json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位
-local gga2 = gnss.getGga(2)
+local gga2 = exgnss.gga(2)
 if gga2 then
     log.info("GGA2", json.encode(gga2))
 end
 {"longitude":114.3199081,"dgps_age":0,"altitude":86.4000015,"hdop":0.5940000,"height":-13.6999998,"fix_quality":1,"satellites_tracked":22,"latitude":34.7978172}
 模式3示例:
-local gga3 = gnss.getGga(3)
+local gga3 = exgnss.gga(3)
 if gga3 then
     log.info("GGA3", gga3)
 end
 $GNGGA,131241.000,3434.81372,N,11350.39930,E,1,05,4.924,165.5,M,-15.2,M,,*6D\r
 ]]
-function gnss.getGga(lnglat_mode)
-    return  libgnss.getGga(lnglat_mode)
+function exgnss.gga(lnglat_mode)
+    return  libgnss.gga(lnglat_mode)
 end
 
 --[[
 获取GLL数据
-@api gnss.getGll(data_mode)
+@api exgnss.gll(data_mode)
 @number 经纬度数据的格式, 0-ddmm.mmmmm格式, 1-DDDDDDDDD格式, 2-DD.DDDDDDD格式
 @return table GLL数据, 若如不存在会返回nil
 @usage
-local gll = gnss.getGll(2)
+local gll = exgnss.gll(2)
 if gll then
     log.info("GLL", json.encode(gll, "11g"))
 end
@@ -970,46 +965,46 @@ end
 -- }
 --模式0示例:
 --json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位,本示例保留5位小数
-local gll = gnss.getGll(0)
+local gll = exgnss.gll(0)
 if gll then
     log.info("GLL0", json.encode(gll, "5f"))
 end
 {"longitude":11419.19531,"sec":14,"min":32,"mode":"A","hour":6,"us":0,"status":"A","latitude":3447.86914}
 --模式1示例:
 --DDDDDDDDD格式是由DD.DDDDDDD*10000000转换而来,目的是作为整数,方便某些场景使用
-local gll1 = gnss.getGll(1)
+local gll1 = exgnss.gll(1)
 if gll1 then
     log.info("GLL1", json.encode(gll1))
 end
 {"longitude":1143199103,"sec":14,"min":32,"mode":"A","hour":6,"us":0,"status":"A","latitude":347978178}
 模式2示例:
 --json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位
-local gll2 = gnss.getGll(2)
+local gll2 = exgnss.gll(2)
 if gll2 then
     log.info("GLL2", json.encode(gll2))
 end
 {"longitude":114.3199081,"sec":14,"min":32,"mode":"A","hour":6,"us":0,"status":"A","latitude":34.7978172}
 ]]
-function gnss.getGll(data_mode)
-    return  libgnss.getGll(data_mode)
+function exgnss.gll(data_mode)
+    return  libgnss.gll(data_mode)
 end
 --[[
 获取最后的经纬度数据
-@api gnss.getlastloc()
-@return table 经纬度数据,格式:ddmm.mmmmm0000,返回nil表示没有数据,此数据在定位成功,关闭gps时,会自动保存到文件系统中,定位成功之后每10分钟如果还处于定位成功状态会更新
+@api exgnss.last_loc()
+@return table 经纬度数据,表里面的内容:{lat=ddmm.mmmmm0000,lng=ddmm.mmmmm0000},返回nil表示没有数据,此数据在定位成功,关闭gps时,会自动保存到文件系统中,定位成功之后每10分钟如果还处于定位成功状态会更新
 @usage
-local loc= gnss.getlastloc()
+local loc= exgnss.last_loc()
 if loc then
     log.info("lastloc", loc.lat,loc.lng)
 end
-输出示例:
-3434.7937000000 11350.386720000
+日志输出内容示例:
+3447.8679200000 11419.196290000
 ]]
-function gnss.getlastloc()
+function exgnss.last_loc()
     local locStr = io.readFile("/hxxtloc")
     if locStr then
         local jdata = json.decode(locStr)
         return jdata 
     end
 end
-return gnss
+return exgnss

+ 276 - 0
script/libs/exvib.lua

@@ -0,0 +1,276 @@
+--[[
+@module exvib
+@summary exvib 三轴加速度传感器扩展库
+@version 1.0
+@date    2025.08.10
+@author  李源龙
+@usage
+-- 用法实例
+注意:
+
+1. exvib.lua可适用于合宙内部集成了G-Sensor加速度传感器DA221的模组型号,
+目前仅有Air8000系列模组内置了DA221,Air7000推出时也会内置该型号G-Sensor;
+
+2. DA221在Air8000内部通过I2C1与之通信,并通过WAKEUP2接收运动监测中断,
+如您使用合宙其它型号模组外接DA221时,比如Air780EGH,建议与Air8000保持一致也选用I2C1和WAKEUP2
+(该管脚即为Air780EGH的PIN79:USIM_DET),这样便可以无缝使用本扩展库,DA221的供应商为苏州明皜
+如需采购DA221或者其他更高端的加速度传感器可以联系他们;
+
+3. DA221作为加速度传感器,LuatOS仅支持运动检测这一功能,主要用于震动检测,运动检测,跌倒检测,
+搭配GNSS实现震动然后定位的功能,其余功能请自行研究,合宙提供了三种应用场景,如果需要适配自己的场景需求,
+请参考手册参数自行修改代码,调试适合自己场景的传感器值,合宙不提供DA221任何其它功能的任何形式的技术支持;
+
+关于exvib库的三种模式主要用于以下场景:
+1,微小震动检测,用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
+2,运动检测,用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
+3,跌倒检测,用于人或物体瞬间跌倒时的检测;加速度量程8g;
+
+exvib=require("exvib")
+
+local intPin=gpio.WAKEUP2   --中断检测脚,内部固定wakeup2
+local tid   --获取定时打开的定时器id
+local num=0 --计数器 
+local ticktable={0,0,0,0,0} --存放5次中断的tick值,用于做有效震动对比
+local eff=false --有效震动标志位,用于判断是否触发定位
+
+
+--有效震动模式
+--tick计数器,每秒+1用于存放5次中断的tick值,用于做有效震动对比
+-- local function tick()
+--     num=num+1
+-- end
+-- --每秒运行一次计时
+-- sys.timerLoopStart(tick,1000)
+
+-- --有效震动判断
+-- local function ind()
+--     log.info("int", gpio.get(intPin))
+--     if gpio.get(intPin) == 1 then
+--         --接收数据如果大于5就删掉第一个
+--         if #ticktable>=5 then
+--             log.info("table.remove",table.remove(ticktable,1))
+--         end
+--         --存入新的tick值
+--         table.insert(ticktable,num)
+--         log.info("tick",num,(ticktable[5]-ticktable[1]<10),ticktable[5]>0)
+--         log.info("tick2",ticktable[1],ticktable[2],ticktable[3],ticktable[4],ticktable[5])
+--         --表长度为5且,第5次中断时间间隔减去第一次间隔小于10s,且第5次值为有效值
+--         if #ticktable>=5 and (ticktable[5]-ticktable[1]<10 and ticktable[1]>0) then
+--             log.info("vib", "xxx")
+--             --是否要去触发有效震动逻辑
+--             if eff==false then
+--                 sys.publish("EFFECTIVE_VIBRATION")
+--             end
+--         end
+--     end
+-- end
+
+-- --设置30s分钟之后再判断是否有效震动函数
+-- local function num_cb()
+--     eff=false
+-- end
+
+-- local function eff_vib()
+--     --触发之后eff设置为true,30分钟之后再触发有效震动
+--     eff=true
+--     --30分钟之后再触发有效震动
+--     sys.timerStart(num_cb,180000)
+-- end
+
+-- sys.subscribe("EFFECTIVE_VIBRATION",eff_vib)
+
+
+
+--持续震动模式
+
+--持续震动模式中断函数
+local function ind()
+    log.info("int", gpio.get(intPin))
+    --上升沿为触发震动中断
+    if gpio.get(intPin) == 1 then
+        local x,y,z =  exvib.read_xyz()      --读取x,y,z轴的数据
+        log.info("x", x..'g', "y", y..'g', "z", z..'g')
+    end
+end
+
+
+local function vib_fnc()
+    -- 1,微小震动检测,用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
+    -- 2,运动检测,用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
+    -- 3,跌倒检测,用于人或物体瞬间跌倒时的检测;加速度量程8g;
+    --打开震动检测功能
+    exvib.open(1)
+    --设置gpio防抖100ms
+    gpio.debounce(intPin, 100)
+    --设置gpio中断触发方式wakeup2唤醒脚默认为双边沿触发
+    gpio.setup(intPin, ind)
+
+end
+
+sys.taskInit(vib_fnc)
+
+]]
+local exvib={}
+
+local i2cId = 0
+
+local da221Addr = 0x27
+local soft_reset = {0x00, 0x24}         -- 软件复位地址
+local chipid_addr = 0x01                -- 芯片ID地址
+local rangeaddr = {0x0f, 0x00}          -- 设置加速度量程,默认2g
+-- local rangeaddr = {0x0f, 0x01}          -- 设置加速度量程,默认4g
+-- local rangeaddr = {0x0f, 0x10}          -- 设置加速度量程,默认8g
+local int_set1_reg = {0x16, 0x87}       --设置x,y,z发生变化时,产生中断
+local int_set2_reg = {0x17, 0x10}       --使能新数据中断,数据变化时,产生中断,本程序不设置
+local int_map1_reg = {0x19, 0x04}       --运动的时候,产生中断
+local int_map2_reg = {0x1a, 0x01}
+
+local active_dur_addr = {0x27, 0x01}    -- 设置激活时间,默认0x01
+local active_ths_addr = {0x28, 0x33}    -- 设置激活阈值,灵敏度最高
+-- local active_ths_addr = {0x28, 0x80}    -- 设置激活阈值,灵敏度适中
+-- local active_ths_addr = {0x28, 0xFE}    -- 设置激活阈值,灵敏度最低
+local odr_addr = {0x10, 0x08}           -- 设置采样率 100Hz
+local mode_addr = {0x11, 0x00}          -- 设置正常模式
+local int_latch_addr = {0x21, 0x02}     -- 设置中断锁存
+
+local x_lsb_reg = 0x02 -- X轴LSB寄存器地址
+local x_msb_reg = 0x03 -- X轴MSB寄存器地址
+local y_lsb_reg = 0x04 -- Y轴LSB寄存器地址
+local y_msb_reg = 0x05 -- Y轴MSB寄存器地址
+local z_lsb_reg = 0x06 -- Z轴LSB寄存器地址
+local z_msb_reg = 0x07 -- Z轴MSB寄存器地址
+
+local active_state = 0x0b -- 激活状态寄存器地址
+local active_state_data
+
+--[[
+    获取da221的xyz轴数据
+@api exvib.read_xyz()
+@return number x轴数据,number y轴数据,number z轴数据
+@usage
+    local x,y,z =  exvib.read_xyz()      --读取x,y,z轴的数据
+        log.info("x", x..'g', "y", y..'g', "z", z..'g')
+]]
+function exvib.read_xyz()
+    -- da221是LSB在前,MSB在后,每个寄存器都是1字节数据,每次读取都是6个寄存器数据一起获取
+    -- 因此直接从X轴LSB寄存器(0x02)开始连续读取6字节数据(X/Y/Z各2字节),避免出现数据撕裂问题
+    i2c.send(i2cId, da221Addr, x_lsb_reg, 1)
+    local recv_data = i2c.recv(i2cId, da221Addr, 6)
+
+    -- LSB数据格式为: D[3] D[2] D[1] D[0] unused unused unused unused
+    -- MSB数据格式为: D[11] D[10] D[9] D[8] D[7] D[6] D[5] D[4]
+    -- 数据位为12位,需要将MSB数据左移4位,LSB数据右移4位,最后进行或运算
+    -- 解析X轴数据 (LSB在前,MSB在后)
+    local x_data = (string.byte(recv_data, 2) << 4) | (string.byte(recv_data, 1) >> 4)
+
+    -- 解析Y轴数据 (LSB在前,MSB在后)
+    local y_data = (string.byte(recv_data, 4) << 4) | (string.byte(recv_data, 3) >> 4)
+
+    -- 解析Z轴数据 (LSB在前,MSB在后)
+    local z_data = (string.byte(recv_data, 6) << 4) | (string.byte(recv_data, 5) >> 4)
+
+    -- 转换为12位有符号整数
+    -- 判断X轴数据是否大于2047,若大于则表示数据为负数
+    -- 因为12位有符号整数的范围是 -2048 到 2047,原始数据为无符号形式,大于2047的部分需要转换为负数
+    -- 通过减去4096 (2^12) 将无符号数转换为对应的有符号负数
+    if x_data > 2047 then x_data = x_data - 4096 end
+    -- 判断Y轴数据是否大于2047,若大于则进行同样的有符号转换
+    if y_data > 2047 then y_data = y_data - 4096 end
+    -- 判断Z轴数据是否大于2047,若大于则进行同样的有符号转换
+    if z_data > 2047 then z_data = z_data - 4096 end
+
+    -- 转换为加速度值(单位:g)
+    local x_accel = x_data / 1024
+    local y_accel = y_data / 1024
+    local z_accel = z_data / 1024
+
+    -- 输出加速度值(单位:g)
+    return x_accel, y_accel, z_accel
+end
+
+--初始化da221
+local function da221_init()
+    gpio.setup(24, 1, gpio.PULLUP)  -- gsensor 开关
+    --关闭i2c
+    i2c.close(i2cId)
+    --重新打开i2c,i2c速度设置为低速
+    i2c.setup(i2cId, i2c.SLOW)
+
+    sys.wait(50)
+    i2c.send(i2cId, da221Addr, soft_reset, 1)   --复位da221
+    sys.wait(50)
+    i2c.send(i2cId, da221Addr, chipid_addr, 1)  --读取芯片id
+    local chipid = i2c.recv(i2cId, da221Addr, 1)    --接收返回的芯片id
+    log.info("i2c", "chipid",chipid:toHex())
+    if string.byte(chipid) == 0x13 then
+        log.info("exvib init success")
+    else
+        log.info("exvib init fail")
+    end
+    -- 设置寄存器
+    i2c.send(i2cId, da221Addr, rangeaddr, 1)    --设置加速度量程,默认2g
+    sys.wait(5)
+    i2c.send(i2cId, da221Addr, int_set1_reg, 1) --设置x,y,z发生变化时,产生中断
+    sys.wait(5)
+    i2c.send(i2cId, da221Addr, int_map1_reg, 1)--运动的时候,产生中断
+    sys.wait(5)
+    i2c.send(i2cId, da221Addr, active_dur_addr, 1)-- 设置激活时间,默认0x00
+    sys.wait(5)
+    i2c.send(i2cId, da221Addr, active_ths_addr, 1)-- 设置激活阈值
+    sys.wait(5)
+    i2c.send(i2cId, da221Addr, mode_addr, 1)-- 设置模式
+    sys.wait(5)
+    i2c.send(i2cId, da221Addr, odr_addr, 1)-- 设置采样率
+    sys.wait(5)
+    i2c.send(i2cId, da221Addr, int_latch_addr, 1)-- 设置中断锁存 中断一旦触发将保持,直到手动清除
+    sys.wait(5)
+end
+
+--[[
+    打开da221
+@api exvib.open(mode)
+@number da221模式设置,1,微小震动检测,用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
+                        2,运动检测,用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
+                        3,跌倒检测,用于人或物体瞬间跌倒时的检测;加速度量程8g;
+@return nil
+@usage
+    exvib.open(1)
+]]
+function exvib.open(mode)
+    if mode==1 or tonumber(mode)==1 then
+        --轻微检测
+        log.info("轻微检测")
+        rangeaddr = {0x0f, 0x00}          -- 设置加速度量程,默认2g
+        active_ths_addr = {0x28, 0x33}    -- 设置激活阈值
+        odr_addr = {0x10, 0x04}           -- 设置采样率 15.63Hz
+        active_dur_addr = {0x27, 0x01}    -- 设置激活时间
+    elseif mode==2 or tonumber(mode)==2 then
+        --常规检测
+        rangeaddr = {0x0f, 0x01}          -- 设置加速度量程,默认4g
+        active_ths_addr = {0x28, 0x26}    -- 设置激活阈值
+        odr_addr = {0x10, 0x08}           -- 设置采样率 250Hz
+        active_dur_addr = {0x27, 0x14}    -- 设置激活时间
+    elseif mode==3 or tonumber(mode)==3 then
+        --高动态检测
+        rangeaddr = {0x0f, 0x10}          -- 设置加速度量程,默认8g
+        active_ths_addr = {0x28, 0x80}    -- 设置激活阈值
+        odr_addr = {0x10, 0x0F}           -- 设置采样率 1000Hz
+        active_dur_addr = {0x27, 0x04}    -- 设置激活时间
+    end
+    sys.taskInit(da221_init)
+end
+
+--[[
+    关闭da221
+@api exvib.close()
+@return nil
+@usage
+    exvib.close()
+]]
+function exvib.close()
+    gpio.close(24)  -- gsensor供电关闭
+    log.info("exvib close..")
+end
+
+
+return exvib