lan_wan.lua 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. --[[
  2. =======================================================================
  3. CH390双网口SPI0复用演示程序核心逻辑
  4. =======================================================================
  5. 功能概述:
  6. 本程序演示如何在单个SPI总线上同时连接两个CH390网络芯片,实现完整的
  7. WAN+LAN双网口路由器功能。
  8. SPI复用技术原理:
  9. 1. 【总线共享】两个CH390芯片共享SPI0的SCK、MOSI、MISO三条信号线
  10. 2. 【片选分离】通过不同的CS引脚(GPIO8/GPIO12)实现设备选择
  11. 3. 【时序互斥】使用SPI锁定机制确保同一时刻只有一个设备通信
  12. 4. 【驱动隔离】每个CH390有独立的网络适配器和协议栈
  13. 硬件连接:
  14. MCU (Air780EPM) CH390-WAN CH390-LAN
  15. ├─ SPI0_SCK ─────┬─ SCK ┌─ SCK
  16. ├─ SPI0_MOSI ─────┼─ MOSI ├─ MOSI
  17. ├─ SPI0_MISO ─────┼─ MISO ├─ MISO
  18. ├─ GPIO12 ─────┘ CS │
  19. ├─ GPIO8 ─────────────────────┘ CS
  20. ├─ GPIO29 ─────── 3.3V供电控制 │
  21. └─ GPIO20 ─────────────────────── 3.3V供电控制
  22. 网络拓扑:
  23. Internet ←→ [WAN口CH390] ←→ [Air780EPM] ←→ [LAN口CH390] ←→ 内网设备
  24. CS=GPIO12 4G/路由转发 CS=GPIO8 192.168.4.x
  25. 技术特点:
  26. - ✅ 完全硬件SPI复用,无需软件SPI
  27. - ✅ 25.6MHz高速SPI通信
  28. - ✅ 自动SPI总线锁定/解锁机制
  29. - ✅ 支持并发网络数据处理
  30. - ✅ 独立的DHCP、DNS、NAT服务
  31. 关键点:
  32. 1. 两个网口使用相同的SPI总线(SPI0)
  33. 2. 每个网口使用不同的CS片选引脚(WAN=GPIO12,LAN=GPIO8)
  34. 3. SPI总线只需要配置一次,CS引脚需要单独初始化
  35. 4. 通过LuatOS的SPI锁定机制保证通信安全
  36. =======================================================================
  37. ]]
  38. -- 引入必要的库文件(lua编写), 内部库不需要require
  39. sys = require("sys")
  40. sysplus = require("sysplus")
  41. -- 引入DHCP服务器和DNS代理模块
  42. dhcps = require "dhcpsrv"
  43. dnsproxy = require "dnsproxy"
  44. -- 网络配置参数
  45. local WAN_SPI_ID = 0 -- WAN口使用SPI0(复用)
  46. local WAN_CS_PIN = 12 -- WAN口片选引脚
  47. local WAN_SPI_SPEED = 25600000 -- WAN口SPI速度
  48. local LAN_SPI_ID = 0 -- LAN口使用SPI0(复用)
  49. local LAN_CS_PIN = 8 -- LAN口片选引脚(必须与WAN口不同)
  50. local LAN_SPI_SPEED = 25600000 -- LAN口SPI速度
  51. local BOTH_SPI_SPEED = 25600000 -- SPI速度
  52. local LAN_IP = "192.168.4.1" -- LAN口IP地址
  53. local LAN_MASK = "255.255.255.0" -- LAN口子网掩码
  54. local LAN_GW = "192.168.4.1" -- LAN口网关
  55. -- 网络适配器定义
  56. local WAN_ADAPTER = socket.LWIP_USER1 -- WAN口适配器
  57. local LAN_ADAPTER = socket.LWIP_USER0 -- LAN口适配器
  58. -- 网口初始化配置选项
  59. -- "LAN" - 只初始化LAN口
  60. -- "WAN" - 只初始化WAN口
  61. -- "BOTH" - 同时初始化WAN口和LAN口
  62. local INIT_MODE = "BOTH"
  63. -- 同时初始化WAN口和LAN口
  64. local function init_wan_lan()
  65. log.info("INIT", "开始初始化网口,模式:" .. INIT_MODE)
  66. -- 根据模式选择SPI ID和速度
  67. local spi_id, spi_speed
  68. if INIT_MODE == "WAN" then
  69. spi_id = WAN_SPI_ID
  70. spi_speed = WAN_SPI_SPEED
  71. elseif INIT_MODE == "LAN" then
  72. spi_id = LAN_SPI_ID
  73. spi_speed = LAN_SPI_SPEED
  74. else -- INIT_MODE == "BOTH"
  75. spi_id = WAN_SPI_ID -- 复用模式使用WAN口的SPI ID
  76. spi_speed = BOTH_SPI_SPEED
  77. end
  78. -- 配置SPI接口(只需要配置一次SPI总线)
  79. local result = spi.setup(
  80. spi_id,
  81. nil, -- CS由netdrv管理,这里不设置
  82. 0, -- CPHA
  83. 0, -- CPOL
  84. 8, -- 数据宽度
  85. spi_speed
  86. )
  87. if result ~= 0 then
  88. log.error("INIT", "SPI配置失败", result)
  89. return false
  90. end
  91. -- 根据配置初始化对应的网口
  92. if INIT_MODE == "WAN" or INIT_MODE == "BOTH" then
  93. -- 初始化WAN口CS引脚
  94. gpio.setup(WAN_CS_PIN, 1) -- 拉高CS引脚(空闲状态)
  95. gpio.setup(LAN_CS_PIN, 1) -- 拉高CS引脚,防止干扰
  96. -- 初始化CH390网络驱动(WAN口)
  97. log.info("INIT", "初始化WAN口网络驱动")
  98. netdrv.setup(WAN_ADAPTER, netdrv.CH390, {
  99. spi = WAN_SPI_ID,
  100. cs = WAN_CS_PIN
  101. })
  102. -- 启用DHCP客户端,从外网获取IP地址
  103. netdrv.dhcp(WAN_ADAPTER, true)
  104. sys.wait(1000) -- 等待WAN口初始化稳定
  105. log.info("INIT", "WAN口初始化完成,使用SPI", WAN_SPI_ID, "CS引脚", WAN_CS_PIN)
  106. end
  107. if INIT_MODE == "LAN" or INIT_MODE == "BOTH" then
  108. -- 初始化LAN口CS引脚
  109. gpio.setup(LAN_CS_PIN, 1) -- 拉高CS引脚(空闲状态)
  110. gpio.setup(WAN_CS_PIN, 1) -- 拉高CS引脚,防止干扰
  111. -- 初始化CH390网络驱动(LAN口)
  112. log.info("INIT", "初始化LAN口网络驱动")
  113. netdrv.setup(LAN_ADAPTER, netdrv.CH390, {
  114. spi = LAN_SPI_ID,
  115. cs = LAN_CS_PIN
  116. })
  117. sys.wait(2000) -- 等待LAN口初始化稳定
  118. -- 配置LAN网络IP地址
  119. local ipv4, mask, gw = netdrv.ipv4(LAN_ADAPTER, LAN_IP, LAN_MASK, LAN_GW)
  120. log.info("LAN", "IP配置", ipv4, mask, gw)
  121. log.info("INIT", "LAN口初始化完成,使用SPI", LAN_SPI_ID, "CS引脚", LAN_CS_PIN)
  122. end
  123. log.info("INIT", "网口初始化完成,模式:" .. INIT_MODE)
  124. return true
  125. end
  126. -- 等待网络连接并设置服务
  127. local function setup_network_services()
  128. log.info("NET", "开始配置网络服务")
  129. -- 根据初始化模式等待对应网口连接
  130. if INIT_MODE == "LAN" or INIT_MODE == "BOTH" then
  131. -- 等待LAN口以太网连接建立
  132. while netdrv.link(LAN_ADAPTER) ~= true do
  133. log.info("NET", "等待LAN口以太网连接...")
  134. sys.wait(100)
  135. end
  136. log.info("NET", "LAN口以太网连接已建立")
  137. end
  138. -- 等待4G网络连接建立(用于NAT转发)
  139. if INIT_MODE == "LAN" or INIT_MODE == "BOTH" then
  140. while netdrv.link(socket.LWIP_GP) ~= true do
  141. log.info("NET", "等待4G网络连接...")
  142. sys.wait(100)
  143. end
  144. log.info("NET", "4G网络连接已建立")
  145. -- 启动DHCP服务器,为局域网设备分配IP地址
  146. dhcps.create({adapter = LAN_ADAPTER})
  147. log.info("NET", "DHCP服务器已启动")
  148. -- 启动DNS代理服务,转发DNS查询请求
  149. dnsproxy.setup(LAN_ADAPTER, socket.LWIP_GP)
  150. log.info("NET", "DNS代理服务已启动")
  151. -- 启用NAT转发功能,实现内网与外网的地址转换
  152. netdrv.napt(socket.LWIP_GP)
  153. log.info("NET", "NAT转发已启用")
  154. -- 如果支持iperf,启动网络性能测试服务器
  155. if iperf then
  156. log.info("NET", "启动iperf服务器端")
  157. iperf.server(LAN_ADAPTER)
  158. end
  159. end
  160. log.info("NET", "网络服务配置完成")
  161. end
  162. -- 网络状态监控
  163. local function network_monitor()
  164. while true do
  165. sys.wait(10000) -- 每10秒检查一次
  166. local status_info = {}
  167. -- 根据初始化模式检查对应网口状态
  168. if INIT_MODE == "WAN" or INIT_MODE == "BOTH" then
  169. local wan_link = netdrv.link(WAN_ADAPTER)
  170. local wan_ready = netdrv.ready(WAN_ADAPTER)
  171. table.insert(status_info, string.format("WAN: link=%s ready=%s", tostring(wan_link), tostring(wan_ready)))
  172. end
  173. if INIT_MODE == "LAN" or INIT_MODE == "BOTH" then
  174. local lan_link = netdrv.link(LAN_ADAPTER)
  175. local lan_ready = netdrv.ready(LAN_ADAPTER)
  176. table.insert(status_info, string.format("LAN: link=%s ready=%s", tostring(lan_link), tostring(lan_ready)))
  177. end
  178. -- 检查4G网络状态
  179. local gprs_link = netdrv.link(socket.LWIP_GP)
  180. local gprs_ready = netdrv.ready(socket.LWIP_GP)
  181. table.insert(status_info, string.format("4G: link=%s ready=%s", tostring(gprs_link), tostring(gprs_ready)))
  182. log.info("状态", table.concat(status_info, ", "))
  183. -- 输出内存使用情况
  184. log.info("内存", "Lua:", rtos.meminfo())
  185. log.info("内存", "Sys:", rtos.meminfo("sys"))
  186. end
  187. end
  188. -- 主初始化任务
  189. sys.taskInit(function()
  190. if init_wan_lan() then
  191. log.info("INIT", "网口初始化成功")
  192. -- 初始化成功后,启动网络服务
  193. setup_network_services()
  194. else
  195. log.error("INIT", "网口初始化失败")
  196. end
  197. end)
  198. -- 网络监控任务
  199. sys.taskInit(network_monitor)
  200. -- 事件处理
  201. sys.subscribe("IP_READY", function(adapter)
  202. log.info("事件", "IP_READY", adapter)
  203. if adapter == WAN_ADAPTER and (INIT_MODE == "WAN" or INIT_MODE == "BOTH") then
  204. log.info("事件", "WAN口IP就绪")
  205. elseif adapter == LAN_ADAPTER and (INIT_MODE == "LAN" or INIT_MODE == "BOTH") then
  206. log.info("事件", "LAN口IP就绪")
  207. elseif adapter == socket.LWIP_GP then
  208. log.info("事件", "4G网络IP就绪")
  209. end
  210. end)
  211. sys.subscribe("IP_LOSE", function(adapter)
  212. log.info("事件", "IP_LOSE", adapter)
  213. if adapter == WAN_ADAPTER and (INIT_MODE == "WAN" or INIT_MODE == "BOTH") then
  214. log.warn("事件", "WAN口IP丢失")
  215. elseif adapter == LAN_ADAPTER and (INIT_MODE == "LAN" or INIT_MODE == "BOTH") then
  216. log.warn("事件", "LAN口IP丢失")
  217. elseif adapter == socket.LWIP_GP then
  218. log.warn("事件", "4G网络IP丢失")
  219. end
  220. end)