exnetif.lua 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. --[[
  2. @module exnetif
  3. @summary exnetif 控制网络优先级(以太网->WIFI->4G)根据优先级选择上网的网卡。简化开启多网融合的操作,4G作为数据出口给WIFI,以太网设备上网,以太网作为数据出口给WIFI,Air8000上网,WIFI作为数据出口给Air8000,以太网上网。
  4. @version 1.0
  5. @date 2025.06.26
  6. @author wjq
  7. @usage
  8. 本文件的对外接口有4个:
  9. 1、exnetif.set_priority_order(networkConfigs):设置网络优先级顺序并初始化对应网络(需要在task中调用)
  10. 2、exnetif.notify_status(cb_fnc):设置网络状态变化回调函数
  11. 3、exnetif.setproxy(adapter, main_adapter,other_configs):配置网络代理实现多网融合(需要在task中调用)
  12. 4、exnetif.check_network_status(interval),检测间隔时间ms(选填),不填时只检测一次,填写后将根据间隔时间循环检测,会提高模块功耗
  13. ]]
  14. local exnetif = {}
  15. dnsproxy = require("dnsproxy")
  16. dhcpsrv = require("dhcpsrv")
  17. httpdns = require("httpdns")
  18. -- 设置pingip
  19. local wifi_ping_ip
  20. local eth_ping_ip
  21. local local_network_mode
  22. local need_ping = true
  23. local single_network_mode = false
  24. local ping_time = 10000
  25. -- 连接状态
  26. local connection_states = {
  27. DISCONNECTED = 0,
  28. CONNECTING = 1,
  29. CONNECTED = 2,
  30. OPENED = 3,
  31. SINGLE_NETWORK=4
  32. }
  33. -- 状态回调函数
  34. local states_cbfnc = function(net_type) end
  35. -- 当前优先级
  36. local current_priority = { socket.LWIP_ETH, socket.LWIP_STA, socket.LWIP_GP }
  37. -- 连接状态
  38. local available = {
  39. [socket.LWIP_STA] = connection_states.DISCONNECTED,
  40. [socket.LWIP_ETH] = connection_states.DISCONNECTED,
  41. [socket.LWIP_GP] = connection_states.DISCONNECTED,
  42. [socket.LWIP_USER1] = connection_states.DISCONNECTED
  43. }
  44. -- 当前使用的网卡
  45. local current_active = nil
  46. -- 网络类型转字符串
  47. local function type_to_string(net_type)
  48. local type_map = {
  49. [socket.LWIP_STA] = "WiFi",
  50. [socket.LWIP_ETH] = "Ethernet",
  51. [socket.LWIP_GP] = "4G",
  52. [socket.LWIP_USER1] = "8101SPIETH"
  53. }
  54. return type_map[net_type] or "Unknown"
  55. end
  56. local function socket_state_detection(adapter)
  57. if netdrv.on then
  58. log.info("netdrv", "订阅socket连接状态变化事件", type_to_string(adapter))
  59. -- 订阅socket连接状态变化事件
  60. netdrv.on(adapter, netdrv.EVT_SOCKET, function(id, event, params)
  61. if event == "timeout" or event == "error" then
  62. if available[adapter] == connection_states.CONNECTED then
  63. available[adapter] = connection_states.CONNECTING
  64. end
  65. end
  66. -- log.info("netdrv", "socket event", id, event, json.encode(params or {}))
  67. -- if params then
  68. -- -- params里会有remote_ip, remote_port等信息, 可按需获取
  69. -- local remote_ip = params.remote_ip
  70. -- local remote_port = params.remote_port
  71. -- local domain_name = params.domain_name
  72. -- log.info("netdrv", "socket event", "remote_ip", remote_ip, "remote_port", remote_port, "domain_name", domain_name)
  73. -- end
  74. end)
  75. end
  76. end
  77. -- 状态更改后重新设置默认网卡
  78. local function apply_priority()
  79. local usable = false
  80. -- 查找优先级最高的可用网络
  81. for _, net_type in ipairs(current_priority) do
  82. -- log.info("网卡顺序",type_to_string(net_type),available[net_type])
  83. if available[net_type] == connection_states.CONNECTED then
  84. usable = true
  85. -- 设置优先级高的网卡
  86. if current_active ~= net_type then
  87. log.info("设置网卡", type_to_string(net_type))
  88. states_cbfnc(type_to_string(net_type), net_type) -- 默认网卡改变的回调函数
  89. socket.dft(net_type)
  90. current_active = net_type
  91. end
  92. break
  93. end
  94. end
  95. -- 从存在可用网卡到没有可用网卡,才通知回调
  96. if usable == false and current_active ~= nil then
  97. --避免重复通知
  98. current_active = nil
  99. states_cbfnc(nil, -1)
  100. end
  101. end
  102. --httpdns域名解析测试
  103. local function http_dnstest(adaptertest)
  104. local ip = httpdns.ali("baidu.com", { adapter = adaptertest, timeout = 3000 })
  105. if ip ~= nil then
  106. available[adaptertest] = connection_states.CONNECTED
  107. log.info(type_to_string(adaptertest) .. "网卡httpdns域名解析成功")
  108. else
  109. log.info(type_to_string(adaptertest) .. "网卡httpdns域名解析失败")
  110. end
  111. log.info("httpdns", "baidu.com", ip)
  112. end
  113. -- ping操作
  114. local function ping_request(adaptertest)
  115. log.info("dns_request",type_to_string(adaptertest),need_ping)
  116. if need_ping then
  117. if adaptertest == socket.LWIP_ETH or adaptertest == socket.LWIP_USER1 then
  118. if eth_ping_ip == nil then
  119. http_dnstest(adaptertest)
  120. else
  121. icmp.setup(adaptertest)
  122. icmp.ping(adaptertest, eth_ping_ip)
  123. end
  124. end
  125. if adaptertest == socket.LWIP_STA then
  126. if wifi_ping_ip == nil then
  127. http_dnstest(adaptertest)
  128. else
  129. icmp.setup(adaptertest)
  130. icmp.ping(adaptertest, wifi_ping_ip)
  131. end
  132. end
  133. if adaptertest == socket.LWIP_GP then
  134. if eth_ping_ip ~= nil then
  135. icmp.setup(adaptertest)
  136. icmp.ping(adaptertest, eth_ping_ip)
  137. elseif wifi_ping_ip ~= nil then
  138. icmp.setup(adaptertest)
  139. icmp.ping(adaptertest, wifi_ping_ip)
  140. else
  141. http_dnstest(adaptertest)
  142. end
  143. end
  144. else
  145. log.info(type_to_string(adaptertest) .. "配置了不需要ping,直接切换为CONNECTED状态")
  146. available[adaptertest] = connection_states.CONNECTED
  147. end
  148. apply_priority()
  149. end
  150. -- 网卡上线回调函数
  151. local function ip_ready_handle(ip, adapter)
  152. local _, _, gw = socket.localIP(adapter)
  153. log.info("ip_ready_handle", ip, type_to_string(adapter), "state", available[adapter], "gw", gw)
  154. if local_network_mode then
  155. if adapter == socket.LWIP_ETH or adapter == socket.LWIP_USER1 then
  156. eth_ping_ip = gw
  157. elseif adapter == socket.LWIP_STA then
  158. wifi_ping_ip = gw
  159. end
  160. end
  161. log.info("eth_ping_ip", eth_ping_ip, "wifi_ping_ip", wifi_ping_ip)
  162. -- 需要ping操作,ping通后认为网络可用
  163. if available[adapter] == connection_states.OPENED then
  164. available[adapter] = connection_states.CONNECTING
  165. end
  166. -- ping_request(adapter)
  167. end
  168. -- 网卡下线回调函数
  169. local function ip_lose_handle(adapter)
  170. log.info("ip_lose_handle", type_to_string(adapter))
  171. if available[adapter] == connection_states.CONNECTING or available[adapter] == connection_states.CONNECTED then
  172. available[adapter] = connection_states.OPENED
  173. end
  174. if current_active == adapter then
  175. log.info(type_to_string(adapter) .. " 失效,切换到其他网络")
  176. apply_priority()
  177. end
  178. end
  179. local interval_time = nil
  180. --[[
  181. 对正常状态的网卡进行ping测试
  182. @api exnetif.check_network_status(interval),
  183. @int 检测间隔时间ms(选填),不填时只检测一次,填写后将根据间隔时间循环检测,会提高模块功耗
  184. ]]
  185. function exnetif.check_network_status(interval)
  186. if interval ~= nil then
  187. interval_time = interval
  188. end
  189. for _, net_type in ipairs(current_priority) do
  190. if available[net_type] == connection_states.CONNECTED then
  191. available[net_type] = connection_states.CONNECTING
  192. end
  193. end
  194. end
  195. --打开以太网Wan功能
  196. local function setup_eth(config)
  197. if config.local_network_mode then
  198. local_network_mode = true
  199. end
  200. if config.need_ping~=nil then
  201. need_ping = config.need_ping
  202. end
  203. eth_ping_ip = config.ping_ip
  204. if type(config.ping_time) == "number" then
  205. ping_time = config.ping_time
  206. end
  207. log.info("初始化以太网")
  208. if not single_network_mode then
  209. available[socket.LWIP_ETH] = connection_states.OPENED
  210. else
  211. available[socket.LWIP_ETH] = connection_states.SINGLE_NETWORK
  212. end
  213. -- 打开CH390供电
  214. if config.pwrpin then
  215. gpio.setup(config.pwrpin, 1, gpio.PULLUP)
  216. end
  217. -- sys.wait(100) -- 等待以太网模块上电稳定
  218. if config.tp == nil then
  219. log.info("8101以太网")
  220. if netdrv.setup(socket.LWIP_ETH) == false then
  221. log.error("以太网初始化失败")
  222. if config.pwrpin then
  223. gpio.close(config.pwrpin)
  224. end
  225. return false
  226. end
  227. else
  228. log.info("config.opts.spi",config.opts.spi,",config.type",config.tp)
  229. -- 配置SPI和初始化网络驱动
  230. local result = spi.setup(config.opts.spi, -- spi id
  231. nil, 0, -- CPHA
  232. 0, -- CPOL
  233. 8, -- 数据宽度
  234. 25600000 -- ,--波特率
  235. )
  236. log.info("main", "open spi", result)
  237. if result ~= 0 then -- 返回值为0,表示打开成功
  238. log.info("main", "spi open error", result)
  239. if config.pwrpin then
  240. gpio.close(config.pwrpin)
  241. end
  242. return false
  243. end
  244. -- 初始化指定netdrv设备,
  245. -- socket.LWIP_ETH 网络适配器编号
  246. -- netdrv.CH390外挂CH390
  247. -- SPI ID 1, 片选 GPIO12
  248. if netdrv.setup(socket.LWIP_ETH, config.tp, config.opts) == false then
  249. log.error("以太网初始化失败")
  250. if config.pwrpin then
  251. gpio.close(config.pwrpin)
  252. end
  253. return false
  254. end
  255. end
  256. if config.static_ip then
  257. sys.wait(1000) -- 等待以太网模块初始化完成,去掉会导致以太网初始化失败
  258. log.info("netdrv", "自定义以太网IP地址", config.static_ip.ipv4)
  259. log.info("静态ip",netdrv.ipv4(socket.LWIP_ETH, config.static_ip.ipv4,config.static_ip.mark,config.static_ip.gw))
  260. else
  261. netdrv.dhcp(socket.LWIP_ETH, true)
  262. end
  263. log.info("以太网初始化完成")
  264. socket_state_detection(socket.LWIP_ETH)
  265. return true
  266. end
  267. --打开8101spi以太网Wan功能
  268. local function setup_eth_user1(config)
  269. if config.local_network_mode then
  270. local_network_mode = true
  271. end
  272. if config.need_ping~=nil then
  273. need_ping = config.need_ping
  274. end
  275. eth_ping_ip = config.ping_ip
  276. if type(config.ping_time) == "number" then
  277. ping_time = config.ping_time
  278. end
  279. log.info("初始化以太网")
  280. if not single_network_mode then
  281. available[socket.LWIP_USER1] = connection_states.OPENED
  282. else
  283. available[socket.LWIP_USER1] = connection_states.SINGLE_NETWORK
  284. end
  285. -- 打开CH390供电
  286. if config.pwrpin then
  287. gpio.setup(config.pwrpin, 1, gpio.PULLUP)
  288. end
  289. -- sys.wait(100)-- 等待以太网模块上电稳定
  290. log.info("config.opts.spi", config.opts.spi, ",config.type", config.tp)
  291. -- 配置SPI和初始化网络驱动
  292. local result = spi.setup(config.opts.spi, -- spi id
  293. nil, 0, -- CPHA
  294. 0, -- CPOL
  295. 8, -- 数据宽度
  296. 25600000 -- ,--波特率
  297. )
  298. log.info("main", "open spi", result)
  299. if result ~= 0 then -- 返回值为0,表示打开成功
  300. log.info("main", "spi open error", result)
  301. if config.pwrpin then
  302. gpio.close(config.pwrpin)
  303. end
  304. return false
  305. end
  306. -- 初始化指定netdrv设备,
  307. -- socket.LWIP_ETH 网络适配器编号
  308. -- netdrv.CH390外挂CH390
  309. -- SPI ID 1, 片选 GPIO12
  310. if netdrv.setup(socket.LWIP_USER1, config.tp, config.opts) == false then
  311. log.error("以太网初始化失败")
  312. if config.pwrpin then
  313. gpio.close(config.pwrpin)
  314. end
  315. return false
  316. end
  317. if config.static_ip then
  318. sys.wait(1000) -- 等待以太网模块初始化完成,去掉会导致以太网初始化失败
  319. log.info("netdrv", "自定义以太网IP地址", config.static_ip.ipv4)
  320. log.info("静态ip",netdrv.ipv4(socket.LWIP_USER1, config.static_ip.ipv4, config.static_ip.mark, config.static_ip.gw))
  321. else
  322. netdrv.dhcp(socket.LWIP_USER1, true)
  323. end
  324. log.info("以太网初始化完成")
  325. socket_state_detection(socket.LWIP_USER1)
  326. return true
  327. end
  328. --连接wifi(STA模式)
  329. local function set_wifi_info(config)
  330. if config.local_network_mode then
  331. local_network_mode = true
  332. end
  333. if config.need_ping~=nil then
  334. need_ping = config.need_ping
  335. end
  336. wifi_ping_ip = config.ping_ip
  337. if type(config.ping_time) == "number" then
  338. ping_time = config.ping_time
  339. end
  340. log.info("WiFi名称:", config.ssid)
  341. log.info("密码 :", config.password)
  342. log.info("ping_ip :", config.ping_ip)
  343. wlan.init()
  344. if not single_network_mode then
  345. available[socket.LWIP_STA] = connection_states.OPENED
  346. else
  347. available[socket.LWIP_STA] = connection_states.SINGLE_NETWORK
  348. end
  349. -- 尝试连接Wi-Fi,并处理可能出现的错误
  350. local success = wlan.connect(config.ssid, config.password)
  351. if not success then
  352. log.error("WiFi连接失败")
  353. return false
  354. end
  355. log.info("WiFi STA初始化完成")
  356. socket_state_detection(socket.LWIP_STA)
  357. return true
  358. end
  359. --[[
  360. 设置网络优先级,相应网卡获取到ip且网络正常视为网卡可用,丢失ip视为网卡不可用.(需要在task中调用)
  361. @api exnetif.set_priority_order(new_priority)
  362. @table 网络优先级列表,优先级从高到低对应table中的第一个参数到最后一个参数
  363. @return boolean 成功返回true,失败返回false
  364. @usage
  365. 多网优先级模式:
  366. exnetif.set_priority_order({
  367. { -- 最高优先级网络
  368. WIFI = { -- WiFi配置
  369. ssid = "your_ssid", -- WiFi名称(string)
  370. password = "your_pwd", -- WiFi密码(string)
  371. need_ping = true, -- 是否需要通过ping来测试网络的连通性
  372. -- 在没有ping测试环境的项目中,需要将这个参数设置为false,表示不需要ping测试网络连通,
  373. -- 仅根据IP READY消息(即获取到了ip地址)来判断网络环境准备就绪,是否网络连通性则无法保证
  374. -- 如果没有设置此参数,默认为true
  375. -- 在有ping测试环境的项目中,建议不要将这个参数设置为true
  376. local_network_mode = true,-- 局域网模式(选填参数),设置为true时,exnetif会自动将ping_ip设置为网卡的网关ip。
  377. -- 用户不需要传入ping_ip参数,即使传入了,也无效。
  378. -- 这个模式的使用场景,仅适用于局域网环境;可以访问外网时,不要使用
  379. ping_ip = "112.125.89.8", -- 连通性检测IP(选填参数),默认使用httpdns获取baidu.com的ip作为判断条件,
  380. -- 注:如果填写ip,则ping通作为判断网络是否可用的条件,
  381. -- 所以需要根据网络环境填写内网或者外网ip,
  382. -- 填写外网ip的话要保证外网ip始终可用,
  383. -- 填写局域网ip的话要确保相应ip固定且能够被ping通
  384. ping_time = 10000 -- 填写ping_ip且未ping通时的检测间隔(ms, 可选,默认为10秒)
  385. -- 定时ping将会影响模块功耗,使用低功耗模式的话可以适当延迟间隔时间
  386. }
  387. },
  388. { -- 次优先级网络
  389. ETHERNET = { -- 以太网配置
  390. pwrpin = 140, -- 供电使能引脚(number)
  391. need_ping = true, -- 是否需要通过ping来测试网络的连通性
  392. -- 在没有ping测试环境的项目中,需要将这个参数设置为false,表示不需要ping测试网络连通,
  393. -- 仅根据IP READY消息(即获取到了ip地址)来判断网络环境准备就绪,是否网络连通性则无法保证
  394. -- 如果没有设置此参数,默认为true
  395. -- 在有ping测试环境的项目中,建议不要将这个参数设置为true
  396. local_network_mode = true, -- 局域网模式(选填参数),设置为true时,exnetif会自动将ping_ip设置为网卡的网关ip。
  397. -- 用户不需要传入ping_ip参数,即使传入了,也无效。
  398. -- 这个模式的使用场景,仅适用于局域网环境;可以访问外网时,不要使用
  399. ping_ip = "112.125.89.8", -- 连通性检测IP(选填参数),默认使用httpdns获取baidu.com的ip作为判断条件,
  400. -- 注:如果填写ip,则ping通作为判断网络是否可用的条件,
  401. -- 所以需要根据网络环境填写内网或者外网ip,
  402. -- 填写外网ip的话要保证外网ip始终可用,
  403. -- 填写局域网ip的话要确保相应ip固定且能够被ping通
  404. ping_time = 10000, -- 填写ping_ip且未ping通时的检测间隔(ms, 可选,默认为10秒)
  405. -- 定时ping将会影响模块功耗,使用低功耗模式的话可以适当延迟间隔时间
  406. tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
  407. opts = { spi = 1, cs = 12 }, -- 外挂方式,需要额外的参数(选填参数),仅spi方式外挂以太网时需要填写。
  408. static_ip = { -- 静态ip配置(选填参数),不填写则使用dhcp获取ip
  409. ipv4 = "192.168.5.100", -- ip地址(string)
  410. mark = "255.255.255.0", -- 子网掩码(string)
  411. gw = "192.168.5.1" -- 网关地址(string)
  412. }
  413. }
  414. },
  415. { -- 最低优先级网络
  416. LWIP_GP = true -- 启用4G网络
  417. }
  418. })
  419. 单网络模式:
  420. -- 单网络模式下只使用WIFI网络
  421. exnetif.set_priority_order({
  422. { -- 单网络,打开wifi
  423. WIFI = { -- WiFi配置
  424. ssid = "test", -- WiFi名称(string)
  425. password = "HZ88888888", -- WiFi密码(string)
  426. }
  427. }
  428. })
  429. -- Air8000系列和780EXX系列单网络模式下只使用SPI以太网网络
  430. exnetif.set_priority_order({
  431. {
  432. ETHERNET = { -- 以太网配置
  433. pwrpin = 140, -- 供电使能引脚(number)
  434. tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
  435. opts = {spi = 1, cs = 12}, -- 外挂方式,需要额外的参数(选填参数),仅spi方式外挂以太网时需要填写。
  436. }
  437. }
  438. })
  439. -- Air8101单网络模式下只使用SPI以太网网络
  440. exnetif.set_priority_order({
  441. {
  442. ETHUSER1 = { -- 以太网配置
  443. pwrpin = 13, -- 供电使能引脚(number)
  444. tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
  445. opts = {spi = 0, cs = 15}, -- 外挂方式,需要额外的参数(选填参数),仅spi方式外挂以太网时需要填写。
  446. static_ip = { -- 静态ip配置(选填参数),不填写则使用dhcp获取ip
  447. ipv4 = "192.168.5.100", -- ip地址(string)
  448. mark = "255.255.255.0", -- 子网掩码(string)
  449. gw = "192.168.5.1" -- 网关地址(string)
  450. }
  451. }
  452. }
  453. })
  454. -- 单网络模式下只使用RMII以太网网络
  455. exnetif.set_priority_order({
  456. {
  457. ETHERNET = { -- 以太网配置
  458. pwrpin = 13, -- 供电使能引脚(number)
  459. }
  460. }
  461. })
  462. -- 4G单网模式下,不需要require "exnetif",减少不必要的功能模块加载
  463. ]]
  464. function exnetif.set_priority_order(networkConfigs)
  465. -- 判断表中数据个数
  466. if #networkConfigs < 1 then
  467. log.error("网络配置为空")
  468. return false
  469. end
  470. if #networkConfigs == 1 then
  471. single_network_mode = true
  472. end
  473. if not single_network_mode then
  474. -- CONNECTING的网卡需要定时ping
  475. sys.taskInit(function()
  476. while true do
  477. for _, net_type in ipairs(current_priority) do
  478. -- log.info("网卡顺序",type_to_string(net_type),available[net_type])
  479. if available[net_type] == connection_states.CONNECTING then
  480. log.info(type_to_string(net_type) .. "网卡开始PING")
  481. ping_request(net_type)
  482. sys.wait(ping_time)
  483. end
  484. end
  485. sys.wait(1000) -- 避免死循环
  486. end
  487. end)
  488. -- 循环ping检测任务,默认不启用
  489. sys.taskInit(function()
  490. while true do
  491. if interval_time ~= nil then
  492. sys.wait(interval_time)
  493. exnetif.check_network_status()
  494. end
  495. sys.wait(1000) -- 避免死循环
  496. end
  497. end)
  498. sys.subscribe("PING_RESULT", function(id, time, dst)
  499. log.info("ping", id, time, dst)
  500. log.info(type_to_string(id) .. "网卡PING测试成功")
  501. available[id] = connection_states.CONNECTED
  502. apply_priority()
  503. end)
  504. -- 订阅网络状态变化的消息
  505. sys.subscribe("IP_READY", ip_ready_handle)
  506. sys.subscribe("IP_LOSE", ip_lose_handle)
  507. end
  508. local new_priority = {}
  509. for _, config in ipairs(networkConfigs) do
  510. if type(config.WIFI) == "table" then
  511. -- 开启wifi
  512. local res = set_wifi_info(config.WIFI)
  513. if res == false then
  514. log.error("wifi连接失败")
  515. return false
  516. end
  517. table.insert(new_priority, socket.LWIP_STA)
  518. end
  519. if type(config.ETHUSER1) == "table" then
  520. -- 开启以太网
  521. local res = setup_eth_user1(config.ETHUSER1)
  522. if res == false then
  523. log.error("以太网打开失败")
  524. return false
  525. end
  526. table.insert(new_priority, socket.LWIP_USER1)
  527. end
  528. if type(config.ETHERNET) == "table" then
  529. -- 开启以太网
  530. local res = setup_eth(config.ETHERNET)
  531. if res == false then
  532. log.error("以太网打开失败")
  533. return false
  534. end
  535. table.insert(new_priority, socket.LWIP_ETH)
  536. end
  537. if config.LWIP_GP then
  538. -- 开启4G
  539. table.insert(new_priority, socket.LWIP_GP)
  540. available[socket.LWIP_GP] = connection_states.CONNECTING
  541. end
  542. end
  543. -- 设置新优先级
  544. current_priority = new_priority
  545. -- 此处按照用户期望的配置,先设置优先级最高的默认网卡
  546. -- 防止出现以下问题:
  547. -- 例如Air8000内核固件运行起来之后,默认网卡是socket.LWIP_GP,如果用户调用exnetif.set_priority_order接口配置最高优先级网卡为socket.LWIP_ETH
  548. -- 在socket.LWIP_ETH网卡准备就绪之前,socket.LWIP_GP可能已经准备就绪,此时默认网卡仍然是socket.LWIP_GP;
  549. -- 而网络应用层(例如socket,mqtt等)有关的demo,我们编写时,不关心具体网卡,直接使用默认网卡(这样符合正常逻辑);
  550. -- 就可能会出现“网络应用在这段时间内直接使用socket.LWIP_GP,而不是用户期望的网卡socket.LWIP_ETH来上网”的问题;
  551. socket.dft(new_priority[1])
  552. apply_priority()
  553. return true
  554. end
  555. --[[
  556. 设置网络状态变化回调函数。触发条件:网卡切换或者所有网卡都断网。回调函数的输入参数: 1. 当有可用网络的时候,返回当前使用网卡、网卡id;2. 当没有可用网络的时候,返回 nil、-1 。
  557. @api exnetif.notify_status(cb_fnc)
  558. @function 回调函数
  559. @usage
  560. exnetif.notify_status(function(net_type,adapter)
  561. log.info("可以使用优先级更高的网络:", net_type,adapter)
  562. end)
  563. ]]
  564. function exnetif.notify_status(cb_fnc)
  565. log.info("notify_status", type(cb_fnc))
  566. if type(cb_fnc) ~= "function" then
  567. log.error("notify_status设置错误,请传入一个函数")
  568. return
  569. end
  570. states_cbfnc = cb_fnc
  571. end
  572. --[[
  573. 设置多网融合模式,例如4G作为数据出口给WIFI或以太网设备上网(需要在task中调用)
  574. @api exnetif.setproxy(adapter, main_adapter,other_configs)
  575. @adapter 需要使用网络的网卡,例如socket.LWIP_ETH
  576. @adapter 提供网络的网卡,例如socket.LWIP_GP
  577. @table 其他设置参数(选填参数),
  578. @usage
  579. 典型应用:
  580. -- 以太网WAN提供网络其他设备连接以太网LAN口上网
  581. exnetif.setproxy(socket.LWIP_ETH, socket.LWIP_USER1, {
  582. ethpower_en = 20,-- 以太网模块的pwrpin引脚(gpio编号)
  583. tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
  584. opts = {spi = 0, cs = 8}, -- 外挂方式,需要额外的参数(选填参数),仅spi方式外挂以太网时需要填写。
  585. main_adapter = {
  586. ethpower_en = 21,-- 以太网模块的pwrpin引脚(gpio编号)
  587. tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
  588. opts = {spi = 1, cs = 12}
  589. }
  590. }) then
  591. -- wifi_sta提供网络开启wifi_ap热点供设备上网
  592. exnetif.setproxy(socket.LWIP_AP, socket.LWIP_STA, {
  593. ssid = "test2", -- AP热点名称(string),网卡包含wifi时填写
  594. password = "HZ88888888", -- AP热点密码(string),网卡包含wifi时填写
  595. ap_opts = { -- AP模式下配置项(选填参数)
  596. hidden = false, -- 是否隐藏SSID, 默认false,不隐藏
  597. max_conn = 4 }, -- 最大客户端数量, 默认4
  598. channel = 6, -- AP建立的通道, 默认6
  599. main_adapter = {
  600. ssid = "test", -- 提供网络的网卡开启参数
  601. password = "HZ88888888"
  602. }
  603. })
  604. -- 4G提供网络开启wifi_ap热点供设备上网,其他设备连接以太网LAN口上网
  605. exnetif.setproxy(socket.LWIP_AP, socket.LWIP_GP, {
  606. ssid = "Hotspot", -- WiFi名称(string),网卡包含wifi时填写
  607. password = "password123", -- WiFi密码(string),网卡包含wifi时填写
  608. adapter_addr = "192.168.5.1", -- adapter网卡的ip地址(选填),需要自定义ip和网关ip时填写
  609. adapter_gw= { 192, 168, 5, 1 }, -- adapter网卡的网关地址(选填),需要自定义ip和网关ip时填写
  610. ap_opts={ -- AP模式下配置项(选填参数)
  611. hidden = false, -- 是否隐藏SSID, 默认false,不隐藏
  612. max_conn = 4 }, -- 最大客户端数量, 默认4
  613. channel=6 -- AP建立的通道, 默认6
  614. })
  615. exnetif.setproxy(socket.LWIP_ETH, socket.LWIP_GP, {
  616. tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
  617. opts = { spi = 1, cs = 12}, -- 外挂方式,需要额外的参数(选填参数),仅spi方式外挂以太网时需要填写。
  618. ethpower_en = 140, -- 以太网模块的pwrpin引脚(gpio编号)
  619. adapter_addr = "192.168.5.1", -- adapter网卡的ip地址(选填),需要自定义ip和网关ip时填写
  620. adapter_gw= { 192, 168, 5, 1 }, -- adapter网卡的网关地址(选填),需要自定义ip和网关ip时填写
  621. })
  622. -- 以太网提供网络供WiFi设备上网
  623. exnetif.setproxy(socket.LWIP_AP, socket.LWIP_ETH, {
  624. ssid = "Hotspot", -- WiFi名称(string),网卡包含wifi时填写
  625. password = "password123", -- WiFi密码(string),网卡包含wifi时填写
  626. main_adapter={
  627. tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
  628. opts = { spi = 1, cs = 12}, -- 外挂方式,需要额外的参数(选填参数),仅spi方式外挂以太网时需要填写。
  629. ethpower_en = 140, -- 以太网模块的pwrpin引脚(gpio编号)
  630. }
  631. })
  632. -- WIFI提供网络供以太网设备上网
  633. exnetif.setproxy(socket.LWIP_ETH, socket.LWIP_STA, {
  634. tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
  635. opts = { spi = 1, cs = 12}, -- 外挂方式,需要额外的参数(选填参数),仅spi方式外挂以太网时需要填写。
  636. ethpower_en = 140, -- 以太网模块的pwrpin引脚(gpio编号)
  637. main_adapter = {
  638. ssid = "test", -- 提供网络的网卡开启参数
  639. password = "HZ88888888"
  640. }
  641. })
  642. ]]
  643. function exnetif.setproxy(adapter, main_adapter, other_configs)
  644. if main_adapter == socket.LWIP_ETH and available[socket.LWIP_ETH] == connection_states.DISCONNECTED then
  645. -- 打开WAN功能
  646. log.info("ch390", "打开LDO供电", other_configs.main_adapter.ethpower_en)
  647. available[socket.LWIP_ETH] = connection_states.OPENED
  648. -- 打开CH390供电
  649. if other_configs.main_adapter.ethpower_en then
  650. gpio.setup(other_configs.main_adapter.ethpower_en, 1, gpio.PULLUP)
  651. end
  652. -- sys.wait(100) -- 等待以太网模块上电稳定
  653. if other_configs.main_adapter.tp == nil then
  654. log.info("8101以太网")
  655. if netdrv.setup(socket.LWIP_ETH) == false then
  656. log.error("以太网初始化失败")
  657. if other_configs.main_adapter.ethpower_en then
  658. gpio.close(other_configs.main_adapter.ethpower_en)
  659. end
  660. return false
  661. end
  662. else
  663. log.info("config.opts.spi", other_configs.main_adapter.opts.spi, ",config.type", other_configs.main_adapter.tp)
  664. -- 配置SPI和初始化网络驱动
  665. local result = spi.setup(other_configs.main_adapter.opts.spi, -- spi id
  666. nil, 0, -- CPHA
  667. 0, -- CPOL
  668. 8, -- 数据宽度
  669. 25600000 -- ,--波特率
  670. )
  671. log.info("main", "open spi", result)
  672. if result ~= 0 then -- 返回值为0,表示打开成功
  673. log.info("main", "spi open error", result)
  674. if other_configs.main_adapter.ethpower_en then
  675. gpio.close(other_configs.main_adapter.ethpower_en)
  676. end
  677. return false
  678. end
  679. -- 初始化指定netdrv设备,
  680. local success = netdrv.setup(socket.LWIP_ETH, other_configs.main_adapter.tp, other_configs.main_adapter.opts)
  681. if not success then
  682. log.error("以太网初始化失败")
  683. if other_configs.main_adapter.ethpower_en then
  684. gpio.close(other_configs.main_adapter.ethpower_en)
  685. end
  686. return false
  687. end
  688. end
  689. netdrv.dhcp(socket.LWIP_ETH, true)
  690. local count = 1
  691. while 1 do
  692. local ip = netdrv.ipv4(socket.LWIP_ETH)
  693. if ip and ip ~= "0.0.0.0" then break end
  694. if count > 600 then
  695. log.error("以太网连接超时,请检查配置")
  696. if other_configs.main_adapter.ethpower_en then
  697. gpio.close(other_configs.main_adapter.ethpower_en)
  698. end
  699. return false
  700. end
  701. sys.wait(100)
  702. count = count + 1
  703. end
  704. elseif main_adapter == socket.LWIP_USER1 and available[socket.LWIP_USER1] == connection_states.DISCONNECTED then
  705. log.info("初始化以太网")
  706. -- 打开CH390供电
  707. if other_configs.main_adapter.ethpower_en then
  708. gpio.setup(other_configs.main_adapter.ethpower_en, 1, gpio.PULLUP)
  709. end
  710. -- sys.wait(100) -- 等待以太网模块上电稳定
  711. log.info("config.opts.spi", other_configs.main_adapter.opts.spi, ",config.type", other_configs.main_adapter.tp)
  712. available[socket.LWIP_USER1] = connection_states.OPENED
  713. -- 配置SPI和初始化网络驱动
  714. local result = spi.setup(other_configs.main_adapter.opts.spi, -- spi id
  715. nil, 0, -- CPHA
  716. 0, -- CPOL
  717. 8, -- 数据宽度
  718. 25600000 -- ,--波特率
  719. )
  720. log.info("main", "open spi", result)
  721. if result ~= 0 then -- 返回值为0,表示打开成功
  722. log.info("main", "spi open error", result)
  723. if other_configs.main_adapter.ethpower_en then
  724. gpio.close(other_configs.main_adapter.ethpower_en)
  725. end
  726. return false
  727. end
  728. -- 初始化指定netdrv设备,
  729. -- socket.LWIP_ETH 网络适配器编号
  730. -- netdrv.CH390外挂CH390
  731. -- SPI ID 1, 片选 GPIO12
  732. if netdrv.setup(socket.LWIP_USER1, other_configs.main_adapter.tp, other_configs.main_adapter.opts) == false then
  733. log.error("以太网初始化失败")
  734. if other_configs.main_adapter.ethpower_en then
  735. gpio.close(other_configs.main_adapter.ethpower_en)
  736. end
  737. return false
  738. end
  739. netdrv.dhcp(socket.LWIP_USER1, true)
  740. log.info("以太网初始化完成")
  741. local count = 1
  742. while 1 do
  743. local ip = netdrv.ipv4(socket.LWIP_USER1)
  744. if ip and ip ~= "0.0.0.0" then break end
  745. if count > 600 then
  746. log.error("以太网连接超时,请检查配置")
  747. if other_configs.main_adapter.ethpower_en then
  748. gpio.close(other_configs.main_adapter.ethpower_en)
  749. end
  750. return false
  751. end
  752. sys.wait(100)
  753. count = count + 1
  754. end
  755. elseif main_adapter == socket.LWIP_STA and available[socket.LWIP_STA] == connection_states.DISCONNECTED then
  756. -- 打开STA功能,设置混合模式
  757. wlan.init()
  758. wlan.setMode(wlan.APSTA)
  759. available[socket.LWIP_STA] = connection_states.OPENED
  760. -- 尝试连接Wi-Fi,并处理可能出现的错误
  761. wlan.connect(other_configs.main_adapter.ssid, other_configs.main_adapter.password)
  762. -- 等待获取IP地址
  763. local count = 1
  764. while 1 do
  765. local ip = netdrv.ipv4(socket.LWIP_STA)
  766. if ip and ip ~= "0.0.0.0" then
  767. log.info("WiFi STA已连接,IP:", ip)
  768. break
  769. end
  770. if count > 600 then
  771. log.error("WiFi STA连接超时,请检查配置")
  772. return false
  773. end
  774. sys.wait(100)
  775. count = count + 1
  776. end
  777. log.info("WiFi STA初始化完成")
  778. end
  779. if adapter == socket.LWIP_ETH then
  780. log.info("ch390", "打开LDO供电", other_configs.ethpower_en)
  781. if other_configs.ethpower_en then
  782. gpio.setup(other_configs.ethpower_en, 1, gpio.PULLUP)
  783. end
  784. -- 打开LAN功能
  785. -- 配置 SPI 参数,Air8000 使用 SPI 接口与以太网模块进行通信。
  786. if other_configs.tp then
  787. log.info("netdrv spi挂载以太网", "初始化LAN功能")
  788. local result = spi.setup(
  789. other_configs.opts.spi, -- spi id
  790. nil, 0, -- CPHA
  791. 0, -- CPOL
  792. 8, -- 数据宽度
  793. 25600000 -- ,--波特率
  794. )
  795. log.info("main", "open spi", result)
  796. if result ~= 0 then -- 返回值为 0,表示打开成功
  797. log.error("main", "spi open error", result)
  798. if other_configs.ethpower_en then
  799. gpio.close(other_configs.ethpower_en)
  800. end
  801. return false
  802. end
  803. end
  804. -- 初始化以太网,Air8000 指定使用 CH390 芯片。
  805. log.info("netdrv", "初始化以太网", other_configs.tp, other_configs.opts)
  806. if netdrv.setup(socket.LWIP_ETH, other_configs.tp, other_configs.opts) == false then
  807. log.error("初始化以太网失败")
  808. if other_configs.ethpower_en then
  809. gpio.close(other_configs.ethpower_en)
  810. end
  811. return false
  812. end
  813. sys.wait(1000) -- 等待以太网模块初始化完成,去掉会导致以太网初始化失败
  814. -- 设置以太网的 IP 地址、子网掩码、网关地址
  815. log.info("netdrv", "自定义以太网IP地址", other_configs.adapter_addr, "网关地址", other_configs.adapter_gw)
  816. netdrv.ipv4(socket.LWIP_ETH, other_configs.adapter_addr or "192.168.5.1", "255.255.255.0", "0.0.0.0")
  817. -- 获取以太网网络状态,连接后返回 true,否则返回 false,如果不存在就返回 nil。
  818. local count = 1
  819. while netdrv.ready(socket.LWIP_ETH) ~= true do
  820. if count > 600 then
  821. log.error("以太网连接超时,请检查配置")
  822. if other_configs.ethpower_en then
  823. gpio.close(other_configs.ethpower_en)
  824. end
  825. return false
  826. end
  827. count = count + 1
  828. -- log.info("netdrv", "等待以太网就绪") -- 若以太网设备没有连上,可打开此处注释排查。
  829. sys.wait(100)
  830. end
  831. log.info("netdrv", "以太网就绪")
  832. -- 创建 DHCP 服务器,为连接到以太网的设备分配 IP 地址。
  833. log.info("netdrv", "创建dhcp服务器, 供以太网使用")
  834. if other_configs.adapter_gw then
  835. dhcpsrv.create({ adapter = socket.LWIP_ETH, gw = other_configs.adapter_gw })
  836. else
  837. dhcpsrv.create({ adapter = socket.LWIP_ETH, gw = { 192, 168, 5, 1 } })
  838. end
  839. -- 创建 DNS 代理服务,使得以太网接口上的设备可以通过 4G 网络访问互联网。
  840. log.info("netdrv", "创建dns代理服务, 供以太网使用")
  841. elseif adapter == socket.LWIP_AP then
  842. wlan.setMode(wlan.APSTA)
  843. -- 打开AP功能,设置混合模式
  844. log.info("执行AP创建操作", airlink.ready(), "正常吗?")
  845. wlan.createAP(other_configs.ssid, other_configs.password, other_configs.adapter_addr or "192.168.4.1",
  846. "255.255.255.0",
  847. other_configs.channel, other_configs.ap_opts)
  848. -- 设置 AP 的 IP 地址、子网掩码、网关地址
  849. netdrv.ipv4(socket.LWIP_AP, other_configs.adapter_addr or "192.168.4.1", "255.255.255.0", "0.0.0.0")
  850. -- 获取 WiFi AP 网络状态,连接后返回 true,否则返回 false,如果不存在就返回 nil。
  851. log.info("netdrv", "等待AP就绪")
  852. local count = 1
  853. while netdrv.ready(socket.LWIP_AP) ~= true do
  854. -- log.info("netdrv", "等待AP就绪")
  855. if count > 600 then
  856. log.error("AP创建超时,请检查配置")
  857. return false
  858. end
  859. sys.wait(100)
  860. count = count + 1
  861. end
  862. -- 创建 DHCP 服务器,为连接到 WiFi AP 的设备分配 IP 地址。
  863. log.info("netdrv", "创建dhcp服务器, 供AP使用")
  864. if other_configs.adapter_gw then
  865. dhcpsrv.create({ adapter = socket.LWIP_AP, gw = other_configs.adapter_gw })
  866. else
  867. dhcpsrv.create({ adapter = socket.LWIP_AP })
  868. end
  869. elseif adapter == socket.LWIP_USER1 then
  870. log.info("ch390", "打开LDO供电", other_configs.ethpower_en)
  871. if other_configs.ethpower_en then
  872. gpio.setup(other_configs.ethpower_en, 1, gpio.PULLUP)
  873. end
  874. -- 打开LAN功能
  875. -- 配置 SPI 参数,Air8101 使用 SPI 接口与以太网模块进行通信。
  876. log.info("netdrv spi挂载以太网", "初始化LAN功能")
  877. local result = spi.setup(
  878. other_configs.opts.spi, -- spi id
  879. nil, 0, -- CPHA
  880. 0, -- CPOL
  881. 8, -- 数据宽度
  882. 25600000 -- ,--波特率
  883. )
  884. log.info("main", "open spi", result)
  885. if result ~= 0 then -- 返回值为 0,表示打开成功
  886. log.error("main", "spi open error", result)
  887. if other_configs.ethpower_en then
  888. gpio.close(other_configs.ethpower_en)
  889. end
  890. return false
  891. end
  892. -- 初始化以太网,Air8000 指定使用 CH390 芯片。
  893. log.info("netdrv", "初始化以太网", other_configs.tp, other_configs.opts)
  894. if netdrv.setup(socket.LWIP_USER1, other_configs.tp, other_configs.opts) == false then
  895. log.error("初始化以太网失败")
  896. if other_configs.ethpower_en then
  897. gpio.close(other_configs.ethpower_en)
  898. end
  899. return false
  900. end
  901. sys.wait(1000) -- 等待以太网模块初始化完成,去掉会导致以太网初始化失败
  902. -- 设置以太网的 IP 地址、子网掩码、网关地址
  903. log.info("netdrv", "自定义以太网IP地址", other_configs.adapter_addr, "网关地址", other_configs.adapter_gw)
  904. netdrv.ipv4(socket.LWIP_USER1, other_configs.adapter_addr or "192.168.5.1", "255.255.255.0", "0.0.0.0")
  905. -- 获取以太网网络状态,连接后返回 true,否则返回 false,如果不存在就返回 nil。
  906. local count = 1
  907. while netdrv.ready(socket.LWIP_USER1) ~= true do
  908. if count > 600 then
  909. log.error("以太网连接超时,请检查配置")
  910. if other_configs.ethpower_en then
  911. gpio.close(other_configs.ethpower_en)
  912. end
  913. return false
  914. end
  915. count = count + 1
  916. -- log.info("netdrv", "等待以太网就绪") -- 若以太网设备没有连上,可打开此处注释排查。
  917. sys.wait(100)
  918. end
  919. log.info("netdrv", "以太网就绪")
  920. -- 创建 DHCP 服务器,为连接到以太网的设备分配 IP 地址。
  921. log.info("netdrv", "创建dhcp服务器, 供以太网使用")
  922. if other_configs.adapter_gw then
  923. dhcpsrv.create({ adapter = socket.LWIP_USER1, gw = other_configs.adapter_gw })
  924. else
  925. dhcpsrv.create({ adapter = socket.LWIP_USER1, gw = { 192, 168, 5, 1 } })
  926. end
  927. -- 创建 DNS 代理服务,使得以太网接口上的设备可以通过 4G 网络访问互联网。
  928. log.info("netdrv", "创建dns代理服务, 供以太网使用")
  929. end
  930. dnsproxy.setup(adapter, main_adapter)
  931. netdrv.napt(main_adapter)
  932. return true
  933. end
  934. return exnetif