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,127 @@
--[[
@module tcp_server_main
@summary tcp server主应用功能模块
@version 1.0
@date 2025.11.15
@author 王世豪
@usage
本文件为tcp server主应用功能模块,核心业务逻辑为:
1、创建一个tcp server ,等待client连接;
2、处理连接异常,出现异常后,关闭当前连接,等待下一个client连接;
3、调用tcp_server_receiver和tcp_server_sender中的外部接口,进行数据收发处理;
本文件没有对外接口,直接在main.lua中require "tcp_server_main"就可以加载运行;
]]
local libnet = require "libnet"
-- 加载TCP服务器数据接收功能模块
local tcp_server_receiver = require "tcp_server_receiver"
-- 加载TCP服务器数据发送功能模块
local tcp_server_sender = require "tcp_server_sender"
-- tcp_server_main的任务名
local TASK_NAME = tcp_server_sender.TASK_NAME
-- 处理未识别的消息
local function tcp_server_main_cbfunc(msg)
log.info("tcp_server_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
end
-- tcp server socket的任务处理函数
local function tcp_server_main_task_func()
local netc = nil
local result, param
local listen_port = 50003 -- tcp server监听的端口号
while true do
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
while not socket.adapter(socket.dft()) do
log.warn("tcp_server_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
-- 检测到了IP_READY消息
log.info("tcp_server_main_task_func", "recv IP_READY", socket.dft())
netc = socket.create(socket.dft(), TASK_NAME)
if not netc then
log.error("tcp_server_task_func", "socket.create失败")
goto EXCEPTION_PROC
end
socket.debug(netc, true)
-- 配置socker server 对象为tcp server
result = socket.config(netc, listen_port, nil, nil, 300, 10, 3)
-- 如果配置失败
if not result then
log.error("tcp_server_task_func", "socket.config失败")
goto EXCEPTION_PROC
end
-- 监听tcp server端口
result = libnet.listen(TASK_NAME, 0, netc)
-- 如果监听失败
if not result then
log.error("tcp_server_task_func", "监听失败")
goto EXCEPTION_PROC
end
-- 客户端连上了, 发一条数据给客户端
libnet.tx(TASK_NAME, 0, netc, "TCP server is UP!")
-- 数据收发以及网络连接异常事件总处理逻辑
while true do
-- 数据接收处理
if not tcp_server_receiver.proc(netc) then
log.info("tcp_server_task_func", "tcp_server_receiver.proc error")
break
end
-- 数据发送处理
if not tcp_server_sender.proc(TASK_NAME, netc) then
log.info("tcp_server_task_func", "tcp_server_sender.proc error")
break
end
-- 阻塞等待socket.EVENT事件或者15秒钟超时
result, param = libnet.wait(TASK_NAME, 15000, netc)
log.info("tcp_server_task_func", "wait result", result, param)
-- 如果连接异常,则退出循环
if not result then
log.info("tcp_server_task_func", "客户端断开")
break
end
end
-- 出现异常
::EXCEPTION_PROC::
-- 数据发送应用模块对来不及发送的数据做清空和通知失败处理
tcp_server_sender.exception_proc()
-- 如果存在socket server对象
if netc then
-- 关闭socket server连接
libnet.close(TASK_NAME, 5000, netc)
-- 释放socket server对象
socket.release(netc)
netc = nil
end
-- 等待5秒后,再次尝试创建新的连接
sys.wait(5000)
end
end
--创建并且启动一个task
--运行这个task的主函数tcp_server_main_task_func
sys.taskInitEx(tcp_server_main_task_func, TASK_NAME, tcp_server_main_cbfunc)
@@ -0,0 +1,87 @@
--[[
@module tcp_server_receiver
@summary tcp server socket数据接收应用功能模块
@version 1.0
@date 2025.11.15
@author 王世豪
@usage
本文件为tcp server 数据接收应用功能模块,核心业务逻辑为:
从内核读取接收到的数据,然后将数据发送给其他应用功能模块做进一步处理;
本文件的对外接口有2个:
1、tcp_server_receiver.proc(netc):数据接收应用逻辑处理入口,在tcp_server_main.lua中调用;
2、sys.publish("RECV_DATA_FROM_CLIENT", data)
将接收到的数据通过消息"RECV_DATA_FROM_CLIENT"发布出去;
需要处理数据的应用功能模块订阅处理此消息即可,本demo项目中uart_app.lua中订阅处理了本消息;
]]
local tcp_server_receiver = {}
-- socket数据接收缓冲区
local recv_buff = nil
--[[
检查socket server是否收到数据,如果收到数据,读取并且处理完所有数据
@api tcp_server_receiver.proc(netc)
@param1 netc userdata
表示由socket.create接口创建的socket server对象;
必须传入,不允许为空或者nil
@return1 result bool
表示处理结果,成功为true,失败为false
@usage
-- 示例:处理tcp server接收数据
tcp_server_receiver.proc(netc)
]]
function tcp_server_receiver.proc(netc)
-- 如果socket数据接收缓冲区还没有申请过空间,则先申请内存空间
if recv_buff==nil then
recv_buff = zbuff.create(1024)
-- 当recv_buff不再使用时,不需要主动调用recv_buff:free()去释放
-- 因为Lua的垃圾处理器会自动释放recv_buff所申请的内存空间
-- 如果等不及垃圾处理器自动处理,在确定以后不会再使用recv_buff时,则可以主动调用recv_buff:free()释放内存空间
end
-- 循环从内核的缓冲区读取接收到的数据
-- 如果读取失败,返回false,退出循环
-- 如果读取成功,处理数据,并且继续循环读取
-- 如果读取成功,并且读出来的数据为空,表示已经没有数据可读,返回true,退出循环
while true do
-- 从内核的缓冲区中读取数据到recv_buff中
local succ, param = socket.rx(netc, recv_buff)
-- 读取数据失败
-- 有两种情况:
-- 1、recv_buff扩容失败
-- 2、socket server和client之间的连接断开
if not succ then
log.info("tcp_server_receiver.proc", "socket.rx error", param)
return false
end
-- 如果读取到了数据, used()就必然大于0, 进行处理
if recv_buff:used() > 0 then
log.info("tcp_server_receiver.proc", "recv data len", recv_buff:used())
-- 读取socket数据接收缓冲区中的数据,赋值给data
local data = recv_buff:query()
log.info("tcp_server_receiver.proc", "recv data", data)
-- 将数据通过"RECV_DATA_FROM_CLIENT"消息publish出去,给其他应用模块处理
sys.publish("RECV_DATA_FROM_CLIENT", data)
-- 清空socket数据接收缓冲区中的数据
recv_buff:del()
else
-- 读取成功,但是读出来的数据为空,表示已经没有数据可读,可以退出循环了
break
end
end
return true
end
return tcp_server_receiver
@@ -0,0 +1,135 @@
--[[
@module tcp_server_sender
@summary tcp server socket数据发送应用功能模块
@version 1.0
@date 2025.11.15
@author 王世豪
@usage
本文件为tcp server socket数据发送应用功能模块,核心业务逻辑为:
1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
2、tcp_server_main主任务调用tcp_server_sender.proc接口,遍历队列send_queue,逐条发送数据到server
3、tcp server socket和server之间的连接如果出现异常,tcp_server_main主任务调用tcp_server_sender.exception_proc接口,丢弃掉队列send_queue中未发送的数据;
4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
本文件的对外接口有3个:
1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
2、tcp_server_sender.proc:数据发送应用逻辑处理入口,在tcp_server_main.lua中调用;
3、tcp_server_sender.exception_proc:数据发送应用逻辑异常处理入口,在tcp_server_main.lua中调用;
]]
local tcp_server_sender = {}
local libnet = require "libnet"
--[[
数据发送队列,数据结构为:
{
[1] = {data="data1", cb={func=callback_function1, para=callback_para1}},
[2] = {data="data2", cb={func=callback_function2, para=callback_para2}},
}
data的内容为真正要发送的数据,必须存在;
func的内容为数据发送结果的用户回调函数,可以不存在
para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
]]
local send_queue = {}
-- tcp_server_main的任务名
tcp_server_sender.TASK_NAME = "tcp_server_main"
-- "SEND_DATA_REQ"消息的处理函数
local function send_data_req_proc_func(tag, data, cb)
-- 将原始数据增加前缀,然后插入到发送队列send_queue中
table.insert(send_queue, {data="send from "..tag..": "..data, cb=cb})
-- 通知tcp_server_main主任务有数据需要发送
-- tcp_server_main主任务如果处在libnet.wait调用的阻塞等待状态,就会退出阻塞状态
sys.sendMsg(tcp_server_sender.TASK_NAME, socket.EVENT, 0)
end
--[[
检查socket server是否需要发送数据,如果需要发送数据,读取并且发送完发送队列中的所有数据
@api tcp_server_sender.proc(task_name, socket_server)
@param1 task_name string
表示socket.create接口创建socket server对象时所处的task的name
必须传入,不允许为空或者nil
@param2 socket_server userdata
表示由socket.create接口创建的socket server对象;
必须传入,不允许为空或者nil
@return1 result bool
表示处理结果,成功为true,失败为false
@usage
tcp_server_sender.proc("tcp_server_main", socket_server)
]]
function tcp_server_sender.proc(task_name, netc)
local send_item
local result, buff_full
-- 遍历数据发送队列send_queue
while #send_queue>0 do
-- 取出来第一条数据赋值给send_item
-- 同时从队列send_queue中删除这一条数据
send_item = table.remove(send_queue,1)
-- 发送这条数据,超时时间15秒钟
result, buff_full = libnet.tx(task_name, 15000, netc, send_item.data)
-- 检查发送结果
if not result then
log.error("tcp_server_sender.proc", "libnet.tx error")
-- 如果当前发送的数据有用户回调函数,则执行用户回调函数
if send_item.cb and send_item.cb.func then
send_item.cb.func(false, send_item.cb.para)
end
return false
end
-- 如果内核固件中缓冲区满了,则将send_item再次插入到send_queue的队首位置,等待下次尝试发送
if buff_full then
log.error("tcp_client_sender.proc", "buffer is full, wait for the next time")
table.insert(send_queue, 1, send_item)
return true
end
log.info("tcp_server_sender.proc", "send success")
-- 发送成功,如果当前发送的数据有用户回调函数,则执行用户回调函数
if send_item.cb and send_item.cb.func then
send_item.cb.func(true, send_item.cb.para)
end
end
return true
end
--[[
socket server连接出现异常时,清空等待发送的数据,并且执行发送方的回调函数
@api tcp_server_sender.exception_proc()
@usage
tcp_server_sender.exception_proc()
]]
function tcp_server_sender.exception_proc()
-- 遍历数据发送队列send_queue
while #send_queue>0 do
local send_item = table.remove(send_queue,1)
-- 发送失败,如果当前发送的数据有用户回调函数,则执行用户回调函数
if send_item.cb and send_item.cb.func then
send_item.cb.func(false, send_item.cb.para)
end
end
end
-- 订阅"SEND_DATA_REQ"消息;
-- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
-- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
return tcp_server_sender