#pragma execution_character_set("utf-8") #include "device/Device.h" #include #include #include #include #include "Utils.h" #include "frame/Frame.h" #include "data/DateTimeData.h" #include #include #include "Common.h" #include "logger/LogManager.h" #include "crypto/CRC.h" Device::Device() : m_portName(QString("COM1")) , m_baudRate(QString("9600")) , m_dataBits(QString("8")) , m_stopBits(QString("1")) , m_parity("None") { InitRecvTimer(1000); } Device::Device(QString portName, QString baudRate, QString dataBits, QString stopBits, QString parity) : m_portName(portName) , m_baudRate(baudRate) , m_dataBits(dataBits) , m_stopBits(stopBits) , m_parity(parity) { InitRecvTimer(1000); m_lastLogString = ""; m_lastLogTimes = 0; } Device::~Device() { StopRecvTimer(); } /* **************************************** * * 串口数据转换 * * * **************************************** */ // 转换波特率 QSerialPort::BaudRate Device::convertBaudRate(QString baudRate) { if(baudRate == QObject::tr("1200")) { return QSerialPort::Baud1200; } else if(baudRate == QObject::tr("2400")) { return QSerialPort::Baud2400; } else if(baudRate == QObject::tr("4800")) { return QSerialPort::Baud4800; } else if(baudRate == QObject::tr("9600")) { return QSerialPort::Baud9600; } else if(baudRate == QObject::tr("19200")) { return QSerialPort::Baud19200; } else if(baudRate == QObject::tr("38400")) { return QSerialPort::Baud38400; } else if(baudRate == QObject::tr("57600")) { return QSerialPort::Baud57600; } else if(baudRate == QObject::tr("115200")) { return QSerialPort::Baud115200; } //return gDefaultBaudRate; return QSerialPort::Baud115200; } // 转换数据位 QSerialPort::DataBits Device::convertDataBits(QString dataBits) { if(dataBits == QObject::tr("5")) { return QSerialPort::Data5; } else if(dataBits == QObject::tr("6")) { return QSerialPort::Data6; } else if(dataBits == QObject::tr("7")) { return QSerialPort::Data7; } else if(dataBits == QObject::tr("8")) { return QSerialPort::Data8; } //return gDefaultDataBits; return QSerialPort::Data8; } // 转换停止位 QSerialPort::StopBits Device::convertStopBits(QString stopBits) { if(stopBits == QObject::tr("1")) { return QSerialPort::OneStop; } else if(stopBits == QObject::tr("1,5")) { return QSerialPort::OneAndHalfStop; } else if(stopBits == QObject::tr("2")) { return QSerialPort::TwoStop; } //return gDefaultStopBits; return QSerialPort::OneStop; } // 转换校验位 QSerialPort::Parity Device::convertParity(QString parity) { if(parity == QObject::tr("None")) { return QSerialPort::NoParity; } else if(parity == QObject::tr("Odd")) { return QSerialPort::OddParity; } else if(parity == QObject::tr("Even")) { return QSerialPort::EvenParity; } //return gDefaultParity; return QSerialPort::NoParity; } bool Device::Open() { m_serialPort.setPortName(m_portName); if(!m_serialPort.open(QIODevice::ReadWrite)) { return false; } // 设置波特率 m_serialPort.setBaudRate(convertBaudRate(m_baudRate)); // 设置数据位 m_serialPort.setDataBits(convertDataBits(m_dataBits)); // 设置停止位 m_serialPort.setStopBits(convertStopBits(m_stopBits)); // 设置校验位 m_serialPort.setParity(convertParity(m_parity)); m_serialPort.setFlowControl(QSerialPort::NoFlowControl); // readyRead()信号不产生的解决方案,设置"控制管脚状态". m_serialPort.setDataTerminalReady(true); //m_commThread.start(); connect(&m_serialPort, SIGNAL(readyRead()), this, SLOT(slot_readData())); logInfo(tr("Device Opened!")); return true; } bool Device::Close() { if(m_serialPort.isOpen()) { disconnect(&m_serialPort, SIGNAL(readyRead()), this, SLOT(slot_readData())); m_serialPort.clear(); m_serialPort.close(); } logInfo("Device Closed!"); return true; } void Device::ClearRecvData() { m_recvMutex.lock(); m_recvData.clear(); m_recvMutex.unlock(); logInfo("Recv Data Cleared!"); } /* 字符串解析: 当前状态 下一状态 字节长度 判断 0 1 1 head-1 = 0x5A 1 2 1 head-2 = 0xA5 2 3 1 addr-1 3 4 1 addr-2 4 5 1 cmd 5 6 1 len-1 6 7 1 len-2 7 8 length >=0 && <= 10240 8 9 1 crc-1 9 10 1 crc-2 */ // DMS Device Machine Status // 名称表示该状态完成 #define DMS0_INIT 0 #define DMS1_HEAD_1 1 #define DMS2_HEAD_2 2 #define DMS3_ADDR_1 3 #define DMS4_ADDR_2 4 #define DMS5_CMD 5 #define DMS6_LEN_1 6 #define DMS7_LEN_2 7 #define DMS8_CONTENT 8 #define DMS9_CRC_1 9 #define DMS10_CRC_2 10 // 5A A5 00 00 01 00 00 C0 8C void Device::slot_readData() { QByteArray byteArray = m_serialPort.readAll(); m_serialPort.clear(); logInfo("Read Data!"); m_recvMutex.lock(); m_recvData.append(byteArray); m_recvMutex.unlock(); } // 发送数据 bool Device::SendData(int cmd, std::string str, int msec) { if(!IsOpen()) { logInfo("串口未打开!"); return false; } Frame *frame = new Frame(cmd, FRAME_DIRECT_REQ); if(frame == nullptr) { logInfo("创建协议帧失败!"); return false; } frame->setAddr(0x1234); // // 设置的时间为当前时间,不从text中获取 // Data *data = new DateTimeData(); // frame->setData(data); frame->getData()->fromByteStr(str); frame->updateLen(); std::string sendData = frame->toByteStr(); int sendDataLen = sendData.length(); //#ifdef _DEBUG logDebug(QString::fromStdString(Utils::strToHexStr(sendData))); //#endif // 发送前先清理数据 m_recvMutex.lock(); m_recvData.clear(); m_serialPort.clear(); //m_serialPort.write(frame->toByteStr().c_str(), frame->toByteStr().length()); logInfo(tr("发送消息:%1").arg(gFrameCmdName[(cmd>=FRAME_CMD_START && cmd <=FRAME_CMD_MAX ? cmd : 0)].c_str())); m_serialPort.write(sendData.c_str(), sendDataLen); m_recvMutex.unlock(); delete frame; // 启动定时器,等待返回 // 如果定时器时间到,尚未收到响应消息,则报超时 // 如果在定时器时间内收到响应消息,关闭定时器 StartRecvTimer(msec); return true; } bool Device::SendData(int cmd, Data *data, int msec) { if(!IsOpen()) { logInfo("串口未打开!"); return false; } Frame *frame = new Frame(cmd, FRAME_DIRECT_REQ); if(frame == nullptr) { logInfo("创建协议帧失败!"); return false; } frame->setAddr(0x1234); // // 设置的时间为当前时间,不从text中获取 // Data *data = new DateTimeData(); // frame->setData(data); //frame->getData()->fromByteStr(str); frame->setData(data); frame->updateLen(); std::string sendData = frame->toByteStr(); int sendDataLen = sendData.length(); //#ifdef _DEBUG logDebug(QString::fromStdString(Utils::strToHexStr(sendData))); //#endif // 发送前先清理数据 m_recvMutex.lock(); m_recvData.clear(); m_serialPort.clear(); //m_serialPort.write(frame->toByteStr().c_str(), frame->toByteStr().length()); logInfo(tr("发送消息:%1").arg(gFrameCmdName[(cmd>=FRAME_CMD_START && cmd <=FRAME_CMD_MAX ? cmd : 0)].c_str())); m_serialPort.write(sendData.c_str(), sendDataLen); m_recvMutex.unlock(); delete frame; // 启动定时器,等待返回 // 如果定时器时间到,尚未收到响应消息,则报超时 // 如果在定时器时间内收到响应消息,关闭定时器 StartRecvTimer(msec); return true; } // 接收数据定时器初始化 void Device::InitRecvTimer(int msec) { m_recvTimer.stop(); m_recvTimer.setInterval(msec); // 1s超时 connect(&m_recvTimer, SIGNAL(timeout()), this, SLOT(slot_recvTimer())); } // 接收数据定时器 void Device::StartRecvTimer(int msec) { #ifdef _DEBUG logDebug(tr("StartRecvTimer")); #endif m_recvTimer.start(msec); } // 接收数据定时器 void Device::StopRecvTimer() { #ifdef _DEBUG logDebug(tr("StopRecvTimer")); #endif m_recvTimer.stop(); } // 接收数据定时器的功能: void Device::slot_recvTimer() { logInfo(tr("接收消息超时!")); emit recv_timeout(m_portName); StopRecvTimer(); } // 数据解析线程 void Device::runParseThread() { #ifdef _DEBUG logDebug(tr("runParseThread begin")); #endif while(1) { if(!m_bRunParseThread) { break; } if(m_recvData.length() > 0) { #ifdef _DEBUG logDebug(tr("parse data, length=%1, data=[%2]") .arg(m_recvData.length()) .arg(QString::fromStdString(Utils::strToHexStr(m_recvData.toStdString())))); #endif m_recvMutex.lock(); unsigned short nLen = 0; int status = 0; // 解析状态,0-初始,1-head1,2-head2, while(1) { if(status == DMS0_INIT) // 0:head - 1 - 0x5A { if(m_recvData.length() < 1) { break; // 长度不够,退出 } // 判断第一个字符是否0x5A,是则转入下一步,否则移除该字符,重新开始 if(m_recvData.at(0) == 0x5A) { status = DMS1_HEAD_1; } else { m_recvData.remove(0, 1); status = DMS0_INIT; } } else if(status == DMS1_HEAD_1) // 1:head - 2 - 0xA5 { // 状态1,判断第2个字符是否为0xA5 if(m_recvData.length() < 2) { break; // 长度不够,退出 } // 判断第二个字符是否为0xA5,是则转入下一步,否则。。。 if((unsigned char)m_recvData.at(1) == 0xA5) { status = DMS2_HEAD_2; } else { m_recvData.remove(0, 1); status = DMS1_HEAD_1; } } else if(status == DMS2_HEAD_2) // 2:addr - 1 { if(m_recvData.length() < 3) { break; // 长度不够,退出循环 } status = DMS3_ADDR_1; } else if(status == DMS3_ADDR_1) // 3:addr - 2 { // 状态2,判断长度是否超过4,不足则退出循环 if(m_recvData.length() < 4) { break; // 长度不够,退出循环 } status = DMS4_ADDR_2; } else if(status == DMS4_ADDR_2) // 4:cmd { // 状态2,判断命令 if(m_recvData.length() < 5) { break; // 长度不够,退出循环 } if(isCmdValid(m_recvData.at(4))) { status = DMS5_CMD; } else { m_recvData.remove(0, 2); // 移除首部2个字符,重新定位起始位置 status = DMS0_INIT; } } else if(status == DMS5_CMD) // 5:len-1 { // 状态2,判断命令 if(m_recvData.length() < 6) { break; // 长度不够,退出循环 } status = DMS6_LEN_1; } else if(status == DMS6_LEN_1) // 6:len - 2 { if(m_recvData.length() < 7) { break; // 长度不够,退出循环 } nLen = Utils::charToShort(m_recvData.at(5), m_recvData.at(6)); if(nLen > 10240) { m_recvData.remove(0, 2); status = DMS0_INIT; nLen = 0; } else { status = DMS7_LEN_2; } } else if(status == DMS7_LEN_2) // content + CRC { if(m_recvData.length() < 7 + nLen + 2) { break; // 长度不够,退出循环 } // 检查CRC QByteArray tmpRecvData = m_recvData.left(7 + nLen); unsigned short crc = CRC::crc16Table((unsigned char *)tmpRecvData.data(), tmpRecvData.length()); if(crc == Utils::charToShort(m_recvData.at(7+nLen), m_recvData.at(7+nLen+1))) { QByteArray recvData = m_recvData.left(7 + nLen + 2); m_recvData.remove(0, 7+nLen+2); //emit recv_data(m_portName, recvData); // 收到消息 // 此处直接返回类型和数据 unsigned char cmd = recvData.at(4); recvData.remove(0, 7); // 移除帧头 recvData.remove(nLen, 2); // 移除帧尾 emit recv_data(m_portName, cmd, recvData); StopRecvTimer(); // 停止定时器 status = DMS0_INIT; } else { m_recvData.remove(0, 2); status = DMS0_INIT; nLen = 0; } } } m_recvMutex.unlock(); } QThread::msleep(10); } #ifdef _DEBUG logDebug(tr("runParseThread end")); #endif } // 启动解析线程 void Device::startParseThread() { #ifdef _DEBUG logDebug(tr("startParseThread")); #endif m_bRunParseThread = true; m_parseThread = std::thread(&Device::runParseThread, this); //m_parseThread.detach(); } // 停止解析线程 void Device::stopParseThread() { #ifdef _DEBUG logDebug(tr("stopParseThread")); #endif m_bRunParseThread = false; m_parseThread.join(); }