init: Air780EPM 官方 LuatOS 项目代码基线

- 来源: 合宙 LuatOS 官方仓库 air780epm 模块完整代码
- 路径: luatos/air780epm/module/Air780EPM/demo 含官方 demo(含 mqtt/mqtts/socket/uart 等)
- 后续: 基于 demo 开发 UART<->MQTT 数据上报功能
This commit is contained in:
wangfq
2026-08-31 08:53:49 +08:00
commit 173dd6874f
813 changed files with 125484 additions and 0 deletions
@@ -0,0 +1,130 @@
--[[
@module fota
@summary 使用合宙iot平台远程升级功能模块
@version 1.0
@date 2025.09.25
@author 王城钧
@usage
SHT30获取温湿度
]]
--本文件中的主机是指I2C主机,具体指Air780EHV
--本文件中的从机是指I2C从机,具体指AirSHT30_1000配件板上的sht30温湿度传感器芯片
local AirSHT30_1000 =
{
-- i2c_id:主机的i2c id
}
-- 从机地址为0x44
local slave_addr = 0x44
--电平设为3.3v
pm.ioVol(pm.IOVOL_ALL_GPIO, 3300)
--设置gpio2输出,给camera_sda、camera_scl引脚提供上拉
gpio.setup(2, 1)
-- 计算数据表data中所有数据元素的crc8校验值
local function crc8(data)
local crc = 0xFF
for i = 1, #data do
crc = bit.bxor(crc, data[i])
for j = 1, 8 do
crc = crc * 2
if crc >= 0x100 then
crc = bit.band(bit.bxor(crc, 0x31), 0xff)
end
end
end
return crc
end
--打开AirSHT30_1000
--i2c_idnumber类型;
-- 主机使用的I2C ID,用来控制AirSHT30_1000
-- 取值范围:仅支持0和1;
-- 如果没有传入此参数,则默认为0;
--返回值:成功返回true,失败返回false
function AirSHT30_1000.open(i2c_id)
--如果i2c_id为nil,则赋值为默认值0
if i2c_id==nil then i2c_id=0 end
--检查参数的合法性
if not (i2c_id == 0 or i2c_id == 1) then
log.error("AirSHT30_1000.open", "invalid i2c_id", i2c_id)
return false
end
AirSHT30_1000.i2c_id = i2c_id
--初始化I2C
if i2c.setup(i2c_id, i2c.FAST) ~= 1 then
log.error("AirSHT30_1000.open", "i2c.setup error", i2c_id)
return false
end
return true
end
--读取温湿度数据;
--返回值:失败返回false
-- 成功返回两个值,第一个为摄氏温度值(number类型,例如23.6表示23.6摄氏度),第二个为百分比湿度值(number类型,例如67表示67%的湿度)
function AirSHT30_1000.read()
-- 发送启动测量命令(高精度)
i2c.send(AirSHT30_1000.i2c_id, slave_addr, {0x24, 0x00})
-- 等待测量完成(SHT30高精度测量需~15ms)
sys.wait(20)
-- 读取6字节数据(温度高/低 + CRC,湿度高/低 + CRC
local data = i2c.recv(AirSHT30_1000.i2c_id, slave_addr, 6)
-- 如果没有读取到6字节数据
if type(data)~="string" or data:len()~=6 then
log.error("AirSHT30_1000.read", "i2c.recv error")
return false
end
-- log.info("AirSHT30_1000.read", data:toHex())
--如果校验值正确
if crc8({data:byte(1), data:byte(2)}) == data:byte(3) and crc8({data:byte(4), data:byte(5)}) == data:byte(6) then
-- 提取原始温度值
local temp_raw = (data:byte(1) << 8) | data:byte(2)
-- 提取原始湿度值
local hum_raw = (data:byte(4) << 8) | data:byte(5)
-- 转换为实际值(根据SHT30数据手册公式)
local temprature = (-45 + 175 * temp_raw / 65535.0)
local humidity = (100 * hum_raw / 65535.0)
-- 打印输出结果(保留2位小数)
-- log.info("AirSHT30_1000.read", "temprature", string.format("%.2f ℃", temprature))
-- log.info("AirSHT30_1000.read", "temprature", string.format("%.2f %%RH", humidity))
return temprature, humidity
else
log.error("AirSHT30_1000.read", "crc error", i2c_id)
return false
end
end
--关闭AirSHT30_1000
--返回值:成功返回true,失败返回false
function AirSHT30_1000.close()
--close接口没有返回值,理论上不会关闭失败
i2c.close(AirSHT30_1000.i2c_id)
return true
end
return AirSHT30_1000
@@ -0,0 +1,286 @@
--[[
@module excloud_test
@summary excloud测试文件
@version 1.0
@date 2025.09.25
@author 王城钧
@usage
本demo演示的功能为:
演示excloud扩展库的使用。
]]
-- 导入excloud库
local excloud = require("excloud")
--加载AirSHT30_1000驱动文件
local air_sht30 = require "AirSHT30_1000"
--加载lbsLoc2库
local lbsLoc2 = require("lbsLoc2")
-- 注册回调函数
excloud.on(function(event, data)
log.info("用户回调函数", event, json.encode(data))
if event == "connect_result" then
if data.success then
log.info("连接成功")
else
log.info("连接失败: " .. (data.error or "未知错误"))
end
elseif event == "auth_result" then
if data.success then
log.info("认证成功")
else
log.info("认证失败: " .. data.message)
end
elseif event == "message" then
log.info("收到消息, 流水号: " .. data.header.sequence_num)
-- 处理服务器下发的消息
for _, tlv in ipairs(data.tlvs) do
if tlv.field == excloud.FIELD_MEANINGS.CONTROL_COMMAND then
log.info("收到控制命令: " .. tostring(tlv.value))
-- 处理控制命令并发送响应
local response_ok, err_msg = excloud.send({
{
field_meaning = excloud.FIELD_MEANINGS.CONTROL_RESPONSE,
data_type = excloud.DATA_TYPES.ASCII,
value = "命令执行成功"
}
}, false)
if not response_ok then
log.info("发送控制响应失败: " .. err_msg)
end
end
end
elseif event == "disconnect" then
log.warn("与服务器断开连接")
elseif event == "reconnect_failed" then
log.info("重连失败,已尝试 " .. data.count .. "")
elseif event == "send_result" then
if data.success then
log.info("发送成功,流水号: " .. data.sequence_num)
else
log.info("发送失败: " .. data.error_msg)
end
end
end)
local getCellInfo1
local band1
local lat, lng
-- 定期轮训式
sys.taskInit(function()
sys.wait(3000)
while 1 do
mobile.reqCellInfo(15)
sys.waitUntil("CELL_INFO_UPDATE", 30000)
getCellInfo1 = mobile.getCellInfo()
band1 = getCellInfo1[1].band
log.info("驻留频段", band1, json.encode(getCellInfo1))
lat, lng, t = lbsLoc2.request(5000, nil, nil, true) --需要经纬度和当前时间
--(时间格式{"year":2024,"min":56,"month":11,"day":12,"sec":44,"hour":14})
log.info("lbsLoc2", lat, lng, (json.encode(t or {}))) --打印经纬度和时间
sys.wait(60000)
end
end)
local temprature, humidity
sys.taskInit(function()
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
while not socket.adapter(socket.dft()) do
log.warn("tcp_client_main_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
sys.wait(1000)
-- 配置excloud参数
local ok, err_msg = excloud.setup({
-- device_id = "862419074073247", -- 设备ID (IMEI前14位)
device_type = 1, -- 设备类型: 4G
host = "124.71.128.165", -- 服务器地址
port = 9108, -- 服务器端口
auth_key = "SIsRml1ImTsP6XR4lvRAQVuksbZZuUpO", -- 鉴权密钥
transport = "tcp", -- 使用TCP传输
auto_reconnect = true, -- 自动重连
reconnect_interval = 10, -- 重连间隔(秒)
max_reconnect = 5, -- 最大重连次数
timeout = 30, -- 超时时间(秒)
})
-- 配置MQTT连接参数
-- local ok, err_msg = excloud.setup({
-- device_type = 1, -- 设备类型: 4G设备
-- transport = "mqtt", -- 使用MQTT传输协议
-- host = "airtest.openluat.com", -- MQTT服务器地址
-- port = 1883, -- MQTT服务器端口
-- auth_key = "VmhtOb81EgZau6YyuuZJzwF6oUNGCbXi", -- 鉴权密钥(请替换为实际密钥)
-- username = "root", -- MQTT用户名(可选)
-- password = "Luat123456", -- MQTT密码(可选)
-- keepalive = 300, -- 心跳间隔(秒)
-- -- auto_reconnect = true, -- 自动重连
-- reconnect_interval = 10, -- 重连间隔(秒)
-- max_reconnect = 5, -- 最大重连次数
-- timeout = 30, -- 超时时间(秒)
-- qos = 1, -- MQTT QoS等级(0/1/2)
-- -- retain = false, -- MQTT retain标志
-- -- clean_session = true, -- MQTT clean session
-- ssl = false -- 不使用SSL
-- })
if not ok then
log.info("初始化失败: " .. err_msg)
return
end
log.info("excloud初始化成功")
-- 开启excloud服务
local ok, err_msg = excloud.open()
if not ok then
log.info("开启excloud服务失败: " .. err_msg)
return
end
log.info("excloud服务已开启")
-- 在主循环中定期上报数据
while true do
-- 每60秒上报一次数据
sys.wait(60000)
-- 检查连接状态
-- local status = excloud.status()
-- if not status.is_connected or not status.is_authenticated then
-- log.info("设备未连接或未认证,跳过数据上报")
-- else
-- 获取信号强度
local rssi = mobile.csq()
log.info("信号强度", rssi)
-- 获取sim卡的iccid
local iccid = mobile.iccid()
log.info("iccid", iccid)
-- 获取驻留频段
local buff = zbuff.create(40)
-- 获取驻留小区
local cell_info = mobile.scell()
local cell_id = cell_info.cid
log.info("小区ID", cell_id)
-- 获取环境温度
--打开sht30硬件
air_sht30.open(1)
--读取温湿度数据
temprature, humidity = air_sht30.read()
log.info("温度", temprature, humidity)
-- 获取cpu温度
adc.open(adc.CH_CPU) --打开adc.CH_CPU通道
local data5 = adc.get(adc.CH_CPU) --获取adc.CH_CPU计算值,将获取到的值赋给data5
-- adc.close(adc.CH_CPU)--关闭adc.CH_CPU通道
log.info("CPU温度", data5)
if not lat then
lat = 0
end
if not lng then
lng = 0
end
if not rssi then
rssi = 0
end
if not cell_id then
cell_id = 0
end
if not temprature then
temprature = 0
end
if not humidity then
humidity = 0
end
if not band1 then
band1 = 0
end
if not iccid then
iccid = ""
end
if not data5 then
data5 = 0
end
local ok, err_msg = excloud.send({
{
--信号强度
field_meaning = excloud.FIELD_MEANINGS.SIGNAL_STRENGTH_4G,
data_type = excloud.DATA_TYPES.INTEGER,
value = rssi -- 信号强度
},
{
--iccid
field_meaning = excloud.FIELD_MEANINGS.SIM_ICCID,
data_type = excloud.DATA_TYPES.ASCII,
value = iccid -- sim卡iccid
},
{
--驻留频段
field_meaning = excloud.FIELD_MEANINGS.SERVING_CELL,
data_type = excloud.DATA_TYPES.INTEGER,
value = band1 -- 驻留频段
},
{
--驻留小区
field_meaning = excloud.FIELD_MEANINGS.CELL_INFO,
data_type = excloud.DATA_TYPES.INTEGER,
value = cell_id -- 驻留小区
},
{
--环境温度
field_meaning = excloud.FIELD_MEANINGS.TEMPERATURE,
data_type = excloud.DATA_TYPES.FLOAT,
value = temprature -- 环境温度
},
{
--环境湿度
field_meaning = excloud.FIELD_MEANINGS.HUMIDITY,
data_type = excloud.DATA_TYPES.FLOAT,
value = humidity -- 环境湿度
},
{
--cpu温度
field_meaning = excloud.FIELD_MEANINGS.ENV_TEMPERATURE,
data_type = excloud.DATA_TYPES.INTEGER,
value = data5 -- cpu温度
},
{
--经度
field_meaning = excloud.FIELD_MEANINGS.GNSS_LONGITUDE,
data_type = excloud.DATA_TYPES.ASCII,
value = lng
},
{
--纬度
field_meaning = excloud.FIELD_MEANINGS.GNSS_LATITUDE,
data_type = excloud.DATA_TYPES.ASCII,
value = lat
}
}, false) -- 不需要服务器回复
if not ok then
log.info("发送数据失败: " .. err_msg)
else
log.info("数据发送成功")
end
-- end
end
end)
@@ -0,0 +1,29 @@
--[[
@module fota
@summary 使用合宙iot平台远程升级功能模块
@version 1.0
@date 2025.09.25
@author 王城钧
@usage
实现远程升级功能
]]
-- 使用合宙iot平台时需要这个参数
PRODUCT_KEY = "SIsRml1ImTsP6XR4lvRAQVuksbZZuUpO" -- 到 iot.openluat.com 创建项目,获取正确的项目id
--加在libfota2扩展库
libfota2 = require "libfota2"
local function fota_cb(ret)
log.info("fota", ret)
-- fota结束,无论成功还是失败,都释放fota_running标志
if ret == 0 then
log.info("升级包下载成功,重启模块")
rtos.reboot()
end
end
local opts = {}
libfota2.request(fota_cb, opts)
sys.timerLoopStart(libfota2.request, 4 * 3600000, fota_cb, opts)
@@ -0,0 +1,65 @@
--[[
@module main
@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
@version 1.0
@date 2025.09.25
@author 王城钧
@usage
本demo演示的功能为:
演示excloud扩展库的使用。
]]
--[[
必须定义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 = "excloud_test"
VERSION = "001.999.000"
-- 如果内核固件支持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)
-- 加载fota升级功能模块
require "fota"
-- 加载网络驱动设备功能模块
require "netdrv_device"
-- 加载excloud测试模块
require "excloud_test"
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- 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
-- 启动一个tasktask的处理函数为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_typestring类型,表示当前使用的网卡字符串
-- adapternumber类型,表示当前使用的网卡id
-- 当所有网卡断网时:
-- net_type:为nil
-- adapternumber类型,为-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网络应用通信异常时自动对当前使用的网卡进行连通性检测。
-- 启动一个tasktask的处理函数为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,85 @@
--[[
@module netdrv_wifi
@summary “WIFI STA网卡”驱动模块
@version 1.0
@date 2025.07.01
@author 马梦阳
@usage
本文件为WIFI STA网卡驱动模块,核心业务逻辑为:
1、初始化WIFI网络;
2、连接WIFI路由器;
3、和WIFI路由器之间的连接状态发生变化时,在日志中进行打印;
本文件没有对外接口,直接在其他功能模块中require "netdrv_wifi"就可以加载运行;
]]
local exnetif = require "exnetif"
local function ip_ready_func(ip, adapter)
if adapter == socket.LWIP_STA 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_wifi.ip_ready_func", "IP_READY", socket.localIP(socket.LWIP_STA))
end
end
local function ip_lose_func(adapter)
if adapter == socket.LWIP_STA then
log.warn("netdrv_wifi.ip_lose_func", "IP_LOSE")
end
end
--WIFI联网成功(做为STATION成功连接AP,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
--各个功能模块可以订阅"IP_READY"消息实时处理WIFI联网成功的事件
--也可以在任何时刻调用socket.adapter(socket.LWIP_STA)来获取WIFI网络是否连接成功
--WIFI断网后,内核固件会产生一个"IP_LOSE"消息
--各个功能模块可以订阅"IP_LOSE"消息实时处理WIFI断网的事件
--也可以在任何时刻调用socket.adapter(socket.LWIP_STA)来获取WIFI网络是否连接成功
--此处订阅"IP_READY"和"IP_LOSE"两种消息
--在消息的处理函数中,仅仅打印了一些信息,便于实时观察WIFI的连接状态
--也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
sys.subscribe("IP_READY", ip_ready_func)
sys.subscribe("IP_LOSE", ip_lose_func)
local function wifi_sta_func(evt, data)
-- evt 可能的值有: "CONNECTED", "DISCONNECTED"
-- 当evt=CONNECTED, data是连接的AP的ssid, 字符串类型
-- 当evt=DISCONNECTED, data断开的原因, 整数类型
log.info("收到STA事件", evt, data)
end
-- wifi的STA相关事件
sys.subscribe("WLAN_STA_INC", wifi_sta_func)
local function netdrv_wifi_task_func()
-- 配置WiFi设备模式的单网卡,exnetif.set_priority_order使用的网卡编号为socket.LWIP_STA
-- ssid为要连接的WiFi路由器名称;
-- password为要连接的WiFi路由器密码;
-- 注意:仅支持2.4G的WiFi,不支持5G的WiFi
-- 实际测试时,根据自己要连接的WiFi热点信息修改以下参数
exnetif.set_priority_order({
{
WIFI = {
ssid = "茶室-降功耗,找合宙!",
password = "Air123456"
}
}
})
end
-- 启动一个tasktask的处理函数为netdrv_wifi_task_func
-- 在处理函数中调用exnetif.set_priority_order设置网卡优先级
-- 因为exnetif.set_priority_order要求必须在task中被调用,所以此处启动一个task
sys.taskInit(netdrv_wifi_task_func)
@@ -0,0 +1,33 @@
--[[
@module netdrv_device
@summary 网络驱动设备功能模块
@version 1.0
@date 2025.07.24
@author 朱天华
@usage
本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
1、netdrv_4gsocket.LWIP_GP4G网卡;
2、netdrv_wifisocket.LWIP_STAWIFI STA网卡;
3、netdrv_eth_spisocket.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"