#ifndef BINOCULARMARKTCPPROTOCOL_H #define BINOCULARMARKTCPPROTOCOL_H #include #include #include #include #include #include #include #include #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_START_CONTINUOUS_IMAGE, // 开始持续图像流命令 CMD_STOP_CONTINUOUS_IMAGE, // 停止持续图像流命令 CMD_SET_CALIBRATION, // 设置标定矩阵命令 CMD_GET_CALIBRATION, // 获取标定矩阵命令 CMD_SET_EXPOSURE_TIME, // 设置曝光时间命令 CMD_SET_GAIN, // 设置增益命令 CMD_GET_CAMERA_INFO, // 获取相机信息命令 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(); 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 开始持续图像流请求信号 */ void startContinuousImageRequested(); /** * @brief 停止持续图像流请求信号 */ void stopContinuousImageRequested(); /** * @brief 设置曝光时间请求信号(同时设置左右相机) * @param exposureTime 曝光时间 */ void setExposureTimeRequested(double exposureTime); /** * @brief 设置增益请求信号(同时设置左右相机) * @param gain 增益 */ void setGainRequested(double gain); /** * @brief 设置左相机曝光时间请求信号 * @param exposureTime 曝光时间 */ void setLeftExposureTimeRequested(double exposureTime); /** * @brief 设置右相机曝光时间请求信号 * @param exposureTime 曝光时间 */ void setRightExposureTimeRequested(double exposureTime); /** * @brief 设置左相机增益请求信号 * @param gain 增益 */ void setLeftGainRequested(double gain); /** * @brief 设置右相机增益请求信号 * @param gain 增益 */ void setRightGainRequested(double gain); /** * @brief 获取相机信息请求信号 * @param pClient 客户端指针 * @param camera 相机标识("left"或"right") */ void getCameraInfoRequested(const TCPClient* pClient, const QString& camera); /** * @brief 获取标定矩阵请求信号 * @param pClient 客户端指针 */ void getCalibrationRequested(const TCPClient* pClient); /** * @brief 设置标定矩阵请求信号 * @param pClient 客户端指针 * @param calibrationXml 标定矩阵XML内容 */ void setCalibrationRequested(const TCPClient* pClient, const QString& calibrationXml); public slots: /** * @brief 发送标记检测结果(持续工作模式) * @param marks 检测到的3D标记列表 * @param leftImage 左相机图像 * @param rightImage 右相机图像 * @param errorCode 错误码 */ void sendMarkResult(const std::vector& 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& 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); /** * @brief 发送相机信息响应 * @param pClient 客户端指针 * @param camera 相机标识("left"或"right") * @param serialNumber 序列号 * @param modelName 型号 * @param displayName 显示名称 * @param exposureTime 曝光时间 * @param gain 增益 */ void sendCameraInfoResponse(const TCPClient* pClient, const QString& camera, const QString& serialNumber, const QString& modelName, const QString& displayName, double exposureTime, double gain); /** * @brief 发送标定矩阵响应 * @param pClient 客户端指针 * @param calibrationXml 标定矩阵XML字符串 */ void sendCalibrationMatrixResponse(const TCPClient* pClient, const QString& calibrationXml); 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& 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 handleStartContinuousImageCommand(const TCPClient* pClient, const QJsonObject& jsonObj); /** * @brief 处理停止持续图像流命令 * @param pClient 客户端指针 * @param jsonObj JSON对象 */ void handleStopContinuousImageCommand(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 handleGetCalibrationCommand(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 客户端指针 * @param jsonObj JSON对象 */ void handleGetCameraInfoCommand(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服务器端口 std::atomic m_bIsProcessingFrame; // 是否正在处理帧(用于丢帧) // 客户端数据缓冲区(用于处理粘包) QMap m_clientBuffers; // 客户端ID -> 数据缓冲区 static BinocularMarkTcpProtocol* s_pInstance; // 静态实例指针 }; #endif // BINOCULARMARKTCPPROTOCOL_H