Files
BR_YKC/4G/tools/resource/soc_script/v2025.12.31.22/lib/lbsLoc.lua
2026-03-31 15:46:04 +08:00

284 lines
11 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
--[[
@module lbsLoc
@summary lbsLoc 发送基站定位请求
@version 1.0
@date 2022.12.16
@author luatos
@usage
-- lbsloc 是异步回调接口,
-- lbsloc2 是是同步接口。
-- lbsloc比lbsloc2多了一个请求地址文本的功能。
-- lbsloc 和 lbsloc2 都是免费LBS定位的实现方式
-- airlbs 扩展库是收费 LBS 的实现方式。
--注意:因使用了sys.wait()所有api需要在协程中使用
--用法实例
--注意此处的PRODUCT_KEY仅供演示使用不能用于生产环境
--量产项目中一定要使用自己在iot.openluat.com中创建的项目productKey,项目详情里可以查看
--基站定位的坐标系是 WSG84
PRODUCT_KEY = "123"
local lbsLoc = require("lbsLoc")
-- 功能:获取基站对应的经纬度后的回调函数
-- 参数:-- resultnumber类型0表示成功1表示网络环境尚未就绪2表示连接服务器失败3表示发送数据失败4表示接收服务器应答超时5表示服务器返回查询失败为0时后面的5个参数才有意义
-- latstring类型纬度整数部分3位小数部分7位例如031.2425864
-- lngstring类型经度整数部分3位小数部分7位例如121.4736522
-- addr目前无意义
-- timestring类型或者nil服务器返回的时间6个字节年月日时分秒需要转为十六进制读取
-- 第一个字节年减去2000例如2017年则为0x11
-- 第二个字节例如7月则为0x0712月则为0x0C
-- 第三个字节例如11日则为0x0B
-- 第四个字节例如18时则为0x12
-- 第五个字节例如59分则为0x3B
-- 第六个字节例如48秒则为0x30
-- locTypenumble类型或者nil定位类型0表示基站定位成功255表示WIFI定位成功
function getLocCb(result, lat, lng, addr, time, locType)
log.info("testLbsLoc.getLocCb", result, lat, lng)
-- 获取经纬度成功, 坐标系WGS84
if result == 0 then
log.info("服务器返回的时间", time:toHex())
log.info("定位类型,基站定位成功返回0", locType)
end
end
sys.taskInit(function()
sys.waitUntil("IP_READY", 30000)
while 1 do
mobile.reqCellInfo(15)
sys.waitUntil("CELL_INFO_UPDATE", 3000)
lbsLoc.request(getLocCb)
sys.wait(60000)
end
end)
]]
local sys = require "sys"
local sysplus = require("sysplus")
local libnet = require("libnet")
local lbsLoc = {}
local d1Name = "lbsLoc"
--- ASCII字符串 转化为 BCD编码格式字符串(仅支持数字)
-- @string inStr 待转换字符串
-- @number destLen 转换后的字符串期望长度如果实际不足则填充F
-- @return string data,转换后的字符串
-- @usage
local function numToBcdNum(inStr,destLen)
local l,t,num = string.len(inStr or ""),{}
destLen = destLen or (inStr:len()+1)/2
for i=1,l,2 do
num = tonumber(inStr:sub(i,i+1),16)
if i==l then
num = 0xf0+num
else
num = (num%0x10)*0x10 + (num-(num%0x10))/0x10
end
table.insert(t,num)
end
local s = string.char(unpack(t))
l = string.len(s)
if l < destLen then
s = s .. string.rep("\255",destLen-l)
elseif l > destLen then
s = string.sub(s,1,destLen)
end
return s
end
--- BCD编码格式字符串 转化为 号码ASCII字符串(仅支持数字)
-- @string num 待转换字符串
-- @return string data,转换后的字符串
-- @usage
local function bcdNumToNum(num)
local byte,v1,v2
local t = {}
for i=1,num:len() do
byte = num:byte(i)
v1,v2 = bit.band(byte,0x0f),bit.band(bit.rshift(byte,4),0x0f)
if v1 == 0x0f then break end
table.insert(t,v1)
if v2 == 0x0f then break end
table.insert(t,v2)
end
return table.concat(t)
end
local function netCB(msg)
--log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
end
local function enCellInfo(s)
local ret,t,mcc,mnc,lac,ci,rssi,k,v,m,n,cntrssi = "",{}
for k,v in pairs(s) do
mcc,mnc,lac,ci,rssi = v.mcc,v.mnc,v.tac,v.cid,((v.rsrq + 144) >31) and 31 or (v.rsrq + 144)
local handle = nil
for k,v in pairs(t) do
if v.lac == lac and v.mcc == mcc and v.mnc == mnc then
if #v.rssici < 8 then
table.insert(v.rssici,{rssi=rssi,ci=ci})
end
handle = true
break
end
end
if not handle then
table.insert(t,{mcc=mcc,mnc=mnc,lac=lac,rssici={{rssi=rssi,ci=ci}}})
end
log.debug("rssi,mcc,mnc,lac,ci", rssi,mcc,mnc,lac,ci)
end
for k,v in pairs(t) do
ret = ret .. pack.pack(">HHb",v.lac,v.mcc,v.mnc)
for m,n in pairs(v.rssici) do
cntrssi = bit.bor(bit.lshift(((m == 1) and (#v.rssici-1) or 0),5),n.rssi or n.rsrp)
ret = ret .. pack.pack(">bi",cntrssi,n.ci)
end
end
return string.char(#t)..ret
end
local function enWifiInfo(tWifi)
local ret,cnt = "", 0
if tWifi then
for k,v in pairs(tWifi) do
-- log.info("lbsLoc.enWifiInfo",k,v)
ret = ret..pack.pack("Ab",(k:gsub(":","")):fromHex(),(v<0) and (v+255) or v)
cnt = cnt+1
end
end
return string.char(cnt)..ret
end
local function enMuid() --获取模块MUID
local muid = mobile.muid()
return string.char(muid:len())..muid
end
local function trans(str)
local s = str
if str:len()<10 then
s = str..string.rep("0",10-str:len())
end
return s:sub(1,3).."."..s:sub(4,10)
end
local function taskClient(cbFnc, reqAddr, timeout, productKey, host, port,reqTime, reqWifi)
if mobile.status() == 0 then
if not sys.waitUntil("IP_READY", timeout) then return cbFnc(1) end
sys.wait(500)
end
if productKey == nil then
productKey = ""
end
local retryCnt = 0
local reqStr = pack.pack("bAbAAAAA", productKey:len(), productKey,
(reqAddr and 2 or 0) + (reqTime and 4 or 0) + 8 +(reqWifi and 16 or 0) + 32, "",
numToBcdNum(mobile.imei()), enMuid(),
enCellInfo(mobile.getCellInfo()),
enWifiInfo(reqWifi))
log.debug("reqStr", reqStr:toHex())
local rx_buff = zbuff.create(17)
-- sys.wait(5000)
while true do
local result,succ,param
local netc = socket.create(nil, d1Name) -- 创建socket对象
if not netc then cbFnc(6) return end -- 创建socket失败
socket.debug(netc, false)
socket.config(netc, nil, true, nil)
--result = libnet.waitLink(d1Name, 0, netc)
result = libnet.connect(d1Name, 5000, netc, host, port)
if result then
while true do
-- log.info(" lbsloc socket_service connect true")
result = libnet.tx(d1Name, 0, netc, reqStr) ---发送数据
if result then
result, param = libnet.wait(d1Name, 15000 + retryCnt * 5, netc)
if not result then
socket.close(netc)
socket.release(netc)
retryCnt = retryCnt+1
if retryCnt>=3 then return cbFnc(4) end
break
end
succ, param = socket.rx(netc, rx_buff) -- 接收数据
-- log.info("是否接收和数据长度", succ, param)
if param ~= 0 then -- 如果接收成功
socket.close(netc) -- 关闭连接
socket.release(netc)
local read_buff = rx_buff:toStr(0, param)
rx_buff:clear()
log.debug("lbsLoc receive", read_buff:toHex())
if read_buff:len() >= 11 and(read_buff:byte(1) == 0 or read_buff:byte(1) == 0xFF) then
local locType = read_buff:byte(1)
cbFnc(0, trans(bcdNumToNum(read_buff:sub(2, 6))),
trans(bcdNumToNum(read_buff:sub(7, 11))), reqAddr and
read_buff:sub(13, 12 + read_buff:byte(12)) or nil,
reqTime and read_buff:sub(reqAddr and (13 + read_buff:byte(12)) or 12, -1) or "",
locType)
else
log.warn("lbsLoc.query", "根据基站查询经纬度失败")
if read_buff:byte(1) == 2 then
log.warn("lbsLoc.query","main.lua中的PRODUCT_KEY和此设备在iot.openluat.com中所属项目的ProductKey必须一致请去检查")
else
log.warn("lbsLoc.query","基站数据库查询不到所有小区的位置信息")
-- log.warn("lbsLoc.query","在trace中向上搜索encellinfo然后在电脑浏览器中打开http://bs.openluat.com/手动查找encellinfo后的所有小区位置")
-- log.warn("lbsLoc.query","如果手动可以查到位置则服务器存在BUG直接向技术人员反映问题")
-- log.warn("lbsLoc.query","如果手动无法查到位置,则基站数据库还没有收录当前设备的小区位置信息,向技术人员反馈,我们会尽快收录")
end
cbFnc(5)
end
return
else
socket.close(netc)
socket.release(netc)
retryCnt = retryCnt+1
if retryCnt>=3 then return cbFnc(4) end
break
end
else
socket.close(netc)
socket.release(netc)
retryCnt = retryCnt+1
if retryCnt>=3 then return cbFnc(3) end
break
end
end
else
socket.close(netc)
socket.release(netc)
retryCnt = retryCnt + 1
if retryCnt >= 3 then return cbFnc(2) end
end
end
end
--[[
发送基站定位请求
@api lbsLoc.request(cbFnc,reqAddr,timeout,productKey,host,port,reqTime,reqWifi)
@function cbFnc 用户回调函数回调函数的调用形式为cbFnc(result,lat,lng,addr,time,locType)
@bool reqAddr 是否请求服务器返回具体的位置字符串信息,已经不支持,填false或者nil
@number timeout 请求超时时间单位毫秒默认20000毫秒
@string productKey IOT网站上的产品KEY如果在main.lua中定义了PRODUCT_KEY变量则此参数可以传nil
@string host 服务器域名, 默认 "bs.openluat.com" ,可选备用服务器(不保证可用) "bs.air32.cn"
@string port 服务器端口,默认"12411",一般不需要设置
@return nil 无返回值
@usage
-- 提醒: 返回的坐标值, 是WGS84坐标系
]]
function lbsLoc.request(cbFnc,reqAddr,timeout,productKey,host,port,reqTime,reqWifi)
sysplus.taskInitEx(taskClient, d1Name, netCB, cbFnc, reqAddr,timeout or 20000,productKey or _G.PRODUCT_KEY,host or "bs.openluat.com",port or "12411", reqTime == nil and true or reqTime,reqWifi)
end
return lbsLoc