exnetif.lua 34 KB

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