lbsLoc2.lua 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. --[[
  2. @module lbsLoc2
  3. @summary 基站定位v2
  4. @version 1.0
  5. @date 2023.5.23
  6. @author wendal
  7. @demo lbsLoc2
  8. @usage
  9. -- lbsloc 是异步回调接口,
  10. -- lbsloc2 是是同步接口。
  11. -- lbsloc比lbsloc2多了一个请求地址文本的功能。
  12. -- lbsloc 和 lbsloc2 都是免费LBS定位的实现方式;
  13. -- airlbs 扩展库是收费 LBS 的实现方式。
  14. -- 注意:
  15. -- 1. 因使用了sys.wait()所有api需要在协程中使用
  16. -- 2. 仅支持单基站定位, 即当前联网的基站
  17. -- 3. 本服务当前处于测试状态
  18. sys.taskInit(function()
  19. sys.waitUntil("IP_READY", 30000)
  20. -- mobile.reqCellInfo(60)
  21. -- sys.wait(1000)
  22. while mobile do -- 没有mobile库就没有基站定位
  23. mobile.reqCellInfo(15)
  24. sys.waitUntil("CELL_INFO_UPDATE", 3000)
  25. local lat, lng, t = lbsLoc2.request(5000)
  26. -- local lat, lng, t = lbsLoc2.request(5000, "bs.openluat.com")
  27. log.info("lbsLoc2", lat, lng, (json.encode(t or {})))
  28. sys.wait(60000)
  29. end
  30. end)
  31. ]]
  32. local sys = require "sys"
  33. local lbsLoc2 = {}
  34. local function numToBcdNum(inStr,destLen)
  35. local l,t,num = string.len(inStr or ""),{}
  36. destLen = destLen or (inStr:len()+1)/2
  37. for i=1,l,2 do
  38. num = tonumber(inStr:sub(i,i+1),16)
  39. if i==l then
  40. num = 0xf0+num
  41. else
  42. num = (num%0x10)*0x10 + (num-(num%0x10))/0x10
  43. end
  44. table.insert(t,num)
  45. end
  46. local s = string.char(unpack(t))
  47. l = string.len(s)
  48. if l < destLen then
  49. s = s .. string.rep("\255",destLen-l)
  50. elseif l > destLen then
  51. s = string.sub(s,1,destLen)
  52. end
  53. return s
  54. end
  55. --- BCD编码格式字符串 转化为 号码ASCII字符串(仅支持数字)
  56. -- @string num 待转换字符串
  57. -- @return string data,转换后的字符串
  58. -- @usage
  59. local function bcdNumToNum(num)
  60. local byte,v1,v2
  61. local t = {}
  62. for i=1,num:len() do
  63. byte = num:byte(i)
  64. v1,v2 = bit.band(byte,0x0f),bit.band(bit.rshift(byte,4),0x0f)
  65. if v1 == 0x0f then break end
  66. table.insert(t,v1)
  67. if v2 == 0x0f then break end
  68. table.insert(t,v2)
  69. end
  70. return table.concat(t)
  71. end
  72. lbsLoc2.imei = numToBcdNum(mobile.imei())
  73. local function enCellInfo(s)
  74. -- 改造成单基站, 反正服务器也只认单基站
  75. local v = s[1]
  76. log.info("cell", json.encode(v))
  77. local ret = pack.pack(">HHbbi",v.tac,v.mcc,v.mnc,31,v.cid)
  78. return string.char(1)..ret
  79. end
  80. local function trans(str)
  81. local s = str
  82. if str:len()<10 then
  83. s = str..string.rep("0",10-str:len())
  84. end
  85. return s:sub(1,3).."."..s:sub(4,10)
  86. end
  87. --[[
  88. 执行定位请求
  89. @api lbsLoc2.request(timeout, host, port, reqTime)
  90. @number 请求超时时间,单位毫秒,默认15000
  91. @number 服务器地址,有默认值,可以是域名,一般不需要填
  92. @number 服务器端口,默认12411,一般不需要填
  93. @bool 是否要求返回服务器时间
  94. @return string 若成功,返回定位坐标的纬度,否则会返还nil
  95. @return string 若成功,返回定位坐标的经度,否则会返还nil
  96. @return table 服务器时间,东八区时间. 当reqTime为true且定位成功才会返回
  97. @usage
  98. -- 关于坐标系
  99. -- 部分情况下会返回GCJ02坐标系, 部分情况返回的是WGS84坐标
  100. -- 历史数据已经无法分辨具体坐标系
  101. -- 鉴于两种坐标系之间的误差并不大,小于基站定位本身的误差, 纠偏的意义不大
  102. sys.taskInit(function()
  103. sys.waitUntil("IP_READY", 30000)
  104. -- mobile.reqCellInfo(60)
  105. -- sys.wait(1000)
  106. while mobile do -- 没有mobile库就没有基站定位
  107. mobile.reqCellInfo(15)
  108. sys.waitUntil("CELL_INFO_UPDATE", 3000)
  109. local lat, lng, t = lbsLoc2.request(5000)
  110. -- local lat, lng, t = lbsLoc2.request(5000, "bs.openluat.com")
  111. log.info("lbsLoc2", lat, lng, (json.encode(t or {})))
  112. sys.wait(60000)
  113. end
  114. end)
  115. ]]
  116. function lbsLoc2.request(timeout, host, port, reqTime)
  117. if mobile.status() == 0 then
  118. return
  119. end
  120. local hosts = host and {host} or {"free.bs.air32.cn", "bs.openluat.com"}
  121. port = port and tonumber(port) or 12411
  122. local sc = socket.create(nil, function(sc, event)
  123. -- log.info("lbsLoc", "event", event, socket.ON_LINE, socket.TX_OK, socket.EVENT)
  124. if event == socket.ON_LINE then
  125. --log.info("lbsLoc", "已连接")
  126. sys.publish("LBS_CONACK")
  127. elseif event == socket.TX_OK then
  128. --log.info("lbsLoc", "发送完成")
  129. sys.publish("LBS_TX")
  130. elseif event == socket.EVENT then
  131. --log.info("lbsLoc", "有数据来")
  132. sys.publish("LBS_RX")
  133. end
  134. end)
  135. if sc == nil then
  136. return
  137. end
  138. -- socket.debug(sc, true)
  139. socket.config(sc, nil, true)
  140. local rxbuff = zbuff.create(64)
  141. for k, rhost in pairs(hosts) do
  142. local reqStr = string.char(0, (reqTime and 4 or 0) +8) .. lbsLoc2.imei
  143. local tmp = nil
  144. if mobile.scell then
  145. local scell = mobile.scell()
  146. if scell and scell.mcc then
  147. -- log.debug("lbsLoc2", "使用当前驻网基站的信息")
  148. tmp = pack.pack(">bHHbbi", 1, scell.tac, scell.mcc, scell.mnc, 31, scell.eci)
  149. end
  150. end
  151. if tmp == nil then
  152. local cells = mobile.getCellInfo()
  153. if cells == nil or #cells == 0 then
  154. socket.release(sc)
  155. return
  156. end
  157. reqStr = reqStr .. enCellInfo(cells)
  158. else
  159. reqStr = reqStr .. tmp
  160. end
  161. -- log.debug("lbsLoc2", "待发送数据", (reqStr:toHex()))
  162. log.debug("lbsLoc2", rhost, port)
  163. if socket.connect(sc, rhost, port) and sys.waitUntil("LBS_CONACK", 1000) then
  164. if socket.tx(sc, reqStr) and sys.waitUntil("LBS_TX", 1000) then
  165. socket.wait(sc)
  166. if sys.waitUntil("LBS_RX", timeout or 15000) then
  167. local succ, data_len = socket.rx(sc, rxbuff)
  168. -- log.debug("lbsLoc", "rx", succ, data_len)
  169. if succ and data_len > 0 then
  170. socket.close(sc)
  171. break
  172. else
  173. log.debug("lbsLoc", "rx数据失败", rhost)
  174. end
  175. else
  176. log.debug("lbsLoc", "等待数据超时", rhost)
  177. end
  178. else
  179. log.debug("lbsLoc", "tx调用失败或TX_ACK超时", rhost)
  180. end
  181. else
  182. log.debug("lbsLoc", "connect调用失败或CONACK超时", rhost)
  183. end
  184. socket.close(sc)
  185. --sys.wait(100)
  186. end
  187. sys.wait(100)
  188. socket.release(sc)
  189. if rxbuff:used() > 0 then
  190. local resp = rxbuff:toStr(0, rxbuff:used())
  191. log.debug("lbsLoc2", "rx", (resp:toHex()))
  192. if resp:len() >= 11 and(resp:byte(1) == 0 or resp:byte(1) == 0xFF) then
  193. local lat = trans(bcdNumToNum(resp:sub(2, 6)))
  194. local lng = trans(bcdNumToNum(resp:sub(7, 11)))
  195. local t = nil
  196. if resp:len() >= 17 then
  197. t = {
  198. year=resp:byte(12) + 2000,
  199. month=resp:byte(13),
  200. day=resp:byte(14),
  201. hour=resp:byte(15),
  202. min=resp:byte(16),
  203. sec=resp:byte(17),
  204. }
  205. end
  206. return lat, lng, t
  207. end
  208. end
  209. rxbuff:del()
  210. end
  211. return lbsLoc2