Browse Source

update:8101 AirPHY_1000 demo

王城钧 6 months ago
parent
commit
db63480740

+ 141 - 0
module/Air8101/demo/accessory_board/AirPHY_1000/http/http_app.lua

@@ -0,0 +1,141 @@
+--[[
+@module  http_app
+@summary http应用功能模块
+@version 1.0
+@date    2025.09.17
+@author  王城钧
+@usage
+本文件为http应用功能模块,核心业务逻辑为:基于不同的应用场景,演示http核心库的使用方式;
+本文件没有对外接口,直接在main.lua中require "http_app"就可以加载运行;
+]]
+
+--[[
+此处先详细解释下http.request接口的使用方法
+
+接口定义:
+    http.request(method, url, headers, body, opts, server_ca_cert, client_cert, client_key, client_password)
+
+使用方法:
+    local code, headers, body = http.request(method, url, headers, body, opts, server_ca_cert, client_cert, client_key, client_password).wait()
+    只能在task中使用
+    发送http请求到服务器,等待服务器的http应答,此处会阻塞当前task,等待整个过程成功结束或者出现错误异常结束或者超时结束
+
+参数定义:
+    method,stirng类型,必须包含此参数,表示HTTP请求方法,支持"GET"、"POST"、"HEAD"等所有HTTP请求方法
+    url,string类型,必须包含此参数,表示HTTP请求URL地址,支持HTTP、HTTPS,支持域名、IP地址,支持自定义端口,标准的HTTP URL格式都支持
+    headers,table或者nil类型,可选包含此参数,表示HTTP请求头,例如 {["Content-Type"] = "application/x-www-form-urlencoded", ["self_defined_key"] = "self_defined_value"}
+    body,string或者zbuff或者nil类型,可选包含此参数,表示HTTP请求体,如果请求体是一个文件中的内容,要把文件内容读出来,赋值给body使用
+    opts,table或者nil类型,可选包含此参数,表示HTTP请求的一些额外配置,包含以下内容
+    {
+        timeout    -- -- number或者nil类型,单位毫秒,可选包含此参数,表示从发送请求到读取到服务器响应整个过程的超时时间,如果传入0,表示永久等待;如果没有传入此参数或者传入nil,则使用默认值10分钟
+        dst        -- 下载路径,string类型,当HTTP请求的数据需要保存到文件中时,此处填写完整的文件路径
+        adapter    -- 使用的网卡ID,number类型,例如4G网卡,SPI外挂以太网卡,WIFI网卡等;如果没有传入此参数,内核固件会自动选择当前时间点其他功能模块设置的默认网卡
+                    -- 除非你HTTP请求时,一定要使用某一种网卡,才设置此参数;如果没什么特别要求,不要使用此参数,使用系统中设置的默认网卡即可
+                    -- 这个参数和本demo中的netdrv_device.lua关系比较大,netdrv_device会设置默认网卡,此处http不要设置adapter参数,直接使用netdrv_device设置的默认网卡就行
+        debug      -- 调试开关,bool类型,true表示打开debug调试信息日志,false表示关闭debug调试信息日志,默认为关闭状态
+        ipv6       -- 是否为ipv6,bool类型,true表示使用ipv6,false表示不使用ipv6,默认为false
+        userdata   -- 下载回调函数使用的用户自定义回调参数,做为callback回调函数的第三个参数使用
+        callback   -- 下载回调函数,function类型,当下载数据时,无论是保存到内存中,还是保存到文件系统中,如果设置了callback,内核固件中每收到一包body数据,都会自动执行一次callback回调函数
+                    -- 回调函数的调用形式为callback(content_len, body_len, userdata)
+                    --     content_len:number类型,数据总长度
+                    --     body_len:number类型,已经下载的数据长度
+                    --     userdata:下载回调函数使用的用户自定义回调参数
+    }
+    server_ca_cert,string类型,服务器ca证书数据,可选包含此参数,当客户端需要验证服务器证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给server_ca_cert
+    client_cert,string类型,客户端证书数据,可选包含此参数,当服务器需要验证客户端证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给client_cert
+    client_key, string类型,客户端加密后的私钥数据,可选包含此参数,当服务器需要验证客户端证书时,需要此参数,如果加密后的私钥数据在一个文件中,要把文件内容读出来,赋值给client_key
+    client_password,string类型,客户端私钥口令数据,可选包含此参数,当服务器需要验证客户端证书时,需要此参数,如果私钥口令数据在一个文件中,要把文件内容读出来,赋值给client_password
+
+返回值定义:
+
+    http.request().wait()有三个返回值code,headers,body
+    code表示执行结果,number类型,有以下两种含义:
+        1、code大于等于100时,表示服务器返回的HTTP状态码,例如200表示成功,详细说明可以通过搜索引擎搜索“HTTP状态码”自行了解
+        2、code小于0时,表示内核固件中检测到通信异常,有如下几种:
+            -1 HTTP_ERROR_STATE 错误的状态, 一般是底层异常,请报issue
+            -2 HTTP_ERROR_HEADER 错误的响应头部, 通常是服务器问题
+            -3 HTTP_ERROR_BODY 错误的响应体,通常是服务器问题
+            -4 HTTP_ERROR_CONNECT 连接服务器失败, 未联网,地址错误,域名错误
+            -5 HTTP_ERROR_CLOSE 提前断开了连接, 网络或服务器问题
+            -6 HTTP_ERROR_RX 接收数据报错, 网络问题
+            -7 HTTP_ERROR_DOWNLOAD 下载文件过程报错, 网络问题或下载路径问题
+            -8 HTTP_ERROR_TIMEOUT 超时, 包括连接超时,读取数据超时
+            -9 HTTP_ERROR_FOTA fota功能报错,通常是更新包不合法
+    headers有以下两种含义:
+        1、当code的返回值大于等于100时,headers表示服务器返回的应答头,table类型
+        2、当code的返回值小于0时,headers为nil
+    body有以下三种含义
+        1、当code的返回值大于等于100时,如果请求的body数据不需要保存到文件中,而是直接保存到内存中,则body表示请求到的数据内容,string类型
+        2、当code的返回值大于等于100时,如果请求的body数据需要保存到文件中,则body表示保存请求数据后的文件的大小,number类型
+        3、当code的返回值小于0时,body为nil
+]]
+
+
+-- 普通的http get请求功能演示
+-- 请求的body数据保存到内存变量中,在内存够用的情况下,最大支持32KB的数据存储到内存中
+-- timeout可以设置超时时间
+-- callback可以设置回调函数,可用于实时检测body数据的下载进度
+local function http_app_get()
+    -- https get请求https://www.air32.cn/网页内容
+    -- 如果请求成功,请求的数据保存到body中
+    local code, headers, body = http.request("GET", "https://www.air32.cn/").wait()
+    log.info("http_app_get1",
+        code == 200 and "success" or "error",
+        code,
+        json.encode(headers or {}),
+        body and (body:len() > 512 and body:len() or body) or "nil")
+
+    -- https get请求https://www.luatos.com/网页内容,超时时间为10秒
+    -- 请求超时时间为10秒,用户自己写代码时,不要照抄10秒,根据自己业务逻辑的需要设置合适的超时时间
+    -- 回调函数为http_cbfunc,回调函数使用的第三个回调参数为"http_app_get2"
+    -- 如果请求成功,请求的数据保存到body中
+    code, headers, body = http.request("GET", "https://www.luatos.com/", nil, nil,
+        { timeout = 10000, userdata = "http_app_get2", callback = http_cbfunc }).wait()
+    log.info("http_app_get2",
+        code == 200 and "success" or "error",
+        code,
+        json.encode(headers or {}),
+        body and (body:len() > 512 and body:len() or body) or "nil")
+
+    -- http get请求http://httpbin.air32.cn/get网页内容,超时时间为3秒
+    -- 请求超时时间为3秒,用户自己写代码时,不要照抄3秒,根据自己业务逻辑的需要设置合适的超时时间
+    -- 回调函数为http_cbfunc,回调函数使用的第三个回调参数为"http_app_get3"
+    -- 如果请求成功,请求的数据保存到body中
+    code, headers, body = http.request("GET", "http://httpbin.air32.cn/get", nil, nil,
+        { timeout = 3000, userdata = "http_app_get3", callback = http_cbfunc }).wait()
+    log.info("http_app_get3",
+        code == 200 and "success" or "error",
+        code,
+        json.encode(headers or {}),
+        body and (body:len() > 512 and body:len() or body) or "nil")
+end
+
+-- http app task 的任务处理函数
+local function http_app_task_func()
+    while true do
+        -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
+        while not socket.adapter(socket.dft()) do
+            log.warn("http_app_task_func", "wait IP_READY", socket.dft())
+            -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
+            -- 或者等待1秒超时退出阻塞等待状态;
+            -- 注意:此处的1000毫秒超时不要修改的更长;
+            -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
+            -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
+            -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
+            sys.waitUntil("IP_READY", 1000)
+        end
+
+        -- 检测到了IP_READY消息
+        log.info("http_app_task_func", "recv IP_READY", socket.dft())
+
+        -- 普通的http get请求功能演示
+        http_app_get()
+
+        -- 50秒之后,循环测试
+        sys.wait(50000)
+    end
+end
+
+--创建并且启动一个task
+--运行这个task的处理函数http_app_task_func
+sys.taskInit(http_app_task_func)

+ 79 - 0
module/Air8101/demo/accessory_board/AirPHY_1000/http/main.lua

@@ -0,0 +1,79 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
+@version 1.0
+@date    2025.09.22
+@author  王城钧
+@usage
+本demo演示的核心功能为:
+1、分别使用http核心库和httpplus扩展库,演示以下一种应用场景的使用方式
+   (1) 普通的http get请求功能演示;;
+2、netdrv_device:配置连接外网使用的网卡,目前支持以下四种选择(二选一)
+   (3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
+   (4) netdrv_multiple:支持以上三种网卡,可以配置三种网卡的优先级
+
+更多说明参考本目录下的readme.md文件
+]]
+
+
+--[[
+必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
+PROJECT:项目名,ascii string类型
+        可以随便定义,只要不使用,就行
+VERSION:项目版本号,ascii string类型
+        如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
+            X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
+            因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
+        如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
+]]
+PROJECT = "HTTP"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
+if wdt then
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
+end
+
+
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
+
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+-- 加载网络驱动设备功能模块
+require "netdrv_device"
+
+-- 加载http应用功能模块
+require "http_app"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 77 - 0
module/Air8101/demo/accessory_board/AirPHY_1000/http/netdrv/netdrv_eth_rmii.lua

@@ -0,0 +1,77 @@
+--[[
+@module  netdrv_eth_rmii
+@summary “通过MAC层的rmii接口外挂PHY芯片(LAN8720Ai)的以太网卡”驱动模块 
+@version 1.0
+@date    2025.07.24
+@author  马梦阳
+@usage
+本文件为“通过MAC层的rmii接口外挂PHY芯片(LAN8720Ai)的以太网卡”驱动模块 ,核心业务逻辑为:
+1、打开PHY芯片供电开关;
+2、初始化以太网卡,并且在以太网卡上开启DHCP(动态主机配置协议);
+3、以太网卡的连接状态发生变化时,在日志中进行打印;
+
+Air8101核心板和AirPHY_1000配件板的硬件接线方式为:
+Air8101核心板通过TYPE-C USB口供电(核心板背面的功耗测试开关拨到OFF一端);
+如果测试发现软件重启,并且日志中出现  poweron reason 0,表示供电不足,此时再通过直流稳压电源对核心板的VIN管脚进行5V供电;
+| Air8101核心板 |  AirPHY_1000配件板  |
+| ------------ | ------------------ |
+|    59/3V3    |         3.3v       |
+|     gnd      |         gnd        |
+|     5/D2     |         RX1        |
+|    72/D1     |         RX0        |
+|    71/D3     |         CRS        |
+|     4/D0     |         MDIO       |
+|     6/D4     |         TX0        |
+|    74/PCK    |         MDC        |
+|    70/D5     |         TX1        |
+|     7/D6     |         TXEN       |
+|     不接     |          NC        |
+|    69/D7     |         CLK        |
+
+本文件没有对外接口,直接在其他功能模块中require "netdrv_eth_rmii"就可以加载运行;
+]]
+
+local function ip_ready_func(ip, adapter)
+    if adapter == socket.LWIP_ETH then
+        log.info("netdrv_eth_rmii.ip_ready_func", "IP_READY", socket.localIP(socket.LWIP_ETH))
+    end
+end
+
+local function ip_lose_func(adapter)
+    if adapter == socket.LWIP_ETH then
+        log.warn("netdrv_eth_rmii.ip_lose_func", "IP_LOSE")
+    end
+end
+
+
+-- 此处订阅"IP_READY"和"IP_LOSE"两种消息
+-- 在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过MAC层的rmii接口外挂PHY芯片(LAN8720Ai)的以太网卡”的连接状态
+-- 也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
+sys.subscribe("IP_READY", ip_ready_func)
+sys.subscribe("IP_LOSE", ip_lose_func)
+
+
+-- 设置默认网卡为socket.LWIP_ETH
+socket.dft(socket.LWIP_ETH)
+
+
+-- 本demo测试使用的是核心板的VDD 3V3引脚对AirPHY_1000配件板进行供电
+-- VDD 3V3引脚是Air8101内部的LDO输出引脚,最大输出电流300mA
+-- GPIO13在Air8101内部使能控制这个LDO的输出
+-- 所以在此处GPIO13输出高电平打开这个LDO
+gpio.setup(13, 1, gpio.PULLUP)
+
+
+--初始化以太网卡
+
+--以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
+--各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
+--也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
+
+--以太网断网后,内核固件会产生一个"IP_LOSE"消息
+--各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
+--也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
+netdrv.setup(socket.LWIP_ETH)
+
+--在以太网卡上开启动态主机配置协议
+netdrv.dhcp(socket.LWIP_ETH, true)

+ 105 - 0
module/Air8101/demo/accessory_board/AirPHY_1000/http/netdrv/netdrv_multiple.lua

@@ -0,0 +1,105 @@
+--[[
+@module  netdrv_multiple
+@summary 多网卡(WIFI STA网卡、通过MAC层的rmii接口外挂PHY芯片(LAN8720Ai)的以太网卡)驱动模块
+@version 1.0
+@date    2025.07.24
+@author  马梦阳
+@usage
+本文件为多网卡驱动模块 ,核心业务逻辑为:
+1、调用exnetif.set_priority_order配置多网卡的控制参数以及优先级;
+
+
+通过MAC层的rmii接口外挂PHY芯片(LAN8720Ai)的以太网卡:
+Air8101核心板和AirPHY_1000配件板的硬件接线方式为:
+Air8101核心板通过TYPE-C USB口供电(核心板背面的功耗测试开关拨到OFF一端);
+如果测试发现软件重启,并且日志中出现  poweron reason 0,表示供电不足,此时再通过直流稳压电源对核心板的VIN管脚进行5V供电;
+| Air8101核心板 | AirPHY_1000配件板  |
+| ------------ | ------------------ |
+|    59/3V3    |         3.3v       |
+|     gnd      |         gnd        |
+|     5/D2     |         RX1        |
+|    72/D1     |         RX0        |
+|    71/D3     |         CRS        |
+|     4/D0     |         MDIO       |
+|     6/D4     |         TX0        |
+|    74/PCK    |         MDC        |
+|    70/D5     |         TX1        |
+|     7/D6     |         TXEN       |
+|     不接     |          NC        |
+|    69/D7     |         CLK        |
+
+本文件没有对外接口,直接在其他功能模块中require "netdrv_multiple"就可以加载运行;
+]]
+
+
+local exnetif = require "exnetif"
+
+-- 网卡状态变化通知回调函数
+-- 当exnetif中检测到网卡切换或者所有网卡都断网时,会触发调用此回调函数
+-- 当网卡切换切换时:
+--     net_type:string类型,表示当前使用的网卡字符串
+--     adapter:number类型,表示当前使用的网卡id
+-- 当所有网卡断网时:
+--     net_type:为nil
+--     adapter:number类型,为-1
+local function netdrv_multiple_notify_cbfunc(net_type,adapter)
+    if type(net_type)=="string" then
+        log.info("netdrv_multiple_notify_cbfunc", "use new adapter", net_type, adapter)
+    elseif type(net_type)=="nil" then
+        log.warn("netdrv_multiple_notify_cbfunc", "no available adapter", net_type, adapter)
+    else
+        log.warn("netdrv_multiple_notify_cbfunc", "unknown status", net_type, adapter)
+    end
+end
+
+
+local function netdrv_multiple_task_func()
+    --设置网卡优先级
+    exnetif.set_priority_order(
+        {
+            -- “通过MAC层的rmii接口外挂PHY芯片(LAN8720Ai)”的以太网卡,可以使用Air8101核心板+AirPHY_1000配件板验证
+            {
+                ETHERNET = {
+                    -- 供电使能GPIO,此demo使用的59脚3V3供电,受GPIO13控制
+                    pwrpin = 13,
+                    -- 设置的多个“已经IP READY,但是还没有ping通”网卡,循环执行ping动作的间隔(单位毫秒,可选)
+                    -- 如果没有传入此参数,exnetif会使用默认值10秒
+                    ping_time = 3000,
+
+                    -- 连通性检测ip(选填参数);
+                    -- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;
+                    -- 如果传入,一定要传入可靠的并且可以ping通的ip地址;
+                    -- ping_ip = "填入可靠的并且可以ping通的ip地址",
+                }
+            },
+
+            -- WIFI STA网卡
+            {
+                WIFI = {
+                    -- 要连接的WIFI路由器名称
+                    ssid = "iPhone",
+                    -- 要连接的WIFI路由器密码
+                    password = "xiaoshuai", 
+
+                    -- 连通性检测ip(选填参数);
+                    -- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;
+                    -- 如果传入,一定要传入可靠的并且可以ping通的ip地址;
+                    -- ping_ip = "填入可靠的并且可以ping通的ip地址",
+                }
+            }
+        }
+    )    
+end
+
+-- 设置网卡状态变化通知回调函数netdrv_multiple_notify_cbfunc
+exnetif.notify_status(netdrv_multiple_notify_cbfunc)
+
+-- 如果存在udp网络应用,并且udp网络应用中,根据应用层的心跳能够判断出来udp数据通信出现了异常;
+-- 可以在判断出现异常的位置,调用一次exnetif.check_network_status()接口,强制对当前正式使用的网卡进行一次连通性检测;
+-- 如果存在tcp网络应用,不需要用户调用exnetif.check_network_status()接口去控制,exnetif会在tcp网络应用通信异常时自动对当前使用的网卡进行连通性检测。
+
+
+-- 启动一个task,task的处理函数为netdrv_multiple_task_func
+-- 在处理函数中调用exnetif.set_priority_order设置网卡优先级
+-- 因为exnetif.set_priority_order要求必须在task中被调用,所以此处启动一个task
+sys.taskInit(netdrv_multiple_task_func)

+ 25 - 0
module/Air8101/demo/accessory_board/AirPHY_1000/http/netdrv_device.lua

@@ -0,0 +1,25 @@
+--[[
+@module  netdrv_device
+@summary 网络驱动设备功能模块
+@version 1.0
+@date    2025.09.24
+@author  王城钧
+@usage
+本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
+1、netdrv_ethernet_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
+2、netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
+
+根据自己的项目需求,只需要require以上其中的一种即可;
+
+
+本文件没有对外接口,直接在main.lua中require "netdrv_device"就可以加载运行;
+]]
+
+
+-- 根据自己的项目需求,只需要require以下其中的一种即可;
+
+-- 加载“通过MAC层的rmii接口外挂PHY芯片(LAN8720Ai)的以太网卡”驱动模块
+-- require "netdrv_eth_rmii"
+
+-- 加载“可以配置优先级的多种网卡”驱动模块
+require "netdrv_multiple"

+ 85 - 0
module/Air8101/demo/accessory_board/AirPHY_1000/http/readme.md

@@ -0,0 +1,85 @@
+## 功能模块介绍:
+
+1、main.lua:主程序入口;
+
+2、netdrv_device.lua:加载网络驱动设备功能模块;
+
+3、http_app.lua:加载http应用模块
+
+## 演示功能概述
+
+1、以太网给模组供网,通过连接http测试连通。
+
+## 演示硬件环境
+
+1、Air8101核心板一块+可上网的sim卡一张+网线一根+AirPHY_1000板子一个;
+
+[](https://docs.openLuat.com/cdn/image/8101_AirPHY1000.jpg)
+
+![lan](https://docs.openLuat.com/cdn/image/8101_AirPHY1000.jpg)
+
+2、TYPE-C USB数据线一根 + 杜邦线若干;
+
+* Air8101核心板通过TYPE-C USB口供电;(外部供电/USB供电 拨动开关 拨到 USB供电一端)
+
+* TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+* AirPHY_1000板子网口与路由器网口通过网线连接;
+
+3、Air8101核心板和AirPHY_1000配件板的硬件接线方式为:
+
+| Air8101核心板 | AirPHY_1000配件板 |
+| ---------- | -------------- |
+| 59/3V3     | 3.3v           |
+| gnd        | gnd            |
+| 5/D2       | RX1            |
+| 72/D1      | RX0            |
+| 71/D3      | CRS            |
+| 4/D0       | MDIO           |
+| 6/D4       | TX0            |
+| 74/PCK     | MDC            |
+| 70/D5      | TX1            |
+| 7/D6       | TXEN           |
+| 不接         | NC             |
+| 69/D7      | CLK            |
+
+演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8101 V2014版本固件](https://docs.openluat.com/air8101/luatos/firmware/)(理论上,2025年9月12日之后发布的固件都可以)
+
+## 演示核心步骤
+
+1、搭建好硬件环境,按接线图连接硬件。
+
+2、烧录内核固件和本项目的Lua脚本:main.lua:主程序入口(需要在main.lua文件中打开require"netdrv_device"和require"http_app")
+
+3、启动设备,观察日志输出:
+
+```
+出现类似如下打印,就表示成功。
+
+[2025-09-17 14:35:59.774][000000005.877] D/ulwip IP_READY 4 192.168.3.99
+
+[2025-09-17 14:35:59.777][000000005.878] I/user.netdrv_PHY_spi.ip_ready_func IP_READY 192.168.3.99 255.255.255.0 
+192.168.3.1 nil
+
+[2025-09-17 14:35:59.783][000000005.879] I/user.http_app_task_func recv IP_READY 4 4
+
+[2025-09-17 14:35:59.786][000000005.883] dns_run 676:www.air32.cn state 0 id 1 ipv6 0 use dns server0, try 0
+
+[2025-09-17 14:35:59.789][000000005.883] D/net adatper 4 dns server 192.168.3.1
+
+[2025-09-17 14:35:59.793][000000005.883] D/net dns udp sendto 192.168.3.1:53 from 192.168.3.99
+
+[2025-09-17 14:35:59.799][000000005.891] dns_run 693:dns all done ,now stop
+
+[2025-09-17 14:35:59.802][000000005.891] D/net connect 49.232.89.122:443 TCP
+
+[2025-09-17 14:36:00.215][000000006.395] I/user.http_app_get1 success 200 {"Transfer-Encoding":"chunked","Date":"Wed, 17 Sep 2025 06:36:02 GMT","Connection":"keep-alive","Server":"openresty\/1.27.1.2","Content-Type":"text\/html"} 2416
+
+[2025-09-17 14:36:00.226][000000006.396] dns_run 676:www.luatos.com state 0 id 2 ipv6 0 use dns server0, try 0
+
+
+```

+ 0 - 53
module/Air8101/demo/accessory_board/AirPHY_1000/http_app.lua

@@ -1,53 +0,0 @@
-
---这个task的核心业务逻辑是:每隔一段时间发送一次http get请求,测试http数传是否正常
-local function http_get_task_func()
-    --检查当前使用的网卡(本demo使用的是以太网卡socket.LWIP_ETH)的连接状态
-    log.info("http_get_task_func", "socket.adapter(socket.dft())", socket.adapter(socket.dft()))
-    --如果当前使用的网卡(本demo使用的是以太网卡socket.LWIP_ETH)还没有连接成功
-    if not socket.adapter(socket.dft()) then
-        --phy_app.lua中的以太网配置和启动结束后,一旦以太网卡准备就绪,就会产生一个"IP_READY"消息
-        --在此处阻塞等待以太网连接成功的消息"IP_READY"
-        --或者等待30秒超时退出阻塞等待状态
-        --如果没有等到"IP_READY"消息,直接退出这个函数
-        if not sys.waitUntil("IP_READY", 30000) then
-            log.error("http_get_task_func error", "ip network timeout")
-            return
-        end
-    end
-
-    
-    --每6秒执行一次循环
-    while true do
-        --发送http get请求服务器,等待服务器的http应答,此处会阻塞当前task,等待整个过程成功结束或者出现错误异常结束
-        --此处使用了http.request().wait()的形式
-        --http.request()的详细说明参考API文档
-        --wait()表示在此处阻塞等待整个过程的结束
-
-        --具体到此处的代码,对部分参数以及返回值做如下解释
-        --timeout=3000表示超时时间为3秒,如果3秒内没有成功结束或者异常结束整个过程,则会超时结束;
-        --整个过程结束后,http.request().wait()有三个返回值code,headers,body
-        --code表示结果,number类型,详细说明参考API手册,一般来说:
-        --             200表示成功
-        --             小于0的值表示出错,例如-8表示超时错误
-        --             其余结果值参考API手册
-        --headers表示服务器返回的应答头,table类型
-        --body表示服务器返回的应答题,具体到这里的代码使用方式,为string类型
-        log.info("http", http.request("GET", "http://httpbin.air32.cn/get", nil, nil, {timeout=3000}).wait())
-
-        --打印使用的内存信息,方便分析内存使用情况
-        log.info("lua", rtos.meminfo())
-        log.info("sys", rtos.meminfo("sys"))
-
-        --打印当前使用的网卡(本demo使用的是以太网卡socket.LWIP_ETH)下的本地IP,网关,子网掩码,网关IP信息
-        log.info("ip", socket.dft(), socket.localIP(socket.dft()))
-
-        --等待6秒钟
-        sys.wait(6000)
-    end
-
-end
-
---创建并且启动一个task
---task的主函数为http_get_task_func
-sys.taskInit(http_get_task_func)
-

+ 18 - 12
module/Air8101/demo/accessory_board/AirPHY_1000/main.lua → module/Air8101/demo/accessory_board/AirPHY_1000/network_routing/wifi_out_ethernet_in_wifi_in/main.lua

@@ -1,4 +1,15 @@
 --[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
+@version 1.0
+@date    2025.09.22
+@author  王城钧
+@usage
+本demo演示的核心功能为:
+1.设置多网融合功能,wifi提供网络供wifi和以太网设备上网
+更多说明参考本目录下的readme.md文件
+]]
+--[[
 必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
 PROJECT:项目名,ascii string类型
         可以随便定义,只要不使用,就行
@@ -7,19 +18,15 @@ VERSION:项目版本号,ascii string类型
             X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
             因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
         如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
-
-AirPHY_1000是合宙设计生产的一款搭载LAN8720Ai芯片的以太网配件板;
-本demo演示的核心功能为:
-Air8101核心板+AirPHY_1000配件板,使用配件板上的以太网口通过网线连接路由器,演示以太网数传功能;
-更多说明参考本目录下的readme.md文件
 ]]
-PROJECT = "AirPHY_1000"
+PROJECT = "wifi_out_ethernet_in_wifi_in"
 VERSION = "001.000.000"
 
 
 -- 在日志中打印项目名和项目版本号
 log.info("main", PROJECT, VERSION)
 
+
 -- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
 -- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
 if wdt then
@@ -51,15 +58,14 @@ end
 -- sys.timerLoopStart(function()
 --     log.info("mem.lua", rtos.meminfo())
 --     log.info("mem.sys", rtos.meminfo("sys"))
---  end, 3000)
+-- end, 3000)
+
 
--- 加载以太网连接管理功能模块
-require "phy_app"
--- 加载http get应用的功能模块
-require "http_app"
 
+-- 开启多网融合功能
+require "netif_app"
 
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()
--- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行
+-- sys.run()之后后面不要加任何语句!!!!!

+ 53 - 0
module/Air8101/demo/accessory_board/AirPHY_1000/network_routing/wifi_out_ethernet_in_wifi_in/netif_app.lua

@@ -0,0 +1,53 @@
+--[[
+@module  netif_app
+@summary netif_app 网络管理模块,开启多网融合功能,wifi提供网络供以太网和wifi设备上网
+@version 1.0
+@date    2025.09.22
+@author  王城钧
+@usage
+本文件为网络管理模块,核心业务逻辑为:
+1.设置多网融合功能,wifi提供网络供wifi和以太网设备上网
+2、http测试wifi网络
+本文件没有对外接口,直接在main.lua中require "netif_app"就可以加载运行;
+]] 
+exnetif = require "exnetif"
+
+function netif_app_task_func()
+    local res
+    -- 设置多网融合功能,wifi提供网络供wifi设备上网
+    res = exnetif.setproxy(socket.LWIP_AP, socket.LWIP_STA, {
+        ssid = "test2",                 -- AP热点名称(string),网卡包含wifi时填写
+        password = "HZ88888888",        -- AP热点密码(string),网卡包含wifi时填写
+        ap_opts = {                     -- AP模式下配置项(选填参数)
+            hidden = false,             -- 是否隐藏SSID, 默认false,不隐藏
+            max_conn = 4
+        },                              -- 最大客户端数量, 默认4
+        channel = 6,                    -- AP建立的通道, 默认6
+        main_adapter = {                -- 提供网络的网卡开启参数
+            ssid = "iPhone", 
+            password = "xiaoshuai"
+        }
+    })
+    -- 设置多网融合功能,wifi提供网络供以太网设备上网,RMII方式外挂
+    res = exnetif.setproxy(socket.LWIP_ETH, socket.LWIP_STA, {
+        ethpower_en = 13,               -- 以太网模块的pwrpin引脚(gpio编号)
+        main_adapter = {                -- 提供网络的网卡开启参数
+            ssid = "iPhone", 
+            password = "xiaoshuai"
+        }
+    })
+
+    if res then
+        log.info("exnetif", "setproxy success")
+    else
+        log.info("开启失败,请检查配置项是否正确,日志中是否打印了错误信息")
+    end
+    -- 每5秒进行HTTPS连接测试,实时监测wifi网络连接状态, 仅供测试需要,量产不需要,用来判断当前网络是否可用,需要的话可以打开注释
+    -- while 1 do
+    --     local code, headers, body = http.request("GET", "https://httpbin.air32.cn/bytes/2048", nil, nil, {adapter=socket.LWIP_STA,timeout=5000,debug=false}).wait()
+    --     log.info("http执行结果", code, headers, body and #body)
+    --     sys.wait(5000)
+    -- end
+end
+
+sys.taskInit(netif_app_task_func)

+ 73 - 0
module/Air8101/demo/accessory_board/AirPHY_1000/network_routing/wifi_out_ethernet_in_wifi_in/readme.md

@@ -0,0 +1,73 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、netif_app: 网络管理模块,开启多网融合功能,wifi提供网络供以太网和wifi设备上网;
+
+## 演示功能概述
+
+1、开启多网融合模式,WIFI连接外部网络,支持以太网lan模式为其他以太网设备提供接入,支持生成WiFi热点为WiFi终端设备提供接入
+
+2、​网络监控​,每5秒进行HTTPS连接测试,实时监测WIFI网络的连接状态
+
+## 演示硬件环境
+
+![](https://docs.openluat.com/air8101/product/file/AirPHY_1000/hw_connection.jpg)
+
+![](https://docs.openluat.com/air8101/product/file/AirPHY_1000/hw_connection1.jpg)
+
+1、Air8101核心板
+
+2、AirPHY_1000配件板
+
+3、公对母的杜邦线11根(连接核心板和配件板)
+
+4、网线1根(一端接配件板,一端接路由器)
+
+5、Air8101核心板和AirPHY_1000配件板的硬件接线方式为
+
+- Air8101核心板通过TYPE-C USB口供电(核心板背面的功耗测试开关拨到OFF一端);如果测试发现软件重启,并且日志中出现  poweron reason 0,表示供电不足,此时再通过直流稳压电源对核心板的VIN管脚进行5V供电;
+
+Air8101核心板和AirPHY_1000配件板的硬件接线方式为:
+
+| Air8101核心板 | AirPHY_1000配件板 |
+| ---------- | -------------- |
+| 59/3V3     | 3.3v           |
+| gnd        | gnd            |
+| 5/D2       | RX1            |
+| 72/D1      | RX0            |
+| 71/D3      | CRS            |
+| 4/D0       | MDIO           |
+| 6/D4       | TX0            |
+| 74/PCK     | MDC            |
+| 70/D5      | TX1            |
+| 7/D6       | TXEN           |
+| 不接         | NC             |
+| 69/D7      | CLK            |
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8101 V1005版本固件](https://docs.openluat.com/air8101/luatos/firmware/)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录V1005固件对比验证)
+
+## 演示核心步骤
+
+1、搭建好硬件环境,按接线图连接硬件,
+
+2、按需修改WiFi配置(在netif_app.lua中):
+ssid = "WIFI名称"
+password = "WiFi密码"
+
+3、如果使用spi方式外挂网卡,打开SPI方式外挂网卡的代码,注释掉RMII方式外挂网卡的代码
+
+4、内核固件和本项目的Lua脚本:main.lua:主程序入口,netif_app.lua:网络管理模块
+
+5、启动设备,观察日志输出:
+
+```lua
+[INFO] exnetif setproxy success
+[INFO] http执行结果 200 ... 
+```
+
+6、其他设备通过wifi或以太网接入Air8101,其他设备都能正常上网,则表示验证成功。

+ 0 - 42
module/Air8101/demo/accessory_board/AirPHY_1000/phy_app.lua

@@ -1,42 +0,0 @@
-
-local function ip_ready_func()
-    log.info("phy connect.ip_ready_func", "IP_READY")
-end
-
-local function ip_lose_func()
-    log.info("phy connect.ip_lose_func", "IP_LOSE")
-end
-
-
-
---此处订阅"IP_READY"和"IP_LOSE"两种消息
---在消息的处理函数中,仅仅打印了一些信息,便于实时观察以太网的连接状态
---也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
-sys.subscribe("IP_READY", ip_ready_func)
-sys.subscribe("IP_LOSE", ip_lose_func)
-
-
-
-
---本demo测试使用的是核心板的VDD 3V3引脚对AirPHY_1000配件板进行供电
---VDD 3V3引脚是Air8101内部的LDO输出引脚,最大输出电流300mA
---GPIO13在Air8101内部使能控制这个LDO的输出
---所以在此处GPIO13输出高电平打开这个LDO
-gpio.setup(13, 1, gpio.PULLUP) 
-
-
-
---初始化以太网卡
-
---以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
---各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
---也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
-
---以太网断网后,内核固件会产生一个"IP_LOSE"消息
---各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
---也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
-netdrv.setup(socket.LWIP_ETH)
-
---在以太网上开启动态主机配置协议
-netdrv.dhcp(socket.LWIP_ETH, true)
-

+ 5 - 84
module/Air8101/demo/accessory_board/AirPHY_1000/readme.md

@@ -1,88 +1,9 @@
+## 演示功能概述:
 
-## 演示功能概述
+本文件下共有两个示例demo
 
-AirPHY_1000是合宙设计生产的一款搭载LAN8720Ai芯片的以太网配件板;
+1、http:通过外挂AirPHY_1000小板使用WAN功能或者多网切换模式连接http测试网络连通性。
 
-本demo演示的核心功能为:
-
-Air8101核心板+AirPHY_1000配件板,使用配件板上的以太网口通过网线连接路由器,演示以太网数传功能;
-
-
-## 核心板+配件板资料
-
-[Air8101核心板+配件板相关资料](https://docs.openluat.com/air8101/product/shouce/#air8101_1)
-
-
-## 演示硬件环境
-
-![](https://docs.openluat.com/air8101/product/file/AirPHY_1000/hw_connection.jpg)
-
-![](https://docs.openluat.com/air8101/product/file/AirPHY_1000/hw_connection1.jpg)
-
-1、Air8101核心板
-
-2、AirPHY_1000配件板
-
-3、公对母的杜邦线11根(连接核心板和配件板)
-
-4、网线1根(一端接配件板,一端接路由器)
-
-5、Air8101核心板和AirPHY_1000配件板的硬件接线方式为
-
-- Air8101核心板通过TYPE-C USB口供电(核心板背面的功耗测试开关拨到OFF一端);
-
-- 如果测试发现软件重启,并且日志中出现  poweron reason 0,表示供电不足,此时再通过直流稳压电源对核心板的VIN管脚进行5V供电;
-
-| Air8101核心板 | AirPHY_1000配件板  |
-| ------------ | ------------------ |
-|    59/3V3    |         3.3v       |
-|     gnd      |         gnd        |
-|     5/D2     |         RX1        |
-|    72/D1     |         RX0        |
-|    71/D3     |         CRS        |
-|     4/D0     |         MDIO       |
-|     6/D4     |         TX0        |
-|    74/PCK    |         MDC        |
-|    70/D5     |         TX1        |
-|     7/D6     |         TXEN       |
-|     不接     |          NC        |
-|    69/D7     |         CLK        |
-
-
-## 演示软件环境
-
-1、Luatools下载调试工具
-
-2、[最新版本的内核固件](https://docs.openluat.com/air8101/luatos/firmware/)
-
-
-## 演示操作步骤
-
-1、搭建好演示硬件环境
-
-2、不需要修改demo脚本代码
-
-3、Luatools烧录内核固件和demo脚本代码
-
-4、烧录成功后,自动开机运行
-
-   (1) 配件板上网口水晶头位置处的橙色灯常亮,表示配件板和路由器的连接正常;
-
-   (2) 配件板上网口水晶头位置处的绿色灯常亮或者闪烁,表示配件板和核心板的供电连接正常;
-
-   (3) 观察Luatools的运行日志,如果出现类似于下面的日志,表示软件功能正常:
-
-```lua
-user.http	200	table: 608FD678	{
-   "args": {}, 
-   "headers": {
-      "Accept-Encoding": "gzip", 
-      "Host": "httpbin.air32.cn:80", 
-      "X-Forwarded-Host": "httpbin.air32.cn:80", 
-      "X-Forwarded-Server": "c4a1487bcf14"
-   }, 
-   "origin": "10.0.0.24", 
-   "url": "http://httpbin.air32.cn:80/get"
-}
-```
+2、network_routing:
 
+(1)使用网络路由功能,以太网提供网络供以太网和wifi设备上网