| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642 |
- --- 模块功能:esp8266 wifi模块AT命令交互管理
- -- @module wifiRil
- -- @author openLuat
- -- @license MIT
- -- @copyright openLuat
- -- @release 2017.02.13
- -- require "uart"
- -- require "rtos"
- require "sys"
- require "log"
- module(..., package.seeall)
- local UART_ID = 1
- --加载常用的全局函数至本地
- local vwrite = uart.write
- local vread = uart.read
- --是否为透传模式,true为透传模式,false或者nil为非透传模式
- --默认非透传模式
- local transparentmode
- --透传模式下,虚拟串口数据接收的处理函数
- local rcvfunc
- local uartswitch
- --cipsend执行完毕的flag
- local cipsendflag
- --执行AT命令后1分钟无反馈,判定at命令执行失败,则重启软件
- local TIMEOUT,DATA_TIMEOUT = 120000,120000
- --AT命令的应答类型
- --NORESULT:收到的应答数据当做urc通知处理,如果发送的AT命令不处理应答或者没有设置类型,默认为此类型
- --NUMBERIC:纯数字类型;例如发送AT+CGSN命令,应答的内容为:862991527986589\r\nOK,此类型指的是862991527986589这一部分为纯数字类型
- --SLINE:有前缀的单行字符串类型;例如发送AT+CSQ命令,应答的内容为:+CSQ: 23,99\r\nOK,此类型指的是+CSQ: 23,99这一部分为单行字符串类型
- --MLINE:有前缀的多行字符串类型;例如发送AT+CMGR=5命令,应答的内容为:+CMGR: 0,,84\r\n0891683108200105F76409A001560889F800087120315123842342050003590404590D003A59\r\nOK,此类型指的是OK之前为多行字符串类型
- --STRING:无前缀的字符串类型,例如发送AT+ATWMFT=99命令,应答的内容为:SUCC\r\nOK,此类型指的是SUCC
- --SPECIAL:特殊类型,需要针对AT命令做特殊处理,例如CIPSEND、CIPCLOSE、CIFSR
- local NORESULT, NUMBERIC, SLINE, MLINE, STRING, SPECIAL = 0, 1, 2, 3, 4, 10
- --AT命令的应答类型表,预置了如下几项
- local RILCMD = {
- ["+CSQ"] = 2,
- ["+MUID"] = 2,
- ["+CGSN"] = 1,
- ["+WISN"] = 4,
- ["+CIMI"] = 1,
- ["+CCID"] = 1,
- ["+CGATT"] = 2,
- ["+CCLK"] = 2,
- ["+ATWMFT"] = 4,
- ["+CMGR"] = 3,
- ["+CMGS"] = 2,
- ["+CPBF"] = 3,
- ["+CPBR"] = 3,
- ['+CLCC'] = 3,
- ['+CNUM'] = 3,
- ["+CIPSEND"] = 10,
- ["+CIPCLOSE"] = 10,
- ["+SSLINIT"] = 10,
- ["+SSLCERT"] = 10,
- ["+SSLCREATE"] = 10,
- ["+SSLCONNECT"] = 10,
- ["+SSLSEND"] = 10,
- ["+SSLDESTROY"] = 10,
- ["+SSLTERM"] = 10,
- ["+CIFSR"] = 10,
- ["+CTFSGETID"] = 2,
- ["+CTFSDECRYPT"] = 2,
- ["+CTFSAUTH"] = 2,
- ["+ALIPAYOPEN"] = 2,
- ["+ALIPAYREP"] = 2,
- ["+ALIPAYPINFO"] = 2,
- ["+ALIPAYACT"] = 2,
- ["+ALIPAYDID"] = 2,
- ["+ALIPAYSIGN"] = 2
- }
- --radioready:AT命令通道是否准备就绪
- --delaying:执行完某些AT命令前,需要延时一段时间,才允许执行这些AT命令;此标志表示是否在延时状态
- local radioready, delaying = false
- --AT命令队列
- local cmdqueue = {
- "ATE0",
- -- "AT+SYSLOG=0",
- 'AT+CIPSNTPCFG=1,8,"cn.ntp.org.cn","ntp.sjtu.edu.cn"',
- }
- --当前正在执行的AT命令,参数,反馈回调,延迟执行时间,命令头,类型,反馈格式
- local currcmd, currarg, currsp, curdelay, cmdhead, cmdtype, rspformt, cmdRspParam
- --反馈结果,中间信息,结果信息
- local result, interdata, respdata
- local sslCreating
- --ril会出现三种情况:
- --发送AT命令,收到应答
- --发送AT命令,命令超时没有应答
- --底层软件主动上报的通知,下文我们简称为urc
- --[[
- 函数名:atimeout
- 功能 :发送AT命令,命令超时没有应答的处理
- 参数 :无
- 返回值:无
- ]]
- local function atimeout()
- --重启软件
- sys.restart("wifiRil.atimeout_" .. (currcmd or ""))
- end
- --[[
- 函数名:defrsp
- 功能 :AT命令的默认应答处理。如果没有定义某个AT的应答处理函数,则会走到本函数
- 参数 :
- cmd:此应答对应的AT命令
- success:AT命令执行结果,true或者false
- response:AT命令的应答中的执行结果字符串
- intermediate:AT命令的应答中的中间信息
- 返回值:无
- ]]
- local function defrsp(cmd, success, response, intermediate)
- log.info("wifiRil.defrsp", cmd, success, response, intermediate)
- end
- --AT命令的应答处理表
- local rsptable = {}
- setmetatable(rsptable, {
- __index = function()
- return defrsp
- end
- })
- --自定义的AT命令应答格式表,当AT命令应答为STRING格式时,用户可以进一步定义这里面的格式
- local formtab = {}
- ---注册某个AT命令应答的处理函数
- -- @param head 此应答对应的AT命令头,去掉了最前面的AT两个字符
- -- @param fnc AT命令应答的处理函数
- -- @param typ AT命令的应答类型,取值范围NORESULT,NUMBERIC,SLINE,MLINE,STRING,SPECIAL
- -- @param formt typ为STRING时,进一步定义STRING中的详细格式
- -- @return bool ,成功返回true,失败false
- -- @usage wifiRil.regRsp("+CSQ", rsp)
- function regRsp(head, fnc, typ, formt)
- --没有定义应答类型
- if typ == nil then
- rsptable[head] = fnc
- return true
- end
- --定义了合法应答类型
- if typ == 0 or typ == 1 or typ == 2 or typ == 3 or typ == 4 or typ == 10 then
- --如果AT命令的应答类型已存在,并且与新设置的不一致
- if RILCMD[head] and RILCMD[head] ~= typ then
- return false
- end
- --保存
- RILCMD[head] = typ
- rsptable[head] = fnc
- formtab[head] = formt
- return true
- else
- return false
- end
- end
- --[[
- 函数名:rsp
- 功能 :AT命令的应答处理
- 参数 :无
- 返回值:无
- ]]
- local function rsp()
- --停止应答超时定时器
- sys.timerStopAll(atimeout)
-
- --如果发送AT命令时已经同步指定了应答处理函数
- if currsp then
- currsp(currcmd, result, respdata, interdata)
- --用户注册的应答处理函数表中找到处理函数
- else
- rsptable[cmdhead](currcmd, result, respdata, interdata, cmdRspParam)
- end
- --重置全局变量
- if cmdhead == "+CIPSEND" and cipsendflag then
- return
- end
- currcmd, currarg, currsp, curdelay, cmdhead, cmdtype, rspformt = nil
- result, interdata, respdata = nil
- end
- --[[
- 函数名:defurc
- 功能 :urc的默认处理。如果没有定义某个urc的应答处理函数,则会走到本函数
- 参数 :
- data:urc内容
- 返回值:无
- ]]
- local function defurc(data)
- log.info("wifiRil.defurc", data)
- end
- --urc的处理表
- local urctable = {}
- setmetatable(urctable, {
- __index = function()
- return defurc
- end
- })
- --- 注册某个urc的处理函数
- -- @param prefix urc前缀,最前面的连续字符串,包含+、大写字符、数字的组合
- -- @param handler urc的处理函数
- -- @return 无
- -- @usage wifiRil.regUrc("+CREG", neturc)
- function regUrc(prefix, handler)
- urctable[prefix] = handler
- end
- --- 解注册某个urc的处理函数
- -- @param prefix urc前缀,最前面的连续字符串,包含+、大写字符、数字的组合
- -- @return 无
- -- @usage deRegUrc("+CREG")
- function deRegUrc(prefix)
- urctable[prefix] = nil
- end
- --“数据过滤器”,虚拟串口收到的数据时,首先需要调用此函数过滤处理一下
- local urcfilter
- --[[
- 函数名:urc
- 功能 :urc处理
- 参数 :
- data:urc数据
- 返回值:无
- ]]
- local function urc(data, cmd)
- --AT通道准备就绪
- if data == "ready" then
- radioready = true
- else
- local prefix = string.match(data, "([%+%*]*[%a%d& ]+)")
- -- 执行prefix的urc处理函数,返回数据过滤器
- urcfilter = urctable[prefix](data, prefix, cmd)
- end
- end
- --[[
- 函数名:procatc
- 功能 :处理虚拟串口收到的数据
- 参数 :
- data:收到的数据
- 返回值:无
- ]]
- local function procatc(data)
- log.info("wifiRil.proatc", data)
- --如果命令的应答是多行字符串格式
- if interdata and cmdtype == MLINE then
- --不出现OK\r\n,则认为应答还未结束
- if data ~= "OK\r\n" then
- --去掉最后的\r\n
- if string.find(data, "\r\n", -2) then
- data = string.sub(data, 1, -3)
- end
- --拼接到中间数据
- interdata = interdata .. "\r\n" .. data
- return
- end
- end
- --如果存在“数据过滤器”
- if urcfilter then
- data, urcfilter = urcfilter(data)
- end
- --去掉最后的\r\n
- if not data:find("+CIPRECVDATA") then
- if string.find(data, "\r\n", -2) then
- data = string.sub(data, 1, -3)
- end
- else
- local len, tmp = data:match("%+CIPRECVDATA:(%d+),(.+)")
- if len + 2 == #tmp and string.find(data, "\r\n", -2) then
- data = string.sub(data, 1, -3)
- end
- end
- --数据为空
- if data == "" then
- return
- end
- --当前无命令在执行则判定为urc
- if currcmd == nil then
- urc(data)
- return
- end
-
- local isurc = false
-
- --一些特殊的错误信息,转化为ERROR统一处理
- if string.find(data, "^%+CMS ERROR:") or string.find(data, "^%+CME ERROR:") or (data == "CONNECT FAIL" and currcmd and string.match(currcmd, "CIPSTART")) then
- data = "ERROR"
- end
- if sslCreating and data=="+PDP: DEACT" and tonumber(string.match(rtos.get_version(),"Luat_V(%d+)_"))<31 then
- sys.publish("SSL_DNS_PARSE_PDP_DEACT")
- end
- if cmdhead == "+CIPSEND" and data == "SEND OK" then
- result = true
- respdata = data
- cipsendflag = false
- elseif cmdhead == "+CIPSEND" and data == "OK" then
- result = true
- respdata = data
- cipsendflag = true
- --执行成功的应答
- elseif data == "OK" or data == "SHUT OK" then
- result = true
- respdata = data
- --执行失败的应答
- elseif data == "ERROR" or data == "NO ANSWER" or data == "NO DIALTONE" then
- result = false
- respdata = data
- --需要继续输入参数的AT命令应答
- elseif data == ">" then
- --发送短信
- if cmdhead == "+CMGS" then
- log.info("wifiRil.procatc.send", currarg)
- vwrite(UART_ID, currarg, "\026")
- --发送数据
- elseif cmdhead == "+CIPSEND" or cmdhead == "+SSLSEND" or cmdhead == "+SSLCERT" then
- log.info("wifiRil.procatc.send", "first 200 bytes", currarg:sub(1,200))
- vwrite(UART_ID, currarg)
- elseif cmdhead == "+SYSFLASH" then
- log.info("wifiRil.sysflash.send", "first 200 bytes", currarg:sub(1,200))
- vwrite(UART_ID, currarg)
- else
- log.error("error promot cmd:", currcmd)
- end
- else
- --无类型
- if cmdtype == NORESULT then
- isurc = true
- --全数字类型
- elseif cmdtype == NUMBERIC then
- local numstr = string.match(data, "(%x+)")
- if numstr == data then
- interdata = data
- else
- isurc = true
- end
- --字符串类型
- elseif cmdtype == STRING then
- --进一步检查格式
- if string.match(data, rspformt or "^.+$") then
- interdata = data
- else
- isurc = true
- end
- elseif cmdtype == SLINE or cmdtype == MLINE then
- if interdata == nil and string.find(data, cmdhead) == 1 then
- interdata = data
- else
- isurc = true
- end
- --特殊处理
- elseif cmdhead == "+CIFSR" then
- local s = string.match(data, "%d+%.%d+%.%d+%.%d+")
- if s ~= nil then
- interdata = s
- result = true
- else
- isurc = true
- end
- --特殊处理
- elseif cmdhead == "+CIPSEND" or cmdhead == "+CIPCLOSE" then
- local keystr = cmdhead == "+CIPSEND" and "SEND" or "CLOSE"
- local lid, res = string.match(data, "(%d), *([%u%d :]+)")
-
- if data:match("^%d, *CLOSED$") then
- isurc = true
- elseif lid and res then
- if (string.find(res, keystr) == 1 or string.find(res, "TCP ERROR") == 1 or string.find(res, "UDP ERROR") == 1 or string.find(data, "DATA ACCEPT")) and (lid == string.match(currcmd, "=(%d)")) then
- result = data:match("ERROR") == nil
- respdata = data
- else
- isurc = true
- end
- elseif data == "+PDP: DEACT" then
- result = true
- respdata = data
- elseif data:match("^Recv %d+ bytes$") then
- result = true
- respdata = data
- else
- isurc = true
- end
- elseif cmdhead == "+SSLINIT" or cmdhead == "+SSLCERT" or cmdhead == "+SSLCREATE" or cmdhead == "+SSLCONNECT" or cmdhead == "+SSLSEND" or cmdhead == "+SSLDESTROY" or cmdhead == "+SSLTERM" then
- if string.match(data, "^SSL&%d, *CLOSED") or string.match(data, "^SSL&%d, *ERROR") or string.match(data, "SSL&%d,CONNECT ERROR") then
- isurc = true
- elseif string.match(data, "^SSL&%d,") then
- respdata = data
- if string.match(data, "ERROR") then
- result = false
- else
- result = true
- end
- if cmdhead == "+SSLCREATE" then
- sslCreating = false
- end
- else
- isurc = true
- end
- else
- isurc = true
- end
- end
- -- urc处理
- if isurc then
- urc(data, currcmd)
- --应答处理
- elseif result ~= nil then
- rsp()
- end
- end
- --是否在读取虚拟串口数据
- local readat = false
- --[[
- 函数名:getcmd
- 功能 :解析一条AT命令
- 参数 :
- item:AT命令
- 返回值:当前AT命令的内容
- ]]
- local function getcmd(item)
- local cmd, arg, rsp, delay, rspParam
- --命令是string类型
- if type(item) == "string" then
- --命令内容
- cmd = item
- --命令是table类型
- elseif type(item) == "table" then
- --命令内容
- cmd = item.cmd
- --命令参数
- arg = item.arg
- --命令应答处理函数
- rsp = item.rsp
- --命令延时执行时间
- delay = item.delay
- --命令携带的参数,执行回调时传入此参数
- rspParam = item.rspParam
- else
- log.info("wifiRil.getcmd", "getpack unknown item")
- return
- end
- -- 命令前缀
- local head = string.match(cmd, "AT([%+%*]*%u+)")
-
- if head == nil then
- log.error("wifiRil.getcmd", "request error cmd:", cmd)
- return
- end
- --这两个命令必须有参数
- if head == "+CMGS" or head == "+CIPSEND" then -- 必须有参数
- if arg == nil or arg == "" then
- log.error("wifiRil.getcmd", "request error no arg", head)
- return
- end
- end
- --赋值全局变量
- currcmd = cmd
- currarg = arg
- currsp = rsp
- curdelay = delay
- cmdhead = head
- cmdRspParam = rspParam
- cmdtype = RILCMD[head] or NORESULT
- rspformt = formtab[head]
-
- return currcmd
- end
- --[[
- 函数名:sendat
- 功能 :发送AT命令
- 参数 :无
- 返回值:无
- ]]
- local function sendat()
- -- AT通道未准备就绪、正在读取虚拟串口数据、有AT命令在执行或者队列无命令、正延时发送某条AT
- if not radioready or readat or currcmd ~= nil or delaying then
- return
- end
- local item
-
- while true do
- --队列无AT命令
- if #cmdqueue == 0 then
- return
- end
- --读取第一条命令
- item = table.remove(cmdqueue, 1)
- --解析命令
- getcmd(item)
- --需要延迟发送
- if curdelay then
- --启动延迟发送定时器
- sys.timerStart(delayfunc, curdelay)
- --清除全局变量
- currcmd, currarg, currsp, curdelay, cmdhead, cmdtype, rspformt, cmdRspParam = nil
- item.delay = nil
- --设置延迟发送标志
- delaying = true
- --把命令重新插入命令队列的队首
- table.insert(cmdqueue, 1, item)
- return
- end
-
- if currcmd ~= nil then
- break
- end
- end
- --启动AT命令应答超时定时器
- if currcmd:match("^AT%+CIPSTART") or currcmd:match("^AT%+CIPSEND") or currcmd:match("^AT%+SSLCREATE") or currcmd:match("^AT%+SSLCONNECT") or currcmd:match("^AT%+SSLSEND") then
- sys.timerStart(atimeout,DATA_TIMEOUT)
- else
- sys.timerStart(atimeout, TIMEOUT)
- end
-
- if currcmd:match("^AT%+SSLCREATE") then
- sslCreating = true
- end
-
- log.info("wifiRil.sendat", currcmd)
- --向虚拟串口中发送AT命令
- vwrite(UART_ID, currcmd .. "\r\n")
- end
- -- 延时执行某条AT命令的定时器回调
- -- @return 无
- -- @usage wifiRil.delayfunc()
- function delayfunc()
- --清除延时标志
- delaying = nil
- --执行AT命令发送
- sendat()
- end
- --[[
- 函数名:atcreader
- 功能 :“AT命令的虚拟串口数据接收消息”的处理函数,当虚拟串口收到数据时,会走到此函数中
- 参数 :无
- 返回值:无
- ]]
- local function atcreader()
- local s
- if not transparentmode then
- readat = true
- end
- -- 循环读取虚拟串口收到的数据
- while true do
- --每次读取一行
- s = vread(UART_ID, "*l", 0)
- if string.len(s) ~= 0 then
- if transparentmode then
- --透传模式下直接转发数据
- rcvfunc(s)
- else
- --非透传模式下处理收到的数据
- procatc(s)
- end
- else
- break
- end
- end
- if not transparentmode then
- readat = false
- --数据处理完以后继续执行AT命令发送
- sendat()
- end
- end
- --- 发送AT命令到底层软件
- -- @param cmd AT命令内容
- -- @param arg AT命令参数,例如AT+CMGS=12命令执行后,接下来会发送此参数;AT+CIPSEND=14命令执行后,接下来会发送此参数
- -- @param onrsp AT命令应答的处理函数,只是当前发送的AT命令应答有效,处理之后就失效了
- -- @param delay 延时delay毫秒后,才发送此AT命令
- -- @return 无
- -- @usage wifiRil.request("AT+CENG=1,1")
- -- @usage wifiRil.request("AT+CRSM=214,28539,0,0,12,\"64f01064f03064f002fffff\"", nil, crsmResponse)
- function request(cmd, arg, onrsp, delay, param)
- if transparentmode then
- return
- end
- --插入缓冲队列
- if arg or onrsp or delay or formt or param then
- table.insert(cmdqueue, {
- cmd = cmd,
- arg = arg,
- rsp = onrsp,
- delay = delay,
- rspParam = param
- })
- else
- table.insert(cmdqueue, cmd)
- end
- --执行AT命令发送
- sendat()
- end
- --[[
- 函数名:setransparentmode
- 功能 :AT命令通道设置为透传模式
- 参数 :
- fnc:透传模式下,虚拟串口数据接收的处理函数
- 返回值:无
- 注意:透传模式和非透传模式,只支持开机的第一次设置,不支持中途切换
- ]]
- function setransparentmode(fnc)
- transparentmode, rcvfunc = true, fnc
- end
- --[[
- 函数名:sendtransparentdata
- 功能 :透传模式下发送数据
- 参数 :
- data:数据
- 返回值:成功返回true,失败返回nil
- ]]
- function sendtransparentdata(data)
- if not transparentmode then
- return
- end
- vwrite(UART_ID, data)
- return true
- end
- function setDataTimeout(tm)
- DATA_TIMEOUT = (tm<120000 and 120000 or tm)
- end
- uart.setup(UART_ID, 115200, 8, uart.PAR_NONE, uart.STOP_1)
- --注册“AT命令的虚拟串口数据接收消息”的处理函数
- uart.on(UART_ID, "receive", atcreader)
|