--[[ @module gnss @summary gnss拓展库 @version 1.0 @date 2025.07.16 @author 李源龙 @usage -- 用法实例 -- 注意:gnss.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. -- 打开gnss后,gnss定位成功时,如果有回调函数,会调用回调函数 -- 使用此应用模式调用gnss.open打开的“gnss应用”,必须主动调用gnss.close -- 或者gnss.closeAll才能关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数 -- 通俗点说就是一直打开,除非自己手动关闭掉 gnss.TIMERORSUC: --- gnss应用模式2. -- 打开gnss后,如果在gnss开启最大时长到达时,没有定位成功,如果有回调函数, -- 会调用回调函数,然后自动关闭此“gnss应用” -- 打开gnss后,如果在gnss开启最大时长内,定位成功,如果有回调函数, -- 会调用回调函数,然后自动关闭此“gnss应用” -- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者 -- gnss.closeAll主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数 -- 通俗点说就是设置规定时间打开,如果规定时间内定位成功就会自动关闭此应用, -- 如果没有定位成功,时间到了也会自动关闭此应用 gnss.TIMER: --- gnss应用模式3. -- 打开gnss后,在gnss开启最大时长时间到达时,无论是否定位成功,如果有回调函数, -- 会调用回调函数,然后自动关闭此“gnss应用” -- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者gnss.closeAll -- 主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数 -- 通俗点说就是设置规定时间打开,无论是否定位成功,到了时间都会自动关闭此应用, -- 和第二种的区别在于定位成功之后不会自动关闭,到时间之后才会自动关闭 gnss=require("gnss") local function mode1_cb(tag) log.info("TAGmode1_cb+++++++++",tag) log.info("nmea", "rmc", json.encode(gnss.getRmc(2))) end local function mode2_cb(tag) log.info("TAGmode2_cb+++++++++",tag) log.info("nmea", "rmc", json.encode(gnss.getRmc(2))) end local function mode3_cb(tag) log.info("TAGmode3_cb+++++++++",tag) log.info("nmea", "rmc", json.encode(gnss.getRmc(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.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}) sys.wait(40000) log.info("关闭一个gnss应用,然后查看下所有应用的状态") --关闭一个gnss应用 gnss.close(gnss.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"})) sys.wait(10000) --关闭所有gnss应用 gnss.closeAll() --查询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"})) --查询最后一次定位结果 local loc= gnss.getlastloc() 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("gnss", "state", event) end sys.subscribe(gnss_state) ]] local gnss = {} --gnss开启标志,true表示开启状态,false或者nil表示关闭状态 local openFlag --gnss定位标志,true表示,其余表示未定位 local fixFlag=nil --串口配置 local uart_baudrate = 115200 local uart_id = 2 --gnss 的串口线程是否在工作; local taskFlag=false local agpsFlag=false --保存经纬度到文件区 function gnss.saveloc(lat, lng) if not lat or not lng then if libgnss.isFix() then local rmc = libgnss.getRmc(0) if rmc then lat, lng = rmc.lat, rmc.lng end end end if lat and lng then -- log.info("待保存的GPS位置", lat, lng) local locStr = string.format('{"lat":%.5f,"lng":%.5f}', lat, lng) -- log.info("gnss", "保存GPS位置", locStr) io.writeFile("/hxxtloc", locStr) end local now = os.time() 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) elseif event == "LOSE" or event == "CLOSE" then -- log.info("libagps","libagps is close") sys.timerStop(tid) end end) --agps操作,联网访问服务器获取星历数据 local function _agps() local lat, lng --此逻辑在agps定位成功之后,还会继续开启10s-15s, --原因是因为如果第一次冷启动之后,定位成功之后, --如果直接关闭gnss会导致gnss芯片的星历没有解析完毕,会影响下一次的定位为冷启动 --如果对功耗有需求,需要定位快,可以每次都使用agps,不需要这句,直接屏蔽掉即可 --代价是每次定位都会进行基站定位, -- gnss.open(gnss.TIMER,{tag="libagps",val=20}) -- 判断星历时间和下载星历 local now = os.time() local agps_time = tonumber(io.readFile("/hxxt_tm") or "0") or 0 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 -- 单北斗 url = "http://download.openluat.com/9501-xingli/HXXT_BDS_AGNSS_DATA.dat" else url = "http://download.openluat.com/9501-xingli/HXXT_GPS_BDS_AGNSS_DATA.dat" end end local code = http.request("GET", url, nil, nil, {dst="/hxxt.dat"}).wait() if code and code == 200 then log.info("gnss.opts", "下载星历成功", url) io.writeFile("/hxxt_tm", tostring(now)) else log.info("gnss.opts", "下载星历失败", code) end else log.info("gnss.opts", "星历不需要更新", now - agps_time) end --进行基站定位,给到gnss芯片一个大概的位置 if mobile then local lbsLoc2 = require("lbsLoc2") lat, lng = lbsLoc2.request(5000) -- local lat, lng, t = lbsLoc2.request(5000, "bs.openluat.com") -- log.info("lbsLoc2", lat, lng) if lat and lng then lat = tonumber(lat) lng = tonumber(lng) log.info("lbsLoc2", lat, lng) -- 转换单位 local lat_dd,lat_mm = math.modf(lat) local lng_dd,lng_mm = math.modf(lng) lat = lat_dd * 100 + lat_mm * 60 lng = lng_dd * 100 + lng_mm * 60 end elseif wlan then -- wlan.scan() -- sys.waitUntil("WLAN_SCAN_DONE", 5000) end --获取基站定位失败则使用本地之前保存的位置 if not lat then -- 获取最后的本地位置 local locStr = io.readFile("/hxxtloc") if locStr then local jdata = json.decode(locStr) if jdata and jdata.lat then lat = jdata.lat lng = jdata.lng end end end local gps_uart_id = uart_id -- 写入星历 local agps_data = io.readFile("/hxxt.dat") if agps_data and #agps_data > 1024 then log.info("gnss.opts", "写入星历数据", "长度", #agps_data) for offset=1,#agps_data,512 do log.info("gnss", "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", "没有星历数据") 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) return --暂时不写入参考位置 else log.info("gnss.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) uart.write(gps_uart_id, str .. "\r\n") sys.wait(20) end -- 写入参考位置 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) uart.write(gps_uart_id, str) -- 结束 gnss.opts.agps_tm = now agpsFlag=true end --执行agps操作判断 function gnss.agps() -- 如果不是强制写入AGPS信息, 而且是已经定位成功的状态,那就没必要了 if libgnss.isFix() then return end -- 先判断一下时间 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 if not gnss.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 -- 执行AGPS log.info("gnss.opts", "开始执行AGPS") sys.taskInit(_agps) else log.info("gnss.opts", "暂不需要写入AGPS") end end --打开gnss,内部函数使用,不推荐给脚本层使用 local function _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 --默认全开启 log.info("全卫星开启") elseif gnss.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 log.info("debug开启") libgnss.debug(true) elseif gnss.opts.debug==false then log.info("debug关闭") libgnss.debug(false) end if type(gnss.opts.bind)=="number" then log.info("绑定bind事件") libgnss.bind(uart_id,gnss.opts.bind) else libgnss.bind(uart_id) end if gnss.opts.rtc==true then log.info("rtc开启") libgnss.rtcAuto(true) elseif gnss.opts.rtc==false then log.info("rtc关闭") libgnss.rtcAuto(false) end if gnss.opts.agps_enable==true then log.info("agps开启") sys.taskInit(gnss.agps) end --设置输出VTG内容 sys.timerStart(function() uart.write(uart_id,"$CFGMSG,0,5,1,1\r\n") end,800) --设置输出ZDA内容 sys.timerStart(function() uart.write(uart_id,"$CFGMSG,0,6,1,1\r\n") end,900) openFlag = true sys.publish("GNSS_STATE","OPEN") log.info("gnss._open") end --关闭gnss,内部函数使用,不推荐给脚本层使用 local function _close() if not openFlag then return end gnss.saveloc() pm.power(pm.GPS, false) uart.close(uart_id) openFlag = false fixFlag = false sys.publish("GNSS_STATE","CLOSE",fixFlag) log.info("gnss._close") libgnss.clear() end --- gnss应用模式1. -- -- 打开gnss后,gnss定位成功时,如果有回调函数,会调用回调函数 -- -- 使用此应用模式调用gnss.open打开的“gnss应用”,必须主动调用gnss.close或者gnss.closeAll才能关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数 gnss.DEFAULT = 1 --- gnss应用模式2. -- -- 打开gnss后,如果在gnss开启最大时长到达时,没有定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“gnss应用” -- -- 打开gnss后,如果在gnss开启最大时长内,定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“gnss应用” -- -- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者gnss.closeAll主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数 gnss.TIMERORSUC = 2 --- gnss应用模式3. -- -- 打开gnss后,在gnss开启最大时长时间到达时,无论是否定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“gnss应用” -- -- 打开gnss后,在自动关闭此“gnss应用”前,可以调用gnss.close或者gnss.closeAll主动关闭此“gnss应用”,主动关闭时,即使有回调函数,也不会调用回调函数 gnss.TIMER = 3 --“gnss应用”表 local tList = {} --[[ 函数名:delItem 功能 :从“gnss应用”表中删除一项“gnss应用”,并不是真正的删除,只是设置一个无效标志 参数 : mode:gnss应用模式 para: para.tag:“gnss应用”标记 para.val:gnss开启最大时长 para.cb:回调函数 返回值:无 ]] local function delItem(mode,para) for i=1,#tList do --标志有效 并且 gnss应用模式相同 并且 “gnss应用”标记相同 if tList[i].flag and tList[i].mode==mode and tList[i].para.tag==para.tag then --设置无效标志 tList[i].flag,tList[i].delay = false break end end end --[[ 函数名:addItem 功能 :新增一项“gnss应用”到“gnss应用”表 参数 : mode:gnss应用模式 para: para.tag:“gnss应用”标记 para.val:gnss开启最大时长 para.cb:回调函数 返回值:无 ]] local function addItem(mode,para) --删除相同的“gnss应用” 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 for i=1,#tList do --如果存在无效的“gnss应用”项,直接使用此位置 if not tList[i].flag then tList[i] = item fnd = true break end end --新增一项 if not fnd then table.insert(tList,item) end 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 end end --GNSS定时器 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) 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 tList[i].para.remain = rmn-1 end if dly and dly>0 then tList[i].para.delay = dly-1 end rmn = tList[i].para.remain if libgnss.isFix() and md==gnss.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 tList[i].para.delay = nil else gnss.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) end end end end if existTimerItem() then sys.timerStart(timerFnc,1000) end end --[[ 函数名:statInd 功能 :处理gnss定位成功的消息 参数 : evt:gnss消息类型 返回值:无 ]] 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) if tList[i].flag then if tList[i].mode ~= gnss.TIMER then tList[i].para.delay = 1 if tList[i].mode == gnss.DEFAULT then if existTimerItem() then sys.timerStart(timerFnc,1000) end end end end end end end --[[ 设置gnss定位参数 @api gnss.setup(opts) @table opts gnss定位参数,可选值gnssmode:定位卫星模式,1为卫星全定位,2为单北斗,默认为卫星全定位 agps_enable:是否启用AGPS,true为启用,false为不启用,默认为false debug:是否输出调试信息到luatools,true为输出,false为不输出,默认为false uart:GNSS串口配置,780EGH和8000默认为uart2,可不填 uartbaud:GNSS串口波特率,780EGH和8000默认为115200,可不填 bind:绑定uart端口进行GNSS数据读取,是否设置串口转发,指定串口号,不需要转发可不填 rtc:定位成功后自动设置RTC true开启,flase关闭,默认为flase,不需要可不填 @return nil @usage 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.setup(gnssotps) ]] function gnss.setup(opts) gnss.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 else uart_id=2 end if gnss.opts.uartbaud then uart_baudrate=gnss.opts.uartbaud else uart_baudrate=115200 end end end --[[ 打开一个“gnss应用” @api gnss.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 @usage -- “gnss应用”:指的是使用gnss功能的一个应用 -- 例如,假设有如下3种需求,要打开gnss,则一共有3个“gnss应用”: -- “gnss应用1”:每隔1分钟打开一次gnss -- “gnss应用2”:设备发生震动时打开gnss -- “gnss应用3”:收到一条特殊短信时打开gnss -- 只有所有“gnss应用”都关闭了,才会去真正关闭gnss -- 每个“gnss应用”打开或者关闭gnss时,最多有4个参数,其中 gnss应用模式和gnss应用标记 共同决定了一个唯一的“gnss应用”: -- 1、gnss应用模式(必选) -- 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}) ]] 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) --如果gnss定位成功 if libgnss.isFix() then if mode~=gnss.TIMER then --执行回调函数 if para.cb then para.cb(para.tag) end if mode==gnss.TIMERORSUC then return end end end addItem(mode,para) --真正去打开gnss _open() --启动1秒的定时器 if existTimerItem() and not sys.timerIsActive(timerFnc) then sys.timerStart(timerFnc,1000) end end --[[ 关闭一个“gnss应用”,只是从逻辑上关闭一个gnss应用,并不一定真正关闭gnss,是有所有的gnss应用都处于关闭状态,才会去真正关闭gnss @api gnss.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"}) ]] 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) --删除此“gnss应用” delItem(mode,para) local valid,i for i=1,#tList do if tList[i].flag then valid = true end end --如果没有一个“gnss应用”有效,则关闭gnss if not valid then _close() end end --[[ 关闭所有“gnss应用” @api gnss.closeAll() @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() ]] function gnss.closeAll() 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) end end --[[ 判断一个“gnss应用”是否处于激活状态 @api gnss.isActive(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"})) ]] function gnss.isActive(mode,para) assert((para and type(para)=="table" and para.tag and type(para.tag)=="string"),"gnss.isActive 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 end sys.subscribe("GNSS_STATE",statInd) --[[ 当前是否已经定位成功 @api gnss.isFix() @return boolean true/false,定位成功返回true,否则返回false @usage log.info("nmea", "isFix", gnss.isFix()) ]] function gnss.isFix() return libgnss.isFix() end --[[ 获取number类型的位置和速度信息 @api gnss.getIntLocation(speed_type) @number 速度单位,默认是m/h, 0 - m/h 米/小时, 默认值, 整型 1 - m/s 米/秒, 浮点数 2 - km/h 千米/小时, 浮点数 3 - kn/h 英里/小时, 浮点数 @return number lat数据, 格式为 DDDDDDDDD,示例:343482649,DDDDDDDDD格式是由DD.DDDDDDD*10000000转换而来,目的是作为整数,方便某些场景使用 @return number lng数据, 格式为 DDDDDDDDD,示例:1135039700,DDDDDDDDD格式是由DD.DDDDDDD*10000000转换而来,目的是作为整数,方便某些场景使用 @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) -- speed数据默认 米/小时,返回值例如:343482649 1135039700 390m/h log.info("nmea", "loc", gnss.getIntLocation()) -- speed数据米/秒,返回值例如:343482649 1135039700 0.1085478m/s log.info("nmea", "loc", gnss.getIntLocation(1)) -- speed数据千米/小时,返回值例如:343482649 1135039700 0.3907720km/h log.info("nmea", "loc", gnss.getIntLocation(2)) -- speed数据英里/小时,返回值例如:343482649 1135039700 0.2110000kn/h log.info("nmea", "loc", gnss.getIntLocation(3)) ]] function gnss.getIntLocation(speed_type) return libgnss.getIntLocation(speed_type) end --[[ 获取RMC的信息,经纬度,时间,速度,航向,定位是否有效,磁偏角 @api gnss.getRmc(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))) -- 实例输出,获取值的解释 -- { -- "course":344.9920044, // 地面航向,单位为度,从北向起顺时针计算 -- "valid":true, // true定位成功,false定位丢失 -- "lat":34.5804405, // 纬度, 正数为北纬, 负数为南纬 -- "lng":113.8399506, // 经度, 正数为东经, 负数为西经 -- "variation":0, // 磁偏角,固定为0 -- "speed":0.2110000 // 地面速度, 单位为"节" -- "year":2023, // 年份 -- "month":1, // 月份, 1-12 -- "day":5, // 月份天, 1-31 -- "hour":7, // 小时,0-23 -- "min":23, // 分钟,0-59 -- "sec":20, // 秒,0-59 -- } --模式0示例: --json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位,本示例保留5位小数 log.info("nmea", "rmc0", json.encode(gnss.getRmc(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))) {"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))) {"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)) $GNRMC,115430.000,A,3434.82649,N,11350.39700,E,0.211,344.992,170725,,,A,S*02\r ]] function gnss.getRmc(lnglat_mode) return libgnss.getRmc(lnglat_mode) end --[[ 获取原始GSV信息 @api gnss.getGsv() @return table 原始GSV数据 @usage -- 解析nmea log.info("nmea", "gsv", json.encode(gnss.getGsv())) -- 实例输出 -- { -- "total_sats":24, // 总可见卫星数量 -- "sats":[ -- { -- "snr":27, // 信噪比 -- "azimuth":278, // 方向角 -- "elevation":59, // 仰角 -- "tp":0, // 0 - GPS, 1 - BD, 2 - GLONASS, 3 - Galileo, 4 - QZSS -- "nr":4 // 卫星编号 -- }, -- // 这里忽略了22个卫星的信息 -- { -- "snr":0, -- "azimuth":107, -- "elevation":19, -- "tp":1, -- "nr":31 -- } -- ] -- } ]] function gnss.getGsv() return libgnss.getGsv() end --[[ 获取原始GSA信息 @api gnss.getGsa(data_mode) @number 模式,默认为0 -所有卫星系统全部输出在一起,1 - 每个卫星系统单独分开输出 @return table 原始GSA数据 @usage -- 获取 log.info("nmea", "gsa", json.encode(gnss.getGsa())) -- 示例数据(模式0, 也就是默认模式) --sysid:1为GPS,4为北斗,2为GLONASS,3为Galileo {"pdop":1.1770000, 垂直精度因子,0.00 - 99.99,不定位时值为 99.99 "sats":[15,13,5,18,23,20,24,30,24,13,33,38,8,14,28,41,6,39,25,16,32,27], // 正在使用的卫星编号 "vdop":1.0160000, 垂直精度因子,0.00 - 99.99,不定位时值为 99.99 "hdop":0.5940000, // 位置精度因子,0.00 - 99.99,不定位时值为 99.99 "sysid":1, // 卫星系统编号1为GPS,4为北斗,2为GLONASS,3为Galileo "fix_type":3 // 定位模式, 1-未定位, 2-2D定位, 3-3D定位 } --模式1 log.info("nmea", "gsa", json.encode(gnss.getGsa())) [{"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}, {"pdop":1.1770000,"sats":[16,32,27],"vdop":1.0160000,"hdop":0.5940000,"sysid":4,"fix_type":3}, {"pdop":1.1770000,"sats":{},"vdop":1.0160000,"hdop":0.5940000,"sysid":2,"fix_type":3}, {"pdop":1.1770000,"sats":{},"vdop":1.0160000,"hdop":0.5940000,"sysid":3,"fix_type":3}] ]] function gnss.getGsa(data_mode) return libgnss.getGsa(data_mode) end --[[ 获取VTG速度信息 @api gnss.getVtg(data_mode) @number 可选, 3-原始字符串, 不传或者传其他值, 则返回浮点值 @return table/string 原始VTG数据 @usage -- 解析nmea log.info("nmea", "vtg", json.encode(gnss.getVtg())) -- 示例 { "speed_knots":0, // 速度, 英里/小时 "true_track_degrees":0, // 真北方向角 "magnetic_track_degrees":0, // 磁北方向角 "speed_kph":0 // 速度, 千米/小时 } --模式3 log.info("nmea", "vtg", gnss.getVtg(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) end --获取原始ZDA时间和日期信息 --[[ 获取原始ZDA时间和日期信息 @api gnss.getZda() @return table 原始zda数据 @usage log.info("nmea", "zda", json.encode(gnss.getZda())) -- 实例输出 -- { -- "minute_offset":0, // 本地时区的分钟, 一般固定输出0 -- "hour_offset":0, // 本地时区的小时, 一般固定输出0 -- "year":2023 // UTC 年,四位数字 -- "month":1, // UTC 月,两位,01 ~ 12 -- "day":5, // UTC 日,两位数字,01 ~ 31 -- "hour":7, // 小时 -- "min":50, // 分 -- "sec":14, // 秒 -- } ]] function gnss.getZda() return libgnss.getZda() end --[[ 获取GGA数据 @api gnss.getGga(lnglat_mode) @number 经纬度数据的格式, 0-ddmm.mmmmm格式, 1-DDDDDDDDD格式, 2-DD.DDDDDDD格式, 3-原始GGA字符串 @return table GGA数据, 若如不存在会返回nil @usage local gga = gnss.getGga(2) log.info("GGA", json.encode(gga, "11g")) --实例输出,获取值的解释: -- { -- "dgps_age":0, // 差分校正时延,单位为秒 -- "fix_quality":1, // 定位状态标识 0 - 无效,1 - 单点定位,2 - 差分定位 -- "satellites_tracked":14, // 参与定位的卫星数量 -- "altitude":0.255, // 海平面分离度, 或者成为海拔, 单位是米, -- "hdop":0.0335, // 水平精度因子,0.00 - 99.99,不定位时值为 99.99 -- "longitude":113.231, // 经度, 正数为东经, 负数为西经 -- "latitude":23.4067, // 纬度, 正数为北纬, 负数为南纬 -- "height":0 // 椭球高,固定输出 1 位小数 -- } 模式0示例: json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位,本示例保留5位小数 local gga = gnss.getGga(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) 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) 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) 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) end --[[ 获取GLL数据 @api gnss.getGll(data_mode) @number 经纬度数据的格式, 0-ddmm.mmmmm格式, 1-DDDDDDDDD格式, 2-DD.DDDDDDD格式 @return table GLL数据, 若如不存在会返回nil @usage local gll = gnss.getGll(2) if gll then log.info("GLL", json.encode(gll, "11g")) end -- 实例数据,获取值的解释: -- { -- "status":"A", // 定位状态, A有效, B无效 -- "mode":"A", // 定位模式, V无效, A单点解, D差分解 -- "sec":20, // 秒, UTC时间为准 -- "min":23, // 分钟, UTC时间为准 -- "hour":7, // 小时, UTC时间为准 -- "longitude":113.231, // 经度, 正数为东经, 负数为西经 -- "latitude":23.4067, // 纬度, 正数为北纬, 负数为南纬 -- "us":0 // 微妙数, 通常为0 -- } --模式0示例: --json.encode默认输出"7f"格式保留7位小数,可以根据自己需要的格式调整小数位,本示例保留5位小数 local gll = gnss.getGll(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) 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) 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) end --[[ 获取最后的经纬度数据 @api gnss.getlastloc() @return table 经纬度数据,格式:ddmm.mmmmm0000,返回nil表示没有数据,此数据在定位成功,关闭gps时,会自动保存到文件系统中,定位成功之后每10分钟如果还处于定位成功状态会更新 @usage local loc= gnss.getlastloc() if loc then log.info("lastloc", loc.lat,loc.lng) end 输出示例: 3434.7937000000 11350.386720000 ]] function gnss.getlastloc() local locStr = io.readFile("/hxxtloc") if locStr then local jdata = json.decode(locStr) return jdata end end return gnss