2026-04-30 17:16:01 +08:00
|
|
|
|
-- linksocket.lua
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 功能:管理多个 TCP Socket
|
|
|
|
|
|
-- 行为:接收到连接命令后尝试连接一次
|
|
|
|
|
|
-- 连接失败 → 主动上报失败 (0x83 03)
|
|
|
|
|
|
-- 连接成功 → 主动上报成功 (0x83 01)
|
|
|
|
|
|
-- 中途掉线 → 主动上报断开 (0x83 02),停止,等待新连接命令
|
2026-04-30 17:16:01 +08:00
|
|
|
|
|
|
|
|
|
|
local log = require "log"
|
|
|
|
|
|
local sys = require "sys"
|
|
|
|
|
|
local socket = require "socket"
|
2026-05-21 10:01:28 +08:00
|
|
|
|
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
|
|
|
|
|
|
-- }
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-30 17:16:01 +08:00
|
|
|
|
local MAX_CLIENTS = 6
|
|
|
|
|
|
|
2026-03-31 15:46:04 +08:00
|
|
|
|
local clients = {}
|
2026-05-21 10:01:28 +08:00
|
|
|
|
local connectRequested = {} -- 收到连接命令的标志
|
|
|
|
|
|
local disconnectRequested = {} -- 收到断开命令的标志
|
2026-04-30 17:16:01 +08:00
|
|
|
|
local recvCallback = nil
|
2026-03-31 15:46:04 +08:00
|
|
|
|
|
2026-04-30 17:16:01 +08:00
|
|
|
|
for i = 1, MAX_CLIENTS do
|
2026-05-21 10:01:28 +08:00
|
|
|
|
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
|
2026-04-30 17:16:01 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 发送状态通知到 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)
|
2026-04-30 17:16:01 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 关闭单个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)
|
2026-04-30 17:16:01 +08:00
|
|
|
|
if id < 1 or id > MAX_CLIENTS then
|
2026-05-21 10:01:28 +08:00
|
|
|
|
log.error("connectSocket: invalid id", id)
|
2026-04-30 17:16:01 +08:00
|
|
|
|
return false
|
|
|
|
|
|
end
|
2026-05-21 10:01:28 +08:00
|
|
|
|
if clients[id].connected then
|
|
|
|
|
|
log.info("Socket", id, "already connected")
|
|
|
|
|
|
sendStatus(0x01, id, 0)
|
|
|
|
|
|
return true
|
2026-04-30 17:16:01 +08:00
|
|
|
|
end
|
2026-05-21 10:01:28 +08:00
|
|
|
|
connectRequested[id] = true
|
|
|
|
|
|
disconnectRequested[id] = false
|
2026-04-30 17:16:01 +08:00
|
|
|
|
return true
|
|
|
|
|
|
end
|
2026-03-31 15:46:04 +08:00
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- STM32 要求断开
|
|
|
|
|
|
local function disconnectSocket(id)
|
2026-04-30 17:16:01 +08:00
|
|
|
|
if id < 1 or id > MAX_CLIENTS then
|
2026-05-21 10:01:28 +08:00
|
|
|
|
log.error("disconnectSocket: invalid id", id)
|
2026-04-30 17:16:01 +08:00
|
|
|
|
return false
|
|
|
|
|
|
end
|
2026-05-21 10:01:28 +08:00
|
|
|
|
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
|
2026-04-30 17:16:01 +08:00
|
|
|
|
if clients[id].connected and clients[id].socket then
|
|
|
|
|
|
clients[id].socket:asyncSend(data)
|
|
|
|
|
|
return true
|
|
|
|
|
|
end
|
2026-05-21 10:01:28 +08:00
|
|
|
|
return false
|
2026-04-30 17:16:01 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local function setRecvCallback(cb)
|
|
|
|
|
|
recvCallback = cb
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
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的控制任务 ─────────────────────────────
|
2026-04-30 17:16:01 +08:00
|
|
|
|
for id = 1, MAX_CLIENTS do
|
2026-03-31 15:46:04 +08:00
|
|
|
|
sys.taskInit(function()
|
2026-04-30 17:16:01 +08:00
|
|
|
|
local socketId = id
|
2026-03-31 15:46:04 +08:00
|
|
|
|
while true do
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 等待连接命令
|
|
|
|
|
|
while not connectRequested[socketId] do
|
|
|
|
|
|
sys.wait(500)
|
2026-03-31 15:46:04 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 用 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
|
2026-04-30 17:16:01 +08:00
|
|
|
|
sys.wait(1000)
|
|
|
|
|
|
end
|
2026-05-21 10:01:28 +08:00
|
|
|
|
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
|
2026-03-31 15:46:04 +08:00
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 尝试连接(只试一次)
|
2026-04-30 17:16:01 +08:00
|
|
|
|
local sock = socket.tcp()
|
2026-05-21 10:01:28 +08:00
|
|
|
|
log.info("Socket", socketId, "connecting to",
|
|
|
|
|
|
server_config.ip, server_config.port)
|
2026-03-31 15:46:04 +08:00
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
local ok = sock:connect(server_config.ip, server_config.port)
|
|
|
|
|
|
if disconnectRequested[socketId] or not ok then
|
2026-04-30 17:16:01 +08:00
|
|
|
|
if sock then sock:close() end
|
2026-05-21 10:01:28 +08:00
|
|
|
|
connectRequested[socketId] = false
|
|
|
|
|
|
sendStatus(0x03, socketId, 1)
|
|
|
|
|
|
log.warn("Socket", socketId, "connect failed")
|
2026-04-30 17:16:01 +08:00
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 连接成功
|
2026-04-30 17:16:01 +08:00
|
|
|
|
clients[socketId].socket = sock
|
|
|
|
|
|
clients[socketId].connected = true
|
2026-05-21 10:01:28 +08:00
|
|
|
|
connectRequested[socketId] = false
|
|
|
|
|
|
sendStatus(0x01, socketId, 0)
|
2026-04-30 17:16:01 +08:00
|
|
|
|
log.info("Socket", socketId, "connected")
|
|
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 监控连接,直到掉线或收到断开命令
|
|
|
|
|
|
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
|
2026-04-30 17:16:01 +08:00
|
|
|
|
log.warn("Socket", socketId, "connection lost")
|
|
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
sys.wait(100)
|
|
|
|
|
|
end
|
2026-05-21 10:01:28 +08:00
|
|
|
|
until true
|
2026-04-30 17:16:01 +08:00
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 如果还在连接状态说明出了循环 = 掉线或断开
|
|
|
|
|
|
if clients[socketId].connected then
|
|
|
|
|
|
closeSocket(socketId)
|
|
|
|
|
|
sendStatus(0x02, socketId, 0)
|
|
|
|
|
|
log.info("Socket", socketId,
|
|
|
|
|
|
"disconnected, waiting reconnect cmd")
|
2026-04-30 17:16:01 +08:00
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end)
|
2026-03-31 15:46:04 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
2026-05-21 10:01:28 +08:00
|
|
|
|
-- 监听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)
|
|
|
|
|
|
|
|
|
|
|
|
-- 数据接收
|
2026-04-30 17:16:01 +08:00
|
|
|
|
sys.subscribe("SOCKET_RECV", function(socketId)
|
2026-03-31 15:46:04 +08:00
|
|
|
|
for i, client in ipairs(clients) do
|
2026-04-30 17:16:01 +08:00
|
|
|
|
if client.socket and client.socket.id == socketId and client.connected then
|
2026-03-31 15:46:04 +08:00
|
|
|
|
local data = client.socket:asyncRecv()
|
2026-05-21 10:01:28 +08:00
|
|
|
|
if data and #data > 0 and recvCallback then
|
|
|
|
|
|
recvCallback(client.id, data)
|
2026-04-30 17:16:01 +08:00
|
|
|
|
end
|
2026-03-31 15:46:04 +08:00
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end)
|
|
|
|
|
|
|
2026-04-30 17:16:01 +08:00
|
|
|
|
local M = {
|
2026-05-21 10:01:28 +08:00
|
|
|
|
connectSocket = connectSocket,
|
|
|
|
|
|
disconnectSocket = disconnectSocket,
|
2026-04-30 17:16:01 +08:00
|
|
|
|
sendToSocket = sendToSocket,
|
|
|
|
|
|
setRecvCallback = setRecvCallback,
|
2026-05-21 10:01:28 +08:00
|
|
|
|
setServerAddress = setServerAddress,
|
|
|
|
|
|
getLinkStatus = getLinkStatus,
|
2026-04-30 17:16:01 +08:00
|
|
|
|
}
|
2026-05-21 10:01:28 +08:00
|
|
|
|
return M
|