Release:5.20灰测

This commit is contained in:
2026-05-21 10:01:28 +08:00
parent 8a5a32b139
commit fd65e9c6a2
68 changed files with 4329 additions and 1489 deletions

View File

@@ -1,159 +1,263 @@
-- linksocket.lua
-- 功能:管理多个 TCP Socket 连接,支持手动连接/断开,自动重连,数据收发
-- 功能:管理多个 TCP Socket
-- 行为:接收到连接命令后尝试连接一次
-- 连接失败 → 主动上报失败 (0x83 03)
-- 连接成功 → 主动上报成功 (0x83 01)
-- 中途掉线 → 主动上报断开 (0x83 02),停止,等待新连接命令
local log = require "log"
local sys = require "sys"
local socket = require "socket"
-- 服务器配置
local SERVER_IP = "129.211.170.245"
local SERVER_PORT = 9002
local sim = require "sim"
-- 云快充
-- local server_config = {
-- ip = "121.43.69.62",
-- port = 8767
-- }
-- 百瑞
local server_config = {
ip = "129.211.170.245",
port = 9002
}
-- 国网
-- local server_config = {
-- ip = "121.199.29.175",
-- port = 1883
-- }
local MAX_CLIENTS = 6
-- 客户端状态表
local clients = {}
local keepConnecting = {}
local connectRequested = {} -- 收到连接命令的标志
local disconnectRequested = {} -- 收到断开命令的标志
local recvCallback = nil
-- 初始化所有socket槽位
for i = 1, MAX_CLIENTS do
clients[i] = {
id = i,
socket = nil,
connected = false
}
keepConnecting[i] = false
clients[i] = { id = i, socket = nil, connected = false }
connectRequested[i] = false
disconnectRequested[i] = false
end
-- 发送连接状态响应
local function sendConnStatus(subCmd, socketId, status)
local uart = require "uart"
local frame = string.char(0x55, 0xAA, 0x83, subCmd, socketId, status, 0xAA, 0x55)
uart.write(1, frame)
log.debug("Socket", socketId, "status response, subCmd=", subCmd, "status=", status)
local uart
local function getUart()
if not uart then uart = require "uart" end
return uart
end
-- 设置是否保持连接
local function setKeepConnecting(id, keep)
if id < 1 or id > MAX_CLIENTS then
return false
end
keepConnecting[id] = keep
if not keep and clients[id].connected and clients[id].socket then
-- 发送状态通知到 STM32
-- subCmd: 0x01=已连接 0x02=已断开 0x03=连接失败
local function sendStatus(subCmd, socketId, status)
local frame = string.char(0x55, 0xAA, 0x83, subCmd, socketId, status or 0, 0xAA, 0x55)
getUart().write(1, frame)
log.info("Socket", socketId,
subCmd == 0x01 and "connected" or
subCmd == 0x02 and "disconnected" or "connect_failed",
"status=", status or 0)
end
-- 关闭单个socket
local function closeSocket(id)
if clients[id].socket then
clients[id].socket:close()
clients[id].socket = nil
clients[id].connected = false
sendConnStatus(0x02, id, 0)
end
clients[id].connected = false
connectRequested[id] = false
disconnectRequested[id] = false
end
-- ── 外部接口 ──────────────────────────────────────────
-- STM32 要求连接
local function connectSocket(id)
if id < 1 or id > MAX_CLIENTS then
log.error("connectSocket: invalid id", id)
return false
end
if clients[id].connected then
log.info("Socket", id, "already connected")
sendStatus(0x01, id, 0)
return true
end
connectRequested[id] = true
disconnectRequested[id] = false
return true
end
-- STM32 要求断开
local function disconnectSocket(id)
if id < 1 or id > MAX_CLIENTS then
log.error("disconnectSocket: invalid id", id)
return false
end
connectRequested[id] = false
disconnectRequested[id] = true
if clients[id].connected then
closeSocket(id)
sendStatus(0x02, id, 0)
end
return true
end
-- 发送数据到指定socket
-- 发送数据
local function sendToSocket(id, data)
if id < 1 or id > MAX_CLIENTS then
log.error("sendToSocket: invalid id", id)
return false
end
if id < 1 or id > MAX_CLIENTS then return false end
if clients[id].connected and clients[id].socket then
clients[id].socket:asyncSend(data)
log.info("Send to socket", id, "len=", #data)
return true
else
log.warn("Socket", id, "not connected, cannot send")
return false
end
return false
end
-- 注册数据接收回调
local function setRecvCallback(cb)
recvCallback = cb
end
-- 为每个socket创建常驻任务
local function setServerAddress(ip, port)
if not ip or #ip == 0 or not port or port <= 0 or port > 65535 then
return false
end
log.info("setServerAddress:", ip, port)
server_config.ip = ip
server_config.port = port
for id = 1, MAX_CLIENTS do
if clients[id].connected then
closeSocket(id)
sendStatus(0x02, id, 0)
end
end
return true
end
local function getLinkStatus()
local status = {}
for i = 1, MAX_CLIENTS do
status[i] = clients[i].connected
end
return status
end
-- ── 每个Socket的控制任务 ─────────────────────────────
for id = 1, MAX_CLIENTS do
sys.taskInit(function()
local socketId = id
log.debug("Socket", socketId, "control task started")
while true do
while not keepConnecting[socketId] do
sys.wait(1000)
-- 等待连接命令
while not connectRequested[socketId] do
sys.wait(500)
end
while keepConnecting[socketId] do
while not socket.isReady() do
if not keepConnecting[socketId] then break end
-- 用 do..break 代替 goto确保失败/断开都回到外层循环顶部
repeat
disconnectRequested[socketId] = false
-- 等待网络就绪且SIM卡正常
while not socket.isReady() or not sim.getStatus() do
if disconnectRequested[socketId] then break end
local simStatus = sim.getStatus()
if not simStatus then
log.warn("Socket", socketId, "waiting for SIM card, status:", simStatus)
end
sys.wait(1000)
end
if not keepConnecting[socketId] then break end
local sock = socket.tcp()
log.debug("Socket", socketId, "connecting to", SERVER_IP, SERVER_PORT)
local connected = false
while not connected and keepConnecting[socketId] do
connected = sock:connect(SERVER_IP, SERVER_PORT)
if not connected then
log.warn("Socket", socketId, "connect failed, retry in 3s")
sys.wait(3000)
end
if disconnectRequested[socketId] then
connectRequested[socketId] = false
break
end
if not keepConnecting[socketId] then
if sock then sock:close() end
-- 再次检查SIM卡状态防止等待期间SIM卡被拔出
if not sim.getStatus() then
connectRequested[socketId] = false
sendStatus(0x03, socketId, 2)
log.warn("Socket", socketId, "connect failed: SIM card not ready")
break
end
-- 尝试连接(只试一次)
local sock = socket.tcp()
log.info("Socket", socketId, "connecting to",
server_config.ip, server_config.port)
local ok = sock:connect(server_config.ip, server_config.port)
if disconnectRequested[socketId] or not ok then
if sock then sock:close() end
connectRequested[socketId] = false
sendStatus(0x03, socketId, 1)
log.warn("Socket", socketId, "connect failed")
break
end
-- 连接成功
clients[socketId].socket = sock
clients[socketId].connected = true
connectRequested[socketId] = false
sendStatus(0x01, socketId, 0)
log.info("Socket", socketId, "connected")
sendConnStatus(0x01, socketId, 0)
while keepConnecting[socketId] and clients[socketId].connected do
local ok = sock:asyncSelect(60, "recv")
if not ok then
-- 监控连接,直到掉线或收到断开命令
while clients[socketId].connected
and not disconnectRequested[socketId] do
-- 检查SIM卡状态如果SIM卡被拔出则断开连接
if not sim.getStatus() then
log.warn("Socket", socketId, "SIM card removed, disconnecting")
break
end
local alive = sock:asyncSelect(60, "recv")
if not alive then
log.warn("Socket", socketId, "connection lost")
break
end
sys.wait(100)
end
until true
if clients[socketId].socket then
clients[socketId].socket:close()
clients[socketId].socket = nil
end
clients[socketId].connected = false
if not keepConnecting[socketId] then
sendConnStatus(0x02, socketId, 0)
break
else
log.info("Socket", socketId, "will reconnect after 3s")
sys.wait(3000)
end
-- 如果还在连接状态说明出了循环 = 掉线或断开
if clients[socketId].connected then
closeSocket(socketId)
sendStatus(0x02, socketId, 0)
log.info("Socket", socketId,
"disconnected, waiting reconnect cmd")
end
end
end)
end
-- 订阅底层Socket接收事件
-- 监听SIM卡状态变化SIM卡被拔出时断开所有连接
sys.subscribe("SIM_IND", function(para)
log.info("SIM_IND received:", para)
-- SIM卡未就绪被拔出或异常
if para ~= "RDY" then
for id = 1, MAX_CLIENTS do
if clients[id].connected then
log.warn("SIM card removed, disconnecting socket", id)
closeSocket(id)
sendStatus(0x02, id, 3) -- 状态码3表示SIM卡异常导致断开
end
end
end
end)
-- 数据接收
sys.subscribe("SOCKET_RECV", function(socketId)
for i, client in ipairs(clients) do
if client.socket and client.socket.id == socketId and client.connected then
local data = client.socket:asyncRecv()
if data and #data > 0 then
log.info("Socket", client.id, "received data len=", #data)
if recvCallback then
recvCallback(client.id, data)
end
if data and #data > 0 and recvCallback then
recvCallback(client.id, data)
end
break
end
end
end)
-- 模块接口
local M = {
setKeepConnecting = setKeepConnecting,
connectSocket = connectSocket,
disconnectSocket = disconnectSocket,
sendToSocket = sendToSocket,
setRecvCallback = setRecvCallback,
setServerAddress = setServerAddress,
getLinkStatus = getLinkStatus,
}
return M
return M