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,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
|
||||
Reference in New Issue
Block a user