socketCh395.lua 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569
  1. --- 模块功能:数据链路激活、socketCh395管理(创建、连接、数据收发、状态维护)
  2. -- @module socketCh395
  3. -- @author openLuat
  4. -- @license MIT
  5. -- @copyright openLuat
  6. -- @release 2017.9.25
  7. require "link"
  8. require "utils"
  9. module(..., package.seeall)
  10. local sockets = {}
  11. -- 单次发送数据最大值
  12. local SENDSIZE = 1024
  13. -- 缓冲区最大下标
  14. local INDEX_MAX = 2048
  15. -- 是否有socket正处在链接
  16. local socketsConnected = 0
  17. -- CH395配置信息
  18. local configurationCh395 = nil
  19. -- 以太网模块供电设置函数
  20. local powerCbFnc = nil
  21. -- 获取芯片版本(使用0x44以上版本)
  22. local ch395Version = nil
  23. -- 芯片MAC地址
  24. local CH395MAC = nil
  25. local resvnum = 0
  26. TCPCLIENT = 0
  27. UDPCLIENT = 1
  28. RAW = 3
  29. TCPSERVER = 4
  30. local function str2short(str)
  31. local f, n = pack.unpack(str, '<H')
  32. return f and f > 0 and n or 0
  33. end
  34. local function shorts(n)
  35. return pack.pack('<H', n)
  36. end
  37. local function sub_z(data, num)
  38. return string.sub(data, num + 1, data:len())
  39. end
  40. local function ip2num(str)
  41. if (not (str and #str == 4)) then
  42. return ''
  43. end
  44. local t = {pack.unpack(str, 'bbbb')}
  45. return string.format('%d.%d.%d.%d', t[2], t[3], t[4], t[5])
  46. end
  47. local function iptostr(ip)
  48. local d1, d2, d3, d4 = string.match(ip, '(%d+)%.(%d+)%.(%d+).(%d+)')
  49. return {string.sub(shorts(d1), 1, 1), string.sub(shorts(d2), 1, 1), string.sub(shorts(d3), 1, 1),
  50. string.sub(shorts(d4), 1, 1)}
  51. end
  52. ------------
  53. local function spiSend(id, data)
  54. --log.info('send SPI data:', data:toHex())
  55. local dataSpi
  56. if configurationCh395['spiCs'] then
  57. local setSpi_CS = pins.setup(configurationCh395['spiCs'], 0)
  58. dataSpi = spi.send_recv(id, data)
  59. setSpi_CS(1)
  60. else
  61. dataSpi = spi.send_recv(id, data)
  62. end
  63. -- log.info('recv SPI data', dataSpi:toHex())
  64. return dataSpi
  65. end
  66. -- 命令执行查询
  67. local function inquire2c(time)
  68. local num = 0
  69. while true do
  70. sys.wait(time or 10)
  71. local data = string.sub(spiSend(spi.SPI_1, '\x2c\xff'), 2, 2)
  72. if data ~= '\x10' then
  73. return data
  74. end
  75. num = num + 1
  76. if num > 100 then
  77. return data
  78. end
  79. end
  80. end
  81. -- 获取MAC地址
  82. function getMac()
  83. return CH395MAC
  84. end
  85. -- 本地端口,初始化默认端口
  86. local socketLocalPort = 0
  87. -- 动态获取本地端口号,每次获取累加
  88. local function socketTcpClientPort()
  89. -- socketLocalPort = socketLocalPort + 123
  90. -- if socketLocalPort > 65535 then
  91. -- socketLocalPort = 1000
  92. -- end
  93. -- return socketLocalPort
  94. local time = string.sub(rtos.tick(), 3)
  95. if socketLocalPort < 8 then
  96. socketLocalPort = socketLocalPort + 1
  97. else
  98. socketLocalPort = 0
  99. end
  100. return (socketLocalPort + time) * 5
  101. end
  102. -- 初始化socket
  103. local function SocketClientInit(type, socketId, soalAddress, soalPort, localPort)
  104. localPort = localPort or socketTcpClientPort()
  105. local addr = iptostr(soalAddress)
  106. -- 设置协议类型
  107. if type == TCPCLIENT then
  108. spiSend(spi.SPI_1, string.char(0x34, socketId, 3))
  109. elseif type == UDPCLIENT then
  110. spiSend(spi.SPI_1, string.char(0x34, socketId, 2))
  111. end
  112. -- 设置本地端口
  113. spiSend(spi.SPI_1, '\x33' .. string.char(socketId) .. shorts(tonumber(localPort)))
  114. -- 设置目的端口号
  115. spiSend(spi.SPI_1, '\x32' .. string.char(socketId) .. shorts(tonumber(soalPort)))
  116. -- 设置目的地址
  117. spiSend(spi.SPI_1, string.char(0x31, socketId) .. addr[1] .. addr[2] .. addr[3] .. addr[4])
  118. -- 打开socket
  119. spiSend(spi.SPI_1, string.char(0x35, socketId))
  120. -- 查询执行状态
  121. local state = inquire2c(50)
  122. log.info('socketCh395', 'open socket' .. socketId .. state:toHex())
  123. if state ~= '\x00' or type == UDPCLIENT then
  124. if type ~= UDPCLIENT then
  125. log.info('socketCh395', 'open socket err', state:toHex())
  126. else
  127. sys.timerStart(function()
  128. sys.publish('SOCK_CONN_CNF', {
  129. ['socket_index'] = socketId,
  130. ['id'] = 34,
  131. ['result'] = 0
  132. })
  133. end, 200)
  134. end
  135. return state
  136. end
  137. spiSend(spi.SPI_1, string.char(0x37, socketId))
  138. state = inquire2c()
  139. if state == '\x00' then
  140. --sys.publish('SOCK_CONN_CNF', {
  141. -- ['socket_index'] = socketId,
  142. -- ['id'] = 34,
  143. -- ['result'] = 0
  144. --})
  145. else
  146. log.info('socketCh395', 'open socket' .. socketId, state:toHex())
  147. end
  148. return state
  149. end
  150. -- 配置8路socket收发缓存
  151. local function socketBufferConfig()
  152. -- 只有硬件版本大于47才有4-7路
  153. local b = 0
  154. for i = 0, 7 do
  155. spiSend(spi.SPI_1, string.char(0x52, i, b, 4))
  156. b = b + 4
  157. spiSend(spi.SPI_1, string.char(0x53, i, b, 2))
  158. b = b + 2
  159. sys.wait(500)
  160. end
  161. end
  162. -- 关闭套接字连接
  163. local function sockectCh395Close(socketId)
  164. if sockets[socketId] == nil or sockets[socketId] == true then
  165. log.info('socketCh395', 'close err, not socket ' .. socketId)
  166. end
  167. if sockets[socketId] == true or sockets[socketId].protocol == 'TCPSERVERCLIENT' then
  168. -- server客户端断开连接
  169. spiSend(spi.SPI_1, string.char(0x38, socketId))
  170. local state = inquire2c()
  171. log.info('socketCh395', 'close server socket ' .. socketId)
  172. sys.publish('SOCK_CLOSE_CNF', {
  173. ['socket_index'] = socketId,
  174. ['id'] = 33,
  175. ['result'] = 0
  176. })
  177. elseif sockets[socketId].protocol == 'TCPSERVER' then
  178. -- server关闭,断开连接,关闭所有server通道
  179. log.info('socketCh395', 'close server ' .. socketId)
  180. for i, v in ipairs(sockets) do
  181. if sockets[i] ~= true and not sockets[i] and sockets[i].protocol == 'TCPSERVERCLIENT' then
  182. local id = sockets[i].id
  183. spiSend(spi.SPI_1, string.char(0x38, sockets[i].id))
  184. spiSend(spi.SPI_1, string.char(0x3D, socketId))
  185. sockets[i] = nil
  186. log.info('socketCh395', 'close server socket ' .. id)
  187. end
  188. end
  189. spiSend(spi.SPI_1, string.char(0x3D, socketId))
  190. log.info('socketCh395', 'close server ' .. socketId)
  191. local state = inquire2c()
  192. sys.publish('SOCK_CLOSE_CNF', {
  193. ['socket_index'] = socketId,
  194. ['id'] = 33,
  195. ['result'] = 0
  196. })
  197. else
  198. spiSend(spi.SPI_1, string.char(0x3D, socketId))
  199. local stateClose = inquire2c(10)
  200. log.info('sockectCh395', 'close socket' .. socketId .. 'true' .. stateClose:toHex())
  201. sys.publish('SOCK_CLOSE_CNF', {
  202. ['socket_index'] = socketId,
  203. ['id'] = 33,
  204. ['result'] = 0
  205. })
  206. end
  207. end
  208. local function ipError()
  209. if link.isReady() and link.getNetwork() == link.CH395 then
  210. link.setReady(link.CH395, false)
  211. sys.publish('IP_ERROR_IND')
  212. log.info('socketCh395', 'IP_ERROR_IND')
  213. end
  214. end
  215. -- 处理中断
  216. local function interruptProcess()
  217. local intAll = string.sub(spiSend(spi.SPI_1, '\x19\xff\xff'), 2, -1)
  218. -- log.info('INT30', intAll:toHex())
  219. intAll = str2short(intAll)
  220. if intAll == 0 or intAll == 65535 then
  221. return
  222. end
  223. -- 处理PHY中断
  224. if bit.isset(intAll, 2) then
  225. local statePhy = string.sub(spiSend(spi.SPI_1, '\x26\xff'), 2, -1)
  226. if statePhy == '\x01' then
  227. sys.publish("PHY_RESULT", false)
  228. log.info('socketCh395', 'phy false')
  229. ipError()
  230. elseif statePhy == '\x08' then
  231. sys.publish("PHY_RESULT", true)
  232. log.info('socketCh395', 'phy true')
  233. end
  234. end
  235. -- 处理DHCP中断
  236. if bit.isset(intAll, 3) then
  237. -- DHCP中断
  238. local stateDhcp = string.sub(spiSend(spi.SPI_1, '\x42\xff'), 2, -1)
  239. if stateDhcp == '\x00' then
  240. log.info('socketCh395', 'DHCP true')
  241. elseif stateDhcp == '\x01' then
  242. log.info('socketCh395', 'DHCP false')
  243. ipError()
  244. end
  245. end
  246. -- 处理不可达中断
  247. if bit.isset(intAll, 0) then
  248. -- 读取不可达信息?
  249. log.info('socketCh395', 'Unreachable interrupt')
  250. -- getUnreachIpport()
  251. end
  252. -- 处理IP冲突中断
  253. if bit.isset(intAll, 1) then
  254. log.info("IP", 'IP conflict')
  255. -- 建议重新修改本地IP,并初始化芯片(未加)
  256. end
  257. -- socket0-7中断
  258. local socketIntId = {}
  259. for i = 4, 11 do
  260. if bit.isset(intAll, i) then
  261. table.insert(socketIntId, (i - 4))
  262. end
  263. end
  264. local socketCloss = {}
  265. -- 逐个socket查询中断并处理
  266. for q = 1, #socketIntId do
  267. local socketState = string.sub(spiSend(spi.SPI_1, string.char(0x30, socketIntId[q], 0xff, 0xff)), 3, -1)
  268. -- log.info('INT19:' .. socketIntId[q], socketState:toHex())
  269. socketState = str2short(socketState)
  270. -- TCP连接
  271. if bit.isset(socketState, 3) then
  272. -- sockets[socketIntId[q]].connected = true
  273. if sockets[socketIntId[q]] == true then
  274. local data = string.sub(spiSend(spi.SPI_1,
  275. string.char(0x2d, socketIntId[q], 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)), 3, 8)
  276. -- server
  277. local socketData = {
  278. id = socketIntId[q],
  279. ip = ip2num(string.sub(data, 1, 4)),
  280. port = str2short(string.sub(data, 5, 6))
  281. }
  282. sys.publish('tcpServer', socketData)
  283. else
  284. sys.publish('SOCK_CONN_CNF', {
  285. ['socket_index'] = socketIntId[q],
  286. ['id'] = 34,
  287. ['result'] = 0
  288. })
  289. end
  290. end
  291. -- 接收缓冲区非空
  292. if bit.isset(socketState, 2) then
  293. local data_leng
  294. local data
  295. data_leng = string.sub(spiSend(spi.SPI_1, string.char(0x3b, socketIntId[q], 0xff, 0xff)), 3, -1)
  296. -- if data_leng == '\x00\x00' then
  297. -- break
  298. -- end
  299. data = string.sub(spiSend(spi.SPI_1, string.char(0x3c, socketIntId[q]) .. data_leng ..
  300. string.rep('\xff', str2short(data_leng))), 5, -1)
  301. sys.timerStart(function()
  302. sys.publish('MSG_SOCK_RECV_IND', {
  303. ['socket_index'] = socketIntId[q],
  304. ['id'] = 31,
  305. ['result'] = 0,
  306. ['recv_len'] = str2short(data_leng),
  307. ['recv_data'] = data
  308. })
  309. end, 10)
  310. -- data_leng = string.sub(spiSend(spi.SPI_1, string.char(0x3b, socketIntId[q], 0xff, 0xff)), 3, -1)
  311. -- data = string.sub(spiSend(spi.SPI_1, string.char(0x3c, socketIntId[q]) .. data_leng ..
  312. -- string.rep('\xff', str2short(data_leng))), 5, -1)
  313. -- sys.publish('MSG_SOCK_RECV_IND', {
  314. -- ['socket_index'] = socketIntId[q],
  315. -- ['id'] = 31,
  316. -- ['result'] = 0,
  317. -- ['recv_len'] = str2short(data_leng),
  318. -- ['recv_data'] = data
  319. -- })
  320. end
  321. -- 发送缓冲区空闲
  322. if bit.isset(socketState, 0) then
  323. if sockets[socketIntId[q]] and sockets[socketIntId[q]] ~= true then
  324. sockets[socketIntId[q]].sendstate = true
  325. else
  326. log.info('socketCh395', 'sendstate err:' .. socketIntId[q])
  327. end
  328. end
  329. -- 发送成功
  330. if bit.isset(socketState, 1) then
  331. sys.publish('SOCK_SEND_CNF', {
  332. ['socket_index'] = socketIntId[q],
  333. ['id'] = 32,
  334. ['result'] = 0
  335. })
  336. end
  337. -- TCP断开
  338. if bit.isset(socketState, 4) then
  339. table.insert(socketCloss, {
  340. ['socket_index'] = socketIntId[q],
  341. ['id'] = 33,
  342. ['result'] = 0
  343. })
  344. end
  345. -- 超时
  346. if bit.isset(socketState, 6) then
  347. -- 超时处理,重新开启重新连接(未加)
  348. -- 打开socket
  349. log.info('socketCh395', 'socket conn timeout' .. socketIntId[q], sockets[socketIntId[q]], socketIntId[q])
  350. if not sockets[socketIntId[q]] then
  351. sockectCh395Close(socketIntId[q])
  352. elseif sockets[socketIntId[q]] ~= 0 then
  353. local ty = sockets[socketIntId[q]].protocol
  354. local soalAddress = sockets[socketIntId[q]].address
  355. local soalPort = sockets[socketIntId[q]].port
  356. local localPort = sockets[socketIntId[q]].localPort
  357. sockectCh395Close(socketIntId[q])
  358. --if ty == 'TCP' then
  359. --ty = TCPCLIENT
  360. --elseif ty == 'UDP' then
  361. --ty = UDPCLIENT
  362. --end
  363. --SocketClientInit(ty, socketIntId[q], soalAddress, soalPort, localPort)
  364. end
  365. end
  366. end
  367. for i = 0, 7 do
  368. if sockets[i] then
  369. local data_leng
  370. local data
  371. data_leng = string.sub(spiSend(spi.SPI_1, string.char(0x3b, i, 0xff, 0xff)), 3, -1)
  372. if data_leng ~= "\x00\x00" then
  373. data = string.sub(spiSend(spi.SPI_1,
  374. string.char(0x3c, i) .. data_leng .. string.rep('\xff', str2short(data_leng))), 5, -1)
  375. sys.timerStart(function()
  376. sys.publish('MSG_SOCK_RECV_IND', {
  377. ['socket_index'] = i,
  378. ['id'] = 31,
  379. ['result'] = 0,
  380. ['recv_len'] = str2short(data_leng),
  381. ['recv_data'] = data
  382. })
  383. end, 10)
  384. end
  385. end
  386. end
  387. for w = 1, #socketCloss do
  388. local data =
  389. string.sub(spiSend(spi.SPI_1, string.char(0x2F, socketCloss[w]['socket_index'], 0xff, 0xff)), 3, -1)
  390. local data1 = string.sub(data, 1, 1)
  391. local data2 = string.sub(data, 2, 2)
  392. -- if data1 == '\x00' then
  393. if not sockets[socketCloss[w]['socket_index']] or sockets[socketCloss[w]['socket_index']] == true then
  394. sys.timerStart(function(...)
  395. log.info('socketCh395', 'socket ' .. socketCloss[w]['socket_index'] .. 'state' .. data:toHex())
  396. sys.publish('MSG_SOCK_CLOSE_IND', socketCloss[w])
  397. log.info('socketCh395', 'Disconnection socket ', socketCloss[w]['socket_index'])
  398. end, 200)
  399. elseif sockets[socketCloss[w]['socket_index']].protocol == 'TCPSERVERCLIENT' then
  400. -- sockets[socketCloss[w]['socket_index']]=true
  401. sys.timerStart(function(...)
  402. log.info('socketCh395', 'socket ' .. socketCloss[w]['socket_index'] .. 'state' .. data:toHex())
  403. sys.publish('MSG_SOCK_CLOSE_IND', socketCloss[w])
  404. log.info('socketCh395', 'Disconnection socket ', socketCloss[w]['socket_index'])
  405. end, 200)
  406. else
  407. sys.timerStart(function(...)
  408. log.info('socketCh395', 'socket ' .. socketCloss[w]['socket_index'] .. 'state' .. data:toHex())
  409. sys.publish('MSG_SOCK_CLOSE_IND', socketCloss[w])
  410. log.info('socketCh395', 'Disconnection socket ', socketCloss[w]['socket_index'])
  411. end, 200)
  412. end
  413. -- end
  414. end
  415. sys.wait(10)
  416. end
  417. local number = 0
  418. sys.taskInit(function()
  419. while true do
  420. if number > 0 or sys.waitUntil("interruptProcess") then
  421. interruptProcess()
  422. number = number - 1
  423. -- sys.wait(5)
  424. end
  425. end
  426. end)
  427. -- 配置中断检测
  428. local function setInt(state)
  429. if state then
  430. pio.pin.setdebounce(5)
  431. pins.setup(configurationCh395['intPin'], function(a)
  432. if a == 2 then
  433. number = number + 2
  434. sys.publish("interruptProcess")
  435. else
  436. end
  437. end)
  438. pio.pin.setdebounce(20)
  439. else
  440. pins.close(configurationCh395['intPin'])
  441. end
  442. end
  443. --- 初始化CH395模块
  444. -- @table para 取值如下:
  445. -- para为table类型,表示以太网的配置参数,参数结构如下:
  446. -- {
  447. -- mode = 1, --1表示客户端;2表示服务器;默认为1
  448. -- intPin = pio.P0_22, --以太网芯片中断通知引脚
  449. -- rstPin = pio.P0_23, --复位以太网芯片引脚
  450. -- clientNum = 6, --server可连路数
  451. -- spiCs = pio.P0_23, --SPI片选
  452. -- CH395MAC = "84C2E4A82950", --MAC地址
  453. -- localAddr = "192.168.1.112", --本机的地址
  454. -- localSubnetMas = "255.255.255.0", --子网掩码
  455. -- localPort = 1888, --server本机的端口
  456. -- spiCs=pio.P0_7, --spi片选
  457. -- localGateway = "192.168.1.1", --本机的网关地址
  458. -- func=function(id, msg, dat)end, --中断处理函数,处理server中断事件
  459. -- powerFunc=function(state) end --控制以太网模块的供电开关函数,ret为true开启供电,false关闭供电
  460. -- spi = {spi.SPI_1,0,0,8,800000}, --SPI通道参数,id,cpha,cpol,dataBits,clock,默认spi.SPI_1,0,0,8,800000
  461. -- }
  462. -- @return result 数据接收结果
  463. -- true表示成功
  464. -- false表示失败
  465. -- @usage
  466. -- socketCh395.open(para)
  467. function open(para)
  468. configurationCh395 = para
  469. powerCbFnc = nil or para['powerFunc']
  470. -- 供电及其他前置条件
  471. if powerCbFnc then
  472. powerCbFnc(true)
  473. end
  474. -- 复位芯片
  475. spiSend(spi.SPI_1, '\x05')
  476. -- 开启SPI
  477. if not spi.setup(para['spi'][1], para['spi'][2], para['spi'][3], para['spi'][4], para['spi'][5], 1) == 1 then
  478. log.info('socketCh395', 'open spi err')
  479. return ''
  480. end
  481. -- 设置中断
  482. setInt(true)
  483. -- 芯片进入SPI模式
  484. local setGpioFnc_RSTI = pins.setup(para['rstPin'], 0)
  485. setGpioFnc_RSTI(0)
  486. sys.wait(100)
  487. setGpioFnc_RSTI(1)
  488. sys.wait(200)
  489. -- 测试是否成功建立通讯
  490. local state06 = string.sub(spiSend(spi.SPI_1, '\x06\x55\xff'), 3, 3)
  491. state06 = state06 == '\xaa'
  492. log.info('CH395 state', state06)
  493. if not state06 then
  494. log.info('socketCh395', 'err cannot work')
  495. return ''
  496. end
  497. -- server多连接设置
  498. if para['mode'] == 2 then
  499. spiSend(spi.SPI_1, '\x55\x02')
  500. local stateInit = inquire2c(50)
  501. if stateInit ~= '\x00' then
  502. log.info('open server')
  503. else
  504. log.info('open server err', stateInit:toHex())
  505. end
  506. end
  507. -- 获取芯片版本
  508. ch395Version = string.sub(spiSend(spi.SPI_1, '\x01\xff'), 2, 2)
  509. -- 配置芯片信息
  510. if para['localAddr'] and para['localGateway'] then
  511. -- 配置本地信息
  512. local gateway = iptostr(para['localGateway'])
  513. local addr = iptostr(para['localAddr'])
  514. spiSend(spi.SPI_1, '\x22' .. addr[1] .. addr[2] .. addr[3] .. addr[4])
  515. spiSend(spi.SPI_1, '\x23' .. gateway[1] .. gateway[2] .. gateway[3] .. gateway[4])
  516. if para['localSubnetMas'] then
  517. local subnetMas = iptostr(para['localSubnetMas'])
  518. spiSend(spi.SPI_1, '\x24' .. subnetMas[1] .. subnetMas[2] .. subnetMas[3] .. subnetMas[4])
  519. end
  520. end
  521. -- 设置收发缓存(默认8路)
  522. socketBufferConfig()
  523. -- 模块初始化
  524. spiSend(spi.SPI_1, '\x27')
  525. local stateInit = inquire2c(50)
  526. if stateInit ~= '\x00' then
  527. log.info('socketCh395', 'ch395 INIT err' .. stateInit:toHex())
  528. return ''
  529. end
  530. local result, result2 = sys.waitUntil("PHY_RESULT", 60000)
  531. if not result or not result2 then
  532. return ''
  533. end
  534. -- 设置MAC地址
  535. if para['CH395MAC'] and string.len(para['CH395MAC']) == 12 then
  536. spiSend(spi.SPI_1, '\x21' .. string.fromHex(para['CH395MAC']))
  537. sys.wait(200)
  538. end
  539. -- 获取芯片MAC
  540. CH395MAC = string.sub(spiSend(spi.SPI_1, string.fromHex('40FFFFFFFFFFFF2cff')), 2, 7)
  541. if CH395MAC == string.char(0, 0, 0, 0, 0, 0) then
  542. CH395MAC = nil
  543. end
  544. -- DHCP
  545. if not (para['localAddr'] and para['localGateway']) then
  546. spiSend(spi.SPI_1, '\x41\x01')
  547. local stateDhcp = inquire2c(30)
  548. if stateDhcp ~= '\x00' then
  549. log.info('socketCh395', 'ch395 INIT err' .. stateDhcp:toHex())
  550. return ''
  551. end
  552. end
  553. -- 获取本地IP
  554. for q = 1, 20 do
  555. sys.wait(500)
  556. local dataIp = string.sub(spiSend(spi.SPI_1, string.fromHex('43ffffffffffffffffffffffffffffffffffffffff')), 2,
  557. -1)
  558. if link.getNetwork() == link.CH395 and string.sub(dataIp, 1, 4) ~= '\xff\xff\xff\xff' and
  559. string.sub(dataIp, 1, 4) ~= '\x00\x00\x00\x00' then
  560. local ch395Ip = ip2num(string.sub(dataIp, 1, 4))
  561. log.info('ip', ch395Ip)
  562. link.setReady(link.CH395, true)
  563. sys.publish('IP_READY_IND')
  564. return ch395Ip
  565. end
  566. end
  567. return ''
  568. end
  569. --- 开关模块
  570. function close()
  571. link.setReady(link.CH395, false)
  572. sys.publish('IP_ERROR_IND')
  573. -- 关闭所有socket
  574. for i = 0, 7 do
  575. spiSend(spi.SPI_1, string.char(0x3D, i))
  576. sockets[i] = nil
  577. end
  578. -- 关闭中断检测
  579. setInt(false)
  580. -- 关闭SPI
  581. if not spi.close(configurationCh395['spi'][1]) == 1 then
  582. log.info('socketCh395 close spi err', configurationCh395['spi'][1], configurationCh395['spi'][2],
  583. configurationCh395['spi'][3], configurationCh395['spi'][4], configurationCh395['spi'][5], 1)
  584. return false
  585. end
  586. -- 关闭模块
  587. if powerCbFnc then
  588. powerCbFnc(false)
  589. end
  590. return true
  591. end
  592. ---建立套接字连接
  593. local function sockectCh395Conn(type, addr, port, lcoalPort, data)
  594. local socketId = nil
  595. for i = 0, 7 do
  596. if not sockets[i] then
  597. socketId = i
  598. data.id=i
  599. sockets[i] = data
  600. break
  601. end
  602. if i == 7 then
  603. log.info('socketCh395', 'No socket available ')
  604. return nil
  605. end
  606. end
  607. if type == TCPCLIENT or type == UDPCLIENT then
  608. local tcpClientState = SocketClientInit(type, socketId, addr, port, lcoalPort)
  609. if tcpClientState == '\x00' then
  610. return socketId
  611. else
  612. spiSend(spi.SPI_1, string.char(0x3D, socketId))
  613. local stateClose = inquire2c(50)
  614. if stateClose == '\x00' then
  615. log.info('sockectCh395', 'close socket' .. socketId .. 'true')
  616. end
  617. sockets[socketId] = nil
  618. return nil
  619. end
  620. elseif type == TCPSERVER then
  621. end
  622. end
  623. -- 发送数据
  624. local function sockectCh395Send(socketId, data)
  625. for i = 1, 10 do
  626. if sockets[socketId] and sockets[socketId] ~= true and sockets[socketId].sendstate then
  627. spiSend(spi.SPI_1, '\x39' .. string.char(socketId) .. shorts(#data) .. data)
  628. local state = inquire2c(50)
  629. if state == '\x00' then
  630. sys.publish('SOCK_SEND_CNF', {
  631. ['socket_index'] = socketId,
  632. ['id'] = 32,
  633. ['result'] = 0
  634. })
  635. else
  636. sys.publish('SOCK_SEND_CNF', {
  637. ['socket_index'] = socketId,
  638. ['id'] = 32,
  639. ['result'] = 1
  640. })
  641. end
  642. log.info('socketCh395', socketId .. 'send state' .. state:toHex())
  643. break
  644. elseif not sockets[socketId] or sockets[socketId] == true then
  645. -- log.info('socketCh395', 'send err, not socket ' .. socketId)
  646. else
  647. sys.wait(100)
  648. end
  649. end
  650. end
  651. -- 接收数据
  652. local function sockectCh395Recv(socketId, buffLen)
  653. local data_leng = string.sub(spiSend(spi.SPI_1, string.char(0x3b, socketId, 0xff, 0xff)), 3, -1)
  654. local data = string.sub(spiSend(spi.SPI_1, string.char(0x3c, socketId) .. data_leng ..
  655. string.rep('\xff', str2short(data_leng))), 5, -1)
  656. return data
  657. end
  658. -- table 深拷贝
  659. local function clone(tb)
  660. local ret = {}
  661. for k, v in pairs(tb) do
  662. ret[k] = type(v) == "table" and clone(v) or v
  663. end
  664. return ret
  665. end
  666. -- 创建server
  667. local function initServer(port, num, data)
  668. if num > 7 then
  669. return
  670. end
  671. local dd = true
  672. local serverTable = {}
  673. local serverid = nil
  674. for i = 0, 7 do
  675. if not sockets[i] then
  676. table.insert(serverTable, i)
  677. if dd then
  678. sockets[i] = data
  679. dd = false
  680. else
  681. sockets[i] = clone(data)
  682. end
  683. if #serverTable == num + 1 then
  684. break
  685. end
  686. end
  687. if i == 7 then
  688. log.info('socketCh395', 'No socket available ')
  689. for q = 1, #serverTable do
  690. sockets[serverTable[q]] = nil
  691. end
  692. return nil
  693. end
  694. end
  695. for i = 1, #serverTable do
  696. spiSend(spi.SPI_1, string.char(0x34, serverTable[i], 3))
  697. spiSend(spi.SPI_1, string.char(0x33, serverTable[i]) .. shorts(port))
  698. if i == 1 then
  699. spiSend(spi.SPI_1, string.char(0x35, serverTable[i]))
  700. sockets[i].id = serverTable[i]
  701. serverid = serverTable[i]
  702. local state = inquire2c(50)
  703. if state == '\x00' then
  704. sockets[serverTable[i]].id = serverTable[i]
  705. sockets[serverTable[i]].protocol = 'TCPSERVER'
  706. else
  707. log.info('socket open err', state:toHex())
  708. log.info('socketCh395', 'socket open err')
  709. end
  710. else
  711. local state = inquire2c(50)
  712. if state == '\x00' then
  713. log.info('socketCh395', 'server open' .. serverTable[i])
  714. sockets[serverTable[i]].protocol = 'TCPSERVERCLIENT' .. serverTable[i]
  715. sockets[serverTable[i]] = true
  716. end
  717. if i == num + 1 then
  718. spiSend(spi.SPI_1, string.char(0x36, serverid))
  719. local state = inquire2c(50)
  720. if state == '\x00' then
  721. return serverid
  722. end
  723. end
  724. end
  725. end
  726. end
  727. ------------------------
  728. local function errorInd(error)
  729. local coSuspended = {}
  730. for _, c in pairs(sockets) do -- IP状态出错时,通知所有已连接的socket
  731. if c ~= true then
  732. c.error = error
  733. -- 不能打开如下3行代码,IP出错时,会通知每个socket,socket会主动close
  734. -- 如果设置了connected=false,则主动close时,直接退出,不会执行close动作,导致core中的socket资源没释放
  735. -- 会引发core中socket耗尽以及socket id重复的问题
  736. -- c.connected = false
  737. -- socketsConnected = c.connected or socketsConnected
  738. -- if error == 'CLOSED' then sys.publish("SOCKET_ACTIVE", socketsConnected) end
  739. if c.co and coroutine.status(c.co) == "suspended" then
  740. -- coroutine.resume(c.co, false)
  741. table.insert(coSuspended, c.co)
  742. end
  743. end
  744. end
  745. for k, v in pairs(coSuspended) do
  746. if v and coroutine.status(v) == "suspended" then
  747. coroutine.resume(v, false, error)
  748. end
  749. end
  750. end
  751. sys.subscribe("IP_ERROR_IND", function()
  752. errorInd('IP_ERROR_IND')
  753. end)
  754. -- sys.subscribe('IP_SHUT_IND', function()errorInd('CLOSED') end)
  755. -- 创建socket函数
  756. local mt = {}
  757. mt.__index = mt
  758. local function socket(protocol, cert, tCoreExtPara)
  759. local ssl = protocol:match("SSL")
  760. local co = coroutine.running()
  761. if not co then
  762. log.warn("socket.socket: socket must be called in coroutine")
  763. return nil
  764. end
  765. -- if protocol == 'TCPSERVER' and type(tCoreExtPara) == 'table' then
  766. -- protocol
  767. -- end
  768. -- 实例的属性参数表
  769. local o = {
  770. id = nil,
  771. protocol = protocol,
  772. tCoreExtPara = tCoreExtPara,
  773. ssl = ssl,
  774. cert = cert,
  775. co = co,
  776. input = {},
  777. output = {},
  778. wait = "",
  779. connected = false,
  780. iSubscribe = false,
  781. subMessage = nil,
  782. isBlock = false,
  783. msg = nil,
  784. rcvProcFnc = nil,
  785. sendstate = true, -- 发送缓冲区状态,true为空闲,可发送数据
  786. localPort = nil -- 本地端口
  787. }
  788. if tCoreExtPara and tCoreExtPara['localport'] and type(tCoreExtPara['localport']) == 'number' then
  789. o.localPort = tCoreExtPara['port']
  790. end
  791. if protocol == 'TCPSERVER' and tCoreExtPara['type']== 'TCPSERVER' then
  792. o.port = configurationCh395["localPort"]
  793. local id = initServer(configurationCh395["localPort"], configurationCh395["clientNum"], setmetatable(o, mt))
  794. if not id then
  795. log.info('socketCh395', 'server socket err')
  796. return
  797. end
  798. elseif protocol == 'TCPSERVER' and tCoreExtPara['type']~= 'TCPSERVER' then
  799. o.address = tCoreExtPara['ip']
  800. o.port = tCoreExtPara['port']
  801. o.id = tCoreExtPara['id']
  802. o.protocol = 'TCPSERVERCLIENT'
  803. sockets[tCoreExtPara['id']] = setmetatable(o, mt)
  804. end
  805. return setmetatable(o, mt)
  806. end
  807. --- 创建基于TCP的socket对象
  808. -- @bool[opt=nil] ssl 是否为ssl连接,true表示是,其余表示否
  809. -- @table[opt=nil] cert 保留参数,ssl功能还未实现。
  810. -- @table[opt=nil] tCoreExtPara 建立链接扩展参数
  811. -- {
  812. -- id =0, --server socket索引ID
  813. -- ip ="192.168.1.1", --server socket client ip
  814. -- port ="8000", --server socket client port
  815. -- type ="TCPSERVER", --server socket type
  816. -- localport ="8000", -- socket client port
  817. -- }
  818. -- @return client,创建成功返回socket客户端对象;创建失败返回nil
  819. function tcp(ssl, cert, tCoreExtPara)
  820. if tCoreExtPara and tCoreExtPara['type'] == "TCPSERVER" then
  821. return socket("TCPSERVER", nil, tCoreExtPara)
  822. elseif tCoreExtPara and tCoreExtPara['type'] ~= "TCPSERVER" then
  823. return socket("TCPSERVER", nil, tCoreExtPara)
  824. end
  825. return socket("TCP" .. (ssl == true and "SSL" or ""), (ssl == true) and cert or nil, tCoreExtPara)
  826. end
  827. --- 创建基于UDP的socket对象
  828. -- @return client,创建成功返回socket客户端对象;创建失败返回nil
  829. -- @usage c = socketCh395.udp()
  830. function udp(localPort)
  831. return socket("UDP", nil, localPort)
  832. end
  833. --- 连接服务器
  834. -- @string address 服务器地址,支持ip和域名
  835. -- @param port string或者number类型,服务器端口
  836. -- @number[opt=120] timeout 可选参数,连接超时时间,单位秒
  837. -- @return bool result true - 成功,false - 失败
  838. -- @return string ,id '0' -- '8' ,返回通道ID编号
  839. -- @usage
  840. -- socketClient = socketCh395.tcp()
  841. -- socketClient:connect("www.baidu.com","80")
  842. function mt:connect(address, port, timeout)
  843. assert(self.co == coroutine.running(), "socket:connect: coroutine mismatch")
  844. log.info('socketCh395', 'socket data' .. self.protocol, address, port)
  845. if not link.isReady() then
  846. log.info("socket.connect: ip not ready")
  847. return false
  848. end
  849. self.address = address
  850. self.port = port
  851. local tCoreExtPara = self.tCoreExtPara or {}
  852. -- 默认缓冲区大小
  853. local rcvBufferSize = tCoreExtPara.rcvBufferSize or 0
  854. local d1, d2, d3, d4 = string.match(address, '(%d+)%.(%d+)%.(%d+).(%d+)')
  855. if not (d1 == nil or d2 == nil or d3 == nil or d4 == nil) then
  856. if self.protocol == 'TCP' then
  857. self.id = sockectCh395Conn(TCPCLIENT, address, port, self.localPort, self)
  858. elseif self.protocol == 'TCPSSL' then
  859. -- 未实现
  860. log.info("socketCh395", "no ssl")
  861. else
  862. self.id = sockectCh395Conn(UDPCLIENT, address, port, self.localPort, self)
  863. end
  864. else
  865. self.id = -2
  866. end
  867. if type(socketcore.sock_conn_ext) == "function" then
  868. if not self.id or self.id < 0 then
  869. if self.id == -2 then
  870. require "http"
  871. -- 请求腾讯云免费HttpDns解析
  872. http.request("GET", "119.29.29.29/d?dn=" .. address, nil, nil, nil, 40000,
  873. function(result, statusCode, head, body)
  874. log.info("socket.httpDnsCb", result, statusCode, head, body)
  875. sys.publish("SOCKET_HTTPDNS_RESULT_" .. address .. "_" .. port, result, statusCode, head, body)
  876. end)
  877. local _, result, statusCode, head, body = sys.waitUntil(
  878. "SOCKET_HTTPDNS_RESULT_" .. address .. "_" .. port)
  879. -- DNS解析成功
  880. if result and statusCode == "200" and body and body:match("^[%d%.]+") then
  881. return self:connect(body:match("^([%d%.]+)"), port, timeout)
  882. end
  883. end
  884. self.id = nil
  885. end
  886. end
  887. if not self.id then
  888. log.info("socket:connect: core sock conn error", self.protocol, address, port, self.cert)
  889. return false
  890. end
  891. log.info("socket:connect-coreid,prot,addr,port,cert,timeout", self.id, self.protocol, address, port, self.cert,
  892. timeout or 120)
  893. sockets[self.id] = self
  894. self.wait = "SOCKET_CONNECT"
  895. self.timerId = sys.timerStart(coroutine.resume, (timeout or 120) * 1000, self.co, false, "TIMEOUT")
  896. local result, reason = coroutine.yield()
  897. if not result and reason == 'server close' then
  898. return false
  899. end
  900. if self.timerId and reason ~= "TIMEOUT" then
  901. sys.timerStop(self.timerId)
  902. end
  903. if not result then
  904. log.info("socket:connect: connect fail" .. self.id, reason)
  905. if reason == "RESPONSE" then
  906. sockets[self.id] = nil
  907. self.id = nil
  908. end
  909. sys.publish("LIB_SOCKET_CONNECT_FAIL_IND", self.ssl, self.protocol, address, port)
  910. return false
  911. end
  912. log.info("socket:connect: connect ok")
  913. if not self.connected then
  914. self.connected = true
  915. socketsConnected = socketsConnected + 1
  916. sys.publish("SOCKET_ACTIVE", socketsConnected > 0)
  917. end
  918. return true, self.id
  919. end
  920. function mt:serverClose()
  921. if not self then
  922. return false
  923. end
  924. if self.error then
  925. log.warn('socket.client:asyncSelect', 'error', self.error)
  926. return false
  927. end
  928. coroutine.resume(self.co, false, 'server close')
  929. end
  930. --- server发送数据
  931. -- @number[opt=nil] keepAlive 服务器和客户端最大通信间隔时间,也叫心跳包最大时间,单位秒
  932. -- @string[opt=nil] pingreq 心跳包的字符串
  933. -- @return boole,false 失败,true 表示成功
  934. -- @usage
  935. -- socketClient = socketCh395.tcp()
  936. -- socketClient:connect("www.baidu.com","80")
  937. -- while socketClient:serverSelect() do end
  938. function mt:serverSelect(keepAlive, pingreq)
  939. assert(self.co == coroutine.running(), "socket:asyncSelect: coroutine mismatch")
  940. if self.error then
  941. log.warn('socket.client:asyncSelect', 'error', self.error)
  942. return false
  943. end
  944. self.wait = "SOCKET_SEND"
  945. local dataLen = 0
  946. -- log.info("socket.asyncSelect #self.output",#self.output)
  947. while #self.output ~= 0 do
  948. local data = table.concat(self.output)
  949. dataLen = string.len(data)
  950. self.output = {}
  951. local sendSize = SENDSIZE
  952. for i = 1, dataLen, sendSize do
  953. -- 按最大MTU单元对data分包
  954. sockectCh395Send(self.id, data:sub(i, i + sendSize - 1))
  955. if self.timeout then
  956. self.timerId = sys.timerStart(coroutine.resume, self.timeout * 1000, self.co, false, "TIMEOUT")
  957. end
  958. -- log.info("socket.asyncSelect self.timeout",self.timeout)
  959. local result, reason = coroutine.yield()
  960. if not result and reason == 'server close' then
  961. return false
  962. end
  963. log.info('发送结果', result, reason)
  964. if self.timerId and reason ~= "TIMEOUT" then
  965. sys.timerStop(self.timerId)
  966. end
  967. sys.publish("SOCKET_ASYNC_SEND", result)
  968. if not result then
  969. sys.publish("LIB_SOCKET_SEND_FAIL_IND", self.ssl, self.protocol, self.address, self.port)
  970. log.warn('socket.asyncSelect', 'send error', data:sub(i, i + sendSize - 1))
  971. return false
  972. end
  973. end
  974. end
  975. self.wait = "SOCKET_WAIT"
  976. -- log.info("socket.asyncSelect",dataLen,self.id)
  977. if dataLen > 0 then
  978. sys.publish("SOCKET_SEND", self.id, true)
  979. end
  980. if keepAlive and keepAlive ~= 0 then
  981. if type(pingreq) == "function" then
  982. sys.timerStart(pingreq, keepAlive * 1000)
  983. else
  984. sys.timerStart(self.asyncSend, keepAlive * 1000, self, pingreq or "\0")
  985. end
  986. end
  987. local result, reason = coroutine.yield()
  988. if not result and reason == 'server close' then
  989. return false
  990. end
  991. return result, reason
  992. end
  993. --- 异步发送数据
  994. -- @number[opt=nil] keepAlive 服务器和客户端最大通信间隔时间,也叫心跳包最大时间,单位秒
  995. -- @string[opt=nil] pingreq 心跳包的字符串
  996. -- @return boole,false 失败,true 表示成功
  997. -- @usage
  998. -- socketClient = socketCh395.tcp()
  999. -- socketClient:connect("www.baidu.com","80")
  1000. -- while socketClient:asyncSelect() do end
  1001. function mt:asyncSelect(keepAlive, pingreq)
  1002. assert(self.co == coroutine.running(), "socket:asyncSelect: coroutine mismatch")
  1003. if self.error then
  1004. log.warn('socket.client:asyncSelect', 'error', self.error)
  1005. return false
  1006. end
  1007. self.wait = "SOCKET_SEND"
  1008. local dataLen = 0
  1009. -- log.info("socket.asyncSelect #self.output",#self.output)
  1010. while #self.output ~= 0 do
  1011. local data = table.concat(self.output)
  1012. dataLen = string.len(data)
  1013. self.output = {}
  1014. local sendSize = self.protocol == "UDP" and 1472 or SENDSIZE
  1015. for i = 1, dataLen, sendSize do
  1016. -- 按最大MTU单元对data分包
  1017. -- socketcore.sock_send(self.id, data:sub(i, i + sendSize - 1))
  1018. sockectCh395Send(self.id, data:sub(i, i + sendSize - 1))
  1019. if self.timeout then
  1020. self.timerId = sys.timerStart(coroutine.resume, self.timeout * 1000, self.co, false, "TIMEOUT")
  1021. end
  1022. -- log.info("socket.asyncSelect self.timeout",self.timeout)
  1023. local result, reason = coroutine.yield()
  1024. if not result and reason == 'server close' then
  1025. return false
  1026. end
  1027. if self.timerId and reason ~= "TIMEOUT" then
  1028. sys.timerStop(self.timerId)
  1029. end
  1030. sys.publish("SOCKET_ASYNC_SEND", result)
  1031. if not result then
  1032. sys.publish("LIB_SOCKET_SEND_FAIL_IND", self.ssl, self.protocol, self.address, self.port)
  1033. -- log.warn('socket.asyncSelect', 'send error')
  1034. return false
  1035. end
  1036. end
  1037. end
  1038. self.wait = "SOCKET_WAIT"
  1039. -- log.info("socket.asyncSelect",dataLen,self.id)
  1040. if dataLen > 0 then
  1041. sys.publish("SOCKET_SEND", self.id, true)
  1042. end
  1043. if keepAlive and keepAlive ~= 0 then
  1044. if type(pingreq) == "function" then
  1045. sys.timerStart(pingreq, keepAlive * 1000)
  1046. else
  1047. sys.timerStart(self.asyncSend, keepAlive * 1000, self, pingreq or "\0")
  1048. end
  1049. end
  1050. local result, reason = coroutine.yield()
  1051. if not result and reason == 'server close' then
  1052. return false
  1053. end
  1054. return result, reason
  1055. end
  1056. function mt:getAsyncSend()
  1057. if self.error then
  1058. return 0
  1059. end
  1060. return #(self.output)
  1061. end
  1062. --- server缓存待发送的数据
  1063. -- @string data 数据
  1064. -- @number[opt=nil] timeout 可选参数,发送超时时间,单位秒;为nil时表示不支持timeout
  1065. -- @return result true - 成功,false - 失败
  1066. -- @usage
  1067. -- socketClient = socketCh395.tcp()
  1068. -- socketClient:connect("www.baidu.com","80")
  1069. -- socketClient:serverSend("12345678")
  1070. function mt:serverSend(data, timeout)
  1071. if self.error then
  1072. log.warn('socket.client:asyncSend', 'error', self.error)
  1073. return false
  1074. end
  1075. self.timeout = timeout
  1076. table.insert(self.output, data or "")
  1077. -- log.info("socket.asyncSend",self.wait)
  1078. if self.wait == "SOCKET_WAIT" then
  1079. coroutine.resume(self.co, true)
  1080. end
  1081. return true
  1082. end
  1083. --- server接收数据
  1084. -- @return data 表示接收到的数据(如果是UDP,返回最新的一包数据;如果是TCP,返回所有收到的数据)
  1085. -- ""表示未收到数据
  1086. -- @usage
  1087. -- socketClient = socketCh395.tcp()
  1088. -- socketClient:connect("www.baidu.com","80")
  1089. -- data = socketClient:serverRecv()
  1090. function mt:serverRecv()
  1091. if #self.input == 0 then
  1092. return ""
  1093. end
  1094. if self.protocol == "UDP" then
  1095. return table.remove(self.input)
  1096. else
  1097. local s = table.concat(self.input)
  1098. self.input = {}
  1099. if self.isBlock then
  1100. table.insert(self.input, recv(self.msg.socket_index, self.msg.recv_len))
  1101. end
  1102. return s
  1103. end
  1104. end
  1105. --- 异步缓存待发送的数据
  1106. -- @string data 数据
  1107. -- @number[opt=nil] timeout 可选参数,发送超时时间,单位秒;为nil时表示不支持timeout
  1108. -- @return result true - 成功,false - 失败
  1109. -- @usage
  1110. -- socketClient = socketCh395.tcp()
  1111. -- socketClient:connect("www.baidu.com","80")
  1112. -- socketClient:asyncSend("12345678")
  1113. function mt:asyncSend(data, timeout)
  1114. if self.error then
  1115. log.warn('socket.client:asyncSend', 'error', self.error)
  1116. return false
  1117. end
  1118. self.timeout = timeout
  1119. table.insert(self.output, data or "")
  1120. -- log.info("socket.asyncSend",self.wait)
  1121. if self.wait == "SOCKET_WAIT" then
  1122. coroutine.resume(self.co, true)
  1123. end
  1124. return true
  1125. end
  1126. --- 异步接收数据
  1127. -- @return data 表示接收到的数据(如果是UDP,返回最新的一包数据;如果是TCP,返回所有收到的数据)
  1128. -- ""表示未收到数据
  1129. -- @usage
  1130. -- socketClient = socketCh395.tcp()
  1131. -- socketClient:connect("www.baidu.com","80")
  1132. -- data = socketClient:asyncRecv()
  1133. function mt:asyncRecv()
  1134. if #self.input == 0 then
  1135. return ""
  1136. end
  1137. if self.protocol == "UDP" then
  1138. return table.remove(self.input)
  1139. else
  1140. local s = table.concat(self.input)
  1141. self.input = {}
  1142. if self.isBlock then
  1143. table.insert(self.input, socketcore.sock_recv(self.msg.socket_index, self.msg.recv_len))
  1144. end
  1145. return s
  1146. end
  1147. end
  1148. --- 同步发送数据
  1149. -- @string data 数据
  1150. -- 此处传入的数据长度和剩余可用内存有关,只要内存够用,可以随便传入数据
  1151. -- 虽然说此处的数据长度没有特别限制,但是调用core中的socket发送接口时,每次最多发送11200字节的数据
  1152. -- 例如此处传入的data长度是112000字节,则在这个send接口中,会循环10次,每次发送11200字节的数据
  1153. -- @number[opt=120] timeout 可选参数,发送超时时间,单位秒
  1154. -- @return result true - 成功,false - 失败
  1155. -- @usage
  1156. -- socketClient = socketCh395.tcp()
  1157. -- socketClient:connect("www.baidu.com","80")
  1158. -- socketClient:send("12345678")
  1159. function mt:send(data, timeout)
  1160. assert(self.co == coroutine.running(), "socket:send: coroutine mismatch")
  1161. if self.error then
  1162. log.warn('socket.client:send', 'error', self.error)
  1163. return false
  1164. end
  1165. log.debug("socket.send", "total " .. string.len(data or "") .. " bytes", "first 30 bytes", (data or ""):sub(1, 30))
  1166. local sendSize = self.protocol == "UDP" and 1472 or SENDSIZE
  1167. for i = 1, string.len(data or ""), sendSize do
  1168. -- 按最大MTU单元对data分包
  1169. self.wait = "SOCKET_SEND"
  1170. sockectCh395Send(self.id, data:sub(i, i + sendSize - 1))
  1171. self.timerId = sys.timerStart(coroutine.resume, (timeout or 120) * 1000, self.co, false, "TIMEOUT")
  1172. local result, reason = coroutine.yield()
  1173. if not result and reason == 'server close' then
  1174. return false
  1175. end
  1176. if self.timerId and reason ~= "TIMEOUT" then
  1177. sys.timerStop(self.timerId)
  1178. end
  1179. if not result then
  1180. log.info("socket:send" .. self.id, "send fail", reason)
  1181. sys.publish("LIB_SOCKET_SEND_FAIL_IND", self.ssl, self.protocol, self.address, self.port)
  1182. return false
  1183. end
  1184. end
  1185. return true
  1186. end
  1187. --- 同步接收数据
  1188. -- @number[opt=0] timeout 可选参数,接收超时时间,单位毫秒
  1189. -- @string[opt=nil] msg 可选参数,控制socket所在的线程退出recv阻塞状态
  1190. -- @bool[opt=nil] msgNoResume 可选参数,控制socket所在的线程退出recv阻塞状态
  1191. -- false或者nil表示“在recv阻塞状态,收到msg消息,可以退出阻塞状态”,true表示不退出
  1192. -- 此参数仅lib内部使用,应用脚本不要使用此参数
  1193. -- @return result 数据接收结果
  1194. -- true表示成功(接收到了数据)
  1195. -- false表示失败(没有接收到数据)
  1196. -- @return data
  1197. -- 如果result为true,data表示接收到的数据(如果是UDP,返回最新的一包数据;如果是TCP,返回所有收到的数据)
  1198. -- 如果result为false,超时失败,data为"timeout"
  1199. -- 如果result为false,msg控制退出,data为msg的字符串
  1200. -- 如果result为false,socket连接被动断开控制退出,data为"CLOSED"
  1201. -- 如果result为false,PDP断开连接控制退出,data为"IP_ERROR_IND"
  1202. -- @return param 如果是msg控制退出,param的值是msg的参数
  1203. -- @usage
  1204. -- socketClient = socketCh395.tcp()
  1205. -- socketClient:connect("www.baidu.com","80")
  1206. -- result,data = socketClient:recv(60000,"APP_SOCKET_SEND_DATA")
  1207. function mt:recv(timeout, msg, msgNoResume)
  1208. assert(self.co == coroutine.running(), "socket:recv: coroutine mismatch")
  1209. if self.error then
  1210. log.warn('socket.client:recv', 'error', self.error)
  1211. return false
  1212. end
  1213. self.msgNoResume = msgNoResume
  1214. if msg and not self.iSubscribe then
  1215. self.iSubscribe = msg
  1216. self.subMessage = function(data)
  1217. -- if data then table.insert(self.output, data) end
  1218. if self.wait == "+RECEIVE" and not self.msgNoResume then
  1219. if data then
  1220. table.insert(self.output, data)
  1221. end
  1222. coroutine.resume(self.co, 0xAA)
  1223. end
  1224. end
  1225. sys.subscribe(msg, self.subMessage)
  1226. end
  1227. if msg and #self.output > 0 then
  1228. sys.publish(msg, false)
  1229. end
  1230. if #self.input == 0 then
  1231. self.wait = "+RECEIVE"
  1232. if timeout and timeout > 0 then
  1233. local r, s = sys.wait(timeout)
  1234. if r == nil then
  1235. return false, "timeout"
  1236. elseif r == 0xAA then
  1237. local dat = table.concat(self.output)
  1238. self.output = {}
  1239. return false, msg, dat
  1240. else
  1241. return r, s
  1242. end
  1243. else
  1244. local r, s = coroutine.yield()
  1245. if not r and s == 'server close' then
  1246. return false
  1247. end
  1248. if r == 0xAA then
  1249. local dat = table.concat(self.output)
  1250. self.output = {}
  1251. return false, msg, dat
  1252. else
  1253. return r, s
  1254. end
  1255. end
  1256. end
  1257. if self.protocol == "UDP" then
  1258. local s = table.remove(self.input)
  1259. return true, s
  1260. else
  1261. log.warn("-------------------使用缓冲区---------------")
  1262. local s = table.concat(self.input)
  1263. self.input = {}
  1264. if self.isBlock then
  1265. table.insert(self.input, sockectCh395Recv(self.msg.socket_index, self.msg.recv_len))
  1266. end
  1267. return true, s
  1268. end
  1269. end
  1270. --- 主动关闭并且销毁一个socket
  1271. -- @return nil
  1272. -- @usage
  1273. -- socketClient = socketCh395.tcp()
  1274. -- socketClient:connect("www.baidu.com","80")
  1275. -- socketClient:close()
  1276. function mt:close()
  1277. assert(self.co == coroutine.running(), "socket:close: coroutine mismatch")
  1278. if self.iSubscribe then
  1279. sys.unsubscribe(self.iSubscribe, self.subMessage)
  1280. self.iSubscribe = false
  1281. end
  1282. -- log.info('socketCh395', 'close' .. self.id)
  1283. -- 此处不要再判断状态,否则在连接超时失败时,conneted状态仍然是未连接,会导致无法close
  1284. -- if self.connected then
  1285. log.info("socket:sock_close", self.id)
  1286. local result, reason
  1287. if self.id then
  1288. sockectCh395Close(self.id)
  1289. self.wait = "SOCKET_CLOSE"
  1290. while true do
  1291. result, reason = coroutine.yield()
  1292. if not result and reason == 'server close' then
  1293. return false
  1294. end
  1295. if reason == "RESPONSE" then
  1296. break
  1297. end
  1298. end
  1299. end
  1300. if self.connected then
  1301. self.connected = false
  1302. if socketsConnected > 0 then
  1303. socketsConnected = socketsConnected - 1
  1304. end
  1305. sys.publish("SOCKET_ACTIVE", socketsConnected > 0)
  1306. end
  1307. if self.input then
  1308. self.input = {}
  1309. end
  1310. if self.protocol == 'TCPSERVERCLIENT' then
  1311. sockets[self.id] = true
  1312. else
  1313. if self.id ~= nil then
  1314. sockets[self.id] = nil
  1315. end
  1316. end
  1317. end
  1318. -- socket接收自定义控制处理
  1319. -- @function[opt=nil] rcvCbFnc,socket接收到数据后,执行的回调函数,回调函数的调用形式为:
  1320. -- rcvCbFnc(readFnc,socketIndex,rcvDataLen)
  1321. -- rcvCbFnc内部,会判断是否读取数据,如果读取,执行readFnc(socketIndex,rcvDataLen),返回true;否则返回false或者nil
  1322. function mt:setRcvProc(rcvCbFnc)
  1323. assert(self.co == coroutine.running(), "socket:setRcvProc: coroutine mismatch")
  1324. self.rcvProcFnc = rcvCbFnc
  1325. end
  1326. function on_response(msg)
  1327. local t = {
  1328. [rtos.MSG_SOCK_CLOSE_CNF] = 'SOCKET_CLOSE',
  1329. -- 33
  1330. [rtos.MSG_SOCK_SEND_CNF] = 'SOCKET_SEND',
  1331. -- 32
  1332. [rtos.MSG_SOCK_CONN_CNF] = 'SOCKET_CONNECT'
  1333. -- 34
  1334. }
  1335. if not sockets[msg.socket_index] then
  1336. log.warn('response on nil socket', msg.socket_index, t[msg.id], msg.result)
  1337. return
  1338. end
  1339. if sockets[msg.socket_index] == true then
  1340. return
  1341. end
  1342. log.info(sockets[msg.socket_index].wait, t[msg.id], msg.socket_index, msg.id)
  1343. if sockets[msg.socket_index].wait ~= t[msg.id] then
  1344. log.warn('response on invalid wait', sockets[msg.socket_index].id, sockets[msg.socket_index].wait, t[msg.id],
  1345. msg.socket_index)
  1346. return
  1347. end
  1348. log.info('socket:on_response:', msg.socket_index, t[msg.id], msg.result)
  1349. if sockets[msg.socket_index].protocol == 'TCPSERVERCLIENT' then
  1350. msg.result=0
  1351. end
  1352. coroutine.resume(sockets[msg.socket_index].co, msg.result == 0, 'RESPONSE')
  1353. end
  1354. sys.subscribe('SOCK_CONN_CNF', on_response)
  1355. sys.subscribe('SOCK_CLOSE_CNF', on_response)
  1356. sys.subscribe('SOCK_SEND_CNF', on_response)
  1357. -- 被动关闭
  1358. sys.subscribe('MSG_SOCK_CLOSE_IND', function(msg)
  1359. local data = string.sub(spiSend(spi.SPI_1, string.char(0x2F, msg.socket_index, 0xff, 0xff)), 3, -1)
  1360. log.info('socketCh395', 'close socket ' .. msg.socket_index .. 'state', data:toHex())
  1361. if string.sub(data, 1, 1) ~= '\x00' then
  1362. return
  1363. end
  1364. log.info('socket.rtos.MSG_SOCK_CLOSE_IND',msg.socket_index)
  1365. if not sockets[msg.socket_index] then
  1366. return
  1367. elseif sockets[msg.socket_index] == true then
  1368. return
  1369. elseif sockets[msg.socket_index].protocol == 'TCPSERVERCLIENT' then
  1370. coroutine.resume(sockets[msg.socket_index].co, false, 'CLOSED')
  1371. sockets[msg.socket_index] = true
  1372. return
  1373. end
  1374. if not sockets[msg.socket_index] then
  1375. log.warn('close ind on nil socket', msg.socket_index, msg.id)
  1376. return
  1377. end
  1378. if sockets[msg.socket_index].connected then
  1379. sockets[msg.socket_index].connected = false
  1380. if socketsConnected > 0 then
  1381. socketsConnected = socketsConnected - 1
  1382. end
  1383. sys.publish('SOCKET_ACTIVE', socketsConnected > 0)
  1384. end
  1385. sockets[msg.socket_index].error = 'CLOSED'
  1386. --[[
  1387. if type(socketcore.sock_destroy) == "function" then
  1388. socketcore.sock_destroy(msg.socket_index)
  1389. end]]
  1390. sys.publish('LIB_SOCKET_CLOSE_IND', sockets[msg.socket_index].ssl, sockets[msg.socket_index].protocol,
  1391. sockets[msg.socket_index].address, sockets[msg.socket_index].port)
  1392. coroutine.resume(sockets[msg.socket_index].co, false, 'CLOSED')
  1393. end)
  1394. sys.subscribe('MSG_SOCK_RECV_IND', function(msg)
  1395. if type(sockets[msg.socket_index])~='table' then
  1396. log.warn('close ind on nil socket', msg.socket_index, msg.id)
  1397. return
  1398. end
  1399. log.debug('socket.recv', msg.recv_len, sockets[msg.socket_index].rcvProcFnc)
  1400. if sockets[msg.socket_index].rcvProcFnc then
  1401. sockets[msg.socket_index].rcvProcFnc(msg.recv_data)
  1402. else
  1403. if sockets[msg.socket_index].wait == '+RECEIVE' then
  1404. coroutine.resume(sockets[msg.socket_index].co, true, msg.recv_data)
  1405. else -- 数据进缓冲区,缓冲区溢出采用覆盖模式
  1406. if #sockets[msg.socket_index].input > INDEX_MAX then
  1407. log.error('socket recv', 'out of stack', 'block')
  1408. -- sockets[msg.socket_index].input = {}
  1409. sockets[msg.socket_index].isBlock = true
  1410. sockets[msg.socket_index].msg = msg
  1411. else
  1412. sockets[msg.socket_index].isBlock = false
  1413. table.insert(sockets[msg.socket_index].input, msg.recv_data)
  1414. end
  1415. sys.publish('SOCKET_RECV', msg.socket_index)
  1416. end
  1417. end
  1418. end)
  1419. -- 设置TCP层自动重传的参数
  1420. -- @number[opt=4] retryCnt 重传次数;取值范围0到12
  1421. -- @number[opt=16] retryMaxTimeout 限制每次重传允许的最大超时时间(单位秒),取值范围1到16
  1422. -- @return nil
  1423. -- @usage
  1424. -- setTcpResendPara(3,8)
  1425. -- setTcpResendPara(4,16)
  1426. function setTcpResendPara(retryCnt, retryMaxTimeout)
  1427. ril.request("AT+TCPUSERPARAM=6," .. (retryCnt or 4) .. ",7200," .. (retryMaxTimeout or 16))
  1428. end
  1429. -- 设置域名解析参数
  1430. -- 注意:0027以及之后的core版本才支持此功能
  1431. -- @number[opt=4] retryCnt 重传次数;取值范围1到8
  1432. -- @number[opt=4] retryTimeoutMulti 重传超时时间倍数,取值范围1到5
  1433. -- 第n次重传超时时间的计算方式为:第n次的重传超时基数*retryTimeoutMulti,单位为秒
  1434. -- 重传超时基数表为{1, 1, 2, 4, 4, 4, 4, 4}
  1435. -- 第1次重传超时时间为:1*retryTimeoutMulti 秒
  1436. -- 第2次重传超时时间为:1*retryTimeoutMulti 秒
  1437. -- 第3次重传超时时间为:2*retryTimeoutMulti 秒
  1438. -- ...........................................
  1439. -- 第8次重传超时时间为:8*retryTimeoutMulti 秒
  1440. -- @return nil
  1441. -- @usage
  1442. -- socket.setDnsParsePara(8,5)
  1443. function setDnsParsePara(retryCnt, retryTimeoutMulti)
  1444. ril.request("AT*DNSTMOUT=" .. (retryCnt or 4) .. "," .. (retryTimeoutMulti or 4))
  1445. end
  1446. function setIpStatis(interval)
  1447. end
  1448. --- 打印所有socket的状态
  1449. -- @return 无
  1450. -- @usage socketCh395.printStatus()
  1451. function printStatus()
  1452. for _, client in pairs(sockets) do
  1453. for k, v in pairs(client) do
  1454. log.info('socket.printStatus', 'client', client.id, k, v)
  1455. end
  1456. end
  1457. end
  1458. -- 设置数据传输后,允许进入休眠状态的延时时长
  1459. -- 3024版本以及之后的版本才支持此功能
  1460. -- 此功能设置的参数,设置成功后,掉电会自动保存
  1461. -- @number tm,数据传输后,允许进入休眠状态的延时时长,单位为秒,取值范围1到20
  1462. -- 注意:此时间越短,允许进入休眠状态越快,功耗越低;但是在某些网络环境中,此时间越短,可能会造成数据传输不稳定
  1463. -- 建议在可以接受的功耗范围内,此值设置的越大越好
  1464. -- 如果没有设置此参数,此延时时长是和基站的配置有关,一般来说是10秒左右
  1465. -- @return nil
  1466. -- @usage
  1467. -- socketCh395.setLowPower(5)
  1468. function setLowPower(tm)
  1469. ril.request("AT*RTIME=" .. tm)
  1470. end