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,73 @@
--[[
@module main
@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
@version 001.999.000
@date 2025.10.23
@author 马亚丹
@usage
1. 详细逻辑请看ntp_test.lua文件
2. netdrv_device:配置连接外网使用的网卡,目前支持以下四种选择(四选一)
(1) netdrv_4g4G网卡
(2) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
(3) netdrv_multiple:支持以上两种网卡,可以配置两种网卡的优先级
(4) netdrv_pcpc模拟器上的网卡
]]
--[[
必须定义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 = "ntp_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"
--加载ntp_test功能模块
require "ntp_test"
-- 启动系统调度(必须放在最后)
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,中断引脚使用GPIO22
-- 如果使用的硬件和以上描述的环境不同,根据自己的硬件配置修改以下参数
exnetif.set_priority_order({
{
ETHERNET = {
pwrpin = 20,
tp = netdrv.CH390,
opts = {spi = 0, cs = 8, irq = 22}
}
}
})
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, irq=22}
}
},
-- 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,34 @@
--[[
@module netdrv_device
@summary 网络驱动设备功能模块
@version 1.0
@date 2025.07.24
@author 朱天华
@usage
本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
1、netdrv_4gsocket.LWIP_GP4G网卡;
2、netdrv_eth_spisocket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
3、netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
4、netdrv_pcpc模拟器上的网卡
根据自己的项目需求,只需要require以上四种中的一种即可;
本文件没有对外接口,直接在main.lua中require "netdrv_device"就可以加载运行;
]]
-- 根据自己的项目需求,只需要require以下四种中的一种即可;
-- 加载“4G网卡”驱动模块
require "netdrv_4g"
-- 加载“通过SPI外挂CH390H芯片的以太网卡”驱动模块
-- require "netdrv_eth_spi"
-- 加载“可以配置优先级的多种网卡”驱动模块
-- require "netdrv_multiple"
-- 加载“pc模拟器网卡”驱动模块
-- require "netdrv_pc"
@@ -0,0 +1,148 @@
--[[
@module ntp_test
@summary ntp_test测试功能模块
@version 1.0
@date 2025.10.24
@author 马亚丹
@usage
本demo演示的功能为:使用Air780EPM开发板,演示用ntp网络对时后,获取本地时间和UTC时间的功能
核心逻辑:
1.判断是否联网,
2.网络就绪后开始时间同步
3.时间同步成功,获取本地时间和UTC时间,按默认间隔时间循环打印获取的时间信息
4.时间同步失败,打印提醒
]]
-- 自定义NTP服务器列表,可选配置,默认使用内置的ntp服务器地址ntp.aliyun.com
local ntp_servers = {
"ntp.aliyun.com",
"ntp.ntsc.ac.cn",
"time1.cloud.tencent.com"
}
--本地时间是指:当前时区的时间,默认是东八区北京时间,可以通过rtc.timezone接口查询或者设置时区
--UTC时间是指:0时区的时间
--东八区的时间是在UTC时间的基础上增加8个小时
-- 打印时间信息的工具函数
local function print_time_details()
--设置为东3区时间
--rtc.timezone(12)
--获取东3区的时间字符串
--东3区时间字符串 Fri Oct 24 12:01:20 2025
--log.info("sntp", "东3区时间字符串", os.date())
-- 获取本地时间字符串
-- 本地时间字符串 Fri Oct 24 17:01:15 2025
log.info("sntp", "本地时间字符串", os.date())
-- 获取UTC时间字符串
-- UTC时间字符串 Fri Oct 24 09:01:15 2025
log.info("sntp", "UTC时间字符串", os.date("!%c"))
-- 格式化本地时间字符串
-- 本地时间字符串 2025-10-24 17:01:15
log.info("sntp", "格式化本地时间字符串", os.date("%Y-%m-%d %H:%M:%S"))
-- 格式化UTC时间字符串
-- UTC时间字符串 2025-10-24 09:01:15
log.info("sntp", "格式化UTC时间字符串", os.date("!%Y-%m-%d %H:%M:%S"))
-- RTC时钟原始数据(UTC时间)
local rtc_time = rtc.get()
-- RTC时钟(UTC) {"year":2025,"min":1,"hour":9,"mon":10,"sec":15,"day":24}
log.info("sntp", "RTC时钟(UTC)", json.encode(rtc_time))
-- 本地时间戳(秒级)
--本地时间戳 1761296475
log.info("sntp", "本地时间戳", os.time())
-- 获取本地时间的table
-- 本地时间结构 {"wday":6,"min":1,"yday":297,"hour":17,"isdst":false,"year":2025,"month":10,"sec":15,"day":24}
local local_struct_time = os.date("*t")
log.info("sntp", "本地时间结构", json.encode(local_struct_time))
--结构时间转时间戳 1761325275
log.info("sntp", "结构时间转时间戳", os.time(local_struct_time))
end
-- 打印高精度时间戳
local function print_high_precision_time()
local ntp_time = socket.ntptm()
if ntp_time and ntp_time.tsec then
--tm数据 {"sms":89,"tms":320,"vaild":true,"tsec":1761296475,"lms":231,"ndeley":28,"lsec":18,"ssec":1761296457}
log.info("tm数据", json.encode(ntp_time))
-- 格式化:秒.毫秒
--高精度时间戳 1761296475.320
log.info("sntp", "高精度时间戳", string.format("%u.%03d", ntp_time.tsec, ntp_time.tms))
else
log.warn("sntp", "高精度时间戳获取失败")
end
end
-- SNTP同步主逻辑
local function sntp_sync_loop()
--查看网卡适配器的联网状态是否IP_READY,true表示已经准备好可以联网了,false暂时不可以联网
while not socket.adapter(socket.dft()) do
log.warn("sntp", "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("sntp", "recv IP_READY", socket.dft())
while true do
log.info("sntp", "开始同步:")
-- 方式1:使用自定义服务器列表
-- log.info("sntp", "开始同步,服务器列表:", json.encode(ntp_servers))
-- 选择自己要用的的服务器
--socket.sntp(ntp_servers[2])
-- 方式2: 使用默认的ntp服务器地址:ntp.aliyun.com
socket.sntp()
-- 等待同步结果(成功:NTP_UPDATE,失败:超时)
local sync_success = sys.waitUntil("NTP_UPDATE", 5000)
if sync_success then
--ntp同步成功之后,已经自动将系统时间设置为本地时间
--在此处的脚本中,不需要再调用任何时间设置接口去手动设置时间
--本地时间:默认为东八区北京时间,如果使用rtc.timezone(zone)设置过本地时间,则本地时间为自己设置过的时区对应的时间
-- 同步成功:打印时间信息
log.info("sntp", "时间同步成功")
print_time_details()
print_high_precision_time()
--时间同步成功
--再等待1小时再次发起下次时间同步,这里的等待时长可以按自己的需求修改。
sys.wait(3600*1000)
else
log.warn("sntp", "时间同步失败")
--时间同步失败
--再等待10秒重新发起时间同步,这里的等待时长可以按自己的需求修改。
sys.wait(10*1000)
end
end
end
-- 订阅NTP错误消息
sys.subscribe("NTP_ERROR", function(err_info)
log.error("sntp", "同步过程发生错误", err_info or "未知错误")
end)
-- 启动SNTP同步任务
sys.taskInit(sntp_sync_loop)
@@ -0,0 +1,121 @@
## 功能模块介绍:
1、main.lua:主程序入口;
2、netdrv_device.lua:网卡驱动设备,可以配置使用netdrv文件夹内的四种网卡(单4g网卡,单spi以太网卡,多网卡,pc模拟器上的网卡)中的任何一种网卡;
3、netdrv文件夹:四种网卡,单4g网卡、单spi以太网卡、多网卡、pc模拟器上的网卡,供netdrv_device.lua加载配置;
4、ntp_test.lua: 功能演示核心脚本,联网、时间同步、获取时间等,在main.lua中加载运行。
## 演示功能概述:
1.判断是否联网
2.网络就绪后开始时间同步
3.时间同步成功,获取本地时间和UTC时间,按默认间隔时间循环打印获取的时间信息
4.时间同步失败,打印提醒
## 演示硬件环境
![netdrv_multi](https://docs.openluat.com/accessory/AirSPINORFLASH_1000/image/780EPM.jpg)
1、Air780EPM核心板一块+可上网的 sim 卡一张 + 网线一根:
* sim 卡插入核心板的 sim 卡槽
* 网线一端插入AirETH_1000 配件板网口,AirETH_1000 配件板与核心板按下方表格说明接线,另外一端连接可以上外网的路由器网口
2、TYPE-C USB 数据线一根 + USB 转串口数据线一根,Air780EPM核心板和数据线的硬件接线方式为:
* Air780EPM核心板通过 TYPE-C USB 口供电;(USB的拨码开关off/on,拨到on
* TYPE-C USB 数据线直接插到核心板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;
* 3、可选 AirETH_1000 配件板一块,Air780EPM核心板和 AirETH_1000 配件板的硬件接线方式为:
| Air780EPM核心板 | AirETH_1000 配件板 |
|:------------:|:---------------:|
| 3V3 | 3.3v |
| GND | GND |
| 86/SPI0CLK | SCK |
| 83/SPI0CS | CSS |
| 84/SPI0MISO | SDO |
| 85/SPI0MOSI | SDI |
| 107/GPIO21 | INT |
## 演示软件环境
1、 Luatools下载调试工具
2、 Air780EPM固件版本:LuatOS-SoC_V2016_Air780EPM_1,固件地址,如有最新固件请用最新 [https://docs.openluat.com/air780epm/luatos/firmware/](https://docs.openluat.com/air780epm/luatos/firmware/version/)
3、 脚本文件:
main.lua
ntp_test.lua
netdrv_device.lua
netdrv文件夹
4、 pc 系统 win11win10 及以上)
## 演示核心步骤
1、搭建好硬件环境
2、demo脚本代码netdrv_device.lua中,按照自己的网卡需求启用对应的Lua文件
* 如果需要单4G网卡,打开require "netdrv_4g",其余注释掉
* 如果需要以太网卡,打开require "netdrv_eth_spi",其余注释掉
* 如果需要多网卡,打开require "netdrv_multiple",其余注释掉;
3、如果使用自定义NTP服务器 地址,脚本文件ntp_test.lua中,在ntp_servers表中修改为自己的服务器地址,并在sntp_sync_loop()函数中,注释sntp时间同步方式2,打开方式1
4、Luatools烧录内核固件和修改后的demo脚本代码
5、烧录成功后,代码会自动运行,查看打印日志,如果正常运行,会打印网络就绪、时间同步成功、本地时间以及URC时间等信息,如下log显示:
```
[2025-11-20 15:20:12.188][000000000.206] I/user.main ntp_demo 001.000.000
[2025-11-20 15:20:12.195][000000000.226] W/user.sntp wait IP_READY 1 1
[2025-11-20 15:20:12.540][000000001.226] W/user.sntp wait IP_READY 1 1
[2025-11-20 15:20:13.552][000000002.227] W/user.sntp wait IP_READY 1 1
[2025-11-20 15:20:14.550][000000003.228] W/user.sntp wait IP_READY 1 1
[2025-11-20 15:20:15.550][000000004.228] W/user.sntp wait IP_READY 1 1
[2025-11-20 15:20:16.544][000000005.229] W/user.sntp wait IP_READY 1 1
[2025-11-20 15:20:16.707][000000005.355] D/mobile cid1, state0
[2025-11-20 15:20:16.711][000000005.356] D/mobile bearer act 0, result 0
[2025-11-20 15:20:16.718][000000005.356] D/mobile NETIF_LINK_ON -> IP_READY
[2025-11-20 15:20:16.723][000000005.357] I/user.netdrv_4g.ip_ready_func IP_READY 10.129.19.238 255.255.255.255 0.0.0.0 nil
[2025-11-20 15:20:16.726][000000005.359] I/user.sntp recv IP_READY 1 1
[2025-11-20 15:20:16.739][000000005.359] I/user.sntp 开始同步:
[2025-11-20 15:20:16.743][000000005.359] D/sntp query ntp.aliyun.com
[2025-11-20 15:20:16.748][000000005.360] dns_run 676:ntp.aliyun.com state 0 id 1 ipv6 0 use dns server2, try 0
[2025-11-20 15:20:16.755][000000005.391] D/mobile TIME_SYNC 0
[2025-11-20 15:20:16.757][000000005.392] I/user.sntp 时间同步成功
[2025-11-20 15:20:16.761][000000005.393] I/user.sntp 本地时间字符串 Thu Nov 20 15:20:17 2025
[2025-11-20 15:20:16.765][000000005.394] I/user.sntp UTC时间字符串 Thu Nov 20 07:20:17 2025
[2025-11-20 15:20:16.768][000000005.395] I/user.sntp 格式化本地时间字符串 2025-11-20 15:20:17
[2025-11-20 15:20:16.776][000000005.395] I/user.sntp 格式化UTC时间字符串 2025-11-20 07:20:17
[2025-11-20 15:20:16.780][000000005.396] I/user.sntp RTC时钟(UTC) {"year":2025,"min":20,"hour":7,"mon":11,"sec":17,"day":20}
[2025-11-20 15:20:16.788][000000005.396] I/user.sntp 本地时间戳 1763623217
[2025-11-20 15:20:16.793][000000005.397] I/user.sntp 本地时间结构 {"wday":5,"min":20,"yday":324,"hour":15,"isdst":false,"year":2025,"month":11,"sec":17,"day":20}
[2025-11-20 15:20:16.796][000000005.398] I/user.sntp 结构时间转时间戳 1763652017
[2025-11-20 15:20:16.799][000000005.398] I/user.tm数据 {"sms":0,"tms":398,"tsec":5,"lms":398,"ndeley":0,"lsec":5,"ssec":0}
[2025-11-20 15:20:16.811][000000005.399] I/user.sntp 高精度时间戳 5.398
[2025-11-20 15:20:16.815][000000005.404] dns_run 693:dns all done ,now stop
[2025-11-20 15:20:16.821][000000005.457] D/sntp Unix timestamp: 1763623217
```