GrabBag/Module/BinocularMarkReceiver/Src/BinocularMarkReceiver.cpp
2025-12-10 00:01:32 +08:00

409 lines
12 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.

#include "BinocularMarkReceiver.h"
#include <QDebug>
// 静态工厂方法实现
int IBinocularMarkReceiver::CreateInstance(IBinocularMarkReceiver** ppReceiver)
{
if (!ppReceiver) {
return -1;
}
*ppReceiver = new BinocularMarkReceiver();
return 0;
}
BinocularMarkReceiver::BinocularMarkReceiver(QObject *parent)
: QObject(parent)
, m_pTcpSocket(new QTcpSocket(this))
, m_pHeartbeatTimer(new QTimer(this))
, m_nHeartbeatInterval(30)
, m_serverPort(0)
, m_bConnected(false)
{
// 连接TCP套接字信号
connect(m_pTcpSocket, &QTcpSocket::connected, this, &BinocularMarkReceiver::onConnected);
connect(m_pTcpSocket, &QTcpSocket::disconnected, this, &BinocularMarkReceiver::onDisconnected);
connect(m_pTcpSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
this, &BinocularMarkReceiver::onError);
connect(m_pTcpSocket, &QTcpSocket::readyRead, this, &BinocularMarkReceiver::onReadyRead);
// 连接心跳定时器
connect(m_pHeartbeatTimer, &QTimer::timeout, this, &BinocularMarkReceiver::onHeartbeatTimeout);
}
BinocularMarkReceiver::~BinocularMarkReceiver()
{
Disconnect();
}
int BinocularMarkReceiver::Connect(const std::string& serverIp, quint16 serverPort)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_bConnected) {
qDebug() << "已经连接到服务器";
return 0;
}
m_serverIp = serverIp;
m_serverPort = serverPort;
// 连接到服务器
m_pTcpSocket->connectToHost(QString::fromStdString(serverIp), serverPort);
// 等待连接超时5秒
if (!m_pTcpSocket->waitForConnected(5000)) {
qDebug() << "连接BinocularMarkApp服务器失败:" << m_pTcpSocket->errorString();
return -1;
}
return 0;
}
int BinocularMarkReceiver::Disconnect()
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!m_bConnected) {
return 0;
}
// 停止心跳
StopHeartbeat();
// 断开连接
m_pTcpSocket->disconnectFromHost();
// 等待断开连接超时3秒
if (m_pTcpSocket->state() != QAbstractSocket::UnconnectedState) {
m_pTcpSocket->waitForDisconnected(3000);
}
m_bConnected = false;
m_dataBuffer.clear();
return 0;
}
bool BinocularMarkReceiver::IsConnected() const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_bConnected;
}
int BinocularMarkReceiver::SendHeartbeat()
{
QJsonObject jsonObj;
jsonObj["timestamp"] = QDateTime::currentMSecsSinceEpoch();
return sendJsonMessage("HEARTBEAT", jsonObj);
}
int BinocularMarkReceiver::TriggerDetection()
{
QJsonObject jsonObj;
jsonObj["timestamp"] = QDateTime::currentMSecsSinceEpoch();
return sendJsonMessage("CMD_TRIGGER", jsonObj);
}
void BinocularMarkReceiver::SetMarkResultCallback(MarkResultCallback callback)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_markResultCallback = callback;
}
void BinocularMarkReceiver::SetConnectionStatusCallback(ConnectionStatusCallback callback)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_connectionCallback = callback;
}
void BinocularMarkReceiver::StartHeartbeat(int intervalSeconds)
{
m_nHeartbeatInterval = intervalSeconds;
m_pHeartbeatTimer->start(intervalSeconds * 1000);
}
void BinocularMarkReceiver::StopHeartbeat()
{
m_pHeartbeatTimer->stop();
}
void BinocularMarkReceiver::onConnected()
{
qDebug() << "已连接到BinocularMarkApp服务器";
{
std::lock_guard<std::mutex> lock(m_mutex);
m_bConnected = true;
}
// 通知连接状态改变
if (m_connectionCallback) {
m_connectionCallback(true);
}
// 启动心跳
StartHeartbeat(m_nHeartbeatInterval);
}
void BinocularMarkReceiver::onDisconnected()
{
qDebug() << "与BinocularMarkApp服务器断开连接";
{
std::lock_guard<std::mutex> lock(m_mutex);
m_bConnected = false;
}
// 停止心跳
StopHeartbeat();
// 通知连接状态改变
if (m_connectionCallback) {
m_connectionCallback(false);
}
}
void BinocularMarkReceiver::onError(QAbstractSocket::SocketError socketError)
{
qDebug() << "TCP套接字错误:" << socketError << m_pTcpSocket->errorString();
}
void BinocularMarkReceiver::onReadyRead()
{
// 读取所有可用数据
QByteArray data = m_pTcpSocket->readAll();
// 追加到缓冲区
m_dataBuffer.append(data);
// 解析数据帧
parseFrames(m_dataBuffer);
}
void BinocularMarkReceiver::onHeartbeatTimeout()
{
// 发送心跳消息
SendHeartbeat();
}
void BinocularMarkReceiver::parseFrames(const QByteArray& data)
{
while (true) {
// 查找帧头
int headerIndex = m_dataBuffer.indexOf(FRAME_HEADER);
if (headerIndex == -1) {
// 没有找到帧头,清空缓冲区
m_dataBuffer.clear();
break;
}
// 丢弃帧头之前的数据
if (headerIndex > 0) {
m_dataBuffer.remove(0, headerIndex);
}
// 检查是否有足够的数据来读取长度字段
if (m_dataBuffer.size() < FRAME_HEADER_SIZE + FRAME_LENGTH_SIZE) {
// 数据不够,等待更多数据
break;
}
// 读取数据长度8字节ASCII字符串格式如 "00001234"
QByteArray lengthStr = m_dataBuffer.mid(FRAME_HEADER_SIZE, FRAME_LENGTH_SIZE);
bool ok = false;
qint64 dataLength = lengthStr.toLongLong(&ok);
if (!ok) {
qDebug() << "无效的长度字符串:" << lengthStr;
m_dataBuffer.remove(0, FRAME_HEADER_SIZE);
continue;
}
// 检查数据长度是否合理最大10MB
if (dataLength < 0 || dataLength > 10 * 1024 * 1024) {
qDebug() << "无效的数据长度:" << dataLength;
m_dataBuffer.remove(0, FRAME_HEADER_SIZE);
continue;
}
// 计算完整帧的总长度
int totalFrameLength = FRAME_HEADER_SIZE + FRAME_LENGTH_SIZE + dataLength + FRAME_TAIL_SIZE;
// 检查是否有完整的帧
if (m_dataBuffer.size() < totalFrameLength) {
// 数据不够,等待更多数据
break;
}
// 提取JSON数据
QByteArray jsonData = m_dataBuffer.mid(FRAME_HEADER_SIZE + FRAME_LENGTH_SIZE, dataLength);
// 验证帧尾
QByteArray tail = m_dataBuffer.mid(FRAME_HEADER_SIZE + FRAME_LENGTH_SIZE + dataLength, FRAME_TAIL_SIZE);
if (tail != FRAME_TAIL) {
qDebug() << "无效的帧尾";
m_dataBuffer.remove(0, FRAME_HEADER_SIZE);
continue;
}
// 处理JSON消息
handleJsonMessage(jsonData);
// 移除已处理的帧
m_dataBuffer.remove(0, totalFrameLength);
}
}
void BinocularMarkReceiver::handleJsonMessage(const QByteArray& jsonData)
{
// 解析JSON
QJsonParseError parseError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qDebug() << "JSON解析错误:" << parseError.errorString();
return;
}
if (!jsonDoc.isObject()) {
qDebug() << "JSON不是对象";
return;
}
QJsonObject jsonObj = jsonDoc.object();
// 获取消息类型
QString messageType = jsonObj["message_type"].toString();
if (messageType == "MARK_RESULT") {
handleMarkResult(jsonObj);
} else if (messageType == "HEARTBEAT_ACK") {
handleHeartbeatAck(jsonObj);
} else if (messageType == "CMD_RESPONSE") {
handleCommandResponse(jsonObj);
} else {
qDebug() << "未知的消息类型:" << messageType;
}
}
void BinocularMarkReceiver::handleMarkResult(const QJsonObject& jsonObj)
{
// 解析Mark结果
qint64 timestamp = jsonObj["timestamp"].toVariant().toLongLong();
int errorCode = jsonObj["error_code"].toInt();
qDebug() << "========== BinocularMark 接收数据 ==========";
qDebug() << "时间戳 (timestamp):" << timestamp;
qDebug() << "错误码 (error_code):" << errorCode;
std::vector<VrMark3D> marks;
if (errorCode == 0) {
QJsonArray marksArray = jsonObj["marks"].toArray();
qDebug() << "Mark 点数量:" << marksArray.size();
int index = 0;
for (const QJsonValue& markValue : marksArray) {
QJsonObject markObj = markValue.toObject();
VrMark3D mark;
mark.markID = markObj["mark_id"].toInt();
mark.x = markObj["x"].toDouble();
mark.y = markObj["y"].toDouble();
mark.z = markObj["z"].toDouble();
qDebug() << QString(" Mark[%1]: ID=%2, X=%3, Y=%4, Z=%5")
.arg(index)
.arg(mark.markID)
.arg(mark.x, 0, 'f', 3)
.arg(mark.y, 0, 'f', 3)
.arg(mark.z, 0, 'f', 3);
marks.push_back(mark);
index++;
}
} else {
qDebug() << "检测失败,错误码:" << errorCode;
}
qDebug() << "==========================================";
// 调用回调函数
if (m_markResultCallback) {
m_markResultCallback(marks, timestamp, errorCode);
}
}
void BinocularMarkReceiver::handleHeartbeatAck(const QJsonObject& jsonObj)
{
// 心跳应答,暂时不处理
qDebug() << "收到心跳应答";
}
void BinocularMarkReceiver::handleCommandResponse(const QJsonObject& jsonObj)
{
QString cmdType = jsonObj["cmd_type"].toString();
bool result = jsonObj["result"].toBool();
int errorCode = jsonObj["error_code"].toInt();
QString errorMsg = jsonObj["error_msg"].toString();
qDebug() << "命令应答:" << cmdType << "结果:" << result << "错误码:" << errorCode << "错误消息:" << errorMsg;
}
QByteArray BinocularMarkReceiver::buildFrame(const QByteArray& jsonData)
{
QByteArray frame;
// 添加帧头
frame.append(FRAME_HEADER, FRAME_HEADER_SIZE);
// 添加数据长度8字节ASCII字符串格式如 "00001234"
quint64 dataLength = jsonData.size();
char lengthStr[9]; // 8位数字 + '\0'
#ifdef _WIN32
sprintf_s(lengthStr, "%08llu", dataLength);
#else
sprintf(lengthStr, "%08llu", dataLength);
#endif
frame.append(lengthStr, FRAME_LENGTH_SIZE);
// 添加JSON数据
frame.append(jsonData);
// 添加帧尾
frame.append(FRAME_TAIL, FRAME_TAIL_SIZE);
return frame;
}
int BinocularMarkReceiver::sendJsonMessage(const QString& messageType, const QJsonObject& jsonObj)
{
if (!m_bConnected) {
qDebug() << "未连接到服务器";
return -1;
}
// 构造JSON对象
QJsonObject msgObj = jsonObj;
msgObj["message_type"] = messageType;
// 转换为JSON字符串
QJsonDocument jsonDoc(msgObj);
QByteArray jsonData = jsonDoc.toJson(QJsonDocument::Compact);
// 构造数据帧
QByteArray frame = buildFrame(jsonData);
// 发送数据
qint64 bytesWritten = m_pTcpSocket->write(frame);
if (bytesWritten == -1) {
qDebug() << "发送数据失败:" << m_pTcpSocket->errorString();
return -1;
}
m_pTcpSocket->flush();
return 0;
}