/*********************************************************************
* 内容摘要: 串口类
* 其它说明: 无
* 当前版本: V1.0
* 作 者:
* 完成日期: 2022/12/29
**********************************************************************/
#ifndef SERIALPORTDATAPARSE_H
#define SERIALPORTDATAPARSE_H
#include <QObject>
#include <QSerialPort>
#include <QVariantMap>
#include <QTimer>
#include <QMutex>
#include <thread>
#include <QSharedPointer>
typedef struct SerialFrameStru
{
uint16_t frameHead;
uint16_t frameLen;
uint8_t slaveAddr;
uint16_t frameNo;
uint8_t frameCmd;
QByteArray realData;
uint16_t crc16;
} SerialFrame;
Q_DECLARE_METATYPE(SerialFrame)
class SerialPortDataParse : public QObject
{
Q_OBJECT
public:
explicit SerialPortDataParse(QObject *parent = nullptr);
~SerialPortDataParse();
static SerialPortDataParse *getInstance();
void writeData(const QVariantMap &vMap);
// 主板OTA权限下发
void otaPermissionSet(uint16_t &data);
// 主板OTA消息通知
void startSlaveUpgrade(QVariantMap &vMap);
// 主板发送数据
void sendUpgradeData(uint16_t frameNo, QByteArray &byteArray);
// 主板请求升级结果
void getUpgradeResult();
void sendData();
signals:
void sig_startTimer();
void sig_write(const SerialFrame &);
void sig_parseCmd0x01Frame(QVariantMap &vMap);
void sig_parseCmd0x02Frame(QVariantMap &vMap);
void sig_parseCmd0x03Frame(QVariantMap &vMap);
void sig_parseCmd0xA0Frame(QVariantMap &vMap);
void sig_parseCmd0xA3Frame(QVariantMap &vMap);
void sig_parseCmd0xA4Frame(QVariantMap &vMap);
void sig_parseCmd0xA5Frame(QVariantMap &vMap);
public slots:
void readData();
private:
void parseSerialData(QByteArray &data);
void retry();
void write(const SerialFrame &);
bool isReplyFrame(SerialFrame &);
// 接收采集器主动上报传感器数据01
void parseCmd0x01Frame(SerialFrame &frame);
// 回复采集器
void replyCmd0x01Frame(uint8_t);
// 接收采集器发送软件版本号
void parseCmd0x02Frame(SerialFrame &frame);
// 回复采集器
void replyCmd0x02Frame();
// 接收采集器上报工作状态
void parseCmd0x03Frame(SerialFrame &frame);
// 回复采集器
void replyCmd0x03Frame();
// 采集器权限管理回复
void parseCmd0xA0Frame(SerialFrame &frame);
// 接收采集器OTA回复
void parseCmd0xA3Frame(SerialFrame &frame);
// 接收采集器OTA发送数据回复
void parseCmd0xA4Frame(SerialFrame &frame);
// 主板请求升级结果回复
void parseCmd0xA5Frame(SerialFrame &frame);
private:
QMutex m_mutex;
QMutex m_retryMutex;
QList<SerialFrame> m_serialData;
QList<SerialFrame> m_retryList;
QSharedPointer<QSerialPort> m_serialPort{nullptr};
bool retryFlag{false};
SerialFrame m_currSendFrame; // 当前发送Map
QTimer m_timer;
QSharedPointer<std::thread> m_sendThread{nullptr};
};
#endif // SERIALPORTDATAPARSE_H
/*********************************************************************
* 内容摘要: 串口类
* 其它说明: 无
* 当前版本: V1.0
* 作 者:
* 完成日期: 2022/12/29
**********************************************************************/
#include "serialportdataparse.h"
#include <QSerialPortInfo>
#include <QtEndian>
#include <QThread>
#include <QDebug>
static bool flag = true;
static uint16_t crc16Check(uint8_t *buf, uint16_t len)
{
uint8_t crc16L = 0xff;
uint8_t crc16H = 0xff;
uint8_t saveL, saveH;
for (uint16_t i = 0; i < len; ++i) {
crc16L = crc16L ^ (*(buf+i));
for (uint16_t j = 0; j < 8; ++j) {
saveH = crc16H;
saveL = crc16L;
crc16H >>= 1;
crc16L >>= 1;
if ((saveH & 1) == 1) {
crc16L |= 0x80;
}
if ((saveL & 1) == 1) {
crc16H ^= 0xa0;
crc16L ^= 1;
}
}
}
return (crc16H << 8) | crc16L;
}
/**********************************************************************
* 功能描述: 默认构造函数
* 输入参数: parent:父类
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
***********************************************************************/
SerialPortDataParse::SerialPortDataParse(QObject *parent) : QObject(parent)
{
m_serialData.clear();
m_retryList.clear();
m_timer.setInterval(1000);
connect(&m_timer, &QTimer::timeout, this, &SerialPortDataParse::retry);
// 定时器不能从别的线程中开启
connect(this, &SerialPortDataParse::sig_startTimer, this, [&](){m_timer.start();});
m_serialPort = QSharedPointer<QSerialPort>(new QSerialPort);
if (m_serialPort.isNull()) {
return;
}
QList<QSerialPortInfo> serialPortList = QSerialPortInfo::availablePorts();
foreach (QSerialPortInfo info, serialPortList) {
if (info.portName().isEmpty()) {
continue;
}
m_serialPort->setPort(info);
m_serialPort->setBaudRate(QSerialPort::QSerialPort::Baud115200);
m_serialPort->setDataBits(QSerialPort::Data8);
m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
m_serialPort->setParity(QSerialPort::NoParity);
m_serialPort->setStopBits(QSerialPort::OneStop);
if (m_serialPort->open(QIODevice::ReadWrite)) {
qRegisterMetaType<SerialFrame>("SerialFrame");
connect(m_serialPort.data(), &QIODevice::readyRead, this, &SerialPortDataParse::readData);
connect(this, &SerialPortDataParse::sig_write, this, &SerialPortDataParse::write);
m_sendThread = QSharedPointer<std::thread>(new std::thread(&SerialPortDataParse::sendData, this));
break;
}
}
}
/**********************************************************************
* 功能描述: 析构函数
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
***********************************************************************/
SerialPortDataParse::~SerialPortDataParse()
{
flag = false;
if (!m_serialPort.isNull() && m_serialPort->isOpen()) {
m_serialPort->close();
}
if (!m_sendThread.isNull() && m_sendThread->joinable()) {
m_sendThread->join();
}
}
/**********************************************************************
* 功能描述: 获取单例
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
***********************************************************************/
SerialPortDataParse *SerialPortDataParse::getInstance()
{
static SerialPortDataParse serialPortDataParse;
return &serialPortDataParse;
}
/**********************************************************************
* 功能描述: 读取串口数据
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
***********************************************************************/
void SerialPortDataParse::readData()
{
QByteArray data = m_serialPort->readAll();
parseSerialData(data);
}
void SerialPortDataParse::parseSerialData(QByteArray &data)
{
qDebug()<<"______recv__________"<<data.toHex(' ');
int size = data.size();
if (size < 10 || size > 1024) {
QString err = QString("Recv Serial Data Error! Size: %1").arg(size);
qDebug()<<__func__<<__LINE__<<err;
return;
}
SerialFrame frame;
frame.frameHead = (data[0] << 8) + data[1];
frame.frameLen = (data[2] << 8) + data[3];
frame.slaveAddr = data[4];
frame.frameNo = (data[5] << 8) + data[6];
frame.frameCmd = data[7];
frame.realData = data.mid(8, size-10);
frame.crc16 = (data[size-2] << 8) + data[size-1];
uint16_t crc16 = crc16Check((uint8_t *)data.data(), size-2);
if (frame.frameHead != 0xAA55 || crc16 != frame.crc16) {
QString err = QString("Recv Serial Data Crc16 Check Failed! FrameHead: %x%1, Crc16: 0x%2 != 0x%3")
.arg(QString::number(frame.frameHead, 16).toUpper())
.arg(QString::number(crc16, 16).toUpper())
.arg(QString::number(frame.crc16, 16).toUpper());
qDebug()<<__func__<<__LINE__<<err;
return;
}
// 收到回复
if (frame.frameCmd == m_currSendFrame.frameCmd) {
retryFlag = false;
m_timer.stop();
}
if (frame.frameCmd == 0x01) { // 采集器主动上报传感器数据
if (frame.realData.size() < 26) {
QString err = QString("Recv Serial Cmd: 0x%1, DataLen: %2 Error")
.arg(QString::number(frame.frameCmd, 16).toUpper()).arg(frame.realData.size());
qDebug()<<__func__<<__LINE__<<err;
return;
}
parseCmd0x01Frame(frame);
} else if (frame.frameCmd == 0x02) { // 采集器发送软件版本号
if (frame.realData.size() < 4) {
QString err = QString("Recv Serial Cmd: 0x%1, DataLen: %2 Error")
.arg(QString::number(frame.frameCmd, 16).toUpper()).arg(frame.realData.size());
qDebug()<<__func__<<__LINE__<<err;
return;
}
parseCmd0x02Frame(frame);
} else if (frame.frameCmd == 0xA3) { // 采集器OTA回复
if (frame.realData.size() < 1) {
QString err = QString("Recv Serial Cmd: 0x%1, DataLen: %2 Error")
.arg(QString::number(frame.frameCmd, 16).toUpper()).arg(frame.realData.size());
qDebug()<<__func__<<__LINE__<<err;
return;
}
parseCmd0xA3Frame(frame);
} else if (frame.frameCmd == 0xA4) { // 采集器OTA发送数据回复
if (frame.realData.size() < 1) {
QString err = QString("Recv Serial Cmd: 0x%1, DataLen: %2 Error")
.arg(QString::number(frame.frameCmd, 16).toUpper()).arg(frame.realData.size());
qDebug()<<__func__<<__LINE__<<err;
return;
}
parseCmd0xA4Frame(frame);
} else if (frame.frameCmd == 0xA5) { // 采集器OTA升级结果回复
if (frame.realData.size() < 1) {
QString err = QString("Recv Serial Cmd: 0x%1, DataLen: %2 Error")
.arg(QString::number(frame.frameCmd, 16).toUpper()).arg(frame.realData.size());
qDebug()<<__func__<<__LINE__<<err;
return;
}
parseCmd0xA5Frame(frame);
} else if (frame.frameCmd == 0xA0) { // 采集器OTA权限回复
if (frame.realData.size() < 2) {
QString err = QString("Recv Serial Cmd: 0x%1, DataLen: %2 Error")
.arg(QString::number(frame.frameCmd, 16).toUpper()).arg(frame.realData.size());
qDebug()<<__func__<<__LINE__<<err;
return;
}
parseCmd0xA0Frame(frame);
} else if (frame.frameCmd == 0x03) { // 采集器上报工作状态
if (frame.realData.size() < 2) {
QString err = QString("Recv Serial Cmd: 0x%1, DataLen: %2 Error")
.arg(QString::number(frame.frameCmd, 16).toUpper()).arg(frame.realData.size());
qDebug()<<__func__<<__LINE__<<err;
return;
}
parseCmd0x03Frame(frame);
}
}
void SerialPortDataParse::retry()
{
static int cnt = 0;
if (cnt < 2) {
cnt++;
QMutexLocker locker(&m_retryMutex);
m_retryList.append(m_currSendFrame);
} else {
cnt = 0;
retryFlag = false;
m_timer.stop();
}
}
void SerialPortDataParse::write(const SerialFrame &frame)
{
QByteArray byteArray;
char arr[4];
// 帧头
uint8_t len = sizeof(frame.frameHead);
qToBigEndian(frame.frameHead, arr);
byteArray.append(arr, len);
// 帧长度
len = sizeof(frame.frameLen);
qToBigEndian(frame.frameLen, arr);
byteArray.append(arr, len);
// 从机地址
byteArray.append(frame.slaveAddr);
// 帧序号
len = sizeof(frame.frameNo);
qToBigEndian(frame.frameNo, arr);
byteArray.append(arr, len);
// 帧命令
byteArray.append(frame.frameCmd);
// 数据
byteArray.append(frame.realData);
// crc16
uint16_t crc16 = crc16Check((uint8_t *)byteArray.data(), byteArray.size());
len = sizeof(crc16);
qToBigEndian(crc16, arr);
byteArray.append(arr, len);
m_serialPort->write(byteArray);
qDebug()<<"_____write________"<<byteArray.toHex(' ');
}
bool SerialPortDataParse::isReplyFrame(SerialFrame &frame)
{
if (frame.frameCmd == 0x01 || frame.frameCmd == 0x02) {
return true;
}
return false;
}
void SerialPortDataParse::parseCmd0x01Frame(SerialFrame &frame)
{
QVariantMap vMap;
int16_t s16Ntc1 = (frame.realData[0] << 8) + frame.realData[1];
qreal fNtc1 = s16Ntc1*0.1;
vMap.insert("fNtc1", QString::number(fNtc1, 'f', 1));
int16_t s16Ntc2 = (frame.realData[2] << 8) + frame.realData[3];
qreal fNtc2 = s16Ntc2*0.1;
vMap.insert("fNtc2", QString::number(fNtc2, 'f', 1));
int16_t s16Ntc3 = (frame.realData[4] << 8) + frame.realData[5];
qreal fNtc3 = s16Ntc3*0.1;
vMap.insert("fNtc3", QString::number(fNtc3, 'f', 1));
int16_t s16Ntc4 = (frame.realData[6] << 8) + frame.realData[7];
qreal fNtc4 = s16Ntc4*0.1;
vMap.insert("fNtc4", QString::number(fNtc4, 'f', 1));
int16_t s16Ntc5 = (frame.realData[8] << 8) + frame.realData[9];
qreal fNtc5 = s16Ntc5*0.1;
vMap.insert("fNtc5", QString::number(fNtc5, 'f', 1));
int16_t s16HS3002_1_1 = (frame.realData[10] << 8) + frame.realData[11];
qreal fHS3002_1_1 = s16HS3002_1_1*0.1;
vMap.insert("fHS3002_1_1", QString::number(fHS3002_1_1, 'f', 1));
int16_t s16HS3002_1_2 = (frame.realData[12] << 8) + frame.realData[13];
qreal fHS3002_1_2 = s16HS3002_1_2*0.1;
vMap.insert("fHS3002_1_2", QString::number(fHS3002_1_2, 'f', 1));
int16_t s16HS3002_2_1 = (frame.realData[14] << 8) + frame.realData[15];
qreal fHS3002_2_1 = s16HS3002_2_1*0.1;
vMap.insert("fHS3002_2_1", QString::number(fHS3002_2_1, 'f', 1));
int16_t s16HS3002_2_2 = (frame.realData[16] << 8) + frame.realData[17];
qreal fHS3002_2_2 = s16HS3002_2_2*0.1;
vMap.insert("fHS3002_2_2", QString::number(fHS3002_2_2, 'f', 1));
uint16_t u16STK33_1 = (frame.realData[18] << 8) + frame.realData[19];
vMap.insert("u16STK33_1", QString::number(u16STK33_1));
uint16_t u16STK33_2 = (frame.realData[20] << 8) + frame.realData[21];
vMap.insert("u16STK33_2", QString::number(u16STK33_2));
int16_t s16ATC = (frame.realData[22] << 8) + frame.realData[23];
qreal fATC = s16ATC*0.1;
vMap.insert("fATC", QString::number(fATC, 'f', 1));
int16_t s16AHC = (frame.realData[24] << 8) + frame.realData[25];
qreal fAHC = s16AHC*0.1;
vMap.insert("fAHC", QString::number(fAHC, 'f', 1));
emit sig_parseCmd0x01Frame(vMap);
replyCmd0x01Frame(1);
}
void SerialPortDataParse::replyCmd0x01Frame(uint8_t ret)
{
SerialFrame frame;
frame.frameHead = 0xAA55;
frame.frameLen = 10+1;
frame.slaveAddr = 0x01;
frame.frameNo = 0x0001;
frame.frameCmd = 0x01;
frame.realData.append(ret);
frame.crc16 = 0;
QMutexLocker locker(&m_mutex);
m_serialData.append(frame);
}
void SerialPortDataParse::parseCmd0x02Frame(SerialFrame &frame)
{
QVariantMap vMap;
int version = (frame.realData[1] << 16) + (frame.realData[2] << 8) + frame.realData[3];
vMap.insert("version", version);
emit sig_parseCmd0x02Frame(vMap);
replyCmd0x02Frame();
}
void SerialPortDataParse::replyCmd0x02Frame()
{
SerialFrame frame;
frame.frameHead = 0xAA55;
frame.frameLen = 10;
frame.slaveAddr = 0x01;
frame.frameNo = 0x0001;
frame.frameCmd = 0x02;
frame.crc16 = 0;
QMutexLocker locker(&m_mutex);
m_serialData.append(frame);
}
void SerialPortDataParse::parseCmd0x03Frame(SerialFrame &frame)
{
QVariantMap vMap;
int screen = (frame.realData[0] << 8) + frame.realData[1];
vMap.insert("screen", screen);
emit sig_parseCmd0x03Frame(vMap);
replyCmd0x03Frame();
}
void SerialPortDataParse::replyCmd0x03Frame()
{
SerialFrame frame;
frame.frameHead = 0xAA55;
frame.frameLen = 10;
frame.slaveAddr = 0x01;
frame.frameNo = 0x0001;
frame.frameCmd = 0x03;
frame.crc16 = 0;
QMutexLocker locker(&m_mutex);
m_serialData.append(frame);
}
void SerialPortDataParse::parseCmd0xA0Frame(SerialFrame &frame)
{
uint16_t data = (frame.realData[0] << 8) + frame.realData[1];
QVariantMap vMap;
vMap.insert("permission", data);
emit sig_parseCmd0xA0Frame(vMap);
}
void SerialPortDataParse::startSlaveUpgrade(QVariantMap &vMap)
{
uint8_t location = vMap.value("location").toUInt();
uint identify = vMap.value("identify").toUInt();
QByteArray md5 = vMap.value("md5").toByteArray();
uint crc32 = vMap.value("crc32").toUInt();
uint fileSize = vMap.value("fileSize").toUInt();
uint version = vMap.value("version").toUInt();
SerialFrame frame;
frame.frameHead = 0xAA55;
frame.frameLen = 10+50;
frame.slaveAddr = 0x01;
frame.frameNo = 0x0001;
frame.frameCmd = 0xA3;
frame.realData.append(0x01);
frame.realData.append(location);
identify = qToBigEndian(identify);
frame.realData.append((const char *)&identify, sizeof(identify));
frame.realData.append(md5);
crc32 = qToBigEndian(crc32);
frame.realData.append((const char *)&crc32, sizeof(crc32));
fileSize = qToBigEndian(fileSize);
frame.realData.append((const char *)&fileSize, sizeof(fileSize));
version = qToBigEndian(version);
frame.realData.append((const char *)&version, sizeof(version));
frame.crc16 = 0;
QMutexLocker locker(&m_mutex);
m_serialData.append(frame);
}
void SerialPortDataParse::parseCmd0xA3Frame(SerialFrame &frame)
{
QVariantMap vMap;
// flag: 0 不允许升级 1:允许升级
uint8_t flag = frame.realData[0];
vMap.insert("flag", flag);
emit sig_parseCmd0xA3Frame(vMap);
}
void SerialPortDataParse::sendUpgradeData(uint16_t frameNo, QByteArray &byteArray)
{
SerialFrame frame;
frame.frameHead = 0xAA55;
frame.frameLen = 10+byteArray.size();
frame.slaveAddr = 0x01;
frame.frameNo = frameNo;
frame.frameCmd = 0xA4;
frame.realData = byteArray;
frame.crc16 = 0;
QMutexLocker locker(&m_mutex);
m_serialData.append(frame);
}
void SerialPortDataParse::parseCmd0xA4Frame(SerialFrame &frame)
{
QVariantMap vMap;
// flag: 0:失败 1:成功
uint8_t flag = frame.realData[0];
uint16_t frameNo = frame.frameNo;
vMap.insert("flag", flag);
vMap.insert("frameNo", frameNo);
emit sig_parseCmd0xA4Frame(vMap);
}
void SerialPortDataParse::getUpgradeResult()
{
SerialFrame frame;
frame.frameHead = 0xAA55;
frame.frameLen = 10;
frame.slaveAddr = 0x01;
frame.frameNo = 0x0001;
frame.frameCmd = 0xA5;
frame.crc16 = 0;
QMutexLocker locker(&m_mutex);
m_serialData.append(frame);
}
void SerialPortDataParse::parseCmd0xA5Frame(SerialFrame &frame)
{
QVariantMap vMap;
// flag: 0:升级失败 1:升级成功
uint8_t flag = frame.realData[0];
vMap.insert("flag", flag);
emit sig_parseCmd0xA5Frame(vMap);
}
// 将界面下发参数转化为串口数据
void SerialPortDataParse::writeData(const QVariantMap &vMap)
{
}
void SerialPortDataParse::otaPermissionSet(uint16_t &data)
{
SerialFrame frame;
frame.frameHead = 0xAA55;
frame.frameLen = 10+2;
frame.slaveAddr = 0x01;
frame.frameNo = 0x0001;
frame.frameCmd = 0xA0;
data = qToBigEndian(data);
frame.realData.append((const char *)&data, sizeof(data));
frame.crc16 = 0;
QMutexLocker locker(&m_mutex);
m_serialData.append(frame);
}
void SerialPortDataParse::sendData()
{
while (flag) {
QThread::msleep(60);
if (m_serialData.isEmpty()) {
continue;
}
SerialFrame frame;
if (retryFlag) {
if (!m_retryList.isEmpty()) {
QMutexLocker locker(&m_retryMutex);
frame = m_retryList.takeFirst();
locker.unlock();
emit sig_write(frame);
}
} else {
QMutexLocker locker(&m_mutex);
frame = m_serialData.takeFirst();
locker.unlock();
// 非回复帧
if (!isReplyFrame(frame)) {
retryFlag = true;
m_currSendFrame = frame;
emit sig_startTimer();
QMutexLocker locker(&m_retryMutex);
m_retryList.clear();
}
emit sig_write(frame);
}
}
}