GrabBag/App/BeltTearing/BeltTearingServer/TearingTcpProtocol.h

258 lines
7.5 KiB
C
Raw Normal View History

2026-03-28 10:49:55 +08:00
#ifndef TEARINGTCPPROTOCOL_H
#define TEARINGTCPPROTOCOL_H
#include <QObject>
#include <QJsonObject>
#include <QJsonDocument>
#include <QByteArray>
#include <QBuffer>
#include <QImage>
#include <QDateTime>
#include <QTimer>
#include <QMap>
#include <functional>
#include "IYTCPServer.h"
#include "beltTearingDetection_Export.h"
// 帧格式定义
#define FRAME_HEADER "##START#" // 8字节帧头
#define FRAME_TAIL "#END" // 4字节帧尾
#define FRAME_HEADER_SIZE 8
#define FRAME_TAIL_SIZE 4
#define FRAME_LENGTH_SIZE 8
/**
* @brief 消息类型枚举
*/
enum class TcpMessageType
{
DETECT_RESULT, // 撕裂检测结果上报
REALTIME_RESULT, // 实时检测结果上报
SET_SPEED, // 设置速度命令
SET_CONTROL, // 启停控制命令
SET_REALTIME, // 实时传输控制命令
CMD_RESPONSE, // 命令应答
HEARTBEAT, // 心跳消息
HEARTBEAT_ACK, // 心跳应答
UNKNOWN // 未知消息类型
};
/**
* @brief 速度设置回调
* @param speed 速度值(mm/s)
* @return 错误码,0表示成功,非0表示失败
*/
using SpeedCallback = std::function<int(int speed)>;
/**
* @brief 控制命令回调
* @param control true-启动,false-停止
* @return 错误码,0表示成功,非0表示失败
*/
using ControlCallback = std::function<int(bool control)>;
/**
* @brief 撕裂TCP通信协议类
* 实现皮带撕裂检测系统的TCP通信协议
* 协议文档:撕裂TCP通信协议.md
*/
class TearingTcpProtocol : public QObject
{
Q_OBJECT
public:
explicit TearingTcpProtocol(QObject *parent = nullptr);
~TearingTcpProtocol();
/**
* @brief 启动协议处理
* @param heartbeatInterval 心跳间隔(秒),默认30秒
*/
void start(int heartbeatInterval = 30);
/**
* @brief 停止协议处理
*/
void stop();
/**
* @brief 发送撕裂检测结果
* @param results 检测结果数组
* @param visImage 可视化图像
* @note 发送的JSON消息包含:count(撕裂个数)、max(最大撕裂长度)、maxId(最大撕裂ID)、visimg(Base64图像)
*/
void sendDetectResult(const std::vector<SSG_beltTearingInfo>& results, const QImage& visImage);
/**
* @brief 发送实时检测结果
* @param results 检测结果数组
* @param visImage 可视化图像
* @note 发送的JSON消息包含:count(撕裂个数)、tears(撕裂详细数据数组)、visimg(Base64图像)
* @note 只发送给开启了实时传输的客户端
*/
void sendRealtimeResult(const std::vector<SSG_beltTearingInfo>& results, const QImage& visImage);
/**
* @brief 处理接收到的数据
* @param pClient 客户端指针
* @param pData 数据指针
* @param nLen 数据长度
*/
void handleReceivedData(const TCPClient* pClient, const char* pData, unsigned int nLen);
/**
* @brief 设置速度设置回调
*/
void setSpeedCallback(const SpeedCallback& callback);
/**
* @brief 设置控制命令回调
*/
void setControlCallback(const ControlCallback& callback);
/**
* @brief 设置TCP端口
* @param port TCP端口
*/
void setTcpPort(quint16 port);
/**
* @brief 清除历史最大撕裂数据(开流时调用)
*/
void clearHistoryMaxData();
/**
* @brief 获取历史最大撕裂长度
*/
int getHistoryMaxLength() const { return m_historyMaxLength; }
/**
* @brief 获取历史最大撕裂ID
*/
int getHistoryMaxId() const { return m_historyMaxId; }
private slots:
/**
* @brief 心跳定时器超时处理
*/
void onHeartbeatTimeout();
/**
* @brief 客户端超时检查
*/
void onClientTimeoutCheck();
private:
/**
* @brief 构造数据帧
* @param jsonData JSON数据
* @return 完整的数据帧
*/
QByteArray buildFrame(const QByteArray& jsonData);
/**
* @brief 解析数据帧
* @param data 接收到的数据
* @param outJsonData 输出的JSON数据数组
* @return 成功解析的帧数量
*/
int parseFrames(const QByteArray& data, QList<QByteArray>& outJsonData);
/**
* @brief 解析消息类型
* @param msgTypeStr 消息类型字符串
* @return 消息类型枚举
*/
TcpMessageType parseMessageType(const QString& msgTypeStr);
/**
* @brief 处理JSON消息
* @param pClient 客户端指针
* @param jsonData JSON数据
*/
void handleJsonMessage(const TCPClient* pClient, const QByteArray& jsonData);
/**
* @brief 处理速度设置命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleSetSpeed(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理控制命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleSetControl(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理心跳消息
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleHeartbeat(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理实时传输控制命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleSetRealtime(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 发送命令应答
* @param pClient 客户端指针
* @param cmdType 命令类型
* @param result 执行结果
* @param errorCode 错误码
* @param errorMsg 错误消息
*/
void sendCommandResponse(const TCPClient* pClient, const QString& cmdType,
bool result, int errorCode, const QString& errorMsg);
/**
* @brief 发送心跳应答
* @param pClient 客户端指针
*/
void sendHeartbeatAck(const TCPClient* pClient);
/**
* @brief 图像转Base64
* @param image 图像
* @return Base64字符串
*/
QString imageToBase64(const QImage& image);
/**
* @brief 生成客户端ID
* @param pClient 客户端指针
* @return 客户端ID
*/
QString generateClientId(const TCPClient* pClient);
private:
IYTCPServer* m_tcpServer; // TCP服务器
QTimer* m_heartbeatTimer; // 心跳定时器
QTimer* m_clientCheckTimer; // 客户端超时检查定时器
int m_heartbeatInterval; // 心跳间隔(秒)
int m_clientTimeout; // 客户端超时时间(秒)
quint16 m_tcpPort; // TCP服务器端口
// 客户端数据缓冲区
QMap<QString, QByteArray> m_clientBuffers; // 客户端ID -> 数据缓冲区
QMap<QString, qint64> m_clientLastActive; // 客户端ID -> 最后活跃时间
QMap<QString, bool> m_clientRealtimeEnabled; // 客户端ID -> 实时传输开关状态
QMap<QString, const TCPClient*> m_clientPointers; // 客户端ID -> 客户端指针
// 回调函数
SpeedCallback m_speedCallback;
ControlCallback m_controlCallback;
// 历史最大撕裂数据(从开流开始累积)
int m_historyMaxLength; // 历史最大撕裂长度
int m_historyMaxId; // 历史最大撕裂对应的ID
};
#endif // TEARINGTCPPROTOCOL_H