GrabBag/App/BinocularMark/BinocularMarkApp/BinocularMarkTcpProtocol.h

317 lines
9.6 KiB
C++
Raw 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.

#ifndef BINOCULARMARKTCPPROTOCOL_H
#define BINOCULARMARKTCPPROTOCOL_H
#include <QObject>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QByteArray>
#include <QTimer>
#include <QMap>
#include <opencv2/opencv.hpp>
#include "IYTCPServer.h"
#include "binocularMarkCam_Export.h"
#include "SG_baseDataType.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 // 数据长度字段64位整数
/**
* @brief 消息类型枚举
*/
enum class MarkMessageType
{
UNKNOWN, // 未知消息类型
MARK_RESULT, // 标记检测结果上报(持续工作模式)
HEARTBEAT, // 心跳消息
HEARTBEAT_ACK, // 心跳应答
CMD_TRIGGER, // 触发检测命令(已废弃)
CMD_SINGLE_DETECTION, // 单次检测命令返回图像和Mark
SINGLE_DETECTION_RESULT, // 单次检测结果
CMD_SINGLE_IMAGE, // 单次图像命令
IMAGE_DATA, // 图像数据
CMD_START_WORK, // 开始持续工作命令
CMD_STOP_WORK, // 停止持续工作命令
CMD_SET_CALIBRATION, // 设置标定矩阵命令
CMD_SET_EXPOSURE_TIME, // 设置曝光时间命令
CMD_SET_GAIN, // 设置增益命令
CMD_RESPONSE = 200, // 命令应答
};
/**
* @brief BinocularMark TCP通信协议类
* 实现双目标记检测系统的TCP通信协议
* 支持粘包处理
*/
class BinocularMarkTcpProtocol : public QObject
{
Q_OBJECT
public:
explicit BinocularMarkTcpProtocol(QObject *parent = nullptr);
~BinocularMarkTcpProtocol();
/**
* @brief 启动TCP服务器
* @param port TCP端口
* @return true-成功false-失败
*/
bool startServer(quint16 port);
/**
* @brief 停止TCP服务器
*/
void stopServer();
/**
* @brief 启动心跳定时器
* @param heartbeatInterval 心跳间隔默认30秒
*/
void startHeartbeat(int heartbeatInterval = 30);
/**
* @brief 停止心跳定时器
*/
void stopHeartbeat();
/**
* @brief 发送标记检测结果(持续工作模式)
* @param marks 检测到的3D标记列表
* @param leftImage 左相机图像
* @param rightImage 右相机图像
* @param errorCode 错误码
*/
void sendMarkResult(const std::vector<SWD_charuco3DMark>& marks,
const cv::Mat& leftImage,
const cv::Mat& rightImage,
int errorCode);
/**
* @brief 发送单次检测结果包含图像和Mark
* @param pClient 客户端指针
* @param marks 检测到的3D标记列表
* @param leftImage 左相机图像
* @param rightImage 右相机图像
* @param errorCode 错误码
*/
void sendSingleDetectionResult(const TCPClient* pClient,
const std::vector<SWD_charuco3DMark>& marks,
const cv::Mat& leftImage,
const cv::Mat& rightImage,
int errorCode);
/**
* @brief 发送图像数据
* @param pClient 客户端指针
* @param leftImage 左相机图像
* @param rightImage 右相机图像
*/
void sendImageData(const TCPClient* pClient, const cv::Mat& leftImage, const cv::Mat& rightImage);
signals:
/**
* @brief 触发检测信号
*/
void triggerDetection();
/**
* @brief 单次检测请求信号
* @param pClient 请求的客户端
*/
void singleDetectionRequested(const TCPClient* pClient);
/**
* @brief 单次图像请求信号
* @param pClient 请求的客户端
*/
void singleImageRequested(const TCPClient* pClient);
/**
* @brief 开始持续工作请求信号
*/
void startWorkRequested();
/**
* @brief 停止持续工作请求信号
*/
void stopWorkRequested();
/**
* @brief 设置曝光时间请求信号
* @param exposureTime 曝光时间
*/
void setExposureTimeRequested(double exposureTime);
/**
* @brief 设置增益请求信号
* @param gain 增益
*/
void setGainRequested(double gain);
private slots:
/**
* @brief 心跳定时器超时处理
*/
void onHeartbeatTimeout();
private:
/**
* @brief TCP服务器接收回调
*/
static void tcpRecvCallback(const TCPClient* pClient, const char* pData, const unsigned int nLen);
/**
* @brief TCP服务器事件回调
*/
static void tcpEventCallback(const TCPClient* pClient, TCPServerEventType eventType);
/**
* @brief 处理接收到的数据
* @param pClient 客户端指针
* @param pData 数据指针
* @param nLen 数据长度
*/
void handleReceivedData(const TCPClient* pClient, const char* pData, unsigned int nLen);
/**
* @brief 构造数据帧
* @param jsonData JSON数据
* @return 完整的数据帧(帧头+长度+数据+帧尾)
*/
QByteArray buildFrame(const QByteArray& jsonData);
/**
* @brief 解析数据帧(处理粘包)
* @param clientId 客户端ID
* @param data 接收到的数据
* @param outJsonData 输出的JSON数据数组
* @return 成功解析的帧数量
*/
int parseFrames(const QString& clientId, const QByteArray& data, QList<QByteArray>& outJsonData);
/**
* @brief 解析消息类型
* @param msgTypeStr 消息类型字符串
* @return 消息类型枚举
*/
MarkMessageType 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 handleHeartbeat(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理触发检测命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleTriggerCommand(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理单次检测命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleSingleDetectionCommand(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理单次图像命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleSingleImageCommand(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理开始工作命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleStartWorkCommand(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理停止工作命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleStopWorkCommand(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理设置标定矩阵命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleSetCalibrationCommand(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理设置曝光时间命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleSetExposureTimeCommand(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 处理设置增益命令
* @param pClient 客户端指针
* @param jsonObj JSON对象
*/
void handleSetGainCommand(const TCPClient* pClient, const QJsonObject& jsonObj);
/**
* @brief 发送心跳应答
* @param pClient 客户端指针
*/
void sendHeartbeatAck(const TCPClient* pClient);
/**
* @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 图像转Base64
* @param image OpenCV图像
* @return Base64字符串
*/
QString imageToBase64(const cv::Mat& image);
/**
* @brief 生成客户端ID
* @param pClient 客户端指针
* @return 客户端ID
*/
QString generateClientId(const TCPClient* pClient);
private:
IYTCPServer* m_pTcpServer; // TCP服务器
QTimer* m_pHeartbeatTimer; // 心跳定时器
int m_nHeartbeatInterval; // 心跳间隔(秒)
quint16 m_nTcpPort; // TCP服务器端口
// 客户端数据缓冲区(用于处理粘包)
QMap<QString, QByteArray> m_clientBuffers; // 客户端ID -> 数据缓冲区
static BinocularMarkTcpProtocol* s_pInstance; // 静态实例指针
};
#endif // BINOCULARMARKTCPPROTOCOL_H