Files
BR_YKC/4G/源代码/core/linksocket.lua
2026-05-21 13:24:05 +08:00

264 lines
8.2 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- linksocket.lua
-- 功能:管理多个 TCP Socket
-- 行为:接收到连接命令后尝试连接一次
-- 连接失败 → 主动上报失败 (0x83 03)
-- 连接成功 → 主动上报成功 (0x83 01)
-- 中途掉线 → 主动上报断开 (0x83 02),停止,等待新连接命令
local log = require "log"
local sys = require "sys"
local socket = require "socket"
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 connectRequested = {} -- 收到连接命令的标志
local disconnectRequested = {} -- 收到断开命令的标志
local recvCallback = nil
for i = 1, MAX_CLIENTS do
clients[i] = { id = i, socket = nil, connected = false }
connectRequested[i] = false
disconnectRequested[i] = false
end
local uart
local function getUart()
if not uart then uart = require "uart" end
return uart
end
-- 发送状态通知到 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
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
-- 发送数据
local function sendToSocket(id, data)
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)
return true
end
return false
end
local function setRecvCallback(cb)
recvCallback = cb
end
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
while true do
-- 等待连接命令
while not connectRequested[socketId] do
sys.wait(500)
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 disconnectRequested[socketId] then
connectRequested[socketId] = false
break
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")
-- 监控连接,直到掉线或收到断开命令
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].connected then
closeSocket(socketId)
sendStatus(0x02, socketId, 0)
log.info("Socket", socketId,
"disconnected, waiting reconnect cmd")
end
end
end)
end
-- 监听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 and recvCallback then
recvCallback(client.id, data)
end
break
end
end
end)
local M = {
connectSocket = connectSocket,
disconnectSocket = disconnectSocket,
sendToSocket = sendToSocket,
setRecvCallback = setRecvCallback,
setServerAddress = setServerAddress,
getLinkStatus = getLinkStatus,
}
return M