--- 模块功能:GPS模块管理 -- 注意:此功能模块中的功能接口可以分为四大类: -- 1、GPS开启 -- 2、GPS关闭 -- 3、GPS定位数据读取 -- 4、GPS参数和功能设置 -- 1、2、3是通用功能,除了支持合宙的Air512G、Air551G、Air552G模块,理论上也支持其他厂家的串口GPS模块 -- 4是专用功能,仅支持合宙的Air512G、Air551G、Air552G模块 -- @module gps9701 -- @author openLuat -- @license MIT -- @copyright openLuat -- @release 2017.10.23 require"pm" require"utils" module(..., package.seeall) local smatch,sfind,slen,ssub,sbyte,sformat,srep = string.match,string.find,string.len,string.sub,string.byte,string.format,string.rep --GPS开启标志,true表示开启状态,false或者nil表示关闭状态 local openFlag --GPS定位标志,"2D"表示2D定位,"3D"表示3D定位,其余表示未定位 --GPS定位标志,true表示,其余表示未定位 local fixFlag,fixOnece=nil,nil --GPS定位成功后,过滤掉前filterSeconds秒的经纬度信息 --是否已经过滤完成 local filterSeconds,filteredFlag = 0 --从定位成功切换到定位失败,连续定位失败的次数 local fixFailCnt = 0 --经纬度类型和数据 local latitudeType,latitude,longitudeType,longitude = "N","","E","" --海拔,速度,方向角 local altitude,speed,course = "0","0","0" --参与定位的卫星个数,所有可见卫星的最大信号值,所有可见卫星的最大信号值中间缓存值 local usedSateCnt,maxSignalStrength,maxSignalStrengthVar = "0",0,0 --可见卫星个数 local viewedGpsSateCnt,viewedBdSateCnt = "0","0" --可用卫星号,UTC时间,信噪比 local SateSn,UtcTime,Gsv --大地高,度分经度,度分纬度 local Sep,Ggalng,Ggalat --是否需要解析项 local psUtcTime,psGsv,psSn --GPS供电设置函数 local powerCbFnc --串口配置 uartBaudrate = 115200 local uartID,uartDatabits,uartParity,uartStopbits = 2,8,uart.PAR_NONE,uart.STOP_1 --搜星模式命令字符串,"$PGKC115," .. gps .. "," .. glonass .. "," .. beidou .. "," .. galieo .. "*" local aerialModeStr,aerialModeSetted = "" --运行模式命令字符串,"$PGKC105," .. mode .. "," .. rt .. "," .. st .. "*" local runModeStr,runModeSetted = "" --正常运行模式下NMEA数据上报间隔命令字符串,"$PGKC101," .. interval .. "*" local nmeaReportStr,nmeaReportSetted = "" --每种NEMA数据的输出频率命令字符串 local nmeaReportFreqStr,nmeaReportFreqSetted = "" --NMEA数据处理模式,0表示仅gps.lua内部处理,1表示仅用户自己处理,2表示gps.lua和用户同时处理 --用户处理一条NMEA数据的回调函数 local nmeaMode,nmeaCbFnc = 0 --NMEA数据输出间隔 local nmeaInterval = 1000 --运行模式 --0,正常运行模式 --1,周期超低功耗跟踪模式 --2,周期低功耗模式 --4,直接进入超低功耗跟踪模式 --8,自动低功耗模式,可以通过串口唤醒 --9, 自动超低功耗跟踪模式,需要force on来唤醒 local runMode = 0 --gps 的串口线程是否在工作; local taskFlag=false --runMode为1或者2时,GPS运行状态和休眠状态的时长 local runTime,sleepTime --检测gps是否工作正常的定时器ID local workAbnormalTimerId local agpsver = nil checkdatapack = false local testcoro = nil local i = 0 --[[ 函数名:getstrength 功能 :解析GSV数据 参数 : sg:NEMA中的一行GSV数据 返回值:无 ]] local function getstrength(sg) sg = ssub(sg, 4, #sg) local d1,d2,curnum,lineno,total,sgv_str = sfind(sg,"GSV,(%d),(%d),(%d+),(.*)%*.*") if not curnum or not lineno or not total or not sgv_str then return end if lineno == nil then maxSignalStrengthVar = 0 maxSignalStrength = 0 elseif tonumber(lineno) == 1 then maxSignalStrength = maxSignalStrengthVar maxSignalStrengthVar = 0 end local tmpstr,i = sgv_str for i=1,4 do local d1,d2,id,elevation,azimuth,strength = sfind(tmpstr,"(%d+),([%-]*%d*),(%d*),(%d*)") if id == nil then return end if strength == "" or not strength then strength = "00" end strength = tonumber(strength) if strength > maxSignalStrengthVar then maxSignalStrengthVar = strength end local idx,cur,fnd,tmpid = 0,id..","..elevation..","..azimuth..","..strength..",",false for tmpid in string.gmatch(Gsv,"(%d+),%d*,%d*,%d*,") do idx = idx + 1 if tmpid == id then fnd = true break end end if fnd then local pattern,i = "" for i=1,idx do pattern = pattern.."%d+,%d*,%d*,%d*," end local m1,m2 = sfind(Gsv,"^"..pattern) if m1 and m2 then local front = ssub(Gsv,1,m2) local n1,n2 = sfind(front,"%d+,%d*,%d*,%d*,$") if n1 and n2 then Gsv = ssub(Gsv,1,n1-1)..cur..ssub(Gsv,n2+1,-1) end end else Gsv = Gsv..cur end tmpstr = ssub(tmpstr,d2+1,-1) end end local function filterTimerFnc() log.info("gps.filterTimerFnc end") filteredFlag = true end local function stopWorkAbnormalTimer() if workAbnormalTimerId then sys.timerStop(workAbnormalTimerId) workAbnormalTimerId = nil end end local function parseNmea(s) if not s or s=="" then return end local lat,lng,spd,cog,gpsFind,gpsTime,gpsDate,locSateCnt,hdp,latTyp,lngTyp,altd local hexStr = s:toHex() if smatch(hexStr,"AAF00D0001009500039A00AA0F") then sys.publish("GPS_STATE","BINARY_CMD_ACK") agpsver = true stopWorkAbnormalTimer() i= i+1 return elseif smatch(hexStr,"AAF00D000300") then sys.publish("GPS_STATE",smatch(hexStr,"^AAF00D000300FFFF") and "WRITE_EPH_END_ACK" or "WRITE_EPH_ACK") stopWorkAbnormalTimer() return end local fixed,workAbnormal if smatch(s,"GGA") then lat,latTyp,lng,lngTyp,gpsFind,locSateCnt,hdp,altd,sep = smatch(s,"GGA,%d+%.%d+,(%d+%.%d+),([NS]),(%d+%.%d+),([EW]),(%d),(%d+),([%d%.]*),(.*),M,(.*),M") if (gpsFind=="1" or gpsFind=="2" or gpsFind=="4") and altd then --fixed = true altitude = altd latitudeType,longitudeType,latitude,longitude = latTyp,lngTyp,lat,lng usedSateCnt = locSateCnt Ggalng,Ggalat = (lngTyp=="W" and "-" or "")..lng,(latTyp=="S" and "-" or "")..lat Sep = sep else fixed = false end elseif smatch(s,"RMC") then gpsTime,gpsFind,lat,latTyp,lng,lngTyp,spd,cog,gpsDate = smatch(s,"RMC,(%d%d%d%d%d%d)%.%d+,(%w),(%d*%.*%d*),([NS]*),(%d*%.*%d*),([EW]*),(.-),(.-),(%d%d%d%d%d%d),") if gpsFind=="A" and cog then fixed = true latitudeType,longitudeType,latitude,longitude = latTyp,lngTyp,lat,lng speed = spd course = cog else fixed = false end if psUtcTime and gpsFind == "A" and gpsTime and gpsDate and gpsTime ~= "" and gpsDate ~= "" then local yy,mm,dd,h,m,s = tonumber(ssub(gpsDate,5,6)),tonumber(ssub(gpsDate,3,4)),tonumber(ssub(gpsDate,1,2)),tonumber(ssub(gpsTime,1,2)),tonumber(ssub(gpsTime,3,4)),tonumber(ssub(gpsTime,5,6)) UtcTime = {year=2000+yy,month=mm,day=dd,hour=h,min=m,sec=s} end elseif smatch(s,"GPGSV") then viewedGpsSateCnt = tonumber(smatch(s,"%d+,%d+,(%d+)") or "0") if psGsv then getstrength(s) end elseif smatch(s,"BDGSV") then viewedBdSateCnt = tonumber(smatch(s,"%d+,%d+,(%d+)") or "0") if psGsv then getstrength(s) end elseif smatch(s,"GSA") then if psSn then local satesn = smatch(s,"GSA,%w*,%d*,(%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,)") or "" if slen(satesn) > 0 and smatch(satesn,"%d+,") then SateSn = satesn end end else workAbnormal = true end if not workAbnormal then stopWorkAbnormalTimer() end if filterSeconds>0 and fixed and not fixFlag and not filteredFlag then if not sys.timerIsActive(filterTimerFnc) then log.info("gps.filterTimerFnc begin") sys.publish("GPS_STATE","LOCATION_FILTER") sys.timerStart(filterTimerFnc,filterSeconds*1000) end return end --定位成功 if fixed then if not fixFlag then fixFlag,filteredFlag = true,true fixOnece=true fixFailCnt = 0 sys.publish("GPS_STATE","LOCATION_SUCCESS") end elseif fixed==false then if fixFlag then fixFailCnt = fixFailCnt+1 if fixFailCnt>=20 then fixFlag,filteredFlag = false sys.timerStop(filterTimerFnc) sys.publish("GPS_STATE","LOCATION_FAIL") end end end end local function taskRead() local cacheData = "" local co = coroutine.running() while true do local s ="" if openFlag then s= uart.read(uartID, "*l") end if i==2 then agpsver =false i = 0 end if agpsver then if s=="" then checkdatapack = true else sys.publish("NOEMAL_RECE") end end if s == "" then uart.on(uartID,"receive",function() coroutine.resume(co) end) coroutine.yield() uart.on(uartID,"receive") else cacheData = cacheData..s if cacheData:toHex()=="AAF00D0001009500039A00AA0F" or smatch(cacheData:toHex(),"AAF00D000300") then cacheData = cacheData.."\r\n" end local d1,d2,nemaStr = sfind(cacheData,"\r\n")--截取串口收到的数据 while d1 do writePendingCmds() nemaStr = ssub(cacheData,1,d2) cacheData = ssub(cacheData,d2+1,-1) if nmeaMode==0 or nmeaMode==2 then --解析一行NEMA数据 parseNmea(nemaStr) end if (nmeaMode==1 or nmeaMode==2) and nmeaCbFnc then nmeaCbFnc(nemaStr) end d1,d2 = sfind(cacheData,"\r\n") end end end end -- GPS串口写命令操作 -- @string cmd,GPS指令(cmd格式:"$PGKC149,1,115200*"或者"$PGKC149,1,115200*XX\r\n") -- @bool isFull,cmd是否为完整的指令格式,包括校验和以及\r\n;true表示完整,false或者nil为不完整 -- @return nil -- @usage gps.writeCmd(cmd) function writeCmd(cmd,isFull) local tmp = cmd -- log.info("星历数据5",tmp:toHex()) if not isFull then tmp = 0 for i=2,cmd:len()-1 do tmp = bit.bxor(tmp,cmd:byte(i)) end tmp = cmd..(string.format("%02X",tmp)):upper().."\r\n" end -- sys.timerStart(function() uart.write(uartID,tmp) end, 100) uart.write(uartID,tmp) -- log.info("gps.writecmd",tmp) log.info("gps.writecmd:toHex",uartID, tmp:toHex()) end function writePendingCmds() if not aerialModeSetted and aerialModeStr~="" then writeCmd(aerialModeStr) aerialModeSetted=true end if not runModeSetted and runModeStr~="" then writeCmd(runModeStr) runModeSetted=true end if not nmeaReportSetted and nmeaReportStr~="" then writeCmd(nmeaReportStr) nmeaReportSetted=true end if not nmeaReportFreqSetted and nmeaReportFreqStr~="" then writeCmd(nmeaReportFreqStr) nmeaReportFreqSetted=true end end local function _open() if openFlag then return end--gps开启状态 pm.wake("gps.lua") uart.setup(uartID,uartBaudrate,uartDatabits,uartParity,uartStopbits) if not taskFlag then --串口线程 taskFlag =true sys.taskInit(taskRead) end if powerCbFnc then powerCbFnc(true) else pmd.ldoset(15, pmd.LDO_VMMC) rtos.sys32k_clk_out(1) end openFlag = true workAbnormalTimerId = sys.timerStart(sys.publish,8000,"GPS_WORK_ABNORMAL_IND") sys.publish("GPS_STATE","OPEN") fixFlag,filteredFlag = false Ggalng,Ggalat,Gsv,Sep = "","","" log.info("gps._open") end local function _close() if not openFlag then return end if powerCbFnc then powerCbFnc(false) else pmd.ldoset(0,pmd.LDO_VMMC) rtos.sys32k_clk_out(0) end uart.close(uartID) pm.sleep("gps.lua") openFlag = false sys.publish("GPS_STATE","CLOSE",fixFlag) stopWorkAbnormalTimer() fixFlag,filteredFlag = false sys.timerStop(filterTimerFnc) Ggalng,Ggalat,Gsv,Sep = "","","" aerialModeSetted,runModeSetted,nmeaReportSetted,nmeaReportFreqSetted = nil log.info("gps._close") end --- GPS应用模式1. -- -- 打开GPS后,GPS定位成功时,如果有回调函数,会调用回调函数 -- -- 使用此应用模式调用gps9701.open打开的“GPS应用”,必须主动调用gps9701.close或者gps9701.closeAll才能关闭此“GPS应用”,主动关闭时,即使有回调函数,也不会调用回调函数 DEFAULT = 1 --- GPS应用模式2. -- -- 打开GPS后,如果在GPS开启最大时长到达时,没有定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“GPS应用” -- -- 打开GPS后,如果在GPS开启最大时长内,定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“GPS应用” -- -- 打开GPS后,在自动关闭此“GPS应用”前,可以调用gps9701.close或者gps9701.closeAll主动关闭此“GPS应用”,主动关闭时,即使有回调函数,也不会调用回调函数 TIMERORSUC = 2 --- GPS应用模式3. -- -- 打开GPS后,在GPS开启最大时长时间到达时,无论是否定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“GPS应用” -- -- 打开GPS后,在自动关闭此“GPS应用”前,可以调用gps9701.close或者gps9701.closeAll主动关闭此“GPS应用”,主动关闭时,即使有回调函数,也不会调用回调函数 TIMER = 3 --“GPS应用”表 local tList = {} --[[ 函数名:delItem 功能 :从“GPS应用”表中删除一项“GPS应用”,并不是真正的删除,只是设置一个无效标志 参数 : mode:GPS应用模式 para: para.tag:“GPS应用”标记 para.val:GPS开启最大时长 para.cb:回调函数 返回值:无 ]] local function delItem(mode,para) for i=1,#tList do --标志有效 并且 GPS应用模式相同 并且 “GPS应用”标记相同 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 功能 :新增一项“GPS应用”到“GPS应用”表 参数 : mode:GPS应用模式 para: para.tag:“GPS应用”标记 para.val:GPS开启最大时长 para.cb:回调函数 返回值:无 ]] local function addItem(mode,para) --删除相同的“GPS应用” delItem(mode,para) local item,i,fnd = {flag=true, mode=mode, para=para} --如果是TIMERORSUC或者TIMER模式,初始化GPS工作剩余时间 if mode==TIMERORSUC or mode==TIMER then item.para.remain = para.val end for i=1,#tList do --如果存在无效的“GPS应用”项,直接使用此位置 if not tList[i].flag then tList[i] = item fnd = true break end end --新增一项 if not fnd then table.insert(tList,item) end end local function existTimerItem() for i=1,#tList do if tList[i].flag and (tList[i].mode==TIMERORSUC or tList[i].mode==TIMER or tList[i].para.delay) then return true end end end local function timerFnc() for i=1,#tList do if tList[i].flag then log.info("gps.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 isFix() and md==TIMER and rmn==0 and not tList[i].para.delay then tList[i].para.delay = 1 end dly = tList[i].para.delay if isFix() then if dly and dly==0 then if cb then cb(tList[i].para.tag) end if md == DEFAULT then tList[i].para.delay = nil else close(md,tList[i].para) end end else if rmn and rmn == 0 then if cb then cb(tList[i].para.tag) end close(md,tList[i].para) end end end end if existTimerItem() then sys.timerStart(timerFnc,1000) end end --[[ 函数名:statInd 功能 :处理GPS定位成功的消息 参数 : evt:GPS消息类型 返回值:无 ]] local function statInd(evt) --定位成功的消息 if evt == "LOCATION_SUCCESS" then for i=1,#tList do log.info("gps.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 ~= TIMER then tList[i].para.delay = 1 if tList[i].mode == DEFAULT then if existTimerItem() then sys.timerStart(timerFnc,1000) end end end end end end end --- 打开一个“GPS应用” -- “GPS应用”:指的是使用GPS功能的一个应用 -- 例如,假设有如下3种需求,要打开GPS,则一共有3个“GPS应用”: -- “GPS应用1”:每隔1分钟打开一次GPS -- “GPS应用2”:设备发生震动时打开GPS -- “GPS应用3”:收到一条特殊短信时打开GPS -- 只有所有“GPS应用”都关闭了,才会去真正关闭GPS -- 每个“GPS应用”打开或者关闭GPS时,最多有4个参数,其中 GPS应用模式和GPS应用标记 共同决定了一个唯一的“GPS应用”: -- 1、GPS应用模式(必选) -- 2、GPS应用标记(必选) -- 3、GPS开启最大时长[可选] -- 4、回调函数[可选] -- 例如gps9701.open(gps9701.TIMERORSUC,{tag="TEST",val=120,cb=testGpsCb}) -- gps9701.TIMERORSUC为GPS应用模式,"TEST"为GPS应用标记,120秒为GPS开启最大时长,testGpsCb为回调函数 -- @number mode GPS应用模式,支持gps9701.DEFAULT,gps9701.TIMERORSUC,gps9701.TIMER三种 -- @param para table类型,GPS应用参数 -- para.tag:string类型,GPS应用标记 -- para.val:number类型,GPS应用开启最大时长,mode参数为gps9701.TIMERORSUC或者gps9701.TIMER时,此值才有意义 -- para.cb:GPS应用结束时的回调函数,回调函数的调用形式为para.cb(para.tag) -- @return nil -- @usage gps9701.open(gps9701.DEFAULT,{tag="TEST1",cb=test1Cb}) -- @usage gps9701.open(gps9701.TIMERORSUC,{tag="TEST2",val=60,cb=test2Cb}) -- @usage gps9701.open(gps9701.TIMER,{tag="TEST3",val=120,cb=test3Cb}) -- @see DEFAULT,TIMERORSUC,TIMER function open(mode,para) assert((para and type(para) == "table" and para.tag and type(para.tag) == "string"),"gps.open para invalid") log.info("gps.open",mode,para.tag,para.val,para.cb) --如果GPS定位成功 if isFix() then if mode~=TIMER then --执行回调函数 if para.cb then para.cb(para.tag) end if mode==TIMERORSUC then return end end end addItem(mode,para)--gps应用 --真正去打开GPS _open() --启动1秒的定时器 if existTimerItem() and not sys.timerIsActive(timerFnc) then sys.timerStart(timerFnc,1000) end end --- 关闭一个“GPS应用” -- 只是从逻辑上关闭一个GPS应用,并不一定真正关闭GPS,是有所有的GPS应用都处于关闭状态,才会去真正关闭GPS -- @number mode GPS应用模式,支持gps9701.DEFAULT,gps9701.TIMERORSUC,gps9701.TIMER三种 -- @param para table类型,GPS应用参数 -- para.tag:string类型,GPS应用标记 -- para.val:number类型,GPS应用开启最大时长,mode参数为gps9701.TIMERORSUC或者gps9701.TIMER时,此值才有意义;使用close接口时,不需要传入此参数 -- para.cb:GPS应用结束时的回调函数,回调函数的调用形式为para.cb(para.tag);使用close接口时,不需要传入此参数 -- @return nil -- @usage GPS应用模式和GPS应用标记唯一确定一个“GPS应用”,调用本接口关闭时,mode和para.tag要和gps9701.open打开一个“GPS应用”时传入的mode和para.tag保持一致 -- @usage gps9701.close(gps9701.DEFAULT,{tag="TEST1"}) -- @usage gps9701.close(gps9701.TIMERORSUC,{tag="TEST2"}) -- @usage gps9701.close(gps9701.TIMER,{tag="TEST3"}) -- @see open,DEFAULT,TIMERORSUC,TIMER function close(mode,para) assert((para and type(para)=="table" and para.tag and type(para.tag)=="string"),"gps.close para invalid") log.info("gps.close",mode,para.tag,para.val,para.cb) --删除此“GPS应用” delItem(mode,para) local valid,i for i=1,#tList do if tList[i].flag then valid = true end end --如果没有一个“GPS应用”有效,则关闭GPS if not valid then _close() end end --- 关闭所有“GPS应用” -- @return nil -- @usage gps9701.closeAll() -- @see open,DEFAULT,TIMERORSUC,TIMER function 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 close(tList[i].mode,tList[i].para) end end --- 判断一个“GPS应用”是否处于激活状态 -- @number mode GPS应用模式,支持gps9701.DEFAULT,gps9701.TIMERORSUC,gps9701.TIMER三种 -- @param para table类型,GPS应用参数 -- para.tag:string类型,GPS应用标记 -- para.val:number类型,GPS应用开启最大时长,mode参数为gps9701.TIMERORSUC或者gps9701.TIMER时,此值才有意义;使用isActive接口时,不需要传入此参数 -- para.cb:GPS应用结束时的回调函数,回调函数的调用形式为para.cb(para.tag);使用isActive接口时,不需要传入此参数 -- @return bool result,处于激活状态返回true,否则返回nil -- @usage GPS应用模式和GPS应用标记唯一确定一个“GPS应用”,调用本接口查询状态时,mode和para.tag要和gps9701.open打开一个“GPS应用”时传入的mode和para.tag保持一致 -- @usage gps9701.isActive(gps9701.DEFAULT,{tag="TEST1"}) -- @usage gps9701.isActive(gps9701.TIMERORSUC,{tag="TEST2"}) -- @usage gps9701.isActive(gps9701.TIMER,{tag="TEST3"}) -- @see open,DEFAULT,TIMERORSUC,TIMER function isActive(mode,para) assert((para and type(para)=="table" and para.tag and type(para.tag)=="string"),"gps.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 --- 设置GPS模块供电控制的回调函数 -- 如果使用的是Air800,或者供电控制使用的是LDO_VCAM,则打开GPS应用前不需要调用此接口进行设置 -- 否则在调用gps9701.open前,使用此接口,传入自定义的供电控制函数cbFnc,GPS开启时,gps9701.lua自动执行cbFnc(true),GPS关闭时,gps9701.lua自动执行cbFnc(false) -- @param cbFnc function类型,用户自定义的GPS供电控制函数 -- @return nil -- @usage gps9701.setPowerCbFnc(cbFnc) function setPowerCbFnc(cbFnc) powerCbFnc = cbFnc end --- 设置GPS模块和GSM模块之间数据通信的串口参数 -- 如果使用的是Air800,或者使用的UART2(波特率115200,数据位8,无检验位,停止位1),则打开GPS应用前不需要调用此接口进行设置 -- 否则在调用gps9701.open前,使用此接口,传入UART参数 -- @number id UART ID,支持1和2,1表示UART1,2表示UART2 -- @number baudrate 波特率,支持1200,2400,4800,9600,10400,14400,19200,28800,38400,57600,76800,115200,230400,460800,576000,921600,1152000,4000000 -- @number databits 数据位,支持8 -- @number parity 校验位,支持uart.PAR_NONE,uart.PAR_EVEN,uart.PAR_ODD -- @number stopbits 停止位,支持uart.STOP_1,uart.STOP_2 -- @return nil -- @usage gps9701.setUart(2,115200,8,uart.PAR_NONE,uart.STOP_1) function setUart(id,baudrate,databits,parity,stopbits) uartID,uartBaudrate,uartDatabits,uartParity,uartStopbits = id,baudrate,databits,parity,stopbits end --- 设置GPS模块搜星模式. -- 如果使用的是Air800或者Air530,不调用此接口配置,则默认同时开启GPS和北斗定位 -- @number gps GPS定位系统,1是打开,0是关闭 -- @number beidou 中国北斗定位系统,1是打开,0是关闭 -- @number glonass 俄罗斯Glonass定位系统,1是打开,0是关闭 -- @number galieo 欧盟伽利略定位系统,1是打开,0是关闭 -- @return nil -- @usage gps9701.setAeriaMode(1,1,0,0) function setAerialMode(gps,beidou,glonass,galieo) local gps = gps or 0 local glonass = glonass or 0 local beidou = beidou or 0 local galieo = galieo or 0 if gps+glonass+beidou+galieo == 0 then gps=1 beidou=1 end if gps==1 then gps=1 end if glonass==1 then glonass=4 end if beidou==1 then beidou= 8 end if galieo==1 then galieo= 2 end local searchstar=gps+glonass+beidou+galieo searchstar = string.format("%X",searchstar) log.info("搜星",searchstar) --local tmpStr = "$PGKC115,"..gps..","..glonass..","..beidou..","..galieo.."*" local tmpStr = "$PGKC121,0,"..searchstar..",0*" if tmpStr~=aerialModeStr then aerialModeStr,aerialModeSetted = tmpStr end end --- 设置NMEA数据处理模式. -- 如果不调用此接口配置,则默认仅gps.lua内部处理NMEA数据 -- @number mode NMEA数据处理模式,0表示仅gps.lua内部处理,1表示仅用户自己处理,2表示gps.lua和用户同时处理 -- @param cbFnc function类型,用户处理一条NMEA数据的回调函数,mode为1和2时,此值才有意义 -- @return nil -- @usage gps9701.setNmeaMode(0) -- @usage gps9701.setNmeaMode(1,cbFnc) -- @usage gps9701.setNmeaMode(2,cbFnc) function setNmeaMode(mode,cbFnc) nmeaMode,nmeaCbFnc = mode,cbFnc end --- 设置GPS模块的运行模式. -- 如果不调用此接口配置,则默认为正常运行模式 -- @number mode 运行模式 -- 0:正常运行模式 -- 1:周期超低功耗跟踪模式 -- 4:直接进入超低功耗跟踪模式 -- 8:低功耗模式,可以通过串口发送命令唤醒 -- @number runTm 单位毫秒,mode为0时表示NEMA数据的上报间隔,mode为1时表示运行时长,其余mode时此值无意义 -- @number sleepTm 单位毫秒,mode为1时表示运行时长,其余mode时此值无意义 -- @return nil -- @usage gps9701.setRunMode(0,1000) -- @usage gps9701.setRunMode(1,5000,2000) function setRunMode(mode,runTm,sleepTm) local rt,st = runTm or "",sleepTm or "" if mode==0 and rt then if rt>10000 then rt=10000 end if rt<100 then rt=100 end nmeaReportStr = "$PGKC101,"..rt.."*" end local tmpStr = "$PGKC105,"..mode..((mode==1) and (","..rt..","..st) or "").."*" if tmpStr~=runModeStr then runModeStr,runModeSetted = tmpStr end end --- 设置NEMA语句的输出频率. -- @number[opt=1] rmc 单位秒,RMC语句输出频率,取值范围0到10之间的整数,0表示不输出 -- @number[opt=1] gga 单位秒,GGA语句输出频率,取值范围0到10之间的整数,0表示不输出 -- @number[opt=1] gsa 单位秒,GSA语句输出频率,取值范围0到10之间的整数,0表示不输出 -- @number[opt=1] gsv 单位秒,GSV语句输出频率,取值范围0到10之间的整数,0表示不输出 -- @number[opt=1] vtg 单位秒,VTG语句输出频率,取值范围0到10之间的整数,0表示不输出 -- @number[opt=0] gll 单位秒,GLL语句输出频率,取值范围0到10之间的整数,0表示不输出 -- @return nil -- @usage gps9701.setNemaReportFreq(5,0,0,0,0,0) function setNemaReportFreq(rmc,gga,gsa,gsv,vtg,gll) local tmpStr = "$PGKC242,"..(gll or 0)..","..(rmc or 1)..","..(vtg or 1)..","..(gga or 1)..","..(gsa or 1)..","..(gsv or 1)..",0,0,0,0,0,0,0,0,0,0,0,0,0".."*" if tmpStr~=nmeaReportFreqStr then nmeaReportFreqStr,nmeaReportFreqSetted = tmpStr end end --- 设置GPS定位成功后经纬度的过滤时间. -- @number[opt=0] seconds 单位秒,GPS定位成功后,丢弃前seconds秒的位置信息 -- @return nil -- @usage gps9701.setLocationFilter(2) function setLocationFilter(seconds) filterSeconds = seconds or 0 end function setFastFix(lat,lng,tm) local t = tm.year..","..tm.month..","..tm.day..","..tm.hour..","..tm.min..","..tm.sec.."*" log.info("gps.setFastFix",lat,lng,t) -- writeCmd("$PGKC634,"..t) writeCmd("$PGKC639,"..lat..","..lng..",0,"..t) end --- 获取GPS模块是否处于开启状态 -- @return bool result,true表示开启状态,false或者nil表示关闭状态 -- @usage gps9701.isOpen() function isOpen() return openFlag end --- 获取GPS模块是否定位成功 -- @return bool result,true表示定位成功,false或者nil表示定位失败 -- @usage gps9701.isFix() function isFix() return fixFlag end --- 获取GPS模块是否首次定位成功过 -- @return bool result,true表示曾经定位成功 -- @usage gps9701.isOnece() function isOnece() return fixOnece end -- 度分格式转换为度格式 -- @string inStr 度分格式的位置 -- @return string,度格式的位置 -- @usage degreeMinuteToDegree("3114.50931")--->"31.2418218",31度14.50931分转换为31.2418218度 -- @usage degreeMinuteToDegree("12128.44954")--->"121.4741590",121度28.44954分转换为121.4741590度 local function degreeMinuteToDegree(inStr) local integer,fraction = smatch(inStr,"(%d+)%.(%d+)") if integer and fraction then local intLen = slen(integer) if intLen~=4 and intLen~=5 then log.error("gps.degreeMinuteToDegree integer error",inStr) return "" end if slen(fraction)<5 then fraction = fraction..srep("0",5-slen(fraction)) end fraction = ssub(fraction,1,5) local temp = tonumber(ssub(integer,intLen-1,intLen)..fraction)*10 fraction = tostring((temp-(temp%6))/6) local fracLen = slen(fraction) if fracLen>7 then fraction = ssub(fraction,1,7) elseif fracLen<7 then fraction = srep("0",7-fracLen)..fraction end return ssub(integer,1,intLen-2).."."..fraction end return "" end --- 获取度格式的经纬度信息 -- @string[opt=nil] typ 返回的经纬度格式,typ为"DEGREE_MINUTE"时表示返回度分格式,其余表示返回度格式 -- @return table location -- 例如typ为"DEGREE_MINUTE"时返回{lngType="E",lng="12128.44954",latType="N",lat="3114.50931"} -- 例如typ不是"DEGREE_MINUTE"时返回{lngType="E",lng="121.123456",latType="N",lat="31.123456"} -- lngType:string类型,表示经度类型,取值"E","W" -- lng:string类型,表示度格式的经度值,无效时为"" -- latType:string类型,表示纬度类型,取值"N","S" -- lat:string类型,表示度格式的纬度值,无效时为"" -- @usage gps9701.getLocation() function getLocation(typ) return { lngType=longitudeType, lng=isFix() and (typ=="DEGREE_MINUTE" and longitude or degreeMinuteToDegree(longitude)) or "", latType=latitudeType, lat=isFix() and (typ=="DEGREE_MINUTE" and latitude or degreeMinuteToDegree(latitude)) or "" } end function getLastLocation(typ) if typ=="DEGREE_MINUTE" then return { lngType=longitudeType, lng=longitude, latType=latitudeType, lat=latitude } else return (longitude and longitude~="") and degreeMinuteToDegree(longitude) or "", (latitude and latitude~="") and degreeMinuteToDegree(latitude) or "" end end --- 获取海拔 -- @return number altitude,海拔,单位米 -- @usage gps9701.getAltitude() function getAltitude() return tonumber(smatch(altitude,"(%d+)") or "0") end --- 获取速度 -- @return number kmSpeed,第一个返回值为公里每小时的速度 -- @return number nmSpeed,第二个返回值为海里每小时的速度 -- @usage gps9701.getSpeed() function getSpeed() local integer = tonumber(smatch(speed,"(%d+)") or "0") return (integer*1852 - (integer*1852 %1000))/1000,integer end --- 获取原始速度,字符串带浮点 -- @return number speed 海里每小时的速度 -- @usage gps9701.getOrgSpeed() function getOrgSpeed() return speed end --- 获取方向角 -- @return number course,方向角 -- @usage gps9701.getCourse() function getCourse() return tonumber(smatch(course,"(%d+)") or "0") end -- 获取所有可见卫星的最大信号强度 -- @return number strength,最大信号强度 -- @usage gps9701.getMaxSignalStrength() function getMaxSignalStrength() return maxSignalStrength end --- 获取可见卫星的个数 -- @return number count,可见卫星的个数 -- @usage gps9701.getViewedSateCnt() function getViewedSateCnt() return tonumber(viewedGpsSateCnt)+tonumber(viewedBdSateCnt) end --- 获取定位使用的卫星个数 -- @return number count,定位使用的卫星个数 -- @usage gps9701.getUsedSateCnt() function getUsedSateCnt() return tonumber(usedSateCnt) end --- 获取GGA语句中度分格式的经纬度信息 -- @return string lng,度分格式的经度值(dddmm.mmmm),西经会添加一个-前缀,无效时为"";例如"12112.3456"表示东经121度12.3456分,"-12112.3456"表示西经121度12.3456分 -- @return string lat,度分格式的纬度值(ddmm.mmmm),南纬会添加一个-前缀,无效时为"";例如"3112.3456"表示北纬31度12.3456分,"-3112.3456"表示南纬31度12.3456分 -- @usage gps9701.getGgaloc() function getGgaloc() return Ggalng or "",Ggalat or "" end --- 获取RMC语句中的UTC时间 -- 只有同时满足如下两个条件,返回值才有效 -- 1、开启了GPS,并且定位成功 -- 2、调用setParseItem接口,第一个参数设置为true -- @return table utcTime,UTC时间,nil表示无效,例如{year=2018,month=4,day=24,hour=11,min=52,sec=10} -- @usage gps9701.getUtcTime() function getUtcTime() return UtcTime end --- 获取定位使用的大地高 -- @return number sep,大地高 -- @usage gps9701.getSep() function getSep() return tonumber(Sep or "0") end --- 获取GSA语句中的可见卫星号 -- 只有同时满足如下两个条件,返回值才有效 -- 1、开启了GPS,并且定位成功 -- 2、调用setParseItem接口,第三个参数设置为true -- @return string viewedSateId,可用卫星号,""表示无效 -- @usage gps9701.getSateSn() function getSateSn() return SateSn or "" end --- 获取GSV语句中的可见卫星的信噪比 -- 只有同时满足如下两个条件,返回值才有效 -- 1、开启了GPS,并且定位成功 -- 2、调用setParseItem接口,第二个参数设置为true -- @return string gsv,信噪比 -- @usage gps9701.getGsv() function getGsv() return Gsv or "" end --- 设置是否需要解析的字段 -- @bool[opt=nil] utcTime 是否解析RMC语句中的UTC时间,true表示解析,false或者nil不解析 -- @bool[opt=nil] gsv 是否解析GSV语句,true表示解析,false或者nil不解析 -- @bool[opt=nil] gsaId 是否解析GSA语句中的卫星ID,true表示解析,false或者nil不解析 -- @usage gps.setParseItem(true,true,true) function setParseItem(utcTime,gsv,gsaId) psUtcTime,psGsv,psSn = utcTime,gsv,gsaId end function init() sys.subscribe("GPS_STATE",statInd) end function unInit() sys.unsubscribe("GPS_STATE",statInd) closeAll() end init()