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