| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569 |
- --- 模块功能:数据链路激活、socketCh395管理(创建、连接、数据收发、状态维护)
- -- @module socketCh395
- -- @author openLuat
- -- @license MIT
- -- @copyright openLuat
- -- @release 2017.9.25
- require "link"
- require "utils"
- module(..., package.seeall)
- local sockets = {}
- -- 单次发送数据最大值
- local SENDSIZE = 1024
- -- 缓冲区最大下标
- local INDEX_MAX = 2048
- -- 是否有socket正处在链接
- local socketsConnected = 0
- -- CH395配置信息
- local configurationCh395 = nil
- -- 以太网模块供电设置函数
- local powerCbFnc = nil
- -- 获取芯片版本(使用0x44以上版本)
- local ch395Version = nil
- -- 芯片MAC地址
- local CH395MAC = nil
- local resvnum = 0
- TCPCLIENT = 0
- UDPCLIENT = 1
- RAW = 3
- TCPSERVER = 4
- local function str2short(str)
- local f, n = pack.unpack(str, '<H')
- return f and f > 0 and n or 0
- end
- local function shorts(n)
- return pack.pack('<H', n)
- end
- local function sub_z(data, num)
- return string.sub(data, num + 1, data:len())
- end
- local function ip2num(str)
- if (not (str and #str == 4)) then
- return ''
- end
- local t = {pack.unpack(str, 'bbbb')}
- return string.format('%d.%d.%d.%d', t[2], t[3], t[4], t[5])
- end
- local function iptostr(ip)
- local d1, d2, d3, d4 = string.match(ip, '(%d+)%.(%d+)%.(%d+).(%d+)')
- return {string.sub(shorts(d1), 1, 1), string.sub(shorts(d2), 1, 1), string.sub(shorts(d3), 1, 1),
- string.sub(shorts(d4), 1, 1)}
- end
- ------------
- local function spiSend(id, data)
- --log.info('send SPI data:', data:toHex())
- local dataSpi
- if configurationCh395['spiCs'] then
- local setSpi_CS = pins.setup(configurationCh395['spiCs'], 0)
- dataSpi = spi.send_recv(id, data)
- setSpi_CS(1)
- else
- dataSpi = spi.send_recv(id, data)
- end
- -- log.info('recv SPI data', dataSpi:toHex())
- return dataSpi
- end
- -- 命令执行查询
- local function inquire2c(time)
- local num = 0
- while true do
- sys.wait(time or 10)
- local data = string.sub(spiSend(spi.SPI_1, '\x2c\xff'), 2, 2)
- if data ~= '\x10' then
- return data
- end
- num = num + 1
- if num > 100 then
- return data
- end
- end
- end
- -- 获取MAC地址
- function getMac()
- return CH395MAC
- end
- -- 本地端口,初始化默认端口
- local socketLocalPort = 0
- -- 动态获取本地端口号,每次获取累加
- local function socketTcpClientPort()
- -- socketLocalPort = socketLocalPort + 123
- -- if socketLocalPort > 65535 then
- -- socketLocalPort = 1000
- -- end
- -- return socketLocalPort
- local time = string.sub(rtos.tick(), 3)
- if socketLocalPort < 8 then
- socketLocalPort = socketLocalPort + 1
- else
- socketLocalPort = 0
- end
- return (socketLocalPort + time) * 5
- end
- -- 初始化socket
- local function SocketClientInit(type, socketId, soalAddress, soalPort, localPort)
- localPort = localPort or socketTcpClientPort()
- local addr = iptostr(soalAddress)
- -- 设置协议类型
- if type == TCPCLIENT then
- spiSend(spi.SPI_1, string.char(0x34, socketId, 3))
- elseif type == UDPCLIENT then
- spiSend(spi.SPI_1, string.char(0x34, socketId, 2))
- end
- -- 设置本地端口
- spiSend(spi.SPI_1, '\x33' .. string.char(socketId) .. shorts(tonumber(localPort)))
- -- 设置目的端口号
- spiSend(spi.SPI_1, '\x32' .. string.char(socketId) .. shorts(tonumber(soalPort)))
- -- 设置目的地址
- spiSend(spi.SPI_1, string.char(0x31, socketId) .. addr[1] .. addr[2] .. addr[3] .. addr[4])
- -- 打开socket
- spiSend(spi.SPI_1, string.char(0x35, socketId))
- -- 查询执行状态
- local state = inquire2c(50)
- log.info('socketCh395', 'open socket' .. socketId .. state:toHex())
- if state ~= '\x00' or type == UDPCLIENT then
- if type ~= UDPCLIENT then
- log.info('socketCh395', 'open socket err', state:toHex())
- else
- sys.timerStart(function()
- sys.publish('SOCK_CONN_CNF', {
- ['socket_index'] = socketId,
- ['id'] = 34,
- ['result'] = 0
- })
- end, 200)
- end
- return state
- end
- spiSend(spi.SPI_1, string.char(0x37, socketId))
- state = inquire2c()
- if state == '\x00' then
- --sys.publish('SOCK_CONN_CNF', {
- -- ['socket_index'] = socketId,
- -- ['id'] = 34,
- -- ['result'] = 0
- --})
- else
- log.info('socketCh395', 'open socket' .. socketId, state:toHex())
- end
- return state
- end
- -- 配置8路socket收发缓存
- local function socketBufferConfig()
- -- 只有硬件版本大于47才有4-7路
- local b = 0
- for i = 0, 7 do
- spiSend(spi.SPI_1, string.char(0x52, i, b, 4))
- b = b + 4
- spiSend(spi.SPI_1, string.char(0x53, i, b, 2))
- b = b + 2
- sys.wait(500)
- end
- end
- -- 关闭套接字连接
- local function sockectCh395Close(socketId)
- if sockets[socketId] == nil or sockets[socketId] == true then
- log.info('socketCh395', 'close err, not socket ' .. socketId)
- end
- if sockets[socketId] == true or sockets[socketId].protocol == 'TCPSERVERCLIENT' then
- -- server客户端断开连接
- spiSend(spi.SPI_1, string.char(0x38, socketId))
- local state = inquire2c()
- log.info('socketCh395', 'close server socket ' .. socketId)
- sys.publish('SOCK_CLOSE_CNF', {
- ['socket_index'] = socketId,
- ['id'] = 33,
- ['result'] = 0
- })
- elseif sockets[socketId].protocol == 'TCPSERVER' then
- -- server关闭,断开连接,关闭所有server通道
- log.info('socketCh395', 'close server ' .. socketId)
- for i, v in ipairs(sockets) do
- if sockets[i] ~= true and not sockets[i] and sockets[i].protocol == 'TCPSERVERCLIENT' then
- local id = sockets[i].id
- spiSend(spi.SPI_1, string.char(0x38, sockets[i].id))
- spiSend(spi.SPI_1, string.char(0x3D, socketId))
- sockets[i] = nil
- log.info('socketCh395', 'close server socket ' .. id)
- end
- end
- spiSend(spi.SPI_1, string.char(0x3D, socketId))
- log.info('socketCh395', 'close server ' .. socketId)
- local state = inquire2c()
- sys.publish('SOCK_CLOSE_CNF', {
- ['socket_index'] = socketId,
- ['id'] = 33,
- ['result'] = 0
- })
- else
- spiSend(spi.SPI_1, string.char(0x3D, socketId))
- local stateClose = inquire2c(10)
- log.info('sockectCh395', 'close socket' .. socketId .. 'true' .. stateClose:toHex())
- sys.publish('SOCK_CLOSE_CNF', {
- ['socket_index'] = socketId,
- ['id'] = 33,
- ['result'] = 0
- })
- end
- end
- local function ipError()
- if link.isReady() and link.getNetwork() == link.CH395 then
- link.setReady(link.CH395, false)
- sys.publish('IP_ERROR_IND')
- log.info('socketCh395', 'IP_ERROR_IND')
- end
- end
- -- 处理中断
- local function interruptProcess()
- local intAll = string.sub(spiSend(spi.SPI_1, '\x19\xff\xff'), 2, -1)
- -- log.info('INT30', intAll:toHex())
- intAll = str2short(intAll)
- if intAll == 0 or intAll == 65535 then
- return
- end
- -- 处理PHY中断
- if bit.isset(intAll, 2) then
- local statePhy = string.sub(spiSend(spi.SPI_1, '\x26\xff'), 2, -1)
- if statePhy == '\x01' then
- sys.publish("PHY_RESULT", false)
- log.info('socketCh395', 'phy false')
- ipError()
- elseif statePhy == '\x08' then
- sys.publish("PHY_RESULT", true)
- log.info('socketCh395', 'phy true')
- end
- end
- -- 处理DHCP中断
- if bit.isset(intAll, 3) then
- -- DHCP中断
- local stateDhcp = string.sub(spiSend(spi.SPI_1, '\x42\xff'), 2, -1)
- if stateDhcp == '\x00' then
- log.info('socketCh395', 'DHCP true')
- elseif stateDhcp == '\x01' then
- log.info('socketCh395', 'DHCP false')
- ipError()
- end
- end
- -- 处理不可达中断
- if bit.isset(intAll, 0) then
- -- 读取不可达信息?
- log.info('socketCh395', 'Unreachable interrupt')
- -- getUnreachIpport()
- end
- -- 处理IP冲突中断
- if bit.isset(intAll, 1) then
- log.info("IP", 'IP conflict')
- -- 建议重新修改本地IP,并初始化芯片(未加)
- end
- -- socket0-7中断
- local socketIntId = {}
- for i = 4, 11 do
- if bit.isset(intAll, i) then
- table.insert(socketIntId, (i - 4))
- end
- end
- local socketCloss = {}
- -- 逐个socket查询中断并处理
- for q = 1, #socketIntId do
- local socketState = string.sub(spiSend(spi.SPI_1, string.char(0x30, socketIntId[q], 0xff, 0xff)), 3, -1)
- -- log.info('INT19:' .. socketIntId[q], socketState:toHex())
- socketState = str2short(socketState)
- -- TCP连接
- if bit.isset(socketState, 3) then
- -- sockets[socketIntId[q]].connected = true
- if sockets[socketIntId[q]] == true then
- local data = string.sub(spiSend(spi.SPI_1,
- string.char(0x2d, socketIntId[q], 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)), 3, 8)
- -- server
- local socketData = {
- id = socketIntId[q],
- ip = ip2num(string.sub(data, 1, 4)),
- port = str2short(string.sub(data, 5, 6))
- }
- sys.publish('tcpServer', socketData)
- else
- sys.publish('SOCK_CONN_CNF', {
- ['socket_index'] = socketIntId[q],
- ['id'] = 34,
- ['result'] = 0
- })
- end
- end
- -- 接收缓冲区非空
- if bit.isset(socketState, 2) then
- local data_leng
- local data
- data_leng = string.sub(spiSend(spi.SPI_1, string.char(0x3b, socketIntId[q], 0xff, 0xff)), 3, -1)
- -- if data_leng == '\x00\x00' then
- -- break
- -- end
- data = string.sub(spiSend(spi.SPI_1, string.char(0x3c, socketIntId[q]) .. data_leng ..
- string.rep('\xff', str2short(data_leng))), 5, -1)
- sys.timerStart(function()
- sys.publish('MSG_SOCK_RECV_IND', {
- ['socket_index'] = socketIntId[q],
- ['id'] = 31,
- ['result'] = 0,
- ['recv_len'] = str2short(data_leng),
- ['recv_data'] = data
- })
- end, 10)
- -- data_leng = string.sub(spiSend(spi.SPI_1, string.char(0x3b, socketIntId[q], 0xff, 0xff)), 3, -1)
- -- data = string.sub(spiSend(spi.SPI_1, string.char(0x3c, socketIntId[q]) .. data_leng ..
- -- string.rep('\xff', str2short(data_leng))), 5, -1)
- -- sys.publish('MSG_SOCK_RECV_IND', {
- -- ['socket_index'] = socketIntId[q],
- -- ['id'] = 31,
- -- ['result'] = 0,
- -- ['recv_len'] = str2short(data_leng),
- -- ['recv_data'] = data
- -- })
- end
- -- 发送缓冲区空闲
- if bit.isset(socketState, 0) then
- if sockets[socketIntId[q]] and sockets[socketIntId[q]] ~= true then
- sockets[socketIntId[q]].sendstate = true
- else
- log.info('socketCh395', 'sendstate err:' .. socketIntId[q])
- end
- end
- -- 发送成功
- if bit.isset(socketState, 1) then
- sys.publish('SOCK_SEND_CNF', {
- ['socket_index'] = socketIntId[q],
- ['id'] = 32,
- ['result'] = 0
- })
- end
- -- TCP断开
- if bit.isset(socketState, 4) then
- table.insert(socketCloss, {
- ['socket_index'] = socketIntId[q],
- ['id'] = 33,
- ['result'] = 0
- })
- end
- -- 超时
- if bit.isset(socketState, 6) then
- -- 超时处理,重新开启重新连接(未加)
- -- 打开socket
- log.info('socketCh395', 'socket conn timeout' .. socketIntId[q], sockets[socketIntId[q]], socketIntId[q])
- if not sockets[socketIntId[q]] then
- sockectCh395Close(socketIntId[q])
- elseif sockets[socketIntId[q]] ~= 0 then
- local ty = sockets[socketIntId[q]].protocol
- local soalAddress = sockets[socketIntId[q]].address
- local soalPort = sockets[socketIntId[q]].port
- local localPort = sockets[socketIntId[q]].localPort
- sockectCh395Close(socketIntId[q])
- --if ty == 'TCP' then
- --ty = TCPCLIENT
- --elseif ty == 'UDP' then
- --ty = UDPCLIENT
- --end
- --SocketClientInit(ty, socketIntId[q], soalAddress, soalPort, localPort)
- end
- end
- end
- for i = 0, 7 do
- if sockets[i] then
- local data_leng
- local data
- data_leng = string.sub(spiSend(spi.SPI_1, string.char(0x3b, i, 0xff, 0xff)), 3, -1)
- if data_leng ~= "\x00\x00" then
- data = string.sub(spiSend(spi.SPI_1,
- string.char(0x3c, i) .. data_leng .. string.rep('\xff', str2short(data_leng))), 5, -1)
- sys.timerStart(function()
- sys.publish('MSG_SOCK_RECV_IND', {
- ['socket_index'] = i,
- ['id'] = 31,
- ['result'] = 0,
- ['recv_len'] = str2short(data_leng),
- ['recv_data'] = data
- })
- end, 10)
- end
- end
- end
- for w = 1, #socketCloss do
- local data =
- string.sub(spiSend(spi.SPI_1, string.char(0x2F, socketCloss[w]['socket_index'], 0xff, 0xff)), 3, -1)
- local data1 = string.sub(data, 1, 1)
- local data2 = string.sub(data, 2, 2)
- -- if data1 == '\x00' then
- if not sockets[socketCloss[w]['socket_index']] or sockets[socketCloss[w]['socket_index']] == true then
- sys.timerStart(function(...)
- log.info('socketCh395', 'socket ' .. socketCloss[w]['socket_index'] .. 'state' .. data:toHex())
- sys.publish('MSG_SOCK_CLOSE_IND', socketCloss[w])
- log.info('socketCh395', 'Disconnection socket ', socketCloss[w]['socket_index'])
- end, 200)
- elseif sockets[socketCloss[w]['socket_index']].protocol == 'TCPSERVERCLIENT' then
- -- sockets[socketCloss[w]['socket_index']]=true
- sys.timerStart(function(...)
- log.info('socketCh395', 'socket ' .. socketCloss[w]['socket_index'] .. 'state' .. data:toHex())
- sys.publish('MSG_SOCK_CLOSE_IND', socketCloss[w])
- log.info('socketCh395', 'Disconnection socket ', socketCloss[w]['socket_index'])
- end, 200)
- else
- sys.timerStart(function(...)
- log.info('socketCh395', 'socket ' .. socketCloss[w]['socket_index'] .. 'state' .. data:toHex())
- sys.publish('MSG_SOCK_CLOSE_IND', socketCloss[w])
- log.info('socketCh395', 'Disconnection socket ', socketCloss[w]['socket_index'])
- end, 200)
- end
- -- end
- end
- sys.wait(10)
- end
- local number = 0
- sys.taskInit(function()
- while true do
- if number > 0 or sys.waitUntil("interruptProcess") then
- interruptProcess()
- number = number - 1
- -- sys.wait(5)
- end
- end
- end)
- -- 配置中断检测
- local function setInt(state)
- if state then
- pio.pin.setdebounce(5)
- pins.setup(configurationCh395['intPin'], function(a)
- if a == 2 then
- number = number + 2
- sys.publish("interruptProcess")
- else
- end
- end)
- pio.pin.setdebounce(20)
- else
- pins.close(configurationCh395['intPin'])
- end
- end
- --- 初始化CH395模块
- -- @table para 取值如下:
- -- para为table类型,表示以太网的配置参数,参数结构如下:
- -- {
- -- mode = 1, --1表示客户端;2表示服务器;默认为1
- -- intPin = pio.P0_22, --以太网芯片中断通知引脚
- -- rstPin = pio.P0_23, --复位以太网芯片引脚
- -- clientNum = 6, --server可连路数
- -- spiCs = pio.P0_23, --SPI片选
- -- CH395MAC = "84C2E4A82950", --MAC地址
- -- localAddr = "192.168.1.112", --本机的地址
- -- localSubnetMas = "255.255.255.0", --子网掩码
- -- localPort = 1888, --server本机的端口
- -- spiCs=pio.P0_7, --spi片选
- -- localGateway = "192.168.1.1", --本机的网关地址
- -- func=function(id, msg, dat)end, --中断处理函数,处理server中断事件
- -- powerFunc=function(state) end --控制以太网模块的供电开关函数,ret为true开启供电,false关闭供电
- -- spi = {spi.SPI_1,0,0,8,800000}, --SPI通道参数,id,cpha,cpol,dataBits,clock,默认spi.SPI_1,0,0,8,800000
- -- }
- -- @return result 数据接收结果
- -- true表示成功
- -- false表示失败
- -- @usage
- -- socketCh395.open(para)
- function open(para)
- configurationCh395 = para
- powerCbFnc = nil or para['powerFunc']
- -- 供电及其他前置条件
- if powerCbFnc then
- powerCbFnc(true)
- end
- -- 复位芯片
- spiSend(spi.SPI_1, '\x05')
- -- 开启SPI
- if not spi.setup(para['spi'][1], para['spi'][2], para['spi'][3], para['spi'][4], para['spi'][5], 1) == 1 then
- log.info('socketCh395', 'open spi err')
- return ''
- end
- -- 设置中断
- setInt(true)
- -- 芯片进入SPI模式
- local setGpioFnc_RSTI = pins.setup(para['rstPin'], 0)
- setGpioFnc_RSTI(0)
- sys.wait(100)
- setGpioFnc_RSTI(1)
- sys.wait(200)
- -- 测试是否成功建立通讯
- local state06 = string.sub(spiSend(spi.SPI_1, '\x06\x55\xff'), 3, 3)
- state06 = state06 == '\xaa'
- log.info('CH395 state', state06)
- if not state06 then
- log.info('socketCh395', 'err cannot work')
- return ''
- end
- -- server多连接设置
- if para['mode'] == 2 then
- spiSend(spi.SPI_1, '\x55\x02')
- local stateInit = inquire2c(50)
- if stateInit ~= '\x00' then
- log.info('open server')
- else
- log.info('open server err', stateInit:toHex())
- end
- end
- -- 获取芯片版本
- ch395Version = string.sub(spiSend(spi.SPI_1, '\x01\xff'), 2, 2)
- -- 配置芯片信息
- if para['localAddr'] and para['localGateway'] then
- -- 配置本地信息
- local gateway = iptostr(para['localGateway'])
- local addr = iptostr(para['localAddr'])
- spiSend(spi.SPI_1, '\x22' .. addr[1] .. addr[2] .. addr[3] .. addr[4])
- spiSend(spi.SPI_1, '\x23' .. gateway[1] .. gateway[2] .. gateway[3] .. gateway[4])
- if para['localSubnetMas'] then
- local subnetMas = iptostr(para['localSubnetMas'])
- spiSend(spi.SPI_1, '\x24' .. subnetMas[1] .. subnetMas[2] .. subnetMas[3] .. subnetMas[4])
- end
- end
- -- 设置收发缓存(默认8路)
- socketBufferConfig()
- -- 模块初始化
- spiSend(spi.SPI_1, '\x27')
- local stateInit = inquire2c(50)
- if stateInit ~= '\x00' then
- log.info('socketCh395', 'ch395 INIT err' .. stateInit:toHex())
- return ''
- end
- local result, result2 = sys.waitUntil("PHY_RESULT", 60000)
- if not result or not result2 then
- return ''
- end
- -- 设置MAC地址
- if para['CH395MAC'] and string.len(para['CH395MAC']) == 12 then
- spiSend(spi.SPI_1, '\x21' .. string.fromHex(para['CH395MAC']))
- sys.wait(200)
- end
- -- 获取芯片MAC
- CH395MAC = string.sub(spiSend(spi.SPI_1, string.fromHex('40FFFFFFFFFFFF2cff')), 2, 7)
- if CH395MAC == string.char(0, 0, 0, 0, 0, 0) then
- CH395MAC = nil
- end
- -- DHCP
- if not (para['localAddr'] and para['localGateway']) then
- spiSend(spi.SPI_1, '\x41\x01')
- local stateDhcp = inquire2c(30)
- if stateDhcp ~= '\x00' then
- log.info('socketCh395', 'ch395 INIT err' .. stateDhcp:toHex())
- return ''
- end
- end
- -- 获取本地IP
- for q = 1, 20 do
- sys.wait(500)
- local dataIp = string.sub(spiSend(spi.SPI_1, string.fromHex('43ffffffffffffffffffffffffffffffffffffffff')), 2,
- -1)
- if link.getNetwork() == link.CH395 and string.sub(dataIp, 1, 4) ~= '\xff\xff\xff\xff' and
- string.sub(dataIp, 1, 4) ~= '\x00\x00\x00\x00' then
- local ch395Ip = ip2num(string.sub(dataIp, 1, 4))
- log.info('ip', ch395Ip)
- link.setReady(link.CH395, true)
- sys.publish('IP_READY_IND')
- return ch395Ip
- end
- end
- return ''
- end
- --- 开关模块
- function close()
- link.setReady(link.CH395, false)
- sys.publish('IP_ERROR_IND')
- -- 关闭所有socket
- for i = 0, 7 do
- spiSend(spi.SPI_1, string.char(0x3D, i))
- sockets[i] = nil
- end
- -- 关闭中断检测
- setInt(false)
- -- 关闭SPI
- if not spi.close(configurationCh395['spi'][1]) == 1 then
- log.info('socketCh395 close spi err', configurationCh395['spi'][1], configurationCh395['spi'][2],
- configurationCh395['spi'][3], configurationCh395['spi'][4], configurationCh395['spi'][5], 1)
- return false
- end
- -- 关闭模块
- if powerCbFnc then
- powerCbFnc(false)
- end
- return true
- end
- ---建立套接字连接
- local function sockectCh395Conn(type, addr, port, lcoalPort, data)
- local socketId = nil
- for i = 0, 7 do
- if not sockets[i] then
- socketId = i
- data.id=i
- sockets[i] = data
- break
- end
- if i == 7 then
- log.info('socketCh395', 'No socket available ')
- return nil
- end
- end
- if type == TCPCLIENT or type == UDPCLIENT then
- local tcpClientState = SocketClientInit(type, socketId, addr, port, lcoalPort)
- if tcpClientState == '\x00' then
- return socketId
- else
- spiSend(spi.SPI_1, string.char(0x3D, socketId))
- local stateClose = inquire2c(50)
- if stateClose == '\x00' then
- log.info('sockectCh395', 'close socket' .. socketId .. 'true')
- end
- sockets[socketId] = nil
- return nil
- end
- elseif type == TCPSERVER then
- end
- end
- -- 发送数据
- local function sockectCh395Send(socketId, data)
- for i = 1, 10 do
- if sockets[socketId] and sockets[socketId] ~= true and sockets[socketId].sendstate then
- spiSend(spi.SPI_1, '\x39' .. string.char(socketId) .. shorts(#data) .. data)
- local state = inquire2c(50)
- if state == '\x00' then
- sys.publish('SOCK_SEND_CNF', {
- ['socket_index'] = socketId,
- ['id'] = 32,
- ['result'] = 0
- })
- else
- sys.publish('SOCK_SEND_CNF', {
- ['socket_index'] = socketId,
- ['id'] = 32,
- ['result'] = 1
- })
- end
- log.info('socketCh395', socketId .. 'send state' .. state:toHex())
- break
- elseif not sockets[socketId] or sockets[socketId] == true then
- -- log.info('socketCh395', 'send err, not socket ' .. socketId)
- else
- sys.wait(100)
- end
- end
- end
- -- 接收数据
- local function sockectCh395Recv(socketId, buffLen)
- local data_leng = string.sub(spiSend(spi.SPI_1, string.char(0x3b, socketId, 0xff, 0xff)), 3, -1)
- local data = string.sub(spiSend(spi.SPI_1, string.char(0x3c, socketId) .. data_leng ..
- string.rep('\xff', str2short(data_leng))), 5, -1)
- return data
- end
- -- table 深拷贝
- local function clone(tb)
- local ret = {}
- for k, v in pairs(tb) do
- ret[k] = type(v) == "table" and clone(v) or v
- end
- return ret
- end
- -- 创建server
- local function initServer(port, num, data)
- if num > 7 then
- return
- end
- local dd = true
- local serverTable = {}
- local serverid = nil
- for i = 0, 7 do
- if not sockets[i] then
- table.insert(serverTable, i)
- if dd then
- sockets[i] = data
- dd = false
- else
- sockets[i] = clone(data)
- end
- if #serverTable == num + 1 then
- break
- end
- end
- if i == 7 then
- log.info('socketCh395', 'No socket available ')
- for q = 1, #serverTable do
- sockets[serverTable[q]] = nil
- end
- return nil
- end
- end
- for i = 1, #serverTable do
- spiSend(spi.SPI_1, string.char(0x34, serverTable[i], 3))
- spiSend(spi.SPI_1, string.char(0x33, serverTable[i]) .. shorts(port))
- if i == 1 then
- spiSend(spi.SPI_1, string.char(0x35, serverTable[i]))
- sockets[i].id = serverTable[i]
- serverid = serverTable[i]
- local state = inquire2c(50)
- if state == '\x00' then
- sockets[serverTable[i]].id = serverTable[i]
- sockets[serverTable[i]].protocol = 'TCPSERVER'
- else
- log.info('socket open err', state:toHex())
- log.info('socketCh395', 'socket open err')
- end
- else
- local state = inquire2c(50)
- if state == '\x00' then
- log.info('socketCh395', 'server open' .. serverTable[i])
- sockets[serverTable[i]].protocol = 'TCPSERVERCLIENT' .. serverTable[i]
- sockets[serverTable[i]] = true
- end
- if i == num + 1 then
- spiSend(spi.SPI_1, string.char(0x36, serverid))
- local state = inquire2c(50)
- if state == '\x00' then
- return serverid
- end
- end
- end
- end
- end
- ------------------------
- local function errorInd(error)
- local coSuspended = {}
- for _, c in pairs(sockets) do -- IP状态出错时,通知所有已连接的socket
- if c ~= true then
- c.error = error
- -- 不能打开如下3行代码,IP出错时,会通知每个socket,socket会主动close
- -- 如果设置了connected=false,则主动close时,直接退出,不会执行close动作,导致core中的socket资源没释放
- -- 会引发core中socket耗尽以及socket id重复的问题
- -- c.connected = false
- -- socketsConnected = c.connected or socketsConnected
- -- if error == 'CLOSED' then sys.publish("SOCKET_ACTIVE", socketsConnected) end
- if c.co and coroutine.status(c.co) == "suspended" then
- -- coroutine.resume(c.co, false)
- table.insert(coSuspended, c.co)
- end
- end
- end
- for k, v in pairs(coSuspended) do
- if v and coroutine.status(v) == "suspended" then
- coroutine.resume(v, false, error)
- end
- end
- end
- sys.subscribe("IP_ERROR_IND", function()
- errorInd('IP_ERROR_IND')
- end)
- -- sys.subscribe('IP_SHUT_IND', function()errorInd('CLOSED') end)
- -- 创建socket函数
- local mt = {}
- mt.__index = mt
- local function socket(protocol, cert, tCoreExtPara)
- local ssl = protocol:match("SSL")
- local co = coroutine.running()
- if not co then
- log.warn("socket.socket: socket must be called in coroutine")
- return nil
- end
- -- if protocol == 'TCPSERVER' and type(tCoreExtPara) == 'table' then
- -- protocol
- -- end
- -- 实例的属性参数表
- local o = {
- id = nil,
- protocol = protocol,
- tCoreExtPara = tCoreExtPara,
- ssl = ssl,
- cert = cert,
- co = co,
- input = {},
- output = {},
- wait = "",
- connected = false,
- iSubscribe = false,
- subMessage = nil,
- isBlock = false,
- msg = nil,
- rcvProcFnc = nil,
- sendstate = true, -- 发送缓冲区状态,true为空闲,可发送数据
- localPort = nil -- 本地端口
- }
- if tCoreExtPara and tCoreExtPara['localport'] and type(tCoreExtPara['localport']) == 'number' then
- o.localPort = tCoreExtPara['port']
- end
- if protocol == 'TCPSERVER' and tCoreExtPara['type']== 'TCPSERVER' then
- o.port = configurationCh395["localPort"]
- local id = initServer(configurationCh395["localPort"], configurationCh395["clientNum"], setmetatable(o, mt))
- if not id then
- log.info('socketCh395', 'server socket err')
- return
- end
- elseif protocol == 'TCPSERVER' and tCoreExtPara['type']~= 'TCPSERVER' then
- o.address = tCoreExtPara['ip']
- o.port = tCoreExtPara['port']
- o.id = tCoreExtPara['id']
- o.protocol = 'TCPSERVERCLIENT'
- sockets[tCoreExtPara['id']] = setmetatable(o, mt)
- end
- return setmetatable(o, mt)
- end
- --- 创建基于TCP的socket对象
- -- @bool[opt=nil] ssl 是否为ssl连接,true表示是,其余表示否
- -- @table[opt=nil] cert 保留参数,ssl功能还未实现。
- -- @table[opt=nil] tCoreExtPara 建立链接扩展参数
- -- {
- -- id =0, --server socket索引ID
- -- ip ="192.168.1.1", --server socket client ip
- -- port ="8000", --server socket client port
- -- type ="TCPSERVER", --server socket type
- -- localport ="8000", -- socket client port
- -- }
- -- @return client,创建成功返回socket客户端对象;创建失败返回nil
- function tcp(ssl, cert, tCoreExtPara)
- if tCoreExtPara and tCoreExtPara['type'] == "TCPSERVER" then
- return socket("TCPSERVER", nil, tCoreExtPara)
- elseif tCoreExtPara and tCoreExtPara['type'] ~= "TCPSERVER" then
- return socket("TCPSERVER", nil, tCoreExtPara)
- end
- return socket("TCP" .. (ssl == true and "SSL" or ""), (ssl == true) and cert or nil, tCoreExtPara)
- end
- --- 创建基于UDP的socket对象
- -- @return client,创建成功返回socket客户端对象;创建失败返回nil
- -- @usage c = socketCh395.udp()
- function udp(localPort)
- return socket("UDP", nil, localPort)
- end
- --- 连接服务器
- -- @string address 服务器地址,支持ip和域名
- -- @param port string或者number类型,服务器端口
- -- @number[opt=120] timeout 可选参数,连接超时时间,单位秒
- -- @return bool result true - 成功,false - 失败
- -- @return string ,id '0' -- '8' ,返回通道ID编号
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- function mt:connect(address, port, timeout)
- assert(self.co == coroutine.running(), "socket:connect: coroutine mismatch")
- log.info('socketCh395', 'socket data' .. self.protocol, address, port)
- if not link.isReady() then
- log.info("socket.connect: ip not ready")
- return false
- end
- self.address = address
- self.port = port
- local tCoreExtPara = self.tCoreExtPara or {}
- -- 默认缓冲区大小
- local rcvBufferSize = tCoreExtPara.rcvBufferSize or 0
- local d1, d2, d3, d4 = string.match(address, '(%d+)%.(%d+)%.(%d+).(%d+)')
- if not (d1 == nil or d2 == nil or d3 == nil or d4 == nil) then
- if self.protocol == 'TCP' then
- self.id = sockectCh395Conn(TCPCLIENT, address, port, self.localPort, self)
- elseif self.protocol == 'TCPSSL' then
- -- 未实现
- log.info("socketCh395", "no ssl")
- else
- self.id = sockectCh395Conn(UDPCLIENT, address, port, self.localPort, self)
- end
- else
- self.id = -2
- end
- if type(socketcore.sock_conn_ext) == "function" then
- if not self.id or self.id < 0 then
- if self.id == -2 then
- require "http"
- -- 请求腾讯云免费HttpDns解析
- http.request("GET", "119.29.29.29/d?dn=" .. address, nil, nil, nil, 40000,
- function(result, statusCode, head, body)
- log.info("socket.httpDnsCb", result, statusCode, head, body)
- sys.publish("SOCKET_HTTPDNS_RESULT_" .. address .. "_" .. port, result, statusCode, head, body)
- end)
- local _, result, statusCode, head, body = sys.waitUntil(
- "SOCKET_HTTPDNS_RESULT_" .. address .. "_" .. port)
- -- DNS解析成功
- if result and statusCode == "200" and body and body:match("^[%d%.]+") then
- return self:connect(body:match("^([%d%.]+)"), port, timeout)
- end
- end
- self.id = nil
- end
- end
- if not self.id then
- log.info("socket:connect: core sock conn error", self.protocol, address, port, self.cert)
- return false
- end
- log.info("socket:connect-coreid,prot,addr,port,cert,timeout", self.id, self.protocol, address, port, self.cert,
- timeout or 120)
- sockets[self.id] = self
- self.wait = "SOCKET_CONNECT"
- self.timerId = sys.timerStart(coroutine.resume, (timeout or 120) * 1000, self.co, false, "TIMEOUT")
- local result, reason = coroutine.yield()
- if not result and reason == 'server close' then
- return false
- end
- if self.timerId and reason ~= "TIMEOUT" then
- sys.timerStop(self.timerId)
- end
- if not result then
- log.info("socket:connect: connect fail" .. self.id, reason)
- if reason == "RESPONSE" then
- sockets[self.id] = nil
- self.id = nil
- end
- sys.publish("LIB_SOCKET_CONNECT_FAIL_IND", self.ssl, self.protocol, address, port)
- return false
- end
- log.info("socket:connect: connect ok")
- if not self.connected then
- self.connected = true
- socketsConnected = socketsConnected + 1
- sys.publish("SOCKET_ACTIVE", socketsConnected > 0)
- end
- return true, self.id
- end
- function mt:serverClose()
- if not self then
- return false
- end
- if self.error then
- log.warn('socket.client:asyncSelect', 'error', self.error)
- return false
- end
- coroutine.resume(self.co, false, 'server close')
- end
- --- server发送数据
- -- @number[opt=nil] keepAlive 服务器和客户端最大通信间隔时间,也叫心跳包最大时间,单位秒
- -- @string[opt=nil] pingreq 心跳包的字符串
- -- @return boole,false 失败,true 表示成功
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- -- while socketClient:serverSelect() do end
- function mt:serverSelect(keepAlive, pingreq)
- assert(self.co == coroutine.running(), "socket:asyncSelect: coroutine mismatch")
- if self.error then
- log.warn('socket.client:asyncSelect', 'error', self.error)
- return false
- end
- self.wait = "SOCKET_SEND"
- local dataLen = 0
- -- log.info("socket.asyncSelect #self.output",#self.output)
- while #self.output ~= 0 do
- local data = table.concat(self.output)
- dataLen = string.len(data)
- self.output = {}
- local sendSize = SENDSIZE
- for i = 1, dataLen, sendSize do
- -- 按最大MTU单元对data分包
- sockectCh395Send(self.id, data:sub(i, i + sendSize - 1))
- if self.timeout then
- self.timerId = sys.timerStart(coroutine.resume, self.timeout * 1000, self.co, false, "TIMEOUT")
- end
- -- log.info("socket.asyncSelect self.timeout",self.timeout)
- local result, reason = coroutine.yield()
- if not result and reason == 'server close' then
- return false
- end
- log.info('发送结果', result, reason)
- if self.timerId and reason ~= "TIMEOUT" then
- sys.timerStop(self.timerId)
- end
- sys.publish("SOCKET_ASYNC_SEND", result)
- if not result then
- sys.publish("LIB_SOCKET_SEND_FAIL_IND", self.ssl, self.protocol, self.address, self.port)
- log.warn('socket.asyncSelect', 'send error', data:sub(i, i + sendSize - 1))
- return false
- end
- end
- end
- self.wait = "SOCKET_WAIT"
- -- log.info("socket.asyncSelect",dataLen,self.id)
- if dataLen > 0 then
- sys.publish("SOCKET_SEND", self.id, true)
- end
- if keepAlive and keepAlive ~= 0 then
- if type(pingreq) == "function" then
- sys.timerStart(pingreq, keepAlive * 1000)
- else
- sys.timerStart(self.asyncSend, keepAlive * 1000, self, pingreq or "\0")
- end
- end
- local result, reason = coroutine.yield()
- if not result and reason == 'server close' then
- return false
- end
- return result, reason
- end
- --- 异步发送数据
- -- @number[opt=nil] keepAlive 服务器和客户端最大通信间隔时间,也叫心跳包最大时间,单位秒
- -- @string[opt=nil] pingreq 心跳包的字符串
- -- @return boole,false 失败,true 表示成功
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- -- while socketClient:asyncSelect() do end
- function mt:asyncSelect(keepAlive, pingreq)
- assert(self.co == coroutine.running(), "socket:asyncSelect: coroutine mismatch")
- if self.error then
- log.warn('socket.client:asyncSelect', 'error', self.error)
- return false
- end
- self.wait = "SOCKET_SEND"
- local dataLen = 0
- -- log.info("socket.asyncSelect #self.output",#self.output)
- while #self.output ~= 0 do
- local data = table.concat(self.output)
- dataLen = string.len(data)
- self.output = {}
- local sendSize = self.protocol == "UDP" and 1472 or SENDSIZE
- for i = 1, dataLen, sendSize do
- -- 按最大MTU单元对data分包
- -- socketcore.sock_send(self.id, data:sub(i, i + sendSize - 1))
- sockectCh395Send(self.id, data:sub(i, i + sendSize - 1))
- if self.timeout then
- self.timerId = sys.timerStart(coroutine.resume, self.timeout * 1000, self.co, false, "TIMEOUT")
- end
- -- log.info("socket.asyncSelect self.timeout",self.timeout)
- local result, reason = coroutine.yield()
- if not result and reason == 'server close' then
- return false
- end
- if self.timerId and reason ~= "TIMEOUT" then
- sys.timerStop(self.timerId)
- end
- sys.publish("SOCKET_ASYNC_SEND", result)
- if not result then
- sys.publish("LIB_SOCKET_SEND_FAIL_IND", self.ssl, self.protocol, self.address, self.port)
- -- log.warn('socket.asyncSelect', 'send error')
- return false
- end
- end
- end
- self.wait = "SOCKET_WAIT"
- -- log.info("socket.asyncSelect",dataLen,self.id)
- if dataLen > 0 then
- sys.publish("SOCKET_SEND", self.id, true)
- end
- if keepAlive and keepAlive ~= 0 then
- if type(pingreq) == "function" then
- sys.timerStart(pingreq, keepAlive * 1000)
- else
- sys.timerStart(self.asyncSend, keepAlive * 1000, self, pingreq or "\0")
- end
- end
- local result, reason = coroutine.yield()
- if not result and reason == 'server close' then
- return false
- end
- return result, reason
- end
- function mt:getAsyncSend()
- if self.error then
- return 0
- end
- return #(self.output)
- end
- --- server缓存待发送的数据
- -- @string data 数据
- -- @number[opt=nil] timeout 可选参数,发送超时时间,单位秒;为nil时表示不支持timeout
- -- @return result true - 成功,false - 失败
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- -- socketClient:serverSend("12345678")
- function mt:serverSend(data, timeout)
- if self.error then
- log.warn('socket.client:asyncSend', 'error', self.error)
- return false
- end
- self.timeout = timeout
- table.insert(self.output, data or "")
- -- log.info("socket.asyncSend",self.wait)
- if self.wait == "SOCKET_WAIT" then
- coroutine.resume(self.co, true)
- end
- return true
- end
- --- server接收数据
- -- @return data 表示接收到的数据(如果是UDP,返回最新的一包数据;如果是TCP,返回所有收到的数据)
- -- ""表示未收到数据
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- -- data = socketClient:serverRecv()
- function mt:serverRecv()
- if #self.input == 0 then
- return ""
- end
- if self.protocol == "UDP" then
- return table.remove(self.input)
- else
- local s = table.concat(self.input)
- self.input = {}
- if self.isBlock then
- table.insert(self.input, recv(self.msg.socket_index, self.msg.recv_len))
- end
- return s
- end
- end
- --- 异步缓存待发送的数据
- -- @string data 数据
- -- @number[opt=nil] timeout 可选参数,发送超时时间,单位秒;为nil时表示不支持timeout
- -- @return result true - 成功,false - 失败
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- -- socketClient:asyncSend("12345678")
- function mt:asyncSend(data, timeout)
- if self.error then
- log.warn('socket.client:asyncSend', 'error', self.error)
- return false
- end
- self.timeout = timeout
- table.insert(self.output, data or "")
- -- log.info("socket.asyncSend",self.wait)
- if self.wait == "SOCKET_WAIT" then
- coroutine.resume(self.co, true)
- end
- return true
- end
- --- 异步接收数据
- -- @return data 表示接收到的数据(如果是UDP,返回最新的一包数据;如果是TCP,返回所有收到的数据)
- -- ""表示未收到数据
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- -- data = socketClient:asyncRecv()
- function mt:asyncRecv()
- if #self.input == 0 then
- return ""
- end
- if self.protocol == "UDP" then
- return table.remove(self.input)
- else
- local s = table.concat(self.input)
- self.input = {}
- if self.isBlock then
- table.insert(self.input, socketcore.sock_recv(self.msg.socket_index, self.msg.recv_len))
- end
- return s
- end
- end
- --- 同步发送数据
- -- @string data 数据
- -- 此处传入的数据长度和剩余可用内存有关,只要内存够用,可以随便传入数据
- -- 虽然说此处的数据长度没有特别限制,但是调用core中的socket发送接口时,每次最多发送11200字节的数据
- -- 例如此处传入的data长度是112000字节,则在这个send接口中,会循环10次,每次发送11200字节的数据
- -- @number[opt=120] timeout 可选参数,发送超时时间,单位秒
- -- @return result true - 成功,false - 失败
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- -- socketClient:send("12345678")
- function mt:send(data, timeout)
- assert(self.co == coroutine.running(), "socket:send: coroutine mismatch")
- if self.error then
- log.warn('socket.client:send', 'error', self.error)
- return false
- end
- log.debug("socket.send", "total " .. string.len(data or "") .. " bytes", "first 30 bytes", (data or ""):sub(1, 30))
- local sendSize = self.protocol == "UDP" and 1472 or SENDSIZE
- for i = 1, string.len(data or ""), sendSize do
- -- 按最大MTU单元对data分包
- self.wait = "SOCKET_SEND"
- sockectCh395Send(self.id, data:sub(i, i + sendSize - 1))
- self.timerId = sys.timerStart(coroutine.resume, (timeout or 120) * 1000, self.co, false, "TIMEOUT")
- local result, reason = coroutine.yield()
- if not result and reason == 'server close' then
- return false
- end
- if self.timerId and reason ~= "TIMEOUT" then
- sys.timerStop(self.timerId)
- end
- if not result then
- log.info("socket:send" .. self.id, "send fail", reason)
- sys.publish("LIB_SOCKET_SEND_FAIL_IND", self.ssl, self.protocol, self.address, self.port)
- return false
- end
- end
- return true
- end
- --- 同步接收数据
- -- @number[opt=0] timeout 可选参数,接收超时时间,单位毫秒
- -- @string[opt=nil] msg 可选参数,控制socket所在的线程退出recv阻塞状态
- -- @bool[opt=nil] msgNoResume 可选参数,控制socket所在的线程退出recv阻塞状态
- -- false或者nil表示“在recv阻塞状态,收到msg消息,可以退出阻塞状态”,true表示不退出
- -- 此参数仅lib内部使用,应用脚本不要使用此参数
- -- @return result 数据接收结果
- -- true表示成功(接收到了数据)
- -- false表示失败(没有接收到数据)
- -- @return data
- -- 如果result为true,data表示接收到的数据(如果是UDP,返回最新的一包数据;如果是TCP,返回所有收到的数据)
- -- 如果result为false,超时失败,data为"timeout"
- -- 如果result为false,msg控制退出,data为msg的字符串
- -- 如果result为false,socket连接被动断开控制退出,data为"CLOSED"
- -- 如果result为false,PDP断开连接控制退出,data为"IP_ERROR_IND"
- -- @return param 如果是msg控制退出,param的值是msg的参数
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- -- result,data = socketClient:recv(60000,"APP_SOCKET_SEND_DATA")
- function mt:recv(timeout, msg, msgNoResume)
- assert(self.co == coroutine.running(), "socket:recv: coroutine mismatch")
- if self.error then
- log.warn('socket.client:recv', 'error', self.error)
- return false
- end
- self.msgNoResume = msgNoResume
- if msg and not self.iSubscribe then
- self.iSubscribe = msg
- self.subMessage = function(data)
- -- if data then table.insert(self.output, data) end
- if self.wait == "+RECEIVE" and not self.msgNoResume then
- if data then
- table.insert(self.output, data)
- end
- coroutine.resume(self.co, 0xAA)
- end
- end
- sys.subscribe(msg, self.subMessage)
- end
- if msg and #self.output > 0 then
- sys.publish(msg, false)
- end
- if #self.input == 0 then
- self.wait = "+RECEIVE"
- if timeout and timeout > 0 then
- local r, s = sys.wait(timeout)
- if r == nil then
- return false, "timeout"
- elseif r == 0xAA then
- local dat = table.concat(self.output)
- self.output = {}
- return false, msg, dat
- else
- return r, s
- end
- else
- local r, s = coroutine.yield()
- if not r and s == 'server close' then
- return false
- end
- if r == 0xAA then
- local dat = table.concat(self.output)
- self.output = {}
- return false, msg, dat
- else
- return r, s
- end
- end
- end
- if self.protocol == "UDP" then
- local s = table.remove(self.input)
- return true, s
- else
- log.warn("-------------------使用缓冲区---------------")
- local s = table.concat(self.input)
- self.input = {}
- if self.isBlock then
- table.insert(self.input, sockectCh395Recv(self.msg.socket_index, self.msg.recv_len))
- end
- return true, s
- end
- end
- --- 主动关闭并且销毁一个socket
- -- @return nil
- -- @usage
- -- socketClient = socketCh395.tcp()
- -- socketClient:connect("www.baidu.com","80")
- -- socketClient:close()
- function mt:close()
- assert(self.co == coroutine.running(), "socket:close: coroutine mismatch")
- if self.iSubscribe then
- sys.unsubscribe(self.iSubscribe, self.subMessage)
- self.iSubscribe = false
- end
- -- log.info('socketCh395', 'close' .. self.id)
- -- 此处不要再判断状态,否则在连接超时失败时,conneted状态仍然是未连接,会导致无法close
- -- if self.connected then
- log.info("socket:sock_close", self.id)
- local result, reason
- if self.id then
- sockectCh395Close(self.id)
- self.wait = "SOCKET_CLOSE"
- while true do
- result, reason = coroutine.yield()
- if not result and reason == 'server close' then
- return false
- end
- if reason == "RESPONSE" then
- break
- end
- end
- end
- if self.connected then
- self.connected = false
- if socketsConnected > 0 then
- socketsConnected = socketsConnected - 1
- end
- sys.publish("SOCKET_ACTIVE", socketsConnected > 0)
- end
- if self.input then
- self.input = {}
- end
- if self.protocol == 'TCPSERVERCLIENT' then
- sockets[self.id] = true
- else
- if self.id ~= nil then
- sockets[self.id] = nil
- end
- end
- end
- -- socket接收自定义控制处理
- -- @function[opt=nil] rcvCbFnc,socket接收到数据后,执行的回调函数,回调函数的调用形式为:
- -- rcvCbFnc(readFnc,socketIndex,rcvDataLen)
- -- rcvCbFnc内部,会判断是否读取数据,如果读取,执行readFnc(socketIndex,rcvDataLen),返回true;否则返回false或者nil
- function mt:setRcvProc(rcvCbFnc)
- assert(self.co == coroutine.running(), "socket:setRcvProc: coroutine mismatch")
- self.rcvProcFnc = rcvCbFnc
- end
- function on_response(msg)
- local t = {
- [rtos.MSG_SOCK_CLOSE_CNF] = 'SOCKET_CLOSE',
- -- 33
- [rtos.MSG_SOCK_SEND_CNF] = 'SOCKET_SEND',
- -- 32
- [rtos.MSG_SOCK_CONN_CNF] = 'SOCKET_CONNECT'
- -- 34
- }
- if not sockets[msg.socket_index] then
- log.warn('response on nil socket', msg.socket_index, t[msg.id], msg.result)
- return
- end
- if sockets[msg.socket_index] == true then
- return
- end
- log.info(sockets[msg.socket_index].wait, t[msg.id], msg.socket_index, msg.id)
- if sockets[msg.socket_index].wait ~= t[msg.id] then
- log.warn('response on invalid wait', sockets[msg.socket_index].id, sockets[msg.socket_index].wait, t[msg.id],
- msg.socket_index)
- return
- end
- log.info('socket:on_response:', msg.socket_index, t[msg.id], msg.result)
- if sockets[msg.socket_index].protocol == 'TCPSERVERCLIENT' then
- msg.result=0
- end
- coroutine.resume(sockets[msg.socket_index].co, msg.result == 0, 'RESPONSE')
- end
- sys.subscribe('SOCK_CONN_CNF', on_response)
- sys.subscribe('SOCK_CLOSE_CNF', on_response)
- sys.subscribe('SOCK_SEND_CNF', on_response)
- -- 被动关闭
- sys.subscribe('MSG_SOCK_CLOSE_IND', function(msg)
- local data = string.sub(spiSend(spi.SPI_1, string.char(0x2F, msg.socket_index, 0xff, 0xff)), 3, -1)
- log.info('socketCh395', 'close socket ' .. msg.socket_index .. 'state', data:toHex())
- if string.sub(data, 1, 1) ~= '\x00' then
- return
- end
- log.info('socket.rtos.MSG_SOCK_CLOSE_IND',msg.socket_index)
- if not sockets[msg.socket_index] then
- return
- elseif sockets[msg.socket_index] == true then
- return
- elseif sockets[msg.socket_index].protocol == 'TCPSERVERCLIENT' then
- coroutine.resume(sockets[msg.socket_index].co, false, 'CLOSED')
- sockets[msg.socket_index] = true
- return
- end
- if not sockets[msg.socket_index] then
- log.warn('close ind on nil socket', msg.socket_index, msg.id)
- return
- end
- if sockets[msg.socket_index].connected then
- sockets[msg.socket_index].connected = false
- if socketsConnected > 0 then
- socketsConnected = socketsConnected - 1
- end
- sys.publish('SOCKET_ACTIVE', socketsConnected > 0)
- end
- sockets[msg.socket_index].error = 'CLOSED'
- --[[
- if type(socketcore.sock_destroy) == "function" then
- socketcore.sock_destroy(msg.socket_index)
- end]]
- sys.publish('LIB_SOCKET_CLOSE_IND', sockets[msg.socket_index].ssl, sockets[msg.socket_index].protocol,
- sockets[msg.socket_index].address, sockets[msg.socket_index].port)
- coroutine.resume(sockets[msg.socket_index].co, false, 'CLOSED')
- end)
- sys.subscribe('MSG_SOCK_RECV_IND', function(msg)
- if type(sockets[msg.socket_index])~='table' then
- log.warn('close ind on nil socket', msg.socket_index, msg.id)
- return
- end
- log.debug('socket.recv', msg.recv_len, sockets[msg.socket_index].rcvProcFnc)
- if sockets[msg.socket_index].rcvProcFnc then
- sockets[msg.socket_index].rcvProcFnc(msg.recv_data)
- else
- if sockets[msg.socket_index].wait == '+RECEIVE' then
- coroutine.resume(sockets[msg.socket_index].co, true, msg.recv_data)
- else -- 数据进缓冲区,缓冲区溢出采用覆盖模式
- if #sockets[msg.socket_index].input > INDEX_MAX then
- log.error('socket recv', 'out of stack', 'block')
- -- sockets[msg.socket_index].input = {}
- sockets[msg.socket_index].isBlock = true
- sockets[msg.socket_index].msg = msg
- else
- sockets[msg.socket_index].isBlock = false
- table.insert(sockets[msg.socket_index].input, msg.recv_data)
- end
- sys.publish('SOCKET_RECV', msg.socket_index)
- end
- end
- end)
- -- 设置TCP层自动重传的参数
- -- @number[opt=4] retryCnt 重传次数;取值范围0到12
- -- @number[opt=16] retryMaxTimeout 限制每次重传允许的最大超时时间(单位秒),取值范围1到16
- -- @return nil
- -- @usage
- -- setTcpResendPara(3,8)
- -- setTcpResendPara(4,16)
- function setTcpResendPara(retryCnt, retryMaxTimeout)
- ril.request("AT+TCPUSERPARAM=6," .. (retryCnt or 4) .. ",7200," .. (retryMaxTimeout or 16))
- end
- -- 设置域名解析参数
- -- 注意:0027以及之后的core版本才支持此功能
- -- @number[opt=4] retryCnt 重传次数;取值范围1到8
- -- @number[opt=4] retryTimeoutMulti 重传超时时间倍数,取值范围1到5
- -- 第n次重传超时时间的计算方式为:第n次的重传超时基数*retryTimeoutMulti,单位为秒
- -- 重传超时基数表为{1, 1, 2, 4, 4, 4, 4, 4}
- -- 第1次重传超时时间为:1*retryTimeoutMulti 秒
- -- 第2次重传超时时间为:1*retryTimeoutMulti 秒
- -- 第3次重传超时时间为:2*retryTimeoutMulti 秒
- -- ...........................................
- -- 第8次重传超时时间为:8*retryTimeoutMulti 秒
- -- @return nil
- -- @usage
- -- socket.setDnsParsePara(8,5)
- function setDnsParsePara(retryCnt, retryTimeoutMulti)
- ril.request("AT*DNSTMOUT=" .. (retryCnt or 4) .. "," .. (retryTimeoutMulti or 4))
- end
- function setIpStatis(interval)
- end
- --- 打印所有socket的状态
- -- @return 无
- -- @usage socketCh395.printStatus()
- function printStatus()
- for _, client in pairs(sockets) do
- for k, v in pairs(client) do
- log.info('socket.printStatus', 'client', client.id, k, v)
- end
- end
- end
- -- 设置数据传输后,允许进入休眠状态的延时时长
- -- 3024版本以及之后的版本才支持此功能
- -- 此功能设置的参数,设置成功后,掉电会自动保存
- -- @number tm,数据传输后,允许进入休眠状态的延时时长,单位为秒,取值范围1到20
- -- 注意:此时间越短,允许进入休眠状态越快,功耗越低;但是在某些网络环境中,此时间越短,可能会造成数据传输不稳定
- -- 建议在可以接受的功耗范围内,此值设置的越大越好
- -- 如果没有设置此参数,此延时时长是和基站的配置有关,一般来说是10秒左右
- -- @return nil
- -- @usage
- -- socketCh395.setLowPower(5)
- function setLowPower(tm)
- ril.request("AT*RTIME=" .. tm)
- end
|