diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/PhaseCompAcq/common/utils/SettingConfig.cpp b/PhaseCompAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/PhaseCompAcq/common/utils/SettingConfig.cpp b/PhaseCompAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/PhaseCompAcq/common/utils/SettingConfig.h b/PhaseCompAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/PhaseCompAcq/common/utils/SettingConfig.cpp b/PhaseCompAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/PhaseCompAcq/common/utils/SettingConfig.h b/PhaseCompAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/PhaseCompAcq/main.cpp b/PhaseCompAcq/main.cpp new file mode 100644 index 0000000..adf5eeb --- /dev/null +++ b/PhaseCompAcq/main.cpp @@ -0,0 +1,11 @@ +#include "PhaseWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + PhaseWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/PhaseCompAcq/common/utils/SettingConfig.cpp b/PhaseCompAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/PhaseCompAcq/common/utils/SettingConfig.h b/PhaseCompAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/PhaseCompAcq/main.cpp b/PhaseCompAcq/main.cpp new file mode 100644 index 0000000..adf5eeb --- /dev/null +++ b/PhaseCompAcq/main.cpp @@ -0,0 +1,11 @@ +#include "PhaseWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + PhaseWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.cpp b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp new file mode 100644 index 0000000..79bcaa5 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp @@ -0,0 +1,79 @@ +#include "PhaseProtocolBM.h" +#include + +#if _MSC_VER >= 1600 +#pragma execution_character_set("utf-8") +#endif + +PhaseProtocolBM::PhaseProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +PhaseProtocolBM::~PhaseProtocolBM() +{ + +} + +bool PhaseProtocolBM::parseMessureData(QByteArray rawData, PhaseDataDto * dataObj) +{ + // 获取帧头——帧计数 + QByteArray head = rawData.left(PHASE_FRAME_ID_LENGTH); + dataObj->frameId = QByteUtil::binToHexString(head); + + int j = 0; // 用于转换通道顺序 + + // 获取每个通道的测量数据 + for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) + { + if (i <= 8) + { + j = 2 * i - 1; + + } else + { + j = 2 * (i - 8); + } + + QByteArray channelRaw = rawData.left(PHASE_MESSURE_SIZE * j + PHASE_FRAME_ID_LENGTH).right(PHASE_MESSURE_SIZE); + qulonglong channelRawData = QByteUtil::binToULong(channelRaw, 8); + + if (channelRawData == CALCULATE_OFFSET) + { + dataObj->channelActive.append("0"); + dataObj->channelData.append(0.00); + } else + { + dataObj->channelActive.append("1"); + dataObj->channelData.append((channelRawData - CALCULATE_OFFSET) * CALCULATE_FACTOR); + } + } + + return true; +} + +QString PhaseProtocolBM::startMessure() +{ + return "$START*"; +} +QString PhaseProtocolBM::stopMessure() +{ + return "$$STOP*"; +} + +bool PhaseProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.length() != PHASE_FRAM_LENGTH) + { + return false; + } + + // 帧尾不是0xEEEEEEEE + if (rawData.mid(rawData.length() - PHASE_FRAME_TAIL.size()) != PHASE_FRAME_TAIL) + { + return false; + } + + return true; +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/PhaseCompAcq/common/utils/SettingConfig.cpp b/PhaseCompAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/PhaseCompAcq/common/utils/SettingConfig.h b/PhaseCompAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/PhaseCompAcq/main.cpp b/PhaseCompAcq/main.cpp new file mode 100644 index 0000000..adf5eeb --- /dev/null +++ b/PhaseCompAcq/main.cpp @@ -0,0 +1,11 @@ +#include "PhaseWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + PhaseWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.cpp b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp new file mode 100644 index 0000000..79bcaa5 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp @@ -0,0 +1,79 @@ +#include "PhaseProtocolBM.h" +#include + +#if _MSC_VER >= 1600 +#pragma execution_character_set("utf-8") +#endif + +PhaseProtocolBM::PhaseProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +PhaseProtocolBM::~PhaseProtocolBM() +{ + +} + +bool PhaseProtocolBM::parseMessureData(QByteArray rawData, PhaseDataDto * dataObj) +{ + // 获取帧头——帧计数 + QByteArray head = rawData.left(PHASE_FRAME_ID_LENGTH); + dataObj->frameId = QByteUtil::binToHexString(head); + + int j = 0; // 用于转换通道顺序 + + // 获取每个通道的测量数据 + for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) + { + if (i <= 8) + { + j = 2 * i - 1; + + } else + { + j = 2 * (i - 8); + } + + QByteArray channelRaw = rawData.left(PHASE_MESSURE_SIZE * j + PHASE_FRAME_ID_LENGTH).right(PHASE_MESSURE_SIZE); + qulonglong channelRawData = QByteUtil::binToULong(channelRaw, 8); + + if (channelRawData == CALCULATE_OFFSET) + { + dataObj->channelActive.append("0"); + dataObj->channelData.append(0.00); + } else + { + dataObj->channelActive.append("1"); + dataObj->channelData.append((channelRawData - CALCULATE_OFFSET) * CALCULATE_FACTOR); + } + } + + return true; +} + +QString PhaseProtocolBM::startMessure() +{ + return "$START*"; +} +QString PhaseProtocolBM::stopMessure() +{ + return "$$STOP*"; +} + +bool PhaseProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.length() != PHASE_FRAM_LENGTH) + { + return false; + } + + // 帧尾不是0xEEEEEEEE + if (rawData.mid(rawData.length() - PHASE_FRAME_TAIL.size()) != PHASE_FRAME_TAIL) + { + return false; + } + + return true; +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.h b/PhaseCompAcq/protocol/PhaseProtocolBM.h new file mode 100644 index 0000000..048a9c2 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.h @@ -0,0 +1,36 @@ +#ifndef PHASEPROTOCOLBM_H +#define PHASEPROTOCOLBM_H + +#include + +#include "dto/PhaseDataDto.h" +#include "common/utils/QByteUtil.h" + +static const QByteArray PHASE_FRAME_TAIL("\xEE\xEE\xEE\xEE", 4); // 帧尾 + +static const int PHASE_FRAME_ID_LENGTH = 4; // 帧头id计数器为4个字节 +static const int PHASE_MESSURE_CHANNEL = 16; +static const int PHASE_MESSURE_SIZE = 8; +static const int PHASE_FRAM_LENGTH = PHASE_FRAME_ID_LENGTH + PHASE_FRAME_TAIL.size() + + PHASE_MESSURE_CHANNEL * PHASE_MESSURE_SIZE; + +static const qulonglong CALCULATE_OFFSET = 0X0080000000000000; +static const double CALCULATE_FACTOR = 1.6810E-15; + +class PhaseProtocolBM : public QObject +{ +public: + explicit PhaseProtocolBM(QObject *parent = nullptr); + ~PhaseProtocolBM(); + + // 解析比相仪测量数据 + static bool parseMessureData(QByteArray rawData, PhaseDataDto * phaseData); + + static QString startMessure(); + static QString stopMessure(); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // PHASEROTOCOLBM_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/PhaseCompAcq/common/utils/SettingConfig.cpp b/PhaseCompAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/PhaseCompAcq/common/utils/SettingConfig.h b/PhaseCompAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/PhaseCompAcq/main.cpp b/PhaseCompAcq/main.cpp new file mode 100644 index 0000000..adf5eeb --- /dev/null +++ b/PhaseCompAcq/main.cpp @@ -0,0 +1,11 @@ +#include "PhaseWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + PhaseWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.cpp b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp new file mode 100644 index 0000000..79bcaa5 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp @@ -0,0 +1,79 @@ +#include "PhaseProtocolBM.h" +#include + +#if _MSC_VER >= 1600 +#pragma execution_character_set("utf-8") +#endif + +PhaseProtocolBM::PhaseProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +PhaseProtocolBM::~PhaseProtocolBM() +{ + +} + +bool PhaseProtocolBM::parseMessureData(QByteArray rawData, PhaseDataDto * dataObj) +{ + // 获取帧头——帧计数 + QByteArray head = rawData.left(PHASE_FRAME_ID_LENGTH); + dataObj->frameId = QByteUtil::binToHexString(head); + + int j = 0; // 用于转换通道顺序 + + // 获取每个通道的测量数据 + for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) + { + if (i <= 8) + { + j = 2 * i - 1; + + } else + { + j = 2 * (i - 8); + } + + QByteArray channelRaw = rawData.left(PHASE_MESSURE_SIZE * j + PHASE_FRAME_ID_LENGTH).right(PHASE_MESSURE_SIZE); + qulonglong channelRawData = QByteUtil::binToULong(channelRaw, 8); + + if (channelRawData == CALCULATE_OFFSET) + { + dataObj->channelActive.append("0"); + dataObj->channelData.append(0.00); + } else + { + dataObj->channelActive.append("1"); + dataObj->channelData.append((channelRawData - CALCULATE_OFFSET) * CALCULATE_FACTOR); + } + } + + return true; +} + +QString PhaseProtocolBM::startMessure() +{ + return "$START*"; +} +QString PhaseProtocolBM::stopMessure() +{ + return "$$STOP*"; +} + +bool PhaseProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.length() != PHASE_FRAM_LENGTH) + { + return false; + } + + // 帧尾不是0xEEEEEEEE + if (rawData.mid(rawData.length() - PHASE_FRAME_TAIL.size()) != PHASE_FRAME_TAIL) + { + return false; + } + + return true; +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.h b/PhaseCompAcq/protocol/PhaseProtocolBM.h new file mode 100644 index 0000000..048a9c2 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.h @@ -0,0 +1,36 @@ +#ifndef PHASEPROTOCOLBM_H +#define PHASEPROTOCOLBM_H + +#include + +#include "dto/PhaseDataDto.h" +#include "common/utils/QByteUtil.h" + +static const QByteArray PHASE_FRAME_TAIL("\xEE\xEE\xEE\xEE", 4); // 帧尾 + +static const int PHASE_FRAME_ID_LENGTH = 4; // 帧头id计数器为4个字节 +static const int PHASE_MESSURE_CHANNEL = 16; +static const int PHASE_MESSURE_SIZE = 8; +static const int PHASE_FRAM_LENGTH = PHASE_FRAME_ID_LENGTH + PHASE_FRAME_TAIL.size() + + PHASE_MESSURE_CHANNEL * PHASE_MESSURE_SIZE; + +static const qulonglong CALCULATE_OFFSET = 0X0080000000000000; +static const double CALCULATE_FACTOR = 1.6810E-15; + +class PhaseProtocolBM : public QObject +{ +public: + explicit PhaseProtocolBM(QObject *parent = nullptr); + ~PhaseProtocolBM(); + + // 解析比相仪测量数据 + static bool parseMessureData(QByteArray rawData, PhaseDataDto * phaseData); + + static QString startMessure(); + static QString stopMessure(); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // PHASEROTOCOLBM_H diff --git a/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp b/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp new file mode 100644 index 0000000..604700e --- /dev/null +++ b/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp @@ -0,0 +1,13 @@ +#include "PhaseDataDto.h" + +PhaseDataDto::PhaseDataDto(QObject *parent) : QObject(parent) +{ + this->frameId = ""; + this->timestamp = ""; + this->milisecond = 0; + this->devCode = ""; + this->devStatus = ""; + + this->channelActive = QList(); + this->channelData = QList(); +} diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/PhaseCompAcq/common/utils/SettingConfig.cpp b/PhaseCompAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/PhaseCompAcq/common/utils/SettingConfig.h b/PhaseCompAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/PhaseCompAcq/main.cpp b/PhaseCompAcq/main.cpp new file mode 100644 index 0000000..adf5eeb --- /dev/null +++ b/PhaseCompAcq/main.cpp @@ -0,0 +1,11 @@ +#include "PhaseWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + PhaseWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.cpp b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp new file mode 100644 index 0000000..79bcaa5 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp @@ -0,0 +1,79 @@ +#include "PhaseProtocolBM.h" +#include + +#if _MSC_VER >= 1600 +#pragma execution_character_set("utf-8") +#endif + +PhaseProtocolBM::PhaseProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +PhaseProtocolBM::~PhaseProtocolBM() +{ + +} + +bool PhaseProtocolBM::parseMessureData(QByteArray rawData, PhaseDataDto * dataObj) +{ + // 获取帧头——帧计数 + QByteArray head = rawData.left(PHASE_FRAME_ID_LENGTH); + dataObj->frameId = QByteUtil::binToHexString(head); + + int j = 0; // 用于转换通道顺序 + + // 获取每个通道的测量数据 + for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) + { + if (i <= 8) + { + j = 2 * i - 1; + + } else + { + j = 2 * (i - 8); + } + + QByteArray channelRaw = rawData.left(PHASE_MESSURE_SIZE * j + PHASE_FRAME_ID_LENGTH).right(PHASE_MESSURE_SIZE); + qulonglong channelRawData = QByteUtil::binToULong(channelRaw, 8); + + if (channelRawData == CALCULATE_OFFSET) + { + dataObj->channelActive.append("0"); + dataObj->channelData.append(0.00); + } else + { + dataObj->channelActive.append("1"); + dataObj->channelData.append((channelRawData - CALCULATE_OFFSET) * CALCULATE_FACTOR); + } + } + + return true; +} + +QString PhaseProtocolBM::startMessure() +{ + return "$START*"; +} +QString PhaseProtocolBM::stopMessure() +{ + return "$$STOP*"; +} + +bool PhaseProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.length() != PHASE_FRAM_LENGTH) + { + return false; + } + + // 帧尾不是0xEEEEEEEE + if (rawData.mid(rawData.length() - PHASE_FRAME_TAIL.size()) != PHASE_FRAME_TAIL) + { + return false; + } + + return true; +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.h b/PhaseCompAcq/protocol/PhaseProtocolBM.h new file mode 100644 index 0000000..048a9c2 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.h @@ -0,0 +1,36 @@ +#ifndef PHASEPROTOCOLBM_H +#define PHASEPROTOCOLBM_H + +#include + +#include "dto/PhaseDataDto.h" +#include "common/utils/QByteUtil.h" + +static const QByteArray PHASE_FRAME_TAIL("\xEE\xEE\xEE\xEE", 4); // 帧尾 + +static const int PHASE_FRAME_ID_LENGTH = 4; // 帧头id计数器为4个字节 +static const int PHASE_MESSURE_CHANNEL = 16; +static const int PHASE_MESSURE_SIZE = 8; +static const int PHASE_FRAM_LENGTH = PHASE_FRAME_ID_LENGTH + PHASE_FRAME_TAIL.size() + + PHASE_MESSURE_CHANNEL * PHASE_MESSURE_SIZE; + +static const qulonglong CALCULATE_OFFSET = 0X0080000000000000; +static const double CALCULATE_FACTOR = 1.6810E-15; + +class PhaseProtocolBM : public QObject +{ +public: + explicit PhaseProtocolBM(QObject *parent = nullptr); + ~PhaseProtocolBM(); + + // 解析比相仪测量数据 + static bool parseMessureData(QByteArray rawData, PhaseDataDto * phaseData); + + static QString startMessure(); + static QString stopMessure(); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // PHASEROTOCOLBM_H diff --git a/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp b/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp new file mode 100644 index 0000000..604700e --- /dev/null +++ b/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp @@ -0,0 +1,13 @@ +#include "PhaseDataDto.h" + +PhaseDataDto::PhaseDataDto(QObject *parent) : QObject(parent) +{ + this->frameId = ""; + this->timestamp = ""; + this->milisecond = 0; + this->devCode = ""; + this->devStatus = ""; + + this->channelActive = QList(); + this->channelData = QList(); +} diff --git a/PhaseCompAcq/protocol/dto/PhaseDataDto.h b/PhaseCompAcq/protocol/dto/PhaseDataDto.h new file mode 100644 index 0000000..75af3ee --- /dev/null +++ b/PhaseCompAcq/protocol/dto/PhaseDataDto.h @@ -0,0 +1,26 @@ +#ifndef PHASEDATADTO_H +#define PHASEDATADTO_H + +#include + +class PhaseDataDto : public QObject +{ + Q_OBJECT +public: + explicit PhaseDataDto(QObject *parent = nullptr); + + QString frameId; // 帧id + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QByteArray rawFrame; // 原始帧字节数组 + + QString devCode; + QString devStatus; + QList channelActive; + QList channelData; + +signals: + +}; + +#endif // PHASEDATADTO_H diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/PhaseCompAcq/common/utils/SettingConfig.cpp b/PhaseCompAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/PhaseCompAcq/common/utils/SettingConfig.h b/PhaseCompAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/PhaseCompAcq/main.cpp b/PhaseCompAcq/main.cpp new file mode 100644 index 0000000..adf5eeb --- /dev/null +++ b/PhaseCompAcq/main.cpp @@ -0,0 +1,11 @@ +#include "PhaseWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + PhaseWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.cpp b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp new file mode 100644 index 0000000..79bcaa5 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp @@ -0,0 +1,79 @@ +#include "PhaseProtocolBM.h" +#include + +#if _MSC_VER >= 1600 +#pragma execution_character_set("utf-8") +#endif + +PhaseProtocolBM::PhaseProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +PhaseProtocolBM::~PhaseProtocolBM() +{ + +} + +bool PhaseProtocolBM::parseMessureData(QByteArray rawData, PhaseDataDto * dataObj) +{ + // 获取帧头——帧计数 + QByteArray head = rawData.left(PHASE_FRAME_ID_LENGTH); + dataObj->frameId = QByteUtil::binToHexString(head); + + int j = 0; // 用于转换通道顺序 + + // 获取每个通道的测量数据 + for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) + { + if (i <= 8) + { + j = 2 * i - 1; + + } else + { + j = 2 * (i - 8); + } + + QByteArray channelRaw = rawData.left(PHASE_MESSURE_SIZE * j + PHASE_FRAME_ID_LENGTH).right(PHASE_MESSURE_SIZE); + qulonglong channelRawData = QByteUtil::binToULong(channelRaw, 8); + + if (channelRawData == CALCULATE_OFFSET) + { + dataObj->channelActive.append("0"); + dataObj->channelData.append(0.00); + } else + { + dataObj->channelActive.append("1"); + dataObj->channelData.append((channelRawData - CALCULATE_OFFSET) * CALCULATE_FACTOR); + } + } + + return true; +} + +QString PhaseProtocolBM::startMessure() +{ + return "$START*"; +} +QString PhaseProtocolBM::stopMessure() +{ + return "$$STOP*"; +} + +bool PhaseProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.length() != PHASE_FRAM_LENGTH) + { + return false; + } + + // 帧尾不是0xEEEEEEEE + if (rawData.mid(rawData.length() - PHASE_FRAME_TAIL.size()) != PHASE_FRAME_TAIL) + { + return false; + } + + return true; +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.h b/PhaseCompAcq/protocol/PhaseProtocolBM.h new file mode 100644 index 0000000..048a9c2 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.h @@ -0,0 +1,36 @@ +#ifndef PHASEPROTOCOLBM_H +#define PHASEPROTOCOLBM_H + +#include + +#include "dto/PhaseDataDto.h" +#include "common/utils/QByteUtil.h" + +static const QByteArray PHASE_FRAME_TAIL("\xEE\xEE\xEE\xEE", 4); // 帧尾 + +static const int PHASE_FRAME_ID_LENGTH = 4; // 帧头id计数器为4个字节 +static const int PHASE_MESSURE_CHANNEL = 16; +static const int PHASE_MESSURE_SIZE = 8; +static const int PHASE_FRAM_LENGTH = PHASE_FRAME_ID_LENGTH + PHASE_FRAME_TAIL.size() + + PHASE_MESSURE_CHANNEL * PHASE_MESSURE_SIZE; + +static const qulonglong CALCULATE_OFFSET = 0X0080000000000000; +static const double CALCULATE_FACTOR = 1.6810E-15; + +class PhaseProtocolBM : public QObject +{ +public: + explicit PhaseProtocolBM(QObject *parent = nullptr); + ~PhaseProtocolBM(); + + // 解析比相仪测量数据 + static bool parseMessureData(QByteArray rawData, PhaseDataDto * phaseData); + + static QString startMessure(); + static QString stopMessure(); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // PHASEROTOCOLBM_H diff --git a/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp b/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp new file mode 100644 index 0000000..604700e --- /dev/null +++ b/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp @@ -0,0 +1,13 @@ +#include "PhaseDataDto.h" + +PhaseDataDto::PhaseDataDto(QObject *parent) : QObject(parent) +{ + this->frameId = ""; + this->timestamp = ""; + this->milisecond = 0; + this->devCode = ""; + this->devStatus = ""; + + this->channelActive = QList(); + this->channelData = QList(); +} diff --git a/PhaseCompAcq/protocol/dto/PhaseDataDto.h b/PhaseCompAcq/protocol/dto/PhaseDataDto.h new file mode 100644 index 0000000..75af3ee --- /dev/null +++ b/PhaseCompAcq/protocol/dto/PhaseDataDto.h @@ -0,0 +1,26 @@ +#ifndef PHASEDATADTO_H +#define PHASEDATADTO_H + +#include + +class PhaseDataDto : public QObject +{ + Q_OBJECT +public: + explicit PhaseDataDto(QObject *parent = nullptr); + + QString frameId; // 帧id + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QByteArray rawFrame; // 原始帧字节数组 + + QString devCode; + QString devStatus; + QList channelActive; + QList channelData; + +signals: + +}; + +#endif // PHASEDATADTO_H diff --git a/PhaseCompAcq/protocol/protocol.pri b/PhaseCompAcq/protocol/protocol.pri new file mode 100644 index 0000000..d998e2e --- /dev/null +++ b/PhaseCompAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/PhaseProtocolBM.cpp +SOURCES += $$PWD/dto/PhaseDataDto.cpp + +HEADERS += $$PWD/PhaseProtocolBM.h +HEADERS += $$PWD/dto/PhaseDataDto.h diff --git a/CounterAcq/CounterAcq.pro b/CounterAcq/CounterAcq.pro new file mode 100644 index 0000000..061f942 --- /dev/null +++ b/CounterAcq/CounterAcq.pro @@ -0,0 +1,27 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + CounterWindow.cpp \ + main.cpp \ + +HEADERS += \ + CounterWindow.h \ + +FORMS += \ + CounterWindow.ui \ + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h + +SOURCES += CounterDevice.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp new file mode 100644 index 0000000..3dc812b --- /dev/null +++ b/CounterAcq/CounterDevice.cpp @@ -0,0 +1,123 @@ +#include "CounterDevice.h" + +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +CounterDevice::~CounterDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); +} + +void CounterDevice::setComName(QString comName) +{ + this->comName = comName; +} +void CounterDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString CounterDevice::getDevCode() +{ + return this->devCode; +} +void CounterDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool CounterDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void CounterDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + + +void CounterDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + CounterDataDto * counterData = new CounterDataDto(this); + if (CounterProtocolBM::checkFrame(this->dataBuff) == true) + { + counterData->rawFrame = this->dataBuff; + std::cout << counterData->rawFrame.toStdString() << std::endl; + + // ★解析成数据对象 + bool parse = CounterProtocolBM::parseMessureData(this->dataBuff, counterData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + std::cout << counterData->frameId.toStdString() << ", " << counterData->timestamp.toStdString() << ", " << counterData->milisecond << std::endl; +// for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) +// { +// if (phaseData->channelActive.at(i-1).toInt() != 0) +// { +// std::cout << "ch: " << i << ", " << phaseData->channelData.at(i-1) << std::endl; +// } +// } + + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = counterData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 +// for (int i = 1; i <= phaseData->channelActive.size(); i++) +// { +// if (phaseData->channelActive.at(i-1).toUInt() == 1) +// { +// QString chFilename("%1CH_%2_%3.log"); +// chFilename = chFilename.arg(filePrefix); +// if (i < 10) +// { +// chFilename = chFilename.arg(QString("0%1").arg(i)); +// } else +// { +// chFilename = chFilename.arg(i); +// } +// chFilename = chFilename.arg(filePostfix); +// QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + +// QLogUtil::writeChannelDataLog(chFilename, channelDataStr); +// } +// } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 +// emit this->sendDataToDraw(counterData); +} diff --git a/CounterAcq/CounterDevice.h b/CounterAcq/CounterDevice.h new file mode 100644 index 0000000..3ca84da --- /dev/null +++ b/CounterAcq/CounterDevice.h @@ -0,0 +1,44 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void afterFramePhase(CounterDataDto * counterData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); + +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterWindow.cpp b/CounterAcq/CounterWindow.cpp new file mode 100644 index 0000000..bc94305 --- /dev/null +++ b/CounterAcq/CounterWindow.cpp @@ -0,0 +1,40 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + CounterDevice * device = new CounterDevice(this); + + // +// connect(device, &CounterDevice::sendDataToDraw, +// this, &CounterWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + +// this->deviceList.append(device); + + device->initSerialPort(); +// device->startWork(); + } +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} diff --git a/CounterAcq/CounterWindow.h b/CounterAcq/CounterWindow.h new file mode 100644 index 0000000..8bae180 --- /dev/null +++ b/CounterAcq/CounterWindow.h @@ -0,0 +1,24 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include "common/utils/SettingConfig.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +private: + Ui::CounterWindow *ui; +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterWindow.ui b/CounterAcq/CounterWindow.ui new file mode 100644 index 0000000..0b19cdd --- /dev/null +++ b/CounterAcq/CounterWindow.ui @@ -0,0 +1,21 @@ + + + + + CounterWindow + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/CounterAcq/common/common.pri b/CounterAcq/common/common.pri new file mode 100644 index 0000000..cbcd7e5 --- /dev/null +++ b/CounterAcq/common/common.pri @@ -0,0 +1,10 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h diff --git a/CounterAcq/common/utils/QByteUtil.cpp b/CounterAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/CounterAcq/common/utils/QByteUtil.h b/CounterAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/CounterAcq/common/utils/QLogUtil.cpp b/CounterAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/CounterAcq/common/utils/QLogUtil.h b/CounterAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/CounterAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/common/utils/QSerialPortUtil.cpp b/CounterAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/CounterAcq/common/utils/QSerialPortUtil.h b/CounterAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/CounterAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/common/utils/SettingConfig.cpp b/CounterAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/CounterAcq/common/utils/SettingConfig.h b/CounterAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/CounterAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/main.cpp b/CounterAcq/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcq/main.cpp @@ -0,0 +1,11 @@ +#include "CounterWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CounterWindow w; + w.show(); + return a.exec(); +} diff --git a/CounterAcq/protocol/CounterProtocolBM.cpp b/CounterAcq/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..63a047b --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.cpp @@ -0,0 +1,64 @@ +#include "CounterProtocolBM.h" +#include + +CounterProtocolBM::CounterProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +CounterProtocolBM::~CounterProtocolBM() +{ + +} + +bool CounterProtocolBM::parseMessureData(QByteArray rawData, CounterDataDto * counterData) +{ + int start = rawData.indexOf(COUNTER_FRAME_CONTENT_SEP); + int end = rawData.indexOf(COUNTER_FRAME_SUM_SEP); + + QByteArray content = rawData.mid(start + 1, end - start - 1); + QString contentStr = QString(content); + QStringList subList = contentStr.split(","); + + std::cout << contentStr.toStdString() << std::endl; + + counterData->type = subList.at(0).toUInt(); + counterData->channelId = subList.at(1).toUInt(); + counterData->channelActive = subList.at(2).toUInt(); + counterData->channelRefId = subList.at(3).toUInt(); + counterData->channelData = subList.at(4).toULongLong(); + counterData->load = subList.at(5).toDouble(); + counterData->level = subList.at(6).toDouble(); + counterData->frameId = subList.at(7); + + return true; +} + +bool CounterProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.size() < COUNTER_FRAME_MIN_LENGTH) + { + return false; + } + + // 帧头不是$GL + if (COUNTER_FRAME_HEAD.toLocal8Bit() != rawData.mid(0, COUNTER_FRAME_HEAD.size())) + { + return false; + } + + // 帧尾不是\r\n + if (COUNTER_FRAME_TAIL.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size())) + { + return false; + } + + // 校验和的分隔符不是* + if (COUNTER_FRAME_SUM_SEP.toLocal8Bit() != rawData.mid(rawData.size() - COUNTER_FRAME_TAIL.size() - 2 - 1, 1)) + { + return false; + } + + return true; +} diff --git a/CounterAcq/protocol/CounterProtocolBM.h b/CounterAcq/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcq/protocol/CounterProtocolBM.h @@ -0,0 +1,34 @@ +#ifndef COUNTERPROTOCOLBM_H +#define COUNTERPROTOCOLBM_H + +#include + +#include "dto/CounterDataDto.h" + +static const QString COUNTER_FRAME_HEAD = "$GL"; // 帧头 +static const QString COUNTER_FRAME_TAIL = "\r\n"; // 帧尾 +static const QString COUNTER_FRAME_CONTENT_SEP = ","; // 帧内分隔符 +static const QString COUNTER_FRAME_SUM_SEP = "*"; // 异或和字段的分隔符 + +static const int COUNTER_FRAME_SUM_LENGTH = 2; +static const int COUNTER_FRAME_SUB_COUNT = 8; +static const int COUNTER_FRAME_SUB_MIN_SIZE = 2; +static const int COUNTER_FRAME_MIN_LENGTH = COUNTER_FRAME_HEAD.length() + + COUNTER_FRAME_TAIL.length() + + COUNTER_FRAME_SUB_COUNT * COUNTER_FRAME_SUB_MIN_SIZE + + 1 + COUNTER_FRAME_SUM_LENGTH; + +class CounterProtocolBM : public QObject +{ +public: + explicit CounterProtocolBM(QObject *parent = nullptr); + ~CounterProtocolBM(); + + // 解析计数器测量数据 + static bool parseMessureData(QByteArray rawData, CounterDataDto * counterData); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // COUNTERPROTOCOLBM_H diff --git a/CounterAcq/protocol/dto/CounterDataDto.cpp b/CounterAcq/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..3ceb810 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,6 @@ +#include "CounterDataDto.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} diff --git a/CounterAcq/protocol/dto/CounterDataDto.h b/CounterAcq/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..96dd4c0 --- /dev/null +++ b/CounterAcq/protocol/dto/CounterDataDto.h @@ -0,0 +1,32 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include + +class CounterDataDto : public QObject +{ + Q_OBJECT +public: + explicit CounterDataDto(QObject *parent = nullptr); + + QString frameId; // 帧ID -- <8> + double level; // 触发电平浮点数 -- <7> + QString load; // 负载(0=50欧姆,1=1M欧姆) -- <6> + qulonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri new file mode 100644 index 0000000..fd0ab7d --- /dev/null +++ b/CounterAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/DevStatusAcq/DevStatusAcq.pro b/DevStatusAcq/DevStatusAcq.pro new file mode 100644 index 0000000..ae92758 --- /dev/null +++ b/DevStatusAcq/DevStatusAcq.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + DevStatusWindow.cpp + +HEADERS += \ + DevStatusWindow.h + +FORMS += \ + DevStatusWindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/DevStatusAcq/DevStatusWindow.cpp b/DevStatusAcq/DevStatusWindow.cpp new file mode 100644 index 0000000..29a4899 --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.cpp @@ -0,0 +1,15 @@ +#include "DevStatusWindow.h" +#include "ui_DevStatusWindow.h" + +DevStatusWindow::DevStatusWindow(QWidget *parent) + : QWidget(parent) + , ui(new Ui::DevStatusWindow) +{ + ui->setupUi(this); +} + +DevStatusWindow::~DevStatusWindow() +{ + delete ui; +} + diff --git a/DevStatusAcq/DevStatusWindow.h b/DevStatusAcq/DevStatusWindow.h new file mode 100644 index 0000000..2cad41c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.h @@ -0,0 +1,21 @@ +#ifndef DEVSTATUSWINDOW_H +#define DEVSTATUSWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class DevStatusWindow; } +QT_END_NAMESPACE + +class DevStatusWindow : public QWidget +{ + Q_OBJECT + +public: + DevStatusWindow(QWidget *parent = nullptr); + ~DevStatusWindow(); + +private: + Ui::DevStatusWindow *ui; +}; +#endif // DEVSTATUSWINDOW_H diff --git a/DevStatusAcq/DevStatusWindow.ui b/DevStatusAcq/DevStatusWindow.ui new file mode 100644 index 0000000..1de0a2c --- /dev/null +++ b/DevStatusAcq/DevStatusWindow.ui @@ -0,0 +1,19 @@ + + + DevStatusWindow + + + + 0 + 0 + 800 + 600 + + + + DevStatusWindow + + + + + diff --git a/DevStatusAcq/main.cpp b/DevStatusAcq/main.cpp new file mode 100644 index 0000000..abfa6d3 --- /dev/null +++ b/DevStatusAcq/main.cpp @@ -0,0 +1,11 @@ +#include "DevStatusWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + DevStatusWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/PhaseCompAcq.pro b/PhaseCompAcq/PhaseCompAcq.pro new file mode 100644 index 0000000..3a17537 --- /dev/null +++ b/PhaseCompAcq/PhaseCompAcq.pro @@ -0,0 +1,35 @@ +QT += core gui serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + PhaseWindow.cpp + +HEADERS += \ + PhaseWindow.h + +FORMS += \ + PhaseWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += PhaseDevice.h +#HEADERS += PhaseSerialServer.h + +SOURCES += PhaseDevice.cpp +#SOURCES += PhaseSerialServer.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +win32: LIBS += -L$$PWD/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/librdkafka/include +DEPENDPATH += $$PWD/librdkafka/include diff --git a/PhaseCompAcq/PhaseDevice.cpp b/PhaseCompAcq/PhaseDevice.cpp new file mode 100644 index 0000000..3a75d94 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.cpp @@ -0,0 +1,122 @@ +#include "PhaseDevice.h" +#include +#include + +PhaseDevice::PhaseDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +PhaseDevice::~PhaseDevice() +{ + disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &PhaseDevice::dataReceivedHandler); +} + +void PhaseDevice::setComName(QString comName) +{ + this->comName = comName; +} +void PhaseDevice::setBaudRate(int baudRate) +{ + this->baudRate = baudRate; +} +QString PhaseDevice::getDevCode() +{ + return this->devCode; +} +void PhaseDevice::setDevCode(QString devCode) +{ + this->devCode = devCode; +} + +bool PhaseDevice::isSerialOpen() +{ + return this->serialUtil.isOpen(); +} + +void PhaseDevice::initSerialPort() +{ + this->serialUtil.openSerialPort(this->comName, this->baudRate); +} + +void PhaseDevice::startWork() +{ + QString startCommand = PhaseProtocolBM::startMessure(); + this->serialUtil.sendData(startCommand.toLocal8Bit()); +} + +void PhaseDevice::stopWork() +{ + +} + +void PhaseDevice::dataReceivedHandler(QByteArray data) +{ + this->dataBuff.append(data); + + PhaseDataDto * phaseData = new PhaseDataDto(this); + if (PhaseProtocolBM::checkFrame(this->dataBuff) == true) + { + phaseData->rawFrame = this->dataBuff; + + // ★解析成数据对象 + bool parse = PhaseProtocolBM::parseMessureData(this->dataBuff, phaseData); + + // 解析成功 + if (parse == true) + { + QDateTime now = QDateTime::currentDateTime(); + phaseData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + phaseData->milisecond = now.toMSecsSinceEpoch(); + this->afterFramePhase(phaseData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + // 具体原因不明 + delete phaseData; +} + +void PhaseDevice::afterFramePhase(PhaseDataDto * phaseData) +{ + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 输出到日志文件中 + QString filePostfix = phaseData->timestamp.mid(0, 13).replace(" ", "_"); + QString filePrefix = QApplication::applicationDirPath() + "/logs/"; + + // 2.1 原始字节数组数据 + QString filename = filePrefix + "raw_" + filePostfix + ".log"; + QString content = phaseData->timestamp + " " + QByteUtil::binToHexString(phaseData->rawFrame); + QLogUtil::writeRawDataLog(filename, content); + + // 2.2 各个通道的相差数据 + for (int i = 1; i <= phaseData->channelActive.size(); i++) + { + if (phaseData->channelActive.at(i-1).toUInt() == 1) + { + QString chFilename("%1CH_%2_%3.log"); + chFilename = chFilename.arg(filePrefix); + if (i < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(i)); + } else + { + chFilename = chFilename.arg(i); + } + chFilename = chFilename.arg(filePostfix); + QString channelDataStr = QString("%1 %2 %3").arg(phaseData->timestamp).arg(phaseData->channelData.at(i-1)).arg(phaseData->frameId); + + QLogUtil::writeChannelDataLog(chFilename, channelDataStr); + } + } + + // 3. 输出到中间件,执行后续处理过程 + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(phaseData); +} diff --git a/PhaseCompAcq/PhaseDevice.h b/PhaseCompAcq/PhaseDevice.h new file mode 100644 index 0000000..630a0e7 --- /dev/null +++ b/PhaseCompAcq/PhaseDevice.h @@ -0,0 +1,44 @@ +#ifndef PHASEDEVICE_H +#define PHASEDEVICE_H + +#include +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QLogUtil.h" +#include "protocol/PhaseProtocolBM.h" + +class PhaseDevice : public QObject +{ + Q_OBJECT +public: + explicit PhaseDevice(QObject *parent = nullptr); + ~PhaseDevice(); + + void initSerialPort(); + void startWork(); + void stopWork(); + + void afterFramePhase(PhaseDataDto * phaseData); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + + bool isSerialOpen(); +private: + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QByteArray dataBuff; + +signals: + void sendDataToDraw(PhaseDataDto * phaseData); + +public slots: + void dataReceivedHandler(QByteArray data); + +}; + +#endif // PHASEDEVICE_H diff --git a/PhaseCompAcq/PhaseWindow.cpp b/PhaseCompAcq/PhaseWindow.cpp new file mode 100644 index 0000000..8999d5c --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.cpp @@ -0,0 +1,159 @@ +#include "PhaseWindow.h" +#include "ui_PhaseWindow.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/utils/QKafkaUtil.h" + +PhaseWindow::PhaseWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::PhaseWindow) +{ + ui->setupUi(this); + +// QKafkaUtil * kafkaTest = new QKafkaUtil(this); +// kafkaTest->setBrokers("111.198.10.15:12502"); +// kafkaTest->setTopic("cppTest"); +// int kaf = kafkaTest->initKafkaConf(); +// std::cout << "init kafka cppTest: " << kaf << std::endl; + + QString portNames = SettingConfig::getInstance().PORT_NAMES; + int baudRate = SettingConfig::getInstance().BAUD_RATE; + QString devCodes = SettingConfig::getInstance().DEV_CODES; + + QStringList comDevList = portNames.split(","); + QStringList devCodeList = devCodes.split(","); + + for (int i = 0; i < comDevList.size(); i++) + { + PhaseDevice * device = new PhaseDevice(this); + + // + connect(device, &PhaseDevice::sendDataToDraw, + this, &PhaseWindow::drawPhaseDataOnPage); + + device->setComName(comDevList.at(i)); + device->setBaudRate(baudRate); + + device->setDevCode(devCodeList.at(i)); + + this->deviceList.append(device); + + device->initSerialPort(); + device->startWork(); + } + + for (int i = 0; i < this->deviceList.size(); i++) + { + QWidget * devWidget5 = new QWidget(this->ui->stackedWidget); + + this->ui->stackedWidget->addWidget(devWidget5); + + this->devWidgetList.append(devWidget5); + + // 创建设备的widget + this->generateWidgetForDevice(devCodeList.at(i), i); + } +} + +PhaseWindow::~PhaseWindow() +{ + delete ui; +} + +void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData) +{ + // 1. 判断数据属于哪个设备,显示在不同的widget上 + + // 2. 循环设置各个tableView + QList devChannels = this->tableModelList.at(2); // 暂时写死 + for (int i = 0; i < phaseData->channelData.size(); i++) + { + if (phaseData->channelActive.at(i).toInt() == 1) + { + QList row; + QStandardItem * item = 0; + QStandardItem * item2 = 0; + item = new QStandardItem(QString("%1").arg(phaseData->timestamp.mid(11, 12))); + item2 = new QStandardItem(QString("%1").arg(phaseData->channelData.at(i))); + + row.append(item); + row.append(item2); + + QStandardItemModel * model; + model = devChannels.at(i); + if (model->rowCount() >= 60) + { + model->removeRows(0, model->rowCount()); + } + + model->insertRow(0, row); + } + } +} + +void PhaseWindow::generateWidgetForDevice(QString devCode, int index) +{ + // 顶部切换widget + QWidget * switchWidget = new QWidget(this->devWidgetList.at(index)); + switchWidget->setGeometry(0, 0, 1024, 50); + + // 显示数据的区域 + QWidget * gridWidget = new QWidget(this->devWidgetList.at(index)); + gridWidget->setGeometry(0, 50, 1024, 670); + + // 顶部水平布局,用于排布按钮 + QHBoxLayout * hLayout = new QHBoxLayout(switchWidget); + + // 文本 + QLabel * label = new QLabel(switchWidget); + label->setText("设备编号:" + devCode); + label->setFont(QFont("微软雅黑", 12)); + hLayout->addWidget(label); + + // 按钮 + for (int i = 0; i < this->deviceList.size(); i++) + { + QPushButton * butt5 = new QPushButton(this->deviceList.at(i)->getDevCode()); + hLayout->addWidget(butt5); + + connect(butt5, &QPushButton::clicked, [=](){ + this->ui->stackedWidget->setCurrentIndex(i); + }); + } + + // Grid布局 + QGridLayout * gridLayout = new QGridLayout(gridWidget); + gridLayout->setSpacing(10); + + QList channelModelList; + QStringList labels = QObject::trUtf8("时间,相差").simplified().split(","); + + for (int i = 0; i < 16; i++) + { + QTableView * channelTable = new QTableView(gridWidget); + QStandardItemModel * model = new QStandardItemModel(channelTable); + + model->setHorizontalHeaderLabels(labels); + + channelTable->setModel(model); + + gridLayout->addWidget(channelTable, i / 4, i % 4); + + channelTable->verticalHeader()->hide(); + channelTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + channelTable->scrollToBottom(); + + channelModelList.append(model); + } + + this->tableModelList.append(channelModelList); +} + diff --git a/PhaseCompAcq/PhaseWindow.h b/PhaseCompAcq/PhaseWindow.h new file mode 100644 index 0000000..abd1823 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.h @@ -0,0 +1,36 @@ +#ifndef PHASEWINDOW_H +#define PHASEWINDOW_H + +#include +#include + +#include "PhaseDevice.h" +#include "common/utils/SettingConfig.h" + +namespace Ui { +class PhaseWindow; +} + +class PhaseWindow : public QWidget +{ + Q_OBJECT + +public: + explicit PhaseWindow(QWidget *parent = nullptr); + ~PhaseWindow(); + +public slots: + void drawPhaseDataOnPage(PhaseDataDto * phaseData); + +private: + Ui::PhaseWindow *ui; + + QList devWidgetList; + + QList deviceList; + QList> tableModelList; + + void generateWidgetForDevice(QString devCode, int index); +}; + +#endif // PHASEWINDOW_H diff --git a/PhaseCompAcq/PhaseWindow.ui b/PhaseCompAcq/PhaseWindow.ui new file mode 100644 index 0000000..e6da880 --- /dev/null +++ b/PhaseCompAcq/PhaseWindow.ui @@ -0,0 +1,38 @@ + + + PhaseWindow + + + + 0 + 0 + 1024 + 720 + + + + + 1024 + 720 + + + + 多通道比相仪数据采集 + + + + + 0 + 0 + 1024 + 720 + + + + -1 + + + + + + diff --git a/PhaseCompAcq/common/common.pri b/PhaseCompAcq/common/common.pri new file mode 100644 index 0000000..055a2db --- /dev/null +++ b/PhaseCompAcq/common/common.pri @@ -0,0 +1,12 @@ + +SOURCES += $$PWD/utils/SettingConfig.cpp +SOURCES += $$PWD/utils/QByteUtil.cpp +SOURCES += $$PWD/utils/QSerialPortUtil.cpp +SOURCES += $$PWD/utils/QLogUtil.cpp +SOURCES += $$PWD/utils/QKafkaUtil.cpp + +HEADERS += $$PWD/utils/SettingConfig.h +HEADERS += $$PWD/utils/QByteUtil.h +HEADERS += $$PWD/utils/QSerialPortUtil.h +HEADERS += $$PWD/utils/QLogUtil.h +HEADERS += $$PWD/utils/QKafkaUtil.h diff --git a/PhaseCompAcq/common/utils/QByteUtil.cpp b/PhaseCompAcq/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.cpp @@ -0,0 +1,177 @@ +#include "QByteUtil.h" +#include + +static uchar uc = 0x00; +const int FLOAT_BYTE_LENGTH = 4; +const int DOUBLE_BYTE_LENGTH = 8; + +QByteUtil::QByteUtil(QObject *parent) : QObject(parent) +{ + +} + +QByteArray QByteUtil::appendZeroAlign(QByteArray array, int count) +{ + // 如果字节数组的长度不足cout的倍数,在字节数组的前段补0x00 + int rem = array.length() % count; + if (rem > 0) + { + array.insert(0, count - rem, uc); + } + + return array; +} + +QString QByteUtil::binToHexString(QByteArray bytes) +{ + return bytes.toHex().toUpper(); +} + +QByteArray QByteUtil::hexStringToBytes(QString hexString) +{ + hexString = hexString.toUpper(); + if (hexString.length() % 2 == 1) + { + hexString = "0" + hexString; + } + + bool ok; + QByteArray bytes; + for (int i = 0; i < hexString.length() - 1; i = i + 2) + { + QString str = hexString.mid(i, 2); + bytes.append(str.toInt(&ok, 16)); + } + + return bytes; +} + +qulonglong QByteUtil::binToULong(QByteArray bytes, quint8 length) +{ + qulonglong value = 0; + + for (int i = 0; i < bytes.length() && i < length; i++) + { + value = value * 256 + (quint8) bytes.at(i); + } + + return value; +} + + +float QByteUtil::binToFloat(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // 如果字节数组长度超过4位,取前4位 + QString str = QByteUtil::binToHexString(bytes.mid(0, FLOAT_BYTE_LENGTH)); + int hex = str.toUInt(0, 16); + float ret = *(float*) &hex; + + return ret; +} + +QVector QByteUtil::binToFloatArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, FLOAT_BYTE_LENGTH); + + // float用4字节浮点数表示 + int length = bytes.length() / FLOAT_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 4个字节的浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * FLOAT_BYTE_LENGTH, FLOAT_BYTE_LENGTH)); + + int hex = str.toUInt(0, 16); + float fl = *(float*) &hex; + + ret.append(fl); + } + + return ret; +} + +QByteArray QByteUtil::floatToBytes(float value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < FLOAT_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::floatArrayToBytes(QVector floatArray) +{ + QByteArray ret; + for (int i = 0; i < floatArray.length(); i++) + { + ret.append(floatToBytes(floatArray.at(i))); + } + return ret; +} + + +double QByteUtil::binToDouble(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // 如果字节数组长度超过8位,取前8位 + QString str = QByteUtil::binToHexString(bytes.mid(0, DOUBLE_BYTE_LENGTH)); + qulonglong hex = str.toULongLong(0, 16); + double ret = *(double*) &hex; + + return ret; +} + +QVector QByteUtil::binToDoubleArray(QByteArray bytes) +{ + bytes = appendZeroAlign(bytes, DOUBLE_BYTE_LENGTH); + + // double用8字节浮点数表示 + int length = bytes.length() / DOUBLE_BYTE_LENGTH; + + // 返回值 + QVector ret; + + // 8个字节的双精度浮点数,转换为 + for (int i = 0; i < length; i++) + { + QString str = QByteUtil::binToHexString(bytes.mid(i * DOUBLE_BYTE_LENGTH, DOUBLE_BYTE_LENGTH)); + + qulonglong hex = str.toULongLong(0, 16); + double dl = *(double*) &hex; + + ret.append(dl); + } + + return ret; +} + +QByteArray QByteUtil::doubleToBytes(double value) +{ + uchar * hex = (uchar *) &value; + QByteArray ret; + for (int i = 0; i < DOUBLE_BYTE_LENGTH; i++) + { + ret.insert(0, hex[i]); + } + + return ret; +} + +QByteArray QByteUtil::doubleArrayToBytes(QVector doubleArray) +{ + QByteArray ret; + for (int i = 0; i < doubleArray.length(); i++) + { + ret.append(doubleToBytes(doubleArray.at(i))); + } + return ret; +} diff --git a/PhaseCompAcq/common/utils/QByteUtil.h b/PhaseCompAcq/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/PhaseCompAcq/common/utils/QByteUtil.h @@ -0,0 +1,115 @@ +#ifndef QBYTEUTIL_H +#define QBYTEUTIL_H + +#include + +class QByteUtil : public QObject +{ + Q_OBJECT +public: + explicit QByteUtil(QObject *parent = nullptr); + + + /******** 字节数组与字符串互转 ********/ + /** + * @brief binToHexString + * @param bytes + * @note 16进制字节数组转字符串,用于输出显示,不含空格 + * @return + */ + static QString binToHexString(QByteArray bytes); + /** + * @brief hexStringToBytes + * @param hexString + * @note 16进制字符串转字节数组,不含空格 + * @return + */ + static QByteArray hexStringToBytes(QString hexString); + + /******** 字节数组与long互转 ********/ + /** + * @brief binToULong + * @param bytes + * @note 16进制字节数组转无符号long,length个字节。字符串顺序,高位在前,低位在后 + * 如0x0080000000086A43 = 36028797019515459 + * @return + */ + static qulonglong binToULong(QByteArray bytes, quint8 length); + static QByteArray ULongToBytes(qulonglong value); + + /******** 字节数组与float互转 ********/ + /** + * @brief binToFloat + * @param bytes + * @note 4个字节转float浮点数,从左到右排序 + * @example {0x42, 0xF6, 0xE6, 0x66} 转换为 123.45 + * @return + */ + static float binToFloat(QByteArray bytes); + /** + * @brief binToFloatArray + * @param bytes + * @note 字节数组转float数组,16进制浮点数,4个字节表示1个float浮点数,从左到右排序 + * @example {0xBD, 0x1F, 0xB1, 0xDA, 0x40, 0x63, 0x02, 0x0C, 0x40, 0x49, 0x0F, 0xDA} 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToFloatArray(QByteArray bytes); + /** + * @brief floatToBytes + * @param value + * @note 单个float数转4字节数组,从左至右排序 + * @example 123.45 转换为 {0x42, 0xF6, 0xE6, 0x66} + * @return + */ + static QByteArray floatToBytes(float value); + /** + * @brief floatArrayToBytes + * @param floatArray + * @note float数组转换为字节数组,每一个float浮点数4字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 {0x3D, 0x79, 0x09, 0x6C, 0x40, 0x12, 0x7C, 0x5B, 0x3B, 0xDE, 0x9A, 0x3F} + * @return + */ + static QByteArray floatArrayToBytes(QVector floatArray); + + /******** 字节数组与double互转 ********/ + /** + * @brief binToDouble + * @param bytes + * @note 8个字节转double双精度浮点数,从左到右排序 + * @example C00921FB53D92715 转换为 -3.141592650475 + * @return + */ + static double binToDouble(QByteArray bytes); + /** + * @brief binToDoubleArray + * @param bytes + * @note 字节数组转double数组,16进制双精度浮点数,8个字节表示1个double浮点数,从左到右排序 + * @example BFA3F63C31DF761D400C604189374BC74039B2DE00D1B717 转换为 -0.038988, 3.547, 3.141593 + * @return + */ + static QVector binToDoubleArray(QByteArray bytes); + /** + * @brief doubleToBytes + * @param value + * @note 单个double数转换为8字节数组,从左到右排序 + * @example 123.45 转换为 405EDCCCCCCCCCCD + * @return + */ + static QByteArray doubleToBytes(double value); + /** + * @brief doubleArrayToBytes + * @param doubleArray + * @note double数组转换为字节数组,每个double双精度浮点数8字节,从左到右排序 + * @example 0.0608, 2.28884, 0.00679329 转换为 3FAF212D77318FC540024F8B588E368F3F7BD347E61DABB7 + * @return + */ + static QByteArray doubleArrayToBytes(QVector doubleArray); + +private: + static QByteArray appendZeroAlign(QByteArray array, int count); + +signals: + +}; + +#endif // QBYTEUTIL_H diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.cpp b/PhaseCompAcq/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..6ecd6f0 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.cpp @@ -0,0 +1,40 @@ +#include "QKafkaUtil.h" +#include + +QKafkaUtil::QKafkaUtil(QObject *parent) : QObject(parent) +{ + this->conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); +} + +void QKafkaUtil::setBrokers(QString brokers) +{ + this->brokers = brokers; +} +void QKafkaUtil::setTopic(QString topic) +{ + this->topic = topic; +} + + +int QKafkaUtil::initKafkaConf() +{ + int result; + result = this->conf->set("bootstrap.servers", this->brokers.toStdString(), errStr); + + if (result != RdKafka::Conf::CONF_OK) + { + std::cerr << errStr << std::endl; + + return RdKafka::Conf::CONF_INVALID; // -1 + } + + this->producer = RdKafka::Producer::create(this->conf, errStr); + if (producer == 0) + { + std::cerr << "Failed to create producer: " << errStr << std::endl; + return -2; + } + + result = 1; + return result; +} diff --git a/PhaseCompAcq/common/utils/QKafkaUtil.h b/PhaseCompAcq/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..106b289 --- /dev/null +++ b/PhaseCompAcq/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "librdkafka/include/rdkafkacpp.h" +#include "librdkafka/include/wingetopt.c" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int initKafkaConf(); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/PhaseCompAcq/common/utils/QLogUtil.cpp b/PhaseCompAcq/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..458ac15 --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.cpp @@ -0,0 +1,36 @@ +#include "QLogUtil.h" + + +QLogUtil::QLogUtil(QObject *parent) : QObject(parent) +{ + +} + +void QLogUtil::writeRawDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile rawLogFile(filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLog(QString filename, QString content) +{ + content.append("\n"); + QFile chLogFile(filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::writeDebugLog(QString message) +{ + +} + +void QLogUtil::writeInfoLog(QString message) +{ + +} + diff --git a/PhaseCompAcq/common/utils/QLogUtil.h b/PhaseCompAcq/common/utils/QLogUtil.h new file mode 100644 index 0000000..8da0fcd --- /dev/null +++ b/PhaseCompAcq/common/utils/QLogUtil.h @@ -0,0 +1,23 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include + +class QLogUtil : public QObject +{ + Q_OBJECT +public: + explicit QLogUtil(QObject *parent = nullptr); + + static void writeRawDataLog(QString filename, QString content); + static void writeChannelDataLog(QString filename, QString content); + static void writeInfoLog(QString message); + static void writeDebugLog(QString message); + +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.cpp b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..2d54019 --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,48 @@ +#include "QSerialPortUtil.h" + +#include + +QSerialPortUtil::QSerialPortUtil(QObject *parent) : QObject(parent) +{ + // 其他默认配置 + serial.setDataBits(QSerialPort::Data8); + serial.setParity(QSerialPort::NoParity); + serial.setStopBits(QSerialPort::OneStop); + serial.setFlowControl(QSerialPort::NoFlowControl); +} + +void QSerialPortUtil::openSerialPort(QString portName, int baudRate) +{ + serial.setPortName(portName); // 串口名 + serial.setBaudRate(baudRate); // 波特率 + + open = serial.open(QIODevice::ReadWrite); + + if (open == true) + { + // 绑定信号与槽 + connect(&serial, &QSerialPort::readyRead, + this, &QSerialPortUtil::readData); + } +} + +void QSerialPortUtil::sendData(QByteArray data) +{ + if (this->open == true) + { + std::cout << data.toStdString() << std::endl; + serial.write(data); + } +} + +void QSerialPortUtil::readData() +{ + QByteArray buffer = serial.readAll(); + + emit dataRecieved(buffer); +} + +bool QSerialPortUtil::isOpen() +{ + return this->open; +} diff --git a/PhaseCompAcq/common/utils/QSerialPortUtil.h b/PhaseCompAcq/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..1a7f62f --- /dev/null +++ b/PhaseCompAcq/common/utils/QSerialPortUtil.h @@ -0,0 +1,28 @@ +#ifndef QSERIALPORTUTIL_H +#define QSERIALPORTUTIL_H + +#include +#include + +class QSerialPortUtil : public QObject +{ + Q_OBJECT +public: + explicit QSerialPortUtil(QObject *parent = nullptr); + + void openSerialPort(QString portName, int baudRate); + void sendData(QByteArray data); + void readData(); + + bool isOpen(); + +private: + QSerialPort serial; + + bool open; + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/PhaseCompAcq/common/utils/SettingConfig.cpp b/PhaseCompAcq/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..ef037c9 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.cpp @@ -0,0 +1,17 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + PORT_NAMES = getProperty("com", "portNames").toString(); + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + DEV_CODES = getProperty("com", "devCodes").toString(); +} + + +QVariant SettingConfig::getProperty(QString nodeName, QString keyName) { + QVariant var = this->setting->value(QString("/%1/%2").arg(nodeName).arg(keyName)); + return var; +} diff --git a/PhaseCompAcq/common/utils/SettingConfig.h b/PhaseCompAcq/common/utils/SettingConfig.h new file mode 100644 index 0000000..2d68710 --- /dev/null +++ b/PhaseCompAcq/common/utils/SettingConfig.h @@ -0,0 +1,41 @@ +#ifndef SETTINGCONFIG_H +#define SETTINGCONFIG_H + +#include +#include +#include + +class SettingConfig : public QObject +{ +public: + ~SettingConfig() {}; + SettingConfig(const SettingConfig&)=delete; + SettingConfig& operator=(const SettingConfig&)=delete; + + static SettingConfig& getInstance() { + static SettingConfig instance; + return instance; + } + + /** + * @brief get + * @param nodeName + * @param keyName + * @return QVariant + * @title + */ + QVariant getProperty(QString nodeName, QString keyName); + + /******** 以下为需要的各类参数 ********/ + QString PORT_NAMES; + int BAUD_RATE; + QString DEV_CODES; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/PhaseCompAcq/main.cpp b/PhaseCompAcq/main.cpp new file mode 100644 index 0000000..adf5eeb --- /dev/null +++ b/PhaseCompAcq/main.cpp @@ -0,0 +1,11 @@ +#include "PhaseWindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + PhaseWindow w; + w.show(); + return a.exec(); +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.cpp b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp new file mode 100644 index 0000000..79bcaa5 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.cpp @@ -0,0 +1,79 @@ +#include "PhaseProtocolBM.h" +#include + +#if _MSC_VER >= 1600 +#pragma execution_character_set("utf-8") +#endif + +PhaseProtocolBM::PhaseProtocolBM(QObject *parent) : QObject(parent) +{ + +} + +PhaseProtocolBM::~PhaseProtocolBM() +{ + +} + +bool PhaseProtocolBM::parseMessureData(QByteArray rawData, PhaseDataDto * dataObj) +{ + // 获取帧头——帧计数 + QByteArray head = rawData.left(PHASE_FRAME_ID_LENGTH); + dataObj->frameId = QByteUtil::binToHexString(head); + + int j = 0; // 用于转换通道顺序 + + // 获取每个通道的测量数据 + for (int i = 1; i <= PHASE_MESSURE_CHANNEL; i++) + { + if (i <= 8) + { + j = 2 * i - 1; + + } else + { + j = 2 * (i - 8); + } + + QByteArray channelRaw = rawData.left(PHASE_MESSURE_SIZE * j + PHASE_FRAME_ID_LENGTH).right(PHASE_MESSURE_SIZE); + qulonglong channelRawData = QByteUtil::binToULong(channelRaw, 8); + + if (channelRawData == CALCULATE_OFFSET) + { + dataObj->channelActive.append("0"); + dataObj->channelData.append(0.00); + } else + { + dataObj->channelActive.append("1"); + dataObj->channelData.append((channelRawData - CALCULATE_OFFSET) * CALCULATE_FACTOR); + } + } + + return true; +} + +QString PhaseProtocolBM::startMessure() +{ + return "$START*"; +} +QString PhaseProtocolBM::stopMessure() +{ + return "$$STOP*"; +} + +bool PhaseProtocolBM::checkFrame(QByteArray rawData) +{ + // 帧长度小于最小的长度 + if (rawData.length() != PHASE_FRAM_LENGTH) + { + return false; + } + + // 帧尾不是0xEEEEEEEE + if (rawData.mid(rawData.length() - PHASE_FRAME_TAIL.size()) != PHASE_FRAME_TAIL) + { + return false; + } + + return true; +} diff --git a/PhaseCompAcq/protocol/PhaseProtocolBM.h b/PhaseCompAcq/protocol/PhaseProtocolBM.h new file mode 100644 index 0000000..048a9c2 --- /dev/null +++ b/PhaseCompAcq/protocol/PhaseProtocolBM.h @@ -0,0 +1,36 @@ +#ifndef PHASEPROTOCOLBM_H +#define PHASEPROTOCOLBM_H + +#include + +#include "dto/PhaseDataDto.h" +#include "common/utils/QByteUtil.h" + +static const QByteArray PHASE_FRAME_TAIL("\xEE\xEE\xEE\xEE", 4); // 帧尾 + +static const int PHASE_FRAME_ID_LENGTH = 4; // 帧头id计数器为4个字节 +static const int PHASE_MESSURE_CHANNEL = 16; +static const int PHASE_MESSURE_SIZE = 8; +static const int PHASE_FRAM_LENGTH = PHASE_FRAME_ID_LENGTH + PHASE_FRAME_TAIL.size() + + PHASE_MESSURE_CHANNEL * PHASE_MESSURE_SIZE; + +static const qulonglong CALCULATE_OFFSET = 0X0080000000000000; +static const double CALCULATE_FACTOR = 1.6810E-15; + +class PhaseProtocolBM : public QObject +{ +public: + explicit PhaseProtocolBM(QObject *parent = nullptr); + ~PhaseProtocolBM(); + + // 解析比相仪测量数据 + static bool parseMessureData(QByteArray rawData, PhaseDataDto * phaseData); + + static QString startMessure(); + static QString stopMessure(); + + // 检测帧格式,帧头帧尾 + static bool checkFrame(QByteArray rawData); +}; + +#endif // PHASEROTOCOLBM_H diff --git a/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp b/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp new file mode 100644 index 0000000..604700e --- /dev/null +++ b/PhaseCompAcq/protocol/dto/PhaseDataDto.cpp @@ -0,0 +1,13 @@ +#include "PhaseDataDto.h" + +PhaseDataDto::PhaseDataDto(QObject *parent) : QObject(parent) +{ + this->frameId = ""; + this->timestamp = ""; + this->milisecond = 0; + this->devCode = ""; + this->devStatus = ""; + + this->channelActive = QList(); + this->channelData = QList(); +} diff --git a/PhaseCompAcq/protocol/dto/PhaseDataDto.h b/PhaseCompAcq/protocol/dto/PhaseDataDto.h new file mode 100644 index 0000000..75af3ee --- /dev/null +++ b/PhaseCompAcq/protocol/dto/PhaseDataDto.h @@ -0,0 +1,26 @@ +#ifndef PHASEDATADTO_H +#define PHASEDATADTO_H + +#include + +class PhaseDataDto : public QObject +{ + Q_OBJECT +public: + explicit PhaseDataDto(QObject *parent = nullptr); + + QString frameId; // 帧id + QString timestamp; // 时间戳字符串 + qulonglong milisecond; // 毫秒计数 + QByteArray rawFrame; // 原始帧字节数组 + + QString devCode; + QString devStatus; + QList channelActive; + QList channelData; + +signals: + +}; + +#endif // PHASEDATADTO_H diff --git a/PhaseCompAcq/protocol/protocol.pri b/PhaseCompAcq/protocol/protocol.pri new file mode 100644 index 0000000..d998e2e --- /dev/null +++ b/PhaseCompAcq/protocol/protocol.pri @@ -0,0 +1,6 @@ + +SOURCES += $$PWD/PhaseProtocolBM.cpp +SOURCES += $$PWD/dto/PhaseDataDto.cpp + +HEADERS += $$PWD/PhaseProtocolBM.h +HEADERS += $$PWD/dto/PhaseDataDto.h diff --git a/ZXSSCJ.pro b/ZXSSCJ.pro new file mode 100644 index 0000000..f1c0807 --- /dev/null +++ b/ZXSSCJ.pro @@ -0,0 +1,9 @@ +TEMPLATE = subdirs + +#定义了ordered表示子项目按照添加的顺序来编译 +#CONFIG += ordered + +SUBDIRS += CounterAcq #计数器数据采集 +SUBDIRS += PhaseCompAcq #比相仪数据采集 +SUBDIRS += DevStatusAcq +#SUBDIRS += HClockAcq #氢钟状态数据采集