sms.lua 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. --- 模块功能:短信功能
  2. -- @module sms
  3. -- @author openLuat
  4. -- @license MIT
  5. -- @copyright openLuat
  6. -- @release 2018.03.25
  7. require "sys"
  8. require "ril"
  9. require "common"
  10. require "utils"
  11. module(..., package.seeall)
  12. local publish = sys.publish
  13. local req = ril.request
  14. --ready:底层短信功能是否准备就绪
  15. local smsReady, isn, tlongsms, netReady, cpinReady,smsUrcReady = false, 255, {}
  16. local ssub, slen, sformat, smatch = string.sub, string.len, string.format, string.match
  17. local tsend = {}
  18. --[[
  19. 函数名:numtobcdnum
  20. 功能 :号码ASCII字符串 转化为 BCD编码格式字符串,仅支持数字和+,例如"+8618126324567" -> 91688121364265f7 (表示第1个字节是0x91,第2个字节为0x68,......)
  21. 参数 :
  22. num:待转换字符串
  23. 返回值:转换后的字符串
  24. ]]
  25. local function numtobcdnum(num)
  26. local len, numfix, convnum = slen(num), "81", ""
  27. if ssub(num, 1, 1) == "+" then
  28. numfix = "91"
  29. len = len - 1
  30. num = ssub(num, 2, -1)
  31. end
  32. if len % 2 ~= 0 then --奇数位
  33. for i = 1, (len - (len % 2)) / 2 do
  34. convnum = convnum .. ssub(num, i * 2, i * 2) .. ssub(num, i * 2 - 1, i * 2 - 1)
  35. end
  36. convnum = convnum .. "F" .. ssub(num, len, len)
  37. else --偶数位
  38. for i = 1, (len - (len % 2)) / 2 do
  39. convnum = convnum .. ssub(num, i * 2, i * 2) .. ssub(num, i * 2 - 1, i * 2 - 1)
  40. end
  41. end
  42. return numfix .. convnum
  43. end
  44. --[[
  45. 函数名:bcdnumtonum
  46. 功能 :BCD编码格式字符串 转化为 号码ASCII字符串,仅支持数字和+,例如91688121364265f7 (表示第1个字节是0x91,第2个字节为0x68,......) -> "+8618126324567"
  47. 参数 :
  48. num:待转换字符串
  49. 返回值:转换后的字符串
  50. ]]
  51. local function bcdnumtonum(num)
  52. local len, numfix, convnum = slen(num), "", ""
  53. if len % 2 ~= 0 then
  54. print("your bcdnum is err " .. num)
  55. return
  56. end
  57. if ssub(num, 1, 2) == "91" then
  58. numfix = "+"
  59. end
  60. len, num = len - 2, ssub(num, 3, -1)
  61. for i = 1, (len - (len % 2)) / 2 do
  62. convnum = convnum .. ssub(num, i * 2, i * 2) .. ssub(num, i * 2 - 1, i * 2 - 1)
  63. end
  64. if ssub(convnum, len, len) == "f" or ssub(convnum, len, len) == "F" then
  65. convnum = ssub(convnum, 1, -2)
  66. end
  67. return numfix .. convnum
  68. end
  69. --[[
  70. 函数名:_send
  71. 功能 :发送短信(内部接口)
  72. 参数 :num,号码
  73. data:短信内容
  74. 返回值:true:发送成功,false发送失败
  75. ]]
  76. local function _send(num, data)
  77. local numlen, datalen, pducnt, pdu, pdulen, udhi = sformat("%02X", slen(num)), slen(data) / 2, 1, "", "", ""
  78. if not smsReady or not netReady then return false end
  79. --如果发送的数据大于140字节则为长短信
  80. if datalen > 140 then
  81. --计算出长短信拆分后的总条数,长短信的每包的数据实际只有134个实际要发送的短信内容,数据的前6字节为协议头
  82. pducnt = sformat("%d", (datalen + 133) / 134)
  83. pducnt = tonumber(pducnt)
  84. --分配一个序列号,范围为0-255
  85. isn = isn == 255 and 0 or isn + 1
  86. end
  87. table.insert(tsend, {sval = pducnt, rval = 0, flg = true})--sval发送的包数,rval收到的包数
  88. if ssub(num, 1, 1) == "+" then
  89. numlen = sformat("%02X", slen(num) - 1)
  90. end
  91. for i = 1, pducnt do
  92. --如果是长短信
  93. if pducnt > 1 then
  94. local len_mul
  95. len_mul = (i == pducnt and sformat("%02X", datalen - (pducnt - 1) * 134 + 6) or "8C")
  96. --udhi:6位协议头格式
  97. udhi = "050003" .. sformat("%02X", isn) .. sformat("%02X", pducnt) .. sformat("%02X", i)
  98. log.info(datalen, udhi)
  99. pdu = "005110" .. numlen .. numtobcdnum(num) .. "000800" .. len_mul .. udhi .. ssub(data, (i - 1) * 134 * 2 + 1, i * 134 * 2)
  100. --发送短短信
  101. else
  102. datalen = sformat("%02X", datalen)
  103. pdu = "001110" .. numlen .. numtobcdnum(num) .. "000800" .. datalen .. data
  104. end
  105. pdulen = slen(pdu) / 2 - 1
  106. req(sformat("%s%s", "AT+CMGS=", pdulen), pdu)
  107. end
  108. return true
  109. end
  110. --[[
  111. 函数名:read
  112. 功能 :读短信
  113. 参数 :pos短信位置
  114. 返回值:true:读成功,false读失败
  115. ]]
  116. function read(pos)
  117. if not smsReady or pos == nil or pos == 0 then return false end
  118. req("AT+CMGR=" .. pos)
  119. return true
  120. end
  121. --[[
  122. 函数名:delete
  123. 功能 :删除短信
  124. 参数 :pos短信位置
  125. 返回值:true:删除成功,false删除失败
  126. ]]
  127. function delete(pos)
  128. if not smsReady or pos == nil or pos == 0 then return false end
  129. req("AT+CMGD=" .. pos)
  130. return true
  131. end
  132. Charmap = {[0] = 0x40, 0xa3, 0x24, 0xa5, 0xe8, 0xE9, 0xF9, 0xEC, 0xF2, 0xC7, 0x0A, 0xD8, 0xF8, 0x0D, 0xC5, 0xE5
  133. , 0x0394, 0x5F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8, 0x03A3, 0x0398, 0x039E, 0x1B, 0xC6, 0xE5, 0xDF, 0xA9
  134. , 0x20, 0x21, 0x22, 0x23, 0xA4, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F
  135. , 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
  136. , 0xA1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F
  137. , 0X50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0xC4, 0xD6, 0xD1, 0xDC, 0xA7
  138. , 0xBF, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F
  139. , 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xE4, 0xF6, 0xF1, 0xFC, 0xE0}
  140. Charmapctl = {[10] = 0x0C, [20] = 0x5E, [40] = 0x7B, [41] = 0x7D, [47] = 0x5C, [60] = 0x5B, [61] = 0x7E
  141. , [62] = 0x5D, [64] = 0x7C, [101] = 0xA4}
  142. --[[
  143. 函数名:gsm7bitdecode
  144. 功能 :7位编码, 在PDU模式中,当使用7位编码时,最多可发160个字符
  145. 参数 :data
  146. longsms
  147. 返回值:
  148. ]]
  149. function gsm7bitdecode(data, longsms)
  150. local ucsdata, lpcnt, tmpdata, resdata, nbyte, nleft, ucslen, olddat = "", slen(data) / 2, 0, 0, 0, 0, 0
  151. if longsms then
  152. tmpdata = tonumber("0x" .. ssub(data, 1, 2))
  153. resdata = bit.rshift(tmpdata, 1)
  154. if olddat == 27 then
  155. if Charmapctl[resdata] then --特殊字符
  156. olddat, resdata = resdata, Charmapctl[resdata]
  157. ucsdata = ssub(ucsdata, 1, -5)
  158. else
  159. olddat, resdata = resdata, Charmap[resdata]
  160. end
  161. else
  162. olddat, resdata = resdata, Charmap[resdata]
  163. end
  164. ucsdata = ucsdata .. sformat("%04X", resdata)
  165. else
  166. tmpdata = tonumber("0x" .. ssub(data, 1, 2))
  167. resdata = bit.band(bit.bor(bit.lshift(tmpdata, nbyte), nleft), 0x7f)
  168. if olddat == 27 then
  169. if Charmapctl[resdata] then --特殊字符
  170. olddat, resdata = resdata, Charmapctl[resdata]
  171. ucsdata = ssub(ucsdata, 1, -5)
  172. else
  173. olddat, resdata = resdata, Charmap[resdata]
  174. end
  175. else
  176. olddat, resdata = resdata, Charmap[resdata]
  177. end
  178. ucsdata = ucsdata .. sformat("%04X", resdata)
  179. nleft = bit.rshift(tmpdata, 7 - nbyte)
  180. nbyte = nbyte + 1
  181. ucslen = ucslen + 1
  182. end
  183. for i = 2, lpcnt do
  184. tmpdata = tonumber("0x" .. ssub(data, (i - 1) * 2 + 1, i * 2))
  185. if tmpdata == nil then break end
  186. resdata = bit.band(bit.bor(bit.lshift(tmpdata, nbyte), nleft), 0x7f)
  187. if olddat == 27 then
  188. if Charmapctl[resdata] then --特殊字符
  189. olddat, resdata = resdata, Charmapctl[resdata]
  190. ucsdata = ssub(ucsdata, 1, -5)
  191. else
  192. olddat, resdata = resdata, Charmap[resdata]
  193. end
  194. else
  195. olddat, resdata = resdata, Charmap[resdata]
  196. end
  197. ucsdata = ucsdata .. sformat("%04X", resdata)
  198. nleft = bit.rshift(tmpdata, 7 - nbyte)
  199. nbyte = nbyte + 1
  200. ucslen = ucslen + 1
  201. if nbyte == 7 then
  202. if olddat == 27 then
  203. if Charmapctl[nleft] then --特殊字符
  204. olddat, nleft = nleft, Charmapctl[nleft]
  205. ucsdata = ssub(ucsdata, 1, -5)
  206. else
  207. olddat, nleft = nleft, Charmap[nleft]
  208. end
  209. else
  210. olddat, nleft = nleft, Charmap[nleft]
  211. end
  212. ucsdata = ucsdata .. sformat("%04X", nleft)
  213. nbyte, nleft = 0, 0
  214. ucslen = ucslen + 1
  215. end
  216. end
  217. return ucsdata, ucslen
  218. end
  219. --[[
  220. 函数名:gsm8bitdecode
  221. 功能 :8位编码
  222. 参数 :data
  223. longsms
  224. 返回值:
  225. ]]
  226. function gsm8bitdecode(data)
  227. local ucsdata, lpcnt = "", slen(data) / 2
  228. for i = 1, lpcnt do
  229. ucsdata = ucsdata .. "00" .. ssub(data, (i - 1) * 2 + 1, i * 2)
  230. end
  231. return ucsdata, lpcnt
  232. end
  233. --[[
  234. 函数名:rsp
  235. 功能 :AT应答
  236. 参数 :cmd,success,response,intermediate
  237. 返回值:无
  238. ]]
  239. local function rsp(cmd, success, response, intermediate)
  240. local prefix = smatch(cmd, "AT(%+%u+)")
  241. log.info("lib_sms rsp", prefix, cmd, success, response, intermediate)
  242. --读短信成功
  243. if prefix == "+CMGR" then
  244. if not success then publish("SMS_READ_CNF") return end
  245. local convnum, t, stat, alpha, len, pdu, data, longsms, total, isn, idx = "", ""
  246. if intermediate then
  247. stat, alpha, len, pdu = smatch(intermediate, "+CMGR:%s*(%d),(.*),%s*(%d+)\r\n(%x+)")
  248. len = tonumber(len)--PDU数据长度,不包括短信息中心号码
  249. end
  250. --收到的PDU包不为空则解析PDU包
  251. if pdu and pdu ~= "" then
  252. local offset, addlen, addnum, flag, dcs, tz, txtlen, fo = 5
  253. pdu = ssub(pdu, (slen(pdu) / 2 - len) * 2 + 1, -1)--PDU数据,不包括短信息中心号码
  254. fo = tonumber("0x" .. ssub(pdu, 1, 1))--PDU短信首字节的高4位,第6位为数据报头标志位
  255. if bit.band(fo, 0x4) ~= 0 then
  256. longsms = true
  257. end
  258. addlen = tonumber(sformat("%d", "0x" .. ssub(pdu, 3, 4)))--回复地址数字个数
  259. addlen = addlen % 2 == 0 and addlen + 2 or addlen + 3 --加上号码类型2位(5,6)or 加上号码类型2位(5,6)和1位F
  260. offset = offset + addlen
  261. addnum = ssub(pdu, 5, 5 + addlen - 1)
  262. convnum = bcdnumtonum(addnum)
  263. flag = tonumber(sformat("%d", "0x" .. ssub(pdu, offset, offset + 1)))--协议标识 (TP-PID)
  264. offset = offset + 2
  265. dcs = tonumber(sformat("%d", "0x" .. ssub(pdu, offset, offset + 1)))--用户信息编码方式 Dcs=8,表示短信存放的格式为UCS2编码
  266. offset = offset + 2
  267. tz = ssub(pdu, offset, offset + 13)--时区7个字节
  268. offset = offset + 14
  269. txtlen = tonumber(sformat("%d", "0x" .. ssub(pdu, offset, offset + 1)))--短信文本长度
  270. offset = offset + 2
  271. data = ssub(pdu, offset, offset + txtlen * 2 - 1)--短信文本
  272. if longsms then
  273. if tonumber("0x" .. ssub(data, 5, 6)) == 3 then
  274. isn, total, idx = tonumber("0x" .. ssub(data, 7, 8)), tonumber("0x" .. ssub(data, 9, 10)), tonumber("0x" .. ssub(data, 11, 12))
  275. data = ssub(data, 13, -1)--去掉报头6个字节
  276. elseif tonumber("0x" .. ssub(data, 5, 6)) == 4 then
  277. isn, total, idx = tonumber("0x" .. ssub(data, 7, 10)), tonumber("0x" .. ssub(data, 11, 12)), tonumber("0x" .. ssub(data, 13, 14))
  278. data = ssub(data, 15, -1)--去掉报头7个字节
  279. end
  280. end
  281. log.info("TP-PID : ", flag, "dcs: ", dcs, "tz: ", tz, "data: ", data, "txtlen", txtlen)
  282. if dcs == 0x00 then --7bit encode
  283. local newlen
  284. data, newlen = gsm7bitdecode(data, longsms)
  285. if newlen > txtlen then
  286. data = ssub(data, 1, txtlen * 4)
  287. end
  288. log.info("7bit to ucs2 data: ", data, "txtlen", txtlen, "newlen", newlen)
  289. elseif dcs == 0x04 then --8bit encode
  290. data, txtlen = gsm8bitdecode(data)
  291. log.info("8bit to ucs2 data: ", data, "txtlen", txtlen)
  292. end
  293. for i = 1, 7 do
  294. t = t .. ssub(tz, i * 2, i * 2) .. ssub(tz, i * 2 - 1, i * 2 - 1)
  295. if i <= 3 then
  296. t = i < 3 and (t .. "/") or (t .. ",")
  297. elseif i <= 6 then
  298. t = i < 6 and (t .. ":") or (t .. "+")
  299. end
  300. end
  301. end
  302. local pos = smatch(cmd, "AT%+CMGR=(%d+)")
  303. data = data or ""
  304. alpha = alpha or ""
  305. publish("SMS_READ_CNF", success, convnum, data, pos, t, alpha, total, idx, isn)
  306. elseif prefix == "+CMGD" then
  307. publish("SMS_DELETE_CNF", success)
  308. elseif prefix == "+CMGS" then
  309. --如果是短短信,直接发送短信确认消息
  310. if tsend[1].sval == 1 then --{sval=pducnt,rval=0,flg=true}
  311. table.remove(tsend, 1)
  312. publish("SMS_SEND_CNF", success)
  313. --如果是长短信,所有cmgs之后,才抛出SMS_SEND_CNF,所有cmgs都成功,才true,其余都是false
  314. else
  315. tsend[1].rval = tsend[1].rval + 1
  316. --只要其中有发送失败的短信,则整个长短信将标记为发送失败
  317. if not success then tsend[1].flg = false end
  318. if tsend[1].sval == tsend[1].rval then
  319. publish("SMS_SEND_CNF", tsend[1].flg)
  320. table.remove(tsend, 1)
  321. end
  322. end
  323. end
  324. end
  325. local function init()
  326. if cpinReady and smsUrcReady and netReady then
  327. --使用PDU模式发送
  328. req("AT+CMGF=0")
  329. --设置短信TEXT 模式参数
  330. -- req("AT+CSMP=17,167,0,8")
  331. --设置AT命令的字符编码是UCS2
  332. req('AT+CSCS="UCS2"')
  333. --设置存储区为SM
  334. req('AT+CPMS="SM"')
  335. -- 上报消息CMTI
  336. req("AT+CNMI=2,1,0,0,0")
  337. --分发短信准备好消息
  338. publish("SMS_READY")
  339. --清空已读短信
  340. req("AT+CMGD=1,3")
  341. end
  342. end
  343. --[[
  344. 函数名:urc
  345. 功能 :主动上报消息处理函数
  346. 参数 :data,prefix
  347. 返回值:无
  348. ]]
  349. local function urc(data, prefix)
  350. --短信准备好
  351. if data == "SMS READY" then
  352. smsUrcReady = true
  353. init()
  354. -- 存储短信
  355. elseif prefix == "+CMTI" then
  356. --分发收到新短信消息
  357. publish("SMS_NEW_MSG_IND", smatch(data, "(%d+)", slen(prefix) + 1))
  358. end
  359. end
  360. --[[
  361. 函数名:getsmsstate
  362. 功能 :获取短消息是否准备好的状态
  363. 参数 :无
  364. 返回值:true准备好,其他值:未准备好
  365. ]]
  366. function getsmsstate()
  367. return smsReady
  368. end
  369. --[[
  370. 函数名:mergelongsms
  371. 功能 :合并长短信
  372. 参数 :
  373. tag:长短信标记(ISN和总条数的拼接字符串)
  374. 返回值:无
  375. ]]
  376. local function mergelongsms(tag)
  377. local data = ""
  378. --按表中的顺序,一次拼接短消息内容
  379. for i = 1, tlongsms[tag]["total"] do
  380. data = data .. (tlongsms[tag]["dat"][i] or "")
  381. end
  382. --分发长短信合并确认消息
  383. publish("LONG_SMS_MERGR_CNF", true, tlongsms[tag]["num"], data, tlongsms[tag]["t"], tlongsms[tag]["nam"])
  384. log.info("mergelongsms", "num:", tlongsms[tag]["num"], "data", data)
  385. tlongsms[tag]["dat"], tlongsms[tag] = nil
  386. end
  387. --[[
  388. 函数名:longsmsind
  389. 功能 :长短信被拆解后的消息包上报
  390. 参数 :id,num, data,datetime,name,total,idx,isn
  391. 返回值:无
  392. ]]
  393. local function longsmsind(num, data, datetime, name, total, idx, isn)
  394. log.info("longsmsind", "isn", isn, "total:", total, "idx:", idx, "data", data)
  395. if tlongsms[isn .. total] then
  396. if not tlongsms[isn .. total]["dat"] then tlongsms[isn .. total]["dat"] = {} end
  397. tlongsms[isn .. total]["dat"][idx] = data
  398. else
  399. tlongsms[isn .. total] = {}
  400. tlongsms[isn .. total]["total"], tlongsms[isn .. total]["num"], tlongsms[isn .. total]["t"], tlongsms[isn .. total]["nam"] = total, num, datetime, name
  401. tlongsms[isn .. total]["dat"] = {}
  402. tlongsms[isn .. total]["dat"][idx] = data
  403. end
  404. local totalrcv = 0
  405. for i = 1, tlongsms[isn .. total]["total"] do
  406. if tlongsms[isn .. total]["dat"][i] then totalrcv = totalrcv + 1 end
  407. end
  408. --长短信接收完整
  409. if tlongsms[isn .. total]["total"] == totalrcv then
  410. sys.timerStop(mergelongsms, isn .. total)
  411. mergelongsms(isn .. total)
  412. else
  413. --如果2分钟后长短信还没收完整,2分钟后将自动合并已收到的长短信
  414. sys.timerStart(mergelongsms, 120000, isn .. total)
  415. end
  416. end
  417. --注册长短信合并处理函数
  418. sys.subscribe("LONG_SMS_MERGE", longsmsind)
  419. ril.regUrc("SMS READY", urc)
  420. ril.regUrc("+CMT", urc)
  421. ril.regUrc("+CMTI", urc)
  422. ril.regRsp("+CMGR", rsp)
  423. ril.regRsp("+CMGD", rsp)
  424. ril.regRsp("+CMGS", rsp)
  425. --短信发送缓冲表最大个数
  426. local SMS_SEND_BUF_MAX_CNT = 10
  427. --短信发送间隔,单位毫秒
  428. local SMS_SEND_INTERVAL = 3000
  429. --短信发送缓冲表
  430. local tsmsnd = {}
  431. --[[
  432. 函数名:sndnxt
  433. 功能 :发送短信发送缓冲表中的第一条短信
  434. 参数 :无
  435. 返回值:无
  436. ]]
  437. local function sndnxt()
  438. if #tsmsnd > 0 then
  439. _send(tsmsnd[1].num, tsmsnd[1].data)
  440. end
  441. end
  442. --[[
  443. 函数名:sendcnf
  444. 功能 :SMS_SEND_CNF消息的处理函数,异步通知短信发送结果
  445. 参数 :
  446. result:短信发送结果,true为成功,false或者nil为失败
  447. 返回值:无
  448. ]]
  449. local function sendcnf(result)
  450. log.info("sendcnf", result)
  451. local num, data, cb = tsmsnd[1].num, tsmsnd[1].data, tsmsnd[1].cb
  452. --从短信发送缓冲表中移除当前短信
  453. table.remove(tsmsnd, 1)
  454. --如果有发送回调函数,执行回调
  455. if cb then cb(result, num, data) end
  456. --如果短信发送缓冲表中还有短信,则SMS_SEND_INTERVAL毫秒后,继续发送下条短信
  457. if #tsmsnd > 0 then sys.timerStart(sndnxt, SMS_SEND_INTERVAL) end
  458. end
  459. --- 发送短信
  460. -- @string num 短信接收方号码,ASCII码字符串格式
  461. -- @string data 短信内容,GB2312编码的字符串
  462. -- 如果短信内容中只有ascii可见字符,则超过160个字符时,会被拆分为几条长级联短信进行发送
  463. -- 如果短信内容中包含除ascii可见字符外的其他字符,例如包含汉字,一个汉字算作一个字符,一个ascii可见字符也算作一个字符,超过70个字符时,会被拆分为几条长级联短信进行发送
  464. -- @function[opt=nil] cbFnc 短信发送结果异步返回时的用户回调函数,回调函数的调用形式为:
  465. -- cbFnc(result,num,data)
  466. -- num:短信接收方的号码,ASCII码字符串格式
  467. -- data:短信内容,unicode大端编码的HEX字符串
  468. -- @number[opt=nil] idx 插入短信发送缓冲表的位置,默认是插入末尾
  469. -- @return result,true表示调用接口成功(并不是短信发送成功,短信发送结果,通过sendcnf返回,如果有cbFnc,会通知cbFnc函数);返回false,表示调用接口失败
  470. -- @usage sms.send("10086","test",cbFnc)
  471. function send(num, data, cbFnc, idx)
  472. --号码或者内容非法
  473. if not num or num == "" or not data or data == "" then if cbFnc then cbFnc(false, num, data) end return end
  474. --短信发送缓冲表已满
  475. if #tsmsnd >= SMS_SEND_BUF_MAX_CNT then if cbFnc then cbFnc(false, num, data) end return end
  476. local dat = string.toHex(common.gb2312ToUcs2be(data))
  477. --如果指定了插入位置
  478. if idx then
  479. table.insert(tsmsnd, idx, {num = num, data = dat, cb = cbFnc})
  480. --没有指定插入位置,插入到末尾
  481. else
  482. table.insert(tsmsnd, {num = num, data = dat, cb = cbFnc})
  483. end
  484. --如果短信发送缓冲表中只有一条短信,立即触发短信发送动作
  485. if #tsmsnd == 1 then _send(num, dat) return true end
  486. end
  487. --短信接收位置表
  488. local tnewsms = {}
  489. --[[
  490. 函数名:readsms
  491. 功能 :读取短信接收位置表中的第一条短信
  492. 参数 :无
  493. 返回值:无
  494. ]]
  495. local function readsms()
  496. if #tnewsms ~= 0 then
  497. read(tnewsms[1])
  498. end
  499. end
  500. --[[
  501. 函数名:newsms
  502. 功能 :SMS_NEW_MSG_IND(未读短信或者新短信主动上报的消息)消息的处理函数
  503. 参数 :
  504. pos:短信存储位置
  505. 返回值:无
  506. ]]
  507. local function newsms(pos)
  508. --存储位置插入到短信接收位置表中
  509. table.insert(tnewsms, pos)
  510. --如果只有一条短信,则立即读取
  511. if #tnewsms == 1 then
  512. readsms()
  513. end
  514. end
  515. --新短信的用户处理函数
  516. local newsmscb
  517. --- 设置新短信的用户处理函数
  518. -- @function cbFnc 新短信的用户处理函数
  519. -- @return nil
  520. -- @usage sms.setNewSmsCb(cbFnc)
  521. function setNewSmsCb(cbFnc)
  522. newsmscb = cbFnc
  523. end
  524. --[[
  525. 函数名:readcnf
  526. 功能 :SMS_READ_CNF消息的处理函数,异步返回读取的短信内容
  527. 参数 :
  528. result:短信读取结果,true为成功,false或者nil为失败
  529. num:短信号码,ASCII码字符串格式
  530. data:短信内容,UCS2大端格式的16进制字符串
  531. pos:短信的存储位置,暂时没用
  532. datetime:短信日期和时间,ASCII码字符串格式
  533. name:短信号码对应的联系人姓名,暂时没用
  534. 返回值:无
  535. ]]
  536. local function readcnf(result, num, data, pos, datetime, name, total, idx, isn)
  537. if result then
  538. --过滤号码中的86和+86
  539. local d1, d2 = string.find(num, "^([%+]*86)")
  540. if d1 and d2 then
  541. num = string.sub(num, d2 + 1, -1)
  542. end
  543. --删除短信
  544. delete(tnewsms[1])
  545. --从短信接收位置表中删除此短信的位置
  546. table.remove(tnewsms, 1)
  547. if total and total > 1 then
  548. publish("LONG_SMS_MERGE", num, data, datetime, name, total, idx, isn)
  549. readsms()--读取下一条新短信
  550. return
  551. end
  552. if data then
  553. --短信内容转换为GB2312字符串格式
  554. data = common.ucs2beToGb2312(data:fromHex())
  555. --用户应用程序处理短信
  556. if newsmscb then newsmscb(num, data, datetime) end
  557. end
  558. --继续读取下一条短信
  559. readsms()
  560. else
  561. --删除短信
  562. delete(tnewsms[1])
  563. --从短信接收位置表中删除此短信的位置
  564. table.remove(tnewsms, 1)
  565. --继续读取下一条短信
  566. readsms()
  567. end
  568. end
  569. local function longsmsmergecnf(res, num, data, datetime)
  570. --log.info("longsmsmergecnf",num,data,datetime)
  571. if data then
  572. --短信内容转换为GB2312字符串格式
  573. data = common.ucs2beToGb2312(data:fromHex())
  574. --用户应用程序处理短信
  575. if newsmscb then newsmscb(num, data, datetime) end
  576. end
  577. end
  578. sys.subscribe("SMS_NEW_MSG_IND", newsms)
  579. sys.subscribe("SMS_READ_CNF", readcnf)
  580. sys.subscribe("SMS_SEND_CNF", sendcnf)
  581. sys.subscribe("SMS_READY",
  582. function()
  583. if not smsReady then
  584. smsReady = true
  585. if netReady then sndnxt() end
  586. end
  587. end
  588. )
  589. sys.subscribe("NET_STATE_REGISTERED",
  590. function()
  591. if not netReady then
  592. netReady = true
  593. init()
  594. if smsReady then sndnxt() end
  595. end
  596. end
  597. )
  598. sys.subscribe("SIM_IND",
  599. function(para)
  600. if para=="RDY" and not cpinReady then
  601. cpinReady = true
  602. init()
  603. end
  604. end
  605. )
  606. sys.subscribe("LONG_SMS_MERGR_CNF", longsmsmergecnf)
  607. -- 此处为临时AT+CNMI补丁
  608. sys.timerStart(req, 30000, "AT+CNMI=2,1,0,0,0")