GrabBag/GrabBagApp/Presenter/Src/SerialProtocol.cpp

435 lines
14 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 "SerialProtocol.h"
#include "VrLog.h"
#include "VrError.h"
#include <QStringList>
#include <QDebug>
#include <QThread>
#include <sstream>
#include <iomanip>
#include <QSerialPortInfo>
// 协议常量定义
const QString SerialProtocol::PROTOCOL_START = "$";
const QString SerialProtocol::PROTOCOL_END = "#";
const QString SerialProtocol::CMD_START = "START";
const QString SerialProtocol::CMD_DATA = "DATA";
const QString SerialProtocol::SEPARATOR = ",";
SerialProtocol::SerialProtocol(QObject* parent)
: QObject(parent)
, m_serialStatus(STATUS_DISCONNECTED)
{
m_pSerialPort = new QSerialPort(this);
// 连接信号和槽
connect(m_pSerialPort, &QSerialPort::readyRead, this, &SerialProtocol::OnSerialDataReceived);
connect(m_pSerialPort, &QSerialPort::errorOccurred, this, &SerialProtocol::OnSerialError);
}
SerialProtocol::~SerialProtocol()
{
CloseSerial();
}
int SerialProtocol::OpenSerial(const std::string& portName, int baudRate,
int dataBits, int stopBits, int parity, int flowControl)
{
if (m_pSerialPort->isOpen()) {
LOG_WARNING("Serial port is already open: %s\n", portName.c_str());
return SUCCESS;
}
LOG_INFO("Opening serial port: %s, baudRate: %d, dataBits: %d, stopBits: %d, parity: %d, flowControl: %d\n",
portName.c_str(), baudRate, dataBits, stopBits, parity, flowControl);
// 设置串口参数
m_pSerialPort->setPortName(QString::fromStdString(portName));
m_pSerialPort->setBaudRate(baudRate);
// 设置数据位
switch (dataBits) {
case 5: m_pSerialPort->setDataBits(QSerialPort::Data5); break;
case 6: m_pSerialPort->setDataBits(QSerialPort::Data6); break;
case 7: m_pSerialPort->setDataBits(QSerialPort::Data7); break;
case 8: m_pSerialPort->setDataBits(QSerialPort::Data8); break;
default: m_pSerialPort->setDataBits(QSerialPort::Data8); break;
}
// 设置停止位
switch (stopBits) {
case 1: m_pSerialPort->setStopBits(QSerialPort::OneStop); break;
case 2: m_pSerialPort->setStopBits(QSerialPort::TwoStop); break;
default: m_pSerialPort->setStopBits(QSerialPort::OneStop); break;
}
// 设置校验位
switch (parity) {
case 0: m_pSerialPort->setParity(QSerialPort::NoParity); break;
case 1: m_pSerialPort->setParity(QSerialPort::OddParity); break;
case 2: m_pSerialPort->setParity(QSerialPort::EvenParity); break;
default: m_pSerialPort->setParity(QSerialPort::NoParity); break;
}
// 设置流控制
switch (flowControl) {
case 0: m_pSerialPort->setFlowControl(QSerialPort::NoFlowControl); break;
case 1: m_pSerialPort->setFlowControl(QSerialPort::HardwareControl); break;
case 2: m_pSerialPort->setFlowControl(QSerialPort::SoftwareControl); break;
default: m_pSerialPort->setFlowControl(QSerialPort::NoFlowControl); break;
}
// 尝试打开串口
if (!m_pSerialPort->open(QIODevice::ReadWrite)) {
LOG_ERROR("Failed to open serial port: %s, error: %s\n", portName.c_str(), m_pSerialPort->errorString().toStdString().c_str());
m_serialStatus = STATUS_ERROR;
return ERR_CODE(DEV_OPEN_ERR);
}
// 清空接收缓冲区
m_receiveBuffer.clear();
m_pSerialPort->clear();
// 设置读取超时和缓冲区大小
m_pSerialPort->setReadBufferSize(1024);
m_serialStatus = STATUS_CONNECTED;
LOG_INFO("Serial port opened successfully: %s\n", portName.c_str());
// 触发连接状态回调
if (m_connectionCallback) {
m_connectionCallback(true);
}
return SUCCESS;
}
void SerialProtocol::CloseSerial()
{
if (m_pSerialPort && m_pSerialPort->isOpen()) {
LOG_INFO("Closing serial port: %s\n", m_pSerialPort->portName().toStdString().c_str());
m_pSerialPort->close();
m_serialStatus = STATUS_DISCONNECTED;
// 触发连接状态回调
if (m_connectionCallback) {
m_connectionCallback(false);
}
}
}
int SerialProtocol::SendMultiTargetData(const MultiTargetData& multiTargetData, uint16_t cameraId)
{
if (!m_pSerialPort || !m_pSerialPort->isOpen()) {
LOG_ERROR("Serial port is not open, cannot send data\n");
return -1;
}
LOG_DEBUG("Sending multi-target data, count: %d, camera ID: %d\n", multiTargetData.count, cameraId);
// 构造协议数据
std::string protocolData = BuildDataProtocol(multiTargetData, cameraId);
// 发送数据
int result = SendData(protocolData);
if (result == SUCCESS) {
LOG_INFO("Multi-target data sent successfully: %s\n", protocolData.c_str());
} else {
LOG_ERROR("Failed to send multi-target data\n");
}
return result;
}
SerialProtocol::SerialStatus SerialProtocol::GetSerialStatus() const
{
return m_serialStatus;
}
void SerialProtocol::SetConnectionCallback(const ConnectionCallback& callback)
{
m_connectionCallback = callback;
}
void SerialProtocol::SetWorkSignalCallback(const WorkSignalCallback& callback)
{
m_workSignalCallback = callback;
}
bool SerialProtocol::IsOpen() const
{
return m_pSerialPort && m_pSerialPort->isOpen();
}
void SerialProtocol::OnSerialDataReceived()
{
LOG_DEBUG("OnSerialDataReceived() called\n");
LOG_DEBUG("OnSerialDataReceived() called\n");
LOG_DEBUG("OnSerialDataReceived() called\n");
LOG_DEBUG("OnSerialDataReceived() called\n");
LOG_DEBUG("OnSerialDataReceived() called\n");
if (!m_pSerialPort) {
LOG_ERROR("Serial port is null in OnSerialDataReceived\n");
return;
}
if (!m_pSerialPort->isOpen()) {
LOG_ERROR("Serial port is not open in OnSerialDataReceived\n");
return;
}
// 检查可用字节数
qint64 bytesAvailable = m_pSerialPort->bytesAvailable();
LOG_INFO("Bytes available to read: %lld\n", bytesAvailable);
if (bytesAvailable <= 0) {
LOG_WARNING("No bytes available but readyRead signal was triggered\n");
return;
}
// 读取所有可用数据
QByteArray data = m_pSerialPort->readAll();
QString receivedData = QString::fromUtf8(data);
LOG_INFO("Actually read %d bytes from serial port\n", data.size());
if (data.isEmpty()) {
LOG_WARNING("readAll() returned empty data\n");
return;
}
// 添加到接收缓冲区
m_receiveBuffer += receivedData;
// 打印接收到的数据
LOG_INFO("Received [%d bytes]: \"%s\"\n", data.size(), receivedData.toStdString().c_str());
// 如果包含不可打印字符额外打印ASCII码
bool hasNonPrintable = false;
for (char c : data) {
if (c < 32 || c > 126) {
hasNonPrintable = true;
break;
}
}
if (hasNonPrintable) {
QString asciiInfo = "ASCII: ";
for (char c : data) {
if (c >= 32 && c <= 126) {
asciiInfo += QString("'%1' ").arg(c);
} else {
asciiInfo += QString("[%1] ").arg((unsigned char)c);
}
}
LOG_INFO("%s\n", asciiInfo.toStdString().c_str());
}
// 查找完整的协议帧
int startIndex = -1;
int endIndex = -1;
while ((startIndex = m_receiveBuffer.indexOf(PROTOCOL_START)) != -1) {
endIndex = m_receiveBuffer.indexOf(PROTOCOL_END, startIndex);
if (endIndex != -1) {
// 提取完整的协议帧
QString protocolFrame = m_receiveBuffer.mid(startIndex, endIndex - startIndex + 1);
// 解析协议数据
ParseProtocolData(protocolFrame);
// 移除已处理的数据
m_receiveBuffer.remove(0, endIndex + 1);
} else {
// 没有找到结束标识,等待更多数据
break;
}
}
// 如果缓冲区太大,清空一部分(防止内存溢出)
if (m_receiveBuffer.length() > 1024) {
m_receiveBuffer.clear();
}
}
void SerialProtocol::OnSerialError(QSerialPort::SerialPortError error)
{
if (error == QSerialPort::NoError) {
return;
}
QString errorString = m_pSerialPort ? m_pSerialPort->errorString() : "Unknown error";
LOG_ERROR("=== SERIAL PORT ERROR ===\n");
LOG_ERROR("Error type: %d\n", (int)error);
LOG_ERROR("Error message: %s\n", errorString.toStdString().c_str());
LOG_ERROR("Port open status: %s\n", (m_pSerialPort && m_pSerialPort->isOpen()) ? "OPEN" : "CLOSED");
// 详细的错误类型说明
switch (error) {
case QSerialPort::DeviceNotFoundError:
LOG_ERROR("Device not found error - port may be disconnected\n");
break;
case QSerialPort::PermissionError:
LOG_ERROR("Permission error - port may be in use by another application\n");
break;
case QSerialPort::OpenError:
LOG_ERROR("Open error - failed to open the port\n");
break;
case QSerialPort::WriteError:
LOG_ERROR("Write error - failed to write data\n");
break;
case QSerialPort::ReadError:
LOG_ERROR("Read error - failed to read data\n");
break;
case QSerialPort::ResourceError:
LOG_ERROR("Resource error - device disappeared or became unavailable\n");
break;
case QSerialPort::UnsupportedOperationError:
LOG_ERROR("Unsupported operation error\n");
break;
case QSerialPort::TimeoutError:
LOG_ERROR("Timeout error\n");
break;
default:
LOG_ERROR("Unknown error type: %d\n", (int)error);
break;
}
// 设置错误状态
m_serialStatus = STATUS_ERROR;
// 根据错误类型处理
switch (error) {
case QSerialPort::ResourceError:
case QSerialPort::DeviceNotFoundError:
case QSerialPort::PermissionError:
LOG_ERROR("Critical error - notifying connection callback\n");
// 连接断开错误
if (m_connectionCallback) {
m_connectionCallback(false);
}
break;
default:
LOG_WARNING("Non-critical error - continuing operation\n");
break;
}
LOG_ERROR("=== END SERIAL ERROR ===\n");
}
void SerialProtocol::ParseProtocolData(const QString& data)
{
LOG_DEBUG("Parsing protocol data: %s\n", data.toStdString().c_str());
// 移除协议开始和结束标识
QString cleanData = data;
cleanData.remove(PROTOCOL_START);
cleanData.remove(PROTOCOL_END);
// 按分隔符分割数据
QStringList parts = cleanData.split(SEPARATOR);
if (parts.isEmpty()) {
LOG_WARNING("Empty protocol data received\n");
return;
}
QString command = parts[0];
if (command == CMD_START) {
// 处理开始命令:$,START,#
LOG_INFO("Received START command\n");
// 默认相机ID为1如果有更多参数可以解析
int cameraId = 1;
if (parts.size() > 1) {
bool ok;
cameraId = parts[1].toInt(&ok);
if (!ok) {
cameraId = 1;
}
}
// 触发工作信号回调
if (m_workSignalCallback) {
bool result = m_workSignalCallback(true, cameraId);
LOG_INFO("Work signal callback result: %s, camera ID: %d\n",
result ? "success" : "failed", cameraId);
}
m_serialStatus = STATUS_WORKING;
} else {
LOG_WARNING("Unknown command received: %s\n", command.toStdString().c_str());
}
}
int SerialProtocol::SendData(const std::string& data)
{
if (!m_pSerialPort || !m_pSerialPort->isOpen()) {
LOG_ERROR("Serial port is not open, cannot send data\n");
return -1;
}
// 检查串口是否可写
if (!m_pSerialPort->isWritable()) {
LOG_ERROR("Serial port is not writable\n");
return -1;
}
// 检查待写入的字节数
qint64 bytesToWrite = m_pSerialPort->bytesToWrite();
LOG_INFO("Bytes pending write before send: %lld\n", bytesToWrite);
QByteArray dataToSend = data.c_str();
qint64 bytesWritten = m_pSerialPort->write(dataToSend);
LOG_INFO("Write operation result: %lld bytes (expected: %d)\n", bytesWritten, dataToSend.size());
if (bytesWritten == -1) {
LOG_ERROR("Failed to write data to serial port: %s\n", m_pSerialPort->errorString().toStdString().c_str());
m_serialStatus = STATUS_ERROR;
return -1;
}
if (bytesWritten != dataToSend.size()) {
LOG_WARNING("PARTIAL WRITE: %lld of %d bytes written\n", bytesWritten, dataToSend.size());
}
// 立即刷新缓冲区
m_pSerialPort->flush();
// 等待数据发送完成
if (!m_pSerialPort->waitForBytesWritten(3000)) {
LOG_ERROR("Timeout waiting for data to be written\n");
return -1;
}
LOG_DEBUG("Sent %lld bytes to serial port\n", bytesWritten);
return SUCCESS;
}
std::string SerialProtocol::BuildDataProtocol(const MultiTargetData& multiTargetData, uint16_t cameraId)
{
std::stringstream ss;
// 协议格式:$,DATA,NUM,posX,posY,posZ,posC,posX,posY,posZ,posC...,#
ss << PROTOCOL_START.toStdString() << SEPARATOR.toStdString()
<< CMD_DATA.toStdString() << SEPARATOR.toStdString()
<< multiTargetData.count;
// 添加每个目标的坐标数据
for (const auto& target : multiTargetData.targets) {
ss << SEPARATOR.toStdString()
<< std::fixed << std::setprecision(2) << target.x << SEPARATOR.toStdString()
<< std::fixed << std::setprecision(2) << target.y << SEPARATOR.toStdString()
<< std::fixed << std::setprecision(2) << target.z << SEPARATOR.toStdString()
<< std::fixed << std::setprecision(2) << target.rz;
}
ss << SEPARATOR.toStdString() << PROTOCOL_END.toStdString();
return ss.str();
}