net.lua 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. ---模块功能:网络管理、信号查询、GSM网络状态查询、网络指示灯控制、临近小区信息查询
  2. -- @module net
  3. -- @author openLuat
  4. -- @license MIT
  5. -- @copyright openLuat
  6. -- @release 2017.02.17
  7. local base = _G
  8. local string = require "string"
  9. local sys = require "sys"
  10. local ril = require "ril"
  11. local pio = require "pio"
  12. local sim = require "sim"
  13. local log = require "log"
  14. module("net")
  15. --加载常用的全局函数至本地
  16. local publish = sys.publish
  17. local tonumber, tostring = base.tonumber, base.tostring
  18. --GSM网络状态:
  19. --INIT:开机初始化中的状态
  20. --REGISTERED:注册上GSM网络
  21. --UNREGISTER:未注册上GSM网络
  22. local state = "INIT"
  23. --SIM卡状态:true为异常,false或者nil为正常
  24. local simerrsta
  25. -- 飞行模式状态
  26. flyMode = false
  27. --lac:位置区ID
  28. --ci:小区ID
  29. --rssi:信号强度
  30. local lac, ci, rssi = "", "", 0
  31. --cellinfo:当前小区和临近小区信息表
  32. --multicellcb:获取多小区的回调函数
  33. local cellinfo, multicellcb = {}
  34. --注册标志参数,creg3:true为没注册,为false为注册成功
  35. local creg3
  36. --[[
  37. 函数名:checkCRSM
  38. 功能:如果注册被拒绝,运行此函数,先判断是否取得imsi号,再判断是否是中国移动卡
  39. 如果确定是中国移动卡,则进行SIM卡限制访问
  40. 参数:
  41. 返回值:
  42. ]]
  43. local function checkCRSM()
  44. local imsi = sim.getimsi()
  45. if imsi and imsi ~= "" then
  46. if string.sub(imsi, 1, 3) == "460" then
  47. local mnc = string.sub(imsi, 4, 5)
  48. if (mnc == "00" or mnc == "02" or mnc == "04" or mnc == "07") and creg3 then
  49. ril.request("AT+CRSM=176,28539,0,0,12")
  50. end
  51. end
  52. else
  53. sys.timer_start(checkCRSM, 5000)
  54. end
  55. end
  56. --[[
  57. 函数名:creg
  58. 功能 :解析CREG信息
  59. 参数 :data:CREG信息字符串,例如+CREG: 2、+CREG: 1,"18be","93e1"、+CREG: 5,"18a7","cb51"
  60. 返回值:无
  61. ]]
  62. local function creg(data)
  63. local p1, s
  64. --获取注册状态
  65. _, _, p1 = string.find(data, "%d,(%d)")
  66. if p1 == nil then
  67. _, _, p1 = string.find(data, "(%d)")
  68. if p1 == nil then
  69. return
  70. end
  71. end
  72. creg3 = false
  73. --已注册
  74. if p1 == "1" or p1 == "5" then
  75. s = "REGISTERED"
  76. --未注册
  77. else
  78. if p1 == "3" then
  79. creg3 = true
  80. checkCRSM()
  81. end
  82. s = "UNREGISTER"
  83. end
  84. --注册状态发生了改变
  85. if s ~= state then
  86. --临近小区查询处理
  87. if s == "REGISTERED" then
  88. --产生一个内部消息NET_STATE_CHANGED,表示GSM网络注册状态发生变化
  89. publish("NET_STATE_REGISTERED")
  90. cengQueryPoll(60 * 1000)
  91. else
  92. cengQueryPoll()
  93. end
  94. state = s
  95. end
  96. --已注册并且lac或ci发生了变化
  97. if state == "REGISTERED" then
  98. p2, p3 = string.match(data, "\"(%x+)\",\"(%x+)\"")
  99. if lac ~= p2 or ci ~= p3 then
  100. lac = p2
  101. ci = p3
  102. --产生一个内部消息NET_CELL_CHANGED,表示lac或ci发生了变化
  103. publish("NET_CELL_CHANGED")
  104. end
  105. end
  106. end
  107. --[[
  108. 函数名:resetcellinfo
  109. 功能 :重置当前小区和临近小区信息表
  110. 参数 :无
  111. 返回值:无
  112. ]]
  113. local function resetCellInfo()
  114. local i
  115. cellinfo.cnt = 11 --最大个数
  116. for i = 1, cellinfo.cnt do
  117. cellinfo[i] = {}
  118. cellinfo[i].mcc, cellinfo[i].mnc = nil
  119. cellinfo[i].lac = 0
  120. cellinfo[i].ci = 0
  121. cellinfo[i].rssi = 0
  122. cellinfo[i].ta = 0
  123. end
  124. end
  125. --[[
  126. 函数名:ceng
  127. 功能 :解析当前小区和临近小区信息
  128. 参数 :
  129. data:当前小区和临近小区信息字符串,例如下面中的每一行:
  130. +CENG:1,1
  131. +CENG:0,"573,24,99,460,0,13,49234,10,0,6311,255"
  132. +CENG:1,"579,16,460,0,5,49233,6311"
  133. +CENG:2,"568,14,460,0,26,0,6311"
  134. +CENG:3,"584,13,460,0,10,0,6213"
  135. +CENG:4,"582,13,460,0,51,50146,6213"
  136. +CENG:5,"11,26,460,0,3,52049,6311"
  137. +CENG:6,"29,26,460,0,32,0,6311"
  138. 返回值:无
  139. ]]
  140. local function ceng(data)
  141. --只处理有效的CENG信息
  142. if string.find(data, "%+CENG:%d+,\".+\"") then
  143. local id, rssi, lac, ci, ta, mcc, mnc
  144. id = string.match(data, "%+CENG:(%d)")
  145. id = tonumber(id)
  146. --第一条CENG信息和其余的格式不同
  147. if id == 0 then
  148. rssi, mcc, mnc, ci, lac, ta = string.match(data, "%+CENG:%d,\"%d+,(%d+),%d+,(%d+),(%d+),%d+,(%d+),%d+,%d+,(%d+),(%d+)\"")
  149. else
  150. rssi, mcc, mnc, ci, lac, ta = string.match(data, "%+CENG:%d,\"%d+,(%d+),(%d+),(%d+),%d+,(%d+),(%d+)\"")
  151. end
  152. --解析正确
  153. if rssi and ci and lac and mcc and mnc then
  154. --如果是第一条,清除信息表
  155. if id == 0 then
  156. resetCellInfo()
  157. end
  158. --保存mcc、mnc、lac、ci、rssi、ta
  159. cellinfo[id + 1].mcc = mcc
  160. cellinfo[id + 1].mnc = mnc
  161. cellinfo[id + 1].lac = tonumber(lac)
  162. cellinfo[id + 1].ci = tonumber(ci)
  163. cellinfo[id + 1].rssi = (tonumber(rssi) == 99) and 0 or tonumber(rssi)
  164. cellinfo[id + 1].ta = tonumber(ta or "0")
  165. --产生一个内部消息CELL_INFO_IND,表示读取到了新的当前小区和临近小区信息
  166. if id == 0 then
  167. if multicellcb then multicellcb(cellinfo) end
  168. publish("CELL_INFO_IND", cellinfo)
  169. end
  170. end
  171. end
  172. end
  173. -- crsm更新计数
  174. local crsmUpdCnt = 0
  175. --- 更新FPLMN的应答处理
  176. -- @string cmd ,此应答对应的AT命令
  177. -- @bool success ,AT命令执行结果,true或者false
  178. -- @string response ,AT命令的应答中的执行结果字符串
  179. -- @string intermediate ,AT命令的应答中的中间信息
  180. -- @return 无
  181. function crsmResponse(cmd, success, response, intermediate)
  182. log.debug("net.crsmResponse", success)
  183. if success then
  184. sys.restart("net.crsmResponse suc")
  185. else
  186. crsmUpdCnt = crsmUpdCnt + 1
  187. if crsmUpdCnt >= 3 then
  188. sys.restart("net.crsmResponse tmout")
  189. else
  190. ril.request("AT+CRSM=214,28539,0,0,12,\"64f01064f03064f002fffff\"", nil, crsmResponse)
  191. end
  192. end
  193. end
  194. --[[
  195. 函数名:neturc
  196. 功能 :本功能模块内“注册的底层core通过虚拟串口主动上报的通知”的处理
  197. 参数 :
  198. data:通知的完整字符串信息
  199. prefix:通知的前缀
  200. 返回值:无
  201. ]]
  202. local function neturc(data, prefix)
  203. if prefix == "+CREG" then
  204. --收到网络状态变化时,更新一下信号值
  205. csqQueryPoll()
  206. --解析creg信息
  207. creg(data)
  208. elseif prefix == "+CENG" then
  209. --解析ceng信息
  210. ceng(data)
  211. elseif prefix == "+CRSM" then
  212. local str = string.lower(data)
  213. if string.match(str, "64f000") or string.match(str, "64f020") or string.match(str, "64f040") or string.match(str, "64f070") then
  214. ril.request("AT+CRSM=214,28539,0,0,12,\"64f01064f03064f002fffff\"", nil, crsmResponse)
  215. end
  216. end
  217. end
  218. --- 飞行模式开关
  219. -- @bool mode,true:飞行模式开,false:飞行模式关
  220. -- @return 无
  221. -- @usage net.switchFly(mode)
  222. function switchFly(mode)
  223. if flyMode == mode then return end
  224. flyMode = mode
  225. -- 处理飞行模式
  226. if mode then
  227. ril.request("AT+CFUN=4")
  228. -- 处理退出飞行模式
  229. else
  230. ril.request("AT+CFUN=1")
  231. --处理查询定时器
  232. csqQueryPoll()
  233. cengQueryPoll()
  234. --复位GSM网络状态
  235. neturc("2", "+CREG")
  236. end
  237. end
  238. --- 获取GSM网络注册状态
  239. -- @return string ,GSM网络注册状态(INIT、REGISTERED、UNREGISTER)
  240. -- @usage net.getState()
  241. function getState()
  242. return state
  243. end
  244. --- 获取当前小区的mcc
  245. -- @return string ,当前小区的mcc,如果还没有注册GSM网络,则返回sim卡的mcc
  246. -- @usage net.getMcc()
  247. function getMcc()
  248. return cellinfo[1].mcc or sim.getMcc()
  249. end
  250. --- 获取当前小区的mnc
  251. -- @return string ,当前小区的mnc,如果还没有注册GSM网络,则返回sim卡的mnc
  252. -- @usage net.getMnc()
  253. function getMnc()
  254. return cellinfo[1].mnc or sim.getMnc()
  255. end
  256. --- 获取当前位置区ID
  257. -- @return string ,当前位置区ID(16进制字符串,例如"18be"),如果还没有注册GSM网络,则返回""
  258. -- @usage net.getLac()
  259. function getLac()
  260. return lac
  261. end
  262. --- 获取当前小区ID
  263. -- @return string ,当前小区ID(16进制字符串,例如"93e1"),如果还没有注册GSM网络,则返回""
  264. -- @usage net.getCi()
  265. function getCi()
  266. return ci
  267. end
  268. --- 获取信号强度
  269. -- @return number ,当前信号强度(取值范围0-31)
  270. -- @usage net.getRssi()
  271. function getRssi()
  272. return rssi
  273. end
  274. --- 获取当前和临近小区以及信号强度的拼接字符串
  275. -- @return string ,当前和临近小区以及信号强度的拼接字符串,例如:49234.30.49233.23.49232.18.
  276. -- @usage net.getCell()
  277. function getCell()
  278. local i, ret = 1, ""
  279. for i = 1, cellinfo.cnt do
  280. if cellinfo[i] and cellinfo[i].lac and cellinfo[i].lac ~= 0 and cellinfo[i].ci and cellinfo[i].ci ~= 0 then
  281. ret = ret .. cellinfo[i].ci .. "." .. cellinfo[i].rssi .. "."
  282. end
  283. end
  284. return ret
  285. end
  286. --- 获取当前和临近位置区、小区以及信号强度的拼接字符串
  287. -- @return string ,当前和临近位置区、小区以及信号强度的拼接字符串,例如:6311.49234.30;6311.49233.23;6322.49232.18;
  288. -- @usage net.getCellInfo()
  289. function getCellInfo()
  290. local i, ret = 1, ""
  291. for i = 1, cellinfo.cnt do
  292. if cellinfo[i] and cellinfo[i].lac and cellinfo[i].lac ~= 0 and cellinfo[i].ci and cellinfo[i].ci ~= 0 then
  293. ret = ret .. cellinfo[i].lac .. "." .. cellinfo[i].ci .. "." .. cellinfo[i].rssi .. ";"
  294. end
  295. end
  296. return ret
  297. end
  298. --- 获取当前和临近位置区、小区、mcc、mnc、以及信号强度的拼接字符串
  299. -- @return string ,当前和临近位置区、小区、mcc、mnc、以及信号强度的拼接字符串,例如:460.01.6311.49234.30;460.01.6311.49233.23;460.02.6322.49232.18;
  300. -- @usage net.getCellInfoExt()
  301. function getCellInfoExt()
  302. local i, ret = 1, ""
  303. for i = 1, cellinfo.cnt do
  304. if cellinfo[i] and cellinfo[i].mcc and cellinfo[i].mnc and cellinfo[i].lac and cellinfo[i].lac ~= 0 and cellinfo[i].ci and cellinfo[i].ci ~= 0 then
  305. ret = ret .. cellinfo[i].mcc .. "." .. cellinfo[i].mnc .. "." .. cellinfo[i].lac .. "." .. cellinfo[i].ci .. "." .. cellinfo[i].rssi .. ";"
  306. end
  307. end
  308. return ret
  309. end
  310. --- 获取TA值
  311. -- @return string ,TA值
  312. -- @usage net.getTa()
  313. function getTa()
  314. return cellinfo[1].ta
  315. end
  316. --[[
  317. 函数名:rsp
  318. 功能 :本功能模块内“通过虚拟串口发送到底层core软件的AT命令”的应答处理
  319. 参数 :
  320. cmd:此应答对应的AT命令
  321. success:AT命令执行结果,true或者false
  322. response:AT命令的应答中的执行结果字符串
  323. intermediate:AT命令的应答中的中间信息
  324. 返回值:无
  325. ]]
  326. local function rsp(cmd, success, response, intermediate)
  327. local prefix = string.match(cmd, "AT(%+%u+)")
  328. if intermediate ~= nil then
  329. if prefix == "+CSQ" then
  330. local s = string.match(intermediate, "+CSQ:%s*(%d+)")
  331. if s ~= nil then
  332. rssi = tonumber(s)
  333. rssi = rssi == 99 and 0 or rssi
  334. --产生一个内部消息GSM_SIGNAL_REPORT_IND,表示读取到了信号强度
  335. publish("GSM_SIGNAL_REPORT_IND", success, rssi)
  336. end
  337. elseif prefix == "+CFUN" then
  338. publish("FLYMODE", flyMode)
  339. elseif prefix == "+CENG" then end
  340. end
  341. end
  342. --- 读取“当前和临近小区信息”
  343. -- @param cb:回调函数,当读取到小区信息后,会调用此回调函数,调用形式为cb(cells),其中cells为string类型,格式为:当前和临近位置区、小区、mcc、mnc、以及信号强度的拼接字符串,例如:460.01.6311.49234.30;460.01.6311.49233.23;460.02.6322.49232.18;
  344. -- @return 无
  345. function getmulticell(cb)
  346. multicellcb = cb
  347. --发送AT+CENG?查询
  348. ril.request("AT+CENG?")
  349. end
  350. --- 查询基站信息(当前和临近小区信息)
  351. -- @number period 查询间隔,单位毫秒
  352. -- @return bool , true:查询成功,false:查询停止
  353. -- @usage net.cengQueryPoll() --查询1次
  354. -- @usage net.cengQueryPoll(60000) --每分钟查询1次
  355. function cengQueryPoll(period)
  356. -- 不是飞行模式 并且 工作模式为完整模式
  357. if not flyMode then
  358. if nil ~= period then
  359. --启动定时器
  360. sys.timer_start(cengQueryPoll, period, period)
  361. end
  362. --发送AT+CENG?查询
  363. ril.request("AT+CENG?")
  364. return true
  365. else
  366. log.info("net.cengQueryPoll", "flymode:", flyMode)
  367. return false
  368. end
  369. end
  370. --- 查询信号强度
  371. -- @number period 查询间隔,单位毫秒
  372. -- @return bool , true:查询成功,false:查询停止
  373. -- @usage net.csqQueryPoll() --查询1次
  374. -- @usage net.csqQueryPoll(60000) --每分钟查询1次
  375. function csqQueryPoll(period)
  376. --不是飞行模式 并且 工作模式为完整模式
  377. if not flyMode then
  378. if nil ~= period then
  379. --启动定时器
  380. sys.timer_start(csqQueryPoll, period, period)
  381. end
  382. --发送AT+CSQ查询
  383. ril.request("AT+CSQ")
  384. return true
  385. else
  386. log.info("net.csqQueryPoll", "flymode:", flyMode)
  387. return false
  388. end
  389. end
  390. --- 查询信号强度和基站信息(飞行模式,简单模式会返回查询失败)
  391. -- @number ... 查询周期,参数可变,参数为nil只查询1次,参数1是信号强度查询周期,参数2是基站查询周期
  392. -- @return bool ,true:查询成功,false:查询停止
  393. -- @usage net.startQueryAll()
  394. -- @usage net.startQueryAll(60000) -- 6分钟查询1次信号强度和基站信息
  395. -- @usage net.startQueryAll(60000,600000) -- 1分钟查询1次信号强度,10分钟查询1次基站信息
  396. function startQueryAll(...)
  397. if not flyMode then
  398. csqQueryPoll(arg[1])
  399. cengQueryPoll(arg[2])
  400. return true
  401. else
  402. log.info("sim.startQuerAll", "flyMode:", flyMode)
  403. return false
  404. end
  405. end
  406. --- 停止查询信号强度和基站信息
  407. -- @return 无
  408. -- @usage net.stopQueryAll()
  409. function stopQueryAll()
  410. sys.timer_stop(csqQueryPoll)
  411. sys.timer_stop(cengQueryPoll)
  412. end
  413. -- 处理SIM卡状态消息,SIM卡工作不正常时更新网络状态为未注册
  414. sys.subscribe("SIM_IND", function(para)
  415. log.info("SIM.subscribe", simerrsta, para)
  416. if simerrsta ~= (para ~= "RDY") then
  417. simerrsta = (para ~= "RDY")
  418. end
  419. --sim卡工作不正常
  420. if para ~= "RDY" then
  421. --更新GSM网络状态
  422. state = "UNREGISTER"
  423. --产生内部消息NET_STATE_CHANGED,表示网络状态发生变化
  424. publish("NET_STATE_UNREGISTER")
  425. else
  426. state = "INIT"
  427. end
  428. end)
  429. --注册+CREG和+CENG通知的处理函数
  430. ril.regurc("+CREG", neturc)
  431. ril.regurc("+CENG", neturc)
  432. ril.regurc("+CRSM", neturc)
  433. --注册AT+CCSQ和AT+CENG?命令的应答处理函数
  434. ril.regrsp("+CSQ", rsp)
  435. ril.regrsp("+CENG", rsp)
  436. ril.regrsp("+CFUN", rsp)-- 飞行模式
  437. --发送AT命令
  438. ril.request("AT+CREG=2")
  439. ril.request("AT+CREG?")
  440. ril.request("AT+CENG=1,1")
  441. --重置当前小区和临近小区信息表
  442. resetCellInfo()