init: Air780EPM 官方 LuatOS 项目代码基线
- 来源: 合宙 LuatOS 官方仓库 air780epm 模块完整代码 - 路径: luatos/air780epm/module/Air780EPM/demo 含官方 demo(含 mqtt/mqtts/socket/uart 等) - 后续: 基于 demo 开发 UART<->MQTT 数据上报功能
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
--[[
|
||||
@module ftp_up_download
|
||||
@summary ftp服务器上传下载文件处理应用功能模块
|
||||
@version 001.000.000
|
||||
@date 2025.07.29
|
||||
@author 马亚丹
|
||||
@usage
|
||||
本文件为ftp服务器上传下载文件处理主应用功能模块,核心业务逻辑为:
|
||||
1. 配置FTP客户端登录服务器的参数和文件路径
|
||||
2. 封装一个重试机制,在登录失败、上传文件失败或者下载文件失败时尝试重新执行操作
|
||||
3. 登录FTP服务器,通过重试机制确保登录成功
|
||||
4. ftp.push上传本地文件到服务器,在本地新建文件并写入内容后上传到服务器指定路径,通过重试机制确保上传成功
|
||||
5. ftp.pull从服务器下载文件,保存在本地指定路径,并读取文件长度,当长度小于指定字节时,读取文件内容,通常是设定512字节,如果文件太大,会消耗ram,通过重试机制确保上传成功
|
||||
6. 主函数循环运行以下流程:登录服务器、用 ftp.command 操作 ftp 服务器目录以及文件上传下载处理后关闭服务器。
|
||||
|
||||
测试服务器为:
|
||||
非ssl加密:
|
||||
local server_ip = "121.43.224.154" -- 服务器IP
|
||||
local server_port = 21 -- 服务器端口号
|
||||
local server_username = "ftp_user" -- 服务器登陆用户名
|
||||
local server_password = "3QujbiMG" -- 服务器登陆密码
|
||||
|
||||
本文件没有对外接口,直接在main.lua中require "ftp_up_download"就可以加载运行
|
||||
]]
|
||||
|
||||
|
||||
|
||||
--1. 统一配置FTP参数和文件路径
|
||||
local config = {
|
||||
server = {
|
||||
ip = "121.43.224.154", -- FTP服务器IP
|
||||
port = 21, -- FTP端口
|
||||
username = "ftp_user", -- 登陆用户名
|
||||
password = "3QujbiMG", -- 登陆密码
|
||||
is_ssl = false, -- 若需SSL,补充证书
|
||||
},
|
||||
download = {
|
||||
remote_file = "/12222.txt", -- 服务器上要下载的文件
|
||||
local_file = "/ftp_download.txt" -- 本地保存的文件名
|
||||
},
|
||||
upload = {
|
||||
local_file = "/ftp_upload.txt", -- 本地要上传的文件(会自动创建)
|
||||
remote_file = "/uploaded_by_luatos.txt" -- 服务器保存的文件名
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
--2.定义功能函数: 重试机制封装,针对易失败操作
|
||||
local function retry_operation(operation, max_retries, interval)
|
||||
local retries = 0
|
||||
while retries < max_retries do
|
||||
local result = operation()
|
||||
if result then return true end
|
||||
retries = retries + 1
|
||||
log.warn("操作失败,重试第", retries, "次")
|
||||
sys.wait(interval)
|
||||
end
|
||||
log.error("超过最大重试次数")
|
||||
return false
|
||||
end
|
||||
|
||||
--3.定义功能函数: 登录FTP服务器(带重试)
|
||||
local function ftp_login()
|
||||
--查看网卡适配器的联网状态是否IP_READY,true表示已经准备好可以联网了,false暂时不可以联网
|
||||
while not socket.adapter(socket.dft()) do
|
||||
log.warn("ftp_login", "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("ftp_login", "recv IP_READY", socket.dft())
|
||||
|
||||
--登录FTP服务器核心函数
|
||||
local function ftp_login_result()
|
||||
local login_result = ftp.login(
|
||||
nil,
|
||||
config.server.ip,
|
||||
config.server.port,
|
||||
config.server.username,
|
||||
config.server.password,
|
||||
config.server.is_ssl
|
||||
).wait()
|
||||
if login_result then
|
||||
log.info("FTP登录成功")
|
||||
return true
|
||||
end
|
||||
log.error("FTP登录失败")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 如果登录失败,最多重试登录3次,间隔3秒,可按需修改
|
||||
return retry_operation(ftp_login_result, 3, 3000)
|
||||
end
|
||||
|
||||
--4.定义功能函数: 上传文件到服务器(带重试)
|
||||
local function ftp_upload_file()
|
||||
-- 确保本地文件创建成功
|
||||
-- 要写入文件的内容,按需求修改
|
||||
local upload_content = "Luatos FTP上传测试数据 "
|
||||
local file, err = io.open(config.upload.local_file, "w")
|
||||
if not file then
|
||||
log.error("创建本地文件失败:", err)
|
||||
return false
|
||||
end
|
||||
--写入内容到文件
|
||||
file:write(upload_content)
|
||||
file:close()
|
||||
|
||||
--打印创建文件的结果
|
||||
log.info("本地文件" .. config.upload.local_file .. "创建成功," .. "并写入文件内容:", upload_content)
|
||||
|
||||
-- 上传文件核心函数
|
||||
local function ftp_upload_result()
|
||||
log.info("开始上传文件:" .. config.upload.local_file)
|
||||
-- ftp.push参数:本地文件路径 → 服务器文件路径
|
||||
local upload_ok = ftp.push(
|
||||
config.upload.local_file,
|
||||
config.upload.remote_file
|
||||
).wait()
|
||||
if upload_ok then
|
||||
log.info("本地文件上传成功,保存在服务器路径:", config.upload.remote_file)
|
||||
return true
|
||||
end
|
||||
log.error("文件上传失败")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 如果上传失败,最多重试上传3次,间隔2秒,可按需修改
|
||||
return retry_operation(ftp_upload_result, 3, 2000)
|
||||
end
|
||||
|
||||
--5.定义功能函数: 下载文件到本地(带重试)
|
||||
local function ftp_download_file()
|
||||
local function ftp_download_result()
|
||||
log.info(" 开始下载文件:" .. config.download.remote_file)
|
||||
-- ftp.pull参数: 本地文件路径→服务器文件路径
|
||||
local download_ok = ftp.pull(
|
||||
config.download.local_file,
|
||||
config.download.remote_file
|
||||
).wait()
|
||||
if not download_ok then
|
||||
log.error("文件下载失败")
|
||||
return false
|
||||
end
|
||||
|
||||
--检查下载结果
|
||||
local file = io.open(config.download.local_file, "r")
|
||||
if not file then
|
||||
log.error("下载文件本地打开失败!重新下载")
|
||||
return false
|
||||
end
|
||||
|
||||
local fsize = io.fileSize(config.download.local_file)
|
||||
if not fsize then
|
||||
log.error("读取文件大小失败,重新下载")
|
||||
file:close()
|
||||
return false
|
||||
end
|
||||
log.info("服务器上文件" .. config.download.remote_file .. "下载成功,保存在本地路径:", config.download.local_file, "大小:", fsize,
|
||||
"字节")
|
||||
|
||||
if fsize and fsize <= 512 then
|
||||
local content = file:read("*a")
|
||||
file:close()
|
||||
log.info("下载文件内容长度小于512字节,内容是:", content)
|
||||
return true
|
||||
end
|
||||
-- 执行完操作后,一定要关掉文件
|
||||
file:close()
|
||||
return true
|
||||
end
|
||||
|
||||
-- 如果下载失败,最多重试10次,间隔2秒,可按需修改
|
||||
return retry_operation(ftp_download_result, 10, 2000)
|
||||
end
|
||||
|
||||
|
||||
--6.定义功能函数: 功能测试主函数
|
||||
local function ftp_main_task()
|
||||
while true do
|
||||
-- 步骤1:登录FTP服务器
|
||||
if not ftp_login() then
|
||||
log.error("登录失败,退出流程")
|
||||
--退出前关闭连接,释放资源
|
||||
ftp.close().wait()
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
-- 执行FTP命令并检查结果
|
||||
log.info("空操作,防止连接断掉", ftp.command("NOOP").wait())
|
||||
log.info("报告远程系统的操作系统类型", ftp.command("SYST").wait())
|
||||
log.info("指定文件类型", ftp.command("TYPE I").wait())
|
||||
log.info("显示当前工作目录名", ftp.command("PWD").wait())
|
||||
log.info("创建一个目录 目录名为QWER", ftp.command("MKD QWER").wait())
|
||||
log.info("改变当前工作目录为QWER", ftp.command("CWD /QWER").wait())
|
||||
log.info("返回上一层目录", ftp.command("CDUP").wait())
|
||||
log.info("获取当前工作目录下的文件名列表", ftp.command("LIST").wait())
|
||||
|
||||
-- 步骤2:上传文件
|
||||
if not ftp_upload_file() then
|
||||
log.error("上传失败,继续执行下载") -- 不中断流程
|
||||
end
|
||||
|
||||
|
||||
-- 步骤3:下载文件
|
||||
if not ftp_download_file() then
|
||||
log.error("下载失败")
|
||||
end
|
||||
|
||||
-- 步骤4:清理操作(可选),清理之前创建的目录
|
||||
log.info("删除测试目录QWER", ftp.command("RMD QWER").wait())
|
||||
|
||||
-- 步骤5:关闭连接
|
||||
local close_result = ftp.close().wait()
|
||||
log.info("FTP连接关闭结果:", close_result)
|
||||
|
||||
--步骤6:获取内存信息
|
||||
local meminfo_result = rtos.meminfo("sys")
|
||||
log.info("meminfo内存信息", rtos.meminfo("sys"))
|
||||
--循环执行,每1分钟执行一次
|
||||
sys.wait(1 * 60 * 1000)
|
||||
end
|
||||
end
|
||||
|
||||
-- 启动主任务
|
||||
sys.taskInit(ftp_main_task)
|
||||
@@ -0,0 +1,72 @@
|
||||
--[[
|
||||
@module main
|
||||
@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
|
||||
@version 001.999.000
|
||||
@date 2025.07.28
|
||||
@author 马亚丹
|
||||
@usage
|
||||
1. 详细逻辑请看ftp_up_download.lua文件
|
||||
2. netdrv_device:配置连接外网使用的网卡,目前支持以下三种选择(三选一)
|
||||
(1) netdrv_4g:4G网卡
|
||||
(2) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
|
||||
(3) netdrv_multiple:支持以上两种网卡,可以配置两种种网卡的优先级
|
||||
]]
|
||||
|
||||
|
||||
--[[
|
||||
必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
|
||||
PROJECT:项目名,ascii string类型
|
||||
可以随便定义,只要不使用,就行
|
||||
VERSION:项目版本号,ascii string类型
|
||||
如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
|
||||
X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
|
||||
因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为999
|
||||
如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
|
||||
]]
|
||||
PROJECT = "ftp_demo"
|
||||
VERSION = "001.999.000"
|
||||
|
||||
|
||||
-- 在日志中打印项目名和项目版本号
|
||||
log.info("main", PROJECT, VERSION)
|
||||
|
||||
|
||||
|
||||
-- 如果内核固件支持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"
|
||||
|
||||
|
||||
--加载ftp_up_download功能模块
|
||||
require "ftp_up_download"
|
||||
|
||||
|
||||
|
||||
|
||||
-- 启动系统调度(必须放在最后)
|
||||
sys.run()
|
||||
@@ -0,0 +1,43 @@
|
||||
--[[
|
||||
@module netdrv_4g
|
||||
@summary “4G网卡”驱动模块
|
||||
@version 1.0
|
||||
@date 2025.07.01
|
||||
@author 马梦阳
|
||||
@usage
|
||||
本文件为4G网卡驱动模块,核心业务逻辑为:
|
||||
1、监听"IP_READY"和"IP_LOSE",在日志中进行打印;
|
||||
|
||||
本文件没有对外接口,直接在其他功能模块中require "netdrv_4g"就可以加载运行;
|
||||
]]
|
||||
|
||||
local function ip_ready_func(ip, adapter)
|
||||
if adapter == socket.LWIP_GP then
|
||||
-- 在位置1和2设置自定义的DNS服务器ip地址:
|
||||
-- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
|
||||
-- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
|
||||
-- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
|
||||
-- 如果使用专网卡,不要使用这两行代码;
|
||||
-- 如果使用国外的网络,不要使用这两行代码;
|
||||
socket.setDNS(adapter, 1, "223.5.5.5")
|
||||
socket.setDNS(adapter, 2, "114.114.114.114")
|
||||
|
||||
log.info("netdrv_4g.ip_ready_func", "IP_READY", socket.localIP(socket.LWIP_GP))
|
||||
end
|
||||
end
|
||||
|
||||
local function ip_lose_func(adapter)
|
||||
if adapter == socket.LWIP_GP then
|
||||
log.warn("netdrv_4g.ip_lose_func", "IP_LOSE")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- 此处订阅"IP_READY"和"IP_LOSE"两种消息
|
||||
-- 在消息的处理函数中,仅仅打印了一些信息,便于实时观察4G网络的连接状态
|
||||
-- 也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
|
||||
sys.subscribe("IP_READY", ip_ready_func)
|
||||
sys.subscribe("IP_LOSE", ip_lose_func)
|
||||
|
||||
-- 在Air780EPM上,内核固件运行起来之后,默认网卡就是socket.LWIP_GP
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
--[[
|
||||
@module netdrv_eth_spi
|
||||
@summary “通过SPI外挂CH390H芯片的以太网卡”驱动模块
|
||||
@version 1.0
|
||||
@date 2025.07.24
|
||||
@author 马梦阳
|
||||
@usage
|
||||
本文件为“通过SPI外挂CH390H芯片的以太网卡”驱动模块,核心业务逻辑为:
|
||||
1、打开CH390H芯片供电开关;
|
||||
2、初始化spi0,初始化以太网卡,并且在以太网卡上开启DHCP(动态主机配置协议);
|
||||
3、以太网卡的连接状态发生变化时,在日志中进行打印;
|
||||
|
||||
直接使用Air780EPM V1.3版本开发板硬件测试即可;
|
||||
|
||||
本文件没有对外接口,直接在其他功能模块中require "netdrv_eth_spi"就可以加载运行;
|
||||
]]
|
||||
|
||||
local exnetif = require "exnetif"
|
||||
|
||||
local function ip_ready_func(ip, adapter)
|
||||
if adapter == socket.LWIP_ETH then
|
||||
-- 在位置1和2设置自定义的DNS服务器ip地址:
|
||||
-- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
|
||||
-- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
|
||||
-- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
|
||||
-- 如果使用专网卡,不要使用这两行代码;
|
||||
-- 如果使用国外的网络,不要使用这两行代码;
|
||||
socket.setDNS(adapter, 1, "223.5.5.5")
|
||||
socket.setDNS(adapter, 2, "114.114.114.114")
|
||||
|
||||
log.info("netdrv_eth_spi.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_spi.ip_lose_func", "IP_LOSE")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- 以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
|
||||
-- 各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
|
||||
-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
|
||||
|
||||
-- 以太网断网后,内核固件会产生一个"IP_LOSE"消息
|
||||
-- 各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
|
||||
-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
|
||||
|
||||
--此处订阅"IP_READY"和"IP_LOSE"两种消息
|
||||
--在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
|
||||
--也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
|
||||
sys.subscribe("IP_READY", ip_ready_func)
|
||||
sys.subscribe("IP_LOSE", ip_lose_func)
|
||||
|
||||
|
||||
local function netdrv_eth_spi_task_func()
|
||||
-- 配置SPI外接以太网芯片CH390H的单网卡,exnetif.set_priority_order使用的网卡编号为socket.LWIP_ETH
|
||||
-- 本demo使用Air780EPM V1.3版本开发板测试,开发板上的硬件配置为:
|
||||
-- GPIO20为CH390H以太网芯片的供电使能控制引脚
|
||||
-- 使用spi0,片选引脚使用GPIO8
|
||||
-- 如果使用的硬件和以上描述的环境不同,根据自己的硬件配置修改以下参数
|
||||
exnetif.set_priority_order({
|
||||
{
|
||||
ETHERNET = {
|
||||
pwrpin = 20,
|
||||
tp = netdrv.CH390,
|
||||
opts = {spi = 0, cs = 8}
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
-- 启动一个task,task的处理函数为netdrv_eth_spi_task_func
|
||||
-- 在处理函数中调用exnetif.set_priority_order设置网卡优先级
|
||||
-- 因为exnetif.set_priority_order要求必须在task中被调用,所以此处启动一个task
|
||||
sys.taskInit(netdrv_eth_spi_task_func)
|
||||
@@ -0,0 +1,88 @@
|
||||
--[[
|
||||
@module netdrv_multiple
|
||||
@summary 多网卡(4G网卡、通过SPI外挂CH390H芯片的以太网卡)驱动模块
|
||||
@version 1.0
|
||||
@date 2025.07.24
|
||||
@author 马梦阳
|
||||
@usage
|
||||
本文件为多网卡驱动模块,核心业务逻辑为:
|
||||
1、调用exnetif.set_priority_order配置多网卡的控制参数以及优先级;
|
||||
|
||||
直接使用Air780EPM V1.3版本开发板硬件测试即可;
|
||||
|
||||
本文件没有对外接口,直接在其他功能模块中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)
|
||||
-- 在位置1和2设置自定义的DNS服务器ip地址:
|
||||
-- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
|
||||
-- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
|
||||
-- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
|
||||
-- 如果使用专网卡,不要使用这两行代码;
|
||||
-- 如果使用国外的网络,不要使用这两行代码;
|
||||
socket.setDNS(adapter, 1, "223.5.5.5")
|
||||
socket.setDNS(adapter, 2, "114.114.114.114")
|
||||
|
||||
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(
|
||||
{
|
||||
-- “通过SPI外挂CH390H芯片”的以太网卡,使用Air780EPM V1.3版本开发板验证
|
||||
{
|
||||
ETHERNET = {
|
||||
-- 供电使能GPIO
|
||||
pwrpin = 20,
|
||||
-- 设置的多个“已经IP READY,但是还没有ping通”网卡,循环执行ping动作的间隔(单位毫秒,可选)
|
||||
-- 如果没有传入此参数,exnetif会使用默认值10秒
|
||||
ping_time = 3000,
|
||||
|
||||
-- 连通性检测ip(选填参数);
|
||||
-- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;
|
||||
-- 如果传入,一定要传入可靠的并且可以ping通的ip地址;
|
||||
-- ping_ip = "填入可靠的并且可以ping通的ip地址",
|
||||
|
||||
-- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
|
||||
tp = netdrv.CH390,
|
||||
opts = {spi=0, cs=8}
|
||||
}
|
||||
},
|
||||
|
||||
-- 4G网卡
|
||||
{
|
||||
LWIP_GP = true
|
||||
}
|
||||
}
|
||||
)
|
||||
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)
|
||||
@@ -0,0 +1,45 @@
|
||||
--[[
|
||||
@module netdrv_pc
|
||||
@summary “pc模拟器网卡”驱动模块
|
||||
@version 1.0
|
||||
@date 2025.07.01
|
||||
@author 朱天华
|
||||
@usage
|
||||
本文件为pc模拟器网卡驱动模块,核心业务逻辑为:
|
||||
1、监听"IP_READY"和"IP_LOSE",在日志中进行打印;
|
||||
|
||||
本文件没有对外接口,直接在其他功能模块中require "netdrv_pc"就可以加载运行;
|
||||
]]
|
||||
|
||||
local function ip_ready_func(ip, adapter)
|
||||
if adapter == socket.ETH0 then
|
||||
-- 在位置1和2设置自定义的DNS服务器ip地址:
|
||||
-- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
|
||||
-- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
|
||||
-- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
|
||||
-- 如果使用专网卡,不要使用这两行代码;
|
||||
-- 如果使用国外的网络,不要使用这两行代码;
|
||||
socket.setDNS(adapter, 1, "223.5.5.5")
|
||||
socket.setDNS(adapter, 2, "114.114.114.114")
|
||||
|
||||
log.info("netdrv_pc.ip_ready_func", "IP_READY", socket.localIP(socket.ETH0))
|
||||
end
|
||||
end
|
||||
|
||||
local function ip_lose_func(adapter)
|
||||
if adapter == socket.ETH0 then
|
||||
log.warn("netdrv_pc.ip_lose_func", "IP_LOSE")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--此处订阅"IP_READY"和"IP_LOSE"两种消息
|
||||
--在消息的处理函数中,仅仅打印了一些信息,便于实时观察pc模拟器网络的连接状态
|
||||
--也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
|
||||
sys.subscribe("IP_READY", ip_ready_func)
|
||||
sys.subscribe("IP_LOSE", ip_lose_func)
|
||||
|
||||
-- 设置默认网卡为socket.ETH0
|
||||
-- pc模拟器上的默认网卡仍然需要使用接口(socket.ETH0)来设置,因为exnetif扩展库当前还不支持模拟器
|
||||
socket.dft(socket.ETH0)
|
||||
@@ -0,0 +1,33 @@
|
||||
--[[
|
||||
@module netdrv_device
|
||||
@summary 网络驱动设备功能模块
|
||||
@version 1.0
|
||||
@date 2025.08.12
|
||||
@author 孟伟
|
||||
@usage
|
||||
本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
|
||||
1、netdrv_4g:socket.LWIP_GP,4G网卡;
|
||||
2、netdrv_wifi:socket.LWIP_STA,WIFI STA网卡;
|
||||
3、netdrv_eth_spi:socket.LWIP_USER1,通过SPI外挂CH390H芯片的以太网卡;
|
||||
4、netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
|
||||
|
||||
根据自己的项目需求,只需要require以上四种中的一种即可;
|
||||
|
||||
|
||||
本文件没有对外接口,直接在main.lua中require "netdrv_device"就可以加载运行;
|
||||
]]
|
||||
|
||||
|
||||
-- 根据自己的项目需求,只需要require以下四种中的一种即可;
|
||||
|
||||
-- 加载“4G网卡”驱动模块
|
||||
require "netdrv_4g"
|
||||
|
||||
-- 加载“WIFI STA网卡”驱动模块
|
||||
-- require "netdrv_wifi"
|
||||
|
||||
-- 加载“通过SPI外挂CH390H芯片的以太网卡”驱动模块
|
||||
-- require "netdrv_eth_spi"
|
||||
|
||||
-- 加载“可以配置优先级的多种网卡”驱动模块
|
||||
-- require "netdrv_multiple"
|
||||
@@ -0,0 +1,151 @@
|
||||
## 功能模块介绍:
|
||||
|
||||
1、main.lua:主程序入口;
|
||||
|
||||
2、netdrv_device.lua:网卡驱动设备,可以配置使用netdrv文件夹内的三种网卡(单4g网卡,单spi以太网卡,多网卡)中的任何一种网卡;
|
||||
|
||||
3、netdrv文件夹:三种网卡,单4g网卡、单spi以太网卡、多网卡,供netdrv_device.lua加载配置;
|
||||
|
||||
4、ftp_up_download.lua:功能演示核心脚本,操作ftp文件、上传和下载文件等,在main.lua中加载运行。
|
||||
|
||||
## 演示功能概述:
|
||||
|
||||
1、 配置FTP客户端登录服务器的参数和文件路径
|
||||
|
||||
2、 封装一个重试机制,在登录失败、上传文件失败或者下载文件失败时尝试重新执行操作
|
||||
|
||||
3、 登录FTP服务器,通过重试机制确保登录成功
|
||||
|
||||
4、 ftp.push上传本地文件到服务器,在本地新建文件并写入内容后上传到服务器指定路径,通过重试机制确保上传成功
|
||||
|
||||
5、 ftp.pull从服务器下载文件,保存在本地指定路径,并读取文件长度,当长度小于指定字节时,读取文件内容,通常是设定512字节,如果文件太大,会消耗ram。
|
||||
|
||||
6、 主函数循环运行以下流程: 登录服务器、用 ftp.command 操作 ftp 服务器目录以及文件上传下载处理后关闭服务器。
|
||||
|
||||
|
||||
|
||||
## 演示硬件环境
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
1、Air780EPM 1.3 版本开发板一块 + 可上网的 sim 卡一张 +4g 天线一根 + 网线一根:
|
||||
|
||||
* sim 卡插入开发板的 sim 卡槽
|
||||
|
||||
* 天线装到开发板上
|
||||
|
||||
* 网线一端插入开发板网口,另外一端连接可以上外网的路由器网口
|
||||
|
||||
2、TYPE-C USB 数据线一根 + USB 转串口数据线一根,Air780EPM 开发板和数据线的硬件接线方式为:
|
||||
|
||||
* Air780EPM 开发板通过 TYPE-C USB 口供电;(外部供电/USB 供电 拨动开关 拨到 USB 供电一端)
|
||||
|
||||
* TYPE-C USB 数据线直接插到开发板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;
|
||||
|
||||
3、Air780EPM 开发板购买链接:https://item.taobao.com/item.htm?id=871567339387&scene=taobao_shop&skuId=5914252858584&spm=a1z10.1-c-s.w4024-24640132990.1.614a1170fDHCdo
|
||||
|
||||
###
|
||||
|
||||
## 演示软件环境
|
||||
|
||||
1、 Luatools下载调试工具
|
||||
|
||||
2、 测试服务器,非 ssl 加密:
|
||||
local server_ip = "121.43.224.154" -- 服务器 IP
|
||||
local server_port = 21 -- 服务器端口号
|
||||
local server_username = "ftp_user" -- 服务器登陆用户名
|
||||
local server_password = "3QujbiMG" -- 服务器登陆密码
|
||||
|
||||
3、 固件版本:LuatOS-SoC_V2014_Air780EPM_1.soc,固件地址,如有最新固件请用最新 [固件版本 - luatos@air780epm - 合宙模组资料中心](https://docs.openluat.com/air780epm/luatos/firmware/version/)](https://docs.openluat.com/air780epm/luatos/firmware/version/)
|
||||
|
||||
4、 脚本文件:
|
||||
main.lua
|
||||
|
||||
ftp_up_download.lua
|
||||
|
||||
netdrv_device.lua
|
||||
|
||||
netdrv文件夹
|
||||
|
||||
5、 pc 系统 win11(win10 及以上)
|
||||
|
||||
|
||||
|
||||
## 演示核心步骤
|
||||
|
||||
1、搭建好硬件环境
|
||||
|
||||
2、demo脚本代码netdrv_device.lua中,按照自己的网卡需求启用对应的Lua文件
|
||||
|
||||
* 如果需要单4G网卡,打开require "netdrv_4g",其余注释掉
|
||||
|
||||
* 如果需要单WIFI STA网卡,打开require "netdrv_wifi",其余注释掉;同时netdrv_wifi.lua中的wlan.connect("茶室-降功耗,找合宙!", "Air123456", 1),前两个参数,修改为自己测试时wifi热点的名称和密码;注意:仅支持2.4G的wifi,不支持5G的wifi
|
||||
|
||||
* 如果需要以太网卡,打开require "netdrv_eth_spi",其余注释掉
|
||||
|
||||
* 如果需要多网卡,打开require "netdrv_multiple",其余注释掉;同时netdrv_multiple.lua中的ssid = "茶室-降功耗,找合宙!", password = "Air123456", 修改为自己测试时wifi热点的名称和密码;注意:仅支持2.4G的wifi,不支持5G的wifi
|
||||
|
||||
3、如果是自己的ftp服务器,脚本代码ftp_up_download.lua中,在config表中按自己的服务器IP,端口号,用户名,密码修改参数。
|
||||
|
||||
4、Luatools烧录内核固件和修改后的demo脚本代码
|
||||
|
||||
5、烧录成功后,代码会自动运行,查看打印日志,如果正常运行,会打印ftp登录成功,空操作和文件目录打印,上传下载文件结果以及关闭FTP连接等信息,如下log显示:
|
||||
|
||||
```
|
||||
[2025-08-26 15:31:08.486][000000005.263] I/user.FTP登录成功
|
||||
[2025-08-26 15:31:08.548][000000005.308] I/user.空操作,防止连接断掉 200 NOOP ok.
|
||||
|
||||
[2025-08-26 15:31:08.579][000000005.355] I/user.报告远程系统的操作系统类型 215 UNIX Type: L8
|
||||
|
||||
[2025-08-26 15:31:08.625][000000005.399] I/user.指定文件类型 200 Switching to Binary mode.
|
||||
|
||||
[2025-08-26 15:31:08.670][000000005.444] I/user.显示当前工作目录名 257 "/"
|
||||
|
||||
[2025-08-26 15:31:08.719][000000005.490] I/user.创建一个目录 目录名为QWER 257 "/QWER" created
|
||||
|
||||
[2025-08-26 15:31:08.765][000000005.535] I/user.改变当前工作目录为QWER 250 Directory successfully changed.
|
||||
|
||||
[2025-08-26 15:31:08.812][000000005.579] I/user.返回上一层目录 250 Directory successfully changed.
|
||||
|
||||
[2025-08-26 15:31:09.013][000000005.782] I/user.获取当前工作目录下的文件名列表
|
||||
[2025-08-26 15:31:09.018][000000005.782] drwx------ 2 ftp ftp 4096 Apr 29 08:43 080307100000002
|
||||
drwx------ 2 ftp ftp 4096 Apr 11 01:22 080307100000003
|
||||
drwx------ 2 ftp ftp 4096 Apr 11 01:22 080307100000004
|
||||
drwx------ 2 ftp ftp 4096 Apr 11 01:22 080307100000005
|
||||
drwx------ 2 ftp ftp 4096 Apr 11 01:23 080307100000006
|
||||
drwx------ 2 ftp ftp 4096 Apr 30 06:16 080307100000022
|
||||
drwx------ 2 ftp ftp 4096 Apr 30 06:16 080307100000023
|
||||
drwx------ 2 ftp ftp 4096 Apr 30 06:16 080307100000024
|
||||
drwx------ 2 ftp ftp 4096 Apr 30 06:16 080307100000025
|
||||
drwx------ 2 ftp ftp 4096 Apr 30 06:16 080307100000026
|
||||
drwx------ 2 ftp ftp 4096 Jul 25 10:40 080307100000027
|
||||
drwx------ 2 ftp ftp 4096 Jul 25 10:04 080307100000028
|
||||
-rw------- 1 ftp ftp 27588 Jun 03 07:04 12222.mp4
|
||||
-rw------- 1 ftp ftp 62 Aug 22 08:32 12222.txt
|
||||
-rw------- 1 ftp ftp 174016 Jun 02 15:43 122224.mp4
|
||||
-rw------- 1 ftp ftp 27588 Jun 02 03:54 1__19700101080014.mp4
|
||||
drwx------ 2 ftp ftp 4096 Apr 19 04:49 23543121001
|
||||
drwx------ 2 ftp ftp 4096 Aug 04 11:46 MT_T
|
||||
drwx------ 2 ftp ftp 4096 Aug 26 07:31 QWER
|
||||
drwx------ 3 ftp ftp 4096 Jul 09 08:02 Test
|
||||
drwx------ 2 ftp ftp 4096 Apr 19 04:45 YKZ
|
||||
-rw------- 1 ftp ftp 1186492 Apr 19 06:12 data.dat
|
||||
-rw------- 1 ftp ftp 189943 Jun 27 07:04 ftp_test.mp4
|
||||
-rw------- 1 ftp ftp 29 Aug 26 07:30 uploaded_by_luatos.txt
|
||||
-rw------- 1 ftp ftp 0 Jun 02 04:00 新建 文本文档.txt
|
||||
|
||||
[2025-08-26 15:31:09.019][000000005.787] I/user.本地文件/ftp_upload.txt创建成功,并写入文件内容: Luatos FTP上传测试数据
|
||||
[2025-08-26 15:31:09.020][000000005.787] I/user.开始上传文件:/ftp_upload.txt
|
||||
[2025-08-26 15:31:09.386][000000006.161] I/user.本地文件上传成功,保存在服务器路径: /uploaded_by_luatos.txt
|
||||
[2025-08-26 15:31:09.495][000000006.261] I/user. 开始下载文件:/12222.txt
|
||||
[2025-08-26 15:31:09.775][000000006.542] I/user.服务器上文件/12222.txt下载成功,保存在本地路径: /ftp_download.txt 大小: 62 字节
|
||||
[2025-08-26 15:31:09.776][000000006.542] I/user.下载文件内容长度小于512字节,内容是: 23noianfdiasfhnpqw39fhawe;fuibnnpw3fheaios;fna;osfhisao;fadsfl
|
||||
[2025-08-26 15:31:09.835][000000006.615] I/user.删除测试目录QWER 250 Remove directory operation successful.
|
||||
|
||||
[2025-08-26 15:31:09.897][000000006.675] I/user.FTP连接关闭结果: 221 Goodbye.
|
||||
|
||||
[2025-08-26 15:31:09.899][000000006.675] I/user.meminfo内存信息 2376072 63544 69796
|
||||
|
||||
```
|
||||
Reference in New Issue
Block a user