gpsHxxt.lua 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. --- 模块功能:GPS模块管理
  2. -- 注意:此功能模块中的功能接口可以分为四大类:
  3. -- 1、GPS开启
  4. -- 2、GPS关闭
  5. -- 3、GPS定位数据读取
  6. -- 4、GPS参数和功能设置
  7. -- 1、2、3是通用功能,除了支持合宙的Air530H模块,理论上也支持其他厂家的串口GPS模块
  8. -- 4是专用功能,仅支持合宙的Air530H和Air82x系列模块
  9. -- @module gpsHxxt
  10. -- @author openLuat
  11. -- @license MIT
  12. -- @copyright openLuat
  13. -- @release 2021.6.19
  14. require"pm"
  15. require"utils"
  16. module(..., package.seeall)
  17. local smatch,sfind,slen,ssub,sbyte,sformat,srep = string.match,string.find,string.len,string.sub,string.byte,string.format,string.rep
  18. --GPS开启标志,true表示开启状态,false或者nil表示关闭状态
  19. local openFlag
  20. --GPS定位标志,"2D"表示2D定位,"3D"表示3D定位,其余表示未定位
  21. --GPS定位标志,true表示,其余表示未定位
  22. local fixFlag,fixOnece=nil,nil
  23. --GPS定位成功后,过滤掉前filterSeconds秒的经纬度信息
  24. --是否已经过滤完成
  25. local filterSeconds,filteredFlag = 0
  26. --从定位成功切换到定位失败,连续定位失败的次数
  27. local fixFailCnt = 0
  28. --经纬度类型和数据
  29. local latitudeType,latitude,longitudeType,longitude = "N","","E",""
  30. --海拔,速度,方向角
  31. local altitude,speed,course = "0","0","0"
  32. --参与定位的卫星个数,所有可见卫星的最大信号值,所有可见卫星的最大信号值中间缓存值
  33. local usedSateCnt,maxSignalStrength,maxSignalStrengthVar = "0",0,0
  34. --可见卫星个数
  35. local viewedGpsSateCnt,viewedBdSateCnt = "0","0"
  36. --可用卫星号,UTC时间,信噪比
  37. local SateSn,UtcTime,Gsv
  38. --大地高,度分经度,度分纬度
  39. local Sep,Ggalng,Ggalat
  40. --是否需要解析项
  41. local psUtcTime,psGsv,psSn
  42. --GPS供电设置函数
  43. local powerCbFnc
  44. --串口配置
  45. uartBaudrate = 115200
  46. local uartID,uartDatabits,uartParity,uartStopbits = 3,8,uart.PAR_NONE,uart.STOP_1
  47. --搜星模式命令字符串,"$PGKC115," .. gps .. "," .. glonass .. "," .. beidou .. "," .. galieo .. "*"
  48. local aerialModeStr,aerialModeSetted = ""
  49. --启动模式命令字符串
  50. local startModeStr,startModeSetted = "",""
  51. --运行模式命令字符串,"$PGKC105," .. mode .. "," .. rt .. "," .. st .. "*"
  52. local runModeStr,runModeSetted = "",""
  53. --正常运行模式下NMEA数据上报间隔命令字符串,"$PGKC101," .. interval .. "*"
  54. local nmeaReportStr,nmeaReportSetted = ""
  55. --每种NEMA数据的输出频率命令字符串
  56. local nmeaReportFreqStr,nmeaReportFreqSetted = ""
  57. --NMEA数据处理模式,0表示仅gpsHxxt.lua内部处理,1表示仅用户自己处理,2表示gpsHxxt.lua和用户同时处理
  58. --用户处理一条NMEA数据的回调函数
  59. local nmeaMode,nmeaCbFnc = 0
  60. --NMEA数据输出间隔
  61. local nmeaInterval = 1000
  62. --运行模式
  63. --0,正常运行模式
  64. --1,低功耗模式
  65. local runMode = 0
  66. --gps 的串口线程是否在工作;
  67. local taskFlag=false
  68. --runMode为1或者2时,GPS运行状态和休眠状态的时长
  69. local runTime,sleepTime
  70. --检测gps是否工作正常的定时器ID
  71. local workAbnormalTimerId
  72. --[[
  73. 函数名:getstrength
  74. 功能 :解析GSV数据
  75. 参数 :
  76. sg:NEMA中的一行GSV数据
  77. 返回值:无
  78. ]]
  79. local function getstrength(sg)
  80. sg = ssub(sg, 4, #sg)
  81. local d1,d2,curnum,lineno,total,sgv_str = sfind(sg,"GSV,(%d),(%d),(%d+),(.*)%*.*")
  82. if not curnum or not lineno or not total or not sgv_str then
  83. return
  84. end
  85. if lineno == nil then
  86. maxSignalStrengthVar = 0
  87. maxSignalStrength = 0
  88. elseif tonumber(lineno) == 1 then
  89. maxSignalStrength = maxSignalStrengthVar
  90. maxSignalStrengthVar = 0
  91. end
  92. local tmpstr,i = sgv_str
  93. for i=1,4 do
  94. local d1,d2,id,elevation,azimuth,strength = sfind(tmpstr,"(%d+),([%-]*%d*),(%d*),(%d*)")
  95. if id == nil then return end
  96. if strength == "" or not strength then
  97. strength = "00"
  98. end
  99. strength = tonumber(strength)
  100. if strength > maxSignalStrengthVar then
  101. maxSignalStrengthVar = strength
  102. end
  103. local idx,cur,fnd,tmpid = 0,id..","..elevation..","..azimuth..","..strength..",",false
  104. for tmpid in string.gmatch(Gsv,"(%d+),%d*,%d*,%d*,") do
  105. idx = idx + 1
  106. if tmpid == id then fnd = true break end
  107. end
  108. if fnd then
  109. local pattern,i = ""
  110. for i=1,idx do
  111. pattern = pattern.."%d+,%d*,%d*,%d*,"
  112. end
  113. local m1,m2 = sfind(Gsv,"^"..pattern)
  114. if m1 and m2 then
  115. local front = ssub(Gsv,1,m2)
  116. local n1,n2 = sfind(front,"%d+,%d*,%d*,%d*,$")
  117. if n1 and n2 then
  118. Gsv = ssub(Gsv,1,n1-1)..cur..ssub(Gsv,n2+1,-1)
  119. end
  120. end
  121. else
  122. Gsv = Gsv..cur
  123. end
  124. tmpstr = ssub(tmpstr,d2+1,-1)
  125. end
  126. end
  127. local function filterTimerFnc()
  128. log.info("gpsHxxt.filterTimerFnc end")
  129. filteredFlag = true
  130. end
  131. local function stopWorkAbnormalTimer()
  132. if workAbnormalTimerId then
  133. sys.timerStop(workAbnormalTimerId)
  134. workAbnormalTimerId = nil
  135. end
  136. end
  137. local function parseNmea(s)
  138. if not s or s=="" then return end
  139. local lat,lng,spd,cog,gpsFind,gpsTime,gpsDate,locSateCnt,hdp,latTyp,lngTyp,altd
  140. local fixed,workAbnormal
  141. if smatch(s,"GGA") then
  142. 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")
  143. if (gpsFind=="1" or gpsFind=="2" or gpsFind=="4") and altd then
  144. --fixed = true
  145. altitude = altd
  146. latitudeType,longitudeType,latitude,longitude = latTyp,lngTyp,lat,lng
  147. usedSateCnt = locSateCnt
  148. Ggalng,Ggalat = (lngTyp=="W" and "-" or "")..lng,(latTyp=="S" and "-" or "")..lat
  149. Sep = sep
  150. else
  151. fixed = false
  152. end
  153. elseif smatch(s,"RMC") then
  154. 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),")
  155. if gpsFind=="A" and cog then
  156. fixed = true
  157. latitudeType,longitudeType,latitude,longitude = latTyp,lngTyp,lat,lng
  158. speed = spd
  159. course = cog
  160. else
  161. fixed = false
  162. end
  163. if psUtcTime and gpsFind == "A" and gpsTime and gpsDate and gpsTime ~= "" and gpsDate ~= "" then
  164. 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))
  165. UtcTime = {year=2000+yy,month=mm,day=dd,hour=h,min=m,sec=s}
  166. end
  167. elseif smatch(s,"GPGSV") then
  168. viewedGpsSateCnt = tonumber(smatch(s,"%d+,%d+,(%d+)") or "0")
  169. if psGsv then getstrength(s) end
  170. elseif smatch(s,"BDGSV") then
  171. viewedBdSateCnt = tonumber(smatch(s,"%d+,%d+,(%d+)") or "0")
  172. if psGsv then getstrength(s) end
  173. elseif smatch(s,"GSA") then
  174. if psSn then
  175. local satesn = smatch(s,"GSA,%w*,%d*,(%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,%d*,)") or ""
  176. if slen(satesn) > 0 and smatch(satesn,"%d+,") then
  177. SateSn = satesn
  178. end
  179. end
  180. else
  181. workAbnormal = true
  182. end
  183. if not workAbnormal then
  184. stopWorkAbnormalTimer()
  185. end
  186. if filterSeconds>0 and fixed and not fixFlag and not filteredFlag then
  187. if not sys.timerIsActive(filterTimerFnc) then
  188. log.info("gpsHxxt.filterTimerFnc begin")
  189. sys.publish("GPS_STATE","LOCATION_FILTER")
  190. sys.timerStart(filterTimerFnc,filterSeconds*1000)
  191. end
  192. return
  193. end
  194. --定位成功
  195. if fixed then
  196. if not fixFlag then
  197. fixFlag,filteredFlag = true,true
  198. fixOnece=true
  199. fixFailCnt = 0
  200. sys.publish("GPS_STATE","LOCATION_SUCCESS")
  201. end
  202. elseif fixed==false then
  203. if fixFlag then
  204. fixFailCnt = fixFailCnt+1
  205. if fixFailCnt>=20 then
  206. fixFlag,filteredFlag = false
  207. sys.timerStop(filterTimerFnc)
  208. sys.publish("GPS_STATE","LOCATION_FAIL")
  209. end
  210. end
  211. end
  212. end
  213. local function taskRead()
  214. local cacheData = ""
  215. local co = coroutine.running()
  216. while true do
  217. local s =""
  218. if openFlag then
  219. s= uart.read(uartID, "*l")
  220. end
  221. if s == "" then
  222. uart.on(uartID,"receive",function() coroutine.resume(co) end)
  223. coroutine.yield()
  224. uart.on(uartID,"receive")
  225. else
  226. cacheData = cacheData..s
  227. local d1,d2,nemaStr = sfind(cacheData,"\r\n")
  228. while d1 do
  229. writePendingCmds()
  230. nemaStr = ssub(cacheData,1,d2)
  231. cacheData = ssub(cacheData,d2+1,-1)
  232. if nmeaMode==0 or nmeaMode==2 then
  233. --解析一行NEMA数据
  234. parseNmea(nemaStr)
  235. end
  236. if (nmeaMode==1 or nmeaMode==2) and nmeaCbFnc then
  237. nmeaCbFnc(nemaStr)
  238. end
  239. d1,d2 = sfind(cacheData,"\r\n")
  240. end
  241. end
  242. end
  243. end
  244. function writeData(data)
  245. uart.write(uartID,data)
  246. log.info("gpsHxxt.writeData",data:toHex())
  247. end
  248. -- GPS串口写命令操作
  249. -- @number class,消息类
  250. -- @number is,消息编号
  251. -- @string payload,有效载荷
  252. -- @return nil
  253. -- @usage gpsHxxt.writeCmd(cmd)
  254. function writeCasic(class,id,payload)
  255. local tmp = pack.pack("<bbHbbA",0xBA,0xCE,payload:len(),class,id,payload)
  256. local checkSum = bit.lshift(id,24)+bit.lshift(class,16)+payload:len()
  257. for i=1,payload:len(),4 do
  258. checkSum = checkSum + payload:byte(i) + bit.lshift(payload:byte(i+1),8) + bit.lshift(payload:byte(i+2),16) + bit.lshift(payload:byte(i+3),24)
  259. end
  260. tmp = tmp..pack.pack("<I",checkSum)
  261. uart.write(uartID,tmp)
  262. --log.info("gpsZkw.writeCasic",tmp)
  263. log.info("gpsHxxt.writeCasic",tmp:toHex())
  264. end
  265. -- GPS串口写命令操作
  266. -- @string cmd,GPS指令(cmd格式:"$PGKC149,1,115200*"或者"$PGKC149,1,115200*XX\r\n")
  267. -- @bool isFull,cmd是否为完整的指令格式,包括校验和以及\r\n;true表示完整,false或者nil为不完整
  268. -- @return nil
  269. -- @usage gpsHxxt.writeCmd(cmd)
  270. function writeCmd(cmd,isFull)
  271. local tmp = cmd
  272. if not isFull then
  273. tmp = 0
  274. for i=2,cmd:len()-1 do
  275. tmp = bit.bxor(tmp,cmd:byte(i))
  276. end
  277. --tmp = cmd..(string.format("%02X",tmp)):upper().."\r\n"
  278. tmp = cmd.."\r\n"
  279. end
  280. uart.write(uartID,tmp)
  281. log.info("gpsHxxt.writecmd",tmp)
  282. --log.info("gpsHxxt.writecmd:toHex",tmp:toHex())
  283. end
  284. function writePendingCmds()
  285. if not aerialModeSetted and aerialModeStr~="" then writeCmd(aerialModeStr) aerialModeSetted=true end
  286. --if not runModeSetted and runModeStr~="" then writeCmd(runModeStr) runModeSetted=true end
  287. if not nmeaReportSetted and nmeaReportStr~="" then writeCmd(nmeaReportStr) nmeaReportSetted=true end
  288. if not nmeaReportFreqSetted and nmeaReportFreqStr~="" then writeCmd(nmeaReportFreqStr) nmeaReportFreqSetted=true end
  289. end
  290. local function _open()
  291. if openFlag then return end
  292. pm.wake("gpsHxxt.lua")
  293. uart.setup(uartID,uartBaudrate,uartDatabits,uartParity,uartStopbits)
  294. if not taskFlag then
  295. taskFlag =true
  296. sys.taskInit(taskRead)
  297. end
  298. if powerCbFnc then
  299. powerCbFnc(true)
  300. else
  301. pmd.ldoset(15,pmd.LDO_VIBR)
  302. rtos.sys32k_clk_out(1)
  303. end
  304. openFlag = true
  305. workAbnormalTimerId = sys.timerStart(sys.publish,8000,"GPS_WORK_ABNORMAL_IND")
  306. sys.publish("GPS_STATE","OPEN")
  307. fixFlag,filteredFlag = false
  308. Ggalng,Ggalat,Gsv,Sep = "","",""
  309. log.info("gpsHxxt._open")
  310. end
  311. local function _close()
  312. if not openFlag then return end
  313. if powerCbFnc then
  314. powerCbFnc(false)
  315. else
  316. pmd.ldoset(0,pmd.LDO_VIBR)
  317. --rtos.sys32k_clk_out(0)
  318. end
  319. uart.close(uartID)
  320. pm.sleep("gpsHxxt.lua")
  321. openFlag = false
  322. sys.publish("GPS_STATE","CLOSE",fixFlag)
  323. stopWorkAbnormalTimer()
  324. fixFlag,filteredFlag = false
  325. sys.timerStop(filterTimerFnc)
  326. Ggalng,Ggalat,Gsv,Sep = "","",""
  327. aerialModeSetted,runModeSetted,nmeaReportSetted,nmeaReportFreqSetted = nil
  328. log.info("gpsHxxt._close")
  329. end
  330. --- GPS应用模式1.
  331. --
  332. -- 打开GPS后,GPS定位成功时,如果有回调函数,会调用回调函数
  333. --
  334. -- 使用此应用模式调用gpsHxxt.open打开的“GPS应用”,必须主动调用gpsHxxt.close或者gpsHxxt.closeAll才能关闭此“GPS应用”,主动关闭时,即使有回调函数,也不会调用回调函数
  335. DEFAULT = 1
  336. --- GPS应用模式2.
  337. --
  338. -- 打开GPS后,如果在GPS开启最大时长到达时,没有定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“GPS应用”
  339. --
  340. -- 打开GPS后,如果在GPS开启最大时长内,定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“GPS应用”
  341. --
  342. -- 打开GPS后,在自动关闭此“GPS应用”前,可以调用gpsHxxt.close或者gpsHxxt.closeAll主动关闭此“GPS应用”,主动关闭时,即使有回调函数,也不会调用回调函数
  343. TIMERORSUC = 2
  344. --- GPS应用模式3.
  345. --
  346. -- 打开GPS后,在GPS开启最大时长时间到达时,无论是否定位成功,如果有回调函数,会调用回调函数,然后自动关闭此“GPS应用”
  347. --
  348. -- 打开GPS后,在自动关闭此“GPS应用”前,可以调用gpsHxxt.close或者gpsHxxt.closeAll主动关闭此“GPS应用”,主动关闭时,即使有回调函数,也不会调用回调函数
  349. TIMER = 3
  350. --“GPS应用”表
  351. local tList = {}
  352. --[[
  353. 函数名:delItem
  354. 功能 :从“GPS应用”表中删除一项“GPS应用”,并不是真正的删除,只是设置一个无效标志
  355. 参数 :
  356. mode:GPS应用模式
  357. para:
  358. para.tag:“GPS应用”标记
  359. para.val:GPS开启最大时长
  360. para.cb:回调函数
  361. 返回值:无
  362. ]]
  363. local function delItem(mode,para)
  364. for i=1,#tList do
  365. --标志有效 并且 GPS应用模式相同 并且 “GPS应用”标记相同
  366. if tList[i].flag and tList[i].mode==mode and tList[i].para.tag==para.tag then
  367. --设置无效标志
  368. tList[i].flag,tList[i].delay = false
  369. break
  370. end
  371. end
  372. end
  373. --[[
  374. 函数名:addItem
  375. 功能 :新增一项“GPS应用”到“GPS应用”表
  376. 参数 :
  377. mode:GPS应用模式
  378. para:
  379. para.tag:“GPS应用”标记
  380. para.val:GPS开启最大时长
  381. para.cb:回调函数
  382. 返回值:无
  383. ]]
  384. local function addItem(mode,para)
  385. --删除相同的“GPS应用”
  386. delItem(mode,para)
  387. local item,i,fnd = {flag=true, mode=mode, para=para}
  388. --如果是TIMERORSUC或者TIMER模式,初始化GPS工作剩余时间
  389. if mode==TIMERORSUC or mode==TIMER then item.para.remain = para.val end
  390. for i=1,#tList do
  391. --如果存在无效的“GPS应用”项,直接使用此位置
  392. if not tList[i].flag then
  393. tList[i] = item
  394. fnd = true
  395. break
  396. end
  397. end
  398. --新增一项
  399. if not fnd then table.insert(tList,item) end
  400. end
  401. local function existTimerItem()
  402. for i=1,#tList do
  403. if tList[i].flag and (tList[i].mode==TIMERORSUC or tList[i].mode==TIMER or tList[i].para.delay) then return true end
  404. end
  405. end
  406. local function timerFnc()
  407. for i=1,#tList do
  408. if tList[i].flag then
  409. log.info("gpsHxxt.timerFnc@"..i,tList[i].mode,tList[i].para.tag,tList[i].para.val,tList[i].para.remain,tList[i].para.delay)
  410. local rmn,dly,md,cb = tList[i].para.remain,tList[i].para.delay,tList[i].mode,tList[i].para.cb
  411. if rmn and rmn>0 then
  412. tList[i].para.remain = rmn-1
  413. end
  414. if dly and dly>0 then
  415. tList[i].para.delay = dly-1
  416. end
  417. rmn = tList[i].para.remain
  418. if isFix() and md==TIMER and rmn==0 and not tList[i].para.delay then
  419. tList[i].para.delay = 1
  420. end
  421. dly = tList[i].para.delay
  422. if isFix() then
  423. if dly and dly==0 then
  424. if cb then cb(tList[i].para.tag) end
  425. if md == DEFAULT then
  426. tList[i].para.delay = nil
  427. else
  428. close(md,tList[i].para)
  429. end
  430. end
  431. else
  432. if rmn and rmn == 0 then
  433. if cb then cb(tList[i].para.tag) end
  434. close(md,tList[i].para)
  435. end
  436. end
  437. end
  438. end
  439. if existTimerItem() then sys.timerStart(timerFnc,1000) end
  440. end
  441. --[[
  442. 函数名:statInd
  443. 功能 :处理GPS定位成功的消息
  444. 参数 :
  445. evt:GPS消息类型
  446. 返回值:无
  447. ]]
  448. local function statInd(evt)
  449. --定位成功的消息
  450. if evt == "LOCATION_SUCCESS" then
  451. for i=1,#tList do
  452. log.info("gpsHxxt.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)
  453. if tList[i].flag then
  454. if tList[i].mode ~= TIMER then
  455. tList[i].para.delay = 1
  456. if tList[i].mode == DEFAULT then
  457. if existTimerItem() then sys.timerStart(timerFnc,1000) end
  458. end
  459. end
  460. end
  461. end
  462. end
  463. end
  464. --- 打开一个“GPS应用”
  465. -- “GPS应用”:指的是使用GPS功能的一个应用
  466. -- 例如,假设有如下3种需求,要打开GPS,则一共有3个“GPS应用”:
  467. -- “GPS应用1”:每隔1分钟打开一次GPS
  468. -- “GPS应用2”:设备发生震动时打开GPS
  469. -- “GPS应用3”:收到一条特殊短信时打开GPS
  470. -- 只有所有“GPS应用”都关闭了,才会去真正关闭GPS
  471. -- 每个“GPS应用”打开或者关闭GPS时,最多有4个参数,其中 GPS应用模式和GPS应用标记 共同决定了一个唯一的“GPS应用”:
  472. -- 1、GPS应用模式(必选)
  473. -- 2、GPS应用标记(必选)
  474. -- 3、GPS开启最大时长[可选]
  475. -- 4、回调函数[可选]
  476. -- 例如gpsHxxt.open(gpsHxxt.TIMERORSUC,{tag="TEST",val=120,cb=testGpsCb})
  477. -- gpsHxxt.TIMERORSUC为GPS应用模式,"TEST"为GPS应用标记,120秒为GPS开启最大时长,testGpsCb为回调函数
  478. -- @number mode GPS应用模式,支持gpsHxxt.DEFAULT,gpsHxxt.TIMERORSUC,gpsHxxt.TIMER三种
  479. -- @param para table类型,GPS应用参数
  480. -- para.tag:string类型,GPS应用标记
  481. -- para.val:number类型,GPS应用开启最大时长,mode参数为gpsHxxt.TIMERORSUC或者gpsHxxt.TIMER时,此值才有意义
  482. -- para.cb:GPS应用结束时的回调函数,回调函数的调用形式为para.cb(para.tag)
  483. -- @return nil
  484. -- @usage gpsHxxt.open(gpsHxxt.DEFAULT,{tag="TEST1",cb=test1Cb})
  485. -- @usage gpsHxxt.open(gpsHxxt.TIMERORSUC,{tag="TEST2",val=60,cb=test2Cb})
  486. -- @usage gpsHxxt.open(gpsHxxt.TIMER,{tag="TEST3",val=120,cb=test3Cb})
  487. -- @see DEFAULT,TIMERORSUC,TIMER
  488. function open(mode,para)
  489. assert((para and type(para) == "table" and para.tag and type(para.tag) == "string"),"gpsHxxt.open para invalid")
  490. log.info("gpsHxxt.open",mode,para.tag,para.val,para.cb)
  491. --如果GPS定位成功
  492. if isFix() then
  493. if mode~=TIMER then
  494. --执行回调函数
  495. if para.cb then para.cb(para.tag) end
  496. if mode==TIMERORSUC then return end
  497. end
  498. end
  499. addItem(mode,para)
  500. --真正去打开GPS
  501. _open()
  502. --启动1秒的定时器
  503. if existTimerItem() and not sys.timerIsActive(timerFnc) then
  504. sys.timerStart(timerFnc,1000)
  505. end
  506. end
  507. --- 关闭一个“GPS应用”
  508. -- 只是从逻辑上关闭一个GPS应用,并不一定真正关闭GPS,是有所有的GPS应用都处于关闭状态,才会去真正关闭GPS
  509. -- @number mode GPS应用模式,支持gpsHxxt.DEFAULT,gpsHxxt.TIMERORSUC,gpsHxxt.TIMER三种
  510. -- @param para table类型,GPS应用参数
  511. -- para.tag:string类型,GPS应用标记
  512. -- para.val:number类型,GPS应用开启最大时长,mode参数为gpsHxxt.TIMERORSUC或者gpsHxxt.TIMER时,此值才有意义;使用close接口时,不需要传入此参数
  513. -- para.cb:GPS应用结束时的回调函数,回调函数的调用形式为para.cb(para.tag);使用close接口时,不需要传入此参数
  514. -- @return nil
  515. -- @usage GPS应用模式和GPS应用标记唯一确定一个“GPS应用”,调用本接口关闭时,mode和para.tag要和gpsHxxt.open打开一个“GPS应用”时传入的mode和para.tag保持一致
  516. -- @usage gpsHxxt.close(gpsHxxt.DEFAULT,{tag="TEST1"})
  517. -- @usage gpsHxxt.close(gpsHxxt.TIMERORSUC,{tag="TEST2"})
  518. -- @usage gpsHxxt.close(gpsHxxt.TIMER,{tag="TEST3"})
  519. -- @see open,DEFAULT,TIMERORSUC,TIMER
  520. function close(mode,para)
  521. assert((para and type(para)=="table" and para.tag and type(para.tag)=="string"),"gpsHxxt.close para invalid")
  522. log.info("gpsHxxt.close",mode,para.tag,para.val,para.cb)
  523. --删除此“GPS应用”
  524. delItem(mode,para)
  525. local valid,i
  526. for i=1,#tList do
  527. if tList[i].flag then
  528. valid = true
  529. end
  530. end
  531. --如果没有一个“GPS应用”有效,则关闭GPS
  532. if not valid then _close() end
  533. end
  534. --- 关闭所有“GPS应用”
  535. -- @return nil
  536. -- @usage gpsHxxt.closeAll()
  537. -- @see open,DEFAULT,TIMERORSUC,TIMER
  538. function closeAll()
  539. for i=1,#tList do
  540. if tList[i].flag and tList[i].para.cb then tList[i].para.cb(tList[i].para.tag) end
  541. close(tList[i].mode,tList[i].para)
  542. end
  543. end
  544. --- 判断一个“GPS应用”是否处于激活状态
  545. -- @number mode GPS应用模式,支持gpsHxxt.DEFAULT,gpsHxxt.TIMERORSUC,gpsHxxt.TIMER三种
  546. -- @param para table类型,GPS应用参数
  547. -- para.tag:string类型,GPS应用标记
  548. -- para.val:number类型,GPS应用开启最大时长,mode参数为gpsHxxt.TIMERORSUC或者gpsHxxt.TIMER时,此值才有意义;使用isActive接口时,不需要传入此参数
  549. -- para.cb:GPS应用结束时的回调函数,回调函数的调用形式为para.cb(para.tag);使用isActive接口时,不需要传入此参数
  550. -- @return bool result,处于激活状态返回true,否则返回nil
  551. -- @usage GPS应用模式和GPS应用标记唯一确定一个“GPS应用”,调用本接口查询状态时,mode和para.tag要和gpsHxxt.open打开一个“GPS应用”时传入的mode和para.tag保持一致
  552. -- @usage gpsHxxt.isActive(gpsHxxt.DEFAULT,{tag="TEST1"})
  553. -- @usage gpsHxxt.isActive(gpsHxxt.TIMERORSUC,{tag="TEST2"})
  554. -- @usage gpsHxxt.isActive(gpsHxxt.TIMER,{tag="TEST3"})
  555. -- @see open,DEFAULT,TIMERORSUC,TIMER
  556. function isActive(mode,para)
  557. assert((para and type(para)=="table" and para.tag and type(para.tag)=="string"),"gpsHxxt.isActive para invalid")
  558. for i=1,#tList do
  559. if tList[i].flag and tList[i].mode==mode and tList[i].para.tag==para.tag then return true end
  560. end
  561. end
  562. --- 设置GPS模块供电控制的回调函数
  563. -- 如果使用的是Air800,或者供电控制使用的是LDO_VCAM,则打开GPS应用前不需要调用此接口进行设置
  564. -- 否则在调用gpsHxxt.open前,使用此接口,传入自定义的供电控制函数cbFnc,GPS开启时,gpsHxxt.lua自动执行cbFnc(true),GPS关闭时,gpsHxxt.lua自动执行cbFnc(false)
  565. -- @param cbFnc function类型,用户自定义的GPS供电控制函数
  566. -- @return nil
  567. -- @usage gpsHxxt.setPowerCbFnc(cbFnc)
  568. function setPowerCbFnc(cbFnc)
  569. powerCbFnc = cbFnc
  570. end
  571. --- 设置GPS模块和GSM模块之间数据通信的串口参数
  572. -- 如果使用的是Air800,或者使用的UART2(波特率115200,数据位8,无检验位,停止位1),则打开GPS应用前不需要调用此接口进行设置
  573. -- 否则在调用gpsHxxt.open前,使用此接口,传入UART参数
  574. -- @number id UART ID,支持1和2,1表示UART1,2表示UART2
  575. -- @number baudrate 波特率,支持1200,2400,4800,9600,10400,14400,19200,28800,38400,57600,76800,115200,230400,460800,576000,921600,1152000,4000000
  576. -- @number databits 数据位,支持8
  577. -- @number parity 校验位,支持uart.PAR_NONE,uart.PAR_EVEN,uart.PAR_ODD
  578. -- @number stopbits 停止位,支持uart.STOP_1,uart.STOP_2
  579. -- @return nil
  580. -- @usage gpsHxxt.setUart(2,115200,8,uart.PAR_NONE,uart.STOP_1)
  581. function setUart(id,baudrate,databits,parity,stopbits)
  582. uartID,uartBaudrate,uartDatabits,uartParity,uartStopbits = id,baudrate,databits,parity,stopbits
  583. end
  584. --- 设置GPS模块搜星模式
  585. -- 同时仅支持配置为一种搜星模式
  586. -- @number H01 设置为GPS L1+SBAS+QZSS联合定位模式
  587. -- @number H10 设置为BDS B1定位
  588. -- @number H101 设置为GPS+GLONASS+GALILEO+SBAS+QZSS联合定位
  589. -- @number H11 设置为GPS+BDS+GALILEO+SBAS+QZSS联合定位
  590. -- @return nil
  591. -- @usage gpsHxxt.setAerialMode(nil,nil,1)
  592. function setAerialMode(H01,H10,H101,H11)
  593. local H01 = H01 or 0
  594. local H10 = H10 or 0
  595. local H101 = H101 or 0
  596. local H11 = H11 or 0
  597. if H01~=0 then rt=H01 end
  598. if H10~=0 then rt=H10 end
  599. if H101~=0 then rt=H101 end
  600. if H11~=0 then rt=H11 end
  601. if H01+H10+H101+H11 == 0 then H11=1 end
  602. if H01+H10+H101+H11>1 then
  603. log.warn("gpsHxxt.setAerialMode"," function input err")
  604. return
  605. end
  606. local tmpStr = "$CFGSYS,"..rt
  607. if tmpStr~=aerialModeStr then
  608. aerialModeStr,aerialModeSetted = tmpStr
  609. end
  610. end
  611. --- 设置NMEA数据处理模式.
  612. -- 如果不调用此接口配置,则默认仅gpsHxxt.lua内部处理NMEA数据
  613. -- @number mode NMEA数据处理模式,0表示仅gpsHxxt.lua内部处理,1表示仅用户自己处理,2表示gpsHxxt.lua和用户同时处理
  614. -- @param cbFnc function类型,用户处理一条NMEA数据的回调函数,mode为1和2时,此值才有意义
  615. -- @return nil
  616. -- @usage gpsHxxt.setNmeaMode(0)
  617. -- @usage gpsHxxt.setNmeaMode(1,cbFnc)
  618. -- @usage gpsHxxt.setNmeaMode(2,cbFnc)
  619. function setNmeaMode(mode,cbFnc)
  620. nmeaMode,nmeaCbFnc = mode,cbFnc
  621. end
  622. --- 设置GPS模块的运行模式.
  623. -- 如果不调用此接口配置,则默认为正常运行模式
  624. -- @number mode 运行模式
  625. -- 0:正常运行模式
  626. -- 1:低功耗模式
  627. -- @return nil
  628. -- @usage gpsHxxt.setRunMode(0)
  629. -- @usage gpsHxxt.setRunMode(1)
  630. function setRunMode(mode)
  631. local tmpStr = "$CFGLOWPOWER,"..mode
  632. if tmpStr~=runModeStr then
  633. runModeStr,runModeSetted = tmpStr
  634. end
  635. end
  636. --设置NEMA输出语句种类
  637. -- @string date NEMA语句名称
  638. -- @number flag 0关闭1打开
  639. -- @usage gpaHxxt.setNemaReportFreq("GSV",1)
  640. -- 开机后需等待250ms+后发送才有效
  641. function setNemaReportFreq(date,flag)
  642. local rt=""
  643. if date=="RMC" then
  644. writeCmd("$CFGMSG,0,4,"..flag)
  645. elseif date=="GGA" then
  646. writeCmd("$CFGMSG,0,0,"..flag)
  647. elseif date=="GSA" then
  648. writeCmd("$CFGMSG,0,2,"..flag)
  649. elseif date=="VTG" then
  650. writeCmd("$CFGMSG,0,5,"..flag)
  651. elseif date=="GLL" then
  652. writeCmd("$CFGMSG,0,1,"..flag)
  653. elseif date=="GSV" then
  654. writeCmd("$CFGMSG,0,3,"..flag)
  655. end
  656. end
  657. --- 设置GPS定位成功后经纬度的过滤时间.
  658. -- @number[opt=0] seconds 单位秒,GPS定位成功后,丢弃前seconds秒的位置信息
  659. -- @return nil
  660. -- @usage gpsHxxt.setLocationFilter(2)
  661. function setLocationFilter(seconds)
  662. filterSeconds = seconds or 0
  663. end
  664. function setFastFix(lat,lng,tm)
  665. local tLocation = getLocation()
  666. local Altitude = getAltitude()
  667. lngType=tLocation.lngType
  668. latType=tLocation.latType
  669. local tm = os.date("*t")
  670. local t = tm.year..","..tm.month..","..tm.day..","..tm.hour..","..tm.min..","..tm.sec..",000"
  671. local APos = string.format("%s,%f,%s,%f,%s,%f","$AIDPOS",lat,latType,lng,lngType,Altitude)
  672. log.info("gpsHxxt.setFastFix",lat,lng,t)
  673. writeCmd("$AIDTIME,"..t)
  674. writeCmd(APos)
  675. end
  676. --- 获取GPS模块是否处于开启状态
  677. -- @return bool result,true表示开启状态,false或者nil表示关闭状态
  678. -- @usage gpsHxxt.isOpen()
  679. function isOpen()
  680. return openFlag
  681. end
  682. --- 获取GPS模块是否定位成功
  683. -- @return bool result,true表示定位成功,false或者nil表示定位失败
  684. -- @usage gpsHxxt.isFix()
  685. function isFix()
  686. return fixFlag
  687. end
  688. function issFix()
  689. fixFlag=false
  690. end
  691. --- 获取GPS模块是否首次定位成功过
  692. -- @return bool result,true表示曾经定位成功
  693. -- @usage gpsHxxt.isOnece()
  694. function isOnece()
  695. return fixOnece
  696. end
  697. -- 度分格式转换为度格式
  698. -- @string inStr 度分格式的位置
  699. -- @return string,度格式的位置
  700. -- @usage degreeMinuteToDegree("3114.50931")--->"31.2418218",31度14.50931分转换为31.2418218度
  701. -- @usage degreeMinuteToDegree("12128.44954")--->"121.4741590",121度28.44954分转换为121.4741590度
  702. local function degreeMinuteToDegree(inStr)
  703. local integer,fraction = smatch(inStr,"(%d+)%.(%d+)")
  704. if integer and fraction then
  705. local intLen = slen(integer)
  706. if intLen~=4 and intLen~=5 then log.error("gpsHxxt.degreeMinuteToDegree integer error",inStr) return "" end
  707. if slen(fraction)<5 then fraction = fraction..srep("0",5-slen(fraction)) end
  708. fraction = ssub(fraction,1,5)
  709. local temp = tonumber(ssub(integer,intLen-1,intLen)..fraction)*10
  710. fraction = tostring((temp-(temp%6))/6)
  711. local fracLen = slen(fraction)
  712. if fracLen>7 then
  713. fraction = ssub(fraction,1,7)
  714. elseif fracLen<7 then
  715. fraction = srep("0",7-fracLen)..fraction
  716. end
  717. return ssub(integer,1,intLen-2).."."..fraction
  718. end
  719. return ""
  720. end
  721. --- 获取度格式的经纬度信息
  722. -- @string[opt=nil] typ 返回的经纬度格式,typ为"DEGREE_MINUTE"时表示返回度分格式,其余表示返回度格式
  723. -- @return table location
  724. -- 例如typ为"DEGREE_MINUTE"时返回{lngType="E",lng="12128.44954",latType="N",lat="3114.50931"}
  725. -- 例如typ不是"DEGREE_MINUTE"时返回{lngType="E",lng="121.123456",latType="N",lat="31.123456"}
  726. -- lngType:string类型,表示经度类型,取值"E","W"
  727. -- lng:string类型,表示度格式的经度值,无效时为""
  728. -- latType:string类型,表示纬度类型,取值"N","S"
  729. -- lat:string类型,表示度格式的纬度值,无效时为""
  730. -- @usage gpsHxxt.getLocation()
  731. function getLocation(typ)
  732. return {
  733. lngType=longitudeType,
  734. lng=isFix() and (typ=="DEGREE_MINUTE" and longitude or degreeMinuteToDegree(longitude)) or "",
  735. latType=latitudeType,
  736. lat=isFix() and (typ=="DEGREE_MINUTE" and latitude or degreeMinuteToDegree(latitude)) or ""
  737. }
  738. end
  739. function getLastLocation(typ)
  740. if typ=="DEGREE_MINUTE" then
  741. return {
  742. lngType=longitudeType,
  743. lng=longitude,
  744. latType=latitudeType,
  745. lat=latitude
  746. }
  747. else
  748. return (longitude and longitude~="") and degreeMinuteToDegree(longitude) or "", (latitude and latitude~="") and degreeMinuteToDegree(latitude) or ""
  749. end
  750. end
  751. --- 获取海拔
  752. -- @return number altitude,海拔,单位米
  753. -- @usage gpsHxxt.getAltitude()
  754. function getAltitude()
  755. return tonumber(smatch(altitude,"(%d+)") or "0")
  756. end
  757. --- 获取速度
  758. -- @return number kmSpeed,第一个返回值为公里每小时的速度
  759. -- @return number nmSpeed,第二个返回值为海里每小时的速度
  760. -- @usage gpsHxxt.getSpeed()
  761. function getSpeed()
  762. local integer = tonumber(smatch(speed,"(%d+)") or "0")
  763. return (integer*1852 - (integer*1852 %1000))/1000,integer
  764. end
  765. --- 获取原始速度,字符串带浮点
  766. -- @return number speed 海里每小时的速度
  767. -- @usage gpsHxxt.getOrgSpeed()
  768. function getOrgSpeed()
  769. return speed
  770. end
  771. --- 获取方向角
  772. -- @return number course,方向角
  773. -- @usage gpsHxxt.getCourse()
  774. function getCourse()
  775. return tonumber(smatch(course,"(%d+)") or "0")
  776. end
  777. -- 获取所有可见卫星的最大信号强度
  778. -- @return number strength,最大信号强度
  779. -- @usage gpsHxxt.getMaxSignalStrength()
  780. function getMaxSignalStrength()
  781. return maxSignalStrength
  782. end
  783. --- 获取可见卫星的个数
  784. -- @return number count,可见卫星的个数
  785. -- @usage gpsHxxt.getViewedSateCnt()
  786. function getViewedSateCnt()
  787. return tonumber(viewedGpsSateCnt)+tonumber(viewedBdSateCnt)
  788. end
  789. --- 获取定位使用的卫星个数
  790. -- @return number count,定位使用的卫星个数
  791. -- @usage gpsHxxt.getUsedSateCnt()
  792. function getUsedSateCnt()
  793. return tonumber(usedSateCnt)
  794. end
  795. --- 获取GGA语句中度分格式的经纬度信息
  796. -- @return string lng,度分格式的经度值(dddmm.mmmm),西经会添加一个-前缀,无效时为"";例如"12112.3456"表示东经121度12.3456分,"-12112.3456"表示西经121度12.3456分
  797. -- @return string lat,度分格式的纬度值(ddmm.mmmm),南纬会添加一个-前缀,无效时为"";例如"3112.3456"表示北纬31度12.3456分,"-3112.3456"表示南纬31度12.3456分
  798. -- @usage gpsHxxt.getGgaloc()
  799. function getGgaloc()
  800. return Ggalng or "",Ggalat or ""
  801. end
  802. --- 获取RMC语句中的UTC时间
  803. -- 只有同时满足如下两个条件,返回值才有效
  804. -- 1、开启了GPS,并且定位成功
  805. -- 2、调用setParseItem接口,第一个参数设置为true
  806. -- @return table utcTime,UTC时间,nil表示无效,例如{year=2018,month=4,day=24,hour=11,min=52,sec=10}
  807. -- @usage gpsHxxt.getUtcTime()
  808. function getUtcTime()
  809. return UtcTime
  810. end
  811. --- 获取定位使用的大地高
  812. -- @return number sep,大地高
  813. -- @usage gpsHxxt.getSep()
  814. function getSep()
  815. return tonumber(Sep or "0")
  816. end
  817. --- 获取GSA语句中的可见卫星号
  818. -- 只有同时满足如下两个条件,返回值才有效
  819. -- 1、开启了GPS,并且定位成功
  820. -- 2、调用setParseItem接口,第三个参数设置为true
  821. -- @return string viewedSateId,可用卫星号,""表示无效
  822. -- @usage gpsHxxt.getSateSn()
  823. function getSateSn()
  824. return SateSn or ""
  825. end
  826. --- 获取GSV语句中的可见卫星的信噪比
  827. -- 只有同时满足如下两个条件,返回值才有效
  828. -- 1、开启了GPS,并且定位成功
  829. -- 2、调用setParseItem接口,第二个参数设置为true
  830. -- @return string gsv,信噪比
  831. -- @usage gpsHxxt.getGsv()
  832. function getGsv()
  833. return Gsv or ""
  834. end
  835. --- 设置是否需要解析的字段
  836. -- @bool[opt=nil] utcTime 是否解析RMC语句中的UTC时间,true表示解析,false或者nil不解析
  837. -- @bool[opt=nil] gsv 是否解析GSV语句,true表示解析,false或者nil不解析
  838. -- @bool[opt=nil] gsaId 是否解析GSA语句中的卫星ID,true表示解析,false或者nil不解析
  839. -- @usage gpsHxxt.setParseItem(true,true,true)
  840. function setParseItem(utcTime,gsv,gsaId)
  841. psUtcTime,psGsv,psSn = utcTime,gsv,gsaId
  842. end
  843. function init()
  844. sys.subscribe("GPS_STATE",statInd)
  845. end
  846. function unInit()
  847. sys.unsubscribe("GPS_STATE",statInd)
  848. closeAll()
  849. end
  850. init()